@usequeek/app-sdk 0.6.0 → 0.6.2

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 (88) hide show
  1. package/README.md +97 -78
  2. package/dist/app-auth.d.ts +14 -15
  3. package/dist/app-auth.d.ts.map +1 -1
  4. package/dist/app-auth.js +19 -21
  5. package/dist/app-auth.js.map +1 -1
  6. package/dist/auth-fetch.d.ts +22 -23
  7. package/dist/auth-fetch.d.ts.map +1 -1
  8. package/dist/auth-fetch.js +22 -22
  9. package/dist/auth-fetch.js.map +1 -1
  10. package/dist/background.d.ts +1 -1
  11. package/dist/browser.d.ts +25 -0
  12. package/dist/browser.d.ts.map +1 -0
  13. package/dist/browser.js +27 -0
  14. package/dist/browser.js.map +1 -0
  15. package/dist/client.d.ts +8 -9
  16. package/dist/client.d.ts.map +1 -1
  17. package/dist/client.js +2 -2
  18. package/dist/client.js.map +1 -1
  19. package/dist/collected.d.ts +13 -14
  20. package/dist/collected.d.ts.map +1 -1
  21. package/dist/collected.js +4 -4
  22. package/dist/collected.js.map +1 -1
  23. package/dist/crypto.js +3 -3
  24. package/dist/crypto.js.map +1 -1
  25. package/dist/delivery.d.ts +4 -8
  26. package/dist/delivery.d.ts.map +1 -1
  27. package/dist/delivery.js +4 -8
  28. package/dist/delivery.js.map +1 -1
  29. package/dist/frame.d.ts +11 -11
  30. package/dist/frame.d.ts.map +1 -1
  31. package/dist/frame.js +11 -11
  32. package/dist/frame.js.map +1 -1
  33. package/dist/handoff.d.ts +35 -38
  34. package/dist/handoff.d.ts.map +1 -1
  35. package/dist/handoff.js +9 -9
  36. package/dist/hono.d.ts +3 -3
  37. package/dist/hono.js +3 -3
  38. package/dist/install-handlers.d.ts +6 -7
  39. package/dist/install-handlers.d.ts.map +1 -1
  40. package/dist/install-handlers.js +11 -11
  41. package/dist/install-handlers.js.map +1 -1
  42. package/dist/logger.js +1 -1
  43. package/dist/logger.js.map +1 -1
  44. package/dist/merchant-schema.d.ts +14882 -6288
  45. package/dist/merchant-schema.d.ts.map +1 -1
  46. package/dist/proxy.d.ts +20 -22
  47. package/dist/proxy.d.ts.map +1 -1
  48. package/dist/proxy.js +19 -20
  49. package/dist/proxy.js.map +1 -1
  50. package/dist/react.d.ts +1 -1
  51. package/dist/react.js +1 -1
  52. package/dist/resync.d.ts +4 -4
  53. package/dist/resync.d.ts.map +1 -1
  54. package/dist/resync.js +4 -4
  55. package/dist/resync.js.map +1 -1
  56. package/dist/scopes.d.ts +22 -26
  57. package/dist/scopes.d.ts.map +1 -1
  58. package/dist/scopes.js +19 -23
  59. package/dist/scopes.js.map +1 -1
  60. package/dist/server.d.ts +3 -3
  61. package/dist/server.d.ts.map +1 -1
  62. package/dist/server.js +2 -2
  63. package/dist/server.js.map +1 -1
  64. package/dist/session.d.ts +16 -55
  65. package/dist/session.d.ts.map +1 -1
  66. package/dist/session.js +16 -86
  67. package/dist/session.js.map +1 -1
  68. package/dist/signatures.d.ts +5 -4
  69. package/dist/signatures.d.ts.map +1 -1
  70. package/dist/signatures.js +7 -6
  71. package/dist/signatures.js.map +1 -1
  72. package/dist/store.d.ts +20 -25
  73. package/dist/store.d.ts.map +1 -1
  74. package/dist/store.js +16 -19
  75. package/dist/store.js.map +1 -1
  76. package/dist/theme.d.ts +10 -6
  77. package/dist/theme.d.ts.map +1 -1
  78. package/dist/theme.js +10 -6
  79. package/dist/theme.js.map +1 -1
  80. package/dist/tokens.d.ts +9 -9
  81. package/dist/tokens.d.ts.map +1 -1
  82. package/dist/tokens.js +9 -10
  83. package/dist/tokens.js.map +1 -1
  84. package/dist/webhooks.d.ts +2 -3
  85. package/dist/webhooks.d.ts.map +1 -1
  86. package/dist/webhooks.js +2 -3
  87. package/dist/webhooks.js.map +1 -1
  88. package/package.json +8 -3
package/README.md CHANGED
@@ -1,16 +1,39 @@
1
1
  # @usequeek/app-sdk
2
2
 
3
- > In development — not yet released. APIs may change before 1.0.
4
-
5
3
  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`.
6
4
 
5
+ Full guide: <https://docs.usequeek.com/docs/apps/sdk>.
6
+
7
+ > Pre-1.0: the API can still change; pin the exact version (`npm i @usequeek/app-sdk@<version>`).
8
+
7
9
  ```sh
8
10
  npm i @usequeek/app-sdk pg
