@secondlayer/shared 6.21.0 → 6.23.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/crypto/ed25519.d.ts +22 -0
- package/dist/src/crypto/ed25519.js +80 -0
- package/dist/src/crypto/ed25519.js.map +10 -0
- package/dist/src/crypto/secondlayer-webhook.d.ts +40 -0
- package/dist/src/crypto/secondlayer-webhook.js +130 -0
- package/dist/src/crypto/secondlayer-webhook.js.map +11 -0
- package/dist/src/db/index.d.ts +108 -1
- package/dist/src/db/index.js +81 -1
- package/dist/src/db/index.js.map +7 -5
- package/dist/src/db/queries/chain-reorgs.js +76 -1
- package/dist/src/db/queries/chain-reorgs.js.map +6 -4
- package/dist/src/db/queries/subgraphs.js +76 -1
- package/dist/src/db/queries/subgraphs.js.map +6 -4
- package/dist/src/index.d.ts +132 -25
- package/dist/src/index.js +134 -53
- package/dist/src/index.js.map +8 -6
- package/dist/src/leader.d.ts +53 -0
- package/dist/src/leader.js +257 -0
- package/dist/src/leader.js.map +12 -0
- package/dist/src/streams-bulk-manifest.d.ts +33 -0
- package/dist/src/streams-bulk-manifest.js +104 -0
- package/dist/src/streams-bulk-manifest.js.map +11 -0
- package/package.json +17 -1
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { KeyObject } from "node:crypto";
|
|
2
|
+
/**
|
|
3
|
+
* Asymmetric ed25519 signing for Streams response proofs.
|
|
4
|
+
*
|
|
5
|
+
* Asymmetric (not HMAC) so the proof is real: only the server holds the private
|
|
6
|
+
* key, and any consumer verifies with the published public key — no shared
|
|
7
|
+
* secret to leak. ed25519 uses node's `sign`/`verify` with a `null` algorithm.
|
|
8
|
+
* Keys are PEM (PKCS8 private / SPKI public) for env transport; load once and
|
|
9
|
+
* reuse the KeyObject on hot paths.
|
|
10
|
+
*/
|
|
11
|
+
declare function generateEd25519KeyPair(): {
|
|
12
|
+
privateKeyPem: string
|
|
13
|
+
publicKeyPem: string
|
|
14
|
+
};
|
|
15
|
+
declare function loadEd25519PrivateKey(pem: string): KeyObject;
|
|
16
|
+
declare function loadEd25519PublicKey(pem: string): KeyObject;
|
|
17
|
+
declare function publicKeyPemFromPrivate(privateKeyPem: string): string;
|
|
18
|
+
/** Stable short id for a public key (rotation hint via X-Signature-KeyId). */
|
|
19
|
+
declare function ed25519KeyId(publicKeyPem: string): string;
|
|
20
|
+
declare function signEd25519(payload: string, privateKey: KeyObject): string;
|
|
21
|
+
declare function verifyEd25519(payload: string, signatureBase64: string, publicKey: KeyObject): boolean;
|
|
22
|
+
export { verifyEd25519, signEd25519, publicKeyPemFromPrivate, loadEd25519PublicKey, loadEd25519PrivateKey, generateEd25519KeyPair, ed25519KeyId };
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __returnValue = (v) => v;
|
|
4
|
+
function __exportSetter(name, newValue) {
|
|
5
|
+
this[name] = __returnValue.bind(null, newValue);
|
|
6
|
+
}
|
|
7
|
+
var __export = (target, all) => {
|
|
8
|
+
for (var name in all)
|
|
9
|
+
__defProp(target, name, {
|
|
10
|
+
get: all[name],
|
|
11
|
+
enumerable: true,
|
|
12
|
+
configurable: true,
|
|
13
|
+
set: __exportSetter.bind(all, name)
|
|
14
|
+
});
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
// src/crypto/ed25519.ts
|
|
18
|
+
var exports_ed25519 = {};
|
|
19
|
+
__export(exports_ed25519, {
|
|
20
|
+
verifyEd25519: () => verifyEd25519,
|
|
21
|
+
signEd25519: () => signEd25519,
|
|
22
|
+
publicKeyPemFromPrivate: () => publicKeyPemFromPrivate,
|
|
23
|
+
loadEd25519PublicKey: () => loadEd25519PublicKey,
|
|
24
|
+
loadEd25519PrivateKey: () => loadEd25519PrivateKey,
|
|
25
|
+
generateEd25519KeyPair: () => generateEd25519KeyPair,
|
|
26
|
+
ed25519KeyId: () => ed25519KeyId
|
|
27
|
+
});
|
|
28
|
+
import {
|
|
29
|
+
createHash,
|
|
30
|
+
createPrivateKey,
|
|
31
|
+
createPublicKey,
|
|
32
|
+
generateKeyPairSync,
|
|
33
|
+
sign as nodeSign,
|
|
34
|
+
verify as nodeVerify
|
|
35
|
+
} from "node:crypto";
|
|
36
|
+
function generateEd25519KeyPair() {
|
|
37
|
+
const { privateKey, publicKey } = generateKeyPairSync("ed25519");
|
|
38
|
+
return {
|
|
39
|
+
privateKeyPem: privateKey.export({ format: "pem", type: "pkcs8" }).toString(),
|
|
40
|
+
publicKeyPem: publicKey.export({ format: "pem", type: "spki" }).toString()
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
function loadEd25519PrivateKey(pem) {
|
|
44
|
+
return createPrivateKey(pem);
|
|
45
|
+
}
|
|
46
|
+
function loadEd25519PublicKey(pem) {
|
|
47
|
+
return createPublicKey(pem);
|
|
48
|
+
}
|
|
49
|
+
function publicKeyPemFromPrivate(privateKeyPem) {
|
|
50
|
+
return createPublicKey(createPrivateKey(privateKeyPem)).export({ format: "pem", type: "spki" }).toString();
|
|
51
|
+
}
|
|
52
|
+
function ed25519KeyId(publicKeyPem) {
|
|
53
|
+
const der = createPublicKey(publicKeyPem).export({
|
|
54
|
+
format: "der",
|
|
55
|
+
type: "spki"
|
|
56
|
+
});
|
|
57
|
+
return createHash("sha256").update(der).digest("base64url").slice(0, 16);
|
|
58
|
+
}
|
|
59
|
+
function signEd25519(payload, privateKey) {
|
|
60
|
+
return nodeSign(null, Buffer.from(payload, "utf8"), privateKey).toString("base64");
|
|
61
|
+
}
|
|
62
|
+
function verifyEd25519(payload, signatureBase64, publicKey) {
|
|
63
|
+
try {
|
|
64
|
+
return nodeVerify(null, Buffer.from(payload, "utf8"), publicKey, Buffer.from(signatureBase64, "base64"));
|
|
65
|
+
} catch {
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
export {
|
|
70
|
+
verifyEd25519,
|
|
71
|
+
signEd25519,
|
|
72
|
+
publicKeyPemFromPrivate,
|
|
73
|
+
loadEd25519PublicKey,
|
|
74
|
+
loadEd25519PrivateKey,
|
|
75
|
+
generateEd25519KeyPair,
|
|
76
|
+
ed25519KeyId
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
//# debugId=B4FC95F24211B0D064756E2164756E21
|
|
80
|
+
//# sourceMappingURL=ed25519.js.map
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/crypto/ed25519.ts"],
|
|
4
|
+
"sourcesContent": [
|
|
5
|
+
"import {\n\ttype KeyObject,\n\tcreateHash,\n\tcreatePrivateKey,\n\tcreatePublicKey,\n\tgenerateKeyPairSync,\n\tsign as nodeSign,\n\tverify as nodeVerify,\n} from \"node:crypto\";\n\n/**\n * Asymmetric ed25519 signing for Streams response proofs.\n *\n * Asymmetric (not HMAC) so the proof is real: only the server holds the private\n * key, and any consumer verifies with the published public key — no shared\n * secret to leak. ed25519 uses node's `sign`/`verify` with a `null` algorithm.\n * Keys are PEM (PKCS8 private / SPKI public) for env transport; load once and\n * reuse the KeyObject on hot paths.\n */\n\nexport function generateEd25519KeyPair(): {\n\tprivateKeyPem: string;\n\tpublicKeyPem: string;\n} {\n\tconst { privateKey, publicKey } = generateKeyPairSync(\"ed25519\");\n\treturn {\n\t\tprivateKeyPem: privateKey\n\t\t\t.export({ format: \"pem\", type: \"pkcs8\" })\n\t\t\t.toString(),\n\t\tpublicKeyPem: publicKey.export({ format: \"pem\", type: \"spki\" }).toString(),\n\t};\n}\n\nexport function loadEd25519PrivateKey(pem: string): KeyObject {\n\treturn createPrivateKey(pem);\n}\n\nexport function loadEd25519PublicKey(pem: string): KeyObject {\n\treturn createPublicKey(pem);\n}\n\nexport function publicKeyPemFromPrivate(privateKeyPem: string): string {\n\treturn createPublicKey(createPrivateKey(privateKeyPem))\n\t\t.export({ format: \"pem\", type: \"spki\" })\n\t\t.toString();\n}\n\n/** Stable short id for a public key (rotation hint via X-Signature-KeyId). */\nexport function ed25519KeyId(publicKeyPem: string): string {\n\tconst der = createPublicKey(publicKeyPem).export({\n\t\tformat: \"der\",\n\t\ttype: \"spki\",\n\t});\n\treturn createHash(\"sha256\").update(der).digest(\"base64url\").slice(0, 16);\n}\n\nexport function signEd25519(payload: string, privateKey: KeyObject): string {\n\treturn nodeSign(null, Buffer.from(payload, \"utf8\"), privateKey).toString(\n\t\t\"base64\",\n\t);\n}\n\nexport function verifyEd25519(\n\tpayload: string,\n\tsignatureBase64: string,\n\tpublicKey: KeyObject,\n): boolean {\n\ttry {\n\t\treturn nodeVerify(\n\t\t\tnull,\n\t\t\tBuffer.from(payload, \"utf8\"),\n\t\t\tpublicKey,\n\t\t\tBuffer.from(signatureBase64, \"base64\"),\n\t\t);\n\t} catch {\n\t\treturn false;\n\t}\n}\n"
|
|
6
|
+
],
|
|
7
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,UAMC;AAAA,YACA;AAAA;AAaM,SAAS,sBAAsB,GAGpC;AAAA,EACD,QAAQ,YAAY,cAAc,oBAAoB,SAAS;AAAA,EAC/D,OAAO;AAAA,IACN,eAAe,WACb,OAAO,EAAE,QAAQ,OAAO,MAAM,QAAQ,CAAC,EACvC,SAAS;AAAA,IACX,cAAc,UAAU,OAAO,EAAE,QAAQ,OAAO,MAAM,OAAO,CAAC,EAAE,SAAS;AAAA,EAC1E;AAAA;AAGM,SAAS,qBAAqB,CAAC,KAAwB;AAAA,EAC7D,OAAO,iBAAiB,GAAG;AAAA;AAGrB,SAAS,oBAAoB,CAAC,KAAwB;AAAA,EAC5D,OAAO,gBAAgB,GAAG;AAAA;AAGpB,SAAS,uBAAuB,CAAC,eAA+B;AAAA,EACtE,OAAO,gBAAgB,iBAAiB,aAAa,CAAC,EACpD,OAAO,EAAE,QAAQ,OAAO,MAAM,OAAO,CAAC,EACtC,SAAS;AAAA;AAIL,SAAS,YAAY,CAAC,cAA8B;AAAA,EAC1D,MAAM,MAAM,gBAAgB,YAAY,EAAE,OAAO;AAAA,IAChD,QAAQ;AAAA,IACR,MAAM;AAAA,EACP,CAAC;AAAA,EACD,OAAO,WAAW,QAAQ,EAAE,OAAO,GAAG,EAAE,OAAO,WAAW,EAAE,MAAM,GAAG,EAAE;AAAA;AAGjE,SAAS,WAAW,CAAC,SAAiB,YAA+B;AAAA,EAC3E,OAAO,SAAS,MAAM,OAAO,KAAK,SAAS,MAAM,GAAG,UAAU,EAAE,SAC/D,QACD;AAAA;AAGM,SAAS,aAAa,CAC5B,SACA,iBACA,WACU;AAAA,EACV,IAAI;AAAA,IACH,OAAO,WACN,MACA,OAAO,KAAK,SAAS,MAAM,GAC3B,WACA,OAAO,KAAK,iBAAiB,QAAQ,CACtC;AAAA,IACC,MAAM;AAAA,IACP,OAAO;AAAA;AAAA;",
|
|
8
|
+
"debugId": "B4FC95F24211B0D064756E2164756E21",
|
|
9
|
+
"names": []
|
|
10
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Universal Secondlayer webhook authenticity — an ed25519 signature attached to
|
|
3
|
+
* EVERY delivery regardless of body format.
|
|
4
|
+
*
|
|
5
|
+
* Only the `standard-webhooks` format carries an HMAC; `raw`/`cloudevents`/etc.
|
|
6
|
+
* carried no Secondlayer proof, so a receiver had no way to know a payload came
|
|
7
|
+
* from us. This signs each delivery with a single platform ed25519 key so any
|
|
8
|
+
* receiver verifies with the published public key — no per-subscription secret,
|
|
9
|
+
* and the body shape stays format-specific.
|
|
10
|
+
*
|
|
11
|
+
* Header names are lowercase to match the format builders' header maps (HTTP
|
|
12
|
+
* header names are case-insensitive on the wire).
|
|
13
|
+
*/
|
|
14
|
+
declare const WEBHOOK_ID_HEADER = "webhook-id";
|
|
15
|
+
declare const SECONDLAYER_SIGNATURE_HEADER = "x-secondlayer-signature";
|
|
16
|
+
declare const SECONDLAYER_KEY_ID_HEADER = "x-secondlayer-signature-keyid";
|
|
17
|
+
type SecondlayerWebhookSigner = {
|
|
18
|
+
keyId: string
|
|
19
|
+
publicKeyPem: string
|
|
20
|
+
sign(payload: string): string
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* Memoized webhook signer, or null when no key is configured (signing is then a
|
|
24
|
+
* no-op, so the universal header is safe to ship before a key is provisioned).
|
|
25
|
+
*/
|
|
26
|
+
declare function getSecondlayerWebhookSigner(): SecondlayerWebhookSigner | null;
|
|
27
|
+
/** Reset the memoized signer. Tests only. */
|
|
28
|
+
declare function resetSecondlayerWebhookSignerForTest(): void;
|
|
29
|
+
/**
|
|
30
|
+
* Build the universal authenticity headers for a delivery. Returns null when no
|
|
31
|
+
* signing key is configured (caller leaves the delivery unsigned).
|
|
32
|
+
*/
|
|
33
|
+
declare function signSecondlayerWebhook(webhookId: string, body: string): Record<string, string> | null;
|
|
34
|
+
/**
|
|
35
|
+
* Verify a delivery's ed25519 signature over `${webhookId}.${rawBody}` against
|
|
36
|
+
* the published public key. Low-level (raw values); receivers use the SDK's
|
|
37
|
+
* `verifySecondlayerSignature`, which extracts the headers ergonomically.
|
|
38
|
+
*/
|
|
39
|
+
declare function verifySecondlayerSignatureValues(rawBody: string, webhookId: string | undefined, signatureBase64: string | undefined, publicKeyPem: string): boolean;
|
|
40
|
+
export { verifySecondlayerSignatureValues, signSecondlayerWebhook, resetSecondlayerWebhookSignerForTest, getSecondlayerWebhookSigner, WEBHOOK_ID_HEADER, SecondlayerWebhookSigner, SECONDLAYER_SIGNATURE_HEADER, SECONDLAYER_KEY_ID_HEADER };
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __returnValue = (v) => v;
|
|
4
|
+
function __exportSetter(name, newValue) {
|
|
5
|
+
this[name] = __returnValue.bind(null, newValue);
|
|
6
|
+
}
|
|
7
|
+
var __export = (target, all) => {
|
|
8
|
+
for (var name in all)
|
|
9
|
+
__defProp(target, name, {
|
|
10
|
+
get: all[name],
|
|
11
|
+
enumerable: true,
|
|
12
|
+
configurable: true,
|
|
13
|
+
set: __exportSetter.bind(all, name)
|
|
14
|
+
});
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
// src/crypto/ed25519.ts
|
|
18
|
+
var exports_ed25519 = {};
|
|
19
|
+
__export(exports_ed25519, {
|
|
20
|
+
verifyEd25519: () => verifyEd25519,
|
|
21
|
+
signEd25519: () => signEd25519,
|
|
22
|
+
publicKeyPemFromPrivate: () => publicKeyPemFromPrivate,
|
|
23
|
+
loadEd25519PublicKey: () => loadEd25519PublicKey,
|
|
24
|
+
loadEd25519PrivateKey: () => loadEd25519PrivateKey,
|
|
25
|
+
generateEd25519KeyPair: () => generateEd25519KeyPair,
|
|
26
|
+
ed25519KeyId: () => ed25519KeyId
|
|
27
|
+
});
|
|
28
|
+
import {
|
|
29
|
+
createHash,
|
|
30
|
+
createPrivateKey,
|
|
31
|
+
createPublicKey,
|
|
32
|
+
generateKeyPairSync,
|
|
33
|
+
sign as nodeSign,
|
|
34
|
+
verify as nodeVerify
|
|
35
|
+
} from "node:crypto";
|
|
36
|
+
function generateEd25519KeyPair() {
|
|
37
|
+
const { privateKey, publicKey } = generateKeyPairSync("ed25519");
|
|
38
|
+
return {
|
|
39
|
+
privateKeyPem: privateKey.export({ format: "pem", type: "pkcs8" }).toString(),
|
|
40
|
+
publicKeyPem: publicKey.export({ format: "pem", type: "spki" }).toString()
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
function loadEd25519PrivateKey(pem) {
|
|
44
|
+
return createPrivateKey(pem);
|
|
45
|
+
}
|
|
46
|
+
function loadEd25519PublicKey(pem) {
|
|
47
|
+
return createPublicKey(pem);
|
|
48
|
+
}
|
|
49
|
+
function publicKeyPemFromPrivate(privateKeyPem) {
|
|
50
|
+
return createPublicKey(createPrivateKey(privateKeyPem)).export({ format: "pem", type: "spki" }).toString();
|
|
51
|
+
}
|
|
52
|
+
function ed25519KeyId(publicKeyPem) {
|
|
53
|
+
const der = createPublicKey(publicKeyPem).export({
|
|
54
|
+
format: "der",
|
|
55
|
+
type: "spki"
|
|
56
|
+
});
|
|
57
|
+
return createHash("sha256").update(der).digest("base64url").slice(0, 16);
|
|
58
|
+
}
|
|
59
|
+
function signEd25519(payload, privateKey) {
|
|
60
|
+
return nodeSign(null, Buffer.from(payload, "utf8"), privateKey).toString("base64");
|
|
61
|
+
}
|
|
62
|
+
function verifyEd25519(payload, signatureBase64, publicKey) {
|
|
63
|
+
try {
|
|
64
|
+
return nodeVerify(null, Buffer.from(payload, "utf8"), publicKey, Buffer.from(signatureBase64, "base64"));
|
|
65
|
+
} catch {
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// src/crypto/secondlayer-webhook.ts
|
|
71
|
+
var WEBHOOK_ID_HEADER = "webhook-id";
|
|
72
|
+
var SECONDLAYER_SIGNATURE_HEADER = "x-secondlayer-signature";
|
|
73
|
+
var SECONDLAYER_KEY_ID_HEADER = "x-secondlayer-signature-keyid";
|
|
74
|
+
var cached;
|
|
75
|
+
function signingKeyFromEnv() {
|
|
76
|
+
return process.env.SECONDLAYER_WEBHOOK_SIGNING_PRIVATE_KEY || process.env.STREAMS_SIGNING_PRIVATE_KEY || undefined;
|
|
77
|
+
}
|
|
78
|
+
function getSecondlayerWebhookSigner() {
|
|
79
|
+
if (cached !== undefined)
|
|
80
|
+
return cached;
|
|
81
|
+
const raw = signingKeyFromEnv();
|
|
82
|
+
if (!raw) {
|
|
83
|
+
cached = null;
|
|
84
|
+
return null;
|
|
85
|
+
}
|
|
86
|
+
const pem = raw.includes("\\n") ? raw.replace(/\\n/g, `
|
|
87
|
+
`) : raw;
|
|
88
|
+
const privateKey = loadEd25519PrivateKey(pem);
|
|
89
|
+
const publicKeyPem = publicKeyPemFromPrivate(pem);
|
|
90
|
+
cached = {
|
|
91
|
+
keyId: ed25519KeyId(publicKeyPem),
|
|
92
|
+
publicKeyPem,
|
|
93
|
+
sign: (payload) => signEd25519(payload, privateKey)
|
|
94
|
+
};
|
|
95
|
+
return cached;
|
|
96
|
+
}
|
|
97
|
+
function resetSecondlayerWebhookSignerForTest() {
|
|
98
|
+
cached = undefined;
|
|
99
|
+
}
|
|
100
|
+
function signedContent(webhookId, body) {
|
|
101
|
+
return `${webhookId}.${body}`;
|
|
102
|
+
}
|
|
103
|
+
function signSecondlayerWebhook(webhookId, body) {
|
|
104
|
+
const signer = getSecondlayerWebhookSigner();
|
|
105
|
+
if (!signer)
|
|
106
|
+
return null;
|
|
107
|
+
return {
|
|
108
|
+
[WEBHOOK_ID_HEADER]: webhookId,
|
|
109
|
+
[SECONDLAYER_SIGNATURE_HEADER]: signer.sign(signedContent(webhookId, body)),
|
|
110
|
+
[SECONDLAYER_KEY_ID_HEADER]: signer.keyId
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
function verifySecondlayerSignatureValues(rawBody, webhookId, signatureBase64, publicKeyPem) {
|
|
114
|
+
if (!webhookId || !signatureBase64)
|
|
115
|
+
return false;
|
|
116
|
+
const publicKey = loadEd25519PublicKey(publicKeyPem);
|
|
117
|
+
return verifyEd25519(signedContent(webhookId, rawBody), signatureBase64, publicKey);
|
|
118
|
+
}
|
|
119
|
+
export {
|
|
120
|
+
verifySecondlayerSignatureValues,
|
|
121
|
+
signSecondlayerWebhook,
|
|
122
|
+
resetSecondlayerWebhookSignerForTest,
|
|
123
|
+
getSecondlayerWebhookSigner,
|
|
124
|
+
WEBHOOK_ID_HEADER,
|
|
125
|
+
SECONDLAYER_SIGNATURE_HEADER,
|
|
126
|
+
SECONDLAYER_KEY_ID_HEADER
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
//# debugId=ECECE08A1A6DA84764756E2164756E21
|
|
130
|
+
//# sourceMappingURL=secondlayer-webhook.js.map
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/crypto/ed25519.ts", "../src/crypto/secondlayer-webhook.ts"],
|
|
4
|
+
"sourcesContent": [
|
|
5
|
+
"import {\n\ttype KeyObject,\n\tcreateHash,\n\tcreatePrivateKey,\n\tcreatePublicKey,\n\tgenerateKeyPairSync,\n\tsign as nodeSign,\n\tverify as nodeVerify,\n} from \"node:crypto\";\n\n/**\n * Asymmetric ed25519 signing for Streams response proofs.\n *\n * Asymmetric (not HMAC) so the proof is real: only the server holds the private\n * key, and any consumer verifies with the published public key — no shared\n * secret to leak. ed25519 uses node's `sign`/`verify` with a `null` algorithm.\n * Keys are PEM (PKCS8 private / SPKI public) for env transport; load once and\n * reuse the KeyObject on hot paths.\n */\n\nexport function generateEd25519KeyPair(): {\n\tprivateKeyPem: string;\n\tpublicKeyPem: string;\n} {\n\tconst { privateKey, publicKey } = generateKeyPairSync(\"ed25519\");\n\treturn {\n\t\tprivateKeyPem: privateKey\n\t\t\t.export({ format: \"pem\", type: \"pkcs8\" })\n\t\t\t.toString(),\n\t\tpublicKeyPem: publicKey.export({ format: \"pem\", type: \"spki\" }).toString(),\n\t};\n}\n\nexport function loadEd25519PrivateKey(pem: string): KeyObject {\n\treturn createPrivateKey(pem);\n}\n\nexport function loadEd25519PublicKey(pem: string): KeyObject {\n\treturn createPublicKey(pem);\n}\n\nexport function publicKeyPemFromPrivate(privateKeyPem: string): string {\n\treturn createPublicKey(createPrivateKey(privateKeyPem))\n\t\t.export({ format: \"pem\", type: \"spki\" })\n\t\t.toString();\n}\n\n/** Stable short id for a public key (rotation hint via X-Signature-KeyId). */\nexport function ed25519KeyId(publicKeyPem: string): string {\n\tconst der = createPublicKey(publicKeyPem).export({\n\t\tformat: \"der\",\n\t\ttype: \"spki\",\n\t});\n\treturn createHash(\"sha256\").update(der).digest(\"base64url\").slice(0, 16);\n}\n\nexport function signEd25519(payload: string, privateKey: KeyObject): string {\n\treturn nodeSign(null, Buffer.from(payload, \"utf8\"), privateKey).toString(\n\t\t\"base64\",\n\t);\n}\n\nexport function verifyEd25519(\n\tpayload: string,\n\tsignatureBase64: string,\n\tpublicKey: KeyObject,\n): boolean {\n\ttry {\n\t\treturn nodeVerify(\n\t\t\tnull,\n\t\t\tBuffer.from(payload, \"utf8\"),\n\t\t\tpublicKey,\n\t\t\tBuffer.from(signatureBase64, \"base64\"),\n\t\t);\n\t} catch {\n\t\treturn false;\n\t}\n}\n",
|
|
6
|
+
"import {\n\ted25519KeyId,\n\tloadEd25519PrivateKey,\n\tloadEd25519PublicKey,\n\tpublicKeyPemFromPrivate,\n\tsignEd25519,\n\tverifyEd25519,\n} from \"./ed25519.ts\";\n\n/**\n * Universal Secondlayer webhook authenticity — an ed25519 signature attached to\n * EVERY delivery regardless of body format.\n *\n * Only the `standard-webhooks` format carries an HMAC; `raw`/`cloudevents`/etc.\n * carried no Secondlayer proof, so a receiver had no way to know a payload came\n * from us. This signs each delivery with a single platform ed25519 key so any\n * receiver verifies with the published public key — no per-subscription secret,\n * and the body shape stays format-specific.\n *\n * Header names are lowercase to match the format builders' header maps (HTTP\n * header names are case-insensitive on the wire).\n */\nexport const WEBHOOK_ID_HEADER = \"webhook-id\";\nexport const SECONDLAYER_SIGNATURE_HEADER = \"x-secondlayer-signature\";\nexport const SECONDLAYER_KEY_ID_HEADER = \"x-secondlayer-signature-keyid\";\n\nexport type SecondlayerWebhookSigner = {\n\tkeyId: string;\n\tpublicKeyPem: string;\n\tsign(payload: string): string;\n};\n\nlet cached: SecondlayerWebhookSigner | null | undefined;\n\nfunction signingKeyFromEnv(): string | undefined {\n\t// A dedicated webhook key if provided, else the platform Streams key — both\n\t// are the same ed25519 \"single platform identity\", so reusing it keeps key\n\t// distribution to one published public key.\n\treturn (\n\t\tprocess.env.SECONDLAYER_WEBHOOK_SIGNING_PRIVATE_KEY ||\n\t\tprocess.env.STREAMS_SIGNING_PRIVATE_KEY ||\n\t\tundefined\n\t);\n}\n\n/**\n * Memoized webhook signer, or null when no key is configured (signing is then a\n * no-op, so the universal header is safe to ship before a key is provisioned).\n */\nexport function getSecondlayerWebhookSigner(): SecondlayerWebhookSigner | null {\n\tif (cached !== undefined) return cached;\n\tconst raw = signingKeyFromEnv();\n\tif (!raw) {\n\t\tcached = null;\n\t\treturn null;\n\t}\n\t// Env transport often escapes newlines; restore real PEM line breaks.\n\tconst pem = raw.includes(\"\\\\n\") ? raw.replace(/\\\\n/g, \"\\n\") : raw;\n\tconst privateKey = loadEd25519PrivateKey(pem);\n\tconst publicKeyPem = publicKeyPemFromPrivate(pem);\n\tcached = {\n\t\tkeyId: ed25519KeyId(publicKeyPem),\n\t\tpublicKeyPem,\n\t\tsign: (payload) => signEd25519(payload, privateKey),\n\t};\n\treturn cached;\n}\n\n/** Reset the memoized signer. Tests only. */\nexport function resetSecondlayerWebhookSignerForTest(): void {\n\tcached = undefined;\n}\n\n/**\n * The exact bytes the signature covers: `${webhookId}.${body}`. Binding the id\n * into the signed content stops a captured body from being replayed under a\n * different delivery id.\n */\nfunction signedContent(webhookId: string, body: string): string {\n\treturn `${webhookId}.${body}`;\n}\n\n/**\n * Build the universal authenticity headers for a delivery. Returns null when no\n * signing key is configured (caller leaves the delivery unsigned).\n */\nexport function signSecondlayerWebhook(\n\twebhookId: string,\n\tbody: string,\n): Record<string, string> | null {\n\tconst signer = getSecondlayerWebhookSigner();\n\tif (!signer) return null;\n\treturn {\n\t\t[WEBHOOK_ID_HEADER]: webhookId,\n\t\t[SECONDLAYER_SIGNATURE_HEADER]: signer.sign(signedContent(webhookId, body)),\n\t\t[SECONDLAYER_KEY_ID_HEADER]: signer.keyId,\n\t};\n}\n\n/**\n * Verify a delivery's ed25519 signature over `${webhookId}.${rawBody}` against\n * the published public key. Low-level (raw values); receivers use the SDK's\n * `verifySecondlayerSignature`, which extracts the headers ergonomically.\n */\nexport function verifySecondlayerSignatureValues(\n\trawBody: string,\n\twebhookId: string | undefined,\n\tsignatureBase64: string | undefined,\n\tpublicKeyPem: string,\n): boolean {\n\tif (!webhookId || !signatureBase64) return false;\n\tconst publicKey = loadEd25519PublicKey(publicKeyPem);\n\treturn verifyEd25519(\n\t\tsignedContent(webhookId, rawBody),\n\t\tsignatureBase64,\n\t\tpublicKey,\n\t);\n}\n"
|
|
7
|
+
],
|
|
8
|
+
"mappings": "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",
|
|
9
|
+
"debugId": "ECECE08A1A6DA84764756E2164756E21",
|
|
10
|
+
"names": []
|
|
11
|
+
}
|
package/dist/src/db/index.d.ts
CHANGED
|
@@ -948,6 +948,113 @@ declare const SOURCE_READ_COLUMNS: {
|
|
|
948
948
|
readonly events: readonly ["block_height", "data", "event_index", "tx_id", "type"]
|
|
949
949
|
readonly chain_reorgs: readonly ["detected_at"]
|
|
950
950
|
};
|
|
951
|
+
/**
|
|
952
|
+
* Per-migration DB-plane gating for the source/target split.
|
|
953
|
+
*
|
|
954
|
+
* Under the split, SOURCE (chain DB) holds only chain+decoded tables — the
|
|
955
|
+
* control-plane tables were dropped to reclaim space — while TARGET (platform
|
|
956
|
+
* DB) holds the control plane. `migrate.ts` still runs EVERY migration on EVERY
|
|
957
|
+
* database (kysely integrity: the provider set must never be filtered per-DB, or
|
|
958
|
+
* kysely throws "previously executed migration is missing" because each DB's
|
|
959
|
+
* `kysely_migration` already records all of them). Instead, `migrate.ts` sets a
|
|
960
|
+
* role before each pass and a migration gates its DDL with the helpers below: a
|
|
961
|
+
* control migration's `up()` is a no-op on SOURCE but is still recorded applied,
|
|
962
|
+
* so there is no missing-migration error and no re-run.
|
|
963
|
+
*
|
|
964
|
+
* `'both'` is single-DB / collapsed-split mode (dev / OSS / CI): every helper
|
|
965
|
+
* runs, identical to pre-split behavior.
|
|
966
|
+
*
|
|
967
|
+
* Authoring a new migration under the split:
|
|
968
|
+
* async function up(db: Kysely<unknown>): Promise<void> {
|
|
969
|
+
* await onControlPlane(() => sql`ALTER TABLE accounts ADD COLUMN …`.execute(db));
|
|
970
|
+
* await onChainPlane(() => sql`ALTER TABLE blocks ADD COLUMN …`.execute(db));
|
|
971
|
+
* // schema-wide / mixed statements: leave unwrapped (run on both).
|
|
972
|
+
* }
|
|
973
|
+
*/
|
|
974
|
+
type MigrationRole = "source" | "target" | "both";
|
|
975
|
+
declare function setMigrationRole(role: MigrationRole): void;
|
|
976
|
+
declare function getMigrationRole(): MigrationRole;
|
|
977
|
+
/** Run control-plane (TARGET) DDL only when this pass targets the control plane. */
|
|
978
|
+
declare function onControlPlane(fn: () => Promise<void>): Promise<void>;
|
|
979
|
+
/** Run chain/decoded (SOURCE) DDL only when this pass targets the chain plane. */
|
|
980
|
+
declare function onChainPlane(fn: () => Promise<void>): Promise<void>;
|
|
981
|
+
type DbPlane = "source" | "target" | "both";
|
|
982
|
+
/**
|
|
983
|
+
* Canonical table → DB-plane mapping for the source/target split.
|
|
984
|
+
*
|
|
985
|
+
* SOURCE = chain + decoded (the `postgres` instance); TARGET = control plane
|
|
986
|
+
* (the `postgres-platform` instance). `both` = present/used on both planes
|
|
987
|
+
* (`service_heartbeats`: the indexer writes its row on SOURCE, the
|
|
988
|
+
* subgraph-processor writes its row on TARGET).
|
|
989
|
+
*
|
|
990
|
+
* `satisfies Record<keyof Database, DbPlane>` makes adding a table to `Database`
|
|
991
|
+
* without classifying it here a COMPILE error. This is the single source of
|
|
992
|
+
* truth for the split — `docker/SCHEMA_SPLIT.md` and the cutover script's
|
|
993
|
+
* `CONTROL_TABLES` mirror the `target` set (guarded by `table-plane.test.ts`).
|
|
994
|
+
* Use it to decide which migration helper a table's DDL belongs in
|
|
995
|
+
* (`onControlPlane` for `target`, `onChainPlane` for `source`).
|
|
996
|
+
*
|
|
997
|
+
* Note: `kysely_migration` / `kysely_migration_lock` are kysely-managed (not in
|
|
998
|
+
* `Database`) and exist on both — they are intentionally not listed here.
|
|
999
|
+
*/
|
|
1000
|
+
declare const TABLE_TO_DB: {
|
|
1001
|
+
blocks: string
|
|
1002
|
+
transactions: string
|
|
1003
|
+
events: string
|
|
1004
|
+
transactions_archive: string
|
|
1005
|
+
events_archive: string
|
|
1006
|
+
dead_letter_events: string
|
|
1007
|
+
mempool_transactions: string
|
|
1008
|
+
index_progress: string
|
|
1009
|
+
contracts: string
|
|
1010
|
+
chain_reorgs: string
|
|
1011
|
+
decoded_events: string
|
|
1012
|
+
l2_decoder_checkpoints: string
|
|
1013
|
+
pox4_calls: string
|
|
1014
|
+
pox4_cycles_daily: string
|
|
1015
|
+
pox4_signers_daily: string
|
|
1016
|
+
burn_block_rewards: string
|
|
1017
|
+
burn_block_reward_slots: string
|
|
1018
|
+
sbtc_events: string
|
|
1019
|
+
sbtc_token_events: string
|
|
1020
|
+
sbtc_supply_snapshots: string
|
|
1021
|
+
bns_name_events: string
|
|
1022
|
+
bns_namespace_events: string
|
|
1023
|
+
bns_marketplace_events: string
|
|
1024
|
+
bns_names: string
|
|
1025
|
+
bns_namespaces: string
|
|
1026
|
+
accounts: string
|
|
1027
|
+
api_keys: string
|
|
1028
|
+
sessions: string
|
|
1029
|
+
magic_links: string
|
|
1030
|
+
usage_daily: string
|
|
1031
|
+
usage_snapshots: string
|
|
1032
|
+
account_insights: string
|
|
1033
|
+
account_agent_runs: string
|
|
1034
|
+
account_spend_caps: string
|
|
1035
|
+
processed_stripe_events: string
|
|
1036
|
+
tenants: string
|
|
1037
|
+
tenant_usage_monthly: string
|
|
1038
|
+
tenant_compute_addons: string
|
|
1039
|
+
provisioning_audit_log: string
|
|
1040
|
+
projects: string
|
|
1041
|
+
team_members: string
|
|
1042
|
+
team_invitations: string
|
|
1043
|
+
chat_sessions: string
|
|
1044
|
+
chat_messages: string
|
|
1045
|
+
subscriptions: string
|
|
1046
|
+
subscription_outbox: string
|
|
1047
|
+
subscription_deliveries: string
|
|
1048
|
+
trigger_evaluator_state: string
|
|
1049
|
+
subgraphs: string
|
|
1050
|
+
subgraph_operations: string
|
|
1051
|
+
subgraph_health_snapshots: string
|
|
1052
|
+
subgraph_gaps: string
|
|
1053
|
+
subgraph_usage_daily: string
|
|
1054
|
+
subgraph_processing_stats: string
|
|
1055
|
+
subgraph_table_snapshots: string
|
|
1056
|
+
service_heartbeats: string
|
|
1057
|
+
};
|
|
951
1058
|
interface DbSplitStatus {
|
|
952
1059
|
/** "split" when source/target resolve to different DBs, else "single". */
|
|
953
1060
|
mode: "split" | "single";
|
|
@@ -1015,4 +1122,4 @@ declare function getRawClient(role?: "source" | "target"): ReturnType<typeof pos
|
|
|
1015
1122
|
declare function getRawClientFor(url: string): ReturnType<typeof postgres>;
|
|
1016
1123
|
/** Close all DB connection pools. Call in CLI commands to allow process exit. */
|
|
1017
1124
|
declare function closeDb(): Promise<void>;
|
|
1018
|
-
export { sql, parseJsonb, jsonb, getTargetDb, getSourceDb, getRawClientFor, getRawClient, getDbSplitStatus, getDb, closeDb, assertDbSplit, UsageSnapshotsTable, UsageSnapshot, UsageDailyTable, UsageDaily, UpdateTransaction, UpdateTenantUsageMonthly, UpdateTenantComputeAddon, UpdateTenant, UpdateSubscriptionOutbox, UpdateSubscription, UpdateSubgraphOperation, UpdateSubgraph, UpdateProject, UpdateIndexProgress, UpdateEvent, UpdateContract, UpdateChatSession, UpdateBlock, UpdateApiKey, UpdateAccountSpendCap, TriggerEvaluatorStateTable, TriggerEvaluatorState, TransactionsTable, TransactionsArchiveTable, Transaction, TenantsTable, TenantUsageMonthlyTable, TenantUsageMonthly, TenantStatus, TenantComputeAddonsTable, TenantComputeAddon, Tenant, TeamMembersTable, TeamMember, TeamInvitationsTable, TeamInvitation, SubscriptionsTable, SubscriptionStatus, SubscriptionRuntime, SubscriptionOutboxTable, SubscriptionOutbox, SubscriptionKind, SubscriptionFormat, SubscriptionDelivery, SubscriptionDeliveriesTable, Subscription, SubgraphsTable, SubgraphUsageDailyTable, SubgraphUsageDaily, SubgraphTableSnapshotsTable, SubgraphProcessingStatsTable, SubgraphOperationsTable, SubgraphOperationStatus, SubgraphOperationKind, SubgraphOperation, SubgraphHealthSnapshotsTable, SubgraphHealthSnapshot, SubgraphGapsTable, SubgraphGap, Subgraph, SessionsTable, Session, ServiceHeartbeatsTable, SbtcTokenEventsTable, SbtcTokenEventType, SbtcSupplySnapshotsTable, SbtcEventsTable, SbtcEventTopic, SOURCE_READ_COLUMNS, ProvisioningAuditStatus, ProvisioningAuditLogTable, ProvisioningAuditLog, ProvisioningAuditEvent, ProjectsTable, Project, ProcessedStripeEventsTable, Pox4SignersDailyTable, Pox4FunctionName, Pox4CyclesDailyTable, Pox4CallsTable, OutboxStatus, NumericAsText, MempoolTransactionsTable, MempoolTransaction, MagicLinksTable, MagicLink, L2DecoderCheckpointsTable, InsertTransaction, InsertTenantUsageMonthly, InsertTenantComputeAddon, InsertTenant, InsertTeamMember, InsertTeamInvitation, InsertSubscriptionOutbox, InsertSubscriptionDelivery, InsertSubscription, InsertSubgraphUsageDaily, InsertSubgraphOperation, InsertSubgraphHealthSnapshot, InsertSubgraphGap, InsertSubgraph, InsertSession, InsertProvisioningAuditLog, InsertProject, InsertMempoolTransaction, InsertMagicLink, InsertIndexProgress, InsertEvent, InsertContract, InsertChatSession, InsertChatMessage, InsertBlock, InsertApiKey, InsertAccountSpendCap, InsertAccountInsight, InsertAccountAgentRun, InsertAccount, IndexProgressTable, IndexProgress, EventsTable, EventsArchiveTable, Event, DecodedEventsTable, DeadLetterEventsTable, DbSplitStatus, DbReadRow, Database, ContractsTable, Contract, ChatSessionsTable, ChatSession, ChatMessagesTable, ChatMessage, ChainReorgsTable, BurnBlockRewardsTable, BurnBlockRewardSlotsTable, BnsNamespacesTable, BnsNamespaceEventsTable, BnsNamespaceEventStatus, BnsNamesTable, BnsNameEventsTable, BnsNameEventTopic, BnsMarketplaceEventsTable, BnsMarketplaceAction, BlocksTable, Block, ApiKeysTable, ApiKey, AccountsTable, AccountSpendCapsTable, AccountSpendCap, AccountInsightsTable, AccountInsight, AccountAgentRunsTable, AccountAgentRun, Account };
|
|
1125
|
+
export { sql, setMigrationRole, parseJsonb, onControlPlane, onChainPlane, jsonb, getTargetDb, getSourceDb, getRawClientFor, getRawClient, getMigrationRole, getDbSplitStatus, getDb, closeDb, assertDbSplit, UsageSnapshotsTable, UsageSnapshot, UsageDailyTable, UsageDaily, UpdateTransaction, UpdateTenantUsageMonthly, UpdateTenantComputeAddon, UpdateTenant, UpdateSubscriptionOutbox, UpdateSubscription, UpdateSubgraphOperation, UpdateSubgraph, UpdateProject, UpdateIndexProgress, UpdateEvent, UpdateContract, UpdateChatSession, UpdateBlock, UpdateApiKey, UpdateAccountSpendCap, TriggerEvaluatorStateTable, TriggerEvaluatorState, TransactionsTable, TransactionsArchiveTable, Transaction, TenantsTable, TenantUsageMonthlyTable, TenantUsageMonthly, TenantStatus, TenantComputeAddonsTable, TenantComputeAddon, Tenant, TeamMembersTable, TeamMember, TeamInvitationsTable, TeamInvitation, TABLE_TO_DB, SubscriptionsTable, SubscriptionStatus, SubscriptionRuntime, SubscriptionOutboxTable, SubscriptionOutbox, SubscriptionKind, SubscriptionFormat, SubscriptionDelivery, SubscriptionDeliveriesTable, Subscription, SubgraphsTable, SubgraphUsageDailyTable, SubgraphUsageDaily, SubgraphTableSnapshotsTable, SubgraphProcessingStatsTable, SubgraphOperationsTable, SubgraphOperationStatus, SubgraphOperationKind, SubgraphOperation, SubgraphHealthSnapshotsTable, SubgraphHealthSnapshot, SubgraphGapsTable, SubgraphGap, Subgraph, SessionsTable, Session, ServiceHeartbeatsTable, SbtcTokenEventsTable, SbtcTokenEventType, SbtcSupplySnapshotsTable, SbtcEventsTable, SbtcEventTopic, SOURCE_READ_COLUMNS, ProvisioningAuditStatus, ProvisioningAuditLogTable, ProvisioningAuditLog, ProvisioningAuditEvent, ProjectsTable, Project, ProcessedStripeEventsTable, Pox4SignersDailyTable, Pox4FunctionName, Pox4CyclesDailyTable, Pox4CallsTable, OutboxStatus, NumericAsText, MigrationRole, MempoolTransactionsTable, MempoolTransaction, MagicLinksTable, MagicLink, L2DecoderCheckpointsTable, InsertTransaction, InsertTenantUsageMonthly, InsertTenantComputeAddon, InsertTenant, InsertTeamMember, InsertTeamInvitation, InsertSubscriptionOutbox, InsertSubscriptionDelivery, InsertSubscription, InsertSubgraphUsageDaily, InsertSubgraphOperation, InsertSubgraphHealthSnapshot, InsertSubgraphGap, InsertSubgraph, InsertSession, InsertProvisioningAuditLog, InsertProject, InsertMempoolTransaction, InsertMagicLink, InsertIndexProgress, InsertEvent, InsertContract, InsertChatSession, InsertChatMessage, InsertBlock, InsertApiKey, InsertAccountSpendCap, InsertAccountInsight, InsertAccountAgentRun, InsertAccount, IndexProgressTable, IndexProgress, EventsTable, EventsArchiveTable, Event, DecodedEventsTable, DeadLetterEventsTable, DbSplitStatus, DbReadRow, DbPlane, Database, ContractsTable, Contract, ChatSessionsTable, ChatSession, ChatMessagesTable, ChatMessage, ChainReorgsTable, BurnBlockRewardsTable, BurnBlockRewardSlotsTable, BnsNamespacesTable, BnsNamespaceEventsTable, BnsNamespaceEventStatus, BnsNamesTable, BnsNameEventsTable, BnsNameEventTopic, BnsMarketplaceEventsTable, BnsMarketplaceAction, BlocksTable, Block, ApiKeysTable, ApiKey, AccountsTable, AccountSpendCapsTable, AccountSpendCap, AccountInsightsTable, AccountInsight, AccountAgentRunsTable, AccountAgentRun, Account };
|
package/dist/src/db/index.js
CHANGED
|
@@ -378,6 +378,81 @@ var SOURCE_READ_COLUMNS = {
|
|
|
378
378
|
events: ["block_height", "data", "event_index", "tx_id", "type"],
|
|
379
379
|
chain_reorgs: ["detected_at"]
|
|
380
380
|
};
|
|
381
|
+
// src/db/migration-role.ts
|
|
382
|
+
var currentRole = "both";
|
|
383
|
+
function setMigrationRole(role) {
|
|
384
|
+
currentRole = role;
|
|
385
|
+
}
|
|
386
|
+
function getMigrationRole() {
|
|
387
|
+
return currentRole;
|
|
388
|
+
}
|
|
389
|
+
async function onControlPlane(fn) {
|
|
390
|
+
if (currentRole === "target" || currentRole === "both")
|
|
391
|
+
await fn();
|
|
392
|
+
}
|
|
393
|
+
async function onChainPlane(fn) {
|
|
394
|
+
if (currentRole === "source" || currentRole === "both")
|
|
395
|
+
await fn();
|
|
396
|
+
}
|
|
397
|
+
// src/db/table-plane.ts
|
|
398
|
+
var TABLE_TO_DB = {
|
|
399
|
+
blocks: "source",
|
|
400
|
+
transactions: "source",
|
|
401
|
+
events: "source",
|
|
402
|
+
transactions_archive: "source",
|
|
403
|
+
events_archive: "source",
|
|
404
|
+
dead_letter_events: "source",
|
|
405
|
+
mempool_transactions: "source",
|
|
406
|
+
index_progress: "source",
|
|
407
|
+
contracts: "source",
|
|
408
|
+
chain_reorgs: "source",
|
|
409
|
+
decoded_events: "source",
|
|
410
|
+
l2_decoder_checkpoints: "source",
|
|
411
|
+
pox4_calls: "source",
|
|
412
|
+
pox4_cycles_daily: "source",
|
|
413
|
+
pox4_signers_daily: "source",
|
|
414
|
+
burn_block_rewards: "source",
|
|
415
|
+
burn_block_reward_slots: "source",
|
|
416
|
+
sbtc_events: "source",
|
|
417
|
+
sbtc_token_events: "source",
|
|
418
|
+
sbtc_supply_snapshots: "source",
|
|
419
|
+
bns_name_events: "source",
|
|
420
|
+
bns_namespace_events: "source",
|
|
421
|
+
bns_marketplace_events: "source",
|
|
422
|
+
bns_names: "source",
|
|
423
|
+
bns_namespaces: "source",
|
|
424
|
+
accounts: "target",
|
|
425
|
+
api_keys: "target",
|
|
426
|
+
sessions: "target",
|
|
427
|
+
magic_links: "target",
|
|
428
|
+
usage_daily: "target",
|
|
429
|
+
usage_snapshots: "target",
|
|
430
|
+
account_insights: "target",
|
|
431
|
+
account_agent_runs: "target",
|
|
432
|
+
account_spend_caps: "target",
|
|
433
|
+
processed_stripe_events: "target",
|
|
434
|
+
tenants: "target",
|
|
435
|
+
tenant_usage_monthly: "target",
|
|
436
|
+
tenant_compute_addons: "target",
|
|
437
|
+
provisioning_audit_log: "target",
|
|
438
|
+
projects: "target",
|
|
439
|
+
team_members: "target",
|
|
440
|
+
team_invitations: "target",
|
|
441
|
+
chat_sessions: "target",
|
|
442
|
+
chat_messages: "target",
|
|
443
|
+
subscriptions: "target",
|
|
444
|
+
subscription_outbox: "target",
|
|
445
|
+
subscription_deliveries: "target",
|
|
446
|
+
trigger_evaluator_state: "target",
|
|
447
|
+
subgraphs: "target",
|
|
448
|
+
subgraph_operations: "target",
|
|
449
|
+
subgraph_health_snapshots: "target",
|
|
450
|
+
subgraph_gaps: "target",
|
|
451
|
+
subgraph_usage_daily: "target",
|
|
452
|
+
subgraph_processing_stats: "target",
|
|
453
|
+
subgraph_table_snapshots: "target",
|
|
454
|
+
service_heartbeats: "both"
|
|
455
|
+
};
|
|
381
456
|
|
|
382
457
|
// src/db/index.ts
|
|
383
458
|
var DEFAULT_URL = "postgres://postgres:postgres@localhost:5432/secondlayer_dev";
|
|
@@ -537,18 +612,23 @@ async function closeDb() {
|
|
|
537
612
|
}
|
|
538
613
|
export {
|
|
539
614
|
sql2 as sql,
|
|
615
|
+
setMigrationRole,
|
|
540
616
|
parseJsonb,
|
|
617
|
+
onControlPlane,
|
|
618
|
+
onChainPlane,
|
|
541
619
|
jsonb,
|
|
542
620
|
getTargetDb,
|
|
543
621
|
getSourceDb,
|
|
544
622
|
getRawClientFor,
|
|
545
623
|
getRawClient,
|
|
624
|
+
getMigrationRole,
|
|
546
625
|
getDbSplitStatus,
|
|
547
626
|
getDb,
|
|
548
627
|
closeDb,
|
|
549
628
|
assertDbSplit,
|
|
629
|
+
TABLE_TO_DB,
|
|
550
630
|
SOURCE_READ_COLUMNS
|
|
551
631
|
};
|
|
552
632
|
|
|
553
|
-
//# debugId=
|
|
633
|
+
//# debugId=9BD00555AB68090864756E2164756E21
|
|
554
634
|
//# sourceMappingURL=index.js.map
|