@secondlayer/subgraphs 3.6.1 → 3.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/index.js +12 -8
- package/dist/src/index.js.map +4 -4
- package/dist/src/runtime/block-processor.js +12 -8
- package/dist/src/runtime/block-processor.js.map +4 -4
- package/dist/src/runtime/catchup.js +12 -8
- package/dist/src/runtime/catchup.js.map +4 -4
- package/dist/src/runtime/processor.js +338 -64
- package/dist/src/runtime/processor.js.map +10 -7
- package/dist/src/runtime/reindex.js +12 -8
- package/dist/src/runtime/reindex.js.map +4 -4
- package/dist/src/runtime/reorg.js +12 -8
- package/dist/src/runtime/reorg.js.map +4 -4
- package/dist/src/runtime/replay.js +12 -7
- package/dist/src/runtime/replay.js.map +3 -3
- package/dist/src/service.js +343 -68
- package/dist/src/service.js.map +11 -8
- package/package.json +2 -2
package/dist/src/service.js
CHANGED
|
@@ -1149,19 +1149,21 @@ function sourceFilters(subgraph) {
|
|
|
1149
1149
|
const sources = subgraph.sources;
|
|
1150
1150
|
return Array.isArray(sources) ? sources : Object.values(sources);
|
|
1151
1151
|
}
|
|
1152
|
-
function
|
|
1153
|
-
|
|
1154
|
-
if (filters.some((f) => TX_SOURCE_TYPES.has(f.type))) {
|
|
1152
|
+
function indexEventTypesForFilterTypes(filterTypes) {
|
|
1153
|
+
if (filterTypes.some((t) => TX_SOURCE_TYPES.has(t))) {
|
|
1155
1154
|
return ALL_INDEX_EVENT_TYPES;
|
|
1156
1155
|
}
|
|
1157
1156
|
const types = new Set;
|
|
1158
|
-
for (const
|
|
1159
|
-
const
|
|
1160
|
-
if (
|
|
1161
|
-
types.add(
|
|
1157
|
+
for (const t of filterTypes) {
|
|
1158
|
+
const indexType = EVENT_FILTER_TO_INDEX_TYPE[t];
|
|
1159
|
+
if (indexType)
|
|
1160
|
+
types.add(indexType);
|
|
1162
1161
|
}
|
|
1163
1162
|
return [...types];
|
|
1164
1163
|
}
|
|
1164
|
+
function referencedIndexEventTypes(subgraph) {
|
|
1165
|
+
return indexEventTypesForFilterTypes(sourceFilters(subgraph).map((f) => f.type));
|
|
1166
|
+
}
|
|
1165
1167
|
function isStreamsIndexEligible(subgraph) {
|
|
1166
1168
|
if (Array.isArray(subgraph.sources))
|
|
1167
1169
|
return false;
|
|
@@ -1423,6 +1425,8 @@ class SubscriptionMatcher {
|
|
|
1423
1425
|
for (const sub of subs) {
|
|
1424
1426
|
if (sub.status !== "active")
|
|
1425
1427
|
continue;
|
|
1428
|
+
if (sub.kind !== "subgraph" || !sub.subgraph_name || !sub.table_name)
|
|
1429
|
+
continue;
|
|
1426
1430
|
this.byId.set(sub.id, sub);
|
|
1427
1431
|
const k = key(sub.subgraph_name, sub.table_name);
|
|
1428
1432
|
const arr = this.byKey.get(k);
|
|
@@ -2492,8 +2496,8 @@ import { randomUUID } from "node:crypto";
|
|
|
2492
2496
|
import { hostname } from "node:os";
|
|
2493
2497
|
import { resolve } from "node:path";
|
|
2494
2498
|
import { pathToFileURL } from "node:url";
|
|
2495
|
-
import { getErrorMessage as
|
|
2496
|
-
import { getTargetDb as
|
|
2499
|
+
import { getErrorMessage as getErrorMessage6 } from "@secondlayer/shared";
|
|
2500
|
+
import { getTargetDb as getTargetDb8 } from "@secondlayer/shared/db";
|
|
2497
2501
|
import {
|
|
2498
2502
|
cancelSubgraphOperation,
|
|
2499
2503
|
claimSubgraphOperation,
|
|
@@ -2511,20 +2515,71 @@ import {
|
|
|
2511
2515
|
pgSchemaName as pgSchemaName2,
|
|
2512
2516
|
updateSubgraphStatus as updateSubgraphStatus3
|
|
2513
2517
|
} from "@secondlayer/shared/db/queries/subgraphs";
|
|
2514
|
-
import { logger as
|
|
2518
|
+
import { logger as logger14 } from "@secondlayer/shared/logger";
|
|
2515
2519
|
import { listen as listen2 } from "@secondlayer/shared/queue/listener";
|
|
2516
2520
|
|
|
2521
|
+
// src/runtime/chain-reorg.ts
|
|
2522
|
+
import { getTargetDb as getTargetDb5 } from "@secondlayer/shared/db";
|
|
2523
|
+
import { logger as logger9 } from "@secondlayer/shared/logger";
|
|
2524
|
+
var MAX_ORPHANED_PER_SUB = 500;
|
|
2525
|
+
async function handleChainReorg(forkHeight, db = getTargetDb5()) {
|
|
2526
|
+
await db.deleteFrom("subscription_outbox").where("kind", "=", "chain").where("block_height", ">=", forkHeight).where("status", "=", "pending").where("event_type", "like", "chain.%.apply").execute();
|
|
2527
|
+
const delivered = await db.selectFrom("subscription_outbox").select(["subscription_id", "tx_id", "payload"]).where("kind", "=", "chain").where("block_height", ">=", forkHeight).where("status", "=", "delivered").where("event_type", "like", "chain.%.apply").orderBy("block_height").orderBy("id").execute();
|
|
2528
|
+
const bySub = new Map;
|
|
2529
|
+
for (const row of delivered) {
|
|
2530
|
+
const list = bySub.get(row.subscription_id) ?? [];
|
|
2531
|
+
const payload = row.payload;
|
|
2532
|
+
list.push({ tx_id: row.tx_id, event: payload?.event ?? null });
|
|
2533
|
+
bySub.set(row.subscription_id, list);
|
|
2534
|
+
}
|
|
2535
|
+
if (bySub.size > 0) {
|
|
2536
|
+
const rows = [];
|
|
2537
|
+
for (const [subscriptionId, entries] of bySub) {
|
|
2538
|
+
const truncated = entries.length > MAX_ORPHANED_PER_SUB;
|
|
2539
|
+
const payload = {
|
|
2540
|
+
action: "rollback",
|
|
2541
|
+
fork_point_height: forkHeight,
|
|
2542
|
+
orphaned: truncated ? entries.slice(0, MAX_ORPHANED_PER_SUB) : entries,
|
|
2543
|
+
truncated
|
|
2544
|
+
};
|
|
2545
|
+
rows.push({
|
|
2546
|
+
subscription_id: subscriptionId,
|
|
2547
|
+
kind: "chain",
|
|
2548
|
+
subgraph_name: null,
|
|
2549
|
+
table_name: null,
|
|
2550
|
+
block_height: forkHeight,
|
|
2551
|
+
tx_id: null,
|
|
2552
|
+
row_pk: { fork_point_height: forkHeight },
|
|
2553
|
+
event_type: "chain.reorg.rollback",
|
|
2554
|
+
payload,
|
|
2555
|
+
dedup_key: `chainreorg:${subscriptionId}:${forkHeight}`
|
|
2556
|
+
});
|
|
2557
|
+
}
|
|
2558
|
+
await db.insertInto("subscription_outbox").values(rows).onConflict((oc) => oc.columns(["subscription_id", "dedup_key"]).doNothing()).execute();
|
|
2559
|
+
logger9.info("Chain reorg — emitted rollbacks", {
|
|
2560
|
+
forkPointHeight: forkHeight,
|
|
2561
|
+
subscriptions: bySub.size
|
|
2562
|
+
});
|
|
2563
|
+
}
|
|
2564
|
+
await db.transaction().execute(async (trx) => {
|
|
2565
|
+
const cur = await trx.selectFrom("trigger_evaluator_state").select("last_processed_block").where("id", "=", true).forUpdate().executeTakeFirst();
|
|
2566
|
+
if (cur && Number(cur.last_processed_block) >= forkHeight) {
|
|
2567
|
+
await trx.updateTable("trigger_evaluator_state").set({ last_processed_block: forkHeight - 1, updated_at: new Date }).where("id", "=", true).execute();
|
|
2568
|
+
}
|
|
2569
|
+
});
|
|
2570
|
+
}
|
|
2571
|
+
|
|
2517
2572
|
// src/runtime/emitter.ts
|
|
2518
2573
|
import {
|
|
2519
|
-
getTargetDb as
|
|
2574
|
+
getTargetDb as getTargetDb6
|
|
2520
2575
|
} from "@secondlayer/shared/db";
|
|
2521
2576
|
import { getSubscriptionSigningSecret } from "@secondlayer/shared/db/queries/subscriptions";
|
|
2522
|
-
import { logger as
|
|
2577
|
+
import { logger as logger11 } from "@secondlayer/shared/logger";
|
|
2523
2578
|
import { listen } from "@secondlayer/shared/queue/listener";
|
|
2524
2579
|
import { sql as sql4 } from "kysely";
|
|
2525
2580
|
|
|
2526
2581
|
// src/runtime/formats/index.ts
|
|
2527
|
-
import { logger as
|
|
2582
|
+
import { logger as logger10 } from "@secondlayer/shared/logger";
|
|
2528
2583
|
|
|
2529
2584
|
// src/runtime/formats/cloudevents.ts
|
|
2530
2585
|
function buildCloudEvents(outboxRow, _sub) {
|
|
@@ -2671,7 +2726,7 @@ function buildForFormat(outboxRow, sub, signingSecret) {
|
|
|
2671
2726
|
case "standard-webhooks":
|
|
2672
2727
|
return buildStandardWebhooks(outboxRow, signingSecret);
|
|
2673
2728
|
default:
|
|
2674
|
-
|
|
2729
|
+
logger10.warn("Unknown subscription format, falling back to standard-webhooks", {
|
|
2675
2730
|
format: sub.format,
|
|
2676
2731
|
subscriptionId: sub.id
|
|
2677
2732
|
});
|
|
@@ -2754,7 +2809,7 @@ async function dispatchOne(db, outboxRow, sub) {
|
|
|
2754
2809
|
let responseHeaders = {};
|
|
2755
2810
|
if (isPrivateEgress(sub.url) && !allowPrivateEgress()) {
|
|
2756
2811
|
error = "refused private egress (set SECONDLAYER_ALLOW_PRIVATE_EGRESS=true to allow)";
|
|
2757
|
-
|
|
2812
|
+
logger11.warn("[emitter] refused private egress", {
|
|
2758
2813
|
subscription: sub.name,
|
|
2759
2814
|
url: sub.url
|
|
2760
2815
|
});
|
|
@@ -2850,7 +2905,7 @@ async function settleFailed(db, outboxRow, sub, errText) {
|
|
|
2850
2905
|
circuit_opened_at: new Date,
|
|
2851
2906
|
updated_at: new Date
|
|
2852
2907
|
}).where("id", "=", sub.id).execute();
|
|
2853
|
-
|
|
2908
|
+
logger11.warn("Subscription circuit tripped — paused after consecutive failures", {
|
|
2854
2909
|
subscription: sub.name,
|
|
2855
2910
|
failures: newFailures
|
|
2856
2911
|
});
|
|
@@ -2938,7 +2993,7 @@ async function drainForSub(db, state, sub, rows) {
|
|
|
2938
2993
|
await settleFailed(db, row, sub, err);
|
|
2939
2994
|
}
|
|
2940
2995
|
} catch (err) {
|
|
2941
|
-
|
|
2996
|
+
logger11.error("Emitter dispatch crashed", {
|
|
2942
2997
|
outboxId: row.id,
|
|
2943
2998
|
error: err instanceof Error ? err.message : String(err)
|
|
2944
2999
|
});
|
|
@@ -2967,7 +3022,7 @@ async function runRetention(db) {
|
|
|
2967
3022
|
}
|
|
2968
3023
|
async function startEmitter(opts) {
|
|
2969
3024
|
const emitterId = `emitter-${Math.random().toString(36).slice(2, 10)}`;
|
|
2970
|
-
const db =
|
|
3025
|
+
const db = getTargetDb6();
|
|
2971
3026
|
const state = {
|
|
2972
3027
|
running: true,
|
|
2973
3028
|
inFlightBySub: new Map,
|
|
@@ -2975,7 +3030,7 @@ async function startEmitter(opts) {
|
|
|
2975
3030
|
};
|
|
2976
3031
|
const pollIntervalMs = opts?.pollIntervalMs ?? 120000;
|
|
2977
3032
|
const retentionIntervalMs = opts?.retentionIntervalMs ?? 60 * 60000;
|
|
2978
|
-
|
|
3033
|
+
logger11.info("[emitter] started", { id: emitterId });
|
|
2979
3034
|
const MATCHER_BOOT_ATTEMPTS = 5;
|
|
2980
3035
|
let lastErr = null;
|
|
2981
3036
|
for (let i = 0;i < MATCHER_BOOT_ATTEMPTS; i++) {
|
|
@@ -2986,7 +3041,7 @@ async function startEmitter(opts) {
|
|
|
2986
3041
|
} catch (err) {
|
|
2987
3042
|
lastErr = err;
|
|
2988
3043
|
const delayMs = 500 * 2 ** i;
|
|
2989
|
-
|
|
3044
|
+
logger11.warn("[emitter] matcher refresh failed, retrying", {
|
|
2990
3045
|
attempt: i + 1,
|
|
2991
3046
|
delayMs,
|
|
2992
3047
|
error: err instanceof Error ? err.message : String(err)
|
|
@@ -3000,21 +3055,21 @@ async function startEmitter(opts) {
|
|
|
3000
3055
|
const stopNew = await listen("subscriptions:new_outbox", () => {
|
|
3001
3056
|
if (!state.running)
|
|
3002
3057
|
return;
|
|
3003
|
-
claimAndDrain(db, state, emitterId).catch((err) =>
|
|
3058
|
+
claimAndDrain(db, state, emitterId).catch((err) => logger11.error("[emitter] claim failed", {
|
|
3004
3059
|
error: err instanceof Error ? err.message : String(err)
|
|
3005
3060
|
}));
|
|
3006
3061
|
});
|
|
3007
3062
|
const stopChanged = await listen("subscriptions:changed", () => {
|
|
3008
3063
|
if (!state.running)
|
|
3009
3064
|
return;
|
|
3010
|
-
refreshMatcher(db).catch((err) =>
|
|
3065
|
+
refreshMatcher(db).catch((err) => logger11.error("[emitter] matcher refresh failed", {
|
|
3011
3066
|
error: err instanceof Error ? err.message : String(err)
|
|
3012
3067
|
}));
|
|
3013
3068
|
});
|
|
3014
3069
|
const poll = setInterval(() => {
|
|
3015
3070
|
if (!state.running)
|
|
3016
3071
|
return;
|
|
3017
|
-
claimAndDrain(db, state, emitterId).catch((err) =>
|
|
3072
|
+
claimAndDrain(db, state, emitterId).catch((err) => logger11.error("[emitter] poll claim failed", {
|
|
3018
3073
|
error: err instanceof Error ? err.message : String(err)
|
|
3019
3074
|
}));
|
|
3020
3075
|
}, pollIntervalMs);
|
|
@@ -3022,7 +3077,7 @@ async function startEmitter(opts) {
|
|
|
3022
3077
|
const retention = setInterval(() => {
|
|
3023
3078
|
if (!state.running)
|
|
3024
3079
|
return;
|
|
3025
|
-
runRetention(db).catch((err) =>
|
|
3080
|
+
runRetention(db).catch((err) => logger11.error("[emitter] retention failed", {
|
|
3026
3081
|
error: err instanceof Error ? err.message : String(err)
|
|
3027
3082
|
}));
|
|
3028
3083
|
}, retentionIntervalMs);
|
|
@@ -3032,28 +3087,30 @@ async function startEmitter(opts) {
|
|
|
3032
3087
|
clearInterval(retention);
|
|
3033
3088
|
await stopNew();
|
|
3034
3089
|
await stopChanged();
|
|
3035
|
-
|
|
3090
|
+
logger11.info("[emitter] stopped", { id: emitterId });
|
|
3036
3091
|
};
|
|
3037
3092
|
}
|
|
3038
3093
|
|
|
3039
3094
|
// src/runtime/streams-reorg-poll.ts
|
|
3040
3095
|
import { getErrorMessage as getErrorMessage4 } from "@secondlayer/shared";
|
|
3041
3096
|
import { IndexHttpClient as IndexHttpClient2 } from "@secondlayer/shared/index-http";
|
|
3042
|
-
import { logger as
|
|
3097
|
+
import { logger as logger12 } from "@secondlayer/shared/logger";
|
|
3043
3098
|
var POLL_MS = Number(process.env.SUBGRAPH_REORG_POLL_MS) || 15000;
|
|
3044
3099
|
var STARTUP_MARGIN_MS = 60 * 60 * 1000;
|
|
3045
|
-
async function pollReorgsOnce(http, cursor, handleReorg, loadDef) {
|
|
3100
|
+
async function pollReorgsOnce(http, cursor, handleReorg, loadDef, handleChainReorg2) {
|
|
3046
3101
|
const { reorgs, next_since } = await http.listReorgs(cursor);
|
|
3047
3102
|
const sorted = [...reorgs].sort((a, b) => a.fork_point_height - b.fork_point_height);
|
|
3048
3103
|
for (const r of sorted) {
|
|
3049
|
-
|
|
3104
|
+
logger12.info("Streams reorg — rewinding subgraphs", {
|
|
3050
3105
|
forkPointHeight: r.fork_point_height
|
|
3051
3106
|
});
|
|
3052
3107
|
await handleReorg(r.fork_point_height, loadDef);
|
|
3108
|
+
if (handleChainReorg2)
|
|
3109
|
+
await handleChainReorg2(r.fork_point_height);
|
|
3053
3110
|
}
|
|
3054
3111
|
return next_since ?? cursor;
|
|
3055
3112
|
}
|
|
3056
|
-
function startStreamsReorgPoll(handleReorg, loadDef) {
|
|
3113
|
+
function startStreamsReorgPoll(handleReorg, loadDef, handleChainReorg2) {
|
|
3057
3114
|
const baseUrl = process.env.SUBGRAPH_INDEX_API_URL ?? process.env.STREAMS_API_URL ?? "http://api:3800";
|
|
3058
3115
|
const http = new IndexHttpClient2({
|
|
3059
3116
|
indexBaseUrl: baseUrl,
|
|
@@ -3067,9 +3124,9 @@ function startStreamsReorgPoll(handleReorg, loadDef) {
|
|
|
3067
3124
|
if (!running)
|
|
3068
3125
|
return;
|
|
3069
3126
|
try {
|
|
3070
|
-
since = await pollReorgsOnce(http, since, handleReorg, loadDef);
|
|
3127
|
+
since = await pollReorgsOnce(http, since, handleReorg, loadDef, handleChainReorg2);
|
|
3071
3128
|
} catch (err) {
|
|
3072
|
-
|
|
3129
|
+
logger12.error("Streams reorg poll failed", {
|
|
3073
3130
|
error: getErrorMessage4(err)
|
|
3074
3131
|
});
|
|
3075
3132
|
}
|
|
@@ -3077,7 +3134,222 @@ function startStreamsReorgPoll(handleReorg, loadDef) {
|
|
|
3077
3134
|
timer = setTimeout(tick, POLL_MS);
|
|
3078
3135
|
};
|
|
3079
3136
|
timer = setTimeout(tick, POLL_MS);
|
|
3080
|
-
|
|
3137
|
+
logger12.info("Streams reorg poll started", { pollMs: POLL_MS });
|
|
3138
|
+
return () => {
|
|
3139
|
+
running = false;
|
|
3140
|
+
if (timer)
|
|
3141
|
+
clearTimeout(timer);
|
|
3142
|
+
};
|
|
3143
|
+
}
|
|
3144
|
+
|
|
3145
|
+
// src/runtime/trigger-evaluator-loop.ts
|
|
3146
|
+
import { getErrorMessage as getErrorMessage5 } from "@secondlayer/shared";
|
|
3147
|
+
import { getTargetDb as getTargetDb7 } from "@secondlayer/shared/db";
|
|
3148
|
+
import { listActiveChainSubscriptions } from "@secondlayer/shared/db/queries/subscriptions";
|
|
3149
|
+
import { logger as logger13 } from "@secondlayer/shared/logger";
|
|
3150
|
+
|
|
3151
|
+
// src/runtime/trigger-evaluator.ts
|
|
3152
|
+
import { resolveTraitContractIds as resolveTraitContractIds2 } from "@secondlayer/shared/db/queries/contracts";
|
|
3153
|
+
var TX_LEVEL_TRIGGER_TYPES = new Set(["contract_call", "contract_deploy"]);
|
|
3154
|
+
function sourceKey(subscriptionId, triggerIndex) {
|
|
3155
|
+
return `${subscriptionId}#${triggerIndex}`;
|
|
3156
|
+
}
|
|
3157
|
+
function toAmount(v) {
|
|
3158
|
+
return v === undefined ? undefined : BigInt(v);
|
|
3159
|
+
}
|
|
3160
|
+
function chainTriggerToFilter(trigger) {
|
|
3161
|
+
const t = trigger;
|
|
3162
|
+
const filter = { ...trigger };
|
|
3163
|
+
const minAmount = toAmount(t.minAmount);
|
|
3164
|
+
const maxAmount = toAmount(t.maxAmount);
|
|
3165
|
+
if (minAmount !== undefined)
|
|
3166
|
+
filter.minAmount = minAmount;
|
|
3167
|
+
if (maxAmount !== undefined)
|
|
3168
|
+
filter.maxAmount = maxAmount;
|
|
3169
|
+
return filter;
|
|
3170
|
+
}
|
|
3171
|
+
function triggersOf(sub) {
|
|
3172
|
+
return sub.triggers ?? [];
|
|
3173
|
+
}
|
|
3174
|
+
function buildSourcesMap(chainSubs) {
|
|
3175
|
+
const sources = {};
|
|
3176
|
+
const keyMeta = new Map;
|
|
3177
|
+
for (const sub of chainSubs) {
|
|
3178
|
+
triggersOf(sub).forEach((trigger, triggerIndex) => {
|
|
3179
|
+
const key2 = sourceKey(sub.id, triggerIndex);
|
|
3180
|
+
sources[key2] = chainTriggerToFilter(trigger);
|
|
3181
|
+
keyMeta.set(key2, {
|
|
3182
|
+
subscriptionId: sub.id,
|
|
3183
|
+
triggerIndex,
|
|
3184
|
+
triggerType: trigger.type
|
|
3185
|
+
});
|
|
3186
|
+
});
|
|
3187
|
+
}
|
|
3188
|
+
return { sources, keyMeta };
|
|
3189
|
+
}
|
|
3190
|
+
function referencedEventTypes(chainSubs) {
|
|
3191
|
+
const filterTypes = new Set;
|
|
3192
|
+
for (const sub of chainSubs) {
|
|
3193
|
+
for (const trigger of triggersOf(sub))
|
|
3194
|
+
filterTypes.add(trigger.type);
|
|
3195
|
+
}
|
|
3196
|
+
return indexEventTypesForFilterTypes([...filterTypes]);
|
|
3197
|
+
}
|
|
3198
|
+
function referencedTraits(chainSubs) {
|
|
3199
|
+
const traits = new Set;
|
|
3200
|
+
for (const sub of chainSubs) {
|
|
3201
|
+
for (const trigger of triggersOf(sub)) {
|
|
3202
|
+
const trait = trigger.trait;
|
|
3203
|
+
if (trait)
|
|
3204
|
+
traits.add(trait);
|
|
3205
|
+
}
|
|
3206
|
+
}
|
|
3207
|
+
return [...traits];
|
|
3208
|
+
}
|
|
3209
|
+
async function buildTraitContracts(db, chainSubs, asOfBlock) {
|
|
3210
|
+
const resolved = new Map;
|
|
3211
|
+
for (const trait of referencedTraits(chainSubs)) {
|
|
3212
|
+
const ids = await resolveTraitContractIds2(db, trait, asOfBlock);
|
|
3213
|
+
resolved.set(trait, new Set(ids));
|
|
3214
|
+
}
|
|
3215
|
+
return resolved;
|
|
3216
|
+
}
|
|
3217
|
+
function evaluateBlock(block, sources, traitContracts) {
|
|
3218
|
+
return matchSources(sources, block.txs, block.events, traitContracts);
|
|
3219
|
+
}
|
|
3220
|
+
function chainDedupKey(subscriptionId, txId, eventIndex, blockHash) {
|
|
3221
|
+
return `chain:${subscriptionId}:${txId}:${eventIndex}:${blockHash}`;
|
|
3222
|
+
}
|
|
3223
|
+
function applyRow(meta, blockHeight, blockHash, txId, eventIndex, event) {
|
|
3224
|
+
const payload = {
|
|
3225
|
+
action: "apply",
|
|
3226
|
+
block_hash: blockHash,
|
|
3227
|
+
block_height: blockHeight,
|
|
3228
|
+
tx_id: txId,
|
|
3229
|
+
canonical: true,
|
|
3230
|
+
trigger: meta.triggerType,
|
|
3231
|
+
event
|
|
3232
|
+
};
|
|
3233
|
+
return {
|
|
3234
|
+
subscription_id: meta.subscriptionId,
|
|
3235
|
+
kind: "chain",
|
|
3236
|
+
subgraph_name: null,
|
|
3237
|
+
table_name: null,
|
|
3238
|
+
block_height: blockHeight,
|
|
3239
|
+
tx_id: txId,
|
|
3240
|
+
row_pk: { tx_id: txId, event_index: eventIndex },
|
|
3241
|
+
event_type: `chain.${meta.triggerType}.apply`,
|
|
3242
|
+
payload,
|
|
3243
|
+
dedup_key: chainDedupKey(meta.subscriptionId, txId, eventIndex, blockHash)
|
|
3244
|
+
};
|
|
3245
|
+
}
|
|
3246
|
+
async function emitChainOutbox(db, matches, keyMeta, blockHeight, blockHash) {
|
|
3247
|
+
const rows = [];
|
|
3248
|
+
for (const match of matches) {
|
|
3249
|
+
const meta = keyMeta.get(match.sourceName);
|
|
3250
|
+
if (!meta)
|
|
3251
|
+
continue;
|
|
3252
|
+
const txId = match.tx.tx_id;
|
|
3253
|
+
if (TX_LEVEL_TRIGGER_TYPES.has(meta.triggerType)) {
|
|
3254
|
+
rows.push(applyRow(meta, blockHeight, blockHash, txId, -1, {
|
|
3255
|
+
tx_id: txId,
|
|
3256
|
+
type: match.tx.type,
|
|
3257
|
+
sender: match.tx.sender,
|
|
3258
|
+
status: match.tx.status,
|
|
3259
|
+
contract_id: match.tx.contract_id ?? null,
|
|
3260
|
+
function_name: match.tx.function_name ?? null,
|
|
3261
|
+
function_args: match.tx.function_args ?? null,
|
|
3262
|
+
result_hex: match.tx.raw_result ?? null
|
|
3263
|
+
}));
|
|
3264
|
+
} else {
|
|
3265
|
+
for (const event of match.events) {
|
|
3266
|
+
rows.push(applyRow(meta, blockHeight, blockHash, txId, event.event_index, {
|
|
3267
|
+
tx_id: txId,
|
|
3268
|
+
type: event.type,
|
|
3269
|
+
event_index: event.event_index,
|
|
3270
|
+
data: event.data
|
|
3271
|
+
}));
|
|
3272
|
+
}
|
|
3273
|
+
}
|
|
3274
|
+
}
|
|
3275
|
+
if (rows.length === 0)
|
|
3276
|
+
return 0;
|
|
3277
|
+
await db.insertInto("subscription_outbox").values(rows).onConflict((oc) => oc.columns(["subscription_id", "dedup_key"]).doNothing()).execute();
|
|
3278
|
+
return rows.length;
|
|
3279
|
+
}
|
|
3280
|
+
|
|
3281
|
+
// src/runtime/trigger-evaluator-loop.ts
|
|
3282
|
+
var POLL_MS2 = Number(process.env.TRIGGER_EVALUATOR_POLL_MS) || 5000;
|
|
3283
|
+
var BATCH = Number(process.env.TRIGGER_EVALUATOR_BATCH) || 200;
|
|
3284
|
+
var MAX_BLOCKS_PER_TICK = Number(process.env.TRIGGER_EVALUATOR_MAX_BLOCKS) || 2000;
|
|
3285
|
+
async function readCursor(db) {
|
|
3286
|
+
const row = await db.selectFrom("trigger_evaluator_state").select("last_processed_block").where("id", "=", true).executeTakeFirst();
|
|
3287
|
+
return row ? Number(row.last_processed_block) : 0;
|
|
3288
|
+
}
|
|
3289
|
+
async function advanceCursor(db, to) {
|
|
3290
|
+
await db.transaction().execute(async (trx) => {
|
|
3291
|
+
const cur = await trx.selectFrom("trigger_evaluator_state").select("last_processed_block").where("id", "=", true).forUpdate().executeTakeFirst();
|
|
3292
|
+
if (cur && Number(cur.last_processed_block) < to) {
|
|
3293
|
+
await trx.updateTable("trigger_evaluator_state").set({ last_processed_block: to, updated_at: new Date }).where("id", "=", true).execute();
|
|
3294
|
+
}
|
|
3295
|
+
});
|
|
3296
|
+
}
|
|
3297
|
+
async function runEvaluatorOnce(db = getTargetDb7()) {
|
|
3298
|
+
const chainSubs = await listActiveChainSubscriptions(db);
|
|
3299
|
+
const source = new PublicApiBlockSource(buildHttpClient(), referencedEventTypes(chainSubs));
|
|
3300
|
+
const tip = await source.getTip();
|
|
3301
|
+
if (tip <= 0)
|
|
3302
|
+
return 0;
|
|
3303
|
+
const cursor = await readCursor(db);
|
|
3304
|
+
if (cursor === 0 || chainSubs.length === 0) {
|
|
3305
|
+
await advanceCursor(db, tip);
|
|
3306
|
+
return 0;
|
|
3307
|
+
}
|
|
3308
|
+
if (cursor >= tip)
|
|
3309
|
+
return 0;
|
|
3310
|
+
const { sources, keyMeta } = buildSourcesMap(chainSubs);
|
|
3311
|
+
const target = Math.min(tip, cursor + MAX_BLOCKS_PER_TICK);
|
|
3312
|
+
let emitted = 0;
|
|
3313
|
+
for (let from = cursor + 1;from <= target; from = from + BATCH) {
|
|
3314
|
+
const to = Math.min(from + BATCH - 1, target);
|
|
3315
|
+
const blocks = await source.loadBlockRange(from, to);
|
|
3316
|
+
const traitContracts = await buildTraitContracts(db, chainSubs, to);
|
|
3317
|
+
for (let h = from;h <= to; h++) {
|
|
3318
|
+
const bd = blocks.get(h);
|
|
3319
|
+
if (!bd)
|
|
3320
|
+
continue;
|
|
3321
|
+
const matches = evaluateBlock(bd, sources, traitContracts);
|
|
3322
|
+
if (matches.length === 0)
|
|
3323
|
+
continue;
|
|
3324
|
+
emitted += await emitChainOutbox(db, matches, keyMeta, h, bd.block.hash);
|
|
3325
|
+
}
|
|
3326
|
+
await advanceCursor(db, to);
|
|
3327
|
+
}
|
|
3328
|
+
return emitted;
|
|
3329
|
+
}
|
|
3330
|
+
function startTriggerEvaluator() {
|
|
3331
|
+
let running = true;
|
|
3332
|
+
let timer;
|
|
3333
|
+
const tick = async () => {
|
|
3334
|
+
if (!running)
|
|
3335
|
+
return;
|
|
3336
|
+
try {
|
|
3337
|
+
const emitted = await runEvaluatorOnce();
|
|
3338
|
+
if (emitted > 0) {
|
|
3339
|
+
logger13.info("Trigger evaluator emitted chain deliveries", {
|
|
3340
|
+
count: emitted
|
|
3341
|
+
});
|
|
3342
|
+
}
|
|
3343
|
+
} catch (err) {
|
|
3344
|
+
logger13.error("Trigger evaluator tick failed", {
|
|
3345
|
+
error: getErrorMessage5(err)
|
|
3346
|
+
});
|
|
3347
|
+
}
|
|
3348
|
+
if (running)
|
|
3349
|
+
timer = setTimeout(tick, POLL_MS2);
|
|
3350
|
+
};
|
|
3351
|
+
timer = setTimeout(tick, POLL_MS2);
|
|
3352
|
+
logger13.info("Trigger evaluator started", { pollMs: POLL_MS2 });
|
|
3081
3353
|
return () => {
|
|
3082
3354
|
running = false;
|
|
3083
3355
|
if (timer)
|
|
@@ -3104,11 +3376,11 @@ async function catchUpAll(subgraphs, db, concurrency) {
|
|
|
3104
3376
|
const def = await loadSubgraphDefinition(sg);
|
|
3105
3377
|
await catchUpSubgraph(def, sg.name);
|
|
3106
3378
|
} catch (err) {
|
|
3107
|
-
const msg =
|
|
3379
|
+
const msg = getErrorMessage6(err);
|
|
3108
3380
|
if (isHandlerNotFoundError(err)) {
|
|
3109
3381
|
await updateSubgraphStatus3(db, sg.name, "error");
|
|
3110
3382
|
}
|
|
3111
|
-
|
|
3383
|
+
logger14.error("Subgraph catch-up failed", {
|
|
3112
3384
|
subgraph: sg.name,
|
|
3113
3385
|
error: msg
|
|
3114
3386
|
});
|
|
@@ -3121,10 +3393,10 @@ function handlerImportUrl(handlerPath, cacheBust = Date.now()) {
|
|
|
3121
3393
|
return `${pathToFileURL(resolve(handlerPath)).href}?t=${cacheBust}`;
|
|
3122
3394
|
}
|
|
3123
3395
|
function sourceListenerUrl() {
|
|
3124
|
-
return process.env.SOURCE_DATABASE_URL
|
|
3396
|
+
return process.env.SOURCE_DATABASE_URL || process.env.DATABASE_URL;
|
|
3125
3397
|
}
|
|
3126
3398
|
function targetListenerUrl() {
|
|
3127
|
-
return process.env.TARGET_DATABASE_URL
|
|
3399
|
+
return process.env.TARGET_DATABASE_URL || process.env.DATABASE_URL;
|
|
3128
3400
|
}
|
|
3129
3401
|
function isHandlerNotFoundError(err) {
|
|
3130
3402
|
if (!(err instanceof Error))
|
|
@@ -3154,7 +3426,7 @@ async function loadSubgraphDefinition(sg) {
|
|
|
3154
3426
|
definitionCache.set(sg.name, def);
|
|
3155
3427
|
if (prevVersion && prevVersion !== sg.version) {
|
|
3156
3428
|
invalidateSubgraphRoute(sg.name);
|
|
3157
|
-
|
|
3429
|
+
logger14.info("Subgraph handler reloaded", {
|
|
3158
3430
|
subgraph: sg.name,
|
|
3159
3431
|
from: prevVersion,
|
|
3160
3432
|
to: sg.version
|
|
@@ -3173,7 +3445,7 @@ function cleanupCaches(active) {
|
|
|
3173
3445
|
}
|
|
3174
3446
|
}
|
|
3175
3447
|
async function synthesizeLegacyReindexOperations() {
|
|
3176
|
-
const db =
|
|
3448
|
+
const db = getTargetDb8();
|
|
3177
3449
|
const stale = (await listSubgraphs2(db)).filter((sg) => sg.status === "reindexing");
|
|
3178
3450
|
for (const sg of stale) {
|
|
3179
3451
|
const active = await findActiveSubgraphOperation(db, sg.id);
|
|
@@ -3188,7 +3460,7 @@ async function synthesizeLegacyReindexOperations() {
|
|
|
3188
3460
|
fromBlock: sg.reindex_from_block == null ? undefined : Number(sg.reindex_from_block),
|
|
3189
3461
|
toBlock: sg.reindex_to_block == null ? undefined : Number(sg.reindex_to_block)
|
|
3190
3462
|
});
|
|
3191
|
-
|
|
3463
|
+
logger14.info("Queued legacy reindex resume operation", {
|
|
3192
3464
|
subgraph: sg.name
|
|
3193
3465
|
});
|
|
3194
3466
|
} catch (err) {
|
|
@@ -3202,7 +3474,7 @@ async function runSubgraphOperation(operation, signal) {
|
|
|
3202
3474
|
if (operation.cancel_requested) {
|
|
3203
3475
|
return 0;
|
|
3204
3476
|
}
|
|
3205
|
-
const db =
|
|
3477
|
+
const db = getTargetDb8();
|
|
3206
3478
|
const subgraph = await db.selectFrom("subgraphs").selectAll().where("id", "=", operation.subgraph_id).executeTakeFirst();
|
|
3207
3479
|
if (!subgraph)
|
|
3208
3480
|
throw new Error(`Subgraph not found: ${operation.subgraph_id}`);
|
|
@@ -3238,13 +3510,13 @@ async function runSubgraphOperation(operation, signal) {
|
|
|
3238
3510
|
}
|
|
3239
3511
|
async function startSubgraphOperationRunner(opts) {
|
|
3240
3512
|
const concurrency = opts?.concurrency ?? DEFAULT_OPERATION_CONCURRENCY;
|
|
3241
|
-
const db =
|
|
3513
|
+
const db = getTargetDb8();
|
|
3242
3514
|
const lockedBy = `${hostname()}:${process.pid}:${randomUUID()}`;
|
|
3243
3515
|
const active = new Map;
|
|
3244
3516
|
const activeRuns = new Map;
|
|
3245
3517
|
let running = true;
|
|
3246
3518
|
let draining = false;
|
|
3247
|
-
|
|
3519
|
+
logger14.info("Starting subgraph operation runner", { concurrency, lockedBy });
|
|
3248
3520
|
const startOperation = (operation) => {
|
|
3249
3521
|
const controller = new AbortController;
|
|
3250
3522
|
active.set(operation.id, controller);
|
|
@@ -3252,9 +3524,9 @@ async function startSubgraphOperationRunner(opts) {
|
|
|
3252
3524
|
if (!running)
|
|
3253
3525
|
return;
|
|
3254
3526
|
heartbeatSubgraphOperation(db, operation.id, lockedBy).catch((err) => {
|
|
3255
|
-
|
|
3527
|
+
logger14.warn("Subgraph operation heartbeat failed", {
|
|
3256
3528
|
operationId: operation.id,
|
|
3257
|
-
error:
|
|
3529
|
+
error: getErrorMessage6(err)
|
|
3258
3530
|
});
|
|
3259
3531
|
});
|
|
3260
3532
|
}, HEARTBEAT_INTERVAL_MS);
|
|
@@ -3264,9 +3536,9 @@ async function startSubgraphOperationRunner(opts) {
|
|
|
3264
3536
|
controller.abort("user-cancelled");
|
|
3265
3537
|
}
|
|
3266
3538
|
}).catch((err) => {
|
|
3267
|
-
|
|
3539
|
+
logger14.warn("Subgraph operation cancel poll failed", {
|
|
3268
3540
|
operationId: operation.id,
|
|
3269
|
-
error:
|
|
3541
|
+
error: getErrorMessage6(err)
|
|
3270
3542
|
});
|
|
3271
3543
|
});
|
|
3272
3544
|
}, CANCEL_POLL_INTERVAL_MS);
|
|
@@ -3281,14 +3553,14 @@ async function startSubgraphOperationRunner(opts) {
|
|
|
3281
3553
|
const reason = String(controller.signal.reason ?? "");
|
|
3282
3554
|
if (controller.signal.aborted && reason === "user-cancelled") {
|
|
3283
3555
|
await cancelSubgraphOperation(db, operation.id, lockedBy, processed);
|
|
3284
|
-
|
|
3556
|
+
logger14.info("Subgraph operation cancelled", {
|
|
3285
3557
|
operationId: operation.id,
|
|
3286
3558
|
subgraph: operation.subgraph_name
|
|
3287
3559
|
});
|
|
3288
3560
|
return;
|
|
3289
3561
|
}
|
|
3290
3562
|
if (controller.signal.aborted) {
|
|
3291
|
-
|
|
3563
|
+
logger14.info("Subgraph operation interrupted", {
|
|
3292
3564
|
operationId: operation.id,
|
|
3293
3565
|
subgraph: operation.subgraph_name,
|
|
3294
3566
|
reason
|
|
@@ -3296,7 +3568,7 @@ async function startSubgraphOperationRunner(opts) {
|
|
|
3296
3568
|
return;
|
|
3297
3569
|
}
|
|
3298
3570
|
await completeSubgraphOperation(db, operation.id, lockedBy, processed);
|
|
3299
|
-
|
|
3571
|
+
logger14.info("Subgraph operation completed", {
|
|
3300
3572
|
operationId: operation.id,
|
|
3301
3573
|
subgraph: operation.subgraph_name,
|
|
3302
3574
|
processed
|
|
@@ -3304,7 +3576,7 @@ async function startSubgraphOperationRunner(opts) {
|
|
|
3304
3576
|
} catch (err) {
|
|
3305
3577
|
const reason = String(controller.signal.reason ?? "");
|
|
3306
3578
|
if (controller.signal.aborted && reason === "shutdown") {
|
|
3307
|
-
|
|
3579
|
+
logger14.info("Subgraph operation interrupted by shutdown", {
|
|
3308
3580
|
operationId: operation.id,
|
|
3309
3581
|
subgraph: operation.subgraph_name
|
|
3310
3582
|
});
|
|
@@ -3314,11 +3586,11 @@ async function startSubgraphOperationRunner(opts) {
|
|
|
3314
3586
|
await cancelSubgraphOperation(db, operation.id, lockedBy, processed);
|
|
3315
3587
|
return;
|
|
3316
3588
|
}
|
|
3317
|
-
await failSubgraphOperation(db, operation.id, lockedBy,
|
|
3318
|
-
|
|
3589
|
+
await failSubgraphOperation(db, operation.id, lockedBy, getErrorMessage6(err), processed);
|
|
3590
|
+
logger14.error("Subgraph operation failed", {
|
|
3319
3591
|
operationId: operation.id,
|
|
3320
3592
|
subgraph: operation.subgraph_name,
|
|
3321
|
-
error:
|
|
3593
|
+
error: getErrorMessage6(err)
|
|
3322
3594
|
});
|
|
3323
3595
|
} finally {
|
|
3324
3596
|
clearInterval(heartbeat);
|
|
@@ -3362,23 +3634,23 @@ async function startSubgraphOperationRunner(opts) {
|
|
|
3362
3634
|
controller.abort("shutdown");
|
|
3363
3635
|
}
|
|
3364
3636
|
await Promise.allSettled(activeRuns.values());
|
|
3365
|
-
|
|
3637
|
+
logger14.info("Subgraph operation runner stopped");
|
|
3366
3638
|
};
|
|
3367
3639
|
}
|
|
3368
3640
|
async function startSubgraphProcessor(opts) {
|
|
3369
3641
|
const concurrency = opts?.concurrency ?? DEFAULT_CONCURRENCY;
|
|
3370
3642
|
let running = true;
|
|
3371
|
-
|
|
3643
|
+
logger14.info("Starting subgraph processor", { concurrency });
|
|
3372
3644
|
const stopOperations = await startSubgraphOperationRunner({
|
|
3373
3645
|
concurrency: Number.parseInt(process.env.SUBGRAPH_OPERATION_CONCURRENCY ?? String(DEFAULT_OPERATION_CONCURRENCY))
|
|
3374
3646
|
});
|
|
3375
|
-
const targetDb =
|
|
3647
|
+
const targetDb = getTargetDb8();
|
|
3376
3648
|
const activeSubgraphs = (await listSubgraphs2(targetDb)).filter((v) => v.status === "active");
|
|
3377
3649
|
await catchUpAll(activeSubgraphs, targetDb, concurrency);
|
|
3378
3650
|
const stopListening = await listen2(CHANNEL_NEW_BLOCK, async () => {
|
|
3379
3651
|
if (!running)
|
|
3380
3652
|
return;
|
|
3381
|
-
const db =
|
|
3653
|
+
const db = getTargetDb8();
|
|
3382
3654
|
const subgraphs = (await listSubgraphs2(db)).filter((v) => v.status === "active");
|
|
3383
3655
|
cleanupCaches(subgraphs);
|
|
3384
3656
|
await catchUpAll(subgraphs, db, concurrency);
|
|
@@ -3393,37 +3665,39 @@ async function startSubgraphProcessor(opts) {
|
|
|
3393
3665
|
await handleSubgraphReorg(blockHeight, loadSubgraphDefinition);
|
|
3394
3666
|
}
|
|
3395
3667
|
} catch (err) {
|
|
3396
|
-
|
|
3397
|
-
error:
|
|
3668
|
+
logger14.error("Subgraph reorg handling failed", {
|
|
3669
|
+
error: getErrorMessage6(err)
|
|
3398
3670
|
});
|
|
3399
3671
|
}
|
|
3400
3672
|
}, { connectionString: sourceListenerUrl() });
|
|
3401
3673
|
const pollInterval = setInterval(async () => {
|
|
3402
3674
|
if (!running)
|
|
3403
3675
|
return;
|
|
3404
|
-
const db =
|
|
3676
|
+
const db = getTargetDb8();
|
|
3405
3677
|
const subgraphs = (await listSubgraphs2(db)).filter((v) => v.status === "active");
|
|
3406
3678
|
cleanupCaches(subgraphs);
|
|
3407
3679
|
await catchUpAll(subgraphs, db, concurrency);
|
|
3408
3680
|
}, POLL_INTERVAL_MS);
|
|
3409
|
-
const stopStreamsReorgPoll = process.env.SUBGRAPH_SOURCE === "streams-index" ? startStreamsReorgPoll(handleSubgraphReorg, loadSubgraphDefinition) : undefined;
|
|
3681
|
+
const stopStreamsReorgPoll = process.env.SUBGRAPH_SOURCE === "streams-index" ? startStreamsReorgPoll(handleSubgraphReorg, loadSubgraphDefinition, (forkHeight) => handleChainReorg(forkHeight)) : undefined;
|
|
3682
|
+
const stopTriggerEvaluator = process.env.SUBGRAPH_SOURCE === "streams-index" ? startTriggerEvaluator() : undefined;
|
|
3410
3683
|
const stopEmitter = await startEmitter();
|
|
3411
|
-
|
|
3684
|
+
logger14.info("Subgraph processor ready");
|
|
3412
3685
|
return async () => {
|
|
3413
3686
|
running = false;
|
|
3414
3687
|
clearInterval(pollInterval);
|
|
3415
3688
|
await stopListening();
|
|
3416
3689
|
await stopReorgListening();
|
|
3417
3690
|
stopStreamsReorgPoll?.();
|
|
3691
|
+
stopTriggerEvaluator?.();
|
|
3418
3692
|
await stopOperations();
|
|
3419
3693
|
await stopEmitter();
|
|
3420
|
-
|
|
3694
|
+
logger14.info("Subgraph processor stopped");
|
|
3421
3695
|
};
|
|
3422
3696
|
}
|
|
3423
3697
|
|
|
3424
3698
|
// src/service.ts
|
|
3425
|
-
import { getDb } from "@secondlayer/shared/db";
|
|
3426
|
-
import { logger as
|
|
3699
|
+
import { assertDbSplit, getDb } from "@secondlayer/shared/db";
|
|
3700
|
+
import { logger as logger15 } from "@secondlayer/shared/logger";
|
|
3427
3701
|
import { sql as sql5 } from "kysely";
|
|
3428
3702
|
var HEARTBEAT_INTERVAL_MS2 = 30000;
|
|
3429
3703
|
var SERVICE_NAME = "subgraph-processor";
|
|
@@ -3431,18 +3705,19 @@ async function writeHeartbeat() {
|
|
|
3431
3705
|
try {
|
|
3432
3706
|
await getDb().insertInto("service_heartbeats").values({ name: SERVICE_NAME }).onConflict((oc) => oc.column("name").doUpdateSet({ updated_at: sql5`now()` })).execute();
|
|
3433
3707
|
} catch (err) {
|
|
3434
|
-
|
|
3708
|
+
logger15.warn("subgraph-processor heartbeat write failed", {
|
|
3435
3709
|
error: err instanceof Error ? err.message : String(err)
|
|
3436
3710
|
});
|
|
3437
3711
|
}
|
|
3438
3712
|
}
|
|
3713
|
+
assertDbSplit();
|
|
3439
3714
|
var processor = await startSubgraphProcessor({
|
|
3440
3715
|
concurrency: Number.parseInt(process.env.SUBGRAPH_CONCURRENCY ?? "5")
|
|
3441
3716
|
});
|
|
3442
3717
|
await writeHeartbeat();
|
|
3443
3718
|
var heartbeatInterval = setInterval(writeHeartbeat, HEARTBEAT_INTERVAL_MS2);
|
|
3444
3719
|
var shutdown = async () => {
|
|
3445
|
-
|
|
3720
|
+
logger15.info("Shutting down subgraph processor...");
|
|
3446
3721
|
clearInterval(heartbeatInterval);
|
|
3447
3722
|
await processor();
|
|
3448
3723
|
process.exit(0);
|
|
@@ -3450,5 +3725,5 @@ var shutdown = async () => {
|
|
|
3450
3725
|
process.on("SIGINT", shutdown);
|
|
3451
3726
|
process.on("SIGTERM", shutdown);
|
|
3452
3727
|
|
|
3453
|
-
//# debugId=
|
|
3728
|
+
//# debugId=FC45FDEF6FFE3A5D64756E2164756E21
|
|
3454
3729
|
//# sourceMappingURL=service.js.map
|