@usequeek/app-sdk 0.6.1 → 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.
- package/README.md +76 -70
- package/dist/app-auth.d.ts +14 -15
- package/dist/app-auth.d.ts.map +1 -1
- package/dist/app-auth.js +19 -21
- package/dist/app-auth.js.map +1 -1
- package/dist/auth-fetch.d.ts +2 -4
- package/dist/auth-fetch.d.ts.map +1 -1
- package/dist/auth-fetch.js +2 -4
- package/dist/auth-fetch.js.map +1 -1
- package/dist/background.d.ts +1 -1
- package/dist/browser.d.ts +2 -2
- package/dist/browser.js +2 -2
- package/dist/client.d.ts +8 -9
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +2 -2
- package/dist/client.js.map +1 -1
- package/dist/collected.d.ts +13 -14
- package/dist/collected.d.ts.map +1 -1
- package/dist/collected.js +4 -4
- package/dist/collected.js.map +1 -1
- package/dist/crypto.js +3 -3
- package/dist/crypto.js.map +1 -1
- package/dist/delivery.d.ts +4 -8
- package/dist/delivery.d.ts.map +1 -1
- package/dist/delivery.js +4 -8
- package/dist/delivery.js.map +1 -1
- package/dist/frame.d.ts +11 -11
- package/dist/frame.d.ts.map +1 -1
- package/dist/frame.js +11 -11
- package/dist/frame.js.map +1 -1
- package/dist/handoff.d.ts +35 -38
- package/dist/handoff.d.ts.map +1 -1
- package/dist/handoff.js +9 -9
- package/dist/hono.d.ts +3 -3
- package/dist/hono.js +3 -3
- package/dist/install-handlers.d.ts +6 -7
- package/dist/install-handlers.d.ts.map +1 -1
- package/dist/install-handlers.js +11 -11
- package/dist/install-handlers.js.map +1 -1
- package/dist/logger.js +1 -1
- package/dist/logger.js.map +1 -1
- package/dist/merchant-schema.d.ts +14882 -6288
- package/dist/merchant-schema.d.ts.map +1 -1
- package/dist/proxy.d.ts +20 -22
- package/dist/proxy.d.ts.map +1 -1
- package/dist/proxy.js +19 -20
- package/dist/proxy.js.map +1 -1
- package/dist/react.d.ts +1 -1
- package/dist/react.js +1 -1
- package/dist/resync.d.ts +4 -4
- package/dist/resync.d.ts.map +1 -1
- package/dist/resync.js +4 -4
- package/dist/resync.js.map +1 -1
- package/dist/scopes.d.ts +22 -26
- package/dist/scopes.d.ts.map +1 -1
- package/dist/scopes.js +19 -23
- package/dist/scopes.js.map +1 -1
- package/dist/session.d.ts +15 -16
- package/dist/session.d.ts.map +1 -1
- package/dist/session.js +12 -14
- package/dist/session.js.map +1 -1
- package/dist/signatures.d.ts +5 -4
- package/dist/signatures.d.ts.map +1 -1
- package/dist/signatures.js +7 -6
- package/dist/signatures.js.map +1 -1
- package/dist/store.d.ts +20 -25
- package/dist/store.d.ts.map +1 -1
- package/dist/store.js +16 -19
- package/dist/store.js.map +1 -1
- package/dist/theme.d.ts +1 -1
- package/dist/theme.js +1 -1
- package/dist/tokens.d.ts +9 -9
- package/dist/tokens.d.ts.map +1 -1
- package/dist/tokens.js +9 -10
- package/dist/tokens.js.map +1 -1
- package/dist/webhooks.d.ts +2 -3
- package/dist/webhooks.d.ts.map +1 -1
- package/dist/webhooks.js +2 -3
- package/dist/webhooks.js.map +1 -1
- package/package.json +4 -3
package/README.md
CHANGED
|
@@ -1,15 +1,28 @@
|
|
|
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
|
|
|
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
|
+
|
|
13
26
|
## Which entry do I import?
|
|
14
27
|
|
|
15
28
|
| Import | For | Pulls in |
|
|
@@ -18,11 +31,9 @@ Requires Node `>=22.14`. `pg` is a regular dependency (the production store). `h
|
|
|
18
31
|
| `@usequeek/app-sdk/server` | Session-token verifier (`verifySessionToken`) | Server-only (`jose`) — never import in a browser bundle |
|
|
19
32
|
| `@usequeek/app-sdk/hono` | Thin Hono wrappers (`hono` optional peer) | Server-only |
|
|
20
33
|
| `@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
|
|
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.
|
|
34
|
+
| `@usequeek/app-sdk/browser` | Plain-browser code: `installAuthFetch` + bridge/theme helpers, no framework | Browser-safe ONLY |
|
|
24
35
|
|
|
25
|
-
|
|
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).
|
|
26
37
|
|
|
27
38
|
## Example (any framework)
|
|
28
39
|
|
|
@@ -136,17 +147,15 @@ fastify.post("/api/webhooks", async (req, reply) => {
|
|
|
136
147
|
|
|
137
148
|
### Why the raw body matters
|
|
138
149
|
|
|
139
|
-
Signature verification covers the exact bytes Queek sent (`{id}.{timestamp}.{body}
|
|
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()`.
|
|
140
151
|
|
|
141
152
|
### Body-size posture
|
|
142
153
|
|
|
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.
|
|
144
|
-
|
|
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.)
|
|
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.
|
|
146
155
|
|
|
147
156
|
### Hono
|
|
148
157
|
|
|
149
|
-
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.)
|
|
150
159
|
|
|
151
160
|
```ts
|
|
152
161
|
import { SqliteInstallationStore } from "@usequeek/app-sdk";
|
|
@@ -179,28 +188,33 @@ export default app;
|
|
|
179
188
|
Every Merchant API call goes through `createInstallationClient({ installationId, apiBase, tokens })`,
|
|
180
189
|
which resolves the installation's token via `acquireToken()` and sends it as `X-Client-Key`.
|
|
181
190
|
|
|
182
|
-
## Credential lifecycle (
|
|
191
|
+
## Credential lifecycle (GitHub-style installation tokens)
|
|
183
192
|
|
|
184
|
-
One asymmetric credential per app — no per-installation secrets cross the handoff
|
|
193
|
+
One asymmetric credential per app — no per-installation secrets cross the handoff.
|
|
185
194
|
|
|
186
|
-
1. **
|
|
187
|
-
|
|
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:
|
|
188
197
|
|
|
189
198
|
```sh
|
|
190
199
|
openssl genrsa -out app-private.pem 2048
|
|
191
200
|
openssl rsa -in app-private.pem -pubout -out app-public.pem
|
|
192
201
|
```
|
|
193
202
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
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`).
|
|
204
218
|
|
|
205
219
|
3. **Acquire / cache / re-mint.** `acquireToken(installationId)` serves the cached token while
|
|
206
220
|
its expiry is more than 5 minutes away; otherwise it signs an RS256 app JWT
|
|
@@ -209,14 +223,14 @@ One asymmetric credential per app — no per-installation secrets cross the hand
|
|
|
209
223
|
`kid` (one shared cache row per installation — restarts never burst). Concurrent callers
|
|
210
224
|
in one process share one in-flight mint; two containers minting at once is harmless by
|
|
211
225
|
design (Queek keeps coexisting tokens valid; a residual race self-heals via re-mint).
|
|
212
|
-
|
|
226
|
+
Token refusals: any 401, or 403 `api_key_revoked` / `api_key_expired` /
|
|
213
227
|
`invalid_client_key` → drop the token, re-mint once, retry once (a second refusal
|
|
214
228
|
propagates); 403 `app_token_revoked` → drop ALL cached tokens and halt minting (kill
|
|
215
229
|
switch / disabled app, no mint); every other 403 (scope, plan, mode) propagates to the
|
|
216
230
|
caller without a mint.
|
|
217
231
|
|
|
218
|
-
4. **Failures
|
|
219
|
-
constant
|
|
232
|
+
4. **Failures are handled by status and code** (`app-auth.ts` holds each code in one
|
|
233
|
+
constant):
|
|
220
234
|
- `401 invalid_client` — fatal for the app: loud log, minting stops, no retry loop.
|
|
221
235
|
- `403 app_token_revoked` (kill switch / disabled app) — drops ALL cached tokens, stops
|
|
222
236
|
minting, loud log. Minting resumes after the app is re-enabled + process restart
|
|
@@ -244,10 +258,10 @@ One asymmetric credential per app — no per-installation secrets cross the hand
|
|
|
244
258
|
existing installation idempotently (secret + settings refresh, `installedAt` and the
|
|
245
259
|
cached token kept).
|
|
246
260
|
|
|
247
|
-
6. **Kill switch behaviour.** One
|
|
248
|
-
every store on the next request. The SDK side
|
|
249
|
-
|
|
250
|
-
process restarts (or resumes).
|
|
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) →
|
|
251
265
|
switch the app to it → wait one token TTL → remove the old `kid`.
|
|
252
266
|
|
|
253
267
|
## Data rule + backups
|
|
@@ -257,7 +271,7 @@ Business data lives in Queek. `resyncFromQueek` restores CONNECTIVITY with zero
|
|
|
257
271
|
action — but app WORKING data (inbound tokens, order links, form tokens, app-side-only
|
|
258
272
|
settings) does NOT come back from resync: it needs the per-app `pg_dump` backup
|
|
259
273
|
(RPO ≤ 24 h) plus the `APP_ENCRYPTION_KEY` backup. Events missed beyond Queek's webhook
|
|
260
|
-
retries (~4 h) are gone; resync cannot backfill them.
|
|
274
|
+
retries (~4 h) are gone; resync cannot backfill them. Deploy reference: `queek app deploy --help`.
|
|
261
275
|
|
|
262
276
|
## Data deletion
|
|
263
277
|
|
|
@@ -273,8 +287,8 @@ topics, register explicit handlers for them — an unhandled topic only reports
|
|
|
273
287
|
|
|
274
288
|
## Storefront app-proxy (signed reads)
|
|
275
289
|
|
|
276
|
-
Queek signs each storefront proxy fetch with the installation's `proxy_secret
|
|
277
|
-
|
|
290
|
+
Queek signs each storefront proxy fetch with the installation's `proxy_secret`;
|
|
291
|
+
verify before answering the shopper:
|
|
278
292
|
|
|
279
293
|
```ts
|
|
280
294
|
import { handleProxyRequest } from "@usequeek/app-sdk";
|
|
@@ -293,7 +307,7 @@ The canonical string is `path + "\n" + shop + "\n" + ts + "\n" + sorted(k=v&...)
|
|
|
293
307
|
(`sig` excluded), hex HMAC-SHA256 over the FULL `whsec_…` string — no base64 decode
|
|
294
308
|
step. `kid` routes to the installation whose `proxy_secret` verifies (previous-secret
|
|
295
309
|
grace: pass every active secret to `verifyProxyQuery`); timestamps skew at most 5
|
|
296
|
-
minutes, each `jti` is single-use, and only `GET` is served (
|
|
310
|
+
minutes, each `jti` is single-use, and only `GET` is served (proxy reads are read-only).
|
|
297
311
|
Hono: mount `createProxyHandler({ store, path, onVerified })` from
|
|
298
312
|
`@usequeek/app-sdk/hono`.
|
|
299
313
|
|
|
@@ -302,32 +316,31 @@ Hono: mount `createProxyHandler({ store, path, onVerified })` from
|
|
|
302
316
|
- **app-auth** (`app-auth.ts`): `loadAppCredential` (`APP_SLUG`/`APP_KEY_ID`/`APP_PRIVATE_KEY`
|
|
303
317
|
— base64 of the PEM, raw PEM, or `\n`-escaped one-line PEM; RSA validated at boot),
|
|
304
318
|
`signAppJwt` (RS256, `iat` now − 60 s, `exp` window 540 s ≤ 600 s,
|
|
305
|
-
`kid` header), the
|
|
319
|
+
`kid` header), the error codes in one place (`INVALID_CLIENT_CODE`,
|
|
306
320
|
`APP_TOKEN_REVOKED_CODE`, `APP_INSTALLATION_GONE_CODE`, `APP_INSTALLATION_PENDING_CODE`,
|
|
307
321
|
`RESYNC_COOLDOWN_CODE`, `TOO_MANY_REQUESTS_CODE`), `AppMintHaltedError`.
|
|
308
322
|
- **tokens** (`tokens.ts`): `createAppTokenProvider({ credential, store, … })` —
|
|
309
|
-
`acquireToken` (cache → sign → mint → persist), single-flight per installation, the
|
|
310
|
-
|
|
323
|
+
`acquireToken` (cache → sign → mint → persist), single-flight per installation, with the
|
|
324
|
+
error handling in Credential lifecycle items 3–4;
|
|
311
325
|
`createInstallationClient({ installationId, apiBase, tokens })` — the `QueekClient`
|
|
312
326
|
every app call uses (re-mint once + retry once on token refusals only).
|
|
313
|
-
- **resync** (`resync.ts`): `resyncFromQueek({ apiBase, tokens, store })` —
|
|
314
|
-
|
|
315
|
-
429 `resync_cooldown` → skip + record; other 429 → backoff + retry) → drop tokens →
|
|
316
|
-
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.
|
|
317
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.
|
|
318
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.
|
|
319
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`).
|
|
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
|
|
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.
|
|
321
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.
|
|
322
|
-
- **proxy** (`proxy.ts`): `verifyProxyQuery` / `verifyProxyQueryDetailed` — app-proxy query verification byte-exact with
|
|
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`).
|
|
323
335
|
- **store** (`store.ts`): `SqliteInstallationStore` (local/dev/test) and `PostgresInstallationStore`
|
|
324
336
|
(`pg`, pool max 2, advisory-locked schema + `schema_version` row so two containers boot
|
|
325
337
|
safely) — installations encrypted at rest (AES-GCM via `APP_ENCRYPTION_KEY`), plus the
|
|
326
338
|
persisted 409-pending mark (`pending` column, schema v2, migrated in place) and the
|
|
327
339
|
seen-webhook-id claim table behind dedupe. Pick with `createInstallationStore()`
|
|
328
340
|
(`DATABASE_URL` set → Postgres, else SQLite — which production REFUSES with a clear
|
|
329
|
-
message).
|
|
330
|
-
a row to the app's database, with that store's token + webhook secret
|
|
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.
|
|
331
344
|
- **background** (`background.ts`): `detach` plus `runInstallationCatchup` — jittered
|
|
332
345
|
per-installation cron (uniform 0–600 s start jitter, per-install error isolation,
|
|
333
346
|
concurrency ≤ pool size, honors 429 once per installation).
|
|
@@ -337,12 +350,11 @@ Hono: mount `createProxyHandler({ store, path, onVerified })` from
|
|
|
337
350
|
`verifySessionToken` — HS256 dashboard session tokens minted per installation
|
|
338
351
|
(`embsec_…` secret, raw UTF-8 key bytes, 20 s clock tolerance, slug audience,
|
|
339
352
|
issuer = the handoff `apiBase` verbatim (`installation.apiBase` — it equals the
|
|
340
|
-
bare `app.url`
|
|
341
|
-
type
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
ignored. 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
|
|
346
358
|
browser bundle: the main entry does not export the verifier. The install
|
|
347
359
|
and resync handoffs deliver `embed_secret` + `app_id`; the store keeps
|
|
348
360
|
them on the installation (`embedSecret` encrypted, `appId`), and
|
|
@@ -389,8 +401,8 @@ Hono: mount `createProxyHandler({ store, path, onVerified })` from
|
|
|
389
401
|
after a later dashboard token arrives. Pass the same `capabilities`/
|
|
390
402
|
`sdkVersion` as the provider so its refresh `ready` announces one consistent set. The app's
|
|
391
403
|
token-exchange endpoint receives the first-load token and every 401-refresh
|
|
392
|
-
token through the same `exchange` callback
|
|
393
|
-
|
|
404
|
+
token through the same `exchange` callback, so it verifies both with the
|
|
405
|
+
single `verifySessionToken` verifier:
|
|
394
406
|
|
|
395
407
|
```ts
|
|
396
408
|
import { verifySessionTokenDetailed } from "@usequeek/app-sdk/server";
|
|
@@ -453,14 +465,14 @@ list you pass (the app surface exposes the grant but no declared list, so the
|
|
|
453
465
|
split needs your manifest knowledge). `requestScopes` returns
|
|
454
466
|
`/apps?app={slug}&view=scopes&scopes={a},{b}` (absolute under
|
|
455
467
|
`dashboardOrigin` when configured) — open it via `sendOpen` or a redirect: it
|
|
456
|
-
opens the merchant's consent screen in the dashboard (
|
|
457
|
-
|
|
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
|
|
458
470
|
resolves the installation from the signed-in store. The grant reaches you as a
|
|
459
471
|
signed `app/scopes_update` handoff, which the install/settings handlers apply
|
|
460
472
|
like a resync (same verifier, same replay claim): cached grant refreshed,
|
|
461
473
|
cached token dropped only when the grant moved.
|
|
462
474
|
|
|
463
|
-
## Embedded merchant page
|
|
475
|
+
## Embedded merchant page
|
|
464
476
|
|
|
465
477
|
The dashboard frames your app's granted merchant page in a
|
|
466
478
|
`sandbox="allow-scripts allow-forms"` iframe and delivers the session token
|
|
@@ -468,28 +480,22 @@ by postMessage. Serve the page with a `frame-ancestors` policy naming ONLY
|
|
|
468
480
|
your dashboard origin, for example:
|
|
469
481
|
|
|
470
482
|
```http
|
|
471
|
-
Content-Security-Policy: frame-ancestors https://
|
|
483
|
+
Content-Security-Policy: frame-ancestors https://dashboard.usequeek.com
|
|
472
484
|
```
|
|
473
485
|
|
|
474
486
|
Replace the host with the dashboard origin you registered. `frame-ancestors`
|
|
475
|
-
is a
|
|
476
|
-
site may frame the page, and the token handshake (origin-bound) is
|
|
477
|
-
remaining gate. Verify every token server-side before trusting calls that carry one
|
|
478
|
-
|
|
479
|
-
token through the same `installAuthFetch({ exchange })` callback — one token type,
|
|
480
|
-
verified with the single `verifySessionToken` verifier (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).
|
|
481
491
|
|
|
482
492
|
## Local development
|
|
483
493
|
|
|
484
|
-
Point the client at a local
|
|
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`.
|
|
485
495
|
|
|
486
496
|
Postgres locally: any Postgres works — point `DATABASE_URL` at it and the pg suite runs
|
|
487
497
|
(CI always runs it via a service container); without `DATABASE_URL` those tests skip cleanly.
|
|
488
498
|
|
|
489
|
-
## Registration
|
|
490
|
-
|
|
491
|
-
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.
|
|
492
|
-
|
|
493
499
|
## License
|
|
494
500
|
|
|
495
501
|
MIT — see [LICENSE](./LICENSE).
|
package/dist/app-auth.d.ts
CHANGED
|
@@ -1,21 +1,19 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The app credential
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
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
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* `
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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 —
|
|
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
|
/**
|
package/dist/app-auth.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app-auth.d.ts","sourceRoot":"","sources":["../src/app-auth.ts"],"names":[],"mappings":"AAEA
|
|
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
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
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
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* `
|
|
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
|
-
//
|
|
16
|
-
// one constant here, so a
|
|
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
|
|
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
|
|
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
|
|
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 (
|
|
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 —
|
|
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
|
|
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
|
|
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
|
|
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 {
|
package/dist/app-auth.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
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
|
|
1
|
+
{"version":3,"file":"app-auth.js","sourceRoot":"","sources":["../src/app-auth.ts"],"names":[],"mappings":"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"}
|
package/dist/auth-fetch.d.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Same-origin session carriage for embedded apps (
|
|
3
|
-
* carriage"): `installAuthFetch()` reads the dashboard token from the
|
|
2
|
+
* Same-origin session carriage for embedded apps: `installAuthFetch()` reads the dashboard token from the
|
|
4
3
|
* first-load URL (`?queek_token=`, stripped immediately), exchanges it
|
|
5
4
|
* ONCE for the app's own session, and attaches
|
|
6
5
|
* `Authorization: Bearer <session>` to every same-origin fetch. A 401
|
|
@@ -25,8 +24,7 @@ import { type EmbedEventTarget, type EmbedPostTarget } from "./frame.js";
|
|
|
25
24
|
* frame src contract (the ONLY token that may ride a URL, namespaced so it
|
|
26
25
|
* cannot collide with an app's own `token` param). The token is the same
|
|
27
26
|
* type the bridge `ready→token` flow returns on refresh — first load and
|
|
28
|
-
* refresh differ only in transport (URL param vs postMessage)
|
|
29
|
-
* Shopify's `id_token`.
|
|
27
|
+
* refresh differ only in transport (URL param vs postMessage).
|
|
30
28
|
*/
|
|
31
29
|
export declare const LAUNCH_TOKEN_PARAM = "queek_token";
|
|
32
30
|
/** How long to wait for the dashboard's token reply after a `ready`. */
|
package/dist/auth-fetch.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth-fetch.d.ts","sourceRoot":"","sources":["../src/auth-fetch.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"auth-fetch.d.ts","sourceRoot":"","sources":["../src/auth-fetch.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,EAAE,KAAK,gBAAgB,EAAE,KAAK,eAAe,EAAgC,MAAM,YAAY,CAAC;AAEvG;;;;;;GAMG;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"}
|
package/dist/auth-fetch.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Same-origin session carriage for embedded apps (
|
|
3
|
-
* carriage"): `installAuthFetch()` reads the dashboard token from the
|
|
2
|
+
* Same-origin session carriage for embedded apps: `installAuthFetch()` reads the dashboard token from the
|
|
4
3
|
* first-load URL (`?queek_token=`, stripped immediately), exchanges it
|
|
5
4
|
* ONCE for the app's own session, and attaches
|
|
6
5
|
* `Authorization: Bearer <session>` to every same-origin fetch. A 401
|
|
@@ -25,8 +24,7 @@ import { listenToDashboard, sendReady } from "./frame.js";
|
|
|
25
24
|
* frame src contract (the ONLY token that may ride a URL, namespaced so it
|
|
26
25
|
* cannot collide with an app's own `token` param). The token is the same
|
|
27
26
|
* type the bridge `ready→token` flow returns on refresh — first load and
|
|
28
|
-
* refresh differ only in transport (URL param vs postMessage)
|
|
29
|
-
* Shopify's `id_token`.
|
|
27
|
+
* refresh differ only in transport (URL param vs postMessage).
|
|
30
28
|
*/
|
|
31
29
|
export const LAUNCH_TOKEN_PARAM = "queek_token";
|
|
32
30
|
/** How long to wait for the dashboard's token reply after a `ready`. */
|
package/dist/auth-fetch.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth-fetch.js","sourceRoot":"","sources":["../src/auth-fetch.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"auth-fetch.js","sourceRoot":"","sources":["../src/auth-fetch.ts"],"names":[],"mappings":"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"}
|