@usequeek/app-sdk 0.6.2 → 0.7.0
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/LICENSE +1 -1
- package/README.md +340 -337
- package/dist/app-auth.d.ts +1 -2
- package/dist/app-auth.js +1 -2
- package/dist/auth-fetch.d.ts +12 -1
- package/dist/auth-fetch.js +13 -2
- package/dist/background.d.ts +9 -1
- package/dist/background.js +9 -1
- package/dist/browser.d.ts +1 -2
- package/dist/browser.js +1 -2
- package/dist/client.d.ts +130 -7
- package/dist/client.js +198 -41
- package/dist/collected.d.ts +0 -1
- package/dist/collected.js +0 -1
- package/dist/crypto.d.ts +11 -1
- package/dist/crypto.js +22 -7
- package/dist/delivery.d.ts +18 -1
- package/dist/delivery.js +26 -17
- package/dist/frame.d.ts +0 -1
- package/dist/frame.js +0 -1
- package/dist/handoff.d.ts +0 -1
- package/dist/handoff.js +0 -1
- package/dist/hono.d.ts +0 -1
- package/dist/hono.js +0 -1
- package/dist/index.d.ts +1 -2
- package/dist/index.js +1 -2
- package/dist/install-handlers.d.ts +22 -2
- package/dist/install-handlers.js +37 -7
- package/dist/logger.d.ts +7 -1
- package/dist/logger.js +7 -1
- package/dist/merchant-schema.d.ts +1184 -336
- package/dist/merchant-schema.js +0 -1
- package/dist/proxy.d.ts +2 -3
- package/dist/proxy.js +4 -5
- package/dist/react.d.ts +9 -1
- package/dist/react.js +10 -2
- package/dist/resync.d.ts +11 -1
- package/dist/resync.js +18 -16
- package/dist/scopes.d.ts +14 -1
- package/dist/scopes.js +18 -17
- package/dist/server.d.ts +0 -1
- package/dist/server.js +0 -1
- package/dist/session.d.ts +20 -1
- package/dist/session.js +20 -1
- package/dist/signatures.d.ts +26 -1
- package/dist/signatures.js +29 -3
- package/dist/store.d.ts +6 -1
- package/dist/store.js +0 -1
- package/dist/theme.d.ts +0 -1
- package/dist/theme.js +0 -1
- package/dist/tokens.d.ts +9 -1
- package/dist/tokens.js +23 -47
- package/dist/webhooks.d.ts +28 -3
- package/dist/webhooks.js +25 -7
- package/package.json +18 -2
- package/dist/app-auth.d.ts.map +0 -1
- package/dist/app-auth.js.map +0 -1
- package/dist/auth-fetch.d.ts.map +0 -1
- package/dist/auth-fetch.js.map +0 -1
- package/dist/background.d.ts.map +0 -1
- package/dist/background.js.map +0 -1
- package/dist/browser.d.ts.map +0 -1
- package/dist/browser.js.map +0 -1
- package/dist/client.d.ts.map +0 -1
- package/dist/client.js.map +0 -1
- package/dist/collected.d.ts.map +0 -1
- package/dist/collected.js.map +0 -1
- package/dist/crypto.d.ts.map +0 -1
- package/dist/crypto.js.map +0 -1
- package/dist/delivery.d.ts.map +0 -1
- package/dist/delivery.js.map +0 -1
- package/dist/frame.d.ts.map +0 -1
- package/dist/frame.js.map +0 -1
- package/dist/handoff.d.ts.map +0 -1
- package/dist/handoff.js.map +0 -1
- package/dist/hono.d.ts.map +0 -1
- package/dist/hono.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/install-handlers.d.ts.map +0 -1
- package/dist/install-handlers.js.map +0 -1
- package/dist/logger.d.ts.map +0 -1
- package/dist/logger.js.map +0 -1
- package/dist/merchant-schema.d.ts.map +0 -1
- package/dist/merchant-schema.js.map +0 -1
- package/dist/proxy.d.ts.map +0 -1
- package/dist/proxy.js.map +0 -1
- package/dist/react.d.ts.map +0 -1
- package/dist/react.js.map +0 -1
- package/dist/resync.d.ts.map +0 -1
- package/dist/resync.js.map +0 -1
- package/dist/scopes.d.ts.map +0 -1
- package/dist/scopes.js.map +0 -1
- package/dist/server.d.ts.map +0 -1
- package/dist/server.js.map +0 -1
- package/dist/session.d.ts.map +0 -1
- package/dist/session.js.map +0 -1
- package/dist/signatures.d.ts.map +0 -1
- package/dist/signatures.js.map +0 -1
- package/dist/store.d.ts.map +0 -1
- package/dist/store.js.map +0 -1
- package/dist/theme.d.ts.map +0 -1
- package/dist/theme.js.map +0 -1
- package/dist/tokens.d.ts.map +0 -1
- package/dist/tokens.js.map +0 -1
- package/dist/webhooks.d.ts.map +0 -1
- package/dist/webhooks.js.map +0 -1
package/dist/install-handlers.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { decodeBody, readHeader, toResponse, } from "./delivery.js";
|
|
1
|
+
import { decodeBody, readHeader, reportDeliveryFailure, toResponse, } from "./delivery.js";
|
|
2
2
|
import { INSTALL_EVENT, RESYNC_EVENT, SCOPES_UPDATE_EVENT, SETTINGS_EVENT, UNINSTALL_EVENT, } from "./handoff.js";
|
|
3
3
|
import { MAX_TIMESTAMP_SKEW_SECONDS, verifyQueekSignatureDetailed, WEBHOOK_ID_HEADER, WEBHOOK_SIGNATURE_HEADER, WEBHOOK_TIMESTAMP_HEADER, } from "./signatures.js";
|
|
4
4
|
import { normaliseNullablePid, normalisePid } from "./store.js";
|
|
@@ -106,6 +106,18 @@ export function saveResyncedInstallation(existing, data, nowIso = new Date().toI
|
|
|
106
106
|
* `uninstall`, or `settings`, taken from the input path's last segment)
|
|
107
107
|
* from plain data — no `Request`, no framework. Same options, same
|
|
108
108
|
* behaviour, same errors/status codes at every layer.
|
|
109
|
+
*
|
|
110
|
+
* Answers 401 for a missing header, stale timestamp or bad signature, 400
|
|
111
|
+
* for a body that is not the expected envelope, 409 for a repeated
|
|
112
|
+
* `webhook-id`, 404 for an unknown route, and 500 when your callback or the
|
|
113
|
+
* store write throws (Queek then retries).
|
|
114
|
+
*
|
|
115
|
+
* @example
|
|
116
|
+
* const result = await handleInstallDelivery(
|
|
117
|
+
* { rawBody, headers, method: "POST", path: "/queek/install" },
|
|
118
|
+
* { appSecret: process.env.APP_SIGNING_SECRET ?? "", store },
|
|
119
|
+
* );
|
|
120
|
+
* // reply with result.status and result.body
|
|
109
121
|
*/
|
|
110
122
|
export async function handleInstallDelivery(input, options) {
|
|
111
123
|
if ((input.method ?? "POST").toUpperCase() !== "POST") {
|
|
@@ -132,6 +144,9 @@ function trailingSegment(path) {
|
|
|
132
144
|
* Layer 2: the Web-standard wrapper, built ONLY on layer 1 — reads
|
|
133
145
|
* `await request.arrayBuffer()` + headers, calls the core, builds the
|
|
134
146
|
* `Response`.
|
|
147
|
+
*
|
|
148
|
+
* @example
|
|
149
|
+
* export const POST = (request: Request) => handleInstallRequest(request, { appSecret, store });
|
|
135
150
|
*/
|
|
136
151
|
export async function handleInstallRequest(request, options) {
|
|
137
152
|
return toResponse(await handleInstallDelivery({
|
|
@@ -169,6 +184,11 @@ function parseEnvelope(rawBody) {
|
|
|
169
184
|
return null;
|
|
170
185
|
}
|
|
171
186
|
}
|
|
187
|
+
function hasInstallationId(data) {
|
|
188
|
+
return (typeof data === "object" &&
|
|
189
|
+
data !== null &&
|
|
190
|
+
typeof data.installation?.id === "string");
|
|
191
|
+
}
|
|
172
192
|
function isInstallPayload(data) {
|
|
173
193
|
return (!!data &&
|
|
174
194
|
typeof data === "object" &&
|
|
@@ -243,8 +263,9 @@ async function scopesDelivery(rawBody, headers, options) {
|
|
|
243
263
|
}
|
|
244
264
|
}
|
|
245
265
|
}
|
|
246
|
-
catch {
|
|
266
|
+
catch (error) {
|
|
247
267
|
await options.store.releaseWebhookId(checked.id);
|
|
268
|
+
reportDeliveryFailure(options.onError, error, { stage: "scopes_update", eventId: checked.id });
|
|
248
269
|
return { status: 500, body: { ok: false, error: "scopes_update_failed" } };
|
|
249
270
|
}
|
|
250
271
|
return { status: 200, body: { ok: true } };
|
|
@@ -291,10 +312,11 @@ async function installDelivery(rawBody, headers, options) {
|
|
|
291
312
|
await applyResync(options.store, envelope.data);
|
|
292
313
|
}
|
|
293
314
|
}
|
|
294
|
-
catch {
|
|
315
|
+
catch (error) {
|
|
295
316
|
// Non-2xx on purpose: Queek revokes the key and the merchant retries
|
|
296
317
|
// as a fresh install. The claim is released so the retry can land.
|
|
297
318
|
await options.store.releaseWebhookId(checked.id);
|
|
319
|
+
reportDeliveryFailure(options.onError, error, { stage: "install", eventId: checked.id });
|
|
298
320
|
return { status: 500, body: { ok: false, error: "install_failed" } };
|
|
299
321
|
}
|
|
300
322
|
return { status: 200, body: { ok: true } };
|
|
@@ -309,6 +331,9 @@ async function uninstallDelivery(rawBody, headers, options) {
|
|
|
309
331
|
if (envelope.type !== UNINSTALL_EVENT) {
|
|
310
332
|
return { status: 400, body: { ok: false, error: "unexpected event type" } };
|
|
311
333
|
}
|
|
334
|
+
if (!hasInstallationId(envelope.data)) {
|
|
335
|
+
return { status: 400, body: { ok: false, error: "invalid uninstall payload" } };
|
|
336
|
+
}
|
|
312
337
|
if (!(await options.store.claimWebhookId(checked.id))) {
|
|
313
338
|
return { status: 409, body: { ok: false, error: "duplicate delivery" } };
|
|
314
339
|
}
|
|
@@ -320,8 +345,9 @@ async function uninstallDelivery(rawBody, headers, options) {
|
|
|
320
345
|
await options.store.deleteInstallation(envelope.data.installation.id);
|
|
321
346
|
}
|
|
322
347
|
}
|
|
323
|
-
catch {
|
|
348
|
+
catch (error) {
|
|
324
349
|
await options.store.releaseWebhookId(checked.id);
|
|
350
|
+
reportDeliveryFailure(options.onError, error, { stage: "uninstall", eventId: checked.id });
|
|
325
351
|
return { status: 500, body: { ok: false, error: "uninstall_failed" } };
|
|
326
352
|
}
|
|
327
353
|
return { status: 200, body: { ok: true } };
|
|
@@ -355,12 +381,16 @@ async function settingsDelivery(rawBody, headers, options) {
|
|
|
355
381
|
try {
|
|
356
382
|
await applyResync(options.store, envelope.data);
|
|
357
383
|
}
|
|
358
|
-
catch {
|
|
384
|
+
catch (error) {
|
|
359
385
|
await options.store.releaseWebhookId(checked.id);
|
|
386
|
+
reportDeliveryFailure(options.onError, error, { stage: "settings", eventId: checked.id });
|
|
360
387
|
return { status: 500, body: { ok: false, error: "settings_failed" } };
|
|
361
388
|
}
|
|
362
389
|
return { status: 200, body: { ok: true } };
|
|
363
390
|
}
|
|
391
|
+
if (!hasInstallationId(envelope.data)) {
|
|
392
|
+
return { status: 400, body: { ok: false, error: "invalid settings payload" } };
|
|
393
|
+
}
|
|
364
394
|
if (!(await options.store.claimWebhookId(checked.id))) {
|
|
365
395
|
return { status: 409, body: { ok: false, error: "duplicate delivery" } };
|
|
366
396
|
}
|
|
@@ -382,10 +412,10 @@ async function settingsDelivery(rawBody, headers, options) {
|
|
|
382
412
|
});
|
|
383
413
|
}
|
|
384
414
|
}
|
|
385
|
-
catch {
|
|
415
|
+
catch (error) {
|
|
386
416
|
await options.store.releaseWebhookId(checked.id);
|
|
417
|
+
reportDeliveryFailure(options.onError, error, { stage: "settings", eventId: checked.id });
|
|
387
418
|
return { status: 500, body: { ok: false, error: "settings_failed" } };
|
|
388
419
|
}
|
|
389
420
|
return { status: 200, body: { ok: true } };
|
|
390
421
|
}
|
|
391
|
-
//# sourceMappingURL=install-handlers.js.map
|
package/dist/logger.d.ts
CHANGED
|
@@ -23,5 +23,11 @@ export interface Logger {
|
|
|
23
23
|
warn(message: string, fields?: LogFields): void;
|
|
24
24
|
error(message: string, fields?: LogFields): void;
|
|
25
25
|
}
|
|
26
|
+
/**
|
|
27
|
+
* A JSON-lines logger with secret redaction built in.
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* const logger = createLogger({ service: "my-app" });
|
|
31
|
+
* logger.info("order synced", { order: "ord_123" });
|
|
32
|
+
*/
|
|
26
33
|
export declare function createLogger(options: LoggerOptions): Logger;
|
|
27
|
-
//# sourceMappingURL=logger.d.ts.map
|
package/dist/logger.js
CHANGED
|
@@ -40,6 +40,13 @@ function redactUnknown(value, depth) {
|
|
|
40
40
|
}
|
|
41
41
|
return value;
|
|
42
42
|
}
|
|
43
|
+
/**
|
|
44
|
+
* A JSON-lines logger with secret redaction built in.
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* const logger = createLogger({ service: "my-app" });
|
|
48
|
+
* logger.info("order synced", { order: "ord_123" });
|
|
49
|
+
*/
|
|
43
50
|
export function createLogger(options) {
|
|
44
51
|
const threshold = LEVELS[options.level ?? process.env.LOG_LEVEL ?? "info"] ?? 1;
|
|
45
52
|
const sink = options.sink ??
|
|
@@ -72,4 +79,3 @@ export function createLogger(options) {
|
|
|
72
79
|
error: (message, fields) => emit("error", message, fields),
|
|
73
80
|
};
|
|
74
81
|
}
|
|
75
|
-
//# sourceMappingURL=logger.js.map
|