SpaceCatalog
How a creator picks a place to gate and whether the installation controls it — link requests by purpose, instructions, diagnosis, and what the SDK does not yet let a third party complete.
Subscriby\Connector\Contracts\Ports\SpaceCatalog. Optional; no capability binds it. A connector with access_control almost always binds it, because it is how a creator links a place.
Linking is asked through the connector because only the platform can prove the installation administers a place: Telegram answers a chat picker, Discord a guild pick. The connector parks the request under the creator's account with its own handle, the platform answers, and the chosen place is filed under the request's purpose.
Methods
| Method | Called when | Returns |
|---|---|---|
requestLink(installation, credentials, IdentityRef, LinkRequest) | The creator clicks Link a resource, Request a standby or Replace in the dashboard. | void |
withdrawLinkRequest(installation, credentials, creator, LinkPurpose) | The creator cancels the request. | void |
pendingLinkRequest(installation, credentials, creator, LinkPurpose) | The dashboard shows whether a request is waiting, and for what. | ?string |
linkInstructions(LinkPurpose) | The dashboard tells the creator what to do on the platform while a request is open. | string |
describe(installation, credentials, SpaceRef) | The core wants the platform's current title and parent for a place. | SpaceSummary |
diagnose(installation, credentials, SpaceRef) | The connector doctor checks every gated place. | SpaceAccess |
Link requests
A LinkRequest carries the kind of place wanted (one of your resource kinds), the purpose and the subject:
LinkPurpose | The creator is picking… | subjectId, subjectTitle |
|---|---|---|
Resource | A place to sell access to, as a new resource. | The project's id and name. |
Standby | A place to stand by for an existing resource. | The resource's id and title. |
Replacement | A place to replace an existing resource's lost one. | The resource's id and title. |
SupportRelay | A group to relay support conversations into. Reserved: the core does not request it yet; Telegram links the group when the bot is added to it. | The project's id and name. |
One request per purpose is open at a time for a creator; asking again replaces it. The IdentityRef is the creator's account on your connector, the one to ask in; the core refuses the request itself when the creator has no reachable account there.
linkInstructions() is the one or two plain sentences the dashboard shows while the request is open, translated: "Our bot sent you a button to pick the chat. Tap it from your Telegram account…". Only the connector knows whether the creator taps a keyboard, picks a guild or approves a prompt.
Completing a request
When the platform answers with the chosen place, your inbound handler files it under the purpose it parked. Record the place first with Core\Spaces::record(new SpaceRecord(...)), then:
- a
Resourcerequest:Core\Resources::create($project, $space, ResourceKind::for($key, $kind), $title)writes the resource, binds it to the space and announces it; idempotent, so a replayed answer creates nothing twice; - a
Standbyrequest:Core\Recovery::registerStandby($resource, $space)files the place as the resource's reserve; - a
Replacementrequest:Core\Recovery::replaceSpace($resource, $space)points the resource at the new place and re-admits everyone with access.
Each write is the action the dashboard runs, so the owner guard, the tier gate and the allowance are the same whichever road the creator took, and each refusal reaches you as ResourceRefused or RecoveryRefused with the sentence to relay. Core\Spaces::bindResource() stays for a place that should gate an existing resource outside the ledger, which is what a migration uses.
Linking the group a support relay posts into for a SupportRelay request is not on the SDK yet: it lands with Core\Support, scheduled with the second first-party connector, and until then a third-party connector that declares support_relay says so on its listing and watches the SDK changelog.
diagnose()
Whether the installation can grant and revoke in a place, and if not why: SpaceAccess with ready, a state word your connector defines (ready, not_admin, missing_right, gone), a detail sentence for the creator and creatorActionable. The doctor renders it with your resource_health_detail slot when you fill one.
How Telegram does it
Telegram cannot list the chats a bot administers, so a place is linked by asking the creator to pick it: the bot sends a reply keyboard whose one button opens Telegram's chat picker filtered to the kind wanted, Telegram makes the bot an administrator of the chosen chat with the two rights it needs, and answers with a chat_shared update carrying the request id parked under the creator's chat. diagnose() is getChatMember on the bot's own id, the one call that tells a deleted chat from a removed bot from a missing right.
What the kit checks
Nothing beyond the port's shape: a bound SpaceCatalog is exercised by the doctor and the dashboard, not by the kit. Test diagnose() against your platform's fake for each state you return.
Describe, do not decide
A connector reports every place it learns about through Core\Spaces::record() and decides nothing for the creator. Selling access to a place is the core's decision, made when the resource is created.
How is this guide?
RecoverySupport
What the Disaster Recovery Program needs a connector to witness and do — vocabulary, readiness, the three probes, standby installations, failover, mirroring and identity relinks, facet by facet.
Core API
The contracts a connector calls into the core — how they are bound, the records and refs that cross them, the idempotency every write keeps, the exceptions, and what the nine contracts cover.