@secondlayer/shared 7.11.2 → 8.0.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 +0 -169
- package/dist/src/archive/semantic-digest-builder.d.ts +0 -169
- package/dist/src/coverage/index.d.ts +0 -169
- package/dist/src/crypto/secrets.js +22 -3
- package/dist/src/crypto/secrets.js.map +3 -3
- package/dist/src/db/index.d.ts +1 -211
- package/dist/src/db/index.js +22 -16
- package/dist/src/db/index.js.map +4 -4
- package/dist/src/db/queries/chain-reorgs.d.ts +0 -169
- package/dist/src/db/queries/chain-reorgs.js +22 -16
- package/dist/src/db/queries/chain-reorgs.js.map +4 -4
- package/dist/src/db/queries/contracts.d.ts +0 -169
- package/dist/src/db/queries/instance.d.ts +0 -169
- package/dist/src/db/queries/integrity.d.ts +0 -169
- package/dist/src/db/queries/subgraph-gaps.d.ts +0 -169
- package/dist/src/db/queries/subgraph-operations.d.ts +1 -170
- package/dist/src/db/queries/subgraph-operations.js +1 -15
- package/dist/src/db/queries/subgraph-operations.js.map +3 -3
- package/dist/src/db/queries/subgraphs.d.ts +1 -191
- package/dist/src/db/queries/subgraphs.js +30 -1068
- package/dist/src/db/queries/subgraphs.js.map +5 -12
- package/dist/src/db/queries/subscriptions.d.ts +0 -169
- package/dist/src/db/queries/subscriptions.js +22 -3
- package/dist/src/db/queries/subscriptions.js.map +3 -3
- package/dist/src/db/schema.d.ts +1 -198
- package/dist/src/errors.d.ts +1 -22
- package/dist/src/errors.js +2 -4
- package/dist/src/errors.js.map +3 -3
- package/dist/src/index.d.ts +5 -256
- package/dist/src/index.js +23 -20
- package/dist/src/index.js.map +6 -6
- package/dist/src/mode.d.ts +16 -2
- package/dist/src/mode.js +25 -4
- package/dist/src/mode.js.map +3 -3
- package/dist/src/node/local-client.d.ts +0 -169
- package/dist/src/schemas/index.d.ts +5 -25
- package/dist/src/schemas/index.js +1 -2
- package/dist/src/schemas/index.js.map +3 -3
- package/dist/src/schemas/subgraphs.d.ts +5 -25
- package/dist/src/schemas/subgraphs.js +1 -2
- package/dist/src/schemas/subgraphs.js.map +3 -3
- package/dist/src/streams-rows/index.d.ts +399 -0
- package/dist/src/streams-rows/index.js +336 -0
- package/dist/src/streams-rows/index.js.map +17 -0
- package/dist/src/subgraphs/spec.d.ts +0 -9
- package/migrations/0118_drop_retired_control_tables.ts +53 -0
- package/migrations/0119_drop_accounts_plan.ts +29 -0
- package/package.json +5 -1
|
@@ -14,139 +14,34 @@ var __export = (target, all) => {
|
|
|
14
14
|
});
|
|
15
15
|
};
|
|
16
16
|
|
|
17
|
-
// src/env.ts
|
|
18
|
-
import { z } from "zod";
|
|
19
|
-
var networksSchema = z.string().transform((val) => {
|
|
20
|
-
const networks = val.split(",").map((n) => n.trim()).filter(Boolean);
|
|
21
|
-
const valid = ["mainnet", "testnet"];
|
|
22
|
-
for (const n of networks) {
|
|
23
|
-
if (!valid.includes(n)) {
|
|
24
|
-
throw new Error(`Invalid network: ${n}. Must be one of: ${valid.join(", ")}`);
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
return networks;
|
|
28
|
-
});
|
|
29
|
-
var envSchema = z.object({
|
|
30
|
-
DATABASE_URL: z.preprocess((val) => typeof val === "string" && val.length === 0 ? undefined : val, z.string().url().optional()),
|
|
31
|
-
SOURCE_DATABASE_URL: z.preprocess((val) => typeof val === "string" && val.length === 0 ? undefined : val, z.string().url().optional()),
|
|
32
|
-
TARGET_DATABASE_URL: z.preprocess((val) => typeof val === "string" && val.length === 0 ? undefined : val, z.string().url().optional()),
|
|
33
|
-
NETWORK: z.enum(["mainnet", "testnet"]).optional(),
|
|
34
|
-
NETWORKS: networksSchema.optional(),
|
|
35
|
-
LOG_LEVEL: z.enum(["debug", "info", "warn", "error"]).default("info"),
|
|
36
|
-
NODE_ENV: z.enum(["development", "production", "test"]).default("development")
|
|
37
|
-
});
|
|
38
|
-
var cachedEnv = null;
|
|
39
|
-
function getEnv() {
|
|
40
|
-
if (cachedEnv) {
|
|
41
|
-
return cachedEnv;
|
|
42
|
-
}
|
|
43
|
-
const result = envSchema.safeParse(process.env);
|
|
44
|
-
if (!result.success) {
|
|
45
|
-
console.error("❌ Invalid environment configuration:");
|
|
46
|
-
console.error(z.treeifyError(result.error));
|
|
47
|
-
throw new Error("Invalid environment configuration");
|
|
48
|
-
}
|
|
49
|
-
let enabledNetworks;
|
|
50
|
-
if (result.data.NETWORKS && result.data.NETWORKS.length > 0) {
|
|
51
|
-
enabledNetworks = result.data.NETWORKS;
|
|
52
|
-
} else if (result.data.NETWORK) {
|
|
53
|
-
enabledNetworks = [result.data.NETWORK];
|
|
54
|
-
} else {
|
|
55
|
-
enabledNetworks = ["mainnet"];
|
|
56
|
-
}
|
|
57
|
-
cachedEnv = { ...result.data, enabledNetworks };
|
|
58
|
-
return cachedEnv;
|
|
59
|
-
}
|
|
60
|
-
function isProductionEnv() {
|
|
61
|
-
return process.env["NODE_ENV"] === "production";
|
|
62
|
-
}
|
|
63
|
-
function isPox4DecoderEnabled() {
|
|
64
|
-
return process.env.POX4_DECODER_ENABLED !== "false";
|
|
65
|
-
}
|
|
66
|
-
function isPox5DecoderEnabled() {
|
|
67
|
-
return process.env.POX5_DECODER_ENABLED !== "false";
|
|
68
|
-
}
|
|
69
|
-
// src/logger.ts
|
|
70
|
-
var LOG_LEVELS = {
|
|
71
|
-
debug: 0,
|
|
72
|
-
info: 1,
|
|
73
|
-
warn: 2,
|
|
74
|
-
error: 3
|
|
75
|
-
};
|
|
76
|
-
|
|
77
|
-
class Logger {
|
|
78
|
-
_level;
|
|
79
|
-
_isProduction;
|
|
80
|
-
_initialized = false;
|
|
81
|
-
init() {
|
|
82
|
-
if (this._initialized)
|
|
83
|
-
return;
|
|
84
|
-
this._initialized = true;
|
|
85
|
-
try {
|
|
86
|
-
const env = getEnv();
|
|
87
|
-
this._level = env.LOG_LEVEL;
|
|
88
|
-
this._isProduction = env.NODE_ENV === "production";
|
|
89
|
-
} catch {
|
|
90
|
-
this._level = "info";
|
|
91
|
-
this._isProduction = false;
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
get level() {
|
|
95
|
-
this.init();
|
|
96
|
-
return this._level;
|
|
97
|
-
}
|
|
98
|
-
get isProduction() {
|
|
99
|
-
this.init();
|
|
100
|
-
return this._isProduction;
|
|
101
|
-
}
|
|
102
|
-
shouldLog(level) {
|
|
103
|
-
return LOG_LEVELS[level] >= LOG_LEVELS[this.level];
|
|
104
|
-
}
|
|
105
|
-
formatMessage(level, message, meta) {
|
|
106
|
-
const timestamp = new Date().toISOString();
|
|
107
|
-
if (this.isProduction) {
|
|
108
|
-
return JSON.stringify({
|
|
109
|
-
timestamp,
|
|
110
|
-
level,
|
|
111
|
-
message,
|
|
112
|
-
...meta
|
|
113
|
-
});
|
|
114
|
-
}
|
|
115
|
-
const metaStr = meta ? ` ${JSON.stringify(meta)}` : "";
|
|
116
|
-
return `[${timestamp}] ${level.toUpperCase()}: ${message}${metaStr}`;
|
|
117
|
-
}
|
|
118
|
-
debug(message, meta) {
|
|
119
|
-
if (this.shouldLog("debug")) {
|
|
120
|
-
console.debug(this.formatMessage("debug", message, meta));
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
info(message, meta) {
|
|
124
|
-
if (this.shouldLog("info")) {
|
|
125
|
-
console.info(this.formatMessage("info", message, meta));
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
warn(message, meta) {
|
|
129
|
-
if (this.shouldLog("warn")) {
|
|
130
|
-
console.warn(this.formatMessage("warn", message, meta));
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
error(message, meta) {
|
|
134
|
-
if (this.shouldLog("error")) {
|
|
135
|
-
console.error(this.formatMessage("error", message, meta));
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
var logger = new Logger;
|
|
140
|
-
|
|
141
17
|
// src/mode.ts
|
|
142
|
-
var VALID_MODES = [
|
|
143
|
-
|
|
18
|
+
var VALID_MODES = [
|
|
19
|
+
"oss",
|
|
20
|
+
"platform",
|
|
21
|
+
"archive"
|
|
22
|
+
];
|
|
23
|
+
function declaredMode() {
|
|
144
24
|
const raw = process.env.INSTANCE_MODE?.trim().toLowerCase();
|
|
145
25
|
if (raw && VALID_MODES.includes(raw)) {
|
|
146
26
|
return raw;
|
|
147
27
|
}
|
|
148
28
|
return "oss";
|
|
149
29
|
}
|
|
30
|
+
function getInstanceMode() {
|
|
31
|
+
const declared = declaredMode();
|
|
32
|
+
return declared === "archive" ? "platform" : declared;
|
|
33
|
+
}
|
|
34
|
+
function getDeclaredInstanceMode() {
|
|
35
|
+
return declaredMode();
|
|
36
|
+
}
|
|
37
|
+
function isMeteredReads() {
|
|
38
|
+
const override = process.env.METERED_READS?.trim().toLowerCase();
|
|
39
|
+
if (override === "true")
|
|
40
|
+
return true;
|
|
41
|
+
if (override === "false")
|
|
42
|
+
return false;
|
|
43
|
+
return getInstanceMode() === "platform";
|
|
44
|
+
}
|
|
150
45
|
function isPlatformMode() {
|
|
151
46
|
return getInstanceMode() === "platform";
|
|
152
47
|
}
|
|
@@ -171,934 +66,8 @@ function parseJsonb(value) {
|
|
|
171
66
|
return value ?? {};
|
|
172
67
|
}
|
|
173
68
|
|
|
174
|
-
// src/db/index.ts
|
|
175
|
-
import { Kysely } from "kysely";
|
|
176
|
-
import { PostgresJSDialect } from "kysely-postgres-js";
|
|
177
|
-
import postgres from "postgres";
|
|
178
|
-
import { sql as sql2 } from "kysely";
|
|
179
|
-
|
|
180
|
-
// src/db/source-read-columns.ts
|
|
181
|
-
var SOURCE_READ_COLUMNS = {
|
|
182
|
-
blocks: [
|
|
183
|
-
"burn_block_hash",
|
|
184
|
-
"burn_block_height",
|
|
185
|
-
"canonical",
|
|
186
|
-
"hash",
|
|
187
|
-
"height",
|
|
188
|
-
"parent_hash",
|
|
189
|
-
"timestamp"
|
|
190
|
-
],
|
|
191
|
-
decoded_events: [
|
|
192
|
-
"amount",
|
|
193
|
-
"asset_identifier",
|
|
194
|
-
"block_height",
|
|
195
|
-
"canonical",
|
|
196
|
-
"contract_id",
|
|
197
|
-
"cursor",
|
|
198
|
-
"event_index",
|
|
199
|
-
"event_type",
|
|
200
|
-
"memo",
|
|
201
|
-
"payload",
|
|
202
|
-
"recipient",
|
|
203
|
-
"sender",
|
|
204
|
-
"tx_id",
|
|
205
|
-
"tx_index",
|
|
206
|
-
"value"
|
|
207
|
-
],
|
|
208
|
-
transactions: [
|
|
209
|
-
"block_height",
|
|
210
|
-
"contract_id",
|
|
211
|
-
"function_args",
|
|
212
|
-
"function_name",
|
|
213
|
-
"raw_result",
|
|
214
|
-
"raw_tx",
|
|
215
|
-
"sender",
|
|
216
|
-
"status",
|
|
217
|
-
"tx_id",
|
|
218
|
-
"tx_index",
|
|
219
|
-
"type"
|
|
220
|
-
],
|
|
221
|
-
mempool_transactions: [
|
|
222
|
-
"contract_id",
|
|
223
|
-
"function_args",
|
|
224
|
-
"function_name",
|
|
225
|
-
"raw_tx",
|
|
226
|
-
"received_at",
|
|
227
|
-
"sender",
|
|
228
|
-
"seq",
|
|
229
|
-
"tx_id",
|
|
230
|
-
"type"
|
|
231
|
-
],
|
|
232
|
-
pox4_calls: [
|
|
233
|
-
"aggregated_amount_ustx",
|
|
234
|
-
"aggregated_signer_index",
|
|
235
|
-
"amount_ustx",
|
|
236
|
-
"auth_allowed",
|
|
237
|
-
"auth_id",
|
|
238
|
-
"auth_period",
|
|
239
|
-
"auth_topic",
|
|
240
|
-
"block_height",
|
|
241
|
-
"block_time",
|
|
242
|
-
"burn_block_height",
|
|
243
|
-
"caller",
|
|
244
|
-
"canonical",
|
|
245
|
-
"cursor",
|
|
246
|
-
"delegate_to",
|
|
247
|
-
"end_cycle",
|
|
248
|
-
"function_name",
|
|
249
|
-
"lock_period",
|
|
250
|
-
"max_amount",
|
|
251
|
-
"pox_addr_btc",
|
|
252
|
-
"pox_addr_hashbytes",
|
|
253
|
-
"pox_addr_version",
|
|
254
|
-
"result_ok",
|
|
255
|
-
"reward_cycle",
|
|
256
|
-
"signer_key",
|
|
257
|
-
"signer_signature",
|
|
258
|
-
"source_cursor",
|
|
259
|
-
"stacker",
|
|
260
|
-
"start_cycle",
|
|
261
|
-
"tx_id",
|
|
262
|
-
"tx_index"
|
|
263
|
-
],
|
|
264
|
-
pox5_events: [
|
|
265
|
-
"amount_sats",
|
|
266
|
-
"amount_ustx",
|
|
267
|
-
"block_height",
|
|
268
|
-
"block_time",
|
|
269
|
-
"bond_index",
|
|
270
|
-
"canonical",
|
|
271
|
-
"cursor",
|
|
272
|
-
"data",
|
|
273
|
-
"event_index",
|
|
274
|
-
"first_reward_cycle",
|
|
275
|
-
"is_l1_lock",
|
|
276
|
-
"reward_cycle",
|
|
277
|
-
"signer",
|
|
278
|
-
"signer_key",
|
|
279
|
-
"signer_manager",
|
|
280
|
-
"staker",
|
|
281
|
-
"topic",
|
|
282
|
-
"tx_id",
|
|
283
|
-
"tx_index",
|
|
284
|
-
"unlock_burn_height",
|
|
285
|
-
"unlock_cycle"
|
|
286
|
-
],
|
|
287
|
-
sbtc_events: [
|
|
288
|
-
"amount",
|
|
289
|
-
"bitcoin_txid",
|
|
290
|
-
"block_height",
|
|
291
|
-
"block_time",
|
|
292
|
-
"burn_hash",
|
|
293
|
-
"burn_height",
|
|
294
|
-
"canonical",
|
|
295
|
-
"cursor",
|
|
296
|
-
"event_index",
|
|
297
|
-
"fee",
|
|
298
|
-
"governance_contract_type",
|
|
299
|
-
"governance_new_contract",
|
|
300
|
-
"max_fee",
|
|
301
|
-
"output_index",
|
|
302
|
-
"recipient_btc_hashbytes",
|
|
303
|
-
"recipient_btc_version",
|
|
304
|
-
"request_id",
|
|
305
|
-
"sender",
|
|
306
|
-
"signer_address",
|
|
307
|
-
"signer_aggregate_pubkey",
|
|
308
|
-
"signer_bitmap",
|
|
309
|
-
"signer_keys_count",
|
|
310
|
-
"signer_threshold",
|
|
311
|
-
"sweep_txid",
|
|
312
|
-
"topic",
|
|
313
|
-
"tx_id",
|
|
314
|
-
"tx_index"
|
|
315
|
-
],
|
|
316
|
-
sbtc_token_events: [
|
|
317
|
-
"amount",
|
|
318
|
-
"block_height",
|
|
319
|
-
"block_time",
|
|
320
|
-
"canonical",
|
|
321
|
-
"cursor",
|
|
322
|
-
"event_index",
|
|
323
|
-
"event_type",
|
|
324
|
-
"memo",
|
|
325
|
-
"recipient",
|
|
326
|
-
"sender",
|
|
327
|
-
"tx_id",
|
|
328
|
-
"tx_index"
|
|
329
|
-
],
|
|
330
|
-
bns_name_events: [
|
|
331
|
-
"block_height",
|
|
332
|
-
"block_time",
|
|
333
|
-
"bns_id",
|
|
334
|
-
"canonical",
|
|
335
|
-
"cursor",
|
|
336
|
-
"event_index",
|
|
337
|
-
"fqn",
|
|
338
|
-
"hashed_salted_fqn_preorder",
|
|
339
|
-
"imported_at",
|
|
340
|
-
"name",
|
|
341
|
-
"namespace",
|
|
342
|
-
"owner",
|
|
343
|
-
"preordered_by",
|
|
344
|
-
"registered_at",
|
|
345
|
-
"renewal_height",
|
|
346
|
-
"stx_burn",
|
|
347
|
-
"topic",
|
|
348
|
-
"tx_id",
|
|
349
|
-
"tx_index"
|
|
350
|
-
],
|
|
351
|
-
bns_namespace_events: [
|
|
352
|
-
"block_height",
|
|
353
|
-
"block_time",
|
|
354
|
-
"canonical",
|
|
355
|
-
"cursor",
|
|
356
|
-
"event_index",
|
|
357
|
-
"launched_at",
|
|
358
|
-
"lifetime",
|
|
359
|
-
"manager",
|
|
360
|
-
"manager_frozen",
|
|
361
|
-
"manager_transfers_disabled",
|
|
362
|
-
"namespace",
|
|
363
|
-
"price_frozen",
|
|
364
|
-
"price_function",
|
|
365
|
-
"revealed_at",
|
|
366
|
-
"status",
|
|
367
|
-
"tx_id",
|
|
368
|
-
"tx_index"
|
|
369
|
-
],
|
|
370
|
-
bns_marketplace_events: [
|
|
371
|
-
"action",
|
|
372
|
-
"block_height",
|
|
373
|
-
"block_time",
|
|
374
|
-
"bns_id",
|
|
375
|
-
"canonical",
|
|
376
|
-
"commission",
|
|
377
|
-
"cursor",
|
|
378
|
-
"event_index",
|
|
379
|
-
"price_ustx",
|
|
380
|
-
"tx_id",
|
|
381
|
-
"tx_index"
|
|
382
|
-
],
|
|
383
|
-
bns_names: [
|
|
384
|
-
"bns_id",
|
|
385
|
-
"fqn",
|
|
386
|
-
"last_event_at",
|
|
387
|
-
"last_event_cursor",
|
|
388
|
-
"name",
|
|
389
|
-
"namespace",
|
|
390
|
-
"owner",
|
|
391
|
-
"registered_at",
|
|
392
|
-
"renewal_height"
|
|
393
|
-
],
|
|
394
|
-
bns_namespaces: [
|
|
395
|
-
"last_event_at",
|
|
396
|
-
"last_event_cursor",
|
|
397
|
-
"launched_at",
|
|
398
|
-
"lifetime",
|
|
399
|
-
"manager",
|
|
400
|
-
"manager_frozen",
|
|
401
|
-
"name_count",
|
|
402
|
-
"namespace",
|
|
403
|
-
"price_frozen"
|
|
404
|
-
],
|
|
405
|
-
burn_block_rewards: [
|
|
406
|
-
"amount_sats",
|
|
407
|
-
"burn_amount",
|
|
408
|
-
"burn_block_hash",
|
|
409
|
-
"burn_block_height",
|
|
410
|
-
"cursor",
|
|
411
|
-
"recipient_btc",
|
|
412
|
-
"reward_index"
|
|
413
|
-
],
|
|
414
|
-
burn_block_reward_slots: [
|
|
415
|
-
"burn_block_hash",
|
|
416
|
-
"burn_block_height",
|
|
417
|
-
"cursor",
|
|
418
|
-
"holder_btc",
|
|
419
|
-
"slot_index"
|
|
420
|
-
],
|
|
421
|
-
events: ["block_height", "data", "event_index", "tx_id", "type"],
|
|
422
|
-
chain_reorgs: ["detected_at"]
|
|
423
|
-
};
|
|
424
|
-
var SOURCE_READ_TYPES = {
|
|
425
|
-
blocks: {
|
|
426
|
-
burn_block_hash: { type: "text", nullable: true },
|
|
427
|
-
burn_block_height: { type: "int" },
|
|
428
|
-
canonical: { type: "boolean" },
|
|
429
|
-
hash: { type: "text" },
|
|
430
|
-
height: { type: "int" },
|
|
431
|
-
parent_hash: { type: "text" },
|
|
432
|
-
timestamp: { type: "int" }
|
|
433
|
-
},
|
|
434
|
-
decoded_events: {
|
|
435
|
-
amount: { type: "text", nullable: true },
|
|
436
|
-
asset_identifier: { type: "text", nullable: true },
|
|
437
|
-
block_height: { type: "int" },
|
|
438
|
-
canonical: { type: "boolean" },
|
|
439
|
-
contract_id: { type: "text", nullable: true },
|
|
440
|
-
cursor: { type: "text" },
|
|
441
|
-
event_index: { type: "int" },
|
|
442
|
-
event_type: { type: "text" },
|
|
443
|
-
memo: { type: "text", nullable: true },
|
|
444
|
-
payload: { type: "jsonb", nullable: true },
|
|
445
|
-
recipient: { type: "text", nullable: true },
|
|
446
|
-
sender: { type: "text", nullable: true },
|
|
447
|
-
tx_id: { type: "text" },
|
|
448
|
-
tx_index: { type: "int" },
|
|
449
|
-
value: { type: "text", nullable: true }
|
|
450
|
-
},
|
|
451
|
-
transactions: {
|
|
452
|
-
block_height: { type: "int" },
|
|
453
|
-
contract_id: { type: "text", nullable: true },
|
|
454
|
-
function_args: { type: "jsonb", nullable: true },
|
|
455
|
-
function_name: { type: "text", nullable: true },
|
|
456
|
-
raw_result: { type: "text", nullable: true },
|
|
457
|
-
raw_tx: { type: "text" },
|
|
458
|
-
sender: { type: "text" },
|
|
459
|
-
status: { type: "text" },
|
|
460
|
-
tx_id: { type: "text" },
|
|
461
|
-
tx_index: { type: "int" },
|
|
462
|
-
type: { type: "text" }
|
|
463
|
-
},
|
|
464
|
-
mempool_transactions: {
|
|
465
|
-
contract_id: { type: "text", nullable: true },
|
|
466
|
-
function_args: { type: "jsonb", nullable: true },
|
|
467
|
-
function_name: { type: "text", nullable: true },
|
|
468
|
-
raw_tx: { type: "text" },
|
|
469
|
-
received_at: { type: "timestamp" },
|
|
470
|
-
sender: { type: "text" },
|
|
471
|
-
seq: { type: "text" },
|
|
472
|
-
tx_id: { type: "text" },
|
|
473
|
-
type: { type: "text" }
|
|
474
|
-
},
|
|
475
|
-
pox4_calls: {
|
|
476
|
-
aggregated_amount_ustx: { type: "text", nullable: true },
|
|
477
|
-
aggregated_signer_index: { type: "int", nullable: true },
|
|
478
|
-
amount_ustx: { type: "text", nullable: true },
|
|
479
|
-
auth_allowed: { type: "boolean", nullable: true },
|
|
480
|
-
auth_id: { type: "text", nullable: true },
|
|
481
|
-
auth_period: { type: "int", nullable: true },
|
|
482
|
-
auth_topic: { type: "text", nullable: true },
|
|
483
|
-
block_height: { type: "int" },
|
|
484
|
-
block_time: { type: "timestamp" },
|
|
485
|
-
burn_block_height: { type: "int" },
|
|
486
|
-
caller: { type: "text" },
|
|
487
|
-
canonical: { type: "boolean" },
|
|
488
|
-
cursor: { type: "text" },
|
|
489
|
-
delegate_to: { type: "text", nullable: true },
|
|
490
|
-
end_cycle: { type: "int", nullable: true },
|
|
491
|
-
function_name: { type: "text" },
|
|
492
|
-
lock_period: { type: "int", nullable: true },
|
|
493
|
-
max_amount: { type: "text", nullable: true },
|
|
494
|
-
pox_addr_btc: { type: "text", nullable: true },
|
|
495
|
-
pox_addr_hashbytes: { type: "text", nullable: true },
|
|
496
|
-
pox_addr_version: { type: "int", nullable: true },
|
|
497
|
-
result_ok: { type: "boolean" },
|
|
498
|
-
reward_cycle: { type: "int", nullable: true },
|
|
499
|
-
signer_key: { type: "text", nullable: true },
|
|
500
|
-
signer_signature: { type: "text", nullable: true },
|
|
501
|
-
source_cursor: { type: "text" },
|
|
502
|
-
stacker: { type: "text", nullable: true },
|
|
503
|
-
start_cycle: { type: "int", nullable: true },
|
|
504
|
-
tx_id: { type: "text" },
|
|
505
|
-
tx_index: { type: "int" }
|
|
506
|
-
},
|
|
507
|
-
pox5_events: {
|
|
508
|
-
amount_sats: { type: "text", nullable: true },
|
|
509
|
-
amount_ustx: { type: "text", nullable: true },
|
|
510
|
-
block_height: { type: "int" },
|
|
511
|
-
block_time: { type: "timestamp" },
|
|
512
|
-
bond_index: { type: "int", nullable: true },
|
|
513
|
-
canonical: { type: "boolean" },
|
|
514
|
-
cursor: { type: "text" },
|
|
515
|
-
data: { type: "jsonb", nullable: true },
|
|
516
|
-
event_index: { type: "int" },
|
|
517
|
-
first_reward_cycle: { type: "int", nullable: true },
|
|
518
|
-
is_l1_lock: { type: "boolean", nullable: true },
|
|
519
|
-
reward_cycle: { type: "int", nullable: true },
|
|
520
|
-
signer: { type: "text", nullable: true },
|
|
521
|
-
signer_key: { type: "text", nullable: true },
|
|
522
|
-
signer_manager: { type: "text", nullable: true },
|
|
523
|
-
staker: { type: "text", nullable: true },
|
|
524
|
-
topic: { type: "text" },
|
|
525
|
-
tx_id: { type: "text" },
|
|
526
|
-
tx_index: { type: "int" },
|
|
527
|
-
unlock_burn_height: { type: "int", nullable: true },
|
|
528
|
-
unlock_cycle: { type: "int", nullable: true }
|
|
529
|
-
},
|
|
530
|
-
sbtc_events: {
|
|
531
|
-
amount: { type: "text", nullable: true },
|
|
532
|
-
bitcoin_txid: { type: "text", nullable: true },
|
|
533
|
-
block_height: { type: "int" },
|
|
534
|
-
block_time: { type: "timestamp" },
|
|
535
|
-
burn_hash: { type: "text", nullable: true },
|
|
536
|
-
burn_height: { type: "int", nullable: true },
|
|
537
|
-
canonical: { type: "boolean" },
|
|
538
|
-
cursor: { type: "text" },
|
|
539
|
-
event_index: { type: "int" },
|
|
540
|
-
fee: { type: "text", nullable: true },
|
|
541
|
-
governance_contract_type: { type: "int", nullable: true },
|
|
542
|
-
governance_new_contract: { type: "text", nullable: true },
|
|
543
|
-
max_fee: { type: "text", nullable: true },
|
|
544
|
-
output_index: { type: "int", nullable: true },
|
|
545
|
-
recipient_btc_hashbytes: { type: "text", nullable: true },
|
|
546
|
-
recipient_btc_version: { type: "int", nullable: true },
|
|
547
|
-
request_id: { type: "int", nullable: true },
|
|
548
|
-
sender: { type: "text", nullable: true },
|
|
549
|
-
signer_address: { type: "text", nullable: true },
|
|
550
|
-
signer_aggregate_pubkey: { type: "text", nullable: true },
|
|
551
|
-
signer_bitmap: { type: "text", nullable: true },
|
|
552
|
-
signer_keys_count: { type: "int", nullable: true },
|
|
553
|
-
signer_threshold: { type: "int", nullable: true },
|
|
554
|
-
sweep_txid: { type: "text", nullable: true },
|
|
555
|
-
topic: { type: "text" },
|
|
556
|
-
tx_id: { type: "text" },
|
|
557
|
-
tx_index: { type: "int" }
|
|
558
|
-
},
|
|
559
|
-
sbtc_token_events: {
|
|
560
|
-
amount: { type: "text" },
|
|
561
|
-
block_height: { type: "int" },
|
|
562
|
-
block_time: { type: "timestamp" },
|
|
563
|
-
canonical: { type: "boolean" },
|
|
564
|
-
cursor: { type: "text" },
|
|
565
|
-
event_index: { type: "int" },
|
|
566
|
-
event_type: { type: "text" },
|
|
567
|
-
memo: { type: "text", nullable: true },
|
|
568
|
-
recipient: { type: "text", nullable: true },
|
|
569
|
-
sender: { type: "text", nullable: true },
|
|
570
|
-
tx_id: { type: "text" },
|
|
571
|
-
tx_index: { type: "int" }
|
|
572
|
-
},
|
|
573
|
-
bns_name_events: {
|
|
574
|
-
block_height: { type: "int" },
|
|
575
|
-
block_time: { type: "timestamp" },
|
|
576
|
-
bns_id: { type: "text" },
|
|
577
|
-
canonical: { type: "boolean" },
|
|
578
|
-
cursor: { type: "text" },
|
|
579
|
-
event_index: { type: "int" },
|
|
580
|
-
fqn: { type: "text" },
|
|
581
|
-
hashed_salted_fqn_preorder: { type: "text", nullable: true },
|
|
582
|
-
imported_at: { type: "int", nullable: true },
|
|
583
|
-
name: { type: "text" },
|
|
584
|
-
namespace: { type: "text" },
|
|
585
|
-
owner: { type: "text", nullable: true },
|
|
586
|
-
preordered_by: { type: "text", nullable: true },
|
|
587
|
-
registered_at: { type: "int", nullable: true },
|
|
588
|
-
renewal_height: { type: "int", nullable: true },
|
|
589
|
-
stx_burn: { type: "text", nullable: true },
|
|
590
|
-
topic: { type: "text" },
|
|
591
|
-
tx_id: { type: "text" },
|
|
592
|
-
tx_index: { type: "int" }
|
|
593
|
-
},
|
|
594
|
-
bns_namespace_events: {
|
|
595
|
-
block_height: { type: "int" },
|
|
596
|
-
block_time: { type: "timestamp" },
|
|
597
|
-
canonical: { type: "boolean" },
|
|
598
|
-
cursor: { type: "text" },
|
|
599
|
-
event_index: { type: "int" },
|
|
600
|
-
launched_at: { type: "int", nullable: true },
|
|
601
|
-
lifetime: { type: "int", nullable: true },
|
|
602
|
-
manager: { type: "text", nullable: true },
|
|
603
|
-
manager_frozen: { type: "boolean", nullable: true },
|
|
604
|
-
manager_transfers_disabled: { type: "boolean", nullable: true },
|
|
605
|
-
namespace: { type: "text" },
|
|
606
|
-
price_frozen: { type: "boolean", nullable: true },
|
|
607
|
-
price_function: { type: "text", nullable: true },
|
|
608
|
-
revealed_at: { type: "int", nullable: true },
|
|
609
|
-
status: { type: "text" },
|
|
610
|
-
tx_id: { type: "text" },
|
|
611
|
-
tx_index: { type: "int" }
|
|
612
|
-
},
|
|
613
|
-
bns_marketplace_events: {
|
|
614
|
-
action: { type: "text" },
|
|
615
|
-
block_height: { type: "int" },
|
|
616
|
-
block_time: { type: "timestamp" },
|
|
617
|
-
bns_id: { type: "text" },
|
|
618
|
-
canonical: { type: "boolean" },
|
|
619
|
-
commission: { type: "text", nullable: true },
|
|
620
|
-
cursor: { type: "text" },
|
|
621
|
-
event_index: { type: "int" },
|
|
622
|
-
price_ustx: { type: "text", nullable: true },
|
|
623
|
-
tx_id: { type: "text" },
|
|
624
|
-
tx_index: { type: "int" }
|
|
625
|
-
},
|
|
626
|
-
bns_names: {
|
|
627
|
-
bns_id: { type: "text" },
|
|
628
|
-
fqn: { type: "text" },
|
|
629
|
-
last_event_at: { type: "timestamp" },
|
|
630
|
-
last_event_cursor: { type: "text" },
|
|
631
|
-
name: { type: "text" },
|
|
632
|
-
namespace: { type: "text" },
|
|
633
|
-
owner: { type: "text" },
|
|
634
|
-
registered_at: { type: "int", nullable: true },
|
|
635
|
-
renewal_height: { type: "int", nullable: true }
|
|
636
|
-
},
|
|
637
|
-
bns_namespaces: {
|
|
638
|
-
last_event_at: { type: "timestamp" },
|
|
639
|
-
last_event_cursor: { type: "text" },
|
|
640
|
-
launched_at: { type: "int", nullable: true },
|
|
641
|
-
lifetime: { type: "int", nullable: true },
|
|
642
|
-
manager: { type: "text", nullable: true },
|
|
643
|
-
manager_frozen: { type: "boolean" },
|
|
644
|
-
name_count: { type: "int" },
|
|
645
|
-
namespace: { type: "text" },
|
|
646
|
-
price_frozen: { type: "boolean" }
|
|
647
|
-
},
|
|
648
|
-
burn_block_rewards: {
|
|
649
|
-
amount_sats: { type: "text" },
|
|
650
|
-
burn_amount: { type: "text" },
|
|
651
|
-
burn_block_hash: { type: "text" },
|
|
652
|
-
burn_block_height: { type: "int" },
|
|
653
|
-
cursor: { type: "text" },
|
|
654
|
-
recipient_btc: { type: "text" },
|
|
655
|
-
reward_index: { type: "int" }
|
|
656
|
-
},
|
|
657
|
-
burn_block_reward_slots: {
|
|
658
|
-
burn_block_hash: { type: "text" },
|
|
659
|
-
burn_block_height: { type: "int" },
|
|
660
|
-
cursor: { type: "text" },
|
|
661
|
-
holder_btc: { type: "text" },
|
|
662
|
-
slot_index: { type: "int" }
|
|
663
|
-
},
|
|
664
|
-
events: {
|
|
665
|
-
block_height: { type: "int" },
|
|
666
|
-
data: { type: "jsonb" },
|
|
667
|
-
event_index: { type: "int" },
|
|
668
|
-
tx_id: { type: "text" },
|
|
669
|
-
type: { type: "text" }
|
|
670
|
-
},
|
|
671
|
-
chain_reorgs: {
|
|
672
|
-
detected_at: { type: "timestamp" }
|
|
673
|
-
}
|
|
674
|
-
};
|
|
675
|
-
var SOURCE_READ_PKS = {
|
|
676
|
-
blocks: ["height"],
|
|
677
|
-
decoded_events: ["cursor"],
|
|
678
|
-
transactions: ["tx_id"],
|
|
679
|
-
mempool_transactions: ["seq"],
|
|
680
|
-
pox4_calls: ["cursor"],
|
|
681
|
-
pox5_events: ["cursor"],
|
|
682
|
-
sbtc_events: ["cursor"],
|
|
683
|
-
sbtc_token_events: ["cursor"],
|
|
684
|
-
bns_name_events: ["cursor"],
|
|
685
|
-
bns_namespace_events: ["cursor"],
|
|
686
|
-
bns_marketplace_events: ["cursor"],
|
|
687
|
-
bns_names: ["fqn"],
|
|
688
|
-
bns_namespaces: ["namespace"],
|
|
689
|
-
burn_block_rewards: ["cursor"],
|
|
690
|
-
burn_block_reward_slots: ["cursor"],
|
|
691
|
-
events: ["tx_id", "event_index"],
|
|
692
|
-
chain_reorgs: null
|
|
693
|
-
};
|
|
694
|
-
// src/db/migration-role.ts
|
|
695
|
-
var currentRole = "both";
|
|
696
|
-
function setMigrationRole(role) {
|
|
697
|
-
currentRole = role;
|
|
698
|
-
}
|
|
699
|
-
function getMigrationRole() {
|
|
700
|
-
return currentRole;
|
|
701
|
-
}
|
|
702
|
-
async function onControlPlane(fn) {
|
|
703
|
-
if (currentRole === "target" || currentRole === "both")
|
|
704
|
-
await fn();
|
|
705
|
-
}
|
|
706
|
-
async function onChainPlane(fn) {
|
|
707
|
-
if (currentRole === "source" || currentRole === "both")
|
|
708
|
-
await fn();
|
|
709
|
-
}
|
|
710
|
-
// src/db/table-plane.ts
|
|
711
|
-
var TABLE_TO_DB = {
|
|
712
|
-
blocks: "source",
|
|
713
|
-
transactions: "source",
|
|
714
|
-
events: "source",
|
|
715
|
-
transactions_archive: "source",
|
|
716
|
-
events_archive: "source",
|
|
717
|
-
dead_letter_events: "source",
|
|
718
|
-
mempool_transactions: "source",
|
|
719
|
-
index_progress: "source",
|
|
720
|
-
contracts: "source",
|
|
721
|
-
chain_reorgs: "source",
|
|
722
|
-
chain_read_cache: "source",
|
|
723
|
-
pending_fork_blocks: "source",
|
|
724
|
-
observer_journal: "source",
|
|
725
|
-
stage_registry: "source",
|
|
726
|
-
stage_runs: "source",
|
|
727
|
-
stage_block_receipts: "source",
|
|
728
|
-
coverage_segments: "source",
|
|
729
|
-
stage_failures: "source",
|
|
730
|
-
decoded_events: "source",
|
|
731
|
-
decoder_checkpoints: "source",
|
|
732
|
-
pox4_calls: "source",
|
|
733
|
-
pox4_cycles_daily: "source",
|
|
734
|
-
pox4_signers_daily: "source",
|
|
735
|
-
pox5_events: "source",
|
|
736
|
-
burn_block_rewards: "source",
|
|
737
|
-
burn_block_reward_slots: "source",
|
|
738
|
-
sbtc_events: "source",
|
|
739
|
-
sbtc_token_events: "source",
|
|
740
|
-
sbtc_settlements: "source",
|
|
741
|
-
sbtc_supply_snapshots: "source",
|
|
742
|
-
bns_name_events: "source",
|
|
743
|
-
bns_namespace_events: "source",
|
|
744
|
-
bns_marketplace_events: "source",
|
|
745
|
-
bns_names: "source",
|
|
746
|
-
bns_namespaces: "source",
|
|
747
|
-
instances: "target",
|
|
748
|
-
accounts: "target",
|
|
749
|
-
api_keys: "target",
|
|
750
|
-
sessions: "target",
|
|
751
|
-
magic_links: "target",
|
|
752
|
-
claim_tokens: "target",
|
|
753
|
-
usage_daily: "target",
|
|
754
|
-
usage_snapshots: "target",
|
|
755
|
-
account_insights: "target",
|
|
756
|
-
account_agent_runs: "target",
|
|
757
|
-
account_spend_caps: "target",
|
|
758
|
-
processed_stripe_events: "target",
|
|
759
|
-
tenants: "target",
|
|
760
|
-
tenant_usage_monthly: "target",
|
|
761
|
-
tenant_compute_addons: "target",
|
|
762
|
-
provisioning_audit_log: "target",
|
|
763
|
-
projects: "target",
|
|
764
|
-
team_members: "target",
|
|
765
|
-
team_invitations: "target",
|
|
766
|
-
subscriptions: "target",
|
|
767
|
-
subscription_outbox: "target",
|
|
768
|
-
subscription_deliveries: "target",
|
|
769
|
-
trigger_evaluator_state: "target",
|
|
770
|
-
subgraphs: "target",
|
|
771
|
-
subgraph_operations: "target",
|
|
772
|
-
subgraph_health_snapshots: "target",
|
|
773
|
-
subgraph_gaps: "target",
|
|
774
|
-
subgraph_usage_daily: "target",
|
|
775
|
-
subgraph_processing_stats: "target",
|
|
776
|
-
subgraph_table_snapshots: "target",
|
|
777
|
-
x402_payments: "target",
|
|
778
|
-
x402_balances: "target",
|
|
779
|
-
account_credits: "target",
|
|
780
|
-
service_heartbeats: "both"
|
|
781
|
-
};
|
|
782
|
-
|
|
783
|
-
// src/db/index.ts
|
|
784
|
-
var DEFAULT_URL = "postgres://postgres:postgres@localhost:5432/secondlayer_dev";
|
|
785
|
-
var pools = new Map;
|
|
786
|
-
var poolSeq = 0;
|
|
787
|
-
function maxPools() {
|
|
788
|
-
return Number.parseInt(process.env.DATABASE_MAX_POOLS ?? "25", 10);
|
|
789
|
-
}
|
|
790
|
-
function evictIfNeeded() {
|
|
791
|
-
if (pools.size <= maxPools())
|
|
792
|
-
return;
|
|
793
|
-
const protectedUrls = new Set([resolveSourceUrl(), resolveTargetUrl()]);
|
|
794
|
-
let lruUrl;
|
|
795
|
-
let lruEntry;
|
|
796
|
-
for (const [url, entry] of pools) {
|
|
797
|
-
if (protectedUrls.has(url))
|
|
798
|
-
continue;
|
|
799
|
-
if (!lruEntry || entry.lastUsed < lruEntry.lastUsed || entry.lastUsed === lruEntry.lastUsed && entry.seq < lruEntry.seq) {
|
|
800
|
-
lruUrl = url;
|
|
801
|
-
lruEntry = entry;
|
|
802
|
-
}
|
|
803
|
-
}
|
|
804
|
-
if (!lruUrl || !lruEntry)
|
|
805
|
-
return;
|
|
806
|
-
pools.delete(lruUrl);
|
|
807
|
-
const evicted = lruEntry;
|
|
808
|
-
evicted.db.destroy().catch(() => {}).then(() => evicted.rawClient.end({ timeout: 5 })).catch(() => {});
|
|
809
|
-
}
|
|
810
|
-
function applicationDatabaseUrl() {
|
|
811
|
-
return process.env.DATABASE_URL || DEFAULT_URL;
|
|
812
|
-
}
|
|
813
|
-
function resolveSourceUrl() {
|
|
814
|
-
if (!isPlatformMode())
|
|
815
|
-
return applicationDatabaseUrl();
|
|
816
|
-
return process.env.SOURCE_DATABASE_URL || process.env.DATABASE_URL || DEFAULT_URL;
|
|
817
|
-
}
|
|
818
|
-
function resolveTargetUrl() {
|
|
819
|
-
if (!isPlatformMode())
|
|
820
|
-
return applicationDatabaseUrl();
|
|
821
|
-
return process.env.TARGET_DATABASE_URL || process.env.DATABASE_URL || DEFAULT_URL;
|
|
822
|
-
}
|
|
823
|
-
function describeDbUrl(url) {
|
|
824
|
-
try {
|
|
825
|
-
const u = new URL(url);
|
|
826
|
-
return `${u.hostname}${u.port ? `:${u.port}` : ""}${u.pathname}`;
|
|
827
|
-
} catch {
|
|
828
|
-
return "invalid-url";
|
|
829
|
-
}
|
|
830
|
-
}
|
|
831
|
-
var warnedDefaultUrlFallthrough = false;
|
|
832
|
-
function warnIfTestRunFallsThroughToDefault() {
|
|
833
|
-
if (warnedDefaultUrlFallthrough)
|
|
834
|
-
return;
|
|
835
|
-
if (process.env["NODE_ENV"] !== "test")
|
|
836
|
-
return;
|
|
837
|
-
if (process.env.DATABASE_URL || process.env.SOURCE_DATABASE_URL || process.env.TARGET_DATABASE_URL) {
|
|
838
|
-
return;
|
|
839
|
-
}
|
|
840
|
-
warnedDefaultUrlFallthrough = true;
|
|
841
|
-
console.warn(`⚠️ DATABASE_URL unset — falling through to the built-in DEFAULT_URL (${describeDbUrl(DEFAULT_URL)}). Database-backed tests will skip or hit the wrong Postgres. Copy .env.example to .env in this package (see \`bun run db\`).`);
|
|
842
|
-
}
|
|
843
|
-
warnIfTestRunFallsThroughToDefault();
|
|
844
|
-
function getDbSplitStatus() {
|
|
845
|
-
const source = resolveSourceUrl();
|
|
846
|
-
const target = resolveTargetUrl();
|
|
847
|
-
const active = source !== target;
|
|
848
|
-
return {
|
|
849
|
-
mode: active ? "split" : "single",
|
|
850
|
-
active,
|
|
851
|
-
sourceDb: describeDbUrl(source),
|
|
852
|
-
targetDb: describeDbUrl(target)
|
|
853
|
-
};
|
|
854
|
-
}
|
|
855
|
-
function assertDbSplit() {
|
|
856
|
-
const isProd = isProductionEnv();
|
|
857
|
-
const wantsSplit = !!(process.env.SOURCE_DATABASE_URL || process.env.TARGET_DATABASE_URL);
|
|
858
|
-
const databaseUrlSet = !!process.env.DATABASE_URL;
|
|
859
|
-
const source = resolveSourceUrl();
|
|
860
|
-
const target = resolveTargetUrl();
|
|
861
|
-
if (wantsSplit && !databaseUrlSet && (source === DEFAULT_URL || target === DEFAULT_URL)) {
|
|
862
|
-
const which = source === DEFAULT_URL ? "SOURCE_DATABASE_URL" : "TARGET_DATABASE_URL";
|
|
863
|
-
const msg = `${which} unset and DATABASE_URL absent — resolving to built-in DEFAULT_URL; refusing to silently use the wrong database`;
|
|
864
|
-
if (isProd)
|
|
865
|
-
console.error(`❌ ${msg}`);
|
|
866
|
-
else
|
|
867
|
-
console.warn(`⚠️ ${msg}`);
|
|
868
|
-
return;
|
|
869
|
-
}
|
|
870
|
-
if (!wantsSplit) {
|
|
871
|
-
if (isProd) {
|
|
872
|
-
console.warn("⚠️ DB split dormant — all services share one Postgres failure domain (SOURCE_/TARGET_DATABASE_URL unset)");
|
|
873
|
-
}
|
|
874
|
-
return;
|
|
875
|
-
}
|
|
876
|
-
if (source === target) {
|
|
877
|
-
const msg = "DB split requested but SOURCE_DATABASE_URL === TARGET_DATABASE_URL (check for a typo or a stray DATABASE_URL fallback)";
|
|
878
|
-
if (isProd)
|
|
879
|
-
console.error(`❌ ${msg}`);
|
|
880
|
-
else
|
|
881
|
-
console.warn(`⚠️ ${msg}`);
|
|
882
|
-
}
|
|
883
|
-
}
|
|
884
|
-
function getOrCreatePool(url) {
|
|
885
|
-
const existing = pools.get(url);
|
|
886
|
-
if (existing) {
|
|
887
|
-
existing.lastUsed = Date.now();
|
|
888
|
-
existing.seq = poolSeq++;
|
|
889
|
-
return existing;
|
|
890
|
-
}
|
|
891
|
-
const host = (() => {
|
|
892
|
-
try {
|
|
893
|
-
return new URL(url).hostname;
|
|
894
|
-
} catch {
|
|
895
|
-
return "";
|
|
896
|
-
}
|
|
897
|
-
})();
|
|
898
|
-
const isLocal = host === "localhost" || host === "127.0.0.1" || !host.includes(".");
|
|
899
|
-
const poolMax = Number.parseInt(process.env.DATABASE_POOL_MAX ?? "20", 10);
|
|
900
|
-
const idleTimeout = Number.parseInt(process.env.DATABASE_IDLE_TIMEOUT ?? "300", 10);
|
|
901
|
-
const rawClient = postgres(url, {
|
|
902
|
-
max: poolMax,
|
|
903
|
-
idle_timeout: idleTimeout,
|
|
904
|
-
ssl: isLocal ? undefined : {
|
|
905
|
-
rejectUnauthorized: process.env.NODE_TLS_REJECT_UNAUTHORIZED !== "0"
|
|
906
|
-
}
|
|
907
|
-
});
|
|
908
|
-
const db = new Kysely({
|
|
909
|
-
dialect: new PostgresJSDialect({ postgres: rawClient }),
|
|
910
|
-
log: (event) => {
|
|
911
|
-
if (event.level !== "error")
|
|
912
|
-
return;
|
|
913
|
-
const err = event.error;
|
|
914
|
-
if (err?.code !== "42P10")
|
|
915
|
-
return;
|
|
916
|
-
logger.warn("db.on_conflict_constraint_missing", {
|
|
917
|
-
code: err.code,
|
|
918
|
-
message: err.message,
|
|
919
|
-
sql: event.query.sql,
|
|
920
|
-
params: event.query.parameters
|
|
921
|
-
});
|
|
922
|
-
}
|
|
923
|
-
});
|
|
924
|
-
const entry = {
|
|
925
|
-
db,
|
|
926
|
-
rawClient,
|
|
927
|
-
lastUsed: Date.now(),
|
|
928
|
-
seq: poolSeq++
|
|
929
|
-
};
|
|
930
|
-
pools.set(url, entry);
|
|
931
|
-
evictIfNeeded();
|
|
932
|
-
return entry;
|
|
933
|
-
}
|
|
934
|
-
function getSourceDb() {
|
|
935
|
-
return getOrCreatePool(resolveSourceUrl()).db;
|
|
936
|
-
}
|
|
937
|
-
function getTargetDb() {
|
|
938
|
-
return getOrCreatePool(resolveTargetUrl()).db;
|
|
939
|
-
}
|
|
940
|
-
function getDb(connectionString) {
|
|
941
|
-
if (connectionString)
|
|
942
|
-
return getOrCreatePool(connectionString).db;
|
|
943
|
-
return getTargetDb();
|
|
944
|
-
}
|
|
945
|
-
function getRawClient(role = "target") {
|
|
946
|
-
const url = role === "source" ? resolveSourceUrl() : resolveTargetUrl();
|
|
947
|
-
return getOrCreatePool(url).rawClient;
|
|
948
|
-
}
|
|
949
|
-
function getRawClientFor(url) {
|
|
950
|
-
return getOrCreatePool(url).rawClient;
|
|
951
|
-
}
|
|
952
|
-
async function closeDb() {
|
|
953
|
-
for (const entry of pools.values()) {
|
|
954
|
-
await entry.db.destroy();
|
|
955
|
-
await entry.rawClient.end();
|
|
956
|
-
}
|
|
957
|
-
pools.clear();
|
|
958
|
-
}
|
|
959
|
-
// src/crypto/secrets.ts
|
|
960
|
-
import { createCipheriv, createDecipheriv, randomBytes } from "node:crypto";
|
|
961
|
-
import {
|
|
962
|
-
appendFileSync,
|
|
963
|
-
closeSync,
|
|
964
|
-
existsSync,
|
|
965
|
-
openSync,
|
|
966
|
-
readFileSync,
|
|
967
|
-
unlinkSync
|
|
968
|
-
} from "node:fs";
|
|
969
|
-
import { resolve } from "node:path";
|
|
970
|
-
var KEY_ENV = "SECONDLAYER_SECRETS_KEY";
|
|
971
|
-
var IV_LEN = 12;
|
|
972
|
-
var TAG_LEN = 16;
|
|
973
|
-
function readExistingKey(envPath) {
|
|
974
|
-
if (!existsSync(envPath))
|
|
975
|
-
return null;
|
|
976
|
-
const contents = readFileSync(envPath, "utf8");
|
|
977
|
-
const match = contents.match(/^SECONDLAYER_SECRETS_KEY=([a-fA-F0-9]{64})/m);
|
|
978
|
-
return match ? match[1] : null;
|
|
979
|
-
}
|
|
980
|
-
var STALE_LOCK_MS = 1e4;
|
|
981
|
-
var POLL_MS = 25;
|
|
982
|
-
function bootstrapOssKey() {
|
|
983
|
-
const envPath = resolve(process.cwd(), ".env.local");
|
|
984
|
-
const existing = readExistingKey(envPath);
|
|
985
|
-
if (existing) {
|
|
986
|
-
process.env[KEY_ENV] = existing;
|
|
987
|
-
return existing;
|
|
988
|
-
}
|
|
989
|
-
const lockPath = `${envPath}.secret-bootstrap.lock`;
|
|
990
|
-
let lockFd = null;
|
|
991
|
-
try {
|
|
992
|
-
lockFd = openSync(lockPath, "wx", 384);
|
|
993
|
-
} catch (err) {
|
|
994
|
-
const e = err;
|
|
995
|
-
if (e.code !== "EEXIST")
|
|
996
|
-
throw err;
|
|
997
|
-
}
|
|
998
|
-
if (lockFd === null) {
|
|
999
|
-
const deadline = Date.now() + STALE_LOCK_MS;
|
|
1000
|
-
while (Date.now() < deadline) {
|
|
1001
|
-
const key = readExistingKey(envPath);
|
|
1002
|
-
if (key) {
|
|
1003
|
-
process.env[KEY_ENV] = key;
|
|
1004
|
-
return key;
|
|
1005
|
-
}
|
|
1006
|
-
Bun.sleepSync(POLL_MS);
|
|
1007
|
-
}
|
|
1008
|
-
try {
|
|
1009
|
-
unlinkSync(lockPath);
|
|
1010
|
-
} catch {}
|
|
1011
|
-
return bootstrapOssKey();
|
|
1012
|
-
}
|
|
1013
|
-
try {
|
|
1014
|
-
const hex = randomBytes(32).toString("hex");
|
|
1015
|
-
const line = `${existsSync(envPath) ? `
|
|
1016
|
-
` : ""}${KEY_ENV}=${hex}
|
|
1017
|
-
`;
|
|
1018
|
-
appendFileSync(envPath, line, { mode: 384 });
|
|
1019
|
-
process.env[KEY_ENV] = hex;
|
|
1020
|
-
console.log(`[secondlayer] generated ${KEY_ENV}; saved to ${envPath} (mode 0600)`);
|
|
1021
|
-
return hex;
|
|
1022
|
-
} finally {
|
|
1023
|
-
closeSync(lockFd);
|
|
1024
|
-
try {
|
|
1025
|
-
unlinkSync(lockPath);
|
|
1026
|
-
} catch {}
|
|
1027
|
-
}
|
|
1028
|
-
}
|
|
1029
|
-
function loadKey() {
|
|
1030
|
-
let hex = process.env[KEY_ENV];
|
|
1031
|
-
if (!hex) {
|
|
1032
|
-
if (getInstanceMode() === "oss") {
|
|
1033
|
-
hex = bootstrapOssKey();
|
|
1034
|
-
} else {
|
|
1035
|
-
throw new Error(`${KEY_ENV} not set. Generate one with: openssl rand -hex 32`);
|
|
1036
|
-
}
|
|
1037
|
-
}
|
|
1038
|
-
const key = Buffer.from(hex, "hex");
|
|
1039
|
-
if (key.length !== 32) {
|
|
1040
|
-
throw new Error(`${KEY_ENV} must be 32 bytes hex (got ${key.length})`);
|
|
1041
|
-
}
|
|
1042
|
-
return key;
|
|
1043
|
-
}
|
|
1044
|
-
var _cachedKey = null;
|
|
1045
|
-
function getKey() {
|
|
1046
|
-
if (!_cachedKey)
|
|
1047
|
-
_cachedKey = loadKey();
|
|
1048
|
-
return _cachedKey;
|
|
1049
|
-
}
|
|
1050
|
-
function secretsKeyAvailable() {
|
|
1051
|
-
if (process.env[KEY_ENV])
|
|
1052
|
-
return true;
|
|
1053
|
-
if (getInstanceMode() === "oss") {
|
|
1054
|
-
const envPath = resolve(process.cwd(), ".env.local");
|
|
1055
|
-
return readExistingKey(envPath) !== null;
|
|
1056
|
-
}
|
|
1057
|
-
return false;
|
|
1058
|
-
}
|
|
1059
|
-
function encryptSecret(plaintext) {
|
|
1060
|
-
const key = getKey();
|
|
1061
|
-
const iv = randomBytes(IV_LEN);
|
|
1062
|
-
const cipher = createCipheriv("aes-256-gcm", key, iv);
|
|
1063
|
-
const ciphertext = Buffer.concat([
|
|
1064
|
-
cipher.update(plaintext, "utf8"),
|
|
1065
|
-
cipher.final()
|
|
1066
|
-
]);
|
|
1067
|
-
const tag = cipher.getAuthTag();
|
|
1068
|
-
return Buffer.concat([iv, tag, ciphertext]);
|
|
1069
|
-
}
|
|
1070
|
-
function decryptSecret(envelope) {
|
|
1071
|
-
const key = getKey();
|
|
1072
|
-
const iv = envelope.subarray(0, IV_LEN);
|
|
1073
|
-
const tag = envelope.subarray(IV_LEN, IV_LEN + TAG_LEN);
|
|
1074
|
-
const ciphertext = envelope.subarray(IV_LEN + TAG_LEN);
|
|
1075
|
-
const decipher = createDecipheriv("aes-256-gcm", key, iv);
|
|
1076
|
-
decipher.setAuthTag(tag);
|
|
1077
|
-
return decipher.update(ciphertext).toString("utf8") + decipher.final("utf8");
|
|
1078
|
-
}
|
|
1079
|
-
function generateSecretsKey() {
|
|
1080
|
-
return randomBytes(32).toString("hex");
|
|
1081
|
-
}
|
|
1082
|
-
|
|
1083
69
|
// src/db/queries/subgraphs.ts
|
|
1084
|
-
import { sql as
|
|
1085
|
-
function encryptDatabaseUrl(url) {
|
|
1086
|
-
return encryptSecret(url);
|
|
1087
|
-
}
|
|
1088
|
-
function subgraphDatabaseUrl(subgraph) {
|
|
1089
|
-
return subgraph.database_url_enc ? decryptSecret(subgraph.database_url_enc) : null;
|
|
1090
|
-
}
|
|
1091
|
-
function isByoSubgraph(subgraph) {
|
|
1092
|
-
return subgraph.database_url_enc != null;
|
|
1093
|
-
}
|
|
1094
|
-
function resolveSubgraphDb(subgraph) {
|
|
1095
|
-
const url = subgraphDatabaseUrl(subgraph);
|
|
1096
|
-
return url ? getDb(url) : getTargetDb();
|
|
1097
|
-
}
|
|
1098
|
-
function resolveSubgraphRawClient(subgraph) {
|
|
1099
|
-
const url = subgraphDatabaseUrl(subgraph);
|
|
1100
|
-
return url ? getRawClientFor(url) : getRawClient("target");
|
|
1101
|
-
}
|
|
70
|
+
import { sql as sql2 } from "kysely";
|
|
1102
71
|
function pgSchemaName(subgraphName) {
|
|
1103
72
|
const safeName = subgraphName.replace(/-/g, "_");
|
|
1104
73
|
return `subgraph_${safeName}`;
|
|
@@ -1128,7 +97,7 @@ async function registerSubgraph(db, data) {
|
|
|
1128
97
|
source_code: data.sourceCode ?? null,
|
|
1129
98
|
schema_name: data.schemaName ?? null,
|
|
1130
99
|
start_block: data.startBlock ?? 0,
|
|
1131
|
-
database_url_enc:
|
|
100
|
+
database_url_enc: null
|
|
1132
101
|
};
|
|
1133
102
|
const updateSet = {
|
|
1134
103
|
version: data.version,
|
|
@@ -1139,7 +108,7 @@ async function registerSubgraph(db, data) {
|
|
|
1139
108
|
source_code: data.sourceCode ?? null,
|
|
1140
109
|
schema_name: data.schemaName ?? null,
|
|
1141
110
|
start_block: data.startBlock ?? 0,
|
|
1142
|
-
database_url_enc:
|
|
111
|
+
database_url_enc: null,
|
|
1143
112
|
updated_at: new Date
|
|
1144
113
|
};
|
|
1145
114
|
if (!isPlatformMode()) {
|
|
@@ -1188,8 +157,8 @@ async function recordLiveError(db, name, blockHeight) {
|
|
|
1188
157
|
}
|
|
1189
158
|
async function recordSubgraphProcessed(db, name, processed, errors, lastError) {
|
|
1190
159
|
await db.updateTable("subgraphs").set({
|
|
1191
|
-
total_processed:
|
|
1192
|
-
total_errors:
|
|
160
|
+
total_processed: sql2`total_processed + ${processed}`,
|
|
161
|
+
total_errors: sql2`total_errors + ${errors}`,
|
|
1193
162
|
...lastError ? { last_error: lastError, last_error_at: new Date } : {},
|
|
1194
163
|
updated_at: new Date
|
|
1195
164
|
}).where("name", "=", name).execute();
|
|
@@ -1213,9 +182,7 @@ async function deleteSubgraph(db, name, accountId) {
|
|
|
1213
182
|
updated_at: new Date
|
|
1214
183
|
}).where("subgraph_name", "=", name).execute();
|
|
1215
184
|
await db.deleteFrom("subscription_outbox").where("status", "=", "pending").where("subscription_id", "in", (qb) => qb.selectFrom("subscriptions").select("id").where("subgraph_name", "=", name)).execute();
|
|
1216
|
-
|
|
1217
|
-
await sql3`DROP SCHEMA IF EXISTS ${sql3.raw(`"${schemaName}"`)} CASCADE`.execute(db);
|
|
1218
|
-
}
|
|
185
|
+
await sql2`DROP SCHEMA IF EXISTS ${sql2.raw(`"${schemaName}"`)} CASCADE`.execute(db);
|
|
1219
186
|
await db.deleteFrom("subgraphs").where("id", "=", subgraph.id).execute();
|
|
1220
187
|
return subgraph;
|
|
1221
188
|
}
|
|
@@ -1225,7 +192,7 @@ async function updateSubgraphExpiry(db, name, accountId, expiresAt) {
|
|
|
1225
192
|
async function recordLiveProgress(db, name, lastProcessedBlock) {
|
|
1226
193
|
const result = await db.updateTable("subgraphs").set({
|
|
1227
194
|
last_processed_block: lastProcessedBlock,
|
|
1228
|
-
status:
|
|
195
|
+
status: sql2`CASE WHEN status = 'reindexing' THEN status ELSE 'active' END`,
|
|
1229
196
|
updated_at: new Date
|
|
1230
197
|
}).where("name", "=", name).where("last_processed_block", "<", lastProcessedBlock).executeTakeFirst();
|
|
1231
198
|
return Number(result.numUpdatedRows ?? 0n) > 0;
|
|
@@ -1233,7 +200,7 @@ async function recordLiveProgress(db, name, lastProcessedBlock) {
|
|
|
1233
200
|
async function rewindLiveProgress(db, name, lastProcessedBlock) {
|
|
1234
201
|
await db.updateTable("subgraphs").set({
|
|
1235
202
|
last_processed_block: lastProcessedBlock,
|
|
1236
|
-
status:
|
|
203
|
+
status: sql2`CASE WHEN status = 'reindexing' THEN status ELSE 'active' END`,
|
|
1237
204
|
updated_at: new Date
|
|
1238
205
|
}).where("name", "=", name).execute();
|
|
1239
206
|
}
|
|
@@ -1242,10 +209,7 @@ export {
|
|
|
1242
209
|
updateSubgraphStatus,
|
|
1243
210
|
updateSubgraphHandlerPath,
|
|
1244
211
|
updateSubgraphExpiry,
|
|
1245
|
-
subgraphDatabaseUrl,
|
|
1246
212
|
rewindLiveProgress,
|
|
1247
|
-
resolveSubgraphRawClient,
|
|
1248
|
-
resolveSubgraphDb,
|
|
1249
213
|
registerSubgraph,
|
|
1250
214
|
recordSubgraphProcessed,
|
|
1251
215
|
recordLiveProgress,
|
|
@@ -1254,12 +218,10 @@ export {
|
|
|
1254
218
|
pgSchemaName,
|
|
1255
219
|
localSubgraphAccountId,
|
|
1256
220
|
listSubgraphs,
|
|
1257
|
-
isByoSubgraph,
|
|
1258
221
|
getSubgraph,
|
|
1259
222
|
findPublicSubgraphByName,
|
|
1260
|
-
encryptDatabaseUrl,
|
|
1261
223
|
deleteSubgraph
|
|
1262
224
|
};
|
|
1263
225
|
|
|
1264
|
-
//# debugId=
|
|
226
|
+
//# debugId=99813C300C0409BA64756E2164756E21
|
|
1265
227
|
//# sourceMappingURL=subgraphs.js.map
|