@secondlayer/subgraphs 4.2.1 → 4.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/README.md +9 -9
- package/dist/src/index.js +11 -11
- package/dist/src/index.js.map +9 -9
- package/dist/src/runtime/block-processor.js +11 -11
- package/dist/src/runtime/block-processor.js.map +9 -9
- package/dist/src/runtime/catchup.js +11 -11
- package/dist/src/runtime/catchup.js.map +9 -9
- package/dist/src/runtime/context.d.ts +1 -1
- package/dist/src/runtime/context.js.map +1 -1
- package/dist/src/runtime/emitter.d.ts +10 -10
- package/dist/src/runtime/emitter.js +47 -46
- package/dist/src/runtime/emitter.js.map +14 -14
- package/dist/src/runtime/processor.js +19 -19
- package/dist/src/runtime/processor.js.map +13 -13
- package/dist/src/runtime/reindex.js +11 -11
- package/dist/src/runtime/reindex.js.map +9 -9
- package/dist/src/runtime/reorg.d.ts +2 -2
- package/dist/src/runtime/reorg.js +17 -17
- package/dist/src/runtime/reorg.js.map +10 -10
- package/dist/src/runtime/replay.d.ts +6 -6
- package/dist/src/runtime/replay.js +26 -26
- package/dist/src/runtime/replay.js.map +4 -4
- package/dist/src/runtime/runner.d.ts +1 -1
- package/dist/src/service.js +19 -19
- package/dist/src/service.js.map +14 -14
- package/dist/src/testing/index.js.map +1 -1
- package/dist/src/triggers/index.d.ts +2 -2
- package/dist/src/triggers/index.js.map +1 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -13,7 +13,7 @@ bun add @secondlayer/subgraphs
|
|
|
13
13
|
## Quick Start
|
|
14
14
|
|
|
15
15
|
For the full hosted beta loop, including project setup, fast deploys with
|
|
16
|
-
`--start-block`, querying, and
|
|
16
|
+
`--start-block`, querying, and webhooks, start with
|
|
17
17
|
[QUICKSTART.md](QUICKSTART.md).
|
|
18
18
|
|
|
19
19
|
```typescript
|
|
@@ -63,24 +63,24 @@ Deploy via CLI (`secondlayer subgraphs deploy path/to/definition.ts`), SDK (`sl.
|
|
|
63
63
|
| `./validate` | Shape + filter validation for deploys |
|
|
64
64
|
| `./triggers` | Typed `on.*` helpers for all `SubgraphFilter` variants |
|
|
65
65
|
| `./runtime/source-matcher` | Pure fn: match txs+events against a `SubgraphFilter` — used by the processor hot path |
|
|
66
|
-
| `./runtime/replay` | `
|
|
66
|
+
| `./runtime/replay` | `replayWebhook({ accountId, webhookId, fromBlock, toBlock })` — re-enqueue historical rows as outbox entries |
|
|
67
67
|
|
|
68
68
|
## Runtime components
|
|
69
69
|
|
|
70
70
|
The runtime ships behind these entrypoints (import from the package root):
|
|
71
71
|
|
|
72
|
-
- `startSubgraphProcessor(opts?)` — boots the block processor. LISTENs on `indexer:new_block`, matches sources, runs handlers, flushes writes inside a transaction, and emits outbox rows for matching
|
|
72
|
+
- `startSubgraphProcessor(opts?)` — boots the block processor. LISTENs on `indexer:new_block`, matches sources, runs handlers, flushes writes inside a transaction, and emits outbox rows for matching webhooks. Also boots the emitter worker.
|
|
73
73
|
- `processBlock(subgraph, name, height, opts?)` — single-block entry point used by catch-up, reindex, and tests.
|
|
74
74
|
- `catchUpSubgraph(def, name)` — drains pending blocks up to chain tip.
|
|
75
75
|
- `reindexSubgraph(def, opts)` — drop + rebuild schema tables from a start block. Breaking schema changes trigger this automatically on deploy.
|
|
76
76
|
|
|
77
|
-
##
|
|
77
|
+
## Webhook emitter
|
|
78
78
|
|
|
79
|
-
Every row written through `ctx.insert()` / `ctx.upsert()` is atomically enqueued to `
|
|
79
|
+
Every row written through `ctx.insert()` / `ctx.upsert()` is atomically enqueued to `webhook_outbox` for every active webhook whose filter matches — inside the same transaction as the flush, so a processor crash rolls back both.
|
|
80
80
|
|
|
81
|
-
The emitter drains the outbox via `LISTEN
|
|
81
|
+
The emitter drains the outbox via `LISTEN webhooks:new_outbox` and `FOR UPDATE SKIP LOCKED` batch claims. Live deliveries win a 90/10 split over replays. Each row dispatches through the format builder matching the webhook's `format` column (`standard-webhooks`, `inngest`, `trigger`, `cloudflare`, `cloudevents`, `raw`). Retries follow `30s → 2m → 10m → 1h → 6h → 24h → 72h`. Twenty consecutive failures trips the per-sub circuit breaker and pauses the webhook.
|
|
82
82
|
|
|
83
|
-
Delivery bodies and response previews land in `
|
|
83
|
+
Delivery bodies and response previews land in `webhook_deliveries`. Rows whose retries exhaust mark `status = 'dead'` in the outbox and surface in the dashboard's dead-letter queue for one-click requeue.
|
|
84
84
|
|
|
85
85
|
## Environment
|
|
86
86
|
|
|
@@ -88,7 +88,7 @@ Delivery bodies and response previews land in `subscription_deliveries`. Rows wh
|
|
|
88
88
|
| --- | --- | --- |
|
|
89
89
|
| `SECONDLAYER_EMIT_OUTBOX` | `true` | Set `false` to bypass outbox emission on every block (kill-switch). |
|
|
90
90
|
| `SECONDLAYER_ALLOW_PRIVATE_EGRESS` | `false` | Allow the emitter to deliver to private IP ranges (localhost, 10/8, 172.16/12, 192.168/16, link-local, v6 mapped). Leave off in production. |
|
|
91
|
-
| `SECONDLAYER_SECRETS_KEY` | — | 32-byte hex key for the AES-GCM envelope around
|
|
91
|
+
| `SECONDLAYER_SECRETS_KEY` | — | 32-byte hex key for the AES-GCM envelope around webhook signing secrets. OSS mode auto-generates + persists to `.env.local`. |
|
|
92
92
|
| `SUBGRAPH_REINDEX_BATCH_SIZE` | adaptive | Override the default historical block batch size used by reindex/backfill. |
|
|
93
93
|
| `SUBGRAPH_REINDEX_MIN_BATCH_SIZE` | adaptive | Override the adaptive lower bound for reindex/backfill batches. |
|
|
94
94
|
| `SUBGRAPH_REINDEX_MAX_BATCH_SIZE` | adaptive | Override the adaptive upper bound for reindex/backfill batches. |
|
|
@@ -132,7 +132,7 @@ populated. Discover the set via `GET /v1/contracts?trait=sip-010`.
|
|
|
132
132
|
|
|
133
133
|
## Postgres + pool mode
|
|
134
134
|
|
|
135
|
-
The emitter holds a persistent `LISTEN` on `
|
|
135
|
+
The emitter holds a persistent `LISTEN` on `webhooks:new_outbox` and `webhooks:changed`, so it MUST connect through a session-mode pool. pgbouncer in transaction mode silently breaks it. Run the emitter against a session-mode port (`pool_mode = session`), or connect directly to Postgres as the default docker-compose setup does.
|
|
136
136
|
|
|
137
137
|
## License
|
|
138
138
|
|
package/dist/src/index.js
CHANGED
|
@@ -3030,7 +3030,7 @@ function stableStringify(obj) {
|
|
|
3030
3030
|
return acc;
|
|
3031
3031
|
}, {}));
|
|
3032
3032
|
}
|
|
3033
|
-
async function
|
|
3033
|
+
async function emitWebhookOutbox(tx, subgraphName, manifest, matcher, blockHeight) {
|
|
3034
3034
|
if (!isEmitOutboxEnabled()) {
|
|
3035
3035
|
if (!loggedKillSwitch) {
|
|
3036
3036
|
logger6.warn("SECONDLAYER_EMIT_OUTBOX=false — outbox emission bypassed");
|
|
@@ -3049,7 +3049,7 @@ async function emitSubscriptionOutbox(tx, subgraphName, manifest, matcher, block
|
|
|
3049
3049
|
const eventType = `${subgraphName}.${write.table}.${OP_VERB[write.op]}`;
|
|
3050
3050
|
for (const s of subs) {
|
|
3051
3051
|
rows.push({
|
|
3052
|
-
|
|
3052
|
+
webhook_id: s.id,
|
|
3053
3053
|
subgraph_name: subgraphName,
|
|
3054
3054
|
table_name: write.table,
|
|
3055
3055
|
block_height: blockHeight,
|
|
@@ -3063,7 +3063,7 @@ async function emitSubscriptionOutbox(tx, subgraphName, manifest, matcher, block
|
|
|
3063
3063
|
}
|
|
3064
3064
|
if (rows.length === 0)
|
|
3065
3065
|
return 0;
|
|
3066
|
-
await tx.insertInto("
|
|
3066
|
+
await tx.insertInto("webhook_outbox").values(rows).onConflict((oc) => oc.columns(["webhook_id", "dedup_key"]).doNothing()).execute();
|
|
3067
3067
|
return rows.length;
|
|
3068
3068
|
}
|
|
3069
3069
|
|
|
@@ -3376,8 +3376,8 @@ async function answerRead(hostCtx, msg) {
|
|
|
3376
3376
|
}
|
|
3377
3377
|
}
|
|
3378
3378
|
|
|
3379
|
-
// src/runtime/
|
|
3380
|
-
import {
|
|
3379
|
+
// src/runtime/webhook-state.ts
|
|
3380
|
+
import { listWebhooks } from "@secondlayer/shared/db/queries/webhooks";
|
|
3381
3381
|
import { sql as sql3 } from "kysely";
|
|
3382
3382
|
|
|
3383
3383
|
// src/runtime/emitter-matcher.ts
|
|
@@ -3497,7 +3497,7 @@ function key(subgraphName, tableName) {
|
|
|
3497
3497
|
return `${subgraphName}\x00${tableName}`;
|
|
3498
3498
|
}
|
|
3499
3499
|
|
|
3500
|
-
class
|
|
3500
|
+
class WebhookMatcher {
|
|
3501
3501
|
byKey = new Map;
|
|
3502
3502
|
byId = new Map;
|
|
3503
3503
|
setAll(subs) {
|
|
@@ -3539,11 +3539,11 @@ class SubscriptionMatcher {
|
|
|
3539
3539
|
}
|
|
3540
3540
|
}
|
|
3541
3541
|
|
|
3542
|
-
// src/runtime/
|
|
3543
|
-
var matcher = new
|
|
3542
|
+
// src/runtime/webhook-state.ts
|
|
3543
|
+
var matcher = new WebhookMatcher;
|
|
3544
3544
|
async function refreshMatcher(db) {
|
|
3545
3545
|
const rows = await sql3`
|
|
3546
|
-
SELECT * FROM
|
|
3546
|
+
SELECT * FROM webhooks WHERE status = 'active'
|
|
3547
3547
|
`.execute(db);
|
|
3548
3548
|
matcher.setAll(rows.rows);
|
|
3549
3549
|
return matcher.size();
|
|
@@ -3833,7 +3833,7 @@ async function processBlock(subgraph, subgraphName, blockHeight, opts) {
|
|
|
3833
3833
|
const manifest = await ctx.flush();
|
|
3834
3834
|
flushedWrites = manifest.count > 0;
|
|
3835
3835
|
if (manifest.count > 0) {
|
|
3836
|
-
await
|
|
3836
|
+
await emitWebhookOutbox(tx, subgraphName, manifest, matcher, block.height);
|
|
3837
3837
|
}
|
|
3838
3838
|
flushMs = performance.now() - flushStart;
|
|
3839
3839
|
}
|
|
@@ -5798,5 +5798,5 @@ export {
|
|
|
5798
5798
|
ChainReadError
|
|
5799
5799
|
};
|
|
5800
5800
|
|
|
5801
|
-
//# debugId=
|
|
5801
|
+
//# debugId=ADB058A57FECD09264756E2164756E21
|
|
5802
5802
|
//# sourceMappingURL=index.js.map
|