@usequeek/app-sdk 0.5.1 → 0.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. package/README.md +179 -12
  2. package/dist/app-auth.d.ts +9 -1
  3. package/dist/app-auth.d.ts.map +1 -1
  4. package/dist/app-auth.js +11 -1
  5. package/dist/app-auth.js.map +1 -1
  6. package/dist/auth-fetch.d.ts +91 -0
  7. package/dist/auth-fetch.d.ts.map +1 -0
  8. package/dist/auth-fetch.js +263 -0
  9. package/dist/auth-fetch.js.map +1 -0
  10. package/dist/browser.d.ts +25 -0
  11. package/dist/browser.d.ts.map +1 -0
  12. package/dist/browser.js +27 -0
  13. package/dist/browser.js.map +1 -0
  14. package/dist/client.d.ts +32 -10
  15. package/dist/client.d.ts.map +1 -1
  16. package/dist/client.js +6 -2
  17. package/dist/client.js.map +1 -1
  18. package/dist/frame.d.ts +233 -4
  19. package/dist/frame.d.ts.map +1 -1
  20. package/dist/frame.js +694 -19
  21. package/dist/frame.js.map +1 -1
  22. package/dist/handoff.d.ts +32 -2
  23. package/dist/handoff.d.ts.map +1 -1
  24. package/dist/handoff.js +2 -1
  25. package/dist/handoff.js.map +1 -1
  26. package/dist/hono.d.ts +13 -0
  27. package/dist/hono.d.ts.map +1 -1
  28. package/dist/hono.js +15 -0
  29. package/dist/hono.js.map +1 -1
  30. package/dist/index.d.ts +11 -7
  31. package/dist/index.d.ts.map +1 -1
  32. package/dist/index.js +10 -6
  33. package/dist/index.js.map +1 -1
  34. package/dist/install-handlers.d.ts +33 -8
  35. package/dist/install-handlers.d.ts.map +1 -1
  36. package/dist/install-handlers.js +133 -15
  37. package/dist/install-handlers.js.map +1 -1
  38. package/dist/merchant-schema.d.ts +1550 -68
  39. package/dist/merchant-schema.d.ts.map +1 -1
  40. package/dist/merchant-schema.js +1 -1
  41. package/dist/proxy.d.ts +122 -0
  42. package/dist/proxy.d.ts.map +1 -0
  43. package/dist/proxy.js +204 -0
  44. package/dist/proxy.js.map +1 -0
  45. package/dist/react.d.ts +78 -0
  46. package/dist/react.d.ts.map +1 -0
  47. package/dist/react.js +262 -0
  48. package/dist/react.js.map +1 -0
  49. package/dist/scopes.d.ts +174 -0
  50. package/dist/scopes.d.ts.map +1 -0
  51. package/dist/scopes.js +297 -0
  52. package/dist/scopes.js.map +1 -0
  53. package/dist/server.d.ts +1 -1
  54. package/dist/server.js +1 -1
  55. package/dist/session.d.ts +17 -5
  56. package/dist/session.d.ts.map +1 -1
  57. package/dist/session.js +35 -16
  58. package/dist/session.js.map +1 -1
  59. package/dist/store.d.ts +33 -0
  60. package/dist/store.d.ts.map +1 -1
  61. package/dist/store.js +114 -4
  62. package/dist/store.js.map +1 -1
  63. package/dist/theme.d.ts +100 -0
  64. package/dist/theme.d.ts.map +1 -0
  65. package/dist/theme.js +162 -0
  66. package/dist/theme.js.map +1 -0
  67. package/dist/tokens.d.ts +30 -15
  68. package/dist/tokens.d.ts.map +1 -1
  69. package/dist/tokens.js +57 -19
  70. package/dist/tokens.js.map +1 -1
  71. package/dist/webhooks.d.ts.map +1 -1
  72. package/dist/webhooks.js +1 -1
  73. package/dist/webhooks.js.map +1 -1
  74. package/package.json +21 -5
  75. package/CHANGELOG.md +0 -162
  76. package/openapi/merchant.json +0 -21452
package/README.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # @usequeek/app-sdk
2
2
 
3
+ > In development — not yet released. APIs may change before 1.0.
4
+
3
5
  The SDK for building a Queek app on the public Merchant API and signed webhooks. Framework-agnostic Web-standard handlers for the install handoff and topic webhooks (`Request` in, `Response` out — use them from Next.js route handlers, Express, or any runtime), a typed Merchant API client (types generated from the live contract), GitHub-style app credentials (one asymmetric key per app, short-lived per-installation tokens minted on demand), resync recovery, and an encrypted installation store (SQLite for local/test, Postgres in production). Optional Hono wrappers live under `@usequeek/app-sdk/hono`.
4
6
 
