From 1360350d487a5f9c906ae45263c83772a0c1f304 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 18 Oct 2026 15:04:07 +0000 Subject: [PATCH] Use generated types for phone pairing pairkit now declares response models for its /v1/pair/* routes, so the claim and grant types come from the API's OpenAPI contract like everything else. PairGrant adds the space_id that ScribbleScan's grant hook puts in the grant. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01A5s1B8CvD6MoPSJZpL8ScT --- CLAUDE.md | 2 +- openapi.json | 256 +++++++++++++++++++++++++++++++-- src/api/generated/index.ts | 2 +- src/api/generated/types.gen.ts | 176 +++++++++++++++++++++-- src/api/types.ts | 17 +-- 5 files changed, 419 insertions(+), 34 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index ccb3562..bc7dba0 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -7,7 +7,7 @@ The owner is a Principal Software Engineer in Bangladesh building this as a port ## Rules - **Talk only to `/v1`.** Same address as the API in production (Caddy routes `/v1` to it) and in development (Vite proxy). No CORS, no other backends. -- **Types come from the API's OpenAPI spec** (`npm run api:types` -> `src/api/generated`, never edit by hand). When the API changes, refresh `openapi.json` and regenerate. pairkit's `/v1/pair/*` routes have no response models yet; their types are hand-written in `src/api/types.ts`. +- **Types come from the API's OpenAPI spec** (`npm run api:types` -> `src/api/generated`, never edit by hand). When the API changes, refresh `openapi.json` and regenerate. That includes pairkit's `/v1/pair/*` routes; `PairGrant` adds the `space_id` ScribbleScan's grant hook puts in the grant. - **No UI framework**, by choice: plain DOM via `h()`/`render()` in `src/dom.ts`. They flatten nested arrays and drop null/false, so views can write `cond ? h(...) : null`. - **Only use things with a future** (the owner's rule): nothing deprecated, unmaintained or near end of life. Node 24 LTS, TypeScript 7, Vite 8, Vitest, Biome. Check maintenance before adding a dependency, and prefer none. - Dates are DD/MM/YYYY text fields converted to ISO (native date inputs show US order in many browsers). Money uses lakh grouping (`en-IN`). The current month comes from the local clock, not UTC. diff --git a/openapi.json b/openapi.json index 8f8c523..333dce7 100644 --- a/openapi.json +++ b/openapi.json @@ -28,7 +28,9 @@ "description": "Successful Response", "content": { "application/json": { - "schema": {} + "schema": { + "$ref": "#/components/schemas/OfferCreated" + } } } }, @@ -67,7 +69,9 @@ "description": "Successful Response", "content": { "application/json": { - "schema": {} + "schema": { + "$ref": "#/components/schemas/Claimed" + } } } }, @@ -116,7 +120,9 @@ "description": "Successful Response", "content": { "application/json": { - "schema": {} + "schema": { + "$ref": "#/components/schemas/OfferStatus" + } } } }, @@ -162,11 +168,9 @@ ], "responses": { "200": { - "description": "Successful Response", + "description": "Server-sent events: state, claimed, approved, denied, collected, expired", "content": { - "application/json": { - "schema": {} - } + "text/event-stream": {} } }, "422": { @@ -205,7 +209,9 @@ "description": "Successful Response", "content": { "application/json": { - "schema": {} + "schema": { + "$ref": "#/components/schemas/OfferStatus" + } } } }, @@ -245,7 +251,9 @@ "description": "Successful Response", "content": { "application/json": { - "schema": {} + "schema": { + "$ref": "#/components/schemas/OfferStatus" + } } } }, @@ -294,7 +302,9 @@ "description": "Successful Response", "content": { "application/json": { - "schema": {} + "schema": { + "$ref": "#/components/schemas/Collected" + } } } }, @@ -323,7 +333,13 @@ "description": "Successful Response", "content": { "application/json": { - "schema": {} + "schema": { + "items": { + "$ref": "#/components/schemas/LinkedDeviceOut" + }, + "type": "array", + "title": "Response Devices V1 Pair Devices Get" + } } } } @@ -353,7 +369,9 @@ "description": "Successful Response", "content": { "application/json": { - "schema": {} + "schema": { + "$ref": "#/components/schemas/LinkedDeviceOut" + } } } }, @@ -1357,6 +1375,48 @@ ], "title": "ClaimIn" }, + "Claimed": { + "properties": { + "offer_id": { + "type": "string", + "title": "Offer Id" + }, + "claimer_key": { + "type": "string", + "title": "Claimer Key", + "description": "the scanning device's private key: X-Pairkit-Key / ?key=" + }, + "grant_to": { + "$ref": "#/components/schemas/GrantTo" + }, + "scopes": { + "items": { + "type": "string" + }, + "type": "array", + "title": "Scopes" + }, + "shower": { + "type": "string", + "title": "Shower", + "description": "how the device showing the QR describes itself" + }, + "expires_at": { + "type": "string", + "title": "Expires At" + } + }, + "type": "object", + "required": [ + "offer_id", + "claimer_key", + "grant_to", + "scopes", + "shower", + "expires_at" + ], + "title": "Claimed" + }, "ClientConfig": { "properties": { "auth": { @@ -1408,6 +1468,33 @@ "title": "ClientConfig", "description": "Which sign-in this server uses. For \"oidc\", where and how to sign in." }, + "Collected": { + "properties": { + "token": { + "type": "string", + "title": "Token" + }, + "expires_at": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Expires At" + } + }, + "additionalProperties": true, + "type": "object", + "required": [ + "token", + "expires_at" + ], + "title": "Collected", + "description": "The grant from the app's issue_grant hook, plus whatever it put in Grant.data." + }, "CreateOfferIn": { "properties": { "grant_to": { @@ -1770,6 +1857,46 @@ "title": "Issue", "description": "A business rule the document doesn't pass yet, e.g. rule=\"missing\", detail=\"total\"." }, + "LinkedDeviceOut": { + "properties": { + "id": { + "type": "string", + "title": "Id" + }, + "device": { + "type": "string", + "title": "Device" + }, + "scopes": { + "items": { + "type": "string" + }, + "type": "array", + "title": "Scopes" + }, + "linked_at": { + "type": "string", + "title": "Linked At" + }, + "via": { + "$ref": "#/components/schemas/GrantTo" + }, + "active": { + "type": "boolean", + "title": "Active" + } + }, + "type": "object", + "required": [ + "id", + "device", + "scopes", + "linked_at", + "via", + "active" + ], + "title": "LinkedDeviceOut" + }, "Me": { "properties": { "id": { @@ -1811,6 +1938,99 @@ ], "title": "MonthTotal" }, + "OfferCreated": { + "properties": { + "offer_id": { + "type": "string", + "title": "Offer Id" + }, + "secret": { + "type": "string", + "title": "Secret", + "description": "goes in the QR code, in the URL fragment" + }, + "shower_key": { + "type": "string", + "title": "Shower Key", + "description": "this device's private key: X-Pairkit-Key / ?key=" + }, + "expires_at": { + "type": "string", + "title": "Expires At" + }, + "qr_url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Qr Url", + "description": "ready-to-encode scan link, when the router has a scan_url" + } + }, + "type": "object", + "required": [ + "offer_id", + "secret", + "shower_key", + "expires_at" + ], + "title": "OfferCreated" + }, + "OfferStatus": { + "properties": { + "offer_id": { + "type": "string", + "title": "Offer Id" + }, + "state": { + "$ref": "#/components/schemas/State" + }, + "grant_to": { + "$ref": "#/components/schemas/GrantTo" + }, + "scopes": { + "items": { + "type": "string" + }, + "type": "array", + "title": "Scopes" + }, + "expires_at": { + "type": "string", + "title": "Expires At" + }, + "shower": { + "type": "string", + "title": "Shower" + }, + "scanner": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Scanner" + } + }, + "type": "object", + "required": [ + "offer_id", + "state", + "grant_to", + "scopes", + "expires_at", + "shower", + "scanner" + ], + "title": "OfferStatus" + }, "PairOffer": { "properties": { "offer_id": { @@ -1921,6 +2141,18 @@ ], "title": "SpaceOut" }, + "State": { + "type": "string", + "enum": [ + "pending", + "claimed", + "approved", + "collected", + "denied", + "expired" + ], + "title": "State" + }, "Summary": { "properties": { "month": { diff --git a/src/api/generated/index.ts b/src/api/generated/index.ts index 186b8cb..3482a65 100644 --- a/src/api/generated/index.ts +++ b/src/api/generated/index.ts @@ -1,3 +1,3 @@ // This file is auto-generated by @hey-api/openapi-ts -export type { ApproveV1PairOffersOfferIdApprovePostData, ApproveV1PairOffersOfferIdApprovePostError, ApproveV1PairOffersOfferIdApprovePostErrors, ApproveV1PairOffersOfferIdApprovePostResponses, BodyUploadV1SpacesSpaceIdDocumentsPost, BudgetsIn, CategoriesV1CategoriesGetData, CategoriesV1CategoriesGetResponse, CategoriesV1CategoriesGetResponses, CategorySpend, ClaimIn, ClaimV1PairClaimPostData, ClaimV1PairClaimPostError, ClaimV1PairClaimPostErrors, ClaimV1PairClaimPostResponses, ClientConfig, ClientConfigV1ConfigGetData, ClientConfigV1ConfigGetResponse, ClientConfigV1ConfigGetResponses, ClientOptions, CollectV1PairOffersOfferIdCollectPostData, CollectV1PairOffersOfferIdCollectPostError, CollectV1PairOffersOfferIdCollectPostErrors, CollectV1PairOffersOfferIdCollectPostResponses, CreateOfferIn, CreateOfferV1PairOffersPostData, CreateOfferV1PairOffersPostError, CreateOfferV1PairOffersPostErrors, CreateOfferV1PairOffersPostResponses, CreateSpaceV1SpacesPostData, CreateSpaceV1SpacesPostError, CreateSpaceV1SpacesPostErrors, CreateSpaceV1SpacesPostResponse, CreateSpaceV1SpacesPostResponses, DeleteDocumentV1DocumentsDocIdDeleteData, DeleteDocumentV1DocumentsDocIdDeleteError, DeleteDocumentV1DocumentsDocIdDeleteErrors, DeleteDocumentV1DocumentsDocIdDeleteResponse, DeleteDocumentV1DocumentsDocIdDeleteResponses, DenyV1PairOffersOfferIdDenyPostData, DenyV1PairOffersOfferIdDenyPostError, DenyV1PairOffersOfferIdDenyPostErrors, DenyV1PairOffersOfferIdDenyPostResponses, Device, DevicesV1DevicesGetData, DevicesV1DevicesGetResponse, DevicesV1DevicesGetResponses, DevicesV1PairDevicesGetData, DevicesV1PairDevicesGetResponses, DeviceUnlinked, DevToken, DevTokenIn, DevTokenV1DevTokenPostData, DevTokenV1DevTokenPostError, DevTokenV1DevTokenPostErrors, DevTokenV1DevTokenPostResponse, DevTokenV1DevTokenPostResponses, DocStatus, DocumentOut, DocumentPatch, EventsV1PairOffersOfferIdEventsGetData, EventsV1PairOffersOfferIdEventsGetError, EventsV1PairOffersOfferIdEventsGetErrors, EventsV1PairOffersOfferIdEventsGetResponses, Expenses, ExpensesV1SpacesSpaceIdExpensesGetData, ExpensesV1SpacesSpaceIdExpensesGetError, ExpensesV1SpacesSpaceIdExpensesGetErrors, ExpensesV1SpacesSpaceIdExpensesGetResponse, ExpensesV1SpacesSpaceIdExpensesGetResponses, ExportV1SpacesSpaceIdExportGetData, ExportV1SpacesSpaceIdExportGetError, ExportV1SpacesSpaceIdExportGetErrors, ExportV1SpacesSpaceIdExportGetResponses, GetDocumentV1DocumentsDocIdGetData, GetDocumentV1DocumentsDocIdGetError, GetDocumentV1DocumentsDocIdGetErrors, GetDocumentV1DocumentsDocIdGetResponse, GetDocumentV1DocumentsDocIdGetResponses, GetFileV1DocumentsDocIdFileGetData, GetFileV1DocumentsDocIdFileGetError, GetFileV1DocumentsDocIdFileGetErrors, GetFileV1DocumentsDocIdFileGetResponses, GrantTo, HttpValidationError, Issue, ListSpacesV1SpacesGetData, ListSpacesV1SpacesGetResponse, ListSpacesV1SpacesGetResponses, Me, MeV1MeGetData, MeV1MeGetResponse, MeV1MeGetResponses, MonthTotal, PairOffer, PairPhoneV1SpacesSpaceIdPairPostData, PairPhoneV1SpacesSpaceIdPairPostError, PairPhoneV1SpacesSpaceIdPairPostErrors, PairPhoneV1SpacesSpaceIdPairPostResponse, PairPhoneV1SpacesSpaceIdPairPostResponses, PatchDocumentV1DocumentsDocIdPatchData, PatchDocumentV1DocumentsDocIdPatchError, PatchDocumentV1DocumentsDocIdPatchErrors, PatchDocumentV1DocumentsDocIdPatchResponse, PatchDocumentV1DocumentsDocIdPatchResponses, QrIn, QrV1QrPostData, QrV1QrPostError, QrV1QrPostErrors, QrV1QrPostResponse, QrV1QrPostResponses, SchemaV1SchemasDocTypeGetData, SchemaV1SchemasDocTypeGetError, SchemaV1SchemasDocTypeGetErrors, SchemaV1SchemasDocTypeGetResponse, SchemaV1SchemasDocTypeGetResponses, SetBudgetsV1SpacesSpaceIdBudgetsPutData, SetBudgetsV1SpacesSpaceIdBudgetsPutError, SetBudgetsV1SpacesSpaceIdBudgetsPutErrors, SetBudgetsV1SpacesSpaceIdBudgetsPutResponse, SetBudgetsV1SpacesSpaceIdBudgetsPutResponses, SpaceIn, SpaceKind, SpaceOut, StatusV1PairOffersOfferIdGetData, StatusV1PairOffersOfferIdGetError, StatusV1PairOffersOfferIdGetErrors, StatusV1PairOffersOfferIdGetResponses, Summary, SummaryV1SpacesSpaceIdSummaryGetData, SummaryV1SpacesSpaceIdSummaryGetError, SummaryV1SpacesSpaceIdSummaryGetErrors, SummaryV1SpacesSpaceIdSummaryGetResponse, SummaryV1SpacesSpaceIdSummaryGetResponses, UnlinkV1DevicesDeviceTokenIdDeleteData, UnlinkV1DevicesDeviceTokenIdDeleteError, UnlinkV1DevicesDeviceTokenIdDeleteErrors, UnlinkV1DevicesDeviceTokenIdDeleteResponse, UnlinkV1DevicesDeviceTokenIdDeleteResponses, UnlinkV1PairDevicesDeviceIdDeleteData, UnlinkV1PairDevicesDeviceIdDeleteError, UnlinkV1PairDevicesDeviceIdDeleteErrors, UnlinkV1PairDevicesDeviceIdDeleteResponses, UploadV1SpacesSpaceIdDocumentsPostData, UploadV1SpacesSpaceIdDocumentsPostError, UploadV1SpacesSpaceIdDocumentsPostErrors, UploadV1SpacesSpaceIdDocumentsPostResponse, UploadV1SpacesSpaceIdDocumentsPostResponses, ValidationError } from './types.gen'; +export type { ApproveV1PairOffersOfferIdApprovePostData, ApproveV1PairOffersOfferIdApprovePostError, ApproveV1PairOffersOfferIdApprovePostErrors, ApproveV1PairOffersOfferIdApprovePostResponse, ApproveV1PairOffersOfferIdApprovePostResponses, BodyUploadV1SpacesSpaceIdDocumentsPost, BudgetsIn, CategoriesV1CategoriesGetData, CategoriesV1CategoriesGetResponse, CategoriesV1CategoriesGetResponses, CategorySpend, Claimed, ClaimIn, ClaimV1PairClaimPostData, ClaimV1PairClaimPostError, ClaimV1PairClaimPostErrors, ClaimV1PairClaimPostResponse, ClaimV1PairClaimPostResponses, ClientConfig, ClientConfigV1ConfigGetData, ClientConfigV1ConfigGetResponse, ClientConfigV1ConfigGetResponses, ClientOptions, Collected, CollectV1PairOffersOfferIdCollectPostData, CollectV1PairOffersOfferIdCollectPostError, CollectV1PairOffersOfferIdCollectPostErrors, CollectV1PairOffersOfferIdCollectPostResponse, CollectV1PairOffersOfferIdCollectPostResponses, CreateOfferIn, CreateOfferV1PairOffersPostData, CreateOfferV1PairOffersPostError, CreateOfferV1PairOffersPostErrors, CreateOfferV1PairOffersPostResponse, CreateOfferV1PairOffersPostResponses, CreateSpaceV1SpacesPostData, CreateSpaceV1SpacesPostError, CreateSpaceV1SpacesPostErrors, CreateSpaceV1SpacesPostResponse, CreateSpaceV1SpacesPostResponses, DeleteDocumentV1DocumentsDocIdDeleteData, DeleteDocumentV1DocumentsDocIdDeleteError, DeleteDocumentV1DocumentsDocIdDeleteErrors, DeleteDocumentV1DocumentsDocIdDeleteResponse, DeleteDocumentV1DocumentsDocIdDeleteResponses, DenyV1PairOffersOfferIdDenyPostData, DenyV1PairOffersOfferIdDenyPostError, DenyV1PairOffersOfferIdDenyPostErrors, DenyV1PairOffersOfferIdDenyPostResponse, DenyV1PairOffersOfferIdDenyPostResponses, Device, DevicesV1DevicesGetData, DevicesV1DevicesGetResponse, DevicesV1DevicesGetResponses, DevicesV1PairDevicesGetData, DevicesV1PairDevicesGetResponse, DevicesV1PairDevicesGetResponses, DeviceUnlinked, DevToken, DevTokenIn, DevTokenV1DevTokenPostData, DevTokenV1DevTokenPostError, DevTokenV1DevTokenPostErrors, DevTokenV1DevTokenPostResponse, DevTokenV1DevTokenPostResponses, DocStatus, DocumentOut, DocumentPatch, EventsV1PairOffersOfferIdEventsGetData, EventsV1PairOffersOfferIdEventsGetError, EventsV1PairOffersOfferIdEventsGetErrors, EventsV1PairOffersOfferIdEventsGetResponses, Expenses, ExpensesV1SpacesSpaceIdExpensesGetData, ExpensesV1SpacesSpaceIdExpensesGetError, ExpensesV1SpacesSpaceIdExpensesGetErrors, ExpensesV1SpacesSpaceIdExpensesGetResponse, ExpensesV1SpacesSpaceIdExpensesGetResponses, ExportV1SpacesSpaceIdExportGetData, ExportV1SpacesSpaceIdExportGetError, ExportV1SpacesSpaceIdExportGetErrors, ExportV1SpacesSpaceIdExportGetResponses, GetDocumentV1DocumentsDocIdGetData, GetDocumentV1DocumentsDocIdGetError, GetDocumentV1DocumentsDocIdGetErrors, GetDocumentV1DocumentsDocIdGetResponse, GetDocumentV1DocumentsDocIdGetResponses, GetFileV1DocumentsDocIdFileGetData, GetFileV1DocumentsDocIdFileGetError, GetFileV1DocumentsDocIdFileGetErrors, GetFileV1DocumentsDocIdFileGetResponses, GrantTo, HttpValidationError, Issue, LinkedDeviceOut, ListSpacesV1SpacesGetData, ListSpacesV1SpacesGetResponse, ListSpacesV1SpacesGetResponses, Me, MeV1MeGetData, MeV1MeGetResponse, MeV1MeGetResponses, MonthTotal, OfferCreated, OfferStatus, PairOffer, PairPhoneV1SpacesSpaceIdPairPostData, PairPhoneV1SpacesSpaceIdPairPostError, PairPhoneV1SpacesSpaceIdPairPostErrors, PairPhoneV1SpacesSpaceIdPairPostResponse, PairPhoneV1SpacesSpaceIdPairPostResponses, PatchDocumentV1DocumentsDocIdPatchData, PatchDocumentV1DocumentsDocIdPatchError, PatchDocumentV1DocumentsDocIdPatchErrors, PatchDocumentV1DocumentsDocIdPatchResponse, PatchDocumentV1DocumentsDocIdPatchResponses, QrIn, QrV1QrPostData, QrV1QrPostError, QrV1QrPostErrors, QrV1QrPostResponse, QrV1QrPostResponses, SchemaV1SchemasDocTypeGetData, SchemaV1SchemasDocTypeGetError, SchemaV1SchemasDocTypeGetErrors, SchemaV1SchemasDocTypeGetResponse, SchemaV1SchemasDocTypeGetResponses, SetBudgetsV1SpacesSpaceIdBudgetsPutData, SetBudgetsV1SpacesSpaceIdBudgetsPutError, SetBudgetsV1SpacesSpaceIdBudgetsPutErrors, SetBudgetsV1SpacesSpaceIdBudgetsPutResponse, SetBudgetsV1SpacesSpaceIdBudgetsPutResponses, SpaceIn, SpaceKind, SpaceOut, State, StatusV1PairOffersOfferIdGetData, StatusV1PairOffersOfferIdGetError, StatusV1PairOffersOfferIdGetErrors, StatusV1PairOffersOfferIdGetResponse, StatusV1PairOffersOfferIdGetResponses, Summary, SummaryV1SpacesSpaceIdSummaryGetData, SummaryV1SpacesSpaceIdSummaryGetError, SummaryV1SpacesSpaceIdSummaryGetErrors, SummaryV1SpacesSpaceIdSummaryGetResponse, SummaryV1SpacesSpaceIdSummaryGetResponses, UnlinkV1DevicesDeviceTokenIdDeleteData, UnlinkV1DevicesDeviceTokenIdDeleteError, UnlinkV1DevicesDeviceTokenIdDeleteErrors, UnlinkV1DevicesDeviceTokenIdDeleteResponse, UnlinkV1DevicesDeviceTokenIdDeleteResponses, UnlinkV1PairDevicesDeviceIdDeleteData, UnlinkV1PairDevicesDeviceIdDeleteError, UnlinkV1PairDevicesDeviceIdDeleteErrors, UnlinkV1PairDevicesDeviceIdDeleteResponse, UnlinkV1PairDevicesDeviceIdDeleteResponses, UploadV1SpacesSpaceIdDocumentsPostData, UploadV1SpacesSpaceIdDocumentsPostError, UploadV1SpacesSpaceIdDocumentsPostErrors, UploadV1SpacesSpaceIdDocumentsPostResponse, UploadV1SpacesSpaceIdDocumentsPostResponses, ValidationError } from './types.gen'; diff --git a/src/api/generated/types.gen.ts b/src/api/generated/types.gen.ts index acb47f0..72cbf05 100644 --- a/src/api/generated/types.gen.ts +++ b/src/api/generated/types.gen.ts @@ -72,6 +72,37 @@ export type ClaimIn = { device_label?: string; }; +/** + * Claimed + */ +export type Claimed = { + /** + * Offer Id + */ + offer_id: string; + /** + * Claimer Key + * + * the scanning device's private key: X-Pairkit-Key / ?key= + */ + claimer_key: string; + grant_to: GrantTo; + /** + * Scopes + */ + scopes: Array; + /** + * Shower + * + * how the device showing the QR describes itself + */ + shower: string; + /** + * Expires At + */ + expires_at: string; +}; + /** * ClientConfig * @@ -96,6 +127,23 @@ export type ClientConfig = { scopes?: string | null; }; +/** + * Collected + * + * The grant from the app's issue_grant hook, plus whatever it put in Grant.data. + */ +export type Collected = { + /** + * Token + */ + token: string; + /** + * Expires At + */ + expires_at: string | null; + [key: string]: unknown; +}; + /** * CreateOfferIn */ @@ -318,6 +366,33 @@ export type Issue = { detail: string; }; +/** + * LinkedDeviceOut + */ +export type LinkedDeviceOut = { + /** + * Id + */ + id: string; + /** + * Device + */ + device: string; + /** + * Scopes + */ + scopes: Array; + /** + * Linked At + */ + linked_at: string; + via: GrantTo; + /** + * Active + */ + active: boolean; +}; + /** * Me */ @@ -350,6 +425,66 @@ export type MonthTotal = { total: number; }; +/** + * OfferCreated + */ +export type OfferCreated = { + /** + * Offer Id + */ + offer_id: string; + /** + * Secret + * + * goes in the QR code, in the URL fragment + */ + secret: string; + /** + * Shower Key + * + * this device's private key: X-Pairkit-Key / ?key= + */ + shower_key: string; + /** + * Expires At + */ + expires_at: string; + /** + * Qr Url + * + * ready-to-encode scan link, when the router has a scan_url + */ + qr_url?: string | null; +}; + +/** + * OfferStatus + */ +export type OfferStatus = { + /** + * Offer Id + */ + offer_id: string; + state: State; + grant_to: GrantTo; + /** + * Scopes + */ + scopes: Array; + /** + * Expires At + */ + expires_at: string; + /** + * Shower + */ + shower: string; + /** + * Scanner + */ + scanner: string | null; +}; + /** * PairOffer * @@ -427,6 +562,11 @@ export type SpaceOut = { role: string; }; +/** + * State + */ +export type State = 'pending' | 'claimed' | 'approved' | 'collected' | 'denied' | 'expired'; + /** * Summary */ @@ -510,9 +650,11 @@ export type CreateOfferV1PairOffersPostResponses = { /** * Successful Response */ - 201: unknown; + 201: OfferCreated; }; +export type CreateOfferV1PairOffersPostResponse = CreateOfferV1PairOffersPostResponses[keyof CreateOfferV1PairOffersPostResponses]; + export type ClaimV1PairClaimPostData = { body: ClaimIn; path?: never; @@ -533,9 +675,11 @@ export type ClaimV1PairClaimPostResponses = { /** * Successful Response */ - 200: unknown; + 200: Claimed; }; +export type ClaimV1PairClaimPostResponse = ClaimV1PairClaimPostResponses[keyof ClaimV1PairClaimPostResponses]; + export type StatusV1PairOffersOfferIdGetData = { body?: never; headers: { @@ -567,9 +711,11 @@ export type StatusV1PairOffersOfferIdGetResponses = { /** * Successful Response */ - 200: unknown; + 200: OfferStatus; }; +export type StatusV1PairOffersOfferIdGetResponse = StatusV1PairOffersOfferIdGetResponses[keyof StatusV1PairOffersOfferIdGetResponses]; + export type EventsV1PairOffersOfferIdEventsGetData = { body?: never; path: { @@ -598,7 +744,7 @@ export type EventsV1PairOffersOfferIdEventsGetError = EventsV1PairOffersOfferIdE export type EventsV1PairOffersOfferIdEventsGetResponses = { /** - * Successful Response + * Server-sent events: state, claimed, approved, denied, collected, expired */ 200: unknown; }; @@ -628,9 +774,11 @@ export type ApproveV1PairOffersOfferIdApprovePostResponses = { /** * Successful Response */ - 200: unknown; + 200: OfferStatus; }; +export type ApproveV1PairOffersOfferIdApprovePostResponse = ApproveV1PairOffersOfferIdApprovePostResponses[keyof ApproveV1PairOffersOfferIdApprovePostResponses]; + export type DenyV1PairOffersOfferIdDenyPostData = { body?: never; path: { @@ -656,9 +804,11 @@ export type DenyV1PairOffersOfferIdDenyPostResponses = { /** * Successful Response */ - 200: unknown; + 200: OfferStatus; }; +export type DenyV1PairOffersOfferIdDenyPostResponse = DenyV1PairOffersOfferIdDenyPostResponses[keyof DenyV1PairOffersOfferIdDenyPostResponses]; + export type CollectV1PairOffersOfferIdCollectPostData = { body?: never; headers: { @@ -690,9 +840,11 @@ export type CollectV1PairOffersOfferIdCollectPostResponses = { /** * Successful Response */ - 200: unknown; + 200: Collected; }; +export type CollectV1PairOffersOfferIdCollectPostResponse = CollectV1PairOffersOfferIdCollectPostResponses[keyof CollectV1PairOffersOfferIdCollectPostResponses]; + export type DevicesV1PairDevicesGetData = { body?: never; path?: never; @@ -702,11 +854,15 @@ export type DevicesV1PairDevicesGetData = { export type DevicesV1PairDevicesGetResponses = { /** + * Response Devices V1 Pair Devices Get + * * Successful Response */ - 200: unknown; + 200: Array; }; +export type DevicesV1PairDevicesGetResponse = DevicesV1PairDevicesGetResponses[keyof DevicesV1PairDevicesGetResponses]; + export type UnlinkV1PairDevicesDeviceIdDeleteData = { body?: never; path: { @@ -732,9 +888,11 @@ export type UnlinkV1PairDevicesDeviceIdDeleteResponses = { /** * Successful Response */ - 200: unknown; + 200: LinkedDeviceOut; }; +export type UnlinkV1PairDevicesDeviceIdDeleteResponse = UnlinkV1PairDevicesDeviceIdDeleteResponses[keyof UnlinkV1PairDevicesDeviceIdDeleteResponses]; + export type PairPhoneV1SpacesSpaceIdPairPostData = { body?: never; path: { diff --git a/src/api/types.ts b/src/api/types.ts index 53af78b..a7e3180 100644 --- a/src/api/types.ts +++ b/src/api/types.ts @@ -10,17 +10,12 @@ export type { Summary, } from "./generated"; -// pairkit's pairing routes (/v1/pair/*) don't declare response models yet, so these -// mirror what pairkit returns. -export interface PairClaim { - offer_id: string; - claimer_key: string; - shower: string | null; -} -export interface PairGrant { - token: string; - space_id: string; -} +import type { Collected } from "./generated"; + +// Phone pairing (pairkit's /v1/pair/* routes): what the phone gets back when it claims a +// code, and the grant it collects. ScribbleScan's grant hook adds the space to upload to. +export type { Claimed as PairClaim } from "./generated"; +export type PairGrant = Collected & { space_id: string }; /** A locale pack's JSON Schema for one document type; fields carry "x-kind". */ export interface FieldSpec {