9
11
  ```
10
12
 
11
13
  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.
12
14
 
13
- 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`).
15
+ ## Quick start for AI agents
16
+
17
+ Register the app on the Queek Developer page, then use the CLI:
18
+
19
+ 1. Scaffold: `npm create @usequeek/app my-app` (same as `queek app init`).
20
+ 2. Develop: `queek app dev` — tunnel + dev-store install; mints credentials into `.queek/.env.local` on first run.
21
+ 3. Deploy: `queek app deploy` — pushes `queek.app.toml` as a new version (secret shown once, also written to `.queek/.env.local`). In CI, authenticate with a per-app App Automation Token from the Developer page (`QUEEK_APP_AUTOMATION_TOKEN`).
22
+ 4. Import from the entry table below: `@usequeek/app-sdk` for server code, `@usequeek/app-sdk/browser` (or `/react`) for browser code — never the main entry in a browser bundle.
23
+ 5. Serve the install/uninstall/settings handoff (`handleInstallRequest`) and topic webhooks (`handleWebhookRequest`), then call the Merchant API via `createInstallationClient`.
24
+ 6. Capabilities: the live list of scopes, webhook topics and other platform capabilities is served at `https://api.usequeek.com/docs/capabilities.json`; bridge capabilities are in the `queek-bridge` skill of [queek-ai-toolkit](https://github.com/usequeek/queek-ai-toolkit) (`references/bridge-spec.md`). Confirm scope and topic names with `queek app deploy`'s validator rather than a baked-in list.
25
+
26
+ ## Which entry do I import?
27
+
28
+ | Import | For | Pulls in |
29
+ | --- | --- | --- |
30
+ | `@usequeek/app-sdk` (main) | Server / universal code: handlers, client, stores, verifiers | `node:crypto`, `pg` — NOT browser-bundlable |
31
+ | `@usequeek/app-sdk/server` | Session-token verifier (`verifySessionToken`) | Server-only (`jose`) — never import in a browser bundle |
32
+ | `@usequeek/app-sdk/hono` | Thin Hono wrappers (`hono` optional peer) | Server-only |
33
+ | `@usequeek/app-sdk/react` | React apps (`<QueekProvider>`, `useQueek()`; `react` optional peer) | Browser-safe (built on the same bridge modules as `/browser`) |
34
+ | `@usequeek/app-sdk/browser` | Plain-browser code: `installAuthFetch` + bridge/theme helpers, no framework | Browser-safe ONLY |
35
+
36
+ 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 (Vite/Rollup builds break).
14
37
 
15
38
  ## Example (any framework)
16
39
 
@@ -124,17 +147,15 @@ fastify.post("/api/webhooks", async (req, reply) => {
124
147
 
125
148
  ### Why the raw body matters
126
149
 
127
- Signature verification covers the exact bytes Queek sent (`{id}.{timestamp}.{body}`), not the parsed JSON value — so the SDK takes the untouched body bytes at every layer. A parsed-then-restringified body has different bytes (spacing, key order) and will NOT verify. A string `rawBody` is used verbatim, so only pass a string when it is already the exact UTF-8 text — otherwise prefer `Buffer`/`Uint8Array` straight from `express.raw`, Fastify's `parseAs: "buffer"`, or `await request.arrayBuffer()`. This is Stripe's model (`stripe.webhooks.constructEvent(rawBody, sigHeader, secret)`): [their docs](https://docs.stripe.com/webhooks) put it bluntly — "Stripe requires the raw body of the request to perform signature verification… Any manipulation to the raw body of the request causes the verification to fail." In practice: Express needs `express.raw(...)` (never `express.json()`) on webhook routes, Fastify needs `addContentTypeParser` with `parseAs: "buffer"`, and in Next.js you read `await request.arrayBuffer()` (the SDK's layer 2 already does) rather than `await request.json()`.
150
+ Signature verification covers the exact bytes Queek sent (`{id}.{timestamp}.{body}`, as defined by the [Standard Webhooks](https://github.com/standard-webhooks/standard-webhooks/blob/main/spec/standard-webhooks.md) spec), not the parsed JSON value — so the SDK takes the untouched body bytes at every layer. A parsed-then-restringified body has different bytes (spacing, key order) and will NOT verify. A string `rawBody` is used verbatim, so only pass a string when it is already the exact UTF-8 text — otherwise prefer `Buffer`/`Uint8Array` straight from `express.raw`, Fastify's `parseAs: "buffer"`, or `await request.arrayBuffer()`. In practice: Express needs `express.raw(...)` (never `express.json()`) on webhook routes, Fastify needs `addContentTypeParser` with `parseAs: "buffer"`, and in Next.js you read `await request.arrayBuffer()` (the SDK's layer 2 already does) rather than `await request.json()`.
128
151
 
129
152
  ### Body-size posture
130
153
 
131
- 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.
132
-
133
- (If you already run Hono on Node, `@hono/node-server`'s `getRequestListener` bridges serving for you — but the adapters above need no extra dependency.)
154
+ 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. The SDK has no body-size option.
134
155
 
135
156
  ### Hono
136
157
 
137
- Prefer Hono? The thin wrappers under `@usequeek/app-sdk/hono` (same options, same behaviour, same errors/status codes) mount the same core:
158
+ Prefer Hono? The thin wrappers under `@usequeek/app-sdk/hono` (same options, same behaviour, same errors/status codes) mount the same core. (If you already run Hono on Node, `@hono/node-server`'s `getRequestListener` bridges serving for you.)
138
159
 
139
160
  ```ts
140
161
  import { SqliteInstallationStore } from "@usequeek/app-sdk";
@@ -167,28 +188,33 @@ export default app;
167
188
  Every Merchant API call goes through `createInstallationClient({ installationId, apiBase, tokens })`,
168
189
  which resolves the installation's token via `acquireToken()` and sends it as `X-Client-Key`.
169
190
 
170
- ## Credential lifecycle (S1: GitHub-style installation tokens)
191
+ ## Credential lifecycle (GitHub-style installation tokens)
171
192
 
172
- One asymmetric credential per app — no per-installation secrets cross the handoff any more.
193
+ One asymmetric credential per app — no per-installation secrets cross the handoff.
173
194
 
174
- 1. **Generate a keypair** (once, offline) and keep the private key in the founder's password
175
- manager beside `APP_ENCRYPTION_KEY` (key + DB loss = working data lost — see below):
195
+ 1. **Keypair — two paths.** (a) Offline: generate locally, then upload the PUBLIC key on
196
+ the Developer page (Keys) — Queek never receives the private key:
176
197
 
177
198
  ```sh
178
199
  openssl genrsa -out app-private.pem 2048
179
200
  openssl rsa -in app-private.pem -pubout -out app-public.pem
180
201
  ```
181
202
 
182
- 2. **Register the public key** (Queek side; the backend stores it under a `kid`):
183
-
184
- ```sh
185
- php artisan app:register --public-key=./app-public.pem
186
- ```
187
-
188
- Queek prints the app secret (`QUEEK_APP_SECRET`, verifies the handoff) and the key id
189
- (`APP_KEY_ID`, rides the JWT `kid` header). Configure the app with `APP_SLUG` (= `iss`),
190
- `APP_KEY_ID`, and `APP_PRIVATE_KEY` (base64 of the private key PEM, one line — the
191
- Developer page shows it; raw PEM also accepted — never logged, never shipped to clients).
203
+ (b) Faster: `queek app dev` server-generates the pair and stores the kid + private key
204
+ (base64, one line) in `.queek/.env.local` (gitignored, 0600) — the private key is
205
+ returned once and never shown again; if lost, generate a new key. Either way, keep the
206
+ private key in your secrets manager beside `APP_ENCRYPTION_KEY` (key + DB loss = working
207
+ data lost — see below).
208
+
209
+ 2. **Register the app** on the Queek Developer page, then configure five values — each from
210
+ exactly one place: `APP_SLUG` is the slug in `queek.app.toml` (= JWT `iss`); `APP_KEY_ID`
211
+ is the kid from Keys (returned by generate/upload, or written by `queek app dev`);
212
+ `APP_PRIVATE_KEY` is the matching private key (your offline file, or the once-shown
213
+ server-generated one; raw PEM also accepted — never logged, never shipped to clients);
214
+ `QUEEK_APP_SECRET` verifies the handoff (shown once on first registration — `queek app
215
+ deploy` appends it to `.queek/.env.local`; `queek app dev` fetches it there; or Reveal
216
+ it on the dashboard) and is never rotated by dev; `APP_ENCRYPTION_KEY` is 32 local
217
+ random bytes, base64 or hex (`queek app dev` mints one into `.queek/.env.local`).
192
218
 
193
219
  3. **Acquire / cache / re-mint.** `acquireToken(installationId)` serves the cached token while
194
220
  its expiry is more than 5 minutes away; otherwise it signs an RS256 app JWT
@@ -197,14 +223,14 @@ One asymmetric credential per app — no per-installation secrets cross the hand
197
223
  `kid` (one shared cache row per installation — restarts never burst). Concurrent callers
198
224
  in one process share one in-flight mint; two containers minting at once is harmless by
199
225
  design (Queek keeps coexisting tokens valid; a residual race self-heals via re-mint).
200
- Merchant refusal table (rev 7): any 401, or 403 `api_key_revoked` / `api_key_expired` /
226
+ Token refusals: any 401, or 403 `api_key_revoked` / `api_key_expired` /
201
227
  `invalid_client_key` → drop the token, re-mint once, retry once (a second refusal
202
228
  propagates); 403 `app_token_revoked` → drop ALL cached tokens and halt minting (kill
203
229
  switch / disabled app, no mint); every other 403 (scope, plan, mode) propagates to the
204
230
  caller without a mint.
205
231
 
206
- 4. **Failures follow the wire contract exactly** (`app-auth.ts` holds each code in one
207
- constant, confirmed against the backend build):
232
+ 4. **Failures are handled by status and code** (`app-auth.ts` holds each code in one
233
+ constant):
208
234
  - `401 invalid_client` — fatal for the app: loud log, minting stops, no retry loop.
209
235
  - `403 app_token_revoked` (kill switch / disabled app) — drops ALL cached tokens, stops
210
236
  minting, loud log. Minting resumes after the app is re-enabled + process restart
@@ -232,10 +258,10 @@ One asymmetric credential per app — no per-installation secrets cross the hand
232
258
  existing installation idempotently (secret + settings refresh, `installedAt` and the
233
259
  cached token kept).
234
260
 
235
- 6. **Kill switch behaviour.** One backend operation revokes every token of an app across
236
- every store on the next request. The SDK side: cached tokens are dropped, minting halts
237
- with a loud log, and every call fails closed until the app is re-enabled and the
238
- process restarts (or resumes). Rotation without drama: add a `kid` (both verify) →
261
+ 6. **Kill switch behaviour.** One operation on Queek's side (the kill switch) revokes every
262
+ token of an app across every store on the next request. The SDK side is the
263
+ `app_token_revoked` row of item 4: every call fails closed until the app is re-enabled
264
+ and the process restarts (or resumes). Key rotation: add a `kid` (both verify) →
239
265
  switch the app to it → wait one token TTL → remove the old `kid`.
240
266
 
241
267
  ## Data rule + backups
@@ -245,7 +271,7 @@ Business data lives in Queek. `resyncFromQueek` restores CONNECTIVITY with zero
245
271
  action — but app WORKING data (inbound tokens, order links, form tokens, app-side-only
246
272
  settings) does NOT come back from resync: it needs the per-app `pg_dump` backup
247
273
  (RPO ≤ 24 h) plus the `APP_ENCRYPTION_KEY` backup. Events missed beyond Queek's webhook
248
- retries (~4 h) are gone; resync cannot backfill them. Full runbook: `docs/deploy.md` + O1.
274
+ retries (~4 h) are gone; resync cannot backfill them. Deploy reference: `queek app deploy --help`.
249
275
 
250
276
  ## Data deletion
251
277
 
@@ -261,8 +287,8 @@ topics, register explicit handlers for them — an unhandled topic only reports
261
287
 
262
288
  ## Storefront app-proxy (signed reads)
263
289
 
264
- Queek signs each storefront proxy fetch with the installation's `proxy_secret`
265
- (`AppProxyService::signQuery`); verify before answering the shopper:
290
+ Queek signs each storefront proxy fetch with the installation's `proxy_secret`;
291
+ verify before answering the shopper:
266
292
 
267
293
  ```ts
268
294
  import { handleProxyRequest } from "@usequeek/app-sdk";
@@ -281,7 +307,7 @@ The canonical string is `path + "\n" + shop + "\n" + ts + "\n" + sorted(k=v&...)
281
307
  (`sig` excluded), hex HMAC-SHA256 over the FULL `whsec_…` string — no base64 decode
282
308
  step. `kid` routes to the installation whose `proxy_secret` verifies (previous-secret
283
309
  grace: pass every active secret to `verifyProxyQuery`); timestamps skew at most 5
284
- minutes, each `jti` is single-use, and only `GET` is served (phase 1 is read-only).
310
+ minutes, each `jti` is single-use, and only `GET` is served (proxy reads are read-only).
285
311
  Hono: mount `createProxyHandler({ store, path, onVerified })` from
286
312
  `@usequeek/app-sdk/hono`.
287
313
 
@@ -290,32 +316,31 @@ Hono: mount `createProxyHandler({ store, path, onVerified })` from
290
316
  - **app-auth** (`app-auth.ts`): `loadAppCredential` (`APP_SLUG`/`APP_KEY_ID`/`APP_PRIVATE_KEY`
291
317
  — base64 of the PEM, raw PEM, or `\n`-escaped one-line PEM; RSA validated at boot),
292
318
  `signAppJwt` (RS256, `iat` now − 60 s, `exp` window 540 s ≤ 600 s,
293
- `kid` header), the wire-contract error codes in one place (`INVALID_CLIENT_CODE`,
319
+ `kid` header), the error codes in one place (`INVALID_CLIENT_CODE`,
294
320
  `APP_TOKEN_REVOKED_CODE`, `APP_INSTALLATION_GONE_CODE`, `APP_INSTALLATION_PENDING_CODE`,
295
321
  `RESYNC_COOLDOWN_CODE`, `TOO_MANY_REQUESTS_CODE`), `AppMintHaltedError`.
296
322
  - **tokens** (`tokens.ts`): `createAppTokenProvider({ credential, store, … })` —
297
- `acquireToken` (cache → sign → mint → persist), single-flight per installation, the exact
298
- contract error mapping (409 pending → backoff + bounded retry, marked, never purged);
323
+ `acquireToken` (cache → sign → mint → persist), single-flight per installation, with the
324
+ error handling in Credential lifecycle items 3–4;
299
325
  `createInstallationClient({ installationId, apiBase, tokens })` — the `QueekClient`
300
326
  every app call uses (re-mint once + retry once on token refusals only).
301
- - **resync** (`resync.ts`): `resyncFromQueek({ apiBase, tokens, store })` — list active
302
- only (opaque keyset cursor) → resync each (409 pending → retry then skip + record;
303
- 429 `resync_cooldown` → skip + record; other 429 → backoff + retry) → drop tokens →
304
- purge absent except known-pending. Connectivity scope only.
327
+ - **resync** (`resync.ts`): `resyncFromQueek({ apiBase, tokens, store })` — the flow in
328
+ Credential lifecycle item 5. Connectivity scope only.
305
329
  - **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.
306
330
  - **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.
307
331
  - **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`).
308
- - **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.
332
+ - **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 without waiting for an SDK release. 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.
309
333
  - **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.
310
- - **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`).
334
+ - **proxy** (`proxy.ts`): `verifyProxyQuery` / `verifyProxyQueryDetailed` — app-proxy query verification byte-exact with Queek's signer (`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`).
311
335
  - **store** (`store.ts`): `SqliteInstallationStore` (local/dev/test) and `PostgresInstallationStore`
312
336
  (`pg`, pool max 2, advisory-locked schema + `schema_version` row so two containers boot
313
337
  safely) — installations encrypted at rest (AES-GCM via `APP_ENCRYPTION_KEY`), plus the
314
338
  persisted 409-pending mark (`pending` column, schema v2, migrated in place) and the
315
339
  seen-webhook-id claim table behind dedupe. Pick with `createInstallationStore()`
316
340
  (`DATABASE_URL` set → Postgres, else SQLite — which production REFUSES with a clear
317
- message). Set once when the app is deployed; installs never change env: each install adds
318
- a row to the app's database, with that store's token + webhook secret encrypted using this key.
341
+ message). `APP_ENCRYPTION_KEY` is set once when the app is deployed; installs never change env:
342
+ each install adds a row to the app's database, with that store's token + webhook secret
343
+ encrypted using this key.
319
344
  - **background** (`background.ts`): `detach` plus `runInstallationCatchup` — jittered
320
345
  per-installation cron (uniform 0–600 s start jitter, per-install error isolation,
321
346
  concurrency ≤ pool size, honors 429 once per installation).
@@ -325,15 +350,16 @@ Hono: mount `createProxyHandler({ store, path, onVerified })` from
325
350
  `verifySessionToken` — HS256 dashboard session tokens minted per installation
326
351
  (`embsec_…` secret, raw UTF-8 key bytes, 20 s clock tolerance, slug audience,
327
352
  issuer = the handoff `apiBase` verbatim (`installation.apiBase` — it equals the
328
- bare `app.url` the backend signs as `iss`), full installation binding). The secret never enters a
353
+ bare `app.url` Queek signs as `iss`), full installation binding). There is one token
354
+ type: the dashboard puts the same token in the first-load URL param
355
+ (`queek_token`, stripped on arrival) and answers bridge `ready` requests with it,
356
+ so first-load and refresh tokens are verified by this one verifier — no purpose
357
+ split, extra claims are ignored. The secret never enters a
329
358
  browser bundle: the main entry does not export the verifier. The install
330
359
  and resync handoffs deliver `embed_secret` + `app_id`; the store keeps
331
360
  them on the installation (`embedSecret` encrypted, `appId`), and
332
361
  `sessionTokenInstallationId` reads the token's `installation_id` as an
333
362
  unverified routing hint so a server can load that row before verifying.
334
- `verifyLaunchToken` checks the signed-first-load token the same way plus the purpose pin
335
- (`purpose` must be `launch`, with the `store` p_id and `theme` hints) — a launch token is refused
336
- as a bridge token and vice versa.
337
363
  - **frame** (`frame.ts`, browser-safe, no secret): the embedded-app bridge
338
364
  v1 — typed unions both directions (`ready{capabilities,sdkVersion}`,
339
365
  `theme`, `title`/`title-action`, `toast`, `save-bar`/`save-bar-action`,
@@ -363,8 +389,10 @@ Hono: mount `createProxyHandler({ store, path, onVerified })` from
363
389
  Each pick carries a `requestId` (on `pick-resource`); a dashboard that
364
390
  declares `pick-resource` MUST echo it on `resource-picked` / `resource-pick-cancelled` — answers with a
365
391
  different or missing id are dropped as stale.
366
- - **auth** (`auth-fetch.ts`, browser-safe, no secret): `installAuthFetch({ exchange })`
367
- — reads the launch token (`queek_token` query param) from the signed first
392
+ - **auth** (`auth-fetch.ts`, no secret — browser-safe as a module, but import it
393
+ from `@usequeek/app-sdk/browser` in browser bundles, never from the main
394
+ entry): `installAuthFetch({ exchange })`
395
+ — reads the dashboard token (`queek_token` query param) from the first
368
396
  load, strips it with `history.replaceState`, exchanges it once for the
369
397
  app's own session, attaches `Authorization: Bearer <session>` to
370
398
  same-origin fetch (cookies stay out), and re-establishes via the bridge
@@ -372,27 +400,25 @@ Hono: mount `createProxyHandler({ store, path, onVerified })` from
372
400
  window itself) and is not retried per request after a failed attempt — only
373
401
  after a later dashboard token arrives. Pass the same `capabilities`/
374
402
  `sdkVersion` as the provider so its refresh `ready` announces one consistent set. The app's
375
- token-exchange endpoint receives the LAUNCH token on first load and a BRIDGE token on every
376
- 401 refresh through the same `exchange` callback, so it must try
377
- `verifyLaunchTokenDetailed`/`verifyLaunchToken` first and fall back to `verifySessionToken`
378
- (both purposes):
403
+ token-exchange endpoint receives the first-load token and every 401-refresh
404
+ token through the same `exchange` callback, so it verifies both with the
405
+ single `verifySessionToken` verifier:
379
406
 
380
407
  ```ts
381
- import { verifyLaunchTokenDetailed, verifySessionTokenDetailed } from "@usequeek/app-sdk/server";
408
+ import { verifySessionTokenDetailed } from "@usequeek/app-sdk/server";
382
409
 
383
410
  async function exchange(token: string): Promise<string> {
384
411
  const options = { secret: installation.embedSecret!, audience: "my-app", issuer: installation.apiBase, expected };
385
- const launch = await verifyLaunchTokenDetailed(token, options);
386
- if (launch.ok) return mintAppSession(launch.claims);
387
- const bridge = await verifySessionTokenDetailed(token, options);
388
- if (bridge.ok) return mintAppSession(bridge.claims);
389
- throw Object.assign(new Error("unauthorized"), { status: 401 });
412
+ const checked = await verifySessionTokenDetailed(token, options);
413
+ if (!checked.ok) throw Object.assign(new Error("unauthorized"), { status: 401 });
414
+ return mintAppSession(checked.claims);
390
415
  }
391
416
  ```
392
417
  - **theme** (`theme.ts`, browser-safe, no secret): `applyTheme(mode)` toggles
393
418
  `.dark` on `<html>` + `color-scheme` (shadcn's dark-mode mechanism);
394
- `themeBootstrapScript()` returns the inline `<head>` snippet that reads
395
- `theme` from the URL before first paint (no flash);
419
+ `themeBootstrapScript()` returns the inline `<head>` snippet that reads the
420
+ unsigned `theme` URL param before first paint (no flash — a first-paint hint
421
+ only, validated to `light`|`dark`, overwritten by the live bridge message);
396
422
  `installThemeListener` follows live bridge `theme{mode}` messages (only from
397
423
  `window.parent` by default; pass `expectSource` to override). The live mode is
398
424
  remembered in `sessionStorage`, and the bootstrap script falls back to it when
@@ -439,14 +465,14 @@ list you pass (the app surface exposes the grant but no declared list, so the
439
465
  split needs your manifest knowledge). `requestScopes` returns
440
466
  `/apps?app={slug}&view=scopes&scopes={a},{b}` (absolute under
441
467
  `dashboardOrigin` when configured) — open it via `sendOpen` or a redirect: it
442
- opens the merchant's consent screen in the dashboard (shipped with dashboard
443
- item 8). The link carries the slug + the scope list only; the dashboard
468
+ opens the merchant's consent screen in the dashboard (requires a dashboard that
469
+ supports the consent screen). The link carries the slug + the scope list only; the dashboard
444
470
  resolves the installation from the signed-in store. The grant reaches you as a
445
471
  signed `app/scopes_update` handoff, which the install/settings handlers apply
446
472
  like a resync (same verifier, same replay claim): cached grant refreshed,
447
473
  cached token dropped only when the grant moved.
448
474
 
449
- ## Embedded merchant page (S4 stage 2)
475
+ ## Embedded merchant page
450
476
 
451
477
  The dashboard frames your app's granted merchant page in a
452
478
  `sandbox="allow-scripts allow-forms"` iframe and delivers the session token
@@ -454,29 +480,22 @@ by postMessage. Serve the page with a `frame-ancestors` policy naming ONLY
454
480
  your dashboard origin, for example:
455
481
 
456
482
  ```http
457
- Content-Security-Policy: frame-ancestors https://merchant.queek.com
483
+ Content-Security-Policy: frame-ancestors https://dashboard.usequeek.com
458
484
  ```
459
485
 
460
486
  Replace the host with the dashboard origin you registered. `frame-ancestors`
461
- is a docs-only control the dashboard cannot enforce for you: without it any
462
- site may frame the page, and the token handshake (origin-bound) is your only
463
- remaining gate. Verify every token server-side before trusting calls that carry one:
464
- the token-exchange endpoint receives the LAUNCH token on first load and a BRIDGE token on
465
- every 401 refresh through the same `installAuthFetch({ exchange })` callback, so it must try
466
- `verifyLaunchTokenDetailed`/`verifyLaunchToken` first and fall back to `verifySessionToken`
467
- (both purposes — see the `auth` entry above).
487
+ is a header only your server can set, so the dashboard cannot enforce it for you:
488
+ without it any site may frame the page, and the token handshake (origin-bound) is
489
+ your only remaining gate. Verify every token server-side before trusting calls that carry one
490
+ (see the `auth` entry under API surface).
468
491
 
469
492
  ## Local development
470
493
 
471
- Point the client at a local backend with `QUEEK_DEV_API_HOSTS` (comma-separated hosts). It is refused when `NODE_ENV=production`, so it can never weaken a live app. See `devApiHostsFromEnv` in `client.ts`.
494
+ Point the client at a local Queek API with `QUEEK_DEV_API_HOSTS` (comma-separated hosts). It is refused when `NODE_ENV=production`, so it can never weaken a live app. See `devApiHostsFromEnv` in `client.ts`.
472
495
 
473
496
  Postgres locally: any Postgres works — point `DATABASE_URL` at it and the pg suite runs
474
497
  (CI always runs it via a service container); without `DATABASE_URL` those tests skip cleanly.
475
498
 
476
- ## Registration
477
-
478
- App registration is by the Queek team today: you ship Queek your manifest URL and receive the app secret + store key. There is no public self-serve registration yet.
479
-
480
499
  ## License
481
500
 
482
501
  MIT — see [LICENSE](./LICENSE).
@@ -1,21 +1,19 @@
1
1
  /**
2
- * The app credential (S1, SDK 0.2.0): ONE asymmetric RS256 key per app.
3
- * Queek holds the PUBLIC keys (`apps.public_keys`, kid-capped); the app
4
- * holds the PRIVATE key in `APP_PRIVATE_KEY` and signs short-lived app
5
- * JWTs that mint per-installation tokens (`acquireToken()`).
2
+ * The app credential: ONE asymmetric RS256 key per app. Queek holds the
3
+ * PUBLIC keys (kid-capped); the app holds the PRIVATE key in
4
+ * `APP_PRIVATE_KEY` and signs short-lived app JWTs that mint
5
+ * per-installation tokens (`acquireToken()`).
6
6
  *
7
- * Wire contract (BINDING for B2 and S1): every call under `/api/v1/apps`
8
- * carries `Authorization: Bearer <app JWT>` (RS256, header `kid`, claims
9
- * `iss` = app slug, `iat`, `exp`, `exp − iat` ≤ 600 s). `node:crypto` only
10
- * — no new dependency. The JWT and the private key are NEVER logged (the
7
+ * Every call under `/api/v1/apps` carries `Authorization: Bearer <app JWT>`
8
+ * (RS256, header `kid`, claims `iss` = app slug, `iat`, `exp`,
9
+ * `exp − iat` ≤ 600 s). `node:crypto` only — no new dependency. The JWT and the private key are NEVER logged (the
11
10
  * logger redacts `Bearer …` values; signers below never emit them).
12
11
  */
13
12
  /** 401 on an app-credential call: bad/expired JWT or unknown kid. Fatal for the app. */
14
13
  export declare const INVALID_CLIENT_CODE = "invalid_client";
15
14
  /**
16
15
  * 403 on an app-credential call: the app is disabled or its token epoch was
17
- * bumped by `app:revoke-tokens` (kill switch). Confirmed against B1
18
- * (`ApiError::APP_TOKEN_REVOKED`, returned in both cases); matched in
16
+ * bumped (kill switch, returned in both cases); matched in
19
17
  * exactly one place (`isAppTokenRevoked`).
20
18
  */
21
19
  export declare const APP_TOKEN_REVOKED_CODE = "app_token_revoked";
@@ -55,10 +53,10 @@ export declare function isInstallationPending(code: string | undefined): boolean
55
53
  /** True when a resync 429 code is the per-installation rotation cooldown (skip, recorded). */
56
54
  export declare function isResyncCooldown(code: string | undefined): boolean;
57
55
  /**
58
- * Merchant-API token-refusal codes (rev 7): a token in one of these states
56
+ * Merchant-API token-refusal codes: a token in one of these states
59
57
  * is dead — drop it, re-mint once, retry once. `api_key_revoked` covers the
60
- * uninstalled store, the removed kid, and the replaced K-slot; the re-mint
61
- * then answers 404 `app_installation_gone` (purge) or 401 `invalid_client`
58
+ * uninstalled store, the removed kid, and a token replaced by a newer one;
59
+ * the re-mint then answers 404 `app_installation_gone` (purge) or 401 `invalid_client`
62
60
  * (halt) where applicable. Every OTHER merchant 403 (plan, mode)
63
61
  * propagates to the caller without a mint.
64
62
  */
@@ -112,7 +110,7 @@ export declare class UnknownInstallationError extends Error {
112
110
  constructor(installationId: string);
113
111
  }
114
112
  export interface AppCredential {
115
- /** `iss`: the app slug (as registered with `app:register`). */
113
+ /** `iss`: the app slug (as registered on the Queek Developer page). */
116
114
  appSlug: string;
117
115
  /** `kid`: which of the app's public keys Queek verifies against (`APP_KEY_ID`). */
118
116
  keyId: string;
@@ -128,7 +126,8 @@ export interface AppCredentialOptions {
128
126
  /**
129
127
  * Accepted `APP_PRIVATE_KEY` forms (env files are one line per variable):
130
128
  * raw PEM text, one-line PEM with literal `\n` escapes, or base64 of the
131
- * full PEM text (one line, no wrapping — what the Developer page shows).
129
+ * full PEM text (one line, no wrapping — the form `queek app dev` writes to
130
+ * `.queek/.env.local`; a server-generated key is shown once, never again).
132
131
  */
133
132
  export declare const APP_PRIVATE_KEY_FORMS = "raw PEM text, one-line PEM with literal \\n escapes, or base64 of the PEM text";
134
133
  /**
@@ -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
@@ -1,27 +1,24 @@
1
1
  import { createPrivateKey, createSign } from "node:crypto";
2
2
  /**
3
- * The app credential (S1, SDK 0.2.0): ONE asymmetric RS256 key per app.
4
- * Queek holds the PUBLIC keys (`apps.public_keys`, kid-capped); the app
5
- * holds the PRIVATE key in `APP_PRIVATE_KEY` and signs short-lived app
6
- * JWTs that mint per-installation tokens (`acquireToken()`).
3
+ * The app credential: ONE asymmetric RS256 key per app. Queek holds the
4
+ * PUBLIC keys (kid-capped); the app holds the PRIVATE key in
5
+ * `APP_PRIVATE_KEY` and signs short-lived app JWTs that mint
6
+ * per-installation tokens (`acquireToken()`).
7
7
  *
8
- * Wire contract (BINDING for B2 and S1): every call under `/api/v1/apps`
9
- * carries `Authorization: Bearer <app JWT>` (RS256, header `kid`, claims
10
- * `iss` = app slug, `iat`, `exp`, `exp − iat` ≤ 600 s). `node:crypto` only
11
- * — no new dependency. The JWT and the private key are NEVER logged (the
8
+ * Every call under `/api/v1/apps` carries `Authorization: Bearer <app JWT>`
9
+ * (RS256, header `kid`, claims `iss` = app slug, `iat`, `exp`,
10
+ * `exp − iat` ≤ 600 s). `node:crypto` only — no new dependency. The JWT and the private key are NEVER logged (the
12
11
  * logger redacts `Bearer …` values; signers below never emit them).
13
12
  */
14
13
  // ---------------------------------------------------------------------------
15
- // Wire-contract error codes. Each code the SDK reacts to lives in EXACTLY
16
- // one constant here, so a backend rename is a one-line change the parallel
17
- // B1/B2 build must confirm.
14
+ // Error codes on the wire. Each code the SDK reacts to lives in EXACTLY
15
+ // one constant here, so a rename on Queek's side is a one-line change.
18
16
  // ---------------------------------------------------------------------------
19
17
  /** 401 on an app-credential call: bad/expired JWT or unknown kid. Fatal for the app. */
20
18
  export const INVALID_CLIENT_CODE = "invalid_client";
21
19
  /**
22
20
  * 403 on an app-credential call: the app is disabled or its token epoch was
23
- * bumped by `app:revoke-tokens` (kill switch). Confirmed against B1
24
- * (`ApiError::APP_TOKEN_REVOKED`, returned in both cases); matched in
21
+ * bumped (kill switch, returned in both cases); matched in
25
22
  * exactly one place (`isAppTokenRevoked`).
26
23
  */
27
24
  export const APP_TOKEN_REVOKED_CODE = "app_token_revoked";
@@ -71,10 +68,10 @@ export function isResyncCooldown(code) {
71
68
  return code === RESYNC_COOLDOWN_CODE;
72
69
  }
73
70
  /**
74
- * Merchant-API token-refusal codes (rev 7): a token in one of these states
71
+ * Merchant-API token-refusal codes: a token in one of these states
75
72
  * is dead — drop it, re-mint once, retry once. `api_key_revoked` covers the
76
- * uninstalled store, the removed kid, and the replaced K-slot; the re-mint
77
- * then answers 404 `app_installation_gone` (purge) or 401 `invalid_client`
73
+ * uninstalled store, the removed kid, and a token replaced by a newer one;
74
+ * the re-mint then answers 404 `app_installation_gone` (purge) or 401 `invalid_client`
78
75
  * (halt) where applicable. Every OTHER merchant 403 (plan, mode)
79
76
  * propagates to the caller without a mint.
80
77
  */
@@ -146,14 +143,15 @@ export class AppMintHaltedError extends Error {
146
143
  export class UnknownInstallationError extends Error {
147
144
  code = "unknown_installation";
148
145
  constructor(installationId) {
149
- super(`Unknown installation ${installationId}: no local row (resync or reinstall first).`);
146
+ super(`Unknown installation ${installationId}: no local row. Recover with resyncFromQueek() (lists the app's active installations from Queek) or reinstall the app on the store.`);
150
147
  this.name = "UnknownInstallationError";
151
148
  }
152
149
  }
153
150
  /**
154
151
  * Accepted `APP_PRIVATE_KEY` forms (env files are one line per variable):
155
152
  * raw PEM text, one-line PEM with literal `\n` escapes, or base64 of the
156
- * full PEM text (one line, no wrapping — what the Developer page shows).
153
+ * full PEM text (one line, no wrapping — the form `queek app dev` writes to
154
+ * `.queek/.env.local`; a server-generated key is shown once, never again).
157
155
  */
158
156
  export const APP_PRIVATE_KEY_FORMS = "raw PEM text, one-line PEM with literal \\n escapes, or base64 of the PEM text";
159
157
  /**
@@ -183,15 +181,15 @@ export function loadAppCredential(options = {}) {
183
181
  const env = options.env ?? process.env;
184
182
  const appSlug = (options.appSlug ?? env.APP_SLUG ?? "").trim();
185
183
  if (appSlug === "") {
186
- throw new InvalidAppCredentialError("Missing app slug for `iss`: pass appSlug or set APP_SLUG to the slug registered with Queek.");
184
+ throw new InvalidAppCredentialError("Missing app slug for `iss`: pass appSlug or set APP_SLUG to the slug from the Queek Developer page (register the app there, or run `queek app dev` — it writes .queek/.env.local).");
187
185
  }
188
186
  const keyId = (options.keyId ?? env.APP_KEY_ID ?? "").trim();
189
187
  if (keyId === "") {
190
- throw new InvalidAppCredentialError("Missing APP_KEY_ID: set it to the kid registered with Queek (`php artisan app:register --public-key=…`).");
188
+ throw new InvalidAppCredentialError("Missing APP_KEY_ID: set it to the key id shown on the Queek Developer page for this app (`queek app dev` writes it to .queek/.env.local on first run).");
191
189
  }
192
190
  const privateKeyInput = (options.privateKeyPem ?? env.APP_PRIVATE_KEY ?? "").trim();
193
191
  if (privateKeyInput === "") {
194
- throw new InvalidAppCredentialError(`Missing APP_PRIVATE_KEY: set it to base64 of the app's RSA private key PEM (one line). Accepted forms: ${APP_PRIVATE_KEY_FORMS}.`);
192
+ throw new InvalidAppCredentialError(`Missing APP_PRIVATE_KEY: set it to the app's RSA private key — your offline-generated file, or the server-generated key (shown once on the Developer page; \`queek app dev\` stores it in .queek/.env.local). If lost, generate a new key. Accepted forms: ${APP_PRIVATE_KEY_FORMS}.`);
195
193
  }
196
194
  const privateKeyPem = decodePrivateKeyInput(privateKeyInput);
197
195
  try {
@@ -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":"AAAA,OAAO,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAE3D;;;;;;;;;;GAUG;AAEH,8EAA8E;AAC9E,wEAAwE;AACxE,uEAAuE;AACvE,8EAA8E;AAE9E,wFAAwF;AACxF,MAAM,CAAC,MAAM,mBAAmB,GAAG,gBAAgB,CAAC;AACpD;;;;GAIG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG,mBAAmB,CAAC;AAC1D,+EAA+E;AAC/E,MAAM,CAAC,MAAM,0BAA0B,GAAG,uBAAuB,CAAC;AAClE;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,6BAA6B,GAAG,0BAA0B,CAAC;AACxE;;;;;GAKG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,iBAAiB,CAAC;AACtD,qDAAqD;AACrD,MAAM,CAAC,MAAM,sBAAsB,GAAG,mBAAmB,CAAC;AAC1D;;;;GAIG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAG,oBAAoB,CAAC;AAE5D,wEAAwE;AACxE,MAAM,UAAU,iBAAiB,CAAC,IAAwB;IACxD,OAAO,IAAI,KAAK,sBAAsB,CAAC;AACzC,CAAC;AAED,wEAAwE;AACxE,MAAM,UAAU,eAAe,CAAC,IAAwB;IACtD,OAAO,IAAI,KAAK,mBAAmB,CAAC;AACtC,CAAC;AAED,+EAA+E;AAC/E,MAAM,UAAU,kBAAkB,CAAC,IAAwB;IACzD,OAAO,IAAI,KAAK,0BAA0B,CAAC;AAC7C,CAAC;AAED,sGAAsG;AACtG,MAAM,UAAU,qBAAqB,CAAC,IAAwB;IAC5D,OAAO,IAAI,KAAK,6BAA6B,CAAC;AAChD,CAAC;AAED,8FAA8F;AAC9F,MAAM,UAAU,gBAAgB,CAAC,IAAwB;IACvD,OAAO,IAAI,KAAK,oBAAoB,CAAC;AACvC,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,iBAAiB,CAAC;AACtD,MAAM,CAAC,MAAM,oBAAoB,GAAG,iBAAiB,CAAC;AACtD,MAAM,CAAC,MAAM,uBAAuB,GAAG,oBAAoB,CAAC;AAE5D;;;;;GAKG;AACH,MAAM,UAAU,cAAc,CAAC,MAAc,EAAE,IAAwB;IACrE,IAAI,MAAM,KAAK,GAAG;QAAE,OAAO,IAAI,CAAC;IAChC,OAAO,CACL,MAAM,KAAK,GAAG;QACd,CAAC,IAAI,KAAK,oBAAoB,IAAI,IAAI,KAAK,oBAAoB,IAAI,IAAI,KAAK,uBAAuB,CAAC,CACrG,CAAC;AACJ,CAAC;AAED,mFAAmF;AACnF,MAAM,UAAU,mBAAmB,CAAC,MAAc,EAAE,IAAwB;IAC1E,OAAO,MAAM,KAAK,GAAG,IAAI,IAAI,KAAK,uBAAuB,CAAC;AAC5D,CAAC;AAED,8EAA8E;AAC9E,4DAA4D;AAC5D,8EAA8E;AAE9E,iFAAiF;AACjF,MAAM,CAAC,MAAM,oBAAoB,GAAG,EAAE,CAAC;AACvC,gGAAgG;AAChG,MAAM,CAAC,MAAM,mBAAmB,GAAG,GAAG,CAAC;AACvC,oGAAoG;AACpG,MAAM,CAAC,MAAM,2BAA2B,GAAG,GAAG,CAAC;AAC/C,yFAAyF;AACzF,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,CAAC;AACnC,mGAAmG;AACnG,MAAM,CAAC,MAAM,oBAAoB,GAAG,GAAG,CAAC;AACxC,wFAAwF;AACxF,MAAM,CAAC,MAAM,mBAAmB,GAAG,KAAK,CAAC;AACzC,2EAA2E;AAC3E,MAAM,CAAC,MAAM,mBAAmB,GAAG,KAAK,CAAC;AAEzC,8EAA8E;AAC9E,cAAc;AACd,8EAA8E;AAE9E,0FAA0F;AAC1F,MAAM,OAAO,yBAA0B,SAAQ,KAAK;IACzC,IAAI,GAAG,wBAAwB,CAAC;IAEzC,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,2BAA2B,CAAC;IAC1C,CAAC;CACF;AAED;;;;;;;GAOG;AACH,MAAM,OAAO,kBAAmB,SAAQ,KAAK;IAClC,IAAI,GAAG,iBAAiB,CAAC;IACzB,MAAM,CAA6D;IAE5E,YAAY,MAAoC,EAAE,MAAc;QAC9D,KAAK,CAAC,mBAAmB,MAAM,MAAM,MAAM,EAAE,CAAC,CAAC;QAC/C,IAAI,CAAC,IAAI,GAAG,oBAAoB,CAAC;QACjC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;CACF;AAED,gEAAgE;AAChE,MAAM,OAAO,wBAAyB,SAAQ,KAAK;IACxC,IAAI,GAAG,sBAAsB,CAAC;IAEvC,YAAY,cAAsB;QAChC,KAAK,CACH,wBAAwB,cAAc,qIAAqI,CAC5K,CAAC;QACF,IAAI,CAAC,IAAI,GAAG,0BAA0B,CAAC;IACzC,CAAC;CACF;AAkBD;;;;;GAKG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAChC,gFAAgF,CAAC;AAEnF;;;;;GAKG;AACH,MAAM,UAAU,qBAAqB,CAAC,GAAW;IAC/C,MAAM,OAAO,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;IAC3B,IAAI,OAAO,CAAC,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;QACrC,OAAO,OAAO,CAAC,OAAO,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC;IAC9C,CAAC;IACD,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IAChE,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;QAClD,MAAM,IAAI,yBAAyB,CACjC,+EAA+E,qBAAqB,GAAG,CACxG,CAAC;IACJ,CAAC;IACD,OAAO,OAAO,CAAC,IAAI,EAAE,CAAC;AACxB,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,iBAAiB,CAAC,UAAgC,EAAE;IAClE,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,CAAC;IACvC,MAAM,OAAO,GAAG,CAAC,OAAO,CAAC,OAAO,IAAI,GAAG,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IAC/D,IAAI,OAAO,KAAK,EAAE,EAAE,CAAC;QACnB,MAAM,IAAI,yBAAyB,CACjC,oLAAoL,CACrL,CAAC;IACJ,CAAC;IACD,MAAM,KAAK,GAAG,CAAC,OAAO,CAAC,KAAK,IAAI,GAAG,CAAC,UAAU,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IAC7D,IAAI,KAAK,KAAK,EAAE,EAAE,CAAC;QACjB,MAAM,IAAI,yBAAyB,CACjC,wJAAwJ,CACzJ,CAAC;IACJ,CAAC;IACD,MAAM,eAAe,GAAG,CAAC,OAAO,CAAC,aAAa,IAAI,GAAG,CAAC,eAAe,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IACpF,IAAI,eAAe,KAAK,EAAE,EAAE,CAAC;QAC3B,MAAM,IAAI,yBAAyB,CACjC,8PAA8P,qBAAqB,GAAG,CACvR,CAAC;IACJ,CAAC;IACD,MAAM,aAAa,GAAG,qBAAqB,CAAC,eAAe,CAAC,CAAC;IAC7D,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,gBAAgB,CAAC,aAAa,CAAC,CAAC;QAC5C,IAAI,GAAG,CAAC,iBAAiB,KAAK,KAAK,EAAE,CAAC;YACpC,MAAM,IAAI,yBAAyB,CACjC,mDAAmD,GAAG,CAAC,iBAAiB,IAAI,SAAS,aAAa,CACnG,CAAC;QACJ,CAAC;IACH,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,KAAK,YAAY,yBAAyB;YAAE,MAAM,KAAK,CAAC;QAC5D,MAAM,IAAI,yBAAyB,CACjC,6DAA6D,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,aAAa,sBAAsB,qBAAqB,GAAG,CAClK,CAAC;IACJ,CAAC;IACD,oEAAoE;IACpE,gEAAgE;IAChE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,aAAa,EAAE,CAAC;AAC3C,CAAC;AAED,SAAS,SAAS,CAAC,KAAsB;IACvC,OAAO,MAAM,CAAC,IAAI,CAAC,KAAe,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;AAC5D,CAAC;AAQD;;;;;GAKG;AACH,MAAM,UAAU,UAAU,CAAC,OAA0B;IACnD,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,UAAU,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC;IAChE,MAAM,GAAG,GAAG,GAAG,GAAG,oBAAoB,CAAC;IACvC,MAAM,GAAG,GAAG,GAAG,GAAG,mBAAmB,CAAC;IACtC,MAAM,MAAM,GAAG,SAAS,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,EAAE,OAAO,CAAC,UAAU,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;IACtG,MAAM,OAAO,GAAG,SAAS,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,GAAG,EAAE,OAAO,CAAC,UAAU,CAAC,OAAO,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC;IACzF,MAAM,YAAY,GAAG,GAAG,MAAM,IAAI,OAAO,EAAE,CAAC;IAC5C,IAAI,SAAiB,CAAC;IACtB,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,UAAU,CAAC,YAAY,CAAC,CAAC;QACxC,MAAM,CAAC,MAAM,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC;QACpC,SAAS,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC;IAC5D,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,yBAAyB,CACjC,+EAA+E,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,UAAU,CAAC,KAAK,CAAC,OAAO,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,gBAAgB,EAAE,CAC1L,CAAC;IACJ,CAAC;IACD,OAAO,GAAG,YAAY,IAAI,SAAS,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC;AAC9D,CAAC"}