Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 17 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ The development branch contains the TypeScript server SDK, a framework-neutral
browser runtime, shared UI contracts, Web Components, React bindings, thin
Next.js server helpers, and a production-gated developer assistant. It follows
the Messaging and Platform contracts recorded at source revision
`8c244aab0e5626d101a2c8c4915287427f39e014`. Graph-compatible APIs are outside
`6918c56135e28ba64557e344cb72889f1f517eb5`. Graph-compatible APIs are outside
this SDK's initial scope.

## Package architecture
Expand Down Expand Up @@ -76,16 +76,18 @@ const sent = await messaging.messages.send(
console.log(sent.data.data.id, sent.metadata.attempts);
```

Messaging credentials use an explicit discriminator. Server keys use
`{ type: "apiKey", value }`; short-lived client tokens use
Messaging credentials use an explicit discriminator. Organization server keys
use `{ type: "apiKey", value }`, project tokens use
`{ type: "projectToken", value }`, and short-lived client tokens use
`{ type: "clientToken", value }`. A discriminator/prefix mismatch fails before
any network request. Server keys are rejected in browser runtimes.
any network request. Server credentials are rejected in browser runtimes.

The handwritten Messaging resources in this milestone are:

- `sessions`: list, create, retrieve, update, delete, start, stop, restart,
logout, account, JSON QR retrieval, and phone pairing codes
logout, account, and entitlement-gated direct JSON QR or phone pairing
- `operations`: retrieve durable lifecycle operation status
- `quickLinks`: create, retrieve, and cancel hosted QuickLink pairing sessions
- `business`: manage the connected Business App profile, commerce catalog,
products, collections, orders, compliance, linked accounts, and eligibility
- `calls`: reject an identified incoming Linked Device call
Expand Down Expand Up @@ -377,16 +379,21 @@ The SDK has no listener, event stream, `AsyncIterable`, or forwarding API.
credential cannot be used by `Client`, `MessagingClient`, or their raw request
helpers.

## QuickLink settings
## QuickLink lifecycle and settings

`MessagingClient.quickLinks.create()`, `retrieve()`, and `cancel()` map the
authenticated hosted lifecycle at `/api/quicklinks`. They accept organization
API keys or project tokens with `quicklink:manage`; browser client tokens fail
before transport. Organization keys can set `projectId` on creation, while a
project token remains bound by the server.

These methods expose the short-lived connection URL and status record. They do
not add list, recovery, or history operations that the API does not provide.

`client.quickLinkSettings.retrieve()` and `update()` map only the management
`GET /v1/quicklink` and `PUT /v1/quicklink` settings contract. The same methods
on `client.project(projectId)` use the immutable project ownership context.

The SDK does not expose hosted QuickLink creation, inspection, or cancellation
for `/api/quicklinks`. Those ephemeral flows belong to an application adapter
and the browser controller, not the management client.

## Browser controllers and UI

Browser code accepts only short-lived `pmfa_ct_` tokens returned by an
Expand Down
24 changes: 14 additions & 10 deletions contracts/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@

The snapshots are byte-identical copies of the Messaging and Platform OpenAPI
files at `polymorfa/polymorfa` commit
`8c244aab0e5626d101a2c8c4915287427f39e014`. `source.json` records their original
`6918c56135e28ba64557e344cb72889f1f517eb5`. `source.json` records their original

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Update reconciliation notes for the new contract pin

Repinning this file makes the existing Reconciliation section describe the wrong refresh. Comparing the parent 8c244aab... snapshot with 6918c561... shows no structural operation-fingerprint changes; the actual changes are the direct-pairing descriptions and removal of the session.qr webhook schemas/callback. The current text instead attributes browser-candidate, agent-token, participant, and TURN changes from an earlier refresh, so the contract provenance documentation is now misleading and should be updated with the pin.

Useful? React with 👍 / 👎.

paths and SHA-256 hashes. `coverage.json` uses the same source revision.

| Status | Operations |
| ------------------- | ---------: |
| Covered | 271 |
| Covered | 274 |
| Missing | 0 |
| Excluded | 131 |
| Excluded | 128 |
| Partial | 0 |
| Changed fingerprint | 0 |
| Total | 402 |
Expand All @@ -20,13 +20,17 @@ successful live call.

## Reconciliation

This refresh adds and removes no operations. Two Messaging operation
fingerprints changed: browser candidate retrieval remains excluded from the
server SDK, and `MessagingClient.voip.agentToken` remains covered by its typed
method and request test. Schema updates include literal webhook event names,
nullable terminal-call callers, participant lifecycle events, client-token
delegation scopes, and TURN health diagnostics. These changes do not alter the
operation coverage totals or the existing missing-operation inventory.
This contract refresh adds and removes no operations and changes no operation
fingerprints. It retires the `session.qr` webhook schema and callback, and it
documents that direct QR and pairing-code session routes require an
organization entitlement while hosted QuickLinks are the standard pairing
flow.

The SDK now covers the three existing QuickLink operations through
`MessagingClient.quickLinks.create`, `retrieve`, and `cancel`. Those rows moved
from excluded to covered, increasing covered operations from 271 to 274 and
reducing excluded operations from 131 to 128. The missing-operation inventory
remains empty.

This snapshot records complete handwritten TypeScript coverage for every
customer-credential-compatible operation in the pinned contracts. Routes that
Expand Down
17 changes: 7 additions & 10 deletions contracts/coverage.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"schemaVersion": 1,
"sourceCommit": "8c244aab0e5626d101a2c8c4915287427f39e014",
"sourceCommit": "6918c56135e28ba64557e344cb72889f1f517eb5",
"excludedContracts": [
{
"family": "graph",
Expand All @@ -26,9 +26,8 @@
"operationId": "cancelQuickLink",
"fingerprint": "763ce4c4e8f4fdec20a081a53a40bcbc10101940bbe9fc41647ca5338215d5f7",
"typescript": {
"status": "excluded",
"reason": "Ephemeral hosted QuickLink orchestration is outside the public server SDK management-resource contract; browser QuickLink uses an application-provided backend adapter.",
"milestone": "not-server-sdk"
"status": "covered",
"method": "MessagingClient.quickLinks.cancel"
}
},
{
Expand Down Expand Up @@ -303,9 +302,8 @@
"operationId": "getQuickLink",
"fingerprint": "76ece78254ba9f50816a3ebb40365ac699bd7b2ceb4b15134a3e6c2521672b4c",
"typescript": {
"status": "excluded",
"reason": "Ephemeral hosted QuickLink orchestration is outside the public server SDK management-resource contract; browser QuickLink uses an application-provided backend adapter.",
"milestone": "not-server-sdk"
"status": "covered",
"method": "MessagingClient.quickLinks.retrieve"
}
},
{
Expand Down Expand Up @@ -1022,9 +1020,8 @@
"operationId": "createQuickLink",
"fingerprint": "0f8aa33283ca0a7b8f5ce21aec512a471ec96fee773a16f1bf96e55c5cea9367",
"typescript": {
"status": "excluded",
"reason": "Ephemeral hosted QuickLink orchestration is outside the public server SDK management-resource contract; browser QuickLink uses an application-provided backend adapter.",
"milestone": "not-server-sdk"
"status": "covered",
"method": "MessagingClient.quickLinks.create"
}
},
{
Expand Down
81 changes: 6 additions & 75 deletions contracts/openapi.messaging.json
Original file line number Diff line number Diff line change
Expand Up @@ -725,51 +725,6 @@
"payload"
]
},
"SessionQRPayload": {
"type": "object",
"properties": {
"code": {
"type": "string"
}
},
"required": [
"code"
]
},
"SessionQREvent": {
"type": "object",
"properties": {
"id": {
"type": "string",
"description": "Unique event identifier"
},
"session": {
"type": "string",
"description": "Session that produced this event"
},
"timestamp": {
"type": "string",
"description": "ISO 8601 timestamp"
},
"event": {
"type": "string",
"enum": [
"session.qr"
],
"description": "Event type"
},
"payload": {
"$ref": "#/components/schemas/SessionQRPayload"
}
},
"required": [
"id",
"session",
"timestamp",
"event",
"payload"
]
},
"SessionConnectedPayload": {
"type": "object",
"properties": {
Expand Down Expand Up @@ -13377,6 +13332,7 @@
"Pairing"
],
"summary": "Get QR code for device pairing",
"description": "**Protocols:** Linked Device API\n\n**Required scope:** `sessions:manage`\n\nDirect QR retrieval requires an explicit organization entitlement. Create a QuickLink for the standard pairing flow.",
"security": [
{
"BearerAuth": []
Expand Down Expand Up @@ -13444,7 +13400,7 @@
}
},
"403": {
"description": "Authenticated but not permitted (missing scope or rule violation)",
"description": "Direct pairing is unavailable; create a QuickLink unless the organization has the direct-pairing entitlement",
"content": {
"application/json": {
"schema": {
Expand Down Expand Up @@ -13479,8 +13435,7 @@
},
"x-protocols": [
"Linked Device API"
],
"description": "**Protocols:** Linked Device API\n\n**Required scope:** `sessions:manage`"
]
}
},
"/api/{session}/pair/code": {
Expand All @@ -13490,6 +13445,7 @@
"Pairing"
],
"summary": "Request a pairing code for a phone number",
"description": "**Protocols:** Linked Device API\n\n**Required scope:** `sessions:manage`\n\nDirect pairing-code retrieval requires an explicit organization entitlement. Create a QuickLink for the standard pairing flow.",
"security": [
{
"BearerAuth": []
Expand Down Expand Up @@ -13547,7 +13503,7 @@
}
},
"403": {
"description": "Authenticated but not permitted (missing scope or rule violation)",
"description": "Direct pairing is unavailable; create a QuickLink unless the organization has the direct-pairing entitlement",
"content": {
"application/json": {
"schema": {
Expand Down Expand Up @@ -13582,8 +13538,7 @@
},
"x-protocols": [
"Linked Device API"
],
"description": "**Protocols:** Linked Device API\n\n**Required scope:** `sessions:manage`"
]
}
},
"/api/{session}/messages/send": {
Expand Down Expand Up @@ -30333,30 +30288,6 @@
}
}
},
"session.qr": {
"post": {
"operationId": "onSessionQr",
"summary": "QR code issued for device linking",
"tags": [
"Webhooks"
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/SessionQREvent"
}
}
}
},
"responses": {
"2XX": {
"description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy."
}
}
}
},
"session.connected": {
"post": {
"operationId": "onSessionConnected",
Expand Down
4 changes: 2 additions & 2 deletions contracts/source.json
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
{
"repository": "polymorfa/polymorfa",
"commit": "8c244aab0e5626d101a2c8c4915287427f39e014",
"commit": "6918c56135e28ba64557e344cb72889f1f517eb5",
"contracts": {
"messaging": {
"sourcePath": "apps/api/docs/openapi.json",
"snapshotPath": "contracts/openapi.messaging.json",
"sha256": "a60bc482b8e830b063895708fbf0b9ea68a05b9d8df3f7256df085349d88ef2e"
"sha256": "2f5d06b1e5103a00e62896636f122c570729578afd3cc5636ae57711941d85cf"
},
"platform": {
"sourcePath": "apps/api/docs/openapi.management.json",
Expand Down
Loading