@secondlayer/shared 0.2.2 → 0.3.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/db/index.d.ts +3 -1
- package/dist/src/db/index.js.map +2 -2
- package/dist/src/db/jsonb.d.ts +2 -1
- package/dist/src/db/jsonb.js.map +2 -2
- package/dist/src/db/queries/accounts.d.ts +2 -1
- package/dist/src/db/queries/accounts.js.map +2 -2
- package/dist/src/db/queries/integrity.d.ts +1 -0
- package/dist/src/db/queries/metrics.d.ts +6 -4
- package/dist/src/db/queries/metrics.js.map +2 -2
- package/dist/src/db/queries/usage.d.ts +1 -0
- package/dist/src/db/queries/views.d.ts +10 -8
- package/dist/src/db/queries/views.js.map +3 -3
- package/dist/src/db/schema.d.ts +1 -0
- package/dist/src/env.d.ts +9 -2
- package/dist/src/env.js.map +2 -2
- package/dist/src/errors.d.ts +15 -2
- package/dist/src/errors.js +7 -2
- package/dist/src/errors.js.map +3 -3
- package/dist/src/index.d.ts +217 -54
- package/dist/src/index.js +12 -6
- package/dist/src/index.js.map +10 -10
- package/dist/src/logger.d.ts +4 -4
- package/dist/src/logger.js.map +3 -3
- package/dist/src/node/hiro-client.js +2 -2
- package/dist/src/node/hiro-client.js.map +5 -5
- package/dist/src/node/local-client.d.ts +212 -0
- package/dist/src/node/local-client.js +70 -0
- package/dist/src/node/local-client.js.map +10 -0
- package/dist/src/queue/index.d.ts +1 -1
- package/dist/src/queue/index.js.map +3 -3
- package/dist/src/queue/recovery.js.map +2 -2
- package/dist/src/schemas/filters.d.ts +92 -28
- package/dist/src/schemas/filters.js.map +2 -2
- package/dist/src/schemas/index.d.ts +186 -43
- package/dist/src/schemas/index.js +6 -5
- package/dist/src/schemas/index.js.map +5 -5
- package/dist/src/schemas/views.d.ts +14 -3
- package/dist/src/schemas/views.js.map +2 -2
- package/dist/src/types.d.ts +9 -3
- package/dist/src/types.js +12 -1
- package/dist/src/types.js.map +1 -1
- package/migrations/0006_tx_index.ts +9 -0
- package/package.json +6 -3
package/dist/src/db/index.d.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
+
import { RawBuilder } from "kysely";
|
|
1
2
|
/**
|
|
2
3
|
* Safely encode a JS value as a JSONB literal for Kysely inserts/updates.
|
|
3
4
|
* Kysely + postgres.js double-encodes JSON when using parameterized queries
|
|
4
5
|
* with ::jsonb casts. This uses sql.raw to inline a properly escaped literal.
|
|
5
6
|
*/
|
|
6
|
-
declare function jsonb(value: unknown)
|
|
7
|
+
declare function jsonb(value: unknown): RawBuilder<unknown>;
|
|
7
8
|
/**
|
|
8
9
|
* Safely parse a JSONB value from the database.
|
|
9
10
|
* Handles double-encoded strings where postgres.js returns a JSON string
|
|
@@ -25,6 +26,7 @@ interface BlocksTable {
|
|
|
25
26
|
interface TransactionsTable {
|
|
26
27
|
tx_id: string;
|
|
27
28
|
block_height: number;
|
|
29
|
+
tx_index: Generated<number>;
|
|
28
30
|
type: string;
|
|
29
31
|
sender: string;
|
|
30
32
|
status: string;
|
package/dist/src/db/index.js.map
CHANGED
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/db/jsonb.ts", "../src/db/index.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
5
|
-
"import { 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 */\nexport function jsonb(value: unknown) {\n const escaped = JSON.stringify(value).replace(/'/g, \"''\");\n return 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 if (typeof value === \"string\") {\n try {\n return JSON.parse(value) as T;\n } catch {\n return value as T;\n }\n }\n return (value ?? {}) as T;\n}\n",
|
|
5
|
+
"import { sql, type RawBuilder } 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 */\nexport function jsonb(value: unknown): RawBuilder<unknown> {\n const escaped = JSON.stringify(value).replace(/'/g, \"''\");\n return 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 if (typeof value === \"string\") {\n try {\n return JSON.parse(value) as T;\n } catch {\n return value as T;\n }\n }\n return (value ?? {}) as T;\n}\n",
|
|
6
6
|
"import { Kysely } from \"kysely\";\nimport { PostgresJSDialect } from \"kysely-postgres-js\";\nimport postgres from \"postgres\";\nimport type { Database } from \"./types.ts\";\n\nlet db: Kysely<Database> | null = null;\nlet rawClient: ReturnType<typeof postgres> | null = null;\n\nexport function getDb(connectionString?: string): Kysely<Database> {\n if (!db) {\n const url = connectionString || process.env.DATABASE_URL || \"postgres://postgres:postgres@localhost:5432/streams_dev\";\n\n // Always use SSL for remote databases, just disable cert verification if needed\n const isLocal = url.includes(\"localhost\") || url.includes(\"127.0.0.1\") || url.includes(\"@postgres:\");\n rawClient = postgres(url, {\n ssl: isLocal ? undefined : { rejectUnauthorized: process.env.NODE_TLS_REJECT_UNAUTHORIZED !== \"0\" },\n });\n db = new Kysely<Database>({\n dialect: new PostgresJSDialect({ postgres: rawClient }),\n });\n }\n return db;\n}\n\n/** Raw postgres.js client for dynamic schema DDL (CREATE SCHEMA, DROP, etc.) */\nexport function getRawClient(): ReturnType<typeof postgres> {\n if (!rawClient) getDb();\n return rawClient!;\n}\n\n/** Close the DB connection pool. Call in CLI commands to allow process exit. */\nexport async function closeDb(): Promise<void> {\n if (db) {\n await db.destroy();\n db = null;\n }\n if (rawClient) {\n await rawClient.end();\n rawClient = null;\n }\n}\n\nimport { sql } from \"kysely\";\nexport { sql };\nexport * from \"./types.ts\";\nexport { jsonb, parseJsonb } from \"./jsonb.ts\";\n"
|
|
7
7
|
],
|
|
8
|
-
"mappings": ";;;;;;;;;;;;;AAAA;AAOO,SAAS,KAAK,CAAC,
|
|
8
|
+
"mappings": ";;;;;;;;;;;;;AAAA;AAOO,SAAS,KAAK,CAAC,OAAqC;AAAA,EACzD,MAAM,UAAU,KAAK,UAAU,KAAK,EAAE,QAAQ,MAAM,IAAI;AAAA,EACxD,OAAO,MAAM,IAAI,IAAI,IAAI,iBAAiB;AAAA;AAQrC,SAAS,UAAuB,CAAC,OAAmB;AAAA,EACzD,IAAI,OAAO,UAAU,UAAU;AAAA,IAC7B,IAAI;AAAA,MACF,OAAO,KAAK,MAAM,KAAK;AAAA,MACvB,MAAM;AAAA,MACN,OAAO;AAAA;AAAA,EAEX;AAAA,EACA,OAAQ,SAAS,CAAC;AAAA;;;ACzBpB;AACA;AACA;AAwCA,gBAAS;AArCT,IAAI,KAA8B;AAClC,IAAI,YAAgD;AAE7C,SAAS,KAAK,CAAC,kBAA6C;AAAA,EACjE,IAAI,CAAC,IAAI;AAAA,IACP,MAAM,MAAM,oBAAoB,QAAQ,IAAI,gBAAgB;AAAA,IAG5D,MAAM,UAAU,IAAI,SAAS,WAAW,KAAK,IAAI,SAAS,WAAW,KAAK,IAAI,SAAS,YAAY;AAAA,IACnG,YAAY,SAAS,KAAK;AAAA,MACxB,KAAK,UAAU,YAAY,EAAE,oBAAoB,QAAQ,IAAI,iCAAiC,IAAI;AAAA,IACpG,CAAC;AAAA,IACD,KAAK,IAAI,OAAiB;AAAA,MACxB,SAAS,IAAI,kBAAkB,EAAE,UAAU,UAAU,CAAC;AAAA,IACxD,CAAC;AAAA,EACH;AAAA,EACA,OAAO;AAAA;AAIF,SAAS,YAAY,GAAgC;AAAA,EAC1D,IAAI,CAAC;AAAA,IAAW,MAAM;AAAA,EACtB,OAAO;AAAA;AAIT,eAAsB,OAAO,GAAkB;AAAA,EAC7C,IAAI,IAAI;AAAA,IACN,MAAM,GAAG,QAAQ;AAAA,IACjB,KAAK;AAAA,EACP;AAAA,EACA,IAAI,WAAW;AAAA,IACb,MAAM,UAAU,IAAI;AAAA,IACpB,YAAY;AAAA,EACd;AAAA;",
|
|
9
9
|
"debugId": "F675FEF083D960AD64756E2164756E21",
|
|
10
10
|
"names": []
|
|
11
11
|
}
|
package/dist/src/db/jsonb.d.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
+
import { RawBuilder } from "kysely";
|
|
1
2
|
/**
|
|
2
3
|
* Safely encode a JS value as a JSONB literal for Kysely inserts/updates.
|
|
3
4
|
* Kysely + postgres.js double-encodes JSON when using parameterized queries
|
|
4
5
|
* with ::jsonb casts. This uses sql.raw to inline a properly escaped literal.
|
|
5
6
|
*/
|
|
6
|
-
declare function jsonb(value: unknown)
|
|
7
|
+
declare function jsonb(value: unknown): RawBuilder<unknown>;
|
|
7
8
|
/**
|
|
8
9
|
* Safely parse a JSONB value from the database.
|
|
9
10
|
* Handles double-encoded strings where postgres.js returns a JSON string
|
package/dist/src/db/jsonb.js.map
CHANGED
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/db/jsonb.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
5
|
-
"import { 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 */\nexport function jsonb(value: unknown) {\n const escaped = JSON.stringify(value).replace(/'/g, \"''\");\n return 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 if (typeof value === \"string\") {\n try {\n return JSON.parse(value) as T;\n } catch {\n return value as T;\n }\n }\n return (value ?? {}) as T;\n}\n"
|
|
5
|
+
"import { sql, type RawBuilder } 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 */\nexport function jsonb(value: unknown): RawBuilder<unknown> {\n const escaped = JSON.stringify(value).replace(/'/g, \"''\");\n return 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 if (typeof value === \"string\") {\n try {\n return JSON.parse(value) as T;\n } catch {\n return value as T;\n }\n }\n return (value ?? {}) as T;\n}\n"
|
|
6
6
|
],
|
|
7
|
-
"mappings": ";;;;;;;;;;;;;AAAA;AAOO,SAAS,KAAK,CAAC,
|
|
7
|
+
"mappings": ";;;;;;;;;;;;;AAAA;AAOO,SAAS,KAAK,CAAC,OAAqC;AAAA,EACzD,MAAM,UAAU,KAAK,UAAU,KAAK,EAAE,QAAQ,MAAM,IAAI;AAAA,EACxD,OAAO,MAAM,IAAI,IAAI,IAAI,iBAAiB;AAAA;AAQrC,SAAS,UAAuB,CAAC,OAAmB;AAAA,EACzD,IAAI,OAAO,UAAU,UAAU;AAAA,IAC7B,IAAI;AAAA,MACF,OAAO,KAAK,MAAM,KAAK;AAAA,MACvB,MAAM;AAAA,MACN,OAAO;AAAA;AAAA,EAEX;AAAA,EACA,OAAQ,SAAS,CAAC;AAAA;",
|
|
8
8
|
"debugId": "FD7B2A33BAF805D564756E2164756E21",
|
|
9
9
|
"names": []
|
|
10
10
|
}
|
|
@@ -12,6 +12,7 @@ interface BlocksTable {
|
|
|
12
12
|
interface TransactionsTable {
|
|
13
13
|
tx_id: string;
|
|
14
14
|
block_height: number;
|
|
15
|
+
tx_index: Generated<number>;
|
|
15
16
|
type: string;
|
|
16
17
|
sender: string;
|
|
17
18
|
status: string;
|
|
@@ -170,7 +171,7 @@ interface Database {
|
|
|
170
171
|
type Account = Selectable<AccountsTable>;
|
|
171
172
|
declare function upsertAccount(db: Kysely<Database>, email: string): Promise<Account>;
|
|
172
173
|
declare function getAccountById(db: Kysely<Database>, id: string): Promise<Account | null>;
|
|
173
|
-
declare function createMagicLink(db: Kysely<Database>, email: string, token: string, expiresInMs
|
|
174
|
+
declare function createMagicLink(db: Kysely<Database>, email: string, token: string, expiresInMs?: number): Promise<void>;
|
|
174
175
|
/**
|
|
175
176
|
* Verify a magic link token. Returns the email if valid, null otherwise.
|
|
176
177
|
* Marks the token as used atomically.
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/db/queries/accounts.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
5
|
-
"import type { Kysely } from \"kysely\";\nimport type { Database, Account } from \"../types.ts\";\n\nexport async function upsertAccount(\n db: Kysely<Database>,\n email: string,\n): Promise<Account> {\n return await db\n .insertInto(\"accounts\")\n .values({ email })\n .onConflict((oc) =>\n oc.column(\"email\").doUpdateSet({ email }), // no-op update to return existing\n )\n .returningAll()\n .executeTakeFirstOrThrow();\n}\n\nexport async function getAccountById(\n db: Kysely<Database>,\n id: string,\n): Promise<Account | null> {\n return (\n (await db\n .selectFrom(\"accounts\")\n .selectAll()\n .where(\"id\", \"=\", id)\n .executeTakeFirst()) ?? null\n );\n}\n\nexport async function createMagicLink(\n db: Kysely<Database>,\n email: string,\n token: string,\n expiresInMs = 15 * 60 * 1000,\n): Promise<void> {\n await db\n .insertInto(\"magic_links\")\n .values({\n email,\n token,\n expires_at: new Date(Date.now() + expiresInMs),\n })\n .execute();\n}\n\n/**\n * Verify a magic link token. Returns the email if valid, null otherwise.\n * Marks the token as used atomically.\n */\nexport async function verifyMagicLink(\n db: Kysely<Database>,\n token: string,\n): Promise<string | null> {\n const result = await db\n .updateTable(\"magic_links\")\n .set({ used_at: new Date() })\n .where(\"token\", \"=\", token)\n .where(\"used_at\", \"is\", null)\n .where(\"expires_at\", \">\", new Date())\n .returning(\"email\")\n .executeTakeFirst();\n\n return result?.email ?? null;\n}\n"
|
|
5
|
+
"import type { Kysely } from \"kysely\";\nimport type { Database, Account } from \"../types.ts\";\n\nexport async function upsertAccount(\n db: Kysely<Database>,\n email: string,\n): Promise<Account> {\n return await db\n .insertInto(\"accounts\")\n .values({ email })\n .onConflict((oc) =>\n oc.column(\"email\").doUpdateSet({ email }), // no-op update to return existing\n )\n .returningAll()\n .executeTakeFirstOrThrow();\n}\n\nexport async function getAccountById(\n db: Kysely<Database>,\n id: string,\n): Promise<Account | null> {\n return (\n (await db\n .selectFrom(\"accounts\")\n .selectAll()\n .where(\"id\", \"=\", id)\n .executeTakeFirst()) ?? null\n );\n}\n\nexport async function createMagicLink(\n db: Kysely<Database>,\n email: string,\n token: string,\n expiresInMs: number = 15 * 60 * 1000,\n): Promise<void> {\n await db\n .insertInto(\"magic_links\")\n .values({\n email,\n token,\n expires_at: new Date(Date.now() + expiresInMs),\n })\n .execute();\n}\n\n/**\n * Verify a magic link token. Returns the email if valid, null otherwise.\n * Marks the token as used atomically.\n */\nexport async function verifyMagicLink(\n db: Kysely<Database>,\n token: string,\n): Promise<string | null> {\n const result = await db\n .updateTable(\"magic_links\")\n .set({ used_at: new Date() })\n .where(\"token\", \"=\", token)\n .where(\"used_at\", \"is\", null)\n .where(\"expires_at\", \">\", new Date())\n .returning(\"email\")\n .executeTakeFirst();\n\n return result?.email ?? null;\n}\n"
|
|
6
6
|
],
|
|
7
|
-
"mappings": ";;;;;;;;;;;;;AAGA,eAAsB,aAAa,CACjC,IACA,OACkB;AAAA,EAClB,OAAO,MAAM,GACV,WAAW,UAAU,EACrB,OAAO,EAAE,MAAM,CAAC,EAChB,WAAW,CAAC,OACX,GAAG,OAAO,OAAO,EAAE,YAAY,EAAE,MAAM,CAAC,CAC1C,EACC,aAAa,EACb,wBAAwB;AAAA;AAG7B,eAAsB,cAAc,CAClC,IACA,IACyB;AAAA,EACzB,OACG,MAAM,GACJ,WAAW,UAAU,EACrB,UAAU,EACV,MAAM,MAAM,KAAK,EAAE,EACnB,iBAAiB,KAAM;AAAA;AAI9B,eAAsB,eAAe,CACnC,IACA,OACA,OACA,
|
|
7
|
+
"mappings": ";;;;;;;;;;;;;AAGA,eAAsB,aAAa,CACjC,IACA,OACkB;AAAA,EAClB,OAAO,MAAM,GACV,WAAW,UAAU,EACrB,OAAO,EAAE,MAAM,CAAC,EAChB,WAAW,CAAC,OACX,GAAG,OAAO,OAAO,EAAE,YAAY,EAAE,MAAM,CAAC,CAC1C,EACC,aAAa,EACb,wBAAwB;AAAA;AAG7B,eAAsB,cAAc,CAClC,IACA,IACyB;AAAA,EACzB,OACG,MAAM,GACJ,WAAW,UAAU,EACrB,UAAU,EACV,MAAM,MAAM,KAAK,EAAE,EACnB,iBAAiB,KAAM;AAAA;AAI9B,eAAsB,eAAe,CACnC,IACA,OACA,OACA,cAAsB,KAAK,KAAK,MACjB;AAAA,EACf,MAAM,GACH,WAAW,aAAa,EACxB,OAAO;AAAA,IACN;AAAA,IACA;AAAA,IACA,YAAY,IAAI,KAAK,KAAK,IAAI,IAAI,WAAW;AAAA,EAC/C,CAAC,EACA,QAAQ;AAAA;AAOb,eAAsB,eAAe,CACnC,IACA,OACwB;AAAA,EACxB,MAAM,SAAS,MAAM,GAClB,YAAY,aAAa,EACzB,IAAI,EAAE,SAAS,IAAI,KAAO,CAAC,EAC3B,MAAM,SAAS,KAAK,KAAK,EACzB,MAAM,WAAW,MAAM,IAAI,EAC3B,MAAM,cAAc,KAAK,IAAI,IAAM,EACnC,UAAU,OAAO,EACjB,iBAAiB;AAAA,EAEpB,OAAO,QAAQ,SAAS;AAAA;",
|
|
8
8
|
"debugId": "BF026A17168292E864756E2164756E21",
|
|
9
9
|
"names": []
|
|
10
10
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Kysely } from "kysely";
|
|
2
|
-
import { Generated } from "kysely";
|
|
2
|
+
import { Generated, Selectable } from "kysely";
|
|
3
3
|
interface BlocksTable {
|
|
4
4
|
height: number;
|
|
5
5
|
hash: string;
|
|
@@ -12,6 +12,7 @@ interface BlocksTable {
|
|
|
12
12
|
interface TransactionsTable {
|
|
13
13
|
tx_id: string;
|
|
14
14
|
block_height: number;
|
|
15
|
+
tx_index: Generated<number>;
|
|
15
16
|
type: string;
|
|
16
17
|
sender: string;
|
|
17
18
|
status: string;
|
|
@@ -167,13 +168,14 @@ interface Database {
|
|
|
167
168
|
usage_daily: UsageDailyTable;
|
|
168
169
|
usage_snapshots: UsageSnapshotsTable;
|
|
169
170
|
}
|
|
170
|
-
|
|
171
|
+
type StreamMetrics = Selectable<StreamMetricsTable>;
|
|
172
|
+
declare function getStreamMetrics(db: Kysely<Database>, streamId: string): Promise<StreamMetrics | null>;
|
|
171
173
|
declare function updateStreamMetrics(db: Kysely<Database>, streamId: string, updates: Partial<{
|
|
172
174
|
lastTriggeredAt: Date
|
|
173
175
|
lastTriggeredBlock: number
|
|
174
176
|
totalDeliveries: number
|
|
175
177
|
failedDeliveries: number
|
|
176
178
|
errorMessage: string | null
|
|
177
|
-
}>)
|
|
178
|
-
declare function incrementDeliveryCount(db: Kysely<Database>, streamId: string, failed: boolean)
|
|
179
|
+
}>): Promise<void>;
|
|
180
|
+
declare function incrementDeliveryCount(db: Kysely<Database>, streamId: string, failed: boolean): Promise<void>;
|
|
179
181
|
export { updateStreamMetrics, incrementDeliveryCount, getStreamMetrics };
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/db/queries/metrics.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
5
|
-
"import { sql, type Kysely } from \"kysely\";\nimport type { Database } from \"../types.ts\";\n\nexport async function getStreamMetrics(db: Kysely<Database>, streamId: string) {\n return (\n await db\n .selectFrom(\"stream_metrics\")\n .selectAll()\n .where(\"stream_id\", \"=\", streamId)\n .executeTakeFirst()\n ) ?? null;\n}\n\nexport async function updateStreamMetrics(\n db: Kysely<Database>,\n streamId: string,\n updates: Partial<{\n lastTriggeredAt: Date;\n lastTriggeredBlock: number;\n totalDeliveries: number;\n failedDeliveries: number;\n errorMessage: string | null;\n }>,\n) {\n await db\n .insertInto(\"stream_metrics\")\n .values({\n stream_id: streamId,\n last_triggered_at: updates.lastTriggeredAt ?? null,\n last_triggered_block: updates.lastTriggeredBlock ?? null,\n total_deliveries: updates.totalDeliveries ?? 0,\n failed_deliveries: updates.failedDeliveries ?? 0,\n error_message: updates.errorMessage ?? null,\n })\n .onConflict((oc) =>\n oc.column(\"stream_id\").doUpdateSet({\n ...(updates.lastTriggeredAt !== undefined ? { last_triggered_at: updates.lastTriggeredAt } : {}),\n ...(updates.lastTriggeredBlock !== undefined ? { last_triggered_block: updates.lastTriggeredBlock } : {}),\n ...(updates.totalDeliveries !== undefined ? { total_deliveries: updates.totalDeliveries } : {}),\n ...(updates.failedDeliveries !== undefined ? { failed_deliveries: updates.failedDeliveries } : {}),\n ...(updates.errorMessage !== undefined ? { error_message: updates.errorMessage } : {}),\n }),\n )\n .execute();\n}\n\nexport async function incrementDeliveryCount(\n db: Kysely<Database>,\n streamId: string,\n failed: boolean,\n) {\n await db\n .insertInto(\"stream_metrics\")\n .values({\n stream_id: streamId,\n total_deliveries: 1,\n failed_deliveries: failed ? 1 : 0,\n })\n .onConflict((oc) =>\n oc.column(\"stream_id\").doUpdateSet({\n total_deliveries: sql`stream_metrics.total_deliveries + 1`,\n ...(failed ? { failed_deliveries: sql`stream_metrics.failed_deliveries + 1` } : {}),\n }),\n )\n .execute();\n}\n"
|
|
5
|
+
"import { sql, type Kysely } from \"kysely\";\nimport type { Database, StreamMetrics } from \"../types.ts\";\n\nexport async function getStreamMetrics(db: Kysely<Database>, streamId: string): Promise<StreamMetrics | null> {\n return (\n await db\n .selectFrom(\"stream_metrics\")\n .selectAll()\n .where(\"stream_id\", \"=\", streamId)\n .executeTakeFirst()\n ) ?? null;\n}\n\nexport async function updateStreamMetrics(\n db: Kysely<Database>,\n streamId: string,\n updates: Partial<{\n lastTriggeredAt: Date;\n lastTriggeredBlock: number;\n totalDeliveries: number;\n failedDeliveries: number;\n errorMessage: string | null;\n }>,\n): Promise<void> {\n await db\n .insertInto(\"stream_metrics\")\n .values({\n stream_id: streamId,\n last_triggered_at: updates.lastTriggeredAt ?? null,\n last_triggered_block: updates.lastTriggeredBlock ?? null,\n total_deliveries: updates.totalDeliveries ?? 0,\n failed_deliveries: updates.failedDeliveries ?? 0,\n error_message: updates.errorMessage ?? null,\n })\n .onConflict((oc) =>\n oc.column(\"stream_id\").doUpdateSet({\n ...(updates.lastTriggeredAt !== undefined ? { last_triggered_at: updates.lastTriggeredAt } : {}),\n ...(updates.lastTriggeredBlock !== undefined ? { last_triggered_block: updates.lastTriggeredBlock } : {}),\n ...(updates.totalDeliveries !== undefined ? { total_deliveries: updates.totalDeliveries } : {}),\n ...(updates.failedDeliveries !== undefined ? { failed_deliveries: updates.failedDeliveries } : {}),\n ...(updates.errorMessage !== undefined ? { error_message: updates.errorMessage } : {}),\n }),\n )\n .execute();\n}\n\nexport async function incrementDeliveryCount(\n db: Kysely<Database>,\n streamId: string,\n failed: boolean,\n): Promise<void> {\n await db\n .insertInto(\"stream_metrics\")\n .values({\n stream_id: streamId,\n total_deliveries: 1,\n failed_deliveries: failed ? 1 : 0,\n })\n .onConflict((oc) =>\n oc.column(\"stream_id\").doUpdateSet({\n total_deliveries: sql`stream_metrics.total_deliveries + 1`,\n ...(failed ? { failed_deliveries: sql`stream_metrics.failed_deliveries + 1` } : {}),\n }),\n )\n .execute();\n}\n"
|
|
6
6
|
],
|
|
7
|
-
"mappings": ";;;;;;;;;;;;;AAAA;AAGA,eAAsB,gBAAgB,CAAC,IAAsB,
|
|
7
|
+
"mappings": ";;;;;;;;;;;;;AAAA;AAGA,eAAsB,gBAAgB,CAAC,IAAsB,UAAiD;AAAA,EAC5G,OACE,MAAM,GACH,WAAW,gBAAgB,EAC3B,UAAU,EACV,MAAM,aAAa,KAAK,QAAQ,EAChC,iBAAiB,KACjB;AAAA;AAGP,eAAsB,mBAAmB,CACvC,IACA,UACA,SAOe;AAAA,EACf,MAAM,GACH,WAAW,gBAAgB,EAC3B,OAAO;AAAA,IACN,WAAW;AAAA,IACX,mBAAmB,QAAQ,mBAAmB;AAAA,IAC9C,sBAAsB,QAAQ,sBAAsB;AAAA,IACpD,kBAAkB,QAAQ,mBAAmB;AAAA,IAC7C,mBAAmB,QAAQ,oBAAoB;AAAA,IAC/C,eAAe,QAAQ,gBAAgB;AAAA,EACzC,CAAC,EACA,WAAW,CAAC,OACX,GAAG,OAAO,WAAW,EAAE,YAAY;AAAA,OAC7B,QAAQ,oBAAoB,YAAY,EAAE,mBAAmB,QAAQ,gBAAgB,IAAI,CAAC;AAAA,OAC1F,QAAQ,uBAAuB,YAAY,EAAE,sBAAsB,QAAQ,mBAAmB,IAAI,CAAC;AAAA,OACnG,QAAQ,oBAAoB,YAAY,EAAE,kBAAkB,QAAQ,gBAAgB,IAAI,CAAC;AAAA,OACzF,QAAQ,qBAAqB,YAAY,EAAE,mBAAmB,QAAQ,iBAAiB,IAAI,CAAC;AAAA,OAC5F,QAAQ,iBAAiB,YAAY,EAAE,eAAe,QAAQ,aAAa,IAAI,CAAC;AAAA,EACtF,CAAC,CACH,EACC,QAAQ;AAAA;AAGb,eAAsB,sBAAsB,CAC1C,IACA,UACA,QACe;AAAA,EACf,MAAM,GACH,WAAW,gBAAgB,EAC3B,OAAO;AAAA,IACN,WAAW;AAAA,IACX,kBAAkB;AAAA,IAClB,mBAAmB,SAAS,IAAI;AAAA,EAClC,CAAC,EACA,WAAW,CAAC,OACX,GAAG,OAAO,WAAW,EAAE,YAAY;AAAA,IACjC,kBAAkB;AAAA,OACd,SAAS,EAAE,mBAAmB,0CAA0C,IAAI,CAAC;AAAA,EACnF,CAAC,CACH,EACC,QAAQ;AAAA;",
|
|
8
8
|
"debugId": "A4E370524682609864756E2164756E21",
|
|
9
9
|
"names": []
|
|
10
10
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Kysely } from "kysely";
|
|
2
|
-
import { Generated } from "kysely";
|
|
2
|
+
import { Generated, Selectable } from "kysely";
|
|
3
3
|
interface BlocksTable {
|
|
4
4
|
height: number;
|
|
5
5
|
hash: string;
|
|
@@ -12,6 +12,7 @@ interface BlocksTable {
|
|
|
12
12
|
interface TransactionsTable {
|
|
13
13
|
tx_id: string;
|
|
14
14
|
block_height: number;
|
|
15
|
+
tx_index: Generated<number>;
|
|
15
16
|
type: string;
|
|
16
17
|
sender: string;
|
|
17
18
|
status: string;
|
|
@@ -167,6 +168,7 @@ interface Database {
|
|
|
167
168
|
usage_daily: UsageDailyTable;
|
|
168
169
|
usage_snapshots: UsageSnapshotsTable;
|
|
169
170
|
}
|
|
171
|
+
type View = Selectable<ViewsTable>;
|
|
170
172
|
/**
|
|
171
173
|
* Convert a view name to its PostgreSQL schema name.
|
|
172
174
|
* With keyPrefix: "view_{prefix}_{name}" (tenant-isolated)
|
|
@@ -181,11 +183,11 @@ declare function registerView(db: Kysely<Database>, data: {
|
|
|
181
183
|
handlerPath: string
|
|
182
184
|
apiKeyId?: string
|
|
183
185
|
schemaName?: string
|
|
184
|
-
})
|
|
185
|
-
declare function getView(db: Kysely<Database>, name: string, apiKeyId?: string)
|
|
186
|
-
declare function listViews(db: Kysely<Database>, apiKeyId?: string)
|
|
187
|
-
declare function updateViewStatus(db: Kysely<Database>, name: string, status: string, lastProcessedBlock?: number)
|
|
188
|
-
declare function recordViewProcessed(db: Kysely<Database>, name: string, processed: number, errors: number, lastError?: string)
|
|
189
|
-
declare function updateViewHandlerPath(db: Kysely<Database>, name: string, handlerPath: string)
|
|
190
|
-
declare function deleteView(db: Kysely<Database>, name: string, apiKeyId?: string)
|
|
186
|
+
}): Promise<View>;
|
|
187
|
+
declare function getView(db: Kysely<Database>, name: string, apiKeyId?: string): Promise<View | null>;
|
|
188
|
+
declare function listViews(db: Kysely<Database>, apiKeyId?: string): Promise<View[]>;
|
|
189
|
+
declare function updateViewStatus(db: Kysely<Database>, name: string, status: string, lastProcessedBlock?: number): Promise<void>;
|
|
190
|
+
declare function recordViewProcessed(db: Kysely<Database>, name: string, processed: number, errors: number, lastError?: string): Promise<void>;
|
|
191
|
+
declare function updateViewHandlerPath(db: Kysely<Database>, name: string, handlerPath: string): Promise<void>;
|
|
192
|
+
declare function deleteView(db: Kysely<Database>, name: string, apiKeyId?: string): Promise<View | null>;
|
|
191
193
|
export { updateViewStatus, updateViewHandlerPath, registerView, recordViewProcessed, pgSchemaName, listViews, getView, deleteView };
|
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/db/jsonb.ts", "../src/db/queries/views.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
5
|
-
"import { 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 */\nexport function jsonb(value: unknown) {\n const escaped = JSON.stringify(value).replace(/'/g, \"''\");\n return 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 if (typeof value === \"string\") {\n try {\n return JSON.parse(value) as T;\n } catch {\n return value as T;\n }\n }\n return (value ?? {}) as T;\n}\n",
|
|
6
|
-
"import { sql, type Kysely } from \"kysely\";\nimport { jsonb } from \"../jsonb.ts\";\nimport type { Database } from \"../types.ts\";\n\n/**\n * Convert a view name to its PostgreSQL schema name.\n * With keyPrefix: \"view_{prefix}_{name}\" (tenant-isolated)\n * Without keyPrefix: \"view_{name}\" (backward compat)\n */\nexport function pgSchemaName(viewName: string, keyPrefix?: string): string {\n const safeName = viewName.replace(/-/g, \"_\");\n if (!keyPrefix) {\n return `view_${safeName}`;\n }\n const safePrefix = keyPrefix.replace(/^sk-sl_/, \"\").replace(/-/g, \"_\");\n return `view_${safePrefix}_${safeName}`;\n}\n\nexport async function registerView(\n db: Kysely<Database>,\n data: {\n name: string;\n version: string;\n definition: Record<string, unknown>;\n schemaHash: string;\n handlerPath: string;\n apiKeyId?: string;\n schemaName?: string;\n },\n) {\n return await db\n .insertInto(\"views\")\n .values({\n name: data.name,\n version: data.version,\n definition: jsonb(data.definition) as any,\n schema_hash: data.schemaHash,\n handler_path: data.handlerPath,\n api_key_id: data.apiKeyId ?? null,\n schema_name: data.schemaName ?? null,\n })\n .onConflict((oc) =>\n oc.columns([\"name\", \"api_key_id\"]).doUpdateSet({\n version: data.version,\n definition: jsonb(data.definition) as any,\n schema_hash: data.schemaHash,\n handler_path: data.handlerPath,\n schema_name: data.schemaName ?? null,\n updated_at: new Date(),\n }),\n )\n .returningAll()\n .executeTakeFirstOrThrow();\n}\n\nexport async function getView(db: Kysely<Database>, name: string, apiKeyId?: string) {\n let query = db\n .selectFrom(\"views\")\n .selectAll()\n .where(\"name\", \"=\", name);\n\n if (apiKeyId) {\n query = query.where(\"api_key_id\", \"=\", apiKeyId);\n }\n\n return (await query.executeTakeFirst()) ?? null;\n}\n\nexport async function listViews(db: Kysely<Database>, apiKeyId?: string) {\n let query = db.selectFrom(\"views\").selectAll();\n if (apiKeyId) {\n query = query.where(\"api_key_id\", \"=\", apiKeyId);\n }\n return query.execute();\n}\n\nexport async function updateViewStatus(\n db: Kysely<Database>,\n name: string,\n status: string,\n lastProcessedBlock?: number,\n) {\n await db\n .updateTable(\"views\")\n .set({\n status,\n ...(lastProcessedBlock !== undefined ? { last_processed_block: lastProcessedBlock } : {}),\n updated_at: new Date(),\n })\n .where(\"name\", \"=\", name)\n .execute();\n}\n\nexport async function recordViewProcessed(\n db: Kysely<Database>,\n name: string,\n processed: number,\n errors: number,\n lastError?: string,\n) {\n await db\n .updateTable(\"views\")\n .set({\n total_processed: sql`total_processed + ${processed}`,\n total_errors: sql`total_errors + ${errors}`,\n ...(lastError\n ? { last_error: lastError, last_error_at: new Date() }\n : {}),\n updated_at: new Date(),\n })\n .where(\"name\", \"=\", name)\n .execute();\n}\n\nexport async function updateViewHandlerPath(\n db: Kysely<Database>,\n name: string,\n handlerPath: string,\n) {\n await db\n .updateTable(\"views\")\n .set({ handler_path: handlerPath, updated_at: new Date() })\n .where(\"name\", \"=\", name)\n .execute();\n}\n\nexport async function deleteView(db: Kysely<Database>, name: string, apiKeyId?: string) {\n const view = await getView(db, name, apiKeyId);\n if (!view) return null;\n\n // Use stored schema_name if available, otherwise compute\n const schemaName = view.schema_name ?? pgSchemaName(name);\n\n // Drop the view's schema (CASCADE drops all tables within)\n await sql`DROP SCHEMA IF EXISTS ${sql.raw(`\"${schemaName}\"`)} CASCADE`.execute(db);\n\n // Remove from registry\n await db.deleteFrom(\"views\").where(\"id\", \"=\", view.id).execute();\n\n return view;\n}\n"
|
|
5
|
+
"import { sql, type RawBuilder } 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 */\nexport function jsonb(value: unknown): RawBuilder<unknown> {\n const escaped = JSON.stringify(value).replace(/'/g, \"''\");\n return 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 if (typeof value === \"string\") {\n try {\n return JSON.parse(value) as T;\n } catch {\n return value as T;\n }\n }\n return (value ?? {}) as T;\n}\n",
|
|
6
|
+
"import { sql, type Kysely } from \"kysely\";\nimport { jsonb } from \"../jsonb.ts\";\nimport type { Database, View } from \"../types.ts\";\n\n/**\n * Convert a view name to its PostgreSQL schema name.\n * With keyPrefix: \"view_{prefix}_{name}\" (tenant-isolated)\n * Without keyPrefix: \"view_{name}\" (backward compat)\n */\nexport function pgSchemaName(viewName: string, keyPrefix?: string): string {\n const safeName = viewName.replace(/-/g, \"_\");\n if (!keyPrefix) {\n return `view_${safeName}`;\n }\n const safePrefix = keyPrefix.replace(/^sk-sl_/, \"\").replace(/-/g, \"_\");\n return `view_${safePrefix}_${safeName}`;\n}\n\nexport async function registerView(\n db: Kysely<Database>,\n data: {\n name: string;\n version: string;\n definition: Record<string, unknown>;\n schemaHash: string;\n handlerPath: string;\n apiKeyId?: string;\n schemaName?: string;\n },\n): Promise<View> {\n return await db\n .insertInto(\"views\")\n .values({\n name: data.name,\n version: data.version,\n definition: jsonb(data.definition) as any,\n schema_hash: data.schemaHash,\n handler_path: data.handlerPath,\n api_key_id: data.apiKeyId ?? null,\n schema_name: data.schemaName ?? null,\n })\n .onConflict((oc) =>\n oc.columns([\"name\", \"api_key_id\"]).doUpdateSet({\n version: data.version,\n definition: jsonb(data.definition) as any,\n schema_hash: data.schemaHash,\n handler_path: data.handlerPath,\n schema_name: data.schemaName ?? null,\n updated_at: new Date(),\n }),\n )\n .returningAll()\n .executeTakeFirstOrThrow();\n}\n\nexport async function getView(db: Kysely<Database>, name: string, apiKeyId?: string): Promise<View | null> {\n let query = db\n .selectFrom(\"views\")\n .selectAll()\n .where(\"name\", \"=\", name);\n\n if (apiKeyId) {\n query = query.where(\"api_key_id\", \"=\", apiKeyId);\n }\n\n return (await query.executeTakeFirst()) ?? null;\n}\n\nexport async function listViews(db: Kysely<Database>, apiKeyId?: string): Promise<View[]> {\n let query = db.selectFrom(\"views\").selectAll();\n if (apiKeyId) {\n query = query.where(\"api_key_id\", \"=\", apiKeyId);\n }\n return query.execute();\n}\n\nexport async function updateViewStatus(\n db: Kysely<Database>,\n name: string,\n status: string,\n lastProcessedBlock?: number,\n): Promise<void> {\n await db\n .updateTable(\"views\")\n .set({\n status,\n ...(lastProcessedBlock !== undefined ? { last_processed_block: lastProcessedBlock } : {}),\n updated_at: new Date(),\n })\n .where(\"name\", \"=\", name)\n .execute();\n}\n\nexport async function recordViewProcessed(\n db: Kysely<Database>,\n name: string,\n processed: number,\n errors: number,\n lastError?: string,\n): Promise<void> {\n await db\n .updateTable(\"views\")\n .set({\n total_processed: sql`total_processed + ${processed}`,\n total_errors: sql`total_errors + ${errors}`,\n ...(lastError\n ? { last_error: lastError, last_error_at: new Date() }\n : {}),\n updated_at: new Date(),\n })\n .where(\"name\", \"=\", name)\n .execute();\n}\n\nexport async function updateViewHandlerPath(\n db: Kysely<Database>,\n name: string,\n handlerPath: string,\n): Promise<void> {\n await db\n .updateTable(\"views\")\n .set({ handler_path: handlerPath, updated_at: new Date() })\n .where(\"name\", \"=\", name)\n .execute();\n}\n\nexport async function deleteView(db: Kysely<Database>, name: string, apiKeyId?: string): Promise<View | null> {\n const view = await getView(db, name, apiKeyId);\n if (!view) return null;\n\n // Use stored schema_name if available, otherwise compute\n const schemaName = view.schema_name ?? pgSchemaName(name);\n\n // Drop the view's schema (CASCADE drops all tables within)\n await sql`DROP SCHEMA IF EXISTS ${sql.raw(`\"${schemaName}\"`)} CASCADE`.execute(db);\n\n // Remove from registry\n await db.deleteFrom(\"views\").where(\"id\", \"=\", view.id).execute();\n\n return view;\n}\n"
|
|
7
7
|
],
|
|
8
|
-
"mappings": ";;;;;;;;;;;;;AAAA;AAOO,SAAS,KAAK,CAAC,
|
|
8
|
+
"mappings": ";;;;;;;;;;;;;AAAA;AAOO,SAAS,KAAK,CAAC,OAAqC;AAAA,EACzD,MAAM,UAAU,KAAK,UAAU,KAAK,EAAE,QAAQ,MAAM,IAAI;AAAA,EACxD,OAAO,MAAM,IAAI,IAAI,IAAI,iBAAiB;AAAA;AAQrC,SAAS,UAAuB,CAAC,OAAmB;AAAA,EACzD,IAAI,OAAO,UAAU,UAAU;AAAA,IAC7B,IAAI;AAAA,MACF,OAAO,KAAK,MAAM,KAAK;AAAA,MACvB,MAAM;AAAA,MACN,OAAO;AAAA;AAAA,EAEX;AAAA,EACA,OAAQ,SAAS,CAAC;AAAA;;;ACzBpB,gBAAS;AASF,SAAS,YAAY,CAAC,UAAkB,WAA4B;AAAA,EACzE,MAAM,WAAW,SAAS,QAAQ,MAAM,GAAG;AAAA,EAC3C,IAAI,CAAC,WAAW;AAAA,IACd,OAAO,QAAQ;AAAA,EACjB;AAAA,EACA,MAAM,aAAa,UAAU,QAAQ,WAAW,EAAE,EAAE,QAAQ,MAAM,GAAG;AAAA,EACrE,OAAO,QAAQ,cAAc;AAAA;AAG/B,eAAsB,YAAY,CAChC,IACA,MASe;AAAA,EACf,OAAO,MAAM,GACV,WAAW,OAAO,EAClB,OAAO;AAAA,IACN,MAAM,KAAK;AAAA,IACX,SAAS,KAAK;AAAA,IACd,YAAY,MAAM,KAAK,UAAU;AAAA,IACjC,aAAa,KAAK;AAAA,IAClB,cAAc,KAAK;AAAA,IACnB,YAAY,KAAK,YAAY;AAAA,IAC7B,aAAa,KAAK,cAAc;AAAA,EAClC,CAAC,EACA,WAAW,CAAC,OACX,GAAG,QAAQ,CAAC,QAAQ,YAAY,CAAC,EAAE,YAAY;AAAA,IAC7C,SAAS,KAAK;AAAA,IACd,YAAY,MAAM,KAAK,UAAU;AAAA,IACjC,aAAa,KAAK;AAAA,IAClB,cAAc,KAAK;AAAA,IACnB,aAAa,KAAK,cAAc;AAAA,IAChC,YAAY,IAAI;AAAA,EAClB,CAAC,CACH,EACC,aAAa,EACb,wBAAwB;AAAA;AAG7B,eAAsB,OAAO,CAAC,IAAsB,MAAc,UAAyC;AAAA,EACzG,IAAI,QAAQ,GACT,WAAW,OAAO,EAClB,UAAU,EACV,MAAM,QAAQ,KAAK,IAAI;AAAA,EAE1B,IAAI,UAAU;AAAA,IACZ,QAAQ,MAAM,MAAM,cAAc,KAAK,QAAQ;AAAA,EACjD;AAAA,EAEA,OAAQ,MAAM,MAAM,iBAAiB,KAAM;AAAA;AAG7C,eAAsB,SAAS,CAAC,IAAsB,UAAoC;AAAA,EACxF,IAAI,QAAQ,GAAG,WAAW,OAAO,EAAE,UAAU;AAAA,EAC7C,IAAI,UAAU;AAAA,IACZ,QAAQ,MAAM,MAAM,cAAc,KAAK,QAAQ;AAAA,EACjD;AAAA,EACA,OAAO,MAAM,QAAQ;AAAA;AAGvB,eAAsB,gBAAgB,CACpC,IACA,MACA,QACA,oBACe;AAAA,EACf,MAAM,GACH,YAAY,OAAO,EACnB,IAAI;AAAA,IACH;AAAA,OACI,uBAAuB,YAAY,EAAE,sBAAsB,mBAAmB,IAAI,CAAC;AAAA,IACvF,YAAY,IAAI;AAAA,EAClB,CAAC,EACA,MAAM,QAAQ,KAAK,IAAI,EACvB,QAAQ;AAAA;AAGb,eAAsB,mBAAmB,CACvC,IACA,MACA,WACA,QACA,WACe;AAAA,EACf,MAAM,GACH,YAAY,OAAO,EACnB,IAAI;AAAA,IACH,iBAAiB,yBAAwB;AAAA,IACzC,cAAc,sBAAqB;AAAA,OAC/B,YACA,EAAE,YAAY,WAAW,eAAe,IAAI,KAAO,IACnD,CAAC;AAAA,IACL,YAAY,IAAI;AAAA,EAClB,CAAC,EACA,MAAM,QAAQ,KAAK,IAAI,EACvB,QAAQ;AAAA;AAGb,eAAsB,qBAAqB,CACzC,IACA,MACA,aACe;AAAA,EACf,MAAM,GACH,YAAY,OAAO,EACnB,IAAI,EAAE,cAAc,aAAa,YAAY,IAAI,KAAO,CAAC,EACzD,MAAM,QAAQ,KAAK,IAAI,EACvB,QAAQ;AAAA;AAGb,eAAsB,UAAU,CAAC,IAAsB,MAAc,UAAyC;AAAA,EAC5G,MAAM,OAAO,MAAM,QAAQ,IAAI,MAAM,QAAQ;AAAA,EAC7C,IAAI,CAAC;AAAA,IAAM,OAAO;AAAA,EAGlB,MAAM,aAAa,KAAK,eAAe,aAAa,IAAI;AAAA,EAGxD,MAAM,6BAA4B,KAAI,IAAI,IAAI,aAAa,YAAY,QAAQ,EAAE;AAAA,EAGjF,MAAM,GAAG,WAAW,OAAO,EAAE,MAAM,MAAM,KAAK,KAAK,EAAE,EAAE,QAAQ;AAAA,EAE/D,OAAO;AAAA;",
|
|
9
9
|
"debugId": "C19949368802BB4964756E2164756E21",
|
|
10
10
|
"names": []
|
|
11
11
|
}
|
package/dist/src/db/schema.d.ts
CHANGED
package/dist/src/env.d.ts
CHANGED
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
interface EnvSchemaOutput {
|
|
3
|
+
DATABASE_URL?: string;
|
|
4
|
+
NETWORK?: "mainnet" | "testnet";
|
|
5
|
+
NETWORKS?: ("mainnet" | "testnet")[];
|
|
6
|
+
LOG_LEVEL: "debug" | "info" | "warn" | "error";
|
|
7
|
+
NODE_ENV: "development" | "production" | "test";
|
|
8
|
+
}
|
|
9
|
+
declare const envSchema: z.ZodType<EnvSchemaOutput>;
|
|
10
|
+
type Env = EnvSchemaOutput & {
|
|
4
11
|
enabledNetworks: ("mainnet" | "testnet")[]
|
|
5
12
|
};
|
|
6
13
|
declare function getEnv(): Env;
|
package/dist/src/env.js.map
CHANGED
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/env.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
5
|
-
"import { z } from \"zod\";\n\n// Parse comma-separated networks\nconst networksSchema = z.string().transform((val) => {\n const networks = val.split(\",\").map((n) => n.trim()).filter(Boolean);\n const valid = [\"mainnet\", \"testnet\"];\n for (const n of networks) {\n if (!valid.includes(n)) {\n throw new Error(`Invalid network: ${n}. Must be one of: ${valid.join(\", \")}`);\n }\n }\n return networks as (\"mainnet\" | \"testnet\")[];\n});\n\
|
|
5
|
+
"import { z } from \"zod\";\n\n// Parse comma-separated networks\nconst networksSchema = z.string().transform((val) => {\n const networks = val.split(\",\").map((n) => n.trim()).filter(Boolean);\n const valid = [\"mainnet\", \"testnet\"];\n for (const n of networks) {\n if (!valid.includes(n)) {\n throw new Error(`Invalid network: ${n}. Must be one of: ${valid.join(\", \")}`);\n }\n }\n return networks as (\"mainnet\" | \"testnet\")[];\n});\n\ninterface EnvSchemaOutput {\n DATABASE_URL?: string;\n NETWORK?: \"mainnet\" | \"testnet\";\n NETWORKS?: (\"mainnet\" | \"testnet\")[];\n LOG_LEVEL: \"debug\" | \"info\" | \"warn\" | \"error\";\n NODE_ENV: \"development\" | \"production\" | \"test\";\n}\n\n// Cast needed: z.preprocess / z.default create different _input vs _output types\n// that z.ZodType<T> can't represent without explicit input type param\nconst envSchema: z.ZodType<EnvSchemaOutput> = z.object({\n DATABASE_URL: z.preprocess(\n (val) => (typeof val === \"string\" && val.length === 0) ? undefined : val,\n z.string().url().optional(),\n ),\n NETWORK: z.enum([\"mainnet\", \"testnet\"]).optional(),\n NETWORKS: networksSchema.optional(),\n LOG_LEVEL: z.enum([\"debug\", \"info\", \"warn\", \"error\"]).default(\"info\"),\n NODE_ENV: z.enum([\"development\", \"production\", \"test\"]).default(\"development\"),\n}) as unknown as z.ZodType<EnvSchemaOutput>;\n\nexport type Env = EnvSchemaOutput & {\n enabledNetworks: (\"mainnet\" | \"testnet\")[];\n};\n\nlet cachedEnv: Env | null = null;\n\nexport function getEnv(): Env {\n if (cachedEnv) {\n return cachedEnv;\n }\n\n const result = envSchema.safeParse(process.env);\n\n if (!result.success) {\n console.error(\"❌ Invalid environment configuration:\");\n console.error(result.error.format());\n throw new Error(\"Invalid environment configuration\");\n }\n\n // Compute enabled networks from NETWORKS or NETWORK\n let enabledNetworks: (\"mainnet\" | \"testnet\")[];\n if (result.data.NETWORKS && result.data.NETWORKS.length > 0) {\n enabledNetworks = result.data.NETWORKS;\n } else if (result.data.NETWORK) {\n enabledNetworks = [result.data.NETWORK];\n } else {\n enabledNetworks = [\"mainnet\"]; // Default\n }\n\n cachedEnv = { ...result.data, enabledNetworks };\n return cachedEnv;\n}\n\n// Export for testing\nexport { envSchema };\n"
|
|
6
6
|
],
|
|
7
|
-
"mappings": ";;;;;;;;;;;;;AAAA;AAGA,IAAM,iBAAiB,EAAE,OAAO,EAAE,UAAU,CAAC,QAAQ;AAAA,EACnD,MAAM,WAAW,IAAI,MAAM,GAAG,EAAE,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,EAAE,OAAO,OAAO;AAAA,EACnE,MAAM,QAAQ,CAAC,WAAW,SAAS;AAAA,EACnC,WAAW,KAAK,UAAU;AAAA,IACxB,IAAI,CAAC,MAAM,SAAS,CAAC,GAAG;AAAA,MACtB,MAAM,IAAI,MAAM,oBAAoB,sBAAsB,MAAM,KAAK,IAAI,GAAG;AAAA,IAC9E;AAAA,EACF;AAAA,EACA,OAAO;AAAA,CACR;
|
|
7
|
+
"mappings": ";;;;;;;;;;;;;AAAA;AAGA,IAAM,iBAAiB,EAAE,OAAO,EAAE,UAAU,CAAC,QAAQ;AAAA,EACnD,MAAM,WAAW,IAAI,MAAM,GAAG,EAAE,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,EAAE,OAAO,OAAO;AAAA,EACnE,MAAM,QAAQ,CAAC,WAAW,SAAS;AAAA,EACnC,WAAW,KAAK,UAAU;AAAA,IACxB,IAAI,CAAC,MAAM,SAAS,CAAC,GAAG;AAAA,MACtB,MAAM,IAAI,MAAM,oBAAoB,sBAAsB,MAAM,KAAK,IAAI,GAAG;AAAA,IAC9E;AAAA,EACF;AAAA,EACA,OAAO;AAAA,CACR;AAYD,IAAM,YAAwC,EAAE,OAAO;AAAA,EACrD,cAAc,EAAE,WACd,CAAC,QAAS,OAAO,QAAQ,YAAY,IAAI,WAAW,IAAK,YAAY,KACrE,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,CAC5B;AAAA,EACA,SAAS,EAAE,KAAK,CAAC,WAAW,SAAS,CAAC,EAAE,SAAS;AAAA,EACjD,UAAU,eAAe,SAAS;AAAA,EAClC,WAAW,EAAE,KAAK,CAAC,SAAS,QAAQ,QAAQ,OAAO,CAAC,EAAE,QAAQ,MAAM;AAAA,EACpE,UAAU,EAAE,KAAK,CAAC,eAAe,cAAc,MAAM,CAAC,EAAE,QAAQ,aAAa;AAC/E,CAAC;AAMD,IAAI,YAAwB;AAErB,SAAS,MAAM,GAAQ;AAAA,EAC5B,IAAI,WAAW;AAAA,IACb,OAAO;AAAA,EACT;AAAA,EAEA,MAAM,SAAS,UAAU,UAAU,QAAQ,GAAG;AAAA,EAE9C,IAAI,CAAC,OAAO,SAAS;AAAA,IACnB,QAAQ,MAAM,sCAAqC;AAAA,IACnD,QAAQ,MAAM,OAAO,MAAM,OAAO,CAAC;AAAA,IACnC,MAAM,IAAI,MAAM,mCAAmC;AAAA,EACrD;AAAA,EAGA,IAAI;AAAA,EACJ,IAAI,OAAO,KAAK,YAAY,OAAO,KAAK,SAAS,SAAS,GAAG;AAAA,IAC3D,kBAAkB,OAAO,KAAK;AAAA,EAChC,EAAO,SAAI,OAAO,KAAK,SAAS;AAAA,IAC9B,kBAAkB,CAAC,OAAO,KAAK,OAAO;AAAA,EACxC,EAAO;AAAA,IACL,kBAAkB,CAAC,SAAS;AAAA;AAAA,EAG9B,YAAY,KAAK,OAAO,MAAM,gBAAgB;AAAA,EAC9C,OAAO;AAAA;",
|
|
8
8
|
"debugId": "36753D595F72E07A64756E2164756E21",
|
|
9
9
|
"names": []
|
|
10
10
|
}
|
package/dist/src/errors.d.ts
CHANGED
|
@@ -5,7 +5,13 @@ declare class StreamsError extends Error {
|
|
|
5
5
|
code: string;
|
|
6
6
|
cause?: unknown;
|
|
7
7
|
constructor(code: string, message: string, cause?: unknown);
|
|
8
|
-
toJSON(): {
|
|
8
|
+
toJSON(): {
|
|
9
|
+
name: string
|
|
10
|
+
code: string
|
|
11
|
+
message: string
|
|
12
|
+
stack: string | undefined
|
|
13
|
+
cause: unknown
|
|
14
|
+
};
|
|
9
15
|
}
|
|
10
16
|
/**
|
|
11
17
|
* Stream not found error
|
|
@@ -31,7 +37,14 @@ declare class DatabaseError extends StreamsError {
|
|
|
31
37
|
declare class WebhookDeliveryError extends StreamsError {
|
|
32
38
|
statusCode?: number;
|
|
33
39
|
constructor(message: string, statusCode?: number, cause?: unknown);
|
|
34
|
-
toJSON(): {
|
|
40
|
+
toJSON(): {
|
|
41
|
+
name: string
|
|
42
|
+
code: string
|
|
43
|
+
message: string
|
|
44
|
+
stack: string | undefined
|
|
45
|
+
cause: unknown
|
|
46
|
+
statusCode: number | undefined
|
|
47
|
+
};
|
|
35
48
|
}
|
|
36
49
|
/**
|
|
37
50
|
* Filter evaluation error
|
package/dist/src/errors.js
CHANGED
|
@@ -57,8 +57,13 @@ class WebhookDeliveryError extends StreamsError {
|
|
|
57
57
|
this.statusCode = statusCode;
|
|
58
58
|
}
|
|
59
59
|
toJSON() {
|
|
60
|
+
const base = super.toJSON();
|
|
60
61
|
return {
|
|
61
|
-
|
|
62
|
+
name: base.name,
|
|
63
|
+
code: base.code,
|
|
64
|
+
message: base.message,
|
|
65
|
+
stack: base.stack,
|
|
66
|
+
cause: base.cause,
|
|
62
67
|
statusCode: this.statusCode
|
|
63
68
|
};
|
|
64
69
|
}
|
|
@@ -103,5 +108,5 @@ export {
|
|
|
103
108
|
AuthenticationError
|
|
104
109
|
};
|
|
105
110
|
|
|
106
|
-
//# debugId=
|
|
111
|
+
//# debugId=B2131D43CC9905E264756E2164756E21
|
|
107
112
|
//# sourceMappingURL=errors.js.map
|
package/dist/src/errors.js.map
CHANGED
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/errors.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
5
|
-
"/**\n * Base error class for all Stacks Streams errors\n */\nexport class StreamsError extends Error {\n public code: string;\n public override cause?: unknown;\n\n constructor(\n code: string,\n message: string,\n cause?: unknown\n ) {\n super(message);\n this.code = code;\n this.cause = cause;\n this.name = this.constructor.name;\n Error.captureStackTrace?.(this, this.constructor);\n }\n\n toJSON() {\n return {\n name: this.name,\n code: this.code,\n message: this.message,\n stack: this.stack,\n cause: this.cause,\n };\n }\n}\n\n/**\n * Stream not found error\n */\nexport class StreamNotFoundError extends StreamsError {\n constructor(streamId: string) {\n super(\"STREAM_NOT_FOUND\", `Stream not found: ${streamId}`);\n }\n}\n\n/**\n * Validation error for invalid input\n */\nexport class ValidationError extends StreamsError {\n constructor(message: string, cause?: unknown) {\n super(\"VALIDATION_ERROR\", message, cause);\n }\n}\n\n/**\n * Database operation error\n */\nexport class DatabaseError extends StreamsError {\n constructor(message: string, cause?: unknown) {\n super(\"DATABASE_ERROR\", message, cause);\n }\n}\n\n/**\n * Webhook delivery error\n */\nexport class WebhookDeliveryError extends StreamsError {\n constructor(\n message: string,\n public statusCode?: number,\n cause?: unknown\n ) {\n super(\"WEBHOOK_DELIVERY_ERROR\", message, cause);\n }\n\n override toJSON() {\n return {\n
|
|
5
|
+
"/**\n * Base error class for all Stacks Streams errors\n */\nexport class StreamsError extends Error {\n public code: string;\n public override cause?: unknown;\n\n constructor(\n code: string,\n message: string,\n cause?: unknown\n ) {\n super(message);\n this.code = code;\n this.cause = cause;\n this.name = this.constructor.name;\n Error.captureStackTrace?.(this, this.constructor);\n }\n\n toJSON(): { name: string; code: string; message: string; stack: string | undefined; cause: unknown } {\n return {\n name: this.name,\n code: this.code,\n message: this.message,\n stack: this.stack,\n cause: this.cause,\n };\n }\n}\n\n/**\n * Stream not found error\n */\nexport class StreamNotFoundError extends StreamsError {\n constructor(streamId: string) {\n super(\"STREAM_NOT_FOUND\", `Stream not found: ${streamId}`);\n }\n}\n\n/**\n * Validation error for invalid input\n */\nexport class ValidationError extends StreamsError {\n constructor(message: string, cause?: unknown) {\n super(\"VALIDATION_ERROR\", message, cause);\n }\n}\n\n/**\n * Database operation error\n */\nexport class DatabaseError extends StreamsError {\n constructor(message: string, cause?: unknown) {\n super(\"DATABASE_ERROR\", message, cause);\n }\n}\n\n/**\n * Webhook delivery error\n */\nexport class WebhookDeliveryError extends StreamsError {\n constructor(\n message: string,\n public statusCode?: number,\n cause?: unknown\n ) {\n super(\"WEBHOOK_DELIVERY_ERROR\", message, cause);\n }\n\n override toJSON(): { name: string; code: string; message: string; stack: string | undefined; cause: unknown; statusCode: number | undefined } {\n const base = super.toJSON();\n return {\n name: base.name,\n code: base.code,\n message: base.message,\n stack: base.stack,\n cause: base.cause,\n statusCode: this.statusCode,\n };\n }\n}\n\n/**\n * Filter evaluation error\n */\nexport class FilterEvaluationError extends StreamsError {\n constructor(message: string, cause?: unknown) {\n super(\"FILTER_EVALUATION_ERROR\", message, cause);\n }\n}\n\nexport class AuthenticationError extends StreamsError {\n constructor(message: string) {\n super(\"AUTHENTICATION_ERROR\", message);\n }\n}\n\nexport class AuthorizationError extends StreamsError {\n constructor(message: string) {\n super(\"AUTHORIZATION_ERROR\", message);\n }\n}\n\nexport class RateLimitError extends StreamsError {\n constructor(message: string) {\n super(\"RATE_LIMIT_ERROR\", message);\n }\n}\n\n/**\n * Safely extract error message from unknown error value\n */\nexport function getErrorMessage(err: unknown): string {\n return err instanceof Error ? err.message : String(err);\n}\n"
|
|
6
6
|
],
|
|
7
|
-
"mappings": ";;;;;;;;;;;;;AAGO,MAAM,qBAAqB,MAAM;AAAA,EAC/B;AAAA,EACS;AAAA,EAEhB,WAAW,CACT,MACA,SACA,OACA;AAAA,IACA,MAAM,OAAO;AAAA,IACb,KAAK,OAAO;AAAA,IACZ,KAAK,QAAQ;AAAA,IACb,KAAK,OAAO,KAAK,YAAY;AAAA,IAC7B,MAAM,oBAAoB,MAAM,KAAK,WAAW;AAAA;AAAA,EAGlD,MAAM,
|
|
8
|
-
"debugId": "
|
|
7
|
+
"mappings": ";;;;;;;;;;;;;AAGO,MAAM,qBAAqB,MAAM;AAAA,EAC/B;AAAA,EACS;AAAA,EAEhB,WAAW,CACT,MACA,SACA,OACA;AAAA,IACA,MAAM,OAAO;AAAA,IACb,KAAK,OAAO;AAAA,IACZ,KAAK,QAAQ;AAAA,IACb,KAAK,OAAO,KAAK,YAAY;AAAA,IAC7B,MAAM,oBAAoB,MAAM,KAAK,WAAW;AAAA;AAAA,EAGlD,MAAM,GAA+F;AAAA,IACnG,OAAO;AAAA,MACL,MAAM,KAAK;AAAA,MACX,MAAM,KAAK;AAAA,MACX,SAAS,KAAK;AAAA,MACd,OAAO,KAAK;AAAA,MACZ,OAAO,KAAK;AAAA,IACd;AAAA;AAEJ;AAAA;AAKO,MAAM,4BAA4B,aAAa;AAAA,EACpD,WAAW,CAAC,UAAkB;AAAA,IAC5B,MAAM,oBAAoB,qBAAqB,UAAU;AAAA;AAE7D;AAAA;AAKO,MAAM,wBAAwB,aAAa;AAAA,EAChD,WAAW,CAAC,SAAiB,OAAiB;AAAA,IAC5C,MAAM,oBAAoB,SAAS,KAAK;AAAA;AAE5C;AAAA;AAKO,MAAM,sBAAsB,aAAa;AAAA,EAC9C,WAAW,CAAC,SAAiB,OAAiB;AAAA,IAC5C,MAAM,kBAAkB,SAAS,KAAK;AAAA;AAE1C;AAAA;AAKO,MAAM,6BAA6B,aAAa;AAAA,EAG5C;AAAA,EAFT,WAAW,CACT,SACO,YACP,OACA;AAAA,IACA,MAAM,0BAA0B,SAAS,KAAK;AAAA,IAHvC;AAAA;AAAA,EAMA,MAAM,GAA+H;AAAA,IAC5I,MAAM,OAAO,MAAM,OAAO;AAAA,IAC1B,OAAO;AAAA,MACL,MAAM,KAAK;AAAA,MACX,MAAM,KAAK;AAAA,MACX,SAAS,KAAK;AAAA,MACd,OAAO,KAAK;AAAA,MACZ,OAAO,KAAK;AAAA,MACZ,YAAY,KAAK;AAAA,IACnB;AAAA;AAEJ;AAAA;AAKO,MAAM,8BAA8B,aAAa;AAAA,EACtD,WAAW,CAAC,SAAiB,OAAiB;AAAA,IAC5C,MAAM,2BAA2B,SAAS,KAAK;AAAA;AAEnD;AAAA;AAEO,MAAM,4BAA4B,aAAa;AAAA,EACpD,WAAW,CAAC,SAAiB;AAAA,IAC3B,MAAM,wBAAwB,OAAO;AAAA;AAEzC;AAAA;AAEO,MAAM,2BAA2B,aAAa;AAAA,EACnD,WAAW,CAAC,SAAiB;AAAA,IAC3B,MAAM,uBAAuB,OAAO;AAAA;AAExC;AAAA;AAEO,MAAM,uBAAuB,aAAa;AAAA,EAC/C,WAAW,CAAC,SAAiB;AAAA,IAC3B,MAAM,oBAAoB,OAAO;AAAA;AAErC;AAKO,SAAS,eAAe,CAAC,KAAsB;AAAA,EACpD,OAAO,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAAA;",
|
|
8
|
+
"debugId": "B2131D43CC9905E264756E2164756E21",
|
|
9
9
|
"names": []
|
|
10
10
|
}
|