@secondlayer/shared 13.0.0 → 13.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/archive/range-digest.d.ts +1 -1
- package/dist/src/archive/semantic-digest-builder.d.ts +1 -1
- package/dist/src/chain-read.d.ts +13 -0
- package/dist/src/chain-read.js +12 -0
- package/dist/src/chain-read.js.map +10 -0
- package/dist/src/coverage/index.d.ts +1 -1
- package/dist/src/db/index.d.ts +1 -1
- package/dist/src/db/queries/chain-reorgs.d.ts +1 -1
- package/dist/src/db/queries/contracts.d.ts +3 -1
- package/dist/src/db/queries/contracts.js +4 -1
- package/dist/src/db/queries/contracts.js.map +3 -3
- package/dist/src/db/queries/instance.d.ts +13 -2
- package/dist/src/db/queries/instance.js +16 -1
- package/dist/src/db/queries/instance.js.map +3 -3
- package/dist/src/db/queries/integrity.d.ts +1 -1
- package/dist/src/db/queries/subgraph-gaps.d.ts +1 -1
- package/dist/src/db/queries/subgraph-operations.d.ts +1 -1
- package/dist/src/db/queries/subgraphs.d.ts +1 -1
- package/dist/src/db/queries/sync-scope.d.ts +1 -1
- package/dist/src/db/queries/webhooks.d.ts +1 -1
- package/dist/src/db/schema.d.ts +1 -1
- package/dist/src/index-http.d.ts +76 -1
- package/dist/src/index-http.js +38 -1
- package/dist/src/index-http.js.map +3 -3
- package/dist/src/index.d.ts +3 -1
- package/dist/src/index.js +8 -2
- package/dist/src/index.js.map +3 -3
- package/dist/src/node/local-client.d.ts +1 -1
- package/dist/src/schemas/index.d.ts +2 -0
- package/dist/src/schemas/index.js +8 -2
- package/dist/src/schemas/index.js.map +3 -3
- package/dist/src/schemas/webhooks.d.ts +4 -1
- package/dist/src/schemas/webhooks.js +9 -2
- package/dist/src/schemas/webhooks.js.map +3 -3
- package/migrations/0165_api_keys_tenant_product.ts +49 -0
- package/package.json +6 -2
|
@@ -284,7 +284,7 @@ interface ApiKeysTable {
|
|
|
284
284
|
rate_limit: Generated<number>;
|
|
285
285
|
ip_address: string;
|
|
286
286
|
account_id: string;
|
|
287
|
-
product: Generated<"account" | "streams" | "index" | "sentinel" | "docs">;
|
|
287
|
+
product: Generated<"account" | "streams" | "index" | "sentinel" | "docs" | "tenant">;
|
|
288
288
|
/** Sentinel permission areas; set only on `product = 'sentinel'` keys. */
|
|
289
289
|
areas: unknown | null;
|
|
290
290
|
tier: "free" | "build" | "scale" | "enterprise" | "internal" | null;
|
|
@@ -284,7 +284,7 @@ interface ApiKeysTable {
|
|
|
284
284
|
rate_limit: Generated<number>;
|
|
285
285
|
ip_address: string;
|
|
286
286
|
account_id: string;
|
|
287
|
-
product: Generated<"account" | "streams" | "index" | "sentinel" | "docs">;
|
|
287
|
+
product: Generated<"account" | "streams" | "index" | "sentinel" | "docs" | "tenant">;
|
|
288
288
|
/** Sentinel permission areas; set only on `product = 'sentinel'` keys. */
|
|
289
289
|
areas: unknown | null;
|
|
290
290
|
tier: "free" | "build" | "scale" | "enterprise" | "internal" | null;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cache key for a contract read's arguments: SHA-256 over the hex-serialized
|
|
3
|
+
* Clarity args (no `0x`, lowercase), joined by `,`.
|
|
4
|
+
*
|
|
5
|
+
* One function for both sides of a hosted read: the subgraph runtime hashes
|
|
6
|
+
* the values it serialized, the hosted chain-read route hashes the hex it
|
|
7
|
+
* received, and both land on the same `chain_read_cache.args_hash`. A
|
|
8
|
+
* collision-resistant hash, because the hosted cache is shared across
|
|
9
|
+
* tenants: with a weak hash, one tenant could craft args that collide with
|
|
10
|
+
* another's read and pin a wrong answer to it.
|
|
11
|
+
*/
|
|
12
|
+
declare function chainReadArgsHash(hexArgs: readonly string[]): string;
|
|
13
|
+
export { chainReadArgsHash };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// src/chain-read.ts
|
|
2
|
+
import { createHash } from "node:crypto";
|
|
3
|
+
function chainReadArgsHash(hexArgs) {
|
|
4
|
+
const normalized = hexArgs.map((arg) => arg.replace(/^0x/i, "").toLowerCase()).join(",");
|
|
5
|
+
return createHash("sha256").update(normalized).digest("hex");
|
|
6
|
+
}
|
|
7
|
+
export {
|
|
8
|
+
chainReadArgsHash
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
//# debugId=578F03C6DABB150A64756E2164756E21
|
|
12
|
+
//# sourceMappingURL=chain-read.js.map
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/chain-read.ts"],
|
|
4
|
+
"sourcesContent": [
|
|
5
|
+
"import { createHash } from \"node:crypto\";\n\n/**\n * Cache key for a contract read's arguments: SHA-256 over the hex-serialized\n * Clarity args (no `0x`, lowercase), joined by `,`.\n *\n * One function for both sides of a hosted read: the subgraph runtime hashes\n * the values it serialized, the hosted chain-read route hashes the hex it\n * received, and both land on the same `chain_read_cache.args_hash`. A\n * collision-resistant hash, because the hosted cache is shared across\n * tenants: with a weak hash, one tenant could craft args that collide with\n * another's read and pin a wrong answer to it.\n */\nexport function chainReadArgsHash(hexArgs: readonly string[]): string {\n\tconst normalized = hexArgs\n\t\t.map((arg) => arg.replace(/^0x/i, \"\").toLowerCase())\n\t\t.join(\",\");\n\treturn createHash(\"sha256\").update(normalized).digest(\"hex\");\n}\n"
|
|
6
|
+
],
|
|
7
|
+
"mappings": ";AAAA;AAaO,SAAS,iBAAiB,CAAC,SAAoC;AAAA,EACrE,MAAM,aAAa,QACjB,IAAI,CAAC,QAAQ,IAAI,QAAQ,QAAQ,EAAE,EAAE,YAAY,CAAC,EAClD,KAAK,GAAG;AAAA,EACV,OAAO,WAAW,QAAQ,EAAE,OAAO,UAAU,EAAE,OAAO,KAAK;AAAA;",
|
|
8
|
+
"debugId": "578F03C6DABB150A64756E2164756E21",
|
|
9
|
+
"names": []
|
|
10
|
+
}
|
|
@@ -601,7 +601,7 @@ interface ApiKeysTable {
|
|
|
601
601
|
rate_limit: Generated<number>;
|
|
602
602
|
ip_address: string;
|
|
603
603
|
account_id: string;
|
|
604
|
-
product: Generated<"account" | "streams" | "index" | "sentinel" | "docs">;
|
|
604
|
+
product: Generated<"account" | "streams" | "index" | "sentinel" | "docs" | "tenant">;
|
|
605
605
|
/** Sentinel permission areas; set only on `product = 'sentinel'` keys. */
|
|
606
606
|
areas: unknown | null;
|
|
607
607
|
tier: "free" | "build" | "scale" | "enterprise" | "internal" | null;
|
package/dist/src/db/index.d.ts
CHANGED
|
@@ -285,7 +285,7 @@ interface ApiKeysTable {
|
|
|
285
285
|
rate_limit: Generated<number>;
|
|
286
286
|
ip_address: string;
|
|
287
287
|
account_id: string;
|
|
288
|
-
product: Generated<"account" | "streams" | "index" | "sentinel" | "docs">;
|
|
288
|
+
product: Generated<"account" | "streams" | "index" | "sentinel" | "docs" | "tenant">;
|
|
289
289
|
/** Sentinel permission areas; set only on `product = 'sentinel'` keys. */
|
|
290
290
|
areas: unknown | null;
|
|
291
291
|
tier: "free" | "build" | "scale" | "enterprise" | "internal" | null;
|
|
@@ -284,7 +284,7 @@ interface ApiKeysTable {
|
|
|
284
284
|
rate_limit: Generated<number>;
|
|
285
285
|
ip_address: string;
|
|
286
286
|
account_id: string;
|
|
287
|
-
product: Generated<"account" | "streams" | "index" | "sentinel" | "docs">;
|
|
287
|
+
product: Generated<"account" | "streams" | "index" | "sentinel" | "docs" | "tenant">;
|
|
288
288
|
/** Sentinel permission areas; set only on `product = 'sentinel'` keys. */
|
|
289
289
|
areas: unknown | null;
|
|
290
290
|
tier: "free" | "build" | "scale" | "enterprise" | "internal" | null;
|
|
@@ -284,7 +284,7 @@ interface ApiKeysTable {
|
|
|
284
284
|
rate_limit: Generated<number>;
|
|
285
285
|
ip_address: string;
|
|
286
286
|
account_id: string;
|
|
287
|
-
product: Generated<"account" | "streams" | "index" | "sentinel" | "docs">;
|
|
287
|
+
product: Generated<"account" | "streams" | "index" | "sentinel" | "docs" | "tenant">;
|
|
288
288
|
/** Sentinel permission areas; set only on `product = 'sentinel'` keys. */
|
|
289
289
|
areas: unknown | null;
|
|
290
290
|
tier: "free" | "build" | "scale" | "enterprise" | "internal" | null;
|
|
@@ -1172,6 +1172,8 @@ declare function listContractsByTrait(db: Kysely<Database>, trait: string, opts?
|
|
|
1172
1172
|
conformance?: Conformance
|
|
1173
1173
|
limit?: number
|
|
1174
1174
|
afterId?: string
|
|
1175
|
+
/** Only contracts classified (ABI stored) at or after this time. */
|
|
1176
|
+
classifiedAfter?: Date
|
|
1175
1177
|
}): Promise<Contract[]>;
|
|
1176
1178
|
/**
|
|
1177
1179
|
* As-of-block trait resolution (B4): contract IDs conforming to `trait` whose
|
|
@@ -57,6 +57,9 @@ async function listContractsByTrait(db, trait, opts = {}) {
|
|
|
57
57
|
}
|
|
58
58
|
if (opts.afterId)
|
|
59
59
|
q = q.where("contract_id", ">", opts.afterId);
|
|
60
|
+
if (opts.classifiedAfter) {
|
|
61
|
+
q = q.where("abi_fetched_at", ">=", opts.classifiedAfter);
|
|
62
|
+
}
|
|
60
63
|
return q.orderBy("contract_id", "asc").limit(opts.limit ?? 100).execute();
|
|
61
64
|
}
|
|
62
65
|
async function resolveTraitContractIds(db, trait, asOfBlock) {
|
|
@@ -76,5 +79,5 @@ export {
|
|
|
76
79
|
setContractAbi
|
|
77
80
|
};
|
|
78
81
|
|
|
79
|
-
//# debugId=
|
|
82
|
+
//# debugId=41DCA798C00E09D764756E2164756E21
|
|
80
83
|
//# sourceMappingURL=contracts.js.map
|
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/db/queries/contracts.ts", "../src/db/jsonb.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
5
|
-
"import { type Kysely, sql } from \"kysely\";\nimport { jsonb } from \"../jsonb.ts\";\nimport type { Contract, Database } from \"../types.ts\";\n\n/**\n * Contract registry queries — backing for trait-based discovery. Populated from\n * contract deploys; ABI fetched async; standards inferred by static analysis.\n */\n\nexport type AbiStatus = \"pending\" | \"fetched\" | \"failed\" | \"unparseable\";\n\n/**\n * Record a contract deploy (idempotent). ABI is fetched separately + async.\n * On conflict the row is re-canonicalized rather than skipped: after a reorg\n * flips contracts non-canonical (markContractsNonCanonical), discovery\n * re-selects any id whose deploy tx exists on the new fork and this upsert\n * restores `canonical` with the fork's height. ABI fields are untouched, so a\n * previously fetched ABI survives the round trip.\n */\nexport async function recordContractDeploy(\n\tdb: Kysely<Database>,\n\trow: { contractId: string; deployer: string; blockHeight: number },\n): Promise<void> {\n\tawait db\n\t\t.insertInto(\"contracts\")\n\t\t.values({\n\t\t\tcontract_id: row.contractId,\n\t\t\tdeployer: row.deployer,\n\t\t\tblock_height: row.blockHeight,\n\t\t})\n\t\t.onConflict((oc) =>\n\t\t\toc.column(\"contract_id\").doUpdateSet({\n\t\t\t\tdeployer: row.deployer,\n\t\t\t\tblock_height: row.blockHeight,\n\t\t\t\tcanonical: true,\n\t\t\t}),\n\t\t)\n\t\t.execute();\n}\n\n/** Store a fetched ABI + the traits/standards derived from it. */\nexport async function setContractAbi(\n\tdb: Kysely<Database>,\n\tcontractId: string,\n\tdata: {\n\t\tabi: unknown | null;\n\t\tstatus: AbiStatus;\n\t\tdeclaredTraits?: string[];\n\t\tinferredStandards?: string[];\n\t},\n): Promise<void> {\n\tawait db\n\t\t.updateTable(\"contracts\")\n\t\t.set({\n\t\t\tabi: data.abi == null ? null : jsonb(data.abi),\n\t\t\tabi_status: data.status,\n\t\t\tabi_fetched_at: new Date(),\n\t\t\t...(data.declaredTraits ? { declared_traits: data.declaredTraits } : {}),\n\t\t\t...(data.inferredStandards\n\t\t\t\t? { inferred_standards: data.inferredStandards }\n\t\t\t\t: {}),\n\t\t})\n\t\t.where(\"contract_id\", \"=\", contractId)\n\t\t.execute();\n}\n\n/**\n * A contract reorged out and not (yet) redeployed on the new fork is not on\n * the canonical chain — serve 404, not its stale row/ABI. Matches every other\n * contracts read (list, trait scope, pending-ABI), which already filter.\n */\nexport async function getContract(\n\tdb: Kysely<Database>,\n\tcontractId: string,\n): Promise<Contract | null> {\n\treturn (\n\t\t(await db\n\t\t\t.selectFrom(\"contracts\")\n\t\t\t.selectAll()\n\t\t\t.where(\"contract_id\", \"=\", contractId)\n\t\t\t.where(\"canonical\", \"=\", true)\n\t\t\t.executeTakeFirst()) ?? null\n\t);\n}\n\n/** Contracts still awaiting an ABI fetch (drives the fetch/backfill worker). */\nexport async function listContractsPendingAbi(\n\tdb: Kysely<Database>,\n\tlimit = 100,\n): Promise<Contract[]> {\n\treturn db\n\t\t.selectFrom(\"contracts\")\n\t\t.selectAll()\n\t\t.where(\"abi_status\", \"=\", \"pending\")\n\t\t.where(\"canonical\", \"=\", true)\n\t\t.orderBy(\"block_height\", \"asc\")\n\t\t.limit(limit)\n\t\t.execute();\n}\n\nexport type Conformance = \"declared\" | \"inferred\" | \"any\";\n\n/** Discovery: contracts matching a trait/standard, by conformance source. */\nexport async function listContractsByTrait(\n\tdb: Kysely<Database>,\n\ttrait: string,\n\topts: {
|
|
5
|
+
"import { type Kysely, sql } from \"kysely\";\nimport { jsonb } from \"../jsonb.ts\";\nimport type { Contract, Database } from \"../types.ts\";\n\n/**\n * Contract registry queries — backing for trait-based discovery. Populated from\n * contract deploys; ABI fetched async; standards inferred by static analysis.\n */\n\nexport type AbiStatus = \"pending\" | \"fetched\" | \"failed\" | \"unparseable\";\n\n/**\n * Record a contract deploy (idempotent). ABI is fetched separately + async.\n * On conflict the row is re-canonicalized rather than skipped: after a reorg\n * flips contracts non-canonical (markContractsNonCanonical), discovery\n * re-selects any id whose deploy tx exists on the new fork and this upsert\n * restores `canonical` with the fork's height. ABI fields are untouched, so a\n * previously fetched ABI survives the round trip.\n */\nexport async function recordContractDeploy(\n\tdb: Kysely<Database>,\n\trow: { contractId: string; deployer: string; blockHeight: number },\n): Promise<void> {\n\tawait db\n\t\t.insertInto(\"contracts\")\n\t\t.values({\n\t\t\tcontract_id: row.contractId,\n\t\t\tdeployer: row.deployer,\n\t\t\tblock_height: row.blockHeight,\n\t\t})\n\t\t.onConflict((oc) =>\n\t\t\toc.column(\"contract_id\").doUpdateSet({\n\t\t\t\tdeployer: row.deployer,\n\t\t\t\tblock_height: row.blockHeight,\n\t\t\t\tcanonical: true,\n\t\t\t}),\n\t\t)\n\t\t.execute();\n}\n\n/** Store a fetched ABI + the traits/standards derived from it. */\nexport async function setContractAbi(\n\tdb: Kysely<Database>,\n\tcontractId: string,\n\tdata: {\n\t\tabi: unknown | null;\n\t\tstatus: AbiStatus;\n\t\tdeclaredTraits?: string[];\n\t\tinferredStandards?: string[];\n\t},\n): Promise<void> {\n\tawait db\n\t\t.updateTable(\"contracts\")\n\t\t.set({\n\t\t\tabi: data.abi == null ? null : jsonb(data.abi),\n\t\t\tabi_status: data.status,\n\t\t\tabi_fetched_at: new Date(),\n\t\t\t...(data.declaredTraits ? { declared_traits: data.declaredTraits } : {}),\n\t\t\t...(data.inferredStandards\n\t\t\t\t? { inferred_standards: data.inferredStandards }\n\t\t\t\t: {}),\n\t\t})\n\t\t.where(\"contract_id\", \"=\", contractId)\n\t\t.execute();\n}\n\n/**\n * A contract reorged out and not (yet) redeployed on the new fork is not on\n * the canonical chain — serve 404, not its stale row/ABI. Matches every other\n * contracts read (list, trait scope, pending-ABI), which already filter.\n */\nexport async function getContract(\n\tdb: Kysely<Database>,\n\tcontractId: string,\n): Promise<Contract | null> {\n\treturn (\n\t\t(await db\n\t\t\t.selectFrom(\"contracts\")\n\t\t\t.selectAll()\n\t\t\t.where(\"contract_id\", \"=\", contractId)\n\t\t\t.where(\"canonical\", \"=\", true)\n\t\t\t.executeTakeFirst()) ?? null\n\t);\n}\n\n/** Contracts still awaiting an ABI fetch (drives the fetch/backfill worker). */\nexport async function listContractsPendingAbi(\n\tdb: Kysely<Database>,\n\tlimit = 100,\n): Promise<Contract[]> {\n\treturn db\n\t\t.selectFrom(\"contracts\")\n\t\t.selectAll()\n\t\t.where(\"abi_status\", \"=\", \"pending\")\n\t\t.where(\"canonical\", \"=\", true)\n\t\t.orderBy(\"block_height\", \"asc\")\n\t\t.limit(limit)\n\t\t.execute();\n}\n\nexport type Conformance = \"declared\" | \"inferred\" | \"any\";\n\n/** Discovery: contracts matching a trait/standard, by conformance source. */\nexport async function listContractsByTrait(\n\tdb: Kysely<Database>,\n\ttrait: string,\n\topts: {\n\t\tconformance?: Conformance;\n\t\tlimit?: number;\n\t\tafterId?: string;\n\t\t/** Only contracts classified (ABI stored) at or after this time. */\n\t\tclassifiedAfter?: Date;\n\t} = {},\n): Promise<Contract[]> {\n\tconst conformance = opts.conformance ?? \"any\";\n\tlet q = db.selectFrom(\"contracts\").selectAll().where(\"canonical\", \"=\", true);\n\n\tif (conformance === \"declared\") {\n\t\tq = q.where(sql<boolean>`${sql.ref(\"declared_traits\")} @> ARRAY[${trait}]`);\n\t} else if (conformance === \"inferred\") {\n\t\tq = q.where(\n\t\t\tsql<boolean>`${sql.ref(\"inferred_standards\")} @> ARRAY[${trait}]`,\n\t\t);\n\t} else {\n\t\tq = q.where(\n\t\t\tsql<boolean>`(${sql.ref(\"declared_traits\")} @> ARRAY[${trait}] OR ${sql.ref(\"inferred_standards\")} @> ARRAY[${trait}])`,\n\t\t);\n\t}\n\n\tif (opts.afterId) q = q.where(\"contract_id\", \">\", opts.afterId);\n\tif (opts.classifiedAfter) {\n\t\tq = q.where(\"abi_fetched_at\", \">=\", opts.classifiedAfter);\n\t}\n\treturn q\n\t\t.orderBy(\"contract_id\", \"asc\")\n\t\t.limit(opts.limit ?? 100)\n\t\t.execute();\n}\n\n/**\n * As-of-block trait resolution (B4): contract IDs conforming to `trait` whose\n * deploy block ≤ `asOfBlock`. Lets a trait-scoped subgraph reindex a token's\n * full history even if classification lagged its deploy.\n */\nexport async function resolveTraitContractIds(\n\tdb: Kysely<Database>,\n\ttrait: string,\n\tasOfBlock: number,\n): Promise<string[]> {\n\tconst rows = await db\n\t\t.selectFrom(\"contracts\")\n\t\t.select(\"contract_id\")\n\t\t.where(\"canonical\", \"=\", true)\n\t\t.where(\"block_height\", \"<=\", asOfBlock)\n\t\t.where(\n\t\t\tsql<boolean>`(${sql.ref(\"declared_traits\")} @> ARRAY[${trait}] OR ${sql.ref(\"inferred_standards\")} @> ARRAY[${trait}])`,\n\t\t)\n\t\t.execute();\n\treturn rows.map((r) => r.contract_id);\n}\n\n/**\n * Reorg: flip contracts deployed at/above a reorged height to non-canonical.\n * Called from the indexer's handleReorg tx. Recovery is eventual: discovery\n * (discoverDeploys) re-selects non-canonical ids whose deploy tx exists on\n * the new fork and recordContractDeploy re-canonicalizes them.\n */\nexport async function markContractsNonCanonical(\n\tdb: Kysely<Database>,\n\tfromBlockHeight: number,\n): Promise<void> {\n\tawait db\n\t\t.updateTable(\"contracts\")\n\t\t.set({ canonical: false })\n\t\t.where(\"block_height\", \">=\", fromBlockHeight)\n\t\t.execute();\n}\n",
|
|
6
6
|
"import { type RawBuilder, sql } from \"kysely\";\n\n/**\n * Safely encode a JS value as a JSONB literal for Kysely inserts/updates.\n * Kysely + postgres.js double-encodes JSON when using parameterized queries\n * with ::jsonb casts. This uses sql.raw to inline a properly escaped literal.\n *\n * Generic parameter lets callers set the RawBuilder's output type so they\n * don't need to cast at the insert site. Default is `unknown` — widen at\n * the call site when the column type is narrower, e.g. `jsonb<MyShape>(...)`.\n */\nexport function jsonb<T = unknown>(value: T): RawBuilder<T> {\n\tconst escaped = JSON.stringify(value, (_k, v) =>\n\t\ttypeof v === \"bigint\" ? v.toString() : v,\n\t).replace(/'/g, \"''\");\n\treturn sql`${sql.raw(`'${escaped}'::jsonb`)}`;\n}\n\n/**\n * Safely parse a JSONB value from the database.\n * Handles double-encoded strings where postgres.js returns a JSON string\n * instead of a parsed object.\n */\nexport function parseJsonb<T = unknown>(value: unknown): T {\n\tif (typeof value === \"string\") {\n\t\ttry {\n\t\t\treturn JSON.parse(value) as T;\n\t\t} catch {\n\t\t\treturn value as T;\n\t\t}\n\t}\n\treturn (value ?? {}) as T;\n}\n"
|
|
7
7
|
],
|
|
8
|
-
"mappings": ";AAAA,gBAAsB;;;ACAtB;AAWO,SAAS,KAAkB,CAAC,OAAyB;AAAA,EAC3D,MAAM,UAAU,KAAK,UAAU,OAAO,CAAC,IAAI,MAC1C,OAAO,MAAM,WAAW,EAAE,SAAS,IAAI,CACxC,EAAE,QAAQ,MAAM,IAAI;AAAA,EACpB,OAAO,MAAM,IAAI,IAAI,IAAI,iBAAiB;AAAA;AAQpC,SAAS,UAAuB,CAAC,OAAmB;AAAA,EAC1D,IAAI,OAAO,UAAU,UAAU;AAAA,IAC9B,IAAI;AAAA,MACH,OAAO,KAAK,MAAM,KAAK;AAAA,MACtB,MAAM;AAAA,MACP,OAAO;AAAA;AAAA,EAET;AAAA,EACA,OAAQ,SAAS,CAAC;AAAA;;;ADZnB,eAAsB,oBAAoB,CACzC,IACA,KACgB;AAAA,EAChB,MAAM,GACJ,WAAW,WAAW,EACtB,OAAO;AAAA,IACP,aAAa,IAAI;AAAA,IACjB,UAAU,IAAI;AAAA,IACd,cAAc,IAAI;AAAA,EACnB,CAAC,EACA,WAAW,CAAC,OACZ,GAAG,OAAO,aAAa,EAAE,YAAY;AAAA,IACpC,UAAU,IAAI;AAAA,IACd,cAAc,IAAI;AAAA,IAClB,WAAW;AAAA,EACZ,CAAC,CACF,EACC,QAAQ;AAAA;AAIX,eAAsB,cAAc,CACnC,IACA,YACA,MAMgB;AAAA,EAChB,MAAM,GACJ,YAAY,WAAW,EACvB,IAAI;AAAA,IACJ,KAAK,KAAK,OAAO,OAAO,OAAO,MAAM,KAAK,GAAG;AAAA,IAC7C,YAAY,KAAK;AAAA,IACjB,gBAAgB,IAAI;AAAA,OAChB,KAAK,iBAAiB,EAAE,iBAAiB,KAAK,eAAe,IAAI,CAAC;AAAA,OAClE,KAAK,oBACN,EAAE,oBAAoB,KAAK,kBAAkB,IAC7C,CAAC;AAAA,EACL,CAAC,EACA,MAAM,eAAe,KAAK,UAAU,EACpC,QAAQ;AAAA;AAQX,eAAsB,WAAW,CAChC,IACA,YAC2B;AAAA,EAC3B,OACE,MAAM,GACL,WAAW,WAAW,EACtB,UAAU,EACV,MAAM,eAAe,KAAK,UAAU,EACpC,MAAM,aAAa,KAAK,IAAI,EAC5B,iBAAiB,KAAM;AAAA;AAK3B,eAAsB,uBAAuB,CAC5C,IACA,QAAQ,KACc;AAAA,EACtB,OAAO,GACL,WAAW,WAAW,EACtB,UAAU,EACV,MAAM,cAAc,KAAK,SAAS,EAClC,MAAM,aAAa,KAAK,IAAI,EAC5B,QAAQ,gBAAgB,KAAK,EAC7B,MAAM,KAAK,EACX,QAAQ;AAAA;AAMX,eAAsB,oBAAoB,CACzC,IACA,OACA,
|
|
9
|
-
"debugId": "
|
|
8
|
+
"mappings": "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",
|
|
9
|
+
"debugId": "41DCA798C00E09D764756E2164756E21",
|
|
10
10
|
"names": []
|
|
11
11
|
}
|
|
@@ -284,7 +284,7 @@ interface ApiKeysTable {
|
|
|
284
284
|
rate_limit: Generated<number>;
|
|
285
285
|
ip_address: string;
|
|
286
286
|
account_id: string;
|
|
287
|
-
product: Generated<"account" | "streams" | "index" | "sentinel" | "docs">;
|
|
287
|
+
product: Generated<"account" | "streams" | "index" | "sentinel" | "docs" | "tenant">;
|
|
288
288
|
/** Sentinel permission areas; set only on `product = 'sentinel'` keys. */
|
|
289
289
|
areas: unknown | null;
|
|
290
290
|
tier: "free" | "build" | "scale" | "enterprise" | "internal" | null;
|
|
@@ -1162,4 +1162,15 @@ declare function getInstance(db: Kysely<Database>): Promise<InstanceRow | null>;
|
|
|
1162
1162
|
declare function ensureInstance(db: Kysely<Database>, input: {
|
|
1163
1163
|
network: InstanceNetwork
|
|
1164
1164
|
}): Promise<InstanceRow>;
|
|
1165
|
-
|
|
1165
|
+
/**
|
|
1166
|
+
* A stack with no local chain: it reads chain data from a hosted Index/Streams
|
|
1167
|
+
* API (`SUBGRAPH_INDEX_API_URL` set) and its own `index_progress` has no row
|
|
1168
|
+
* for this network (a hosted tenant). Derived, not configured: a self-hoster
|
|
1169
|
+
* running a local indexer has the row and keeps reading its own tables, even
|
|
1170
|
+
* with its processors pointed at its own api over HTTP.
|
|
1171
|
+
*/
|
|
1172
|
+
declare function hasNoLocalChain(db: Kysely<Database>, opts?: {
|
|
1173
|
+
env?: NodeJS.ProcessEnv
|
|
1174
|
+
hasProgressRow?: (network: string) => Promise<boolean>
|
|
1175
|
+
}): Promise<boolean>;
|
|
1176
|
+
export { INSTANCE_NETWORKS, InstanceNetwork, InstanceNetworkMismatchError, InstanceRow, InvalidInstanceNetworkError, ensureInstance, getInstance, hasNoLocalChain, instanceNetworkFromEnv, parseInstanceNetwork };
|
|
@@ -62,15 +62,30 @@ function toInstance(row) {
|
|
|
62
62
|
created_at: row.created_at
|
|
63
63
|
};
|
|
64
64
|
}
|
|
65
|
+
async function hasNoLocalChain(db, opts = {}) {
|
|
66
|
+
const env = opts.env ?? process.env;
|
|
67
|
+
if (!env.SUBGRAPH_INDEX_API_URL)
|
|
68
|
+
return false;
|
|
69
|
+
const network = env.NETWORK ?? "mainnet";
|
|
70
|
+
const hasRow = opts.hasProgressRow ?? ((n) => hasLocalProgressRow(db, n));
|
|
71
|
+
return !await hasRow(network);
|
|
72
|
+
}
|
|
73
|
+
async function hasLocalProgressRow(db, network) {
|
|
74
|
+
const row = await db.selectFrom("index_progress").select("network").where("network", "=", network).executeTakeFirst().catch(() => {
|
|
75
|
+
return;
|
|
76
|
+
});
|
|
77
|
+
return row !== undefined;
|
|
78
|
+
}
|
|
65
79
|
export {
|
|
66
80
|
INSTANCE_NETWORKS,
|
|
67
81
|
InstanceNetworkMismatchError,
|
|
68
82
|
InvalidInstanceNetworkError,
|
|
69
83
|
ensureInstance,
|
|
70
84
|
getInstance,
|
|
85
|
+
hasNoLocalChain,
|
|
71
86
|
instanceNetworkFromEnv,
|
|
72
87
|
parseInstanceNetwork
|
|
73
88
|
};
|
|
74
89
|
|
|
75
|
-
//# debugId=
|
|
90
|
+
//# debugId=CD5DDEF4E82D8D8764756E2164756E21
|
|
76
91
|
//# sourceMappingURL=instance.js.map
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/db/queries/instance.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
5
|
-
"import type { Kysely } from \"kysely\";\nimport type { Database } from \"../types.ts\";\n\nexport const INSTANCE_NETWORKS = [\"mainnet\", \"testnet\", \"devnet\"] as const;\nexport type InstanceNetwork = (typeof INSTANCE_NETWORKS)[number];\n\nexport type InstanceRow = {\n\tid: string;\n\tnetwork: InstanceNetwork;\n\tcreated_at: Date;\n};\n\nexport class InstanceNetworkMismatchError extends Error {\n\treadonly name = \"InstanceNetworkMismatchError\";\n\tconstructor(\n\t\treadonly existing: InstanceNetwork,\n\t\treadonly requested: InstanceNetwork,\n\t) {\n\t\tsuper(`instance network is ${existing}; cannot change to ${requested}`);\n\t}\n}\n\nexport class InvalidInstanceNetworkError extends Error {\n\treadonly name = \"InvalidInstanceNetworkError\";\n\tconstructor(readonly value: string) {\n\t\tsuper(\n\t\t\t`instance network must be mainnet, testnet, or devnet (got ${value})`,\n\t\t);\n\t}\n}\n\nexport function parseInstanceNetwork(value: string): InstanceNetwork {\n\tconst network = value.trim().toLowerCase();\n\tif ((INSTANCE_NETWORKS as readonly string[]).includes(network)) {\n\t\treturn network as InstanceNetwork;\n\t}\n\tthrow new InvalidInstanceNetworkError(value);\n}\n\n/** STACKS_NETWORK, then NETWORK, then mainnet. */\nexport function instanceNetworkFromEnv(\n\tenv: NodeJS.ProcessEnv = process.env,\n): InstanceNetwork {\n\treturn parseInstanceNetwork(env.STACKS_NETWORK ?? env.NETWORK ?? \"mainnet\");\n}\n\nexport async function getInstance(\n\tdb: Kysely<Database>,\n): Promise<InstanceRow | null> {\n\tconst row = await db\n\t\t.selectFrom(\"instances\")\n\t\t.select([\"id\", \"network\", \"created_at\"])\n\t\t.executeTakeFirst();\n\treturn row ? toInstance(row) : null;\n}\n\n/**\n * Return the singleton instance, creating it on first call.\n * A second call with a different network is refused — the network is\n * immutable for the life of the database.\n */\nexport async function ensureInstance(\n\tdb: Kysely<Database>,\n\tinput: { network: InstanceNetwork },\n): Promise<InstanceRow> {\n\tconst existing = await getInstance(db);\n\tif (existing) {\n\t\tif (existing.network !== input.network) {\n\t\t\tthrow new InstanceNetworkMismatchError(existing.network, input.network);\n\t\t}\n\t\treturn existing;\n\t}\n\ttry {\n\t\tconst inserted = await db\n\t\t\t.insertInto(\"instances\")\n\t\t\t.values({ network: input.network })\n\t\t\t.returning([\"id\", \"network\", \"created_at\"])\n\t\t\t.executeTakeFirstOrThrow();\n\t\treturn toInstance(inserted);\n\t} catch {\n\t\t// Lost the singleton race — the other writer won.\n\t\tconst raced = await getInstance(db);\n\t\tif (!raced) throw new Error(\"failed to create instance\");\n\t\tif (raced.network !== input.network) {\n\t\t\tthrow new InstanceNetworkMismatchError(raced.network, input.network);\n\t\t}\n\t\treturn raced;\n\t}\n}\n\nfunction toInstance(row: {\n\tid: string;\n\tnetwork: string;\n\tcreated_at: Date;\n}): InstanceRow {\n\treturn {\n\t\tid: row.id,\n\t\tnetwork: parseInstanceNetwork(row.network),\n\t\tcreated_at: row.created_at,\n\t};\n}\n"
|
|
5
|
+
"import type { Kysely } from \"kysely\";\nimport type { Database } from \"../types.ts\";\n\nexport const INSTANCE_NETWORKS = [\"mainnet\", \"testnet\", \"devnet\"] as const;\nexport type InstanceNetwork = (typeof INSTANCE_NETWORKS)[number];\n\nexport type InstanceRow = {\n\tid: string;\n\tnetwork: InstanceNetwork;\n\tcreated_at: Date;\n};\n\nexport class InstanceNetworkMismatchError extends Error {\n\treadonly name = \"InstanceNetworkMismatchError\";\n\tconstructor(\n\t\treadonly existing: InstanceNetwork,\n\t\treadonly requested: InstanceNetwork,\n\t) {\n\t\tsuper(`instance network is ${existing}; cannot change to ${requested}`);\n\t}\n}\n\nexport class InvalidInstanceNetworkError extends Error {\n\treadonly name = \"InvalidInstanceNetworkError\";\n\tconstructor(readonly value: string) {\n\t\tsuper(\n\t\t\t`instance network must be mainnet, testnet, or devnet (got ${value})`,\n\t\t);\n\t}\n}\n\nexport function parseInstanceNetwork(value: string): InstanceNetwork {\n\tconst network = value.trim().toLowerCase();\n\tif ((INSTANCE_NETWORKS as readonly string[]).includes(network)) {\n\t\treturn network as InstanceNetwork;\n\t}\n\tthrow new InvalidInstanceNetworkError(value);\n}\n\n/** STACKS_NETWORK, then NETWORK, then mainnet. */\nexport function instanceNetworkFromEnv(\n\tenv: NodeJS.ProcessEnv = process.env,\n): InstanceNetwork {\n\treturn parseInstanceNetwork(env.STACKS_NETWORK ?? env.NETWORK ?? \"mainnet\");\n}\n\nexport async function getInstance(\n\tdb: Kysely<Database>,\n): Promise<InstanceRow | null> {\n\tconst row = await db\n\t\t.selectFrom(\"instances\")\n\t\t.select([\"id\", \"network\", \"created_at\"])\n\t\t.executeTakeFirst();\n\treturn row ? toInstance(row) : null;\n}\n\n/**\n * Return the singleton instance, creating it on first call.\n * A second call with a different network is refused — the network is\n * immutable for the life of the database.\n */\nexport async function ensureInstance(\n\tdb: Kysely<Database>,\n\tinput: { network: InstanceNetwork },\n): Promise<InstanceRow> {\n\tconst existing = await getInstance(db);\n\tif (existing) {\n\t\tif (existing.network !== input.network) {\n\t\t\tthrow new InstanceNetworkMismatchError(existing.network, input.network);\n\t\t}\n\t\treturn existing;\n\t}\n\ttry {\n\t\tconst inserted = await db\n\t\t\t.insertInto(\"instances\")\n\t\t\t.values({ network: input.network })\n\t\t\t.returning([\"id\", \"network\", \"created_at\"])\n\t\t\t.executeTakeFirstOrThrow();\n\t\treturn toInstance(inserted);\n\t} catch {\n\t\t// Lost the singleton race — the other writer won.\n\t\tconst raced = await getInstance(db);\n\t\tif (!raced) throw new Error(\"failed to create instance\");\n\t\tif (raced.network !== input.network) {\n\t\t\tthrow new InstanceNetworkMismatchError(raced.network, input.network);\n\t\t}\n\t\treturn raced;\n\t}\n}\n\nfunction toInstance(row: {\n\tid: string;\n\tnetwork: string;\n\tcreated_at: Date;\n}): InstanceRow {\n\treturn {\n\t\tid: row.id,\n\t\tnetwork: parseInstanceNetwork(row.network),\n\t\tcreated_at: row.created_at,\n\t};\n}\n\n/**\n * A stack with no local chain: it reads chain data from a hosted Index/Streams\n * API (`SUBGRAPH_INDEX_API_URL` set) and its own `index_progress` has no row\n * for this network (a hosted tenant). Derived, not configured: a self-hoster\n * running a local indexer has the row and keeps reading its own tables, even\n * with its processors pointed at its own api over HTTP.\n */\nexport async function hasNoLocalChain(\n\tdb: Kysely<Database>,\n\topts: {\n\t\tenv?: NodeJS.ProcessEnv;\n\t\thasProgressRow?: (network: string) => Promise<boolean>;\n\t} = {},\n): Promise<boolean> {\n\tconst env = opts.env ?? process.env;\n\tif (!env.SUBGRAPH_INDEX_API_URL) return false;\n\tconst network = env.NETWORK ?? \"mainnet\";\n\tconst hasRow =\n\t\topts.hasProgressRow ?? ((n: string) => hasLocalProgressRow(db, n));\n\treturn !(await hasRow(network));\n}\n\nasync function hasLocalProgressRow(\n\tdb: Kysely<Database>,\n\tnetwork: string,\n): Promise<boolean> {\n\tconst row = await db\n\t\t.selectFrom(\"index_progress\")\n\t\t.select(\"network\")\n\t\t.where(\"network\", \"=\", network)\n\t\t.executeTakeFirst()\n\t\t.catch(() => undefined);\n\treturn row !== undefined;\n}\n"
|
|
6
6
|
],
|
|
7
|
-
"mappings": ";AAGO,IAAM,oBAAoB,CAAC,WAAW,WAAW,QAAQ;AAAA;AASzD,MAAM,qCAAqC,MAAM;AAAA,EAG7C;AAAA,EACA;AAAA,EAHD,OAAO;AAAA,EAChB,WAAW,CACD,UACA,WACR;AAAA,IACD,MAAM,uBAAuB,8BAA8B,WAAW;AAAA,IAH7D;AAAA,IACA;AAAA;AAIX;AAAA;AAEO,MAAM,oCAAoC,MAAM;AAAA,EAEjC;AAAA,EADZ,OAAO;AAAA,EAChB,WAAW,CAAU,OAAe;AAAA,IACnC,MACC,6DAA6D,QAC9D;AAAA,IAHoB;AAAA;AAKtB;AAEO,SAAS,oBAAoB,CAAC,OAAgC;AAAA,EACpE,MAAM,UAAU,MAAM,KAAK,EAAE,YAAY;AAAA,EACzC,IAAK,kBAAwC,SAAS,OAAO,GAAG;AAAA,IAC/D,OAAO;AAAA,EACR;AAAA,EACA,MAAM,IAAI,4BAA4B,KAAK;AAAA;AAIrC,SAAS,sBAAsB,CACrC,MAAyB,QAAQ,KACf;AAAA,EAClB,OAAO,qBAAqB,IAAI,kBAAkB,IAAI,WAAW,SAAS;AAAA;AAG3E,eAAsB,WAAW,CAChC,IAC8B;AAAA,EAC9B,MAAM,MAAM,MAAM,GAChB,WAAW,WAAW,EACtB,OAAO,CAAC,MAAM,WAAW,YAAY,CAAC,EACtC,iBAAiB;AAAA,EACnB,OAAO,MAAM,WAAW,GAAG,IAAI;AAAA;AAQhC,eAAsB,cAAc,CACnC,IACA,OACuB;AAAA,EACvB,MAAM,WAAW,MAAM,YAAY,EAAE;AAAA,EACrC,IAAI,UAAU;AAAA,IACb,IAAI,SAAS,YAAY,MAAM,SAAS;AAAA,MACvC,MAAM,IAAI,6BAA6B,SAAS,SAAS,MAAM,OAAO;AAAA,IACvE;AAAA,IACA,OAAO;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACH,MAAM,WAAW,MAAM,GACrB,WAAW,WAAW,EACtB,OAAO,EAAE,SAAS,MAAM,QAAQ,CAAC,EACjC,UAAU,CAAC,MAAM,WAAW,YAAY,CAAC,EACzC,wBAAwB;AAAA,IAC1B,OAAO,WAAW,QAAQ;AAAA,IACzB,MAAM;AAAA,IAEP,MAAM,QAAQ,MAAM,YAAY,EAAE;AAAA,IAClC,IAAI,CAAC;AAAA,MAAO,MAAM,IAAI,MAAM,2BAA2B;AAAA,IACvD,IAAI,MAAM,YAAY,MAAM,SAAS;AAAA,MACpC,MAAM,IAAI,6BAA6B,MAAM,SAAS,MAAM,OAAO;AAAA,IACpE;AAAA,IACA,OAAO;AAAA;AAAA;AAIT,SAAS,UAAU,CAAC,KAIJ;AAAA,EACf,OAAO;AAAA,IACN,IAAI,IAAI;AAAA,IACR,SAAS,qBAAqB,IAAI,OAAO;AAAA,IACzC,YAAY,IAAI;AAAA,EACjB;AAAA;",
|
|
8
|
-
"debugId": "
|
|
7
|
+
"mappings": ";AAGO,IAAM,oBAAoB,CAAC,WAAW,WAAW,QAAQ;AAAA;AASzD,MAAM,qCAAqC,MAAM;AAAA,EAG7C;AAAA,EACA;AAAA,EAHD,OAAO;AAAA,EAChB,WAAW,CACD,UACA,WACR;AAAA,IACD,MAAM,uBAAuB,8BAA8B,WAAW;AAAA,IAH7D;AAAA,IACA;AAAA;AAIX;AAAA;AAEO,MAAM,oCAAoC,MAAM;AAAA,EAEjC;AAAA,EADZ,OAAO;AAAA,EAChB,WAAW,CAAU,OAAe;AAAA,IACnC,MACC,6DAA6D,QAC9D;AAAA,IAHoB;AAAA;AAKtB;AAEO,SAAS,oBAAoB,CAAC,OAAgC;AAAA,EACpE,MAAM,UAAU,MAAM,KAAK,EAAE,YAAY;AAAA,EACzC,IAAK,kBAAwC,SAAS,OAAO,GAAG;AAAA,IAC/D,OAAO;AAAA,EACR;AAAA,EACA,MAAM,IAAI,4BAA4B,KAAK;AAAA;AAIrC,SAAS,sBAAsB,CACrC,MAAyB,QAAQ,KACf;AAAA,EAClB,OAAO,qBAAqB,IAAI,kBAAkB,IAAI,WAAW,SAAS;AAAA;AAG3E,eAAsB,WAAW,CAChC,IAC8B;AAAA,EAC9B,MAAM,MAAM,MAAM,GAChB,WAAW,WAAW,EACtB,OAAO,CAAC,MAAM,WAAW,YAAY,CAAC,EACtC,iBAAiB;AAAA,EACnB,OAAO,MAAM,WAAW,GAAG,IAAI;AAAA;AAQhC,eAAsB,cAAc,CACnC,IACA,OACuB;AAAA,EACvB,MAAM,WAAW,MAAM,YAAY,EAAE;AAAA,EACrC,IAAI,UAAU;AAAA,IACb,IAAI,SAAS,YAAY,MAAM,SAAS;AAAA,MACvC,MAAM,IAAI,6BAA6B,SAAS,SAAS,MAAM,OAAO;AAAA,IACvE;AAAA,IACA,OAAO;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACH,MAAM,WAAW,MAAM,GACrB,WAAW,WAAW,EACtB,OAAO,EAAE,SAAS,MAAM,QAAQ,CAAC,EACjC,UAAU,CAAC,MAAM,WAAW,YAAY,CAAC,EACzC,wBAAwB;AAAA,IAC1B,OAAO,WAAW,QAAQ;AAAA,IACzB,MAAM;AAAA,IAEP,MAAM,QAAQ,MAAM,YAAY,EAAE;AAAA,IAClC,IAAI,CAAC;AAAA,MAAO,MAAM,IAAI,MAAM,2BAA2B;AAAA,IACvD,IAAI,MAAM,YAAY,MAAM,SAAS;AAAA,MACpC,MAAM,IAAI,6BAA6B,MAAM,SAAS,MAAM,OAAO;AAAA,IACpE;AAAA,IACA,OAAO;AAAA;AAAA;AAIT,SAAS,UAAU,CAAC,KAIJ;AAAA,EACf,OAAO;AAAA,IACN,IAAI,IAAI;AAAA,IACR,SAAS,qBAAqB,IAAI,OAAO;AAAA,IACzC,YAAY,IAAI;AAAA,EACjB;AAAA;AAUD,eAAsB,eAAe,CACpC,IACA,OAGI,CAAC,GACc;AAAA,EACnB,MAAM,MAAM,KAAK,OAAO,QAAQ;AAAA,EAChC,IAAI,CAAC,IAAI;AAAA,IAAwB,OAAO;AAAA,EACxC,MAAM,UAAU,IAAI,WAAW;AAAA,EAC/B,MAAM,SACL,KAAK,mBAAmB,CAAC,MAAc,oBAAoB,IAAI,CAAC;AAAA,EACjE,OAAO,CAAE,MAAM,OAAO,OAAO;AAAA;AAG9B,eAAe,mBAAmB,CACjC,IACA,SACmB;AAAA,EACnB,MAAM,MAAM,MAAM,GAChB,WAAW,gBAAgB,EAC3B,OAAO,SAAS,EAChB,MAAM,WAAW,KAAK,OAAO,EAC7B,iBAAiB,EACjB,MAAM,MAAG;AAAA,IAAG;AAAA,GAAS;AAAA,EACvB,OAAO,QAAQ;AAAA;",
|
|
8
|
+
"debugId": "CD5DDEF4E82D8D8764756E2164756E21",
|
|
9
9
|
"names": []
|
|
10
10
|
}
|
|
@@ -284,7 +284,7 @@ interface ApiKeysTable {
|
|
|
284
284
|
rate_limit: Generated<number>;
|
|
285
285
|
ip_address: string;
|
|
286
286
|
account_id: string;
|
|
287
|
-
product: Generated<"account" | "streams" | "index" | "sentinel" | "docs">;
|
|
287
|
+
product: Generated<"account" | "streams" | "index" | "sentinel" | "docs" | "tenant">;
|
|
288
288
|
/** Sentinel permission areas; set only on `product = 'sentinel'` keys. */
|
|
289
289
|
areas: unknown | null;
|
|
290
290
|
tier: "free" | "build" | "scale" | "enterprise" | "internal" | null;
|
|
@@ -284,7 +284,7 @@ interface ApiKeysTable {
|
|
|
284
284
|
rate_limit: Generated<number>;
|
|
285
285
|
ip_address: string;
|
|
286
286
|
account_id: string;
|
|
287
|
-
product: Generated<"account" | "streams" | "index" | "sentinel" | "docs">;
|
|
287
|
+
product: Generated<"account" | "streams" | "index" | "sentinel" | "docs" | "tenant">;
|
|
288
288
|
/** Sentinel permission areas; set only on `product = 'sentinel'` keys. */
|
|
289
289
|
areas: unknown | null;
|
|
290
290
|
tier: "free" | "build" | "scale" | "enterprise" | "internal" | null;
|
|
@@ -284,7 +284,7 @@ interface ApiKeysTable {
|
|
|
284
284
|
rate_limit: Generated<number>;
|
|
285
285
|
ip_address: string;
|
|
286
286
|
account_id: string;
|
|
287
|
-
product: Generated<"account" | "streams" | "index" | "sentinel" | "docs">;
|
|
287
|
+
product: Generated<"account" | "streams" | "index" | "sentinel" | "docs" | "tenant">;
|
|
288
288
|
/** Sentinel permission areas; set only on `product = 'sentinel'` keys. */
|
|
289
289
|
areas: unknown | null;
|
|
290
290
|
tier: "free" | "build" | "scale" | "enterprise" | "internal" | null;
|
|
@@ -284,7 +284,7 @@ interface ApiKeysTable {
|
|
|
284
284
|
rate_limit: Generated<number>;
|
|
285
285
|
ip_address: string;
|
|
286
286
|
account_id: string;
|
|
287
|
-
product: Generated<"account" | "streams" | "index" | "sentinel" | "docs">;
|
|
287
|
+
product: Generated<"account" | "streams" | "index" | "sentinel" | "docs" | "tenant">;
|
|
288
288
|
/** Sentinel permission areas; set only on `product = 'sentinel'` keys. */
|
|
289
289
|
areas: unknown | null;
|
|
290
290
|
tier: "free" | "build" | "scale" | "enterprise" | "internal" | null;
|
|
@@ -294,7 +294,7 @@ interface ApiKeysTable {
|
|
|
294
294
|
rate_limit: Generated<number>;
|
|
295
295
|
ip_address: string;
|
|
296
296
|
account_id: string;
|
|
297
|
-
product: Generated<"account" | "streams" | "index" | "sentinel" | "docs">;
|
|
297
|
+
product: Generated<"account" | "streams" | "index" | "sentinel" | "docs" | "tenant">;
|
|
298
298
|
/** Sentinel permission areas; set only on `product = 'sentinel'` keys. */
|
|
299
299
|
areas: unknown | null;
|
|
300
300
|
tier: "free" | "build" | "scale" | "enterprise" | "internal" | null;
|
|
@@ -284,7 +284,7 @@ interface ApiKeysTable {
|
|
|
284
284
|
rate_limit: Generated<number>;
|
|
285
285
|
ip_address: string;
|
|
286
286
|
account_id: string;
|
|
287
|
-
product: Generated<"account" | "streams" | "index" | "sentinel" | "docs">;
|
|
287
|
+
product: Generated<"account" | "streams" | "index" | "sentinel" | "docs" | "tenant">;
|
|
288
288
|
/** Sentinel permission areas; set only on `product = 'sentinel'` keys. */
|
|
289
289
|
areas: unknown | null;
|
|
290
290
|
tier: "free" | "build" | "scale" | "enterprise" | "internal" | null;
|
package/dist/src/db/schema.d.ts
CHANGED
|
@@ -283,7 +283,7 @@ interface ApiKeysTable {
|
|
|
283
283
|
rate_limit: Generated<number>;
|
|
284
284
|
ip_address: string;
|
|
285
285
|
account_id: string;
|
|
286
|
-
product: Generated<"account" | "streams" | "index" | "sentinel" | "docs">;
|
|
286
|
+
product: Generated<"account" | "streams" | "index" | "sentinel" | "docs" | "tenant">;
|
|
287
287
|
/** Sentinel permission areas; set only on `product = 'sentinel'` keys. */
|
|
288
288
|
areas: unknown | null;
|
|
289
289
|
tier: "free" | "build" | "scale" | "enterprise" | "internal" | null;
|
package/dist/src/index-http.d.ts
CHANGED
|
@@ -202,6 +202,64 @@ type IndexStateWriteRow = {
|
|
|
202
202
|
tx_contract_id?: string | null
|
|
203
203
|
tx_function_name?: string | null
|
|
204
204
|
};
|
|
205
|
+
/** A `/v1/index/sbtc/events` row: one decoded sBTC protocol event. Numeric
|
|
206
|
+
* columns are JSON numbers here (the API normalizes them). */
|
|
207
|
+
type IndexSbtcEventRow = {
|
|
208
|
+
cursor: string
|
|
209
|
+
block_height: number
|
|
210
|
+
block_time?: string | null
|
|
211
|
+
tx_id: string
|
|
212
|
+
tx_index: number
|
|
213
|
+
event_index: number
|
|
214
|
+
topic: string
|
|
215
|
+
request_id: number | null
|
|
216
|
+
amount: string | null
|
|
217
|
+
sender: string | null
|
|
218
|
+
recipient_btc_version: number | null
|
|
219
|
+
recipient_btc_hashbytes: string | null
|
|
220
|
+
bitcoin_txid: string | null
|
|
221
|
+
output_index: number | null
|
|
222
|
+
sweep_txid: string | null
|
|
223
|
+
burn_hash: string | null
|
|
224
|
+
burn_height: number | null
|
|
225
|
+
signer_bitmap: string | null
|
|
226
|
+
max_fee: string | null
|
|
227
|
+
fee: string | null
|
|
228
|
+
governance_contract_type: number | null
|
|
229
|
+
governance_new_contract: string | null
|
|
230
|
+
signer_aggregate_pubkey: string | null
|
|
231
|
+
signer_threshold: number | null
|
|
232
|
+
signer_address: string | null
|
|
233
|
+
signer_keys_count: number | null
|
|
234
|
+
};
|
|
235
|
+
/** A `/v1/contracts?trait=` row (ABI omitted). */
|
|
236
|
+
type IndexContractRow = {
|
|
237
|
+
contract_id: string
|
|
238
|
+
deployer: string
|
|
239
|
+
block_height: number
|
|
240
|
+
declared_traits: string[] | null
|
|
241
|
+
inferred_standards: string[] | null
|
|
242
|
+
abi_status: string
|
|
243
|
+
/** When the contract's traits were last set (server clock). */
|
|
244
|
+
classified_at: string | null
|
|
245
|
+
};
|
|
246
|
+
/** A `/v1/index/sbtc/withdrawals` row: one peg-out rolled up per request. */
|
|
247
|
+
type IndexSbtcWithdrawalRow = {
|
|
248
|
+
cursor: string
|
|
249
|
+
request_id: number
|
|
250
|
+
status: "REQUESTED" | "ACCEPTED" | "REJECTED"
|
|
251
|
+
amount: string | null
|
|
252
|
+
sender: string | null
|
|
253
|
+
recipient_btc_version: number | null
|
|
254
|
+
recipient_btc_hashbytes: string | null
|
|
255
|
+
sweep_txid: string | null
|
|
256
|
+
settlement_confirmed: boolean | null
|
|
257
|
+
btc_confirmations: number | null
|
|
258
|
+
btc_block_height: number | null
|
|
259
|
+
confirmed_at: string | null
|
|
260
|
+
requested_at?: string | null
|
|
261
|
+
resolved_at?: string | null
|
|
262
|
+
};
|
|
205
263
|
type StreamsReorgRow = {
|
|
206
264
|
id: string
|
|
207
265
|
detected_at: string
|
|
@@ -285,6 +343,23 @@ declare class IndexHttpClient {
|
|
|
285
343
|
/** Lowest height the Index serves `state_writes` for, or null when it has
|
|
286
344
|
* none (its node does not deliver them). One row. */
|
|
287
345
|
firstStateWriteHeight(): Promise<number | null>;
|
|
346
|
+
/**
|
|
347
|
+
* Canonical sBTC protocol events over [fromHeight, toHeight] for `topics`,
|
|
348
|
+
* ordered by (block_height, event_index). One drained walk per topic (the
|
|
349
|
+
* endpoint filters on a single topic); `requestId` narrows each walk.
|
|
350
|
+
*/
|
|
351
|
+
fetchSbtcEvents(fromHeight: number, toHeight: number, topics: readonly string[], opts?: {
|
|
352
|
+
requestId?: number
|
|
353
|
+
}): Promise<IndexSbtcEventRow[]>;
|
|
354
|
+
/** Every canonical contract conforming to `trait` (declared or inferred),
|
|
355
|
+
* draining `/v1/contracts`'s `next_cursor`. `classifiedAfter` limits it to
|
|
356
|
+
* contracts classified at or after that time. */
|
|
357
|
+
listContractsByTrait(trait: string, opts?: {
|
|
358
|
+
classifiedAfter?: Date
|
|
359
|
+
}): Promise<IndexContractRow[]>;
|
|
360
|
+
/** Withdrawals whose BTC sweep crossed the confirmation threshold strictly
|
|
361
|
+
* after `confirmedAfter`, across all history. */
|
|
362
|
+
fetchSettledWithdrawals(confirmedAfter: Date): Promise<IndexSbtcWithdrawalRow[]>;
|
|
288
363
|
walkTransactions(fromHeight: number, toHeight: number): Promise<IndexTransactionRow[]>;
|
|
289
364
|
/** Canonical tip height from the Streams clock. */
|
|
290
365
|
getStreamsTip(): Promise<number>;
|
|
@@ -369,4 +444,4 @@ declare class IndexHttpClient {
|
|
|
369
444
|
}
|
|
370
445
|
/** Decoder + subgraph processor client. One env contract; omits bearer when no key. */
|
|
371
446
|
declare function createInternalIndexHttpClient(): IndexHttpClient;
|
|
372
|
-
export { BillingPausedCode, BillingPausedError, IndexBlockRow, IndexEventRow, IndexHttpClient, IndexHttpOptions, IndexHttpStatusError, IndexStateWriteRow, IndexTipEnvelope, IndexTransactionRow, MAX_INDEX_WAIT_SECONDS, StreamsReorgRow, createInternalIndexHttpClient };
|
|
447
|
+
export { BillingPausedCode, BillingPausedError, IndexBlockRow, IndexContractRow, IndexEventRow, IndexHttpClient, IndexHttpOptions, IndexHttpStatusError, IndexSbtcEventRow, IndexSbtcWithdrawalRow, IndexStateWriteRow, IndexTipEnvelope, IndexTransactionRow, MAX_INDEX_WAIT_SECONDS, StreamsReorgRow, createInternalIndexHttpClient };
|
package/dist/src/index-http.js
CHANGED
|
@@ -78,6 +78,8 @@ function billingPausedFrom(status, body, message) {
|
|
|
78
78
|
} catch {}
|
|
79
79
|
return null;
|
|
80
80
|
}
|
|
81
|
+
var CONTRACTS_PAGE_LIMIT = 500;
|
|
82
|
+
var THROUGH_TIP = Number.MAX_SAFE_INTEGER;
|
|
81
83
|
|
|
82
84
|
class IndexHttpClient {
|
|
83
85
|
indexBaseUrl;
|
|
@@ -189,6 +191,41 @@ class IndexHttpClient {
|
|
|
189
191
|
const { items } = await this.getPage("/v1/index/state-writes", "state_writes", new URLSearchParams({ from_height: "0", limit: "1" }));
|
|
190
192
|
return items[0]?.block_height ?? null;
|
|
191
193
|
}
|
|
194
|
+
async fetchSbtcEvents(fromHeight, toHeight, topics, opts) {
|
|
195
|
+
const out = [];
|
|
196
|
+
for (const topic of topics) {
|
|
197
|
+
out.push(...await this.walk("/v1/index/sbtc/events", "events", fromHeight, toHeight, {
|
|
198
|
+
topic,
|
|
199
|
+
...opts?.requestId !== undefined ? { request_id: String(opts.requestId) } : {}
|
|
200
|
+
}));
|
|
201
|
+
}
|
|
202
|
+
return out.sort((a, b) => a.block_height - b.block_height || a.event_index - b.event_index);
|
|
203
|
+
}
|
|
204
|
+
async listContractsByTrait(trait, opts = {}) {
|
|
205
|
+
const out = [];
|
|
206
|
+
let cursor = null;
|
|
207
|
+
do {
|
|
208
|
+
const params = new URLSearchParams({
|
|
209
|
+
trait,
|
|
210
|
+
limit: String(CONTRACTS_PAGE_LIMIT)
|
|
211
|
+
});
|
|
212
|
+
if (opts.classifiedAfter) {
|
|
213
|
+
params.set("classified_after", opts.classifiedAfter.toISOString());
|
|
214
|
+
}
|
|
215
|
+
if (cursor)
|
|
216
|
+
params.set("cursor", cursor);
|
|
217
|
+
const { items, next_cursor } = await this.getPage("/v1/contracts", "contracts", params);
|
|
218
|
+
out.push(...items);
|
|
219
|
+
cursor = next_cursor;
|
|
220
|
+
} while (cursor);
|
|
221
|
+
return out;
|
|
222
|
+
}
|
|
223
|
+
fetchSettledWithdrawals(confirmedAfter) {
|
|
224
|
+
return this.walk("/v1/index/sbtc/withdrawals", "withdrawals", 0, THROUGH_TIP, {
|
|
225
|
+
settlement_confirmed: "true",
|
|
226
|
+
confirmed_after: confirmedAfter.toISOString()
|
|
227
|
+
});
|
|
228
|
+
}
|
|
192
229
|
walkTransactions(fromHeight, toHeight) {
|
|
193
230
|
return this.walk("/v1/index/transactions", "transactions", fromHeight, toHeight);
|
|
194
231
|
}
|
|
@@ -283,5 +320,5 @@ export {
|
|
|
283
320
|
createInternalIndexHttpClient
|
|
284
321
|
};
|
|
285
322
|
|
|
286
|
-
//# debugId=
|
|
323
|
+
//# debugId=53AE43019E152E4064756E2164756E21
|
|
287
324
|
//# sourceMappingURL=index-http.js.map
|