5
7
  ```sh
@@ -8,6 +10,18 @@ npm i @usequeek/app-sdk pg
8
10
 
9
11
  Requires Node `>=22.14`. `pg` is a regular dependency (the production store). `hono` is an optional peer — install it (`npm i hono`) only if you use the Hono wrappers.
10
12
 
13
+ ## Which entry do I import?
14
+
15
+ | Import | For | Pulls in |
16
+ | --- | --- | --- |
17
+ | `@usequeek/app-sdk` (main) | Server / universal code: handlers, client, stores, verifiers | `node:crypto`, `pg` — NOT browser-bundlable |
18
+ | `@usequeek/app-sdk/server` | Session-token verifier (`verifySessionToken`) | Server-only (`jose`) — never import in a browser bundle |
19
+ | `@usequeek/app-sdk/hono` | Thin Hono wrappers (`hono` optional peer) | Server-only |
20
+ | `@usequeek/app-sdk/react` | React apps (`<QueekProvider>`, `useQueek()`; `react` optional peer) | Browser-safe (built on the same bridge modules as `/browser`) |
21
+ | `@usequeek/app-sdk/browser` | Plain-browser code: `installAuthFetch` + bridge/theme helpers, no framework | Browser-safe ONLY — importing these helpers from the main entry drags in the whole barrel and breaks Vite/Rollup builds |
22
+
23
+ Browser rule of thumb: if the code ships to the browser and does not need React, import it from `@usequeek/app-sdk/browser`. `installAuthFetch` is a browser-safe MODULE, but it is not browser-safe FROM THE MAIN ENTRY — the main barrel re-exports server modules (`app-auth` → `node:crypto`, `store` → `pg`), so a bundler resolving `installAuthFetch` from `@usequeek/app-sdk` still parses those Node-only files and fails.
24
+
11
25
  The shape follows [`@shopify/shopify-api`](https://github.com/Shopify/shopify-app-js/blob/main/packages/apps/shopify-api/README.md): the core "doesn't rely on any specific framework, so you can include it alongside your preferred stack" (runtime differences are covered by adapters such as `@shopify/shopify-api/adapters/node`), and framework integrations are separate packages in the [shopify-app-js monorepo](https://github.com/Shopify/shopify-app-js) (e.g. `@shopify/shopify-app-express` and `@shopify/shopify-app-remix` build on `@shopify/shopify-api`).
12
26
 
13
27
  ## Example (any framework)
@@ -126,7 +140,7 @@ Signature verification covers the exact bytes Queek sent (`{id}.{timestamp}.{bod
126
140
 
127
141
  ### Body-size posture
128
142
 
129
- The SDK itself imposes no maximum body size (`arrayBuffer` / `TextDecoder` / `JSON.parse` are unbounded, as in 0.4.0) — the cap belongs to the framework parser in front of it, which already rejects oversized bodies before the SDK ever sees them. Queek deliveries are small JSON payloads, so the framework defaults are plenty; if you set them explicitly, `express.raw({ type: "application/json", limit: "1mb" })` and Fastify's default `bodyLimit` of 1 MiB are the recommended ceilings. No SDK option is needed unless Queek ever ships large deliveries.
143
+ The SDK itself imposes no maximum body size (`arrayBuffer` / `TextDecoder` / `JSON.parse` are unbounded) — the cap belongs to the framework parser in front of it, which already rejects oversized bodies before the SDK ever sees them. Queek deliveries are small JSON payloads, so the framework defaults are plenty; if you set them explicitly, `express.raw({ type: "application/json", limit: "1mb" })` and Fastify's default `bodyLimit` of 1 MiB are the recommended ceilings. No SDK option is needed unless Queek ever ships large deliveries.
130
144
 
131
145
  (If you already run Hono on Node, `@hono/node-server`'s `getRequestListener` bridges serving for you — but the adapters above need no extra dependency.)
132
146
 
@@ -162,8 +176,6 @@ app.route(
162
176
  export default app;
163
177
  ```
164
178
 
165
- > Migrating from 0.4.x: `import { createInstallHandlers } from "@usequeek/app-sdk/hono"` — the creators moved out of the root entry so non-Hono apps never install `hono`. The options objects are unchanged.
166
-
167
179
  Every Merchant API call goes through `createInstallationClient({ installationId, apiBase, tokens })`,
168
180
  which resolves the installation's token via `acquireToken()` and sends it as `X-Client-Key`.
169
181
 
@@ -247,6 +259,44 @@ settings) does NOT come back from resync: it needs the per-app `pg_dump` backup
247
259
  (RPO ≤ 24 h) plus the `APP_ENCRYPTION_KEY` backup. Events missed beyond Queek's webhook
248
260
  retries (~4 h) are gone; resync cannot backfill them. Full runbook: `docs/deploy.md` + O1.
249
261
 
262
+ ## Data deletion
263
+
264
+ Treat the uninstall handoff (`app/uninstalled`) as the deletion trigger: the default
265
+ `onUninstall` already deletes the installation row (secrets, token cache, settings) —
266
+ keep that delete when you override it, and purge any app-side working data keyed by the
267
+ installation there too.
268
+
269
+ Unknown topics answer 200 without running a handler (forward compatibility, not consent):
270
+ that 200 must not swallow a future privacy topic. If Queek ships mandatory privacy
271
+ topics, register explicit handlers for them — an unhandled topic only reports
272
+ `unhandled: true`, it deletes nothing.
273
+
274
+ ## Storefront app-proxy (signed reads)
275
+
276
+ Queek signs each storefront proxy fetch with the installation's `proxy_secret`
277
+ (`AppProxyService::signQuery`); verify before answering the shopper:
278
+
279
+ ```ts
280
+ import { handleProxyRequest } from "@usequeek/app-sdk";
281
+
282
+ export async function GET(request: Request) {
283
+ return handleProxyRequest(
284
+ request,
285
+ { store, path: "/apps/booking/availability" }, // Queek-side canonical path, not the local route
286
+ ({ installation, params }) =>
287
+ Response.json({ slots: slotsFor(params.date, installation.storePid) }),
288
+ );
289
+ }
290
+ ```
291
+
292
+ The canonical string is `path + "\n" + shop + "\n" + ts + "\n" + sorted(k=v&...)`
293
+ (`sig` excluded), hex HMAC-SHA256 over the FULL `whsec_…` string — no base64 decode
294
+ step. `kid` routes to the installation whose `proxy_secret` verifies (previous-secret
295
+ grace: pass every active secret to `verifyProxyQuery`); timestamps skew at most 5
296
+ minutes, each `jti` is single-use, and only `GET` is served (phase 1 is read-only).
297
+ Hono: mount `createProxyHandler({ store, path, onVerified })` from
298
+ `@usequeek/app-sdk/hono`.
299
+
250
300
  ## API surface
251
301
 
252
302
  - **app-auth** (`app-auth.ts`): `loadAppCredential` (`APP_SLUG`/`APP_KEY_ID`/`APP_PRIVATE_KEY`
@@ -267,8 +317,9 @@ retries (~4 h) are gone; resync cannot backfill them. Full runbook: `docs/deploy
267
317
  - **verify** (`signatures.ts`): `verifyQueekSignature` — Standard Webhooks verification (`webhook-id`, `webhook-timestamp`, `webhook-signature` over `{id}.{timestamp}.{body}`, keyed by the decoded `whsec_…` bytes), with timestamp-skew enforcement.
268
318
  - **delivery core** (`delivery.ts`): `CoreDelivery` (`rawBody` + `headers`) / `InstallDelivery` (+ `method`/`path`) / `DeliveryResult` (`{ status, body }`) / `CoreHeaders`, plus `readHeader` (case-insensitive, array-tolerant), `decodeBody`, and `toResponse`. Zero request/response types.
269
319
  - **install handlers** (`install-handlers.ts`): layer 1 `handleInstallDelivery(input, { appSecret, store, onInstall?, onUninstall?, onSettings? })` serves the signed install/uninstall/settings handoff from raw bytes + headers (routes on the path's trailing segment); layer 2 `handleInstallRequest(request, …)` adapts `Request` → `Response` onto it. Defaults persist the installation (encrypted) in the store; a redelivered install for an existing installation merges idempotently (`saveResyncedInstallation`). The Hono wrapper `createInstallHandlers` lives under `@usequeek/app-sdk/hono` (`hono.ts`).
270
- - **client** (`client.ts`): `createQueekClient({ apiBase, apiKey })` — the low-level typed fetch client over the Merchant API (`X-Client-Key`), with `Idempotency-Key` on writes, typed `QueekApiError`s, and 429 retry helpers. Types come from `openapi/merchant.json`, the committed snapshot of the live contract. Prefer `createInstallationClient` in apps.
271
- - **webhooks** (`webhooks.ts`): layer 1 `handleWebhookDelivery(input, { store, handlers })` verifies each delivery against the installation's endpoint secret, dedupes on `webhook-id`, and dispatches `topic → handler` at most once; layer 2 `handleWebhookRequest(request, …)` adapts `Request` → `Response` onto it. The Hono wrapper `createWebhookHandler` lives under `@usequeek/app-sdk/hono` (`hono.ts`).
320
+ - **client** (`client.ts`): `createQueekClient({ apiBase, apiKey })` — the low-level typed fetch client over the Merchant API (`X-Client-Key`), with `Idempotency-Key` on writes, typed `QueekApiError`s, and 429 retry helpers. Both it and `createInstallationClient({ installationId, apiBase, tokens })` are generic (`<AppPaths>`, default: the bundled `merchant-schema.ts` compat shim): pass the app's own codegen output for current types with zero SDK publish. The default does NOT auto-update (re-run codegen in the app; sunset signal at 1.0). `openapi/merchant.json` stays in-repo as `gen:merchant`'s reference input and is not shipped in the published package. Prefer `createInstallationClient` in apps.
321
+ - **webhooks** (`webhooks.ts`): layer 1 `handleWebhookDelivery(input, { store, handlers })` verifies each delivery against the installation's endpoint secret, dedupes on `webhook-id`, and dispatches `topic → handler` at most once; layer 2 `handleWebhookRequest(request, …)` adapts `Request` → `Response` onto it. The Hono wrapper `createWebhookHandler` lives under `@usequeek/app-sdk/hono` (`hono.ts`). Unknown topics answer 200 `unhandled` — see Data deletion before relying on that.
322
+ - **proxy** (`proxy.ts`): `verifyProxyQuery` / `verifyProxyQueryDetailed` — app-proxy query verification byte-exact with the backend (`path\nshop\nts\nsorted(k=v&...)`, hex HMAC-SHA256 over the FULL `whsec_…` string, 5-minute skew floored at 60 s, `timingSafeEqual`, previous-secret grace over the secrets list); layer 1 `verifyProxyDelivery(input, { store, … })` resolves the installation from the store by `kid` and claims single-use `jti`; layer 2 `handleProxyRequest(request, { store, path, … }, onVerified)` serves GET only. The Hono wrapper `createProxyHandler` lives under `@usequeek/app-sdk/hono` (`hono.ts`).
272
323
  - **store** (`store.ts`): `SqliteInstallationStore` (local/dev/test) and `PostgresInstallationStore`
273
324
  (`pg`, pool max 2, advisory-locked schema + `schema_version` row so two containers boot
274
325
  safely) — installations encrypted at rest (AES-GCM via `APP_ENCRYPTION_KEY`), plus the
@@ -284,16 +335,130 @@ retries (~4 h) are gone; resync cannot backfill them. Full runbook: `docs/deploy
284
335
  PEM private-key blocks — the app JWT and private key can never reach logs.
285
336
  - **session** (`session.ts`, server-only via `@usequeek/app-sdk/server`):
286
337
  `verifySessionToken` — HS256 dashboard session tokens minted per installation
287
- (`embsec_…` secret, raw UTF-8 key bytes, 20 s clock tolerance, slug audience
288
- + api_base issuer, full installation binding). The secret never enters a
338
+ (`embsec_…` secret, raw UTF-8 key bytes, 20 s clock tolerance, slug audience,
339
+ issuer = the handoff `apiBase` verbatim (`installation.apiBase` — it equals the
340
+ bare `app.url` the backend signs as `iss`), full installation binding). One token
341
+ type, exactly Shopify's `id_token`: the dashboard puts the same token in the
342
+ first-load URL param (`queek_token`, stripped on arrival) and answers bridge
343
+ `ready` requests with it, so the app's exchange endpoint verifies first-load and
344
+ refresh tokens with this one verifier — no purpose split, extra claims are
345
+ ignored. The secret never enters a
289
346
  browser bundle: the main entry does not export the verifier. The install
290
347
  and resync handoffs deliver `embed_secret` + `app_id`; the store keeps
291
348
  them on the installation (`embedSecret` encrypted, `appId`), and
292
349
  `sessionTokenInstallationId` reads the token's `installation_id` as an
293
350
  unverified routing hint so a server can load that row before verifying.
294
- - **frame** (`frame.ts`, browser-safe, no secret): `listenToDashboard`
295
- (accepts only the exact dashboard origin) and `sendReady` (exact target
296
- origin, never `"*"`).
351
+ - **frame** (`frame.ts`, browser-safe, no secret): the embedded-app bridge
352
+ v1 — typed unions both directions (`ready{capabilities,sdkVersion}`,
353
+ `theme`, `title`/`title-action`, `toast`, `save-bar`/`save-bar-action`,
354
+ `navigate`/`navigated`, `open`, `pick-resource`/`resource-picked`/
355
+ `resource-pick-cancelled`), unknown types ignored, every outbound string
356
+ length-capped client-side. `listenToDashboard` (accepts only the exact
357
+ dashboard origin, plus an `expectSource` window check) and typed senders
358
+ (`sendReady`, `sendToast`, `sendSaveBar`, `sendTitle`, `sendNavigated`,
359
+ `sendOpen`, `sendPickResource`, …) to the exact target origin, never `"*"`.
360
+ `parseOutboundMessage` runs the same per-type validation the dashboard
361
+ runs — the dashboard re-validates everything before acting (open targets,
362
+ title/toast/pick content), so a compromised frame cannot smuggle
363
+ `javascript:` URLs or uncapped strings through the bridge. `open` targets
364
+ are a dashboard-relative path or an absolute `https:` URL; backslashes,
365
+ control characters, protocol-relative URLs and every other scheme are
366
+ refused (by `clipOutbound` as well as `isAllowedOpenTarget`).
367
+
368
+ **Bridge handshake.** The app announces `ready{capabilities,sdkVersion}`;
369
+ the dashboard answers with its `theme` message, which also declares the
370
+ DASHBOARD's capabilities: `{ type: "theme", mode, locale?, capabilities?:
371
+ string[], bridge?: "1" }` (same caps as outbound: at most 32 entries of 64
372
+ characters). `listenToDashboard` exposes both on the `BridgeTheme` passed to
373
+ `onTheme`. A dashboard that omits `capabilities` is legacy (ready/token/
374
+ resize only). `<QueekProvider>` stores the declared set: `pickResource`
375
+ rejects at once when it lacks `pick-resource`, waits up to 1.5 s after
376
+ `ready` when the set is still unknown, and rejects if no handshake arrives.
377
+ Each pick carries a `requestId` (on `pick-resource`); a dashboard that
378
+ declares `pick-resource` MUST echo it on `resource-picked` / `resource-pick-cancelled` — answers with a
379
+ different or missing id are dropped as stale.
380
+ - **auth** (`auth-fetch.ts`, no secret — browser-safe as a module, but import it
381
+ from `@usequeek/app-sdk/browser` in browser bundles, never from the main
382
+ entry): `installAuthFetch({ exchange })`
383
+ — reads the dashboard token (`queek_token` query param) from the first
384
+ load, strips it with `history.replaceState`, exchanges it once for the
385
+ app's own session, attaches `Authorization: Bearer <session>` to
386
+ same-origin fetch (cookies stay out), and re-establishes via the bridge
387
+ `ready→token` flow + one retry on 401. Session recovery runs only when framed (a post target other than the
388
+ window itself) and is not retried per request after a failed attempt — only
389
+ after a later dashboard token arrives. Pass the same `capabilities`/
390
+ `sdkVersion` as the provider so its refresh `ready` announces one consistent set. The app's
391
+ token-exchange endpoint receives the first-load token and every 401-refresh
392
+ token through the same `exchange` callback — one token type, so it verifies
393
+ both with the single `verifySessionToken` verifier:
394
+
395
+ ```ts
396
+ import { verifySessionTokenDetailed } from "@usequeek/app-sdk/server";
397
+
398
+ async function exchange(token: string): Promise<string> {
399
+ const options = { secret: installation.embedSecret!, audience: "my-app", issuer: installation.apiBase, expected };
400
+ const checked = await verifySessionTokenDetailed(token, options);
401
+ if (!checked.ok) throw Object.assign(new Error("unauthorized"), { status: 401 });
402
+ return mintAppSession(checked.claims);
403
+ }
404
+ ```
405
+ - **theme** (`theme.ts`, browser-safe, no secret): `applyTheme(mode)` toggles
406
+ `.dark` on `<html>` + `color-scheme` (shadcn's dark-mode mechanism);
407
+ `themeBootstrapScript()` returns the inline `<head>` snippet that reads the
408
+ unsigned `theme` URL param before first paint (no flash — a first-paint hint
409
+ only, validated to `light`|`dark`, overwritten by the live bridge message);
410
+ `installThemeListener` follows live bridge `theme{mode}` messages (only from
411
+ `window.parent` by default; pass `expectSource` to override). The live mode is
412
+ remembered in `sessionStorage`, and the bootstrap script falls back to it when
413
+ the URL carries no `theme` param, so an in-frame reload never flashes light. Every live `theme` message also
414
+ rewrites the `theme` URL param (other params kept) so a stale first-load param
415
+ never beats the current mode on reload, and the first-load mode is remembered
416
+ too (a legacy dashboard that never sends `theme` still reloads flash-free).
417
+ - **react** (`react.ts`, via `@usequeek/app-sdk/react` — `react` is an
418
+ optional peer, same pattern as `./hono`): `<QueekProvider>` owns one
419
+ bridge subscription; `useQueek()` returns `{ toast, saveBar, title,
420
+ navigate, pickResource, theme }` over the framework-free core.
421
+ - **scopes** (`scopes.ts`): `createInstallationScopesClient({ installationId, store, signJwt, … })`
422
+ — the optional-scopes session, wired to the same store + token provider as the
423
+ installation client. `queryScopes` reads the cached grant (no network);
424
+ `requestScopes` builds the dashboard consent link (pure — the SDK never
425
+ renders consent); `revokeScopes` posts the app-authenticated revoke and
426
+ refreshes the cache. The install/settings handlers accept the signed
427
+ `app/scopes_update` handoff on both routes and refresh the cached grant
428
+ (dropping the cached token when it moved).
429
+
430
+ ## Scopes
431
+
432
+ Apps declare required scopes (granted at install) plus optional scopes
433
+ (requested later, revocable). The per-installation session covers the app side:
434
+
435
+ ```ts
436
+ import { createInstallationScopesClient } from "@usequeek/app-sdk";
437
+
438
+ const scopes = createInstallationScopesClient({
439
+ installationId,
440
+ store,
441
+ signJwt: () => provider.signJwt(),
442
+ appSlug: "my-app",
443
+ optionalScopes: ["merchant-orders-read"], // the app's own manifest knowledge
444
+ });
445
+
446
+ await scopes.queryScopes(); // { granted, optional } — cached, no network
447
+ scopes.requestScopes(["merchant-orders-read"]); // dashboard consent link (open via sendOpen)
448
+ await scopes.revokeScopes(["merchant-orders-read"]); // 422 app_scope_required → AppScopeRequiredError
449
+ ```
450
+
451
+ `queryScopes` splits the cached effective grant against the declared-optional
452
+ list you pass (the app surface exposes the grant but no declared list, so the
453
+ split needs your manifest knowledge). `requestScopes` returns
454
+ `/apps?app={slug}&view=scopes&scopes={a},{b}` (absolute under
455
+ `dashboardOrigin` when configured) — open it via `sendOpen` or a redirect: it
456
+ opens the merchant's consent screen in the dashboard (shipped with dashboard
457
+ item 8). The link carries the slug + the scope list only; the dashboard
458
+ resolves the installation from the signed-in store. The grant reaches you as a
459
+ signed `app/scopes_update` handoff, which the install/settings handlers apply
460
+ like a resync (same verifier, same replay claim): cached grant refreshed,
461
+ cached token dropped only when the grant moved.
297
462
 
298
463
  ## Embedded merchant page (S4 stage 2)
299
464
 
@@ -309,8 +474,10 @@ Content-Security-Policy: frame-ancestors https://merchant.queek.com
309
474
  Replace the host with the dashboard origin you registered. `frame-ancestors`
310
475
  is a docs-only control the dashboard cannot enforce for you: without it any
311
476
  site may frame the page, and the token handshake (origin-bound) is your only
312
- remaining gate. Verify every token server-side with `verifySessionToken`
313
- before trusting calls that carry one.
477
+ remaining gate. Verify every token server-side before trusting calls that carry one:
478
+ the token-exchange endpoint receives the first-load token and every 401-refresh
479
+ token through the same `installAuthFetch({ exchange })` callback — one token type,
480
+ verified with the single `verifySessionToken` verifier (see the `auth` entry above).
314
481
 
315
482
  ## Local development
316
483
 
@@ -38,6 +38,12 @@ export declare const APP_INSTALLATION_PENDING_CODE = "app_installation_pending";
38
38
  export declare const RESYNC_COOLDOWN_CODE = "resync_cooldown";
39
39
  /** 429 everywhere: honor `Retry-After`, jittered. */
40
40
  export declare const TOO_MANY_REQUESTS_CODE = "too_many_requests";
41
+ /**
42
+ * 403 on a merchant call: the cached installation token was minted for an
43
+ * older grant (missing scope). The grant changed server-side — drop the
44
+ * cached token, re-mint once, retry once.
45
+ */
46
+ export declare const INSUFFICIENT_SCOPE_CODE = "insufficient_scope";
41
47
  /** True when a Queek error code is the kill-switch/disabled refusal. */
42
48
  export declare function isAppTokenRevoked(code: string | undefined): boolean;
43
49
  /** True when a Queek error code is the fatal app-credential refusal. */
@@ -53,7 +59,7 @@ export declare function isResyncCooldown(code: string | undefined): boolean;
53
59
  * is dead — drop it, re-mint once, retry once. `api_key_revoked` covers the
54
60
  * uninstalled store, the removed kid, and the replaced K-slot; the re-mint
55
61
  * then answers 404 `app_installation_gone` (purge) or 401 `invalid_client`
56
- * (halt) where applicable. Every OTHER merchant 403 (scope, plan, mode)
62
+ * (halt) where applicable. Every OTHER merchant 403 (plan, mode)
57
63
  * propagates to the caller without a mint.
58
64
  */
59
65
  export declare const API_KEY_REVOKED_CODE = "api_key_revoked";
@@ -66,6 +72,8 @@ export declare const INVALID_CLIENT_KEY_CODE = "invalid_client_key";
66
72
  * halt), not a single dead token.
67
73
  */
68
74
  export declare function isTokenRefusal(status: number, code: string | undefined): boolean;
75
+ /** True when a merchant-API 403 means the cached token predates a grant change. */
76
+ export declare function isInsufficientScope(status: number, code: string | undefined): boolean;
69
77
  /** App-JWT `iat` is backdated this far (clock skew, GitHub's recommendation). */
70
78
  export declare const APP_JWT_SKEW_SECONDS = 60;
71
79
  /** App-JWT lifetime: `exp = iat + 540`, so `exp − iat` (540 s) stays ≤ the 600 s wire bound. */
@@ -1 +1 @@
1
- {"version":3,"file":"app-auth.d.ts","sourceRoot":"","sources":["../src/app-auth.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"app-auth.d.ts","sourceRoot":"","sources":["../src/app-auth.ts"],"names":[],"mappings":"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"}
package/dist/app-auth.js CHANGED
@@ -44,6 +44,12 @@ export const APP_INSTALLATION_PENDING_CODE = "app_installation_pending";
44
44
  export const RESYNC_COOLDOWN_CODE = "resync_cooldown";
45
45
  /** 429 everywhere: honor `Retry-After`, jittered. */
46
46
  export const TOO_MANY_REQUESTS_CODE = "too_many_requests";
47
+ /**
48
+ * 403 on a merchant call: the cached installation token was minted for an
49
+ * older grant (missing scope). The grant changed server-side — drop the
50
+ * cached token, re-mint once, retry once.
51
+ */
52
+ export const INSUFFICIENT_SCOPE_CODE = "insufficient_scope";
47
53
  /** True when a Queek error code is the kill-switch/disabled refusal. */
48
54
  export function isAppTokenRevoked(code) {
49
55
  return code === APP_TOKEN_REVOKED_CODE;
@@ -69,7 +75,7 @@ export function isResyncCooldown(code) {
69
75
  * is dead — drop it, re-mint once, retry once. `api_key_revoked` covers the
70
76
  * uninstalled store, the removed kid, and the replaced K-slot; the re-mint
71
77
  * then answers 404 `app_installation_gone` (purge) or 401 `invalid_client`
72
- * (halt) where applicable. Every OTHER merchant 403 (scope, plan, mode)
78
+ * (halt) where applicable. Every OTHER merchant 403 (plan, mode)
73
79
  * propagates to the caller without a mint.
74
80
  */
75
81
  export const API_KEY_REVOKED_CODE = "api_key_revoked";
@@ -87,6 +93,10 @@ export function isTokenRefusal(status, code) {
87
93
  return (status === 403 &&
88
94
  (code === API_KEY_REVOKED_CODE || code === API_KEY_EXPIRED_CODE || code === INVALID_CLIENT_KEY_CODE));
89
95
  }
96
+ /** True when a merchant-API 403 means the cached token predates a grant change. */
97
+ export function isInsufficientScope(status, code) {
98
+ return status === 403 && code === INSUFFICIENT_SCOPE_CODE;
99
+ }
90
100
  // ---------------------------------------------------------------------------
91
101
  // Timing bounds (all in the open, all injectable in tests).
92
102
  // ---------------------------------------------------------------------------
@@ -1 +1 @@
1
- {"version":3,"file":"app-auth.js","sourceRoot":"","sources":["../src/app-auth.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"app-auth.js","sourceRoot":"","sources":["../src/app-auth.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,91 @@
1
+ /**
2
+ * Same-origin session carriage for embedded apps (U-validation "Auth
3
+ * carriage"): `installAuthFetch()` reads the dashboard token from the
4
+ * first-load URL (`?queek_token=`, stripped immediately), exchanges it
5
+ * ONCE for the app's own session, and attaches
6
+ * `Authorization: Bearer <session>` to every same-origin fetch. A 401
7
+ * re-establishes the session via the bridge `ready→token` flow and retries
8
+ * once. Cookies stay out (`credentials: "omit"` on handled requests —
9
+ * the cross-site iframe cannot rely on them anyway).
10
+ *
11
+ * The caller supplies `exchange(token) => session`: the app's own endpoint
12
+ * that verifies the dashboard token server-side with the single
13
+ * `verifySessionToken` verifier and mints the app session — the exchange
14
+ * runs once on the first load so the first paint needs no bridge
15
+ * round-trip, and again (same callback) with a fresh token of the same
16
+ * type after every 401 refresh. This module never sees secrets — it only
17
+ * carries opaque tokens.
18
+ *
19
+ * DOM-free by design (like `frame.ts`): location/history access is
20
+ * injectable and defaults to the global window when present.
21
+ */
22
+ import { type EmbedEventTarget, type EmbedPostTarget } from "./frame.js";
23
+ /**
24
+ * Dashboard token query param on the first load. Matches the dashboard
25
+ * frame src contract (the ONLY token that may ride a URL, namespaced so it
26
+ * cannot collide with an app's own `token` param). The token is the same
27
+ * type the bridge `ready→token` flow returns on refresh — first load and
28
+ * refresh differ only in transport (URL param vs postMessage), exactly
29
+ * Shopify's `id_token`.
30
+ */
31
+ export declare const LAUNCH_TOKEN_PARAM = "queek_token";
32
+ /** How long to wait for the dashboard's token reply after a `ready`. */
33
+ export declare const BRIDGE_TOKEN_TIMEOUT_MS = 8000;
34
+ export interface AuthFetchOptions {
35
+ /**
36
+ * Exchange a dashboard token for the app's own session (caller's endpoint).
37
+ * The endpoint receives the first-load token and every 401-refresh token
38
+ * through this same callback — one token type, so it verifies both with
39
+ * the single `verifySessionToken` verifier.
40
+ */
41
+ exchange: (token: string) => Promise<string>;
42
+ /** Exact dashboard origin for the `ready→token` refresh flow. */
43
+ dashboardOrigin: string;
44
+ /** First-load token query param (default `queek_token`). */
45
+ param?: string;
46
+ /** postMessage target for `ready` (defaults to the global window's parent). */
47
+ postTarget?: EmbedPostTarget;
48
+ /**
49
+ * Capabilities announced in the refresh `ready` — pass the SAME list as the
50
+ * React provider / theme listener so the dashboard sees one consistent set.
51
+ */
52
+ capabilities?: string[];
53
+ /** SDK version announced in the refresh `ready`. */
54
+ sdkVersion?: string;
55
+ /** message-event target for the token reply (defaults to the global window). */
56
+ listenTarget?: EmbedEventTarget;
57
+ /**
58
+ * Required `event.source` for bridge messages. Defaults to the global
59
+ * window's parent when present (the embedding dashboard); pass `null` to
60
+ * disable the source check.
61
+ */
62
+ expectSource?: unknown;
63
+ /** fetch implementation (defaults to the global fetch). */
64
+ fetchImpl?: typeof fetch;
65
+ /** Current href (defaults to the global window location). */
66
+ getHref?: () => string;
67
+ /** Replace the URL without navigating (defaults to history.replaceState). */
68
+ replaceUrl?: (url: string) => void;
69
+ }
70
+ export interface InstalledAuth {
71
+ /** Session-carrying fetch: same-origin requests gain the session as a Bearer token, and a 401 retries once after a refresh. */
72
+ fetch: (input: string | URL | Request, init?: RequestInit) => Promise<Response>;
73
+ /** Current app session, or null before the exchange settles / without a token. */
74
+ getSession: () => string | null;
75
+ /** Settles to the session, or null when there is no launch token to exchange. */
76
+ ready: Promise<string | null>;
77
+ /** Re-establish the session via the bridge `ready→token` flow. */
78
+ refresh: () => Promise<string>;
79
+ /** Unsubscribe the bridge token listener. */
80
+ dispose: () => void;
81
+ }
82
+ /** Read the first-load token from a URL without touching it. */
83
+ export declare function readLaunchToken(href: string, param?: string): string | null;
84
+ /**
85
+ * Strip the first-load token from a URL (every other param, plus the hash,
86
+ * is preserved). Returns the stripped href, or null when no token is
87
+ * present.
88
+ */
89
+ export declare function stripLaunchToken(href: string, param?: string): string | null;
90
+ export declare function installAuthFetch(options: AuthFetchOptions): InstalledAuth;
91
+ //# sourceMappingURL=auth-fetch.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth-fetch.d.ts","sourceRoot":"","sources":["../src/auth-fetch.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,EAAE,KAAK,gBAAgB,EAAE,KAAK,eAAe,EAAgC,MAAM,YAAY,CAAC;AAEvG;;;;;;;GAOG;AACH,eAAO,MAAM,kBAAkB,gBAAgB,CAAC;AAEhD,wEAAwE;AACxE,eAAO,MAAM,uBAAuB,OAAO,CAAC;AAE5C,MAAM,WAAW,gBAAgB;IAC/B;;;;;OAKG;IACH,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IAC7C,iEAAiE;IACjE,eAAe,EAAE,MAAM,CAAC;IACxB,4DAA4D;IAC5D,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,+EAA+E;IAC/E,UAAU,CAAC,EAAE,eAAe,CAAC;IAC7B;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,oDAAoD;IACpD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gFAAgF;IAChF,YAAY,CAAC,EAAE,gBAAgB,CAAC;IAChC;;;;OAIG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,2DAA2D;IAC3D,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;IACzB,6DAA6D;IAC7D,OAAO,CAAC,EAAE,MAAM,MAAM,CAAC;IACvB,6EAA6E;IAC7E,UAAU,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;CACpC;AAED,MAAM,WAAW,aAAa;IAC5B,+HAA+H;IAC/H,KAAK,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,GAAG,GAAG,OAAO,EAAE,IAAI,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;IAChF,kFAAkF;IAClF,UAAU,EAAE,MAAM,MAAM,GAAG,IAAI,CAAC;IAChC,iFAAiF;IACjF,KAAK,EAAE,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAC9B,kEAAkE;IAClE,OAAO,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;IAC/B,6CAA6C;IAC7C,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAeD,gEAAgE;AAChE,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,GAAE,MAA2B,GAAG,MAAM,GAAG,IAAI,CAO/F;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,GAAE,MAA2B,GAAG,MAAM,GAAG,IAAI,CAWhG;AAED,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,gBAAgB,GAAG,aAAa,CAqNzE"}