@secondlayer/sdk 6.24.1 → 6.25.1
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/index.d.ts +26 -9
- package/dist/index.js +32 -22
- package/dist/index.js.map +5 -5
- package/dist/streams/index.d.ts +15 -4
- package/dist/streams/index.js +32 -22
- package/dist/streams/index.js.map +4 -4
- package/dist/subgraphs/index.js +32 -22
- package/dist/subgraphs/index.js.map +4 -4
- package/package.json +3 -3
package/dist/index.d.ts
CHANGED
|
@@ -1741,10 +1741,21 @@ type CreateStreamsClientOptions = {
|
|
|
1741
1741
|
*/
|
|
1742
1742
|
dumpsBaseUrl?: string
|
|
1743
1743
|
/**
|
|
1744
|
-
* Verify the ed25519 `X-Signature` on every response
|
|
1745
|
-
*
|
|
1746
|
-
*
|
|
1747
|
-
*
|
|
1744
|
+
* Verify the ed25519 `X-Signature` on every REST response and per-frame SSE
|
|
1745
|
+
* signature. Three states:
|
|
1746
|
+
* - **default (omitted)** — *lenient*: verify when the server signs (the
|
|
1747
|
+
* hosted API signs every response), and pass through when no signature is
|
|
1748
|
+
* present (e.g. a self-hosted instance with no `STREAMS_SIGNING_PRIVATE_KEY`).
|
|
1749
|
+
* So verification is on by default against the hosted API without breaking
|
|
1750
|
+
* unsigned self-host deployments. An *invalid* signature always throws.
|
|
1751
|
+
* - **`true`** (or `{ publicKey }` to pin a known PEM) — *strict*: a missing
|
|
1752
|
+
* OR invalid signature throws `StreamsSignatureError`. Use this when you
|
|
1753
|
+
* require a portable, non-repudiable attestation and won't accept unsigned
|
|
1754
|
+
* data (it also closes the lenient mode's strip-the-header downgrade).
|
|
1755
|
+
* - **`false`** — off.
|
|
1756
|
+
*
|
|
1757
|
+
* The key is fetched once from `/public/streams/signing-key` (cached; a
|
|
1758
|
+
* rotated `X-Signature-KeyId` triggers one refresh) unless a PEM is pinned.
|
|
1748
1759
|
*/
|
|
1749
1760
|
verify?: boolean | {
|
|
1750
1761
|
publicKey: string
|
|
@@ -2293,8 +2304,13 @@ type WebhookHeaderInput = HeaderLookup | StandardWebhooksHeaders | Record<string
|
|
|
2293
2304
|
*
|
|
2294
2305
|
* The signed content is `${id}.${timestamp}.${rawBody}` HMAC-SHA256 with the
|
|
2295
2306
|
* signing secret. Secrets returned by `sl subscriptions create` (or
|
|
2296
|
-
* `rotate-secret`)
|
|
2297
|
-
*
|
|
2307
|
+
* `rotate-secret`) are a bare 64-character hex string used directly as the
|
|
2308
|
+
* HMAC key (its UTF-8 bytes) — this helper handles that. A `whsec_`-prefixed
|
|
2309
|
+
* base64 secret (the Svix convention) is also accepted and base64-decoded after
|
|
2310
|
+
* the prefix is stripped. Note: because the issued secret is bare hex (no
|
|
2311
|
+
* `whsec_` prefix), a generic Svix / Standard Webhooks library will base64-
|
|
2312
|
+
* decode it and derive the wrong key — verify with this helper (or with
|
|
2313
|
+
* {@link verifySecondlayerSignature}, the format-agnostic ed25519 path).
|
|
2298
2314
|
*
|
|
2299
2315
|
* @param rawBody The raw request body as a string. NEVER pass
|
|
2300
2316
|
* `JSON.stringify(req.body)` — re-stringifying drops
|
|
@@ -2308,9 +2324,10 @@ type WebhookHeaderInput = HeaderLookup | StandardWebhooksHeaders | Record<string
|
|
|
2308
2324
|
* a header value by name. Header name matching is
|
|
2309
2325
|
* case-insensitive.
|
|
2310
2326
|
* @param secret The signing secret returned by
|
|
2311
|
-
* `sl subscriptions create` / `rotateSecret
|
|
2312
|
-
* through verbatim — the
|
|
2313
|
-
*
|
|
2327
|
+
* `sl subscriptions create` / `rotateSecret` (a bare
|
|
2328
|
+
* 64-char hex string). Pass it through verbatim — the
|
|
2329
|
+
* helper accepts both bare hex and `whsec_`-prefixed
|
|
2330
|
+
* base64 secrets.
|
|
2314
2331
|
* @param toleranceSeconds Max age of `webhook-timestamp` in seconds. Default
|
|
2315
2332
|
* 300 (5 min) per the Standard Webhooks spec.
|
|
2316
2333
|
* @returns true if every header is present, the timestamp is within
|
package/dist/index.js
CHANGED
|
@@ -1319,10 +1319,16 @@ function subscribeStreamsEvents(opts) {
|
|
|
1319
1319
|
}
|
|
1320
1320
|
if (!parsed.event)
|
|
1321
1321
|
continue;
|
|
1322
|
-
if (opts.verify) {
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1322
|
+
if (opts.verify !== "off") {
|
|
1323
|
+
if (!parsed.sig) {
|
|
1324
|
+
if (opts.verify === "strict") {
|
|
1325
|
+
throw new StreamsSignatureError("Streams SSE frame signature is missing.");
|
|
1326
|
+
}
|
|
1327
|
+
} else {
|
|
1328
|
+
const key = await opts.loadKey();
|
|
1329
|
+
if (!ed25519.verifyEd25519(JSON.stringify(parsed.event), parsed.sig, key.publicKey)) {
|
|
1330
|
+
throw new StreamsSignatureError("Streams SSE frame signature is invalid.");
|
|
1331
|
+
}
|
|
1326
1332
|
}
|
|
1327
1333
|
}
|
|
1328
1334
|
cursor = parsed.event.cursor ?? cursor;
|
|
@@ -1454,7 +1460,8 @@ async function mapStreamsError(response) {
|
|
|
1454
1460
|
function createStreamsClient(options) {
|
|
1455
1461
|
const baseUrl = normalizeBaseUrl(options.baseUrl ?? DEFAULT_STREAMS_BASE_URL);
|
|
1456
1462
|
const fetchImpl = options.fetchImpl ?? ((input, init) => fetch(input, init));
|
|
1457
|
-
const verify = options.verify
|
|
1463
|
+
const verify = options.verify;
|
|
1464
|
+
const verifyMode = verify === false ? "off" : verify === undefined ? "lenient" : "strict";
|
|
1458
1465
|
let keyPromise = null;
|
|
1459
1466
|
function loadKey() {
|
|
1460
1467
|
if (keyPromise)
|
|
@@ -1496,25 +1503,28 @@ function createStreamsClient(options) {
|
|
|
1496
1503
|
if (!response.ok)
|
|
1497
1504
|
await mapStreamsError(response);
|
|
1498
1505
|
const text = await response.text();
|
|
1499
|
-
if (
|
|
1506
|
+
if (verifyMode !== "off") {
|
|
1500
1507
|
const signature = response.headers.get("X-Signature");
|
|
1501
1508
|
if (!signature) {
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
const responseKeyId = response.headers.get("X-Signature-KeyId");
|
|
1505
|
-
let key = await loadKey();
|
|
1506
|
-
if (responseKeyId && responseKeyId !== key.keyId) {
|
|
1507
|
-
if (typeof verify === "object") {
|
|
1508
|
-
throw new StreamsSignatureError(`Response signed with key '${responseKeyId}', expected pinned key '${key.keyId}'.`);
|
|
1509
|
+
if (verifyMode === "strict") {
|
|
1510
|
+
throw new StreamsSignatureError("Response is missing X-Signature.");
|
|
1509
1511
|
}
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1512
|
+
} else {
|
|
1513
|
+
const responseKeyId = response.headers.get("X-Signature-KeyId");
|
|
1514
|
+
let key = await loadKey();
|
|
1515
|
+
if (responseKeyId && responseKeyId !== key.keyId) {
|
|
1516
|
+
if (typeof verify === "object") {
|
|
1517
|
+
throw new StreamsSignatureError(`Response signed with key '${responseKeyId}', expected pinned key '${key.keyId}'.`);
|
|
1518
|
+
}
|
|
1519
|
+
keyPromise = null;
|
|
1520
|
+
key = await loadKey();
|
|
1521
|
+
if (responseKeyId !== key.keyId) {
|
|
1522
|
+
throw new StreamsSignatureError(`Response signed with key '${responseKeyId}' not served by the signing-key endpoint.`);
|
|
1523
|
+
}
|
|
1524
|
+
}
|
|
1525
|
+
if (!ed255192.verifyEd25519(text, signature, key.publicKey)) {
|
|
1526
|
+
throw new StreamsSignatureError;
|
|
1514
1527
|
}
|
|
1515
|
-
}
|
|
1516
|
-
if (!ed255192.verifyEd25519(text, signature, key.publicKey)) {
|
|
1517
|
-
throw new StreamsSignatureError;
|
|
1518
1528
|
}
|
|
1519
1529
|
}
|
|
1520
1530
|
return JSON.parse(text);
|
|
@@ -1618,7 +1628,7 @@ function createStreamsClient(options) {
|
|
|
1618
1628
|
baseUrl,
|
|
1619
1629
|
apiKey: options.apiKey,
|
|
1620
1630
|
fetchImpl,
|
|
1621
|
-
verify:
|
|
1631
|
+
verify: verifyMode,
|
|
1622
1632
|
loadKey,
|
|
1623
1633
|
params
|
|
1624
1634
|
});
|
|
@@ -2505,5 +2515,5 @@ export {
|
|
|
2505
2515
|
ApiError
|
|
2506
2516
|
};
|
|
2507
2517
|
|
|
2508
|
-
//# debugId=
|
|
2518
|
+
//# debugId=9B0B41D8F5C2671064756E2164756E21
|
|
2509
2519
|
//# sourceMappingURL=index.js.map
|