@gathertown/webhook-object-sdk 0.1.1 → 0.2.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/dist/src/catalog.js +39 -30
- package/dist/src/catalog.js.map +7 -1
- package/dist/src/client.js +100 -108
- package/dist/src/client.js.map +7 -1
- package/dist/src/deliver.js +133 -129
- package/dist/src/deliver.js.map +7 -1
- package/dist/src/errors.js +41 -24
- package/dist/src/errors.js.map +7 -1
- package/dist/src/index.js +39 -12
- package/dist/src/index.js.map +7 -1
- package/dist/src/secret.js +61 -46
- package/dist/src/secret.js.map +7 -1
- package/package.json +4 -3
- package/dist/src/catalog.d.ts.map +0 -1
- package/dist/src/client.d.ts.map +0 -1
- package/dist/src/deliver.d.ts.map +0 -1
- package/dist/src/errors.d.ts.map +0 -1
- package/dist/src/index.d.ts.map +0 -1
- package/dist/src/secret.d.ts.map +0 -1
package/dist/src/catalog.js
CHANGED
|
@@ -1,31 +1,40 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
Object.defineProperty
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var catalog_exports = {};
|
|
20
|
+
__export(catalog_exports, {
|
|
21
|
+
createWebhookObjectCatalog: () => createWebhookObjectCatalog
|
|
22
|
+
});
|
|
23
|
+
module.exports = __toCommonJS(catalog_exports);
|
|
24
|
+
var import_client = require("./client");
|
|
25
|
+
const createWebhookObjectCatalog = (entries, options = {}) => (
|
|
26
|
+
// fromEntries can't see the per-entry preset literals, so it needs the double assertion to
|
|
27
|
+
// reach the mapped catalog type; per-name correctness is covered by compile-time tests.
|
|
28
|
+
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
29
|
+
Object.fromEntries(
|
|
30
|
+
Object.entries(entries).map(([name, entry]) => [
|
|
31
|
+
name,
|
|
32
|
+
(0, import_client.createWebhookObjectClient)({ ...entry, ...options })
|
|
33
|
+
])
|
|
34
|
+
)
|
|
35
|
+
);
|
|
36
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
37
|
+
0 && (module.exports = {
|
|
38
|
+
createWebhookObjectCatalog
|
|
39
|
+
});
|
|
40
|
+
//# sourceMappingURL=catalog.js.map
|
package/dist/src/catalog.js.map
CHANGED
|
@@ -1 +1,7 @@
|
|
|
1
|
-
{
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/catalog.ts"],
|
|
4
|
+
"sourcesContent": ["import type { WebhookObjectPreset } from \"@gathertown/webhook-object-types\"\nimport { createWebhookObjectClient, WebhookObjectClient, WebhookObjectClientConfig } from \"./client\"\n\n/** Runtime options that apply to every client in the catalog rather than a single object. */\ntype SharedClientOption = \"maxAttempts\" | \"fetch\" | \"newWebhookId\"\n\n/** Per-object entry: the (url, secret) pair plus optional compile-time preset scoping. */\nexport type WebhookObjectCatalogEntry = Omit<WebhookObjectClientConfig, SharedClientOption>\n\n/** Options shared by every client in the catalog. */\nexport type WebhookObjectCatalogOptions = Pick<WebhookObjectClientConfig, SharedClientOption>\n\n/** The preset literal declared on an entry, or `undefined` when the entry has none. */\ntype PresetOf<Entry extends WebhookObjectCatalogEntry> = Entry extends {\n preset: infer Preset extends WebhookObjectPreset\n}\n ? Preset\n : undefined\n\n/**\n * The value returned by `createWebhookObjectCatalog`: each entry name maps to a client whose\n * `send` is narrowed to that entry's declared preset (or unconstrained when it has none).\n */\nexport type WebhookObjectCatalog<Entries extends Record<string, WebhookObjectCatalogEntry>> = {\n [Name in keyof Entries]: WebhookObjectClient<PresetOf<Entries[Name]>>\n}\n\n/**\n * Build a named catalog of webhook-object clients so multiple Smart Objects (inboxes,\n * lamps, counters, \u2026) stay at hand behind one value. Each entry is just its (url, secret)\n * pair, each secret authenticates only its own object.\n *\n * Entries with a `preset` get a compile-time-narrowed `send`: an `inbox` client only\n * accepts inbox event types, so wiring the lamp's events to the inbox is a type error.\n *\n * ```ts\n * const office = createWebhookObjectCatalog({\n * supportInbox: { url: INBOX_URL, secret: secretFromEnv(\"GATHER_INBOX_SECRET\"), preset: \"inbox\" },\n * buildLamp: { url: LAMP_URL, secret: secretFromEnv(\"GATHER_LAMP_SECRET\"), preset: \"switch\" },\n * })\n * await office.supportInbox.send(\"activity.add\", { id: \"pr-142\", text: \"PR #142 merged\" })\n * await office.buildLamp.send(\"switch.toggle\")\n * ```\n */\nexport const createWebhookObjectCatalog = <\n const Entries extends Record<string, WebhookObjectCatalogEntry>,\n>(\n entries: Entries,\n options: WebhookObjectCatalogOptions = {},\n): WebhookObjectCatalog<Entries> =>\n // fromEntries can't see the per-entry preset literals, so it needs the double assertion to\n // reach the mapped catalog type; per-name correctness is covered by compile-time tests.\n // eslint-disable-next-line @typescript-eslint/consistent-type-assertions\n Object.fromEntries(\n Object.entries(entries).map(([name, entry]) => [\n name,\n createWebhookObjectClient({ ...entry, ...options }),\n ]),\n ) as unknown as WebhookObjectCatalog<Entries>\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AACA,oBAA0F;AA2CnF,MAAM,6BAA6B,CAGxC,SACA,UAAuC,CAAC;AAAA;AAAA;AAAA;AAAA,EAKxC,OAAO;AAAA,IACL,OAAO,QAAQ,OAAO,EAAE,IAAI,CAAC,CAAC,MAAM,KAAK,MAAM;AAAA,MAC7C;AAAA,UACA,yCAA0B,EAAE,GAAG,OAAO,GAAG,QAAQ,CAAC;AAAA,IACpD,CAAC;AAAA,EACH;AAAA;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
package/dist/src/client.js
CHANGED
|
@@ -1,118 +1,110 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
Object.defineProperty
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var client_exports = {};
|
|
20
|
+
__export(client_exports, {
|
|
21
|
+
createWebhookObjectClient: () => createWebhookObjectClient
|
|
22
|
+
});
|
|
23
|
+
module.exports = __toCommonJS(client_exports);
|
|
24
|
+
var import_standardwebhooks = require("standardwebhooks");
|
|
25
|
+
var import_deliver = require("./deliver");
|
|
26
|
+
var import_errors = require("./errors");
|
|
27
|
+
var import_secret = require("./secret");
|
|
28
|
+
const LOCAL_HOSTNAMES = /* @__PURE__ */ new Set(["localhost", "127.0.0.1", "[::1]"]);
|
|
14
29
|
const assertValidUrl = (url) => {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
30
|
+
let parsed;
|
|
31
|
+
try {
|
|
32
|
+
parsed = new URL(url);
|
|
33
|
+
} catch (cause) {
|
|
34
|
+
throw new import_errors.WebhookObjectError("invalid_url", `webhook object URL is not a valid URL: ${url}`, {
|
|
35
|
+
cause
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
if (parsed.protocol === "https:") return;
|
|
39
|
+
if (parsed.protocol === "http:" && LOCAL_HOSTNAMES.has(parsed.hostname)) return;
|
|
40
|
+
throw new import_errors.WebhookObjectError(
|
|
41
|
+
"invalid_url",
|
|
42
|
+
`webhook object URL must use https (got ${parsed.protocol}//); http is allowed only for localhost`
|
|
43
|
+
);
|
|
29
44
|
};
|
|
30
|
-
/** Fluent method → wire method segment: `setState` → `set_state`. */
|
|
31
45
|
const wireMethodName = (method) => method.replace(/[A-Z]/g, (char) => `_${char.toLowerCase()}`);
|
|
32
|
-
|
|
33
|
-
* Properties runtimes probe on arbitrary objects (`await` checks `then`, serializers check
|
|
34
|
-
* `toJSON`). The capability proxy must not answer these, or `await client.counter` would hang.
|
|
35
|
-
*/
|
|
36
|
-
const PROBED_PROPS = new Set(["then", "toJSON"]);
|
|
37
|
-
/** Both "accepted" statuses; extra body fields (if the receiver ever adds any) pass through. */
|
|
46
|
+
const PROBED_PROPS = /* @__PURE__ */ new Set(["then", "toJSON"]);
|
|
38
47
|
const isSendResult = (body) => body.status === "dispatched" || body.status === "space_idle";
|
|
39
|
-
|
|
40
|
-
const isPingResult = (body) => body.status === "pong" &&
|
|
41
|
-
typeof body.objectId === "string" &&
|
|
42
|
-
typeof body.spaceId === "string" &&
|
|
43
|
-
(body.preset === null || typeof body.preset === "string") &&
|
|
44
|
-
typeof body.capabilities === "object" &&
|
|
45
|
-
body.capabilities !== null;
|
|
48
|
+
const isPingResult = (body) => body.status === "pong" && typeof body.objectId === "string" && typeof body.spaceId === "string" && (body.preset === null || typeof body.preset === "string") && typeof body.capabilities === "object" && body.capabilities !== null;
|
|
46
49
|
const serializeEnvelope = (type, data) => {
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
50
|
+
const body = JSON.stringify({ type, timestamp: (/* @__PURE__ */ new Date()).toISOString(), data });
|
|
51
|
+
const byteLength = new TextEncoder().encode(body).length;
|
|
52
|
+
if (byteLength > import_deliver.MAX_BODY_BYTES)
|
|
53
|
+
throw new import_errors.WebhookObjectError(
|
|
54
|
+
"payload_too_large",
|
|
55
|
+
`webhook object payload is ${byteLength} bytes; the server caps bodies at ${import_deliver.MAX_BODY_BYTES} bytes`
|
|
56
|
+
);
|
|
57
|
+
return body;
|
|
52
58
|
};
|
|
53
|
-
/**
|
|
54
|
-
* Create a client for one webhook object. Signing follows Standard Webhooks v1: HMAC over
|
|
55
|
-
* `${id}.${timestamp}.${body}` via the `standardwebhooks` reference library, sent as the
|
|
56
|
-
* `webhook-id` / `webhook-timestamp` / `webhook-signature` headers. The exact serialized
|
|
57
|
-
* body is signed and sent unchanged, so the two can never drift.
|
|
58
|
-
*/
|
|
59
59
|
const createWebhookObjectClient = (config) => {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
const
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
const webhookId = newWebhookId();
|
|
77
|
-
const responseBody = await (0, deliver_1.deliver)({
|
|
78
|
-
url: config.url,
|
|
79
|
-
body,
|
|
80
|
-
webhookId,
|
|
81
|
-
sign: (timestampSeconds) => webhook.sign(webhookId, new Date(timestampSeconds * 1000), body),
|
|
82
|
-
fetchImpl,
|
|
83
|
-
maxAttempts,
|
|
84
|
-
signal: config.signal,
|
|
85
|
-
});
|
|
86
|
-
if (!isExpectedBody(responseBody))
|
|
87
|
-
throw new errors_1.WebhookObjectError("unexpected_response", `webhook object ${type} succeeded but returned an unrecognized body (status: ${String(responseBody.status)})`);
|
|
88
|
-
return responseBody;
|
|
89
|
-
};
|
|
90
|
-
const sendEvent = (type, data) => dispatch(type, data, isSendResult);
|
|
91
|
-
const base = {
|
|
92
|
-
send: (type, ...args) => sendEvent(type, args[0] ?? {}),
|
|
93
|
-
ping: () => dispatch("webhook.ping", {}, isPingResult),
|
|
94
|
-
};
|
|
95
|
-
/** `client.counter` → namespace whose method calls become `sendEvent("counter.<method>")`. */
|
|
96
|
-
const capabilityNamespace = (capability) => new Proxy({}, {
|
|
97
|
-
get: (_target, method) => {
|
|
98
|
-
if (typeof method !== "string" || PROBED_PROPS.has(method))
|
|
99
|
-
return undefined;
|
|
100
|
-
return (data) => sendEvent(`${capability}.${wireMethodName(method)}`, data ?? {});
|
|
101
|
-
},
|
|
102
|
-
});
|
|
103
|
-
// The fluent surface is type-driven (CapabilityNamespaces); the proxy only assembles wire
|
|
104
|
-
// names, so new capabilities work via a types-package bump with zero SDK changes.
|
|
105
|
-
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
106
|
-
return new Proxy(base, {
|
|
107
|
-
get: (target, prop, receiver) => {
|
|
108
|
-
// Real members (send/ping) win over capability namespaces, as do symbol lookups.
|
|
109
|
-
if (prop in target || typeof prop !== "string")
|
|
110
|
-
return Reflect.get(target, prop, receiver);
|
|
111
|
-
if (PROBED_PROPS.has(prop))
|
|
112
|
-
return undefined;
|
|
113
|
-
return capabilityNamespace(prop);
|
|
114
|
-
},
|
|
60
|
+
assertValidUrl(config.url);
|
|
61
|
+
const webhook = new import_standardwebhooks.Webhook((0, import_secret.revealSecret)(config.secret));
|
|
62
|
+
const fetchImpl = config.fetch ?? fetch;
|
|
63
|
+
const newWebhookId = config.newWebhookId ?? (() => crypto.randomUUID());
|
|
64
|
+
const maxAttempts = config.maxAttempts ?? import_deliver.DEFAULT_MAX_ATTEMPTS;
|
|
65
|
+
const dispatch = async (type, data, isExpectedBody) => {
|
|
66
|
+
const body = serializeEnvelope(type, data);
|
|
67
|
+
const webhookId = newWebhookId();
|
|
68
|
+
const responseBody = await (0, import_deliver.deliver)({
|
|
69
|
+
url: config.url,
|
|
70
|
+
body,
|
|
71
|
+
webhookId,
|
|
72
|
+
sign: (timestampSeconds) => webhook.sign(webhookId, new Date(timestampSeconds * 1e3), body),
|
|
73
|
+
fetchImpl,
|
|
74
|
+
maxAttempts,
|
|
75
|
+
signal: config.signal
|
|
115
76
|
});
|
|
77
|
+
if (!isExpectedBody(responseBody))
|
|
78
|
+
throw new import_errors.WebhookObjectError(
|
|
79
|
+
"unexpected_response",
|
|
80
|
+
`webhook object ${type} succeeded but returned an unrecognized body (status: ${String(responseBody.status)})`
|
|
81
|
+
);
|
|
82
|
+
return responseBody;
|
|
83
|
+
};
|
|
84
|
+
const sendEvent = (type, data) => dispatch(type, data, isSendResult);
|
|
85
|
+
const base = {
|
|
86
|
+
send: (type, ...args) => sendEvent(type, args[0] ?? {}),
|
|
87
|
+
ping: () => dispatch("webhook.ping", {}, isPingResult)
|
|
88
|
+
};
|
|
89
|
+
const capabilityNamespace = (capability) => new Proxy(
|
|
90
|
+
{},
|
|
91
|
+
{
|
|
92
|
+
get: (_target, method) => {
|
|
93
|
+
if (typeof method !== "string" || PROBED_PROPS.has(method)) return void 0;
|
|
94
|
+
return (data) => sendEvent(`${capability}.${wireMethodName(method)}`, data ?? {});
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
);
|
|
98
|
+
return new Proxy(base, {
|
|
99
|
+
get: (target, prop, receiver) => {
|
|
100
|
+
if (prop in target || typeof prop !== "string") return Reflect.get(target, prop, receiver);
|
|
101
|
+
if (PROBED_PROPS.has(prop)) return void 0;
|
|
102
|
+
return capabilityNamespace(prop);
|
|
103
|
+
}
|
|
104
|
+
});
|
|
116
105
|
};
|
|
117
|
-
|
|
118
|
-
|
|
106
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
107
|
+
0 && (module.exports = {
|
|
108
|
+
createWebhookObjectClient
|
|
109
|
+
});
|
|
110
|
+
//# sourceMappingURL=client.js.map
|
package/dist/src/client.js.map
CHANGED
|
@@ -1 +1,7 @@
|
|
|
1
|
-
{
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/client.ts"],
|
|
4
|
+
"sourcesContent": ["import { Webhook } from \"standardwebhooks\"\n\nimport type {\n DataFor,\n EventTypeForPreset,\n ReservedEventType,\n WebhookEventType,\n WebhookObjectPreset,\n} from \"@gathertown/webhook-object-types\"\nimport { DEFAULT_MAX_ATTEMPTS, deliver, MAX_BODY_BYTES } from \"./deliver\"\nimport { WebhookObjectError } from \"./errors\"\nimport { revealSecret, WebhookObjectSecret } from \"./secret\"\n\nexport type WebhookObjectClientConfig = {\n /** The object's full webhook URL (copied from the object's \u22EE menu in Gather). */\n url: string\n /**\n * The object's signing secret (per-object; never shared between objects). Either the raw\n * `whsec_\u2026` string, or (recommended) an opaque handle from `secretFromEnv()` /\n * `unsafeSecretLiteral()`, which redacts itself if the config is ever logged or serialized.\n */\n secret: WebhookObjectSecret | string\n /**\n * Compile-time narrowing only: when set, `send` accepts only event types this preset\n * declares (plus reserved `webhook.*`). The server enforces the same thing at runtime.\n */\n preset?: WebhookObjectPreset\n /** Total delivery attempts per event (initial + retries on 429/5xx/network). Default 3. */\n maxAttempts?: number\n /** Custom fetch implementation (tests, proxies). Defaults to the global fetch (Node 18+). */\n fetch?: typeof fetch\n /**\n * Override the per-event `webhook-id` generator. Defaults to the global `crypto.randomUUID`;\n * inject your own for runtimes without global `crypto`, or for deterministic tests. Must return\n * a unique value per event (the server dedups by id, so reused ids would drop distinct events).\n */\n newWebhookId?: () => string\n /**\n * Cancels an in-flight `send`/`ping`, including any pending retry backoff, when aborted.\n * The call rejects with a `WebhookObjectError` whose `code` is `aborted`.\n */\n signal?: AbortSignal\n}\n\n/**\n * Event types a client scoped to preset `P` may send. Intersected with `WebhookEventType`\n * so `DataFor<T>` stays applicable while `P` is still generic.\n */\nexport type AllowedEventType<P extends WebhookObjectPreset | undefined> =\n (P extends WebhookObjectPreset ? EventTypeForPreset<P> : WebhookEventType) & WebhookEventType\n\n/** Empty-payload events take no `data` argument; everything else requires one. */\ntype DataArgs<T extends WebhookEventType> =\n DataFor<T> extends Record<string, never> ? [] : [data: DataFor<T>]\n\n/** Both statuses mean \"accepted\": `space_idle` means the space wasn't live, and the event was persisted for it. */\nexport type SendResult = { status: \"dispatched\" | \"space_idle\" }\n\n/** The `webhook.ping` snapshot: what this object is and what it currently accepts. */\nexport type PingResult = {\n status: \"pong\"\n objectId: string\n spaceId: string\n preset: WebhookObjectPreset | null\n capabilities: Record<string, unknown>\n}\n\n/** `set_state` \u2192 `setState`: fluent method names are idiomatic camelCase versions of wire names. */\ntype SnakeToCamel<S extends string> = S extends `${infer Head}_${infer Tail}`\n ? `${Head}${Capitalize<SnakeToCamel<Tail>>}`\n : S\n\n/** The capability segment of an event type: `\"counter.reset\"` \u2192 `\"counter\"`. */\ntype CapabilityNameOf<E extends string> = E extends `${infer Capability}.${string}`\n ? Capability\n : never\n\n/**\n * Capability-namespaced sugar over `send`: `client.counter.reset()`,\n * `client.switch.setState({ on: true })`. Derived entirely from the generated event union, so\n * new capabilities appear via a types-package bump; reserved `webhook.*` events are excluded\n * (`ping()` is first-class). Backed by a `Proxy` at runtime: no codegen, no runtime catalog.\n */\nexport type CapabilityNamespaces<Events extends WebhookEventType> = {\n [Capability in CapabilityNameOf<Exclude<Events, ReservedEventType>>]: {\n [Event in Extract<\n Events,\n `${Capability}.${string}`\n > as Event extends `${Capability}.${infer Method}` ? SnakeToCamel<Method> : never]: (\n ...args: DataArgs<Event>\n ) => Promise<SendResult>\n }\n}\n\n/**\n * A client bound to one webhook object. Exposes `send`/`ping` plus the capability-namespaced\n * fluent sugar (`client.counter.increment(...)`). The optional preset `P` narrows every surface\n * to the event types that preset declares.\n */\nexport type WebhookObjectClient<P extends WebhookObjectPreset | undefined = undefined> = {\n /**\n * Sign and POST one event. `data` is inferred from the event type and omitted entirely\n * for empty-payload events (e.g. `send(\"counter.reset\")`).\n */\n send<T extends AllowedEventType<P>>(type: T, ...args: DataArgs<T>): Promise<SendResult>\n /** Verify the URL + secret and fetch the object's declared capability state. */\n ping(): Promise<PingResult>\n} & CapabilityNamespaces<AllowedEventType<P>>\n\n/** Hosts allowed to receive cleartext http, so local development keeps working. */\nconst LOCAL_HOSTNAMES = new Set([\"localhost\", \"127.0.0.1\", \"[::1]\"])\n\n/**\n * Signing authenticates but does not encrypt: over plain http the payload, headers, and\n * signature travel in cleartext. Refuse everything but https, except toward localhost.\n */\nconst assertValidUrl = (url: string): void => {\n let parsed: URL\n try {\n parsed = new URL(url)\n } catch (cause) {\n throw new WebhookObjectError(\"invalid_url\", `webhook object URL is not a valid URL: ${url}`, {\n cause,\n })\n }\n if (parsed.protocol === \"https:\") return\n if (parsed.protocol === \"http:\" && LOCAL_HOSTNAMES.has(parsed.hostname)) return\n throw new WebhookObjectError(\n \"invalid_url\",\n `webhook object URL must use https (got ${parsed.protocol}//); http is allowed only for localhost`,\n )\n}\n\n/** Fluent method \u2192 wire method segment: `setState` \u2192 `set_state`. */\nconst wireMethodName = (method: string): string =>\n method.replace(/[A-Z]/g, (char) => `_${char.toLowerCase()}`)\n\n/**\n * Properties runtimes probe on arbitrary objects (`await` checks `then`, serializers check\n * `toJSON`). The capability proxy must not answer these, or `await client.counter` would hang.\n */\nconst PROBED_PROPS = new Set([\"then\", \"toJSON\"])\n\n/** Both \"accepted\" statuses; extra body fields (if the receiver ever adds any) pass through. */\nconst isSendResult = (body: Record<string, unknown>): body is SendResult =>\n body.status === \"dispatched\" || body.status === \"space_idle\"\n\n/** The pong snapshot, checked field by field: the wire is untrusted, so the shape is proven. */\nconst isPingResult = (body: Record<string, unknown>): body is PingResult =>\n body.status === \"pong\" &&\n typeof body.objectId === \"string\" &&\n typeof body.spaceId === \"string\" &&\n (body.preset === null || typeof body.preset === \"string\") &&\n typeof body.capabilities === \"object\" &&\n body.capabilities !== null\n\nconst serializeEnvelope = (type: string, data: unknown): string => {\n const body = JSON.stringify({ type, timestamp: new Date().toISOString(), data })\n const byteLength = new TextEncoder().encode(body).length\n if (byteLength > MAX_BODY_BYTES)\n throw new WebhookObjectError(\n \"payload_too_large\",\n `webhook object payload is ${byteLength} bytes; the server caps bodies at ${MAX_BODY_BYTES} bytes`,\n )\n return body\n}\n\n/**\n * Create a client for one webhook object. Signing follows Standard Webhooks v1: HMAC over\n * `${id}.${timestamp}.${body}` via the `standardwebhooks` reference library, sent as the\n * `webhook-id` / `webhook-timestamp` / `webhook-signature` headers. The exact serialized\n * body is signed and sent unchanged, so the two can never drift.\n */\nexport const createWebhookObjectClient = <P extends WebhookObjectPreset | undefined = undefined>(\n config: WebhookObjectClientConfig & { preset?: P },\n): WebhookObjectClient<P> => {\n assertValidUrl(config.url)\n // Revealed once here and captured only by the standardwebhooks signer; the returned\n // client never holds the raw value on an enumerable property.\n const webhook = new Webhook(revealSecret(config.secret))\n const fetchImpl = config.fetch ?? fetch\n const newWebhookId = config.newWebhookId ?? (() => crypto.randomUUID())\n const maxAttempts = config.maxAttempts ?? DEFAULT_MAX_ATTEMPTS\n\n /**\n * Sign, deliver, and narrow the response to the caller's expected shape. The caller controls\n * the result type, but through a runtime guard rather than a cast: the wire is untrusted, so\n * an off-contract 200 body throws `unexpected_response` instead of lying about its shape.\n */\n const dispatch = async <R extends Record<string, unknown>>(\n type: string,\n data: unknown,\n isExpectedBody: (body: Record<string, unknown>) => body is R,\n ): Promise<R> => {\n const body = serializeEnvelope(type, data)\n // One id per event, reused across retries: the server dedups the last 10 ids per\n // object, so a retry can never double-apply.\n const webhookId = newWebhookId()\n const responseBody = await deliver({\n url: config.url,\n body,\n webhookId,\n sign: (timestampSeconds) => webhook.sign(webhookId, new Date(timestampSeconds * 1000), body),\n fetchImpl,\n maxAttempts,\n signal: config.signal,\n })\n if (!isExpectedBody(responseBody))\n throw new WebhookObjectError(\n \"unexpected_response\",\n `webhook object ${type} succeeded but returned an unrecognized body (status: ${String(responseBody.status)})`,\n )\n return responseBody\n }\n\n const sendEvent = (type: string, data: unknown): Promise<SendResult> =>\n dispatch(type, data, isSendResult)\n\n const base = {\n send: <T extends AllowedEventType<P>>(type: T, ...args: DataArgs<T>): Promise<SendResult> =>\n sendEvent(type, args[0] ?? {}),\n ping: (): Promise<PingResult> => dispatch(\"webhook.ping\", {}, isPingResult),\n }\n\n /** `client.counter` \u2192 namespace whose method calls become `sendEvent(\"counter.<method>\")`. */\n const capabilityNamespace = (capability: string) =>\n new Proxy(\n {},\n {\n get: (_target, method) => {\n if (typeof method !== \"string\" || PROBED_PROPS.has(method)) return undefined\n return (data?: unknown) =>\n sendEvent(`${capability}.${wireMethodName(method)}`, data ?? {})\n },\n },\n )\n\n // The fluent surface is type-driven (CapabilityNamespaces); the proxy only assembles wire\n // names, so new capabilities work via a types-package bump with zero SDK changes.\n // eslint-disable-next-line @typescript-eslint/consistent-type-assertions\n return new Proxy(base, {\n get: (target, prop, receiver) => {\n // Real members (send/ping) win over capability namespaces, as do symbol lookups.\n if (prop in target || typeof prop !== \"string\") return Reflect.get(target, prop, receiver)\n if (PROBED_PROPS.has(prop)) return undefined\n return capabilityNamespace(prop)\n },\n }) as WebhookObjectClient<P>\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
package/dist/src/deliver.js
CHANGED
|
@@ -1,150 +1,154 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
Object.defineProperty
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var deliver_exports = {};
|
|
20
|
+
__export(deliver_exports, {
|
|
21
|
+
DEFAULT_MAX_ATTEMPTS: () => DEFAULT_MAX_ATTEMPTS,
|
|
22
|
+
MAX_BODY_BYTES: () => MAX_BODY_BYTES,
|
|
23
|
+
WIRE_ERROR_CODES: () => WIRE_ERROR_CODES,
|
|
24
|
+
deliver: () => deliver
|
|
25
|
+
});
|
|
26
|
+
module.exports = __toCommonJS(deliver_exports);
|
|
27
|
+
var import_errors = require("./errors");
|
|
28
|
+
const MAX_BODY_BYTES = 4 * 1024;
|
|
29
|
+
const DEFAULT_MAX_ATTEMPTS = 3;
|
|
8
30
|
const BACKOFF_BASE_MS = 500;
|
|
9
|
-
const BACKOFF_CAP_MS =
|
|
10
|
-
/** Small buffer past `RateLimit-Reset` so the retry lands after the window actually rolls. */
|
|
31
|
+
const BACKOFF_CAP_MS = 3e4;
|
|
11
32
|
const RATE_LIMIT_GRACE_MS = 250;
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
"capability_not_declared",
|
|
24
|
-
"method_not_found",
|
|
25
|
-
"token_revoked",
|
|
26
|
-
"unsupported_media_type",
|
|
27
|
-
"internal_error",
|
|
28
|
-
"service_unavailable",
|
|
33
|
+
const WIRE_ERROR_CODES = [
|
|
34
|
+
"invalid_request",
|
|
35
|
+
"invalid_args",
|
|
36
|
+
"not_found",
|
|
37
|
+
"capability_not_found",
|
|
38
|
+
"capability_not_declared",
|
|
39
|
+
"method_not_found",
|
|
40
|
+
"token_revoked",
|
|
41
|
+
"unsupported_media_type",
|
|
42
|
+
"internal_error",
|
|
43
|
+
"service_unavailable"
|
|
29
44
|
];
|
|
30
|
-
const SERVER_ERROR_CODES = new Set(
|
|
45
|
+
const SERVER_ERROR_CODES = new Set(WIRE_ERROR_CODES);
|
|
31
46
|
const ERROR_HINTS = {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
47
|
+
not_found: "uniform pre-auth failure: check the URL, the secret, clock skew (\xB15 min), and that the body was not re-serialized after signing",
|
|
48
|
+
capability_not_declared: "this object's preset doesn't accept that event type, run ping() to see what it accepts",
|
|
49
|
+
token_revoked: "the API key was regenerated, copy the new one from the object's \u22EE menu",
|
|
50
|
+
rate_limited: "rate limited (per space or per IP) and retries were exhausted"
|
|
36
51
|
};
|
|
37
|
-
const abortError = (signal) => new
|
|
38
|
-
/** Sleep `ms`, but reject early (and clean up its listener) if `signal` aborts mid-wait. */
|
|
52
|
+
const abortError = (signal) => new import_errors.WebhookObjectError("aborted", "webhook object delivery aborted", { cause: signal.reason });
|
|
39
53
|
const sleep = (ms, signal) => new Promise((resolve, reject) => {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
54
|
+
if (signal?.aborted) {
|
|
55
|
+
reject(abortError(signal));
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
if (!signal) {
|
|
59
|
+
setTimeout(resolve, ms);
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
const onAbort = () => {
|
|
63
|
+
clearTimeout(timer);
|
|
64
|
+
reject(abortError(signal));
|
|
65
|
+
};
|
|
66
|
+
const timer = setTimeout(() => {
|
|
67
|
+
signal.removeEventListener("abort", onAbort);
|
|
68
|
+
resolve();
|
|
69
|
+
}, ms);
|
|
70
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
57
71
|
});
|
|
58
72
|
const backoffDelayMs = (attempt) => Math.min(BACKOFF_BASE_MS * 2 ** attempt, BACKOFF_CAP_MS) * (0.5 + Math.random() * 0.5);
|
|
59
73
|
const retryDelayMs = (response, attempt) => {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
if (Number.isFinite(retryAfterSeconds) && retryAfterSeconds > 0)
|
|
70
|
-
return retryAfterSeconds * 1000;
|
|
71
|
-
return backoffDelayMs(attempt);
|
|
74
|
+
if (response.status === 429) {
|
|
75
|
+
const resetHeader = response.headers.get("RateLimit-Reset");
|
|
76
|
+
const resetSeconds = resetHeader === null ? NaN : Number(resetHeader);
|
|
77
|
+
if (Number.isFinite(resetSeconds) && resetSeconds >= 0)
|
|
78
|
+
return resetSeconds * 1e3 + RATE_LIMIT_GRACE_MS;
|
|
79
|
+
}
|
|
80
|
+
const retryAfterSeconds = Number(response.headers.get("Retry-After"));
|
|
81
|
+
if (Number.isFinite(retryAfterSeconds) && retryAfterSeconds > 0) return retryAfterSeconds * 1e3;
|
|
82
|
+
return backoffDelayMs(attempt);
|
|
72
83
|
};
|
|
73
|
-
/** Retry only what the receiver documents as transient: 429 and 5xx. 4xx means "fix the request". */
|
|
74
84
|
const isRetryableStatus = (status) => status === 429 || status >= 500;
|
|
75
85
|
const parseBody = async (response) => {
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
return undefined;
|
|
82
|
-
}
|
|
86
|
+
try {
|
|
87
|
+
return await response.json();
|
|
88
|
+
} catch {
|
|
89
|
+
return void 0;
|
|
90
|
+
}
|
|
83
91
|
};
|
|
84
92
|
const isWireErrorCode = (code) => SERVER_ERROR_CODES.has(code);
|
|
85
93
|
const errorFromResponse = (status, body) => {
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
94
|
+
const code = (() => {
|
|
95
|
+
if (status === 429) return "rate_limited";
|
|
96
|
+
const bodyCode = body?.error;
|
|
97
|
+
if (typeof bodyCode === "string" && isWireErrorCode(bodyCode)) return bodyCode;
|
|
98
|
+
return "unexpected_response";
|
|
99
|
+
})();
|
|
100
|
+
const hint = ERROR_HINTS[code];
|
|
101
|
+
return new import_errors.WebhookObjectError(
|
|
102
|
+
code,
|
|
103
|
+
`webhook object delivery failed (${status}): ${code}${hint ? ` (${hint})` : ""}`,
|
|
104
|
+
{ status, body }
|
|
105
|
+
);
|
|
96
106
|
};
|
|
97
|
-
/**
|
|
98
|
-
* POST the signed event, retrying transient failures (429 honoring `RateLimit-Reset`,
|
|
99
|
-
* 5xx honoring `Retry-After`, network errors) with exponential backoff + jitter.
|
|
100
|
-
* Resolves with the parsed 200 body; throws `WebhookObjectError` otherwise. An aborted
|
|
101
|
-
* `signal` cancels the in-flight fetch and any pending backoff, throwing `aborted` at once.
|
|
102
|
-
*/
|
|
103
107
|
const deliver = async (args) => {
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
return response;
|
|
109
|
-
}
|
|
108
|
+
for (let attempt = 0; ; attempt++) {
|
|
109
|
+
const response = await attemptOnce(args, attempt);
|
|
110
|
+
if (response !== void 0) return response;
|
|
111
|
+
}
|
|
110
112
|
};
|
|
111
|
-
exports.deliver = deliver;
|
|
112
|
-
/** One attempt: returns the parsed success body, or undefined after sleeping off a transient failure. */
|
|
113
113
|
const attemptOnce = async (args, attempt) => {
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
throw error;
|
|
147
|
-
await sleep(retryDelayMs(response, attempt), args.signal);
|
|
148
|
-
return undefined;
|
|
114
|
+
const isLastAttempt = attempt >= args.maxAttempts - 1;
|
|
115
|
+
const timestampSeconds = Math.floor(Date.now() / 1e3);
|
|
116
|
+
if (args.signal?.aborted) throw abortError(args.signal);
|
|
117
|
+
let response;
|
|
118
|
+
try {
|
|
119
|
+
response = await args.fetchImpl(args.url, {
|
|
120
|
+
method: "POST",
|
|
121
|
+
headers: {
|
|
122
|
+
"content-type": "application/json",
|
|
123
|
+
"webhook-id": args.webhookId,
|
|
124
|
+
"webhook-timestamp": String(timestampSeconds),
|
|
125
|
+
"webhook-signature": args.sign(timestampSeconds)
|
|
126
|
+
},
|
|
127
|
+
body: args.body,
|
|
128
|
+
signal: args.signal
|
|
129
|
+
});
|
|
130
|
+
} catch (cause) {
|
|
131
|
+
if (args.signal?.aborted) throw abortError(args.signal);
|
|
132
|
+
const error2 = new import_errors.WebhookObjectError(
|
|
133
|
+
"network_error",
|
|
134
|
+
"webhook object delivery failed: network error",
|
|
135
|
+
{ cause }
|
|
136
|
+
);
|
|
137
|
+
if (isLastAttempt) throw error2;
|
|
138
|
+
await sleep(backoffDelayMs(attempt), args.signal);
|
|
139
|
+
return void 0;
|
|
140
|
+
}
|
|
141
|
+
if (response.ok) return await parseBody(response) ?? {};
|
|
142
|
+
const error = errorFromResponse(response.status, await parseBody(response));
|
|
143
|
+
if (!isRetryableStatus(response.status) || isLastAttempt) throw error;
|
|
144
|
+
await sleep(retryDelayMs(response, attempt), args.signal);
|
|
145
|
+
return void 0;
|
|
149
146
|
};
|
|
150
|
-
|
|
147
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
148
|
+
0 && (module.exports = {
|
|
149
|
+
DEFAULT_MAX_ATTEMPTS,
|
|
150
|
+
MAX_BODY_BYTES,
|
|
151
|
+
WIRE_ERROR_CODES,
|
|
152
|
+
deliver
|
|
153
|
+
});
|
|
154
|
+
//# sourceMappingURL=deliver.js.map
|
package/dist/src/deliver.js.map
CHANGED
|
@@ -1 +1,7 @@
|
|
|
1
|
-
{
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/deliver.ts"],
|
|
4
|
+
"sourcesContent": ["import type { WebhookWireErrorCode } from \"@gathertown/webhook-object-types\"\nimport { WebhookObjectError, WebhookObjectErrorCode } from \"./errors\"\n\n/** The receiver caps request bodies at 4 KB; oversized bodies get the uniform 404. */\nexport const MAX_BODY_BYTES = 4 * 1024\n\nexport const DEFAULT_MAX_ATTEMPTS = 3\n\nconst BACKOFF_BASE_MS = 500\nconst BACKOFF_CAP_MS = 30_000\n/** Small buffer past `RateLimit-Reset` so the retry lands after the window actually rolls. */\nconst RATE_LIMIT_GRACE_MS = 250\n\n/**\n * Runtime mirror of the generated `WebhookWireErrorCode` union (the types package is\n * deliberately zero-runtime, so the value list lives here). `satisfies` rejects unknown\n * codes; a compile-time exhaustiveness test catches missing ones. Either way, receiver\n * drift fails the build instead of shipping.\n */\nexport const WIRE_ERROR_CODES = [\n \"invalid_request\",\n \"invalid_args\",\n \"not_found\",\n \"capability_not_found\",\n \"capability_not_declared\",\n \"method_not_found\",\n \"token_revoked\",\n \"unsupported_media_type\",\n \"internal_error\",\n \"service_unavailable\",\n] as const satisfies readonly WebhookWireErrorCode[]\n\nconst SERVER_ERROR_CODES: ReadonlySet<string> = new Set(WIRE_ERROR_CODES)\n\nconst ERROR_HINTS: Partial<Record<WebhookObjectErrorCode, string>> = {\n not_found:\n \"uniform pre-auth failure: check the URL, the secret, clock skew (\u00B15 min), and that the body was not re-serialized after signing\",\n capability_not_declared:\n \"this object's preset doesn't accept that event type, run ping() to see what it accepts\",\n token_revoked: \"the API key was regenerated, copy the new one from the object's \u22EE menu\",\n rate_limited: \"rate limited (per space or per IP) and retries were exhausted\",\n}\n\nconst abortError = (signal: AbortSignal): WebhookObjectError =>\n new WebhookObjectError(\"aborted\", \"webhook object delivery aborted\", { cause: signal.reason })\n\n/** Sleep `ms`, but reject early (and clean up its listener) if `signal` aborts mid-wait. */\nconst sleep = (ms: number, signal?: AbortSignal): Promise<void> =>\n new Promise((resolve, reject) => {\n if (signal?.aborted) {\n reject(abortError(signal))\n return\n }\n if (!signal) {\n setTimeout(resolve, ms)\n return\n }\n const onAbort = (): void => {\n clearTimeout(timer)\n reject(abortError(signal))\n }\n const timer = setTimeout(() => {\n signal.removeEventListener(\"abort\", onAbort)\n resolve()\n }, ms)\n signal.addEventListener(\"abort\", onAbort, { once: true })\n })\n\nconst backoffDelayMs = (attempt: number): number =>\n Math.min(BACKOFF_BASE_MS * 2 ** attempt, BACKOFF_CAP_MS) * (0.5 + Math.random() * 0.5)\n\nconst retryDelayMs = (response: Response, attempt: number): number => {\n if (response.status === 429) {\n // The receiver uses `express-rate-limit` with `standardHeaders: true` (IETF draft-6), which\n // sets `RateLimit-Reset` to the number of SECONDS remaining until the window resets.\n const resetHeader = response.headers.get(\"RateLimit-Reset\")\n const resetSeconds = resetHeader === null ? NaN : Number(resetHeader)\n if (Number.isFinite(resetSeconds) && resetSeconds >= 0)\n return resetSeconds * 1000 + RATE_LIMIT_GRACE_MS\n }\n const retryAfterSeconds = Number(response.headers.get(\"Retry-After\"))\n if (Number.isFinite(retryAfterSeconds) && retryAfterSeconds > 0) return retryAfterSeconds * 1000\n return backoffDelayMs(attempt)\n}\n\n/** Retry only what the receiver documents as transient: 429 and 5xx. 4xx means \"fix the request\". */\nconst isRetryableStatus = (status: number): boolean => status === 429 || status >= 500\n\nconst parseBody = async <T = Record<string, unknown>>(\n response: Response,\n): Promise<T | undefined> => {\n try {\n // eslint-disable-next-line @typescript-eslint/consistent-type-assertions\n return (await response.json()) as T\n } catch {\n return undefined\n }\n}\n\nconst isWireErrorCode = (code: string): code is WebhookWireErrorCode => SERVER_ERROR_CODES.has(code)\n\nconst errorFromResponse = (status: number, body: Record<string, unknown> | undefined) => {\n const code = ((): WebhookObjectErrorCode => {\n if (status === 429) return \"rate_limited\"\n const bodyCode = body?.error\n if (typeof bodyCode === \"string\" && isWireErrorCode(bodyCode)) return bodyCode\n return \"unexpected_response\"\n })()\n const hint = ERROR_HINTS[code]\n return new WebhookObjectError(\n code,\n `webhook object delivery failed (${status}): ${code}${hint ? ` (${hint})` : \"\"}`,\n { status, body },\n )\n}\n\nexport type DeliverArgs = {\n url: string\n /** The exact serialized body, signed per attempt and sent unchanged. */\n body: string\n /** Stable across retries: the server dedups the last 10 ids per object, making retries idempotent. */\n webhookId: string\n /** Signs `webhookId`/timestamp/body; called per attempt so retries carry a fresh timestamp. */\n sign: (timestampSeconds: number) => string\n fetchImpl: typeof fetch\n maxAttempts: number\n /** Aborts the in-flight fetch and any pending backoff sleep; surfaces as an `aborted` error. */\n signal?: AbortSignal\n}\n\n/**\n * POST the signed event, retrying transient failures (429 honoring `RateLimit-Reset`,\n * 5xx honoring `Retry-After`, network errors) with exponential backoff + jitter.\n * Resolves with the parsed 200 body; throws `WebhookObjectError` otherwise. An aborted\n * `signal` cancels the in-flight fetch and any pending backoff, throwing `aborted` at once.\n */\nexport const deliver = async (args: DeliverArgs): Promise<Record<string, unknown>> => {\n // Terminates because `attemptOnce` always throws on the last attempt.\n for (let attempt = 0; ; attempt++) {\n const response = await attemptOnce(args, attempt)\n if (response !== undefined) return response\n }\n}\n\n/** One attempt: returns the parsed success body, or undefined after sleeping off a transient failure. */\nconst attemptOnce = async (\n args: DeliverArgs,\n attempt: number,\n): Promise<Record<string, unknown> | undefined> => {\n const isLastAttempt = attempt >= args.maxAttempts - 1\n const timestampSeconds = Math.floor(Date.now() / 1000)\n\n if (args.signal?.aborted) throw abortError(args.signal)\n\n let response: Response\n try {\n response = await args.fetchImpl(args.url, {\n method: \"POST\",\n headers: {\n \"content-type\": \"application/json\",\n \"webhook-id\": args.webhookId,\n \"webhook-timestamp\": String(timestampSeconds),\n \"webhook-signature\": args.sign(timestampSeconds),\n },\n body: args.body,\n signal: args.signal,\n })\n } catch (cause) {\n // An abort surfaces here as a fetch rejection; report it as `aborted` and never retry it.\n if (args.signal?.aborted) throw abortError(args.signal)\n const error = new WebhookObjectError(\n \"network_error\",\n \"webhook object delivery failed: network error\",\n { cause },\n )\n if (isLastAttempt) throw error\n await sleep(backoffDelayMs(attempt), args.signal)\n return undefined\n }\n\n if (response.ok) return (await parseBody(response)) ?? {}\n\n const error = errorFromResponse(response.status, await parseBody(response))\n if (!isRetryableStatus(response.status) || isLastAttempt) throw error\n await sleep(retryDelayMs(response, attempt), args.signal)\n return undefined\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["error"]
|
|
7
|
+
}
|
package/dist/src/errors.js
CHANGED
|
@@ -1,27 +1,44 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
Object.defineProperty
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var errors_exports = {};
|
|
20
|
+
__export(errors_exports, {
|
|
21
|
+
WebhookObjectError: () => WebhookObjectError
|
|
22
|
+
});
|
|
23
|
+
module.exports = __toCommonJS(errors_exports);
|
|
9
24
|
class WebhookObjectError extends Error {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
body;
|
|
25
|
+
constructor(code, message, options) {
|
|
26
|
+
super(message, options?.cause === void 0 ? void 0 : { cause: options.cause });
|
|
27
|
+
this.code = code;
|
|
28
|
+
this.status = options?.status;
|
|
29
|
+
this.body = options?.body;
|
|
30
|
+
}
|
|
31
|
+
name = "WebhookObjectError";
|
|
32
|
+
status;
|
|
33
|
+
/**
|
|
34
|
+
* The parsed response body for errors that came from an HTTP response (e.g. `{ error: "…" }`),
|
|
35
|
+
* or `undefined` for client-side errors and unparseable bodies. Lets integrators read any
|
|
36
|
+
* extra fields the receiver returns beyond `code`/`status`.
|
|
37
|
+
*/
|
|
38
|
+
body;
|
|
25
39
|
}
|
|
26
|
-
|
|
27
|
-
|
|
40
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
41
|
+
0 && (module.exports = {
|
|
42
|
+
WebhookObjectError
|
|
43
|
+
});
|
|
44
|
+
//# sourceMappingURL=errors.js.map
|
package/dist/src/errors.js.map
CHANGED
|
@@ -1 +1,7 @@
|
|
|
1
|
-
{
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/errors.ts"],
|
|
4
|
+
"sourcesContent": ["import type { WebhookWireErrorCode } from \"@gathertown/webhook-object-types\"\n\n/**\n * Error codes surfaced by `WebhookObjectError.code`.\n *\n * Wire codes come verbatim from the generated `WebhookWireErrorCode` (the receiver's error\n * bodies); the rest are client-side conditions the SDK detects before/around the HTTP exchange.\n */\nexport type WebhookObjectErrorCode =\n | WebhookWireErrorCode\n // 429: rate limited and retries were exhausted (either per space, or per IP);\n // the receiver sends no body code for these, so it's SDK-assigned\n | \"rate_limited\"\n // Client-side: serialized body exceeds the receiver's 4 KB cap (would be a uniform 404)\n | \"payload_too_large\"\n // Client-side: the secret is missing or not a `whsec_\u2026` key\n | \"invalid_secret\"\n // Client-side: the URL is unparseable or not https (http is allowed only for localhost)\n | \"invalid_url\"\n // Client-side: fetch itself failed (DNS, connection) and retries were exhausted\n | \"network_error\"\n // Client-side: the caller's AbortSignal fired during the request or a backoff sleep\n | \"aborted\"\n // Client-side: the server responded with a status/body this SDK doesn't recognize\n | \"unexpected_response\"\n\n/**\n * The single error type the SDK throws. `code` classifies the failure (see\n * {@link WebhookObjectErrorCode}) and `status` carries the HTTP status when the error\n * originated from a response.\n */\nexport class WebhookObjectError extends Error {\n override readonly name = \"WebhookObjectError\"\n\n constructor(\n readonly code: WebhookObjectErrorCode,\n message: string,\n options?: {\n /** HTTP status of the response, when the error came from one. */\n status?: number\n /** Parsed response body, when the error came from one, for reading server-provided fields. */\n body?: unknown\n cause?: unknown\n },\n ) {\n super(message, options?.cause === undefined ? undefined : { cause: options.cause })\n this.status = options?.status\n this.body = options?.body\n }\n\n readonly status: number | undefined\n\n /**\n * The parsed response body for errors that came from an HTTP response (e.g. `{ error: \"\u2026\" }`),\n * or `undefined` for client-side errors and unparseable bodies. Lets integrators read any\n * extra fields the receiver returns beyond `code`/`status`.\n */\n readonly body: unknown\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AA+BO,MAAM,2BAA2B,MAAM;AAAA,EAG5C,YACW,MACT,SACA,SAOA;AACA,UAAM,SAAS,SAAS,UAAU,SAAY,SAAY,EAAE,OAAO,QAAQ,MAAM,CAAC;AAVzE;AAWT,SAAK,SAAS,SAAS;AACvB,SAAK,OAAO,SAAS;AAAA,EACvB;AAAA,EAhBkB,OAAO;AAAA,EAkBhB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA;AACX;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
package/dist/src/index.js
CHANGED
|
@@ -1,13 +1,40 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
Object.defineProperty
|
|
3
|
-
|
|
4
|
-
var
|
|
5
|
-
|
|
6
|
-
var
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
var
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var src_exports = {};
|
|
20
|
+
__export(src_exports, {
|
|
21
|
+
WebhookObjectError: () => import_errors.WebhookObjectError,
|
|
22
|
+
createWebhookObjectCatalog: () => import_catalog.createWebhookObjectCatalog,
|
|
23
|
+
createWebhookObjectClient: () => import_client.createWebhookObjectClient,
|
|
24
|
+
secretFromEnv: () => import_secret.secretFromEnv,
|
|
25
|
+
unsafeSecretLiteral: () => import_secret.unsafeSecretLiteral
|
|
26
|
+
});
|
|
27
|
+
module.exports = __toCommonJS(src_exports);
|
|
28
|
+
var import_catalog = require("./catalog");
|
|
29
|
+
var import_client = require("./client");
|
|
30
|
+
var import_errors = require("./errors");
|
|
31
|
+
var import_secret = require("./secret");
|
|
32
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
33
|
+
0 && (module.exports = {
|
|
34
|
+
WebhookObjectError,
|
|
35
|
+
createWebhookObjectCatalog,
|
|
36
|
+
createWebhookObjectClient,
|
|
37
|
+
secretFromEnv,
|
|
38
|
+
unsafeSecretLiteral
|
|
39
|
+
});
|
|
40
|
+
//# sourceMappingURL=index.js.map
|
package/dist/src/index.js.map
CHANGED
|
@@ -1 +1,7 @@
|
|
|
1
|
-
{
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/index.ts"],
|
|
4
|
+
"sourcesContent": ["export {\n createWebhookObjectCatalog,\n type WebhookObjectCatalog,\n type WebhookObjectCatalogEntry,\n type WebhookObjectCatalogOptions,\n} from \"./catalog\"\nexport {\n type AllowedEventType,\n type CapabilityNamespaces,\n createWebhookObjectClient,\n type PingResult,\n type SendResult,\n type WebhookObjectClient,\n type WebhookObjectClientConfig,\n} from \"./client\"\nexport { WebhookObjectError, type WebhookObjectErrorCode } from \"./errors\"\nexport { secretFromEnv, unsafeSecretLiteral, type WebhookObjectSecret } from \"./secret\"\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,qBAKO;AACP,oBAQO;AACP,oBAAgE;AAChE,oBAA6E;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
package/dist/src/secret.js
CHANGED
|
@@ -1,55 +1,70 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
Object.defineProperty
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var secret_exports = {};
|
|
20
|
+
__export(secret_exports, {
|
|
21
|
+
revealSecret: () => revealSecret,
|
|
22
|
+
secretFromEnv: () => secretFromEnv,
|
|
23
|
+
unsafeSecretLiteral: () => unsafeSecretLiteral
|
|
24
|
+
});
|
|
25
|
+
module.exports = __toCommonJS(secret_exports);
|
|
26
|
+
var import_errors = require("./errors");
|
|
6
27
|
const SECRET_PATTERN = /^whsec_.{20,}/;
|
|
7
|
-
|
|
8
|
-
const secretValues = new WeakMap();
|
|
28
|
+
const secretValues = /* @__PURE__ */ new WeakMap();
|
|
9
29
|
const REDACTED = "[redacted webhook object secret]";
|
|
10
30
|
const brandSecret = (value, source) => {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
31
|
+
if (!SECRET_PATTERN.test(value))
|
|
32
|
+
throw new import_errors.WebhookObjectError(
|
|
33
|
+
"invalid_secret",
|
|
34
|
+
`webhook object secret from ${source} is missing or malformed, expected a whsec_\u2026 key`
|
|
35
|
+
);
|
|
36
|
+
const handle = {
|
|
37
|
+
toString: () => REDACTED,
|
|
38
|
+
toJSON: () => REDACTED,
|
|
39
|
+
[Symbol.for("nodejs.util.inspect.custom")]: () => REDACTED
|
|
40
|
+
};
|
|
41
|
+
const secret = handle;
|
|
42
|
+
secretValues.set(secret, value);
|
|
43
|
+
return secret;
|
|
23
44
|
};
|
|
24
|
-
/**
|
|
25
|
-
* Read a `whsec_…` secret from the named environment variable. The recommended way to
|
|
26
|
-
* provide a secret: the value never appears in your source, and a missing or malformed
|
|
27
|
-
* variable fails fast with the variable's name (never its value).
|
|
28
|
-
*/
|
|
29
45
|
const secretFromEnv = (name) => brandSecret(process.env[name] ?? "", `env var ${name}`);
|
|
30
|
-
exports.secretFromEnv = secretFromEnv;
|
|
31
|
-
/**
|
|
32
|
-
* Wrap a secret you already hold as a string (secret managers, non-Node runtimes without
|
|
33
|
-
* `process.env`). Named `unsafe` so hardcoded `whsec_…` literals are easy to grep for in
|
|
34
|
-
* review; never commit a literal secret to source control.
|
|
35
|
-
*/
|
|
36
46
|
const unsafeSecretLiteral = (value) => brandSecret(value, "a string literal");
|
|
37
|
-
exports.unsafeSecretLiteral = unsafeSecretLiteral;
|
|
38
|
-
/**
|
|
39
|
-
* Internal: recover the raw secret for signing. Not re-exported from the package entry
|
|
40
|
-
* point. Bare strings are validated in place; anything else must be a handle minted by
|
|
41
|
-
* this module (an object that isn't one fails the WeakMap lookup and throws).
|
|
42
|
-
*/
|
|
43
47
|
const revealSecret = (secret) => {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
48
|
+
if (typeof secret === "string") {
|
|
49
|
+
if (!SECRET_PATTERN.test(secret))
|
|
50
|
+
throw new import_errors.WebhookObjectError(
|
|
51
|
+
"invalid_secret",
|
|
52
|
+
"webhook object secret is malformed, expected a whsec_\u2026 key"
|
|
53
|
+
);
|
|
54
|
+
return secret;
|
|
55
|
+
}
|
|
56
|
+
const value = secretValues.get(secret);
|
|
57
|
+
if (value === void 0)
|
|
58
|
+
throw new import_errors.WebhookObjectError(
|
|
59
|
+
"invalid_secret",
|
|
60
|
+
"webhook object secret must be a whsec_\u2026 string or created with secretFromEnv() / unsafeSecretLiteral()"
|
|
61
|
+
);
|
|
62
|
+
return value;
|
|
53
63
|
};
|
|
54
|
-
|
|
55
|
-
|
|
64
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
65
|
+
0 && (module.exports = {
|
|
66
|
+
revealSecret,
|
|
67
|
+
secretFromEnv,
|
|
68
|
+
unsafeSecretLiteral
|
|
69
|
+
});
|
|
70
|
+
//# sourceMappingURL=secret.js.map
|
package/dist/src/secret.js.map
CHANGED
|
@@ -1 +1,7 @@
|
|
|
1
|
-
{
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/secret.ts"],
|
|
4
|
+
"sourcesContent": ["import { WebhookObjectError } from \"./errors\"\n\n/** Fail fast on malformed secrets: `whsec_` + at least 20 chars of key material. */\nconst SECRET_PATTERN = /^whsec_.{20,}/\n\ndeclare const webhookObjectSecretBrand: unique symbol\n\n/**\n * An opaque handle to a `whsec_\u2026` signing secret, obtained via {@link secretFromEnv} or\n * {@link unsafeSecretLiteral}. Unlike a bare string (which the client also accepts), the\n * handle redacts itself when logged or serialized, so it can't leak through console output,\n * error reporters, or `JSON.stringify` of a config object.\n */\nexport type WebhookObjectSecret = { readonly [webhookObjectSecretBrand]: true }\n\n/** Secret values live here, keyed by handle identity, so no property on the handle exposes them. */\nconst secretValues = new WeakMap<WebhookObjectSecret, string>()\n\nconst REDACTED = \"[redacted webhook object secret]\"\n\nconst brandSecret = (value: string, source: string): WebhookObjectSecret => {\n if (!SECRET_PATTERN.test(value))\n throw new WebhookObjectError(\n \"invalid_secret\",\n `webhook object secret from ${source} is missing or malformed, expected a whsec_\u2026 key`,\n )\n const handle = {\n toString: () => REDACTED,\n toJSON: () => REDACTED,\n [Symbol.for(\"nodejs.util.inspect.custom\")]: () => REDACTED,\n }\n // The brand symbol exists only at the type level; the WeakMap entry is the runtime brand.\n // eslint-disable-next-line @typescript-eslint/consistent-type-assertions\n const secret = handle as unknown as WebhookObjectSecret\n secretValues.set(secret, value)\n return secret\n}\n\n/**\n * Read a `whsec_\u2026` secret from the named environment variable. The recommended way to\n * provide a secret: the value never appears in your source, and a missing or malformed\n * variable fails fast with the variable's name (never its value).\n */\nexport const secretFromEnv = (name: string): WebhookObjectSecret =>\n brandSecret(process.env[name] ?? \"\", `env var ${name}`)\n\n/**\n * Wrap a secret you already hold as a string (secret managers, non-Node runtimes without\n * `process.env`). Named `unsafe` so hardcoded `whsec_\u2026` literals are easy to grep for in\n * review; never commit a literal secret to source control.\n */\nexport const unsafeSecretLiteral = (value: string): WebhookObjectSecret =>\n brandSecret(value, \"a string literal\")\n\n/**\n * Internal: recover the raw secret for signing. Not re-exported from the package entry\n * point. Bare strings are validated in place; anything else must be a handle minted by\n * this module (an object that isn't one fails the WeakMap lookup and throws).\n */\nexport const revealSecret = (secret: WebhookObjectSecret | string): string => {\n if (typeof secret === \"string\") {\n if (!SECRET_PATTERN.test(secret))\n throw new WebhookObjectError(\n \"invalid_secret\",\n \"webhook object secret is malformed, expected a whsec_\u2026 key\",\n )\n return secret\n }\n const value = secretValues.get(secret)\n if (value === undefined)\n throw new WebhookObjectError(\n \"invalid_secret\",\n \"webhook object secret must be a whsec_\u2026 string or created with secretFromEnv() / unsafeSecretLiteral()\",\n )\n return value\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,oBAAmC;AAGnC,MAAM,iBAAiB;AAavB,MAAM,eAAe,oBAAI,QAAqC;AAE9D,MAAM,WAAW;AAEjB,MAAM,cAAc,CAAC,OAAe,WAAwC;AAC1E,MAAI,CAAC,eAAe,KAAK,KAAK;AAC5B,UAAM,IAAI;AAAA,MACR;AAAA,MACA,8BAA8B,MAAM;AAAA,IACtC;AACF,QAAM,SAAS;AAAA,IACb,UAAU,MAAM;AAAA,IAChB,QAAQ,MAAM;AAAA,IACd,CAAC,OAAO,IAAI,4BAA4B,CAAC,GAAG,MAAM;AAAA,EACpD;AAGA,QAAM,SAAS;AACf,eAAa,IAAI,QAAQ,KAAK;AAC9B,SAAO;AACT;AAOO,MAAM,gBAAgB,CAAC,SAC5B,YAAY,QAAQ,IAAI,IAAI,KAAK,IAAI,WAAW,IAAI,EAAE;AAOjD,MAAM,sBAAsB,CAAC,UAClC,YAAY,OAAO,kBAAkB;AAOhC,MAAM,eAAe,CAAC,WAAiD;AAC5E,MAAI,OAAO,WAAW,UAAU;AAC9B,QAAI,CAAC,eAAe,KAAK,MAAM;AAC7B,YAAM,IAAI;AAAA,QACR;AAAA,QACA;AAAA,MACF;AACF,WAAO;AAAA,EACT;AACA,QAAM,QAAQ,aAAa,IAAI,MAAM;AACrC,MAAI,UAAU;AACZ,UAAM,IAAI;AAAA,MACR;AAAA,MACA;AAAA,IACF;AACF,SAAO;AACT;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gathertown/webhook-object-sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Typed client for emitting events to Gather webhook objects (Smart Objects): Standard Webhooks signing, retries, and a fully-inferred send API.",
|
|
5
5
|
"main": "dist/src/index.js",
|
|
6
6
|
"types": "dist/src/index.d.ts",
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
"files": [
|
|
9
9
|
"dist/src/**",
|
|
10
10
|
"!dist/src/__tests__/**",
|
|
11
|
+
"!dist/src/**/*.d.ts.map",
|
|
11
12
|
"README.md",
|
|
12
13
|
"LICENSE-MIT",
|
|
13
14
|
"LICENSE-APACHE"
|
|
@@ -20,12 +21,12 @@
|
|
|
20
21
|
"access": "public"
|
|
21
22
|
},
|
|
22
23
|
"engines": {
|
|
23
|
-
"node": ">=
|
|
24
|
+
"node": ">=24"
|
|
24
25
|
},
|
|
25
26
|
"author": "Gather Presence, Inc.",
|
|
26
27
|
"license": "MIT OR Apache-2.0",
|
|
27
28
|
"dependencies": {
|
|
28
|
-
"@gathertown/webhook-object-types": "^0.
|
|
29
|
+
"@gathertown/webhook-object-types": "^0.2.0",
|
|
29
30
|
"standardwebhooks": "~1.0.0"
|
|
30
31
|
},
|
|
31
32
|
"devDependencies": {
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"catalog.d.ts","sourceRoot":"","sources":["../../src/catalog.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAA;AAC3E,OAAO,EAA6B,mBAAmB,EAAE,yBAAyB,EAAE,MAAM,UAAU,CAAA;AAEpG,6FAA6F;AAC7F,KAAK,kBAAkB,GAAG,aAAa,GAAG,OAAO,GAAG,cAAc,CAAA;AAElE,0FAA0F;AAC1F,MAAM,MAAM,yBAAyB,GAAG,IAAI,CAAC,yBAAyB,EAAE,kBAAkB,CAAC,CAAA;AAE3F,qDAAqD;AACrD,MAAM,MAAM,2BAA2B,GAAG,IAAI,CAAC,yBAAyB,EAAE,kBAAkB,CAAC,CAAA;AAE7F,uFAAuF;AACvF,KAAK,QAAQ,CAAC,KAAK,SAAS,yBAAyB,IAAI,KAAK,SAAS;IACrE,MAAM,EAAE,MAAM,MAAM,SAAS,mBAAmB,CAAA;CACjD,GACG,MAAM,GACN,SAAS,CAAA;AAEb;;;GAGG;AACH,MAAM,MAAM,oBAAoB,CAAC,OAAO,SAAS,MAAM,CAAC,MAAM,EAAE,yBAAyB,CAAC,IAAI;KAC3F,IAAI,IAAI,MAAM,OAAO,GAAG,mBAAmB,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;CACtE,CAAA;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,0BAA0B,GACrC,KAAK,CAAC,OAAO,SAAS,MAAM,CAAC,MAAM,EAAE,yBAAyB,CAAC,EAE/D,SAAS,OAAO,EAChB,UAAS,2BAAgC,KACxC,oBAAoB,CAAC,OAAO,CASgB,CAAA"}
|
package/dist/src/client.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/client.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,OAAO,EACP,kBAAkB,EAClB,iBAAiB,EACjB,gBAAgB,EAChB,mBAAmB,EACpB,MAAM,kCAAkC,CAAA;AAGzC,OAAO,EAAgB,mBAAmB,EAAE,MAAM,UAAU,CAAA;AAE5D,MAAM,MAAM,yBAAyB,GAAG;IACtC,iFAAiF;IACjF,GAAG,EAAE,MAAM,CAAA;IACX;;;;OAIG;IACH,MAAM,EAAE,mBAAmB,GAAG,MAAM,CAAA;IACpC;;;OAGG;IACH,MAAM,CAAC,EAAE,mBAAmB,CAAA;IAC5B,2FAA2F;IAC3F,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,6FAA6F;IAC7F,KAAK,CAAC,EAAE,OAAO,KAAK,CAAA;IACpB;;;;OAIG;IACH,YAAY,CAAC,EAAE,MAAM,MAAM,CAAA;IAC3B;;;OAGG;IACH,MAAM,CAAC,EAAE,WAAW,CAAA;CACrB,CAAA;AAED;;;GAGG;AACH,MAAM,MAAM,gBAAgB,CAAC,CAAC,SAAS,mBAAmB,GAAG,SAAS,IACpE,CAAC,CAAC,SAAS,mBAAmB,GAAG,kBAAkB,CAAC,CAAC,CAAC,GAAG,gBAAgB,CAAC,GAAG,gBAAgB,CAAA;AAE/F,kFAAkF;AAClF,KAAK,QAAQ,CAAC,CAAC,SAAS,gBAAgB,IACtC,OAAO,CAAC,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,GAAG,EAAE,GAAG,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,CAAA;AAEpE,mHAAmH;AACnH,MAAM,MAAM,UAAU,GAAG;IAAE,MAAM,EAAE,YAAY,GAAG,YAAY,CAAA;CAAE,CAAA;AAEhE,sFAAsF;AACtF,MAAM,MAAM,UAAU,GAAG;IACvB,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,MAAM,CAAA;IAChB,OAAO,EAAE,MAAM,CAAA;IACf,MAAM,EAAE,mBAAmB,GAAG,IAAI,CAAA;IAClC,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CACtC,CAAA;AAED,oGAAoG;AACpG,KAAK,YAAY,CAAC,CAAC,SAAS,MAAM,IAAI,CAAC,SAAS,GAAG,MAAM,IAAI,IAAI,MAAM,IAAI,EAAE,GACzE,GAAG,IAAI,GAAG,UAAU,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,EAAE,GAC1C,CAAC,CAAA;AAEL,gFAAgF;AAChF,KAAK,gBAAgB,CAAC,CAAC,SAAS,MAAM,IAAI,CAAC,SAAS,GAAG,MAAM,UAAU,IAAI,MAAM,EAAE,GAC/E,UAAU,GACV,KAAK,CAAA;AAET;;;;;GAKG;AACH,MAAM,MAAM,oBAAoB,CAAC,MAAM,SAAS,gBAAgB,IAAI;KACjE,UAAU,IAAI,gBAAgB,CAAC,OAAO,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAC,GAAG;SACnE,KAAK,IAAI,OAAO,CACf,MAAM,EACN,GAAG,UAAU,IAAI,MAAM,EAAE,CAC1B,IAAI,KAAK,SAAS,GAAG,UAAU,IAAI,MAAM,MAAM,EAAE,GAAG,YAAY,CAAC,MAAM,CAAC,GAAG,KAAK,GAAG,CAClF,GAAG,IAAI,EAAE,QAAQ,CAAC,KAAK,CAAC,KACrB,OAAO,CAAC,UAAU,CAAC;KACzB;CACF,CAAA;AAED;;;;GAIG;AACH,MAAM,MAAM,mBAAmB,CAAC,CAAC,SAAS,mBAAmB,GAAG,SAAS,GAAG,SAAS,IAAI;IACvF;;;OAGG;IACH,IAAI,CAAC,CAAC,SAAS,gBAAgB,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,GAAG,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,UAAU,CAAC,CAAA;IACvF,gFAAgF;IAChF,IAAI,IAAI,OAAO,CAAC,UAAU,CAAC,CAAA;CAC5B,GAAG,oBAAoB,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,CAAA;AA4D7C;;;;;GAKG;AACH,eAAO,MAAM,yBAAyB,GAAI,CAAC,SAAS,mBAAmB,GAAG,SAAS,GAAG,SAAS,EAC7F,QAAQ,yBAAyB,GAAG;IAAE,MAAM,CAAC,EAAE,CAAC,CAAA;CAAE,KACjD,mBAAmB,CAAC,CAAC,CAyEvB,CAAA"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"deliver.d.ts","sourceRoot":"","sources":["../../src/deliver.ts"],"names":[],"mappings":"AAGA,sFAAsF;AACtF,eAAO,MAAM,cAAc,QAAW,CAAA;AAEtC,eAAO,MAAM,oBAAoB,IAAI,CAAA;AAOrC;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB,sNAWuB,CAAA;AAsFpD,MAAM,MAAM,WAAW,GAAG;IACxB,GAAG,EAAE,MAAM,CAAA;IACX,wEAAwE;IACxE,IAAI,EAAE,MAAM,CAAA;IACZ,sGAAsG;IACtG,SAAS,EAAE,MAAM,CAAA;IACjB,+FAA+F;IAC/F,IAAI,EAAE,CAAC,gBAAgB,EAAE,MAAM,KAAK,MAAM,CAAA;IAC1C,SAAS,EAAE,OAAO,KAAK,CAAA;IACvB,WAAW,EAAE,MAAM,CAAA;IACnB,gGAAgG;IAChG,MAAM,CAAC,EAAE,WAAW,CAAA;CACrB,CAAA;AAED;;;;;GAKG;AACH,eAAO,MAAM,OAAO,GAAU,MAAM,WAAW,KAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAMhF,CAAA"}
|
package/dist/src/errors.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/errors.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,kCAAkC,CAAA;AAE5E;;;;;GAKG;AACH,MAAM,MAAM,sBAAsB,GAC9B,oBAAoB,GAGpB,cAAc,GAEd,mBAAmB,GAEnB,gBAAgB,GAEhB,aAAa,GAEb,eAAe,GAEf,SAAS,GAET,qBAAqB,CAAA;AAEzB;;;;GAIG;AACH,qBAAa,kBAAmB,SAAQ,KAAK;IAIzC,QAAQ,CAAC,IAAI,EAAE,sBAAsB;IAHvC,SAAkB,IAAI,wBAAuB;gBAGlC,IAAI,EAAE,sBAAsB,EACrC,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE;QACR,iEAAiE;QACjE,MAAM,CAAC,EAAE,MAAM,CAAA;QACf,8FAA8F;QAC9F,IAAI,CAAC,EAAE,OAAO,CAAA;QACd,KAAK,CAAC,EAAE,OAAO,CAAA;KAChB;IAOH,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAA;IAEnC;;;;OAIG;IACH,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAA;CACvB"}
|
package/dist/src/index.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,0BAA0B,EAC1B,KAAK,oBAAoB,EACzB,KAAK,yBAAyB,EAC9B,KAAK,2BAA2B,GACjC,MAAM,WAAW,CAAA;AAClB,OAAO,EACL,KAAK,gBAAgB,EACrB,KAAK,oBAAoB,EACzB,yBAAyB,EACzB,KAAK,UAAU,EACf,KAAK,UAAU,EACf,KAAK,mBAAmB,EACxB,KAAK,yBAAyB,GAC/B,MAAM,UAAU,CAAA;AACjB,OAAO,EAAE,kBAAkB,EAAE,KAAK,sBAAsB,EAAE,MAAM,UAAU,CAAA;AAC1E,OAAO,EAAE,aAAa,EAAE,mBAAmB,EAAE,KAAK,mBAAmB,EAAE,MAAM,UAAU,CAAA"}
|
package/dist/src/secret.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"secret.d.ts","sourceRoot":"","sources":["../../src/secret.ts"],"names":[],"mappings":"AAKA,OAAO,CAAC,MAAM,wBAAwB,EAAE,OAAO,MAAM,CAAA;AAErD;;;;;GAKG;AACH,MAAM,MAAM,mBAAmB,GAAG;IAAE,QAAQ,CAAC,CAAC,wBAAwB,CAAC,EAAE,IAAI,CAAA;CAAE,CAAA;AAyB/E;;;;GAIG;AACH,eAAO,MAAM,aAAa,GAAI,MAAM,MAAM,KAAG,mBACY,CAAA;AAEzD;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,GAAI,OAAO,MAAM,KAAG,mBACZ,CAAA;AAExC;;;;GAIG;AACH,eAAO,MAAM,YAAY,GAAI,QAAQ,mBAAmB,GAAG,MAAM,KAAG,MAgBnE,CAAA"}
|