@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.
- package/README.md +97 -78
- 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 +22 -23
- package/dist/auth-fetch.d.ts.map +1 -1
- package/dist/auth-fetch.js +22 -22
- package/dist/auth-fetch.js.map +1 -1
- package/dist/background.d.ts +1 -1
- package/dist/browser.d.ts +25 -0
- package/dist/browser.d.ts.map +1 -0
- package/dist/browser.js +27 -0
- package/dist/browser.js.map +1 -0
- 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/server.d.ts +3 -3
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +2 -2
- package/dist/server.js.map +1 -1
- package/dist/session.d.ts +16 -55
- package/dist/session.d.ts.map +1 -1
- package/dist/session.js +16 -86
- 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 +10 -6
- package/dist/theme.d.ts.map +1 -1
- package/dist/theme.js +10 -6
- package/dist/theme.js.map +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 +8 -3
package/dist/scopes.js
CHANGED
|
@@ -4,8 +4,7 @@ import { isAllowedOpenTarget } from "./frame.js";
|
|
|
4
4
|
import { installationScopesEqual } from "./install-handlers.js";
|
|
5
5
|
import { resolveAppApiBase } from "./tokens.js";
|
|
6
6
|
/**
|
|
7
|
-
* Optional scopes
|
|
8
|
-
* parity — symbol names cited only).
|
|
7
|
+
* Optional scopes: query, request and revoke.
|
|
9
8
|
*
|
|
10
9
|
* - `queryScopes`: the cached effective grant split against the app's own
|
|
11
10
|
* declared-optional list. Store-read only, never a fetch: the app-credential
|
|
@@ -17,25 +16,24 @@ import { resolveAppApiBase } from "./tokens.js";
|
|
|
17
16
|
* consent — it hands the app a link shaped like the bridge
|
|
18
17
|
* `open`/`navigate` targets (dashboard-relative path, or an absolute URL
|
|
19
18
|
* under a given dashboard origin) for the app to open via `sendOpen` or
|
|
20
|
-
* redirect to.
|
|
21
|
-
*
|
|
19
|
+
* redirect to. Opening it requires a dashboard that supports the consent
|
|
20
|
+
* screen, which honours this link shape.
|
|
22
21
|
* - `revokeScopes`: `POST
|
|
23
22
|
* /api/v1/apps/installations/{installation}/scopes/revoke` with the app
|
|
24
|
-
* JWT (same credential as mint/resync —
|
|
25
|
-
*
|
|
26
|
-
* `RevokeAppScopesRequest`); an `Idempotency-Key` rides the write for
|
|
23
|
+
* JWT (same credential as mint/resync — not the installation token).
|
|
24
|
+
* Body `{scopes[]}` (1–50); an `Idempotency-Key` rides the write for
|
|
27
25
|
* discipline (generated when the caller does not supply one — the client
|
|
28
26
|
* write discipline), though the route is naturally idempotent: revoking
|
|
29
27
|
* a never-granted optional scope is 200 with no change. Required scopes
|
|
30
28
|
* refuse 422 `app_scope_required` (surfaced as `AppScopeRequiredError`).
|
|
31
29
|
* On 200 the cached grant is refreshed from the response and the cached
|
|
32
30
|
* token dropped only when the grant moved (same compare-and-clear as the
|
|
33
|
-
* scopes_update handler —
|
|
34
|
-
*
|
|
31
|
+
* scopes_update handler — Queek rewrites live token rows in place, so
|
|
32
|
+
* the drop is a backstop, not the mechanism).
|
|
35
33
|
*
|
|
36
34
|
* Types here are hand-written: the revoke endpoint and the scopes_update
|
|
37
|
-
* handoff live on the app-credential surface, which the
|
|
38
|
-
* `openapi/merchant.json` does not cover (types are generated app-side by
|
|
35
|
+
* handoff live on the app-credential surface, which the bundled
|
|
36
|
+
* `openapi/merchant.json` snapshot does not cover (types are generated app-side by
|
|
39
37
|
* `queek app codegen`; the merchant spec file is never hand-edited).
|
|
40
38
|
*/
|
|
41
39
|
/** 422 on the revoke endpoint: required scopes are never revocable (uninstall is the remedy). */
|
|
@@ -48,8 +46,8 @@ export function isAppScopeRequired(status, code) {
|
|
|
48
46
|
}
|
|
49
47
|
/**
|
|
50
48
|
* A required-scope refusal, typed so callers switch on the class (or
|
|
51
|
-
* `code`), never on `message`. Carries the offending scopes when
|
|
52
|
-
*
|
|
49
|
+
* `code`), never on `message`. Carries the offending scopes when Queek
|
|
50
|
+
* named them.
|
|
53
51
|
*/
|
|
54
52
|
export class AppScopeRequiredError extends QueekApiError {
|
|
55
53
|
scopes;
|
|
@@ -79,13 +77,13 @@ export class InvalidScopesError extends Error {
|
|
|
79
77
|
this.name = "InvalidScopesError";
|
|
80
78
|
}
|
|
81
79
|
}
|
|
82
|
-
/**
|
|
80
|
+
/** Bounds of the revoke request (1–50 scopes), mirrored client-side. */
|
|
83
81
|
export const MAX_SCOPE_LIST = 50;
|
|
84
82
|
export const MAX_SCOPE_LENGTH = 120;
|
|
85
83
|
/**
|
|
86
84
|
* Validate + normalise a scope list (trim, drop empties, dedupe keeping
|
|
87
|
-
* first order). Mirrors the
|
|
88
|
-
*
|
|
85
|
+
* first order). Mirrors the revoke endpoint's rules (a required array of
|
|
86
|
+
* 1–50 string items) so a malformed call fails before any fetch.
|
|
89
87
|
*/
|
|
90
88
|
export function normaliseScopeList(scopes) {
|
|
91
89
|
if (!Array.isArray(scopes)) {
|
|
@@ -134,8 +132,7 @@ export function revokeScopesPath(installationId) {
|
|
|
134
132
|
* under `dashboardOrigin` (refused exactly like `sendOpen` refuses a bad
|
|
135
133
|
* target).
|
|
136
134
|
*
|
|
137
|
-
* Link shape (the
|
|
138
|
-
* the only query route the dashboard `AppsPage` serves):
|
|
135
|
+
* Link shape (the contract the dashboard's consent screen honours):
|
|
139
136
|
* `/apps?app={slug}&view=scopes&scopes={a},{b}` (each scope
|
|
140
137
|
* URL-encoded, comma-separated). The link carries the slug + the scope
|
|
141
138
|
* list only: the dashboard resolves the installation from the signed-in
|
|
@@ -193,7 +190,7 @@ export function createInstallationScopesClient(options) {
|
|
|
193
190
|
* The dashboard deep link that opens the merchant's consent screen in
|
|
194
191
|
* the dashboard. Pure (no store, no network): the app opens it via
|
|
195
192
|
* `sendOpen` or a redirect and the merchant consents in the dashboard
|
|
196
|
-
* (
|
|
193
|
+
* (requires a dashboard that supports the consent screen). Shaped like the bridge `open`
|
|
197
194
|
* targets — dashboard-relative, or absolute under the dashboard origin
|
|
198
195
|
* when one is configured.
|
|
199
196
|
*/
|
|
@@ -209,14 +206,13 @@ export function createInstallationScopesClient(options) {
|
|
|
209
206
|
});
|
|
210
207
|
}
|
|
211
208
|
/**
|
|
212
|
-
* App-initiated revoke of optional scopes
|
|
213
|
-
* `AppInstallationController::revokeScopes`): the app JWT signs the call
|
|
209
|
+
* App-initiated revoke of optional scopes: the app JWT signs the call
|
|
214
210
|
* (same credential as mint/resync), an `Idempotency-Key` rides the write
|
|
215
211
|
* for discipline only (the route is naturally idempotent), and on 200
|
|
216
212
|
* the cached grant is refreshed from the response with the cached token
|
|
217
213
|
* dropped only when the grant moved (same compare-and-clear as the
|
|
218
|
-
* scopes_update handler — backstop, since
|
|
219
|
-
*
|
|
214
|
+
* scopes_update handler — a backstop, since Queek rewrites live token
|
|
215
|
+
* rows in place). A required scope refuses 422
|
|
220
216
|
* `app_scope_required` as `AppScopeRequiredError`; a gone installation
|
|
221
217
|
* purges the local row and rethrows; anything else propagates untouched.
|
|
222
218
|
* A 401 never halts here — the mint path owns that mapping and halts on
|
package/dist/scopes.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scopes.js","sourceRoot":"","sources":["../src/scopes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,wBAAwB,EAAE,MAAM,eAAe,CAAC;AAC7E,OAAO,EAAE,iBAAiB,EAAE,aAAa,EAAE,yBAAyB,EAAE,MAAM,aAAa,CAAC;AAC1F,OAAO,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AACjD,OAAO,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AAEhE,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAEhD
|
|
1
|
+
{"version":3,"file":"scopes.js","sourceRoot":"","sources":["../src/scopes.ts"],"names":[],"mappings":"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"}
|
package/dist/server.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Server-only entry
|
|
2
|
+
* Server-only entry: session-token verification needs the
|
|
3
3
|
* per-installation `embsec_…` secret, which must never enter a browser
|
|
4
4
|
* bundle. Import the verifier from `@usequeek/app-sdk/server`, never from
|
|
5
5
|
* the main entry.
|
|
6
6
|
*/
|
|
7
|
-
export type {
|
|
8
|
-
export { EMBED_SECRET_PREFIX,
|
|
7
|
+
export type { SessionTokenBinding, SessionTokenClaims, SessionTokenFailure, VerifySessionTokenOptions, } from "./session.js";
|
|
8
|
+
export { EMBED_SECRET_PREFIX, SESSION_CLOCK_TOLERANCE_SECONDS, sessionTokenInstallationId, verifySessionToken, verifySessionTokenDetailed, } from "./session.js";
|
|
9
9
|
//# sourceMappingURL=server.d.ts.map
|
package/dist/server.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,YAAY,EACV,
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,YAAY,EACV,mBAAmB,EACnB,kBAAkB,EAClB,mBAAmB,EACnB,yBAAyB,GAC1B,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,mBAAmB,EACnB,+BAA+B,EAC/B,0BAA0B,EAC1B,kBAAkB,EAClB,0BAA0B,GAC3B,MAAM,cAAc,CAAC"}
|
package/dist/server.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Server-only entry
|
|
2
|
+
* Server-only entry: session-token verification needs the
|
|
3
3
|
* per-installation `embsec_…` secret, which must never enter a browser
|
|
4
4
|
* bundle. Import the verifier from `@usequeek/app-sdk/server`, never from
|
|
5
5
|
* the main entry.
|
|
6
6
|
*/
|
|
7
|
-
export { EMBED_SECRET_PREFIX,
|
|
7
|
+
export { EMBED_SECRET_PREFIX, SESSION_CLOCK_TOLERANCE_SECONDS, sessionTokenInstallationId, verifySessionToken, verifySessionTokenDetailed, } from "./session.js";
|
|
8
8
|
//# sourceMappingURL=server.js.map
|
package/dist/server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAQH,OAAO,EACL,mBAAmB,EACnB,+BAA+B,EAC/B,0BAA0B,EAC1B,kBAAkB,EAClB,0BAA0B,GAC3B,MAAM,cAAc,CAAC"}
|
package/dist/session.d.ts
CHANGED
|
@@ -1,18 +1,15 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Dashboard session tokens
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
2
|
+
* Dashboard session tokens: short-lived HS256 JWTs Queek mints per
|
|
3
|
+
* installation for the framed merchant page. The app's server verifies
|
|
4
|
+
* them with the per-installation `embsec_…` secret before trusting any
|
|
5
|
+
* call that carries one.
|
|
6
6
|
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
* other's purpose with the same failure path callers map to 401, so a
|
|
14
|
-
* launch token that rode a URL can never be replayed as a bridge token
|
|
15
|
-
* and vice versa.
|
|
7
|
+
* ONE token type: the dashboard puts the same token in the first-load URL
|
|
8
|
+
* param (`queek_token`, stripped on arrival) and answers bridge `ready`
|
|
9
|
+
* requests with it, so the app's exchange endpoint verifies first-load and
|
|
10
|
+
* refresh tokens with this one verifier. No purpose split: extra claims the
|
|
11
|
+
* mint may carry are ignored, never gated — identity binding
|
|
12
|
+
* (installation, audience, issuer, expiry) is the whole check.
|
|
16
13
|
*
|
|
17
14
|
* Server-only: the secret must never enter a browser bundle, so this module
|
|
18
15
|
* ships behind the `./server` export, not the main entry. Style mirrors
|
|
@@ -22,9 +19,9 @@
|
|
|
22
19
|
export declare const EMBED_SECRET_PREFIX = "embsec_";
|
|
23
20
|
/** The only JWS algorithm the dashboard mints (HS256 over the embsec_ secret). */
|
|
24
21
|
export declare const SESSION_TOKEN_ALG = "HS256";
|
|
25
|
-
/**
|
|
22
|
+
/** Clock skew the verifier tolerates, in seconds (matches the mint side). */
|
|
26
23
|
export declare const SESSION_CLOCK_TOLERANCE_SECONDS = 20;
|
|
27
|
-
export type SessionTokenFailure = "missing_token" | "missing_secret" | "wrong_algorithm" | "invalid_signature" | "expired" | "not_yet_valid" | "wrong_audience" | "wrong_issuer" | "
|
|
24
|
+
export type SessionTokenFailure = "missing_token" | "missing_secret" | "wrong_algorithm" | "invalid_signature" | "expired" | "not_yet_valid" | "wrong_audience" | "wrong_issuer" | "binding_mismatch";
|
|
28
25
|
export interface SessionTokenClaims {
|
|
29
26
|
installationId: string;
|
|
30
27
|
vendorId: string;
|
|
@@ -41,17 +38,6 @@ export interface SessionTokenBinding {
|
|
|
41
38
|
appSlug: string;
|
|
42
39
|
appId: string;
|
|
43
40
|
}
|
|
44
|
-
/**
|
|
45
|
-
* Launch-token claims: the bridge binding plus the launch-only hints the
|
|
46
|
-
* backend mints for the signed first load — the store p_id (the URL-safe
|
|
47
|
-
* store id) and the dashboard theme for a flash-free first paint. Both are
|
|
48
|
-
* hints, not auth: `storePid` is null when the mint carried none, `theme`
|
|
49
|
-
* is null unless the mint carried exactly `light` or `dark`.
|
|
50
|
-
*/
|
|
51
|
-
export interface LaunchTokenClaims extends SessionTokenClaims {
|
|
52
|
-
storePid: number | null;
|
|
53
|
-
theme: "light" | "dark" | null;
|
|
54
|
-
}
|
|
55
41
|
export interface VerifySessionTokenOptions {
|
|
56
42
|
/** The per-installation `embsec_…` secret, raw UTF-8 bytes (never decoded). */
|
|
57
43
|
secret: string;
|
|
@@ -59,15 +45,15 @@ export interface VerifySessionTokenOptions {
|
|
|
59
45
|
audience: string;
|
|
60
46
|
/**
|
|
61
47
|
* Expected issuer: the handoff `api_base` VERBATIM
|
|
62
|
-
* (`installation.apiBase` — it equals the bare `app.url`
|
|
63
|
-
*
|
|
48
|
+
* (`installation.apiBase` — it equals the bare `app.url` Queek signs as
|
|
49
|
+
* `iss`). Never a prefix or a suffix of it.
|
|
64
50
|
*/
|
|
65
51
|
issuer: string;
|
|
66
52
|
/**
|
|
67
|
-
* The installation row the token must belong to (the app
|
|
53
|
+
* The installation row the token must belong to (the app server's own
|
|
68
54
|
* record). Every field is compared — a token minted for another
|
|
69
55
|
* installation fails closed even when its signature and audience check
|
|
70
|
-
* out
|
|
56
|
+
* out.
|
|
71
57
|
*/
|
|
72
58
|
expected: SessionTokenBinding;
|
|
73
59
|
clockToleranceSeconds?: number;
|
|
@@ -80,24 +66,6 @@ export declare function verifySessionTokenDetailed(token: string, options: Verif
|
|
|
80
66
|
ok: false;
|
|
81
67
|
reason: SessionTokenFailure;
|
|
82
68
|
}>;
|
|
83
|
-
/**
|
|
84
|
-
* Server-side launch exchange input (signed first load): verify a
|
|
85
|
-
* purpose=launch token with the SAME checks as the bridge verifier
|
|
86
|
-
* (signature, audience, issuer, installation binding, expiry) plus the
|
|
87
|
-
* purpose pin — anything but exactly `"launch"` is refused with
|
|
88
|
-
* `wrong_purpose`, so a bridge token can never open the exchange. On
|
|
89
|
-
* success the app mints its own session from the claims (subject, store,
|
|
90
|
-
* theme) and the first paint needs no bridge round-trip. Callers map every
|
|
91
|
-
* `{ ok: false }` to 401, mirroring the backend `verify()`.
|
|
92
|
-
*/
|
|
93
|
-
export declare function verifyLaunchToken(token: string, options: VerifySessionTokenOptions): Promise<boolean>;
|
|
94
|
-
export declare function verifyLaunchTokenDetailed(token: string, options: VerifySessionTokenOptions): Promise<{
|
|
95
|
-
ok: true;
|
|
96
|
-
claims: LaunchTokenClaims;
|
|
97
|
-
} | {
|
|
98
|
-
ok: false;
|
|
99
|
-
reason: SessionTokenFailure;
|
|
100
|
-
}>;
|
|
101
69
|
/**
|
|
102
70
|
* ROUTING HINT ONLY — the `installation_id` claim read WITHOUT verifying
|
|
103
71
|
* anything, so a server can load the installation whose embed secret then
|
|
@@ -106,11 +74,4 @@ export declare function verifyLaunchTokenDetailed(token: string, options: Verify
|
|
|
106
74
|
* Null for anything that is not a decodable JWT carrying the claim.
|
|
107
75
|
*/
|
|
108
76
|
export declare function sessionTokenInstallationId(token: string): string | null;
|
|
109
|
-
/**
|
|
110
|
-
* True for the purposes the bridge verifier accepts: absent (legacy
|
|
111
|
-
* tokens) or "session". "launch" is the signed first-load token for the
|
|
112
|
-
* launch exchange (`verifyLaunchToken`) only, so the bridge verifier
|
|
113
|
-
* refuses it. Any other present value fails closed.
|
|
114
|
-
*/
|
|
115
|
-
export declare function isBridgePurpose(purpose: unknown): boolean;
|
|
116
77
|
//# sourceMappingURL=session.d.ts.map
|
package/dist/session.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../src/session.ts"],"names":[],"mappings":"AAEA
|
|
1
|
+
{"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../src/session.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;GAiBG;AAEH,eAAO,MAAM,mBAAmB,YAAY,CAAC;AAE7C,kFAAkF;AAClF,eAAO,MAAM,iBAAiB,UAAU,CAAC;AAEzC,6EAA6E;AAC7E,eAAO,MAAM,+BAA+B,KAAK,CAAC;AAElD,MAAM,MAAM,mBAAmB,GAC3B,eAAe,GACf,gBAAgB,GAChB,iBAAiB,GACjB,mBAAmB,GACnB,SAAS,GACT,eAAe,GACf,gBAAgB,GAChB,cAAc,GACd,kBAAkB,CAAC;AAEvB,MAAM,WAAW,kBAAkB;IACjC,cAAc,EAAE,MAAM,CAAC;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,mBAAmB;IAClC,cAAc,EAAE,MAAM,CAAC;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,yBAAyB;IACxC,+EAA+E;IAC/E,MAAM,EAAE,MAAM,CAAC;IACf,8CAA8C;IAC9C,QAAQ,EAAE,MAAM,CAAC;IACjB;;;;OAIG;IACH,MAAM,EAAE,MAAM,CAAC;IACf;;;;;OAKG;IACH,QAAQ,EAAE,mBAAmB,CAAC;IAC9B,qBAAqB,CAAC,EAAE,MAAM,CAAC;CAChC;AAED,wBAAsB,kBAAkB,CACtC,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,yBAAyB,GACjC,OAAO,CAAC,OAAO,CAAC,CAGlB;AAED,wBAAsB,0BAA0B,CAC9C,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,yBAAyB,GACjC,OAAO,CAAC;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,kBAAkB,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,mBAAmB,CAAA;CAAE,CAAC,CAUhG;AAkDD;;;;;;GAMG;AACH,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAOvE"}
|
package/dist/session.js
CHANGED
|
@@ -1,19 +1,16 @@
|
|
|
1
1
|
import { decodeJwt, decodeProtectedHeader, jwtVerify } from "jose";
|
|
2
2
|
/**
|
|
3
|
-
* Dashboard session tokens
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
3
|
+
* Dashboard session tokens: short-lived HS256 JWTs Queek mints per
|
|
4
|
+
* installation for the framed merchant page. The app's server verifies
|
|
5
|
+
* them with the per-installation `embsec_…` secret before trusting any
|
|
6
|
+
* call that carries one.
|
|
7
7
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
* other's purpose with the same failure path callers map to 401, so a
|
|
15
|
-
* launch token that rode a URL can never be replayed as a bridge token
|
|
16
|
-
* and vice versa.
|
|
8
|
+
* ONE token type: the dashboard puts the same token in the first-load URL
|
|
9
|
+
* param (`queek_token`, stripped on arrival) and answers bridge `ready`
|
|
10
|
+
* requests with it, so the app's exchange endpoint verifies first-load and
|
|
11
|
+
* refresh tokens with this one verifier. No purpose split: extra claims the
|
|
12
|
+
* mint may carry are ignored, never gated — identity binding
|
|
13
|
+
* (installation, audience, issuer, expiry) is the whole check.
|
|
17
14
|
*
|
|
18
15
|
* Server-only: the secret must never enter a browser bundle, so this module
|
|
19
16
|
* ships behind the `./server` export, not the main entry. Style mirrors
|
|
@@ -23,7 +20,7 @@ import { decodeJwt, decodeProtectedHeader, jwtVerify } from "jose";
|
|
|
23
20
|
export const EMBED_SECRET_PREFIX = "embsec_";
|
|
24
21
|
/** The only JWS algorithm the dashboard mints (HS256 over the embsec_ secret). */
|
|
25
22
|
export const SESSION_TOKEN_ALG = "HS256";
|
|
26
|
-
/**
|
|
23
|
+
/** Clock skew the verifier tolerates, in seconds (matches the mint side). */
|
|
27
24
|
export const SESSION_CLOCK_TOLERANCE_SECONDS = 20;
|
|
28
25
|
export async function verifySessionToken(token, options) {
|
|
29
26
|
const result = await verifySessionTokenDetailed(token, options);
|
|
@@ -33,16 +30,7 @@ export async function verifySessionTokenDetailed(token, options) {
|
|
|
33
30
|
const envelope = await verifyTokenEnvelope(token, options);
|
|
34
31
|
if (!envelope.ok)
|
|
35
32
|
return envelope;
|
|
36
|
-
const
|
|
37
|
-
// Purpose binding (backend contract): absent or "session" is a bridge
|
|
38
|
-
// token; "launch" belongs to the signed first-load exchange only and is
|
|
39
|
-
// refused here with the same failure path callers map to 401. Any other
|
|
40
|
-
// present purpose fails closed as well — the bridge verifier accepts
|
|
41
|
-
// exactly the bridge purposes, never a foreign one.
|
|
42
|
-
if (!isBridgePurpose(payload.purpose)) {
|
|
43
|
-
return { ok: false, reason: "wrong_purpose" };
|
|
44
|
-
}
|
|
45
|
-
const claims = readSessionClaims(payload);
|
|
33
|
+
const claims = readSessionClaims(envelope.payload);
|
|
46
34
|
const { expected } = options;
|
|
47
35
|
if (!claims || !bindingMatches(claims, expected)) {
|
|
48
36
|
return { ok: false, reason: "binding_mismatch" };
|
|
@@ -50,39 +38,9 @@ export async function verifySessionTokenDetailed(token, options) {
|
|
|
50
38
|
return { ok: true, claims };
|
|
51
39
|
}
|
|
52
40
|
/**
|
|
53
|
-
*
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
* purpose pin — anything but exactly `"launch"` is refused with
|
|
57
|
-
* `wrong_purpose`, so a bridge token can never open the exchange. On
|
|
58
|
-
* success the app mints its own session from the claims (subject, store,
|
|
59
|
-
* theme) and the first paint needs no bridge round-trip. Callers map every
|
|
60
|
-
* `{ ok: false }` to 401, mirroring the backend `verify()`.
|
|
61
|
-
*/
|
|
62
|
-
export async function verifyLaunchToken(token, options) {
|
|
63
|
-
const result = await verifyLaunchTokenDetailed(token, options);
|
|
64
|
-
return result.ok;
|
|
65
|
-
}
|
|
66
|
-
export async function verifyLaunchTokenDetailed(token, options) {
|
|
67
|
-
const envelope = await verifyTokenEnvelope(token, options);
|
|
68
|
-
if (!envelope.ok)
|
|
69
|
-
return envelope;
|
|
70
|
-
const { payload } = envelope;
|
|
71
|
-
if (payload.purpose !== "launch") {
|
|
72
|
-
return { ok: false, reason: "wrong_purpose" };
|
|
73
|
-
}
|
|
74
|
-
const claims = readSessionClaims(payload);
|
|
75
|
-
const { expected } = options;
|
|
76
|
-
if (!claims || !bindingMatches(claims, expected)) {
|
|
77
|
-
return { ok: false, reason: "binding_mismatch" };
|
|
78
|
-
}
|
|
79
|
-
return { ok: true, claims: { ...claims, ...readLaunchHints(payload) } };
|
|
80
|
-
}
|
|
81
|
-
/**
|
|
82
|
-
* Shared envelope verification for both purposes: presence, secret shape,
|
|
83
|
-
* algorithm pin, then signature + audience + issuer + expiry via jose.
|
|
84
|
-
* Purpose and binding checks stay with the caller — the only thing that
|
|
85
|
-
* differs between the bridge and launch verifiers.
|
|
41
|
+
* Envelope verification: presence, secret shape, algorithm pin, then
|
|
42
|
+
* signature + audience + issuer + expiry via jose. Binding checks stay
|
|
43
|
+
* with the caller.
|
|
86
44
|
*/
|
|
87
45
|
async function verifyTokenEnvelope(token, options) {
|
|
88
46
|
if (!token) {
|
|
@@ -120,24 +78,6 @@ function bindingMatches(claims, expected) {
|
|
|
120
78
|
claims.appSlug === expected.appSlug &&
|
|
121
79
|
claims.appId === expected.appId);
|
|
122
80
|
}
|
|
123
|
-
/**
|
|
124
|
-
* Launch-only hints off a verified payload. Tolerant by design (they steer
|
|
125
|
-
* first paint, never auth): `store` is the integer p_id or null, `theme`
|
|
126
|
-
* survives only as exactly `light` or `dark`.
|
|
127
|
-
*
|
|
128
|
-
* Boundary (deliberate, pinned both sides): this `store` claim is an INT,
|
|
129
|
-
* while install-handoff p_ids are STRINGS per the handoff contract — never
|
|
130
|
-
* accept a string here to "match" the handoff; a string claim nulls the
|
|
131
|
-
* hint (session.test.ts) exactly as the backend pins int (AppUiKitTest).
|
|
132
|
-
*/
|
|
133
|
-
function readLaunchHints(payload) {
|
|
134
|
-
const store = payload.store;
|
|
135
|
-
const theme = payload.theme;
|
|
136
|
-
return {
|
|
137
|
-
storePid: typeof store === "number" && Number.isInteger(store) && store >= 0 ? store : null,
|
|
138
|
-
theme: theme === "light" || theme === "dark" ? theme : null,
|
|
139
|
-
};
|
|
140
|
-
}
|
|
141
81
|
/**
|
|
142
82
|
* ROUTING HINT ONLY — the `installation_id` claim read WITHOUT verifying
|
|
143
83
|
* anything, so a server can load the installation whose embed secret then
|
|
@@ -168,15 +108,6 @@ function readTokenAlg(token) {
|
|
|
168
108
|
return null;
|
|
169
109
|
}
|
|
170
110
|
}
|
|
171
|
-
/**
|
|
172
|
-
* True for the purposes the bridge verifier accepts: absent (legacy
|
|
173
|
-
* tokens) or "session". "launch" is the signed first-load token for the
|
|
174
|
-
* launch exchange (`verifyLaunchToken`) only, so the bridge verifier
|
|
175
|
-
* refuses it. Any other present value fails closed.
|
|
176
|
-
*/
|
|
177
|
-
export function isBridgePurpose(purpose) {
|
|
178
|
-
return purpose === undefined || purpose === null || purpose === "session";
|
|
179
|
-
}
|
|
180
111
|
function readSessionClaims(payload) {
|
|
181
112
|
const pick = (key) => typeof payload[key] === "string" && payload[key].length > 0 ? payload[key] : null;
|
|
182
113
|
const installationId = pick("installation_id");
|
|
@@ -200,8 +131,7 @@ function readSessionClaims(payload) {
|
|
|
200
131
|
return { installationId, vendorId, appSlug, appId, subject, sessionId, issuedAt, expiresAt };
|
|
201
132
|
}
|
|
202
133
|
function classifyJoseError(error) {
|
|
203
|
-
// Exact jose v6
|
|
204
|
-
// the `claim` field probed, not guessed): claim failures carry code
|
|
134
|
+
// Exact jose v6 error shapes (jose@6.2.12): claim failures carry code
|
|
205
135
|
// ERR_JWT_CLAIM_VALIDATION_FAILED and name the claim; expiry also
|
|
206
136
|
// surfaces as JWTExpired / ERR_JWT_EXPIRED; algorithm refusal is
|
|
207
137
|
// JOSEAlgNotAllowed / ERR_JOSE_ALG_NOT_ALLOWED (unreachable in practice —
|
package/dist/session.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session.js","sourceRoot":"","sources":["../src/session.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,qBAAqB,EAAE,SAAS,EAAE,MAAM,MAAM,CAAC;AAEnE
|
|
1
|
+
{"version":3,"file":"session.js","sourceRoot":"","sources":["../src/session.ts"],"names":[],"mappings":"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"}
|
package/dist/signatures.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Standard Webhooks verification, byte-for-byte compatible with
|
|
3
|
-
*
|
|
2
|
+
* Standard Webhooks verification, byte-for-byte compatible with the way
|
|
3
|
+
* Queek signs deliveries
|
|
4
|
+
* (https://github.com/standard-webhooks/standard-webhooks/blob/main/spec/standard-webhooks.md).
|
|
4
5
|
*
|
|
5
6
|
* Signed content: `{id}.{timestamp}.{body}` where `body` is the RAW request
|
|
6
7
|
* bytes. Re-serialising JSON before verifying breaks the MAC — verify first,
|
|
@@ -8,7 +9,7 @@
|
|
|
8
9
|
*
|
|
9
10
|
* The MAC key is the DECODED bytes of the `whsec_<base64>` secret, not the
|
|
10
11
|
* printable string. A secret without the prefix (or with undecodable base64)
|
|
11
|
-
* falls back to the raw string, exactly like
|
|
12
|
+
* falls back to the raw string, exactly like Queek's signer.
|
|
12
13
|
*
|
|
13
14
|
* Header names: `webhook-id`, `webhook-timestamp`, `webhook-signature`.
|
|
14
15
|
* The signature header may carry several space-delimited `v1,<base64>`
|
|
@@ -41,7 +42,7 @@ export interface VerifyOptions {
|
|
|
41
42
|
skipFreshnessCheck?: boolean;
|
|
42
43
|
}
|
|
43
44
|
export declare function secretKeyBytes(secret: string): Buffer;
|
|
44
|
-
/** One `v1,<base64>` signature for one secret
|
|
45
|
+
/** One `v1,<base64>` signature for one secret, in the format Queek sends. */
|
|
45
46
|
export declare function signQueekPayload(eventId: string, timestamp: number | string, body: string, secret: string): string;
|
|
46
47
|
/** Failure reason when verification rejects a delivery. */
|
|
47
48
|
export type SignatureFailure = "missing_headers" | "stale_timestamp" | "signature_mismatch";
|
package/dist/signatures.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"signatures.d.ts","sourceRoot":"","sources":["../src/signatures.ts"],"names":[],"mappings":"AAEA
|
|
1
|
+
{"version":3,"file":"signatures.d.ts","sourceRoot":"","sources":["../src/signatures.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;GAgBG;AAEH,eAAO,MAAM,iBAAiB,eAAe,CAAC;AAC9C,eAAO,MAAM,wBAAwB,sBAAsB,CAAC;AAC5D,eAAO,MAAM,wBAAwB,sBAAsB,CAAC;AAC5D,eAAO,MAAM,aAAa,WAAW,CAAC;AAEtC,2GAA2G;AAC3G,eAAO,MAAM,0BAA0B,QAAS,CAAC;AAEjD,MAAM,WAAW,cAAc;IAC7B,wCAAwC;IACxC,EAAE,EAAE,MAAM,CAAC;IACX,uEAAuE;IACvE,SAAS,EAAE,MAAM,CAAC;IAClB,yCAAyC;IACzC,IAAI,EAAE,MAAM,CAAC;IACb,wFAAwF;IACxF,eAAe,EAAE,MAAM,CAAC;IACxB,yCAAyC;IACzC,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,aAAa;IAC5B,oFAAoF;IACpF,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,8EAA8E;IAC9E,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,yFAAyF;IACzF,kBAAkB,CAAC,EAAE,OAAO,CAAC;CAC9B;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAarD;AAED,6EAA6E;AAC7E,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,GAAG,MAAM,EAC1B,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,GACb,MAAM,CAKR;AAED,2DAA2D;AAC3D,MAAM,MAAM,gBAAgB,GAAG,iBAAiB,GAAG,iBAAiB,GAAG,oBAAoB,CAAC;AAE5F,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,cAAc,EAAE,OAAO,GAAE,aAAkB,GAAG,OAAO,CAEhG;AAED,wBAAgB,4BAA4B,CAC1C,KAAK,EAAE,cAAc,EACrB,OAAO,GAAE,aAAkB,GAC1B;IAAE,EAAE,EAAE,IAAI,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,gBAAgB,CAAA;CAAE,CAyBxD"}
|
package/dist/signatures.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { createHmac, timingSafeEqual } from "node:crypto";
|
|
2
2
|
/**
|
|
3
|
-
* Standard Webhooks verification, byte-for-byte compatible with
|
|
4
|
-
*
|
|
3
|
+
* Standard Webhooks verification, byte-for-byte compatible with the way
|
|
4
|
+
* Queek signs deliveries
|
|
5
|
+
* (https://github.com/standard-webhooks/standard-webhooks/blob/main/spec/standard-webhooks.md).
|
|
5
6
|
*
|
|
6
7
|
* Signed content: `{id}.{timestamp}.{body}` where `body` is the RAW request
|
|
7
8
|
* bytes. Re-serialising JSON before verifying breaks the MAC — verify first,
|
|
@@ -9,7 +10,7 @@ import { createHmac, timingSafeEqual } from "node:crypto";
|
|
|
9
10
|
*
|
|
10
11
|
* The MAC key is the DECODED bytes of the `whsec_<base64>` secret, not the
|
|
11
12
|
* printable string. A secret without the prefix (or with undecodable base64)
|
|
12
|
-
* falls back to the raw string, exactly like
|
|
13
|
+
* falls back to the raw string, exactly like Queek's signer.
|
|
13
14
|
*
|
|
14
15
|
* Header names: `webhook-id`, `webhook-timestamp`, `webhook-signature`.
|
|
15
16
|
* The signature header may carry several space-delimited `v1,<base64>`
|
|
@@ -25,8 +26,8 @@ export function secretKeyBytes(secret) {
|
|
|
25
26
|
const encoded = secret.startsWith(SECRET_PREFIX) ? secret.slice(SECRET_PREFIX.length) : secret;
|
|
26
27
|
try {
|
|
27
28
|
const decoded = Buffer.from(encoded, "base64");
|
|
28
|
-
// Round-trip guard:
|
|
29
|
-
//
|
|
29
|
+
// Round-trip guard: Queek's signer falls back to the raw secret string
|
|
30
|
+
// when the input is not strictly valid base64.
|
|
30
31
|
if (decoded.length > 0 && decoded.toString("base64").replace(/=+$/, "") === encoded.replace(/=+$/, "")) {
|
|
31
32
|
return decoded;
|
|
32
33
|
}
|
|
@@ -36,7 +37,7 @@ export function secretKeyBytes(secret) {
|
|
|
36
37
|
return Buffer.from(secret, "utf8");
|
|
37
38
|
}
|
|
38
39
|
}
|
|
39
|
-
/** One `v1,<base64>` signature for one secret
|
|
40
|
+
/** One `v1,<base64>` signature for one secret, in the format Queek sends. */
|
|
40
41
|
export function signQueekPayload(eventId, timestamp, body, secret) {
|
|
41
42
|
const mac = createHmac("sha256", secretKeyBytes(secret))
|
|
42
43
|
.update(`${eventId}.${timestamp}.${body}`, "utf8")
|
package/dist/signatures.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"signatures.js","sourceRoot":"","sources":["../src/signatures.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAE1D
|
|
1
|
+
{"version":3,"file":"signatures.js","sourceRoot":"","sources":["../src/signatures.ts"],"names":[],"mappings":"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"}
|