@secondlayer/subgraphs 6.3.3 → 6.3.5
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 +2 -0
- package/dist/index.d.ts +9 -1
- package/dist/index.js +62 -20
- package/dist/index.js.map +3 -3
- package/dist/runtime/replay.js +62 -20
- package/dist/runtime/replay.js.map +3 -3
- package/dist/testing/index.js.map +2 -2
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
Typed on-chain indexing for Stacks. Declare event filters + column schema with `defineSubgraph()`; the runtime decodes blocks, matches filters, runs your handlers inside a transactional context, and exposes the result as a Postgres schema you query over REST or SQL.
|
|
4
4
|
|
|
5
|
+
Run subgraphs on your own instance, or hosted on `api.secondlayer.tools` with `secondlayer subgraphs deploy` and your account key (`SECONDLAYER_API_KEY`). Hosted subgraphs are private to your account and limited to event filters and `contract_call`/`contract_deploy` sources (`422 SOURCE_NOT_HOSTABLE` otherwise); set `startBlock`. Subgraph webhooks are self-host only.
|
|
6
|
+
|
|
5
7
|
Subgraph rows fan out to HTTP subscribers through a post-flush outbox emitter — signed Standard Webhooks POSTs with retries, circuit breaker, and replay.
|
|
6
8
|
|
|
7
9
|
## Install
|
package/dist/index.d.ts
CHANGED
|
@@ -1197,7 +1197,15 @@ type SparseProbeTarget = {
|
|
|
1197
1197
|
* a contract_call/contract_deploy source matches transactions, which the
|
|
1198
1198
|
* event probe can't see. */
|
|
1199
1199
|
declare function canSparseScan(subgraph: SubgraphDefinition): boolean;
|
|
1200
|
-
/**
|
|
1200
|
+
/**
|
|
1201
|
+
* The (decoded event type, contract scope) pairs a subgraph's filters can
|
|
1202
|
+
* match. One function feeds BOTH the sparse probe and the event walks, so a
|
|
1203
|
+
* new contract-pinning filter field is added here once.
|
|
1204
|
+
*
|
|
1205
|
+
* Per event type: if ANY filter for it is unscoped, a single unscoped target
|
|
1206
|
+
* covers everything (today's behavior); otherwise one target per distinct
|
|
1207
|
+
* pinned contract.
|
|
1208
|
+
*/
|
|
1201
1209
|
declare function sparseProbeTargets(subgraph: SubgraphDefinition): SparseProbeTarget[];
|
|
1202
1210
|
/**
|
|
1203
1211
|
* streams-index eligibility: every source must be a known event-type or
|
package/dist/index.js
CHANGED
|
@@ -1979,18 +1979,44 @@ function canSparseScan(subgraph) {
|
|
|
1979
1979
|
return false;
|
|
1980
1980
|
return filters.every((f) => Boolean(EVENT_FILTER_TO_INDEX_TYPE[f.type]));
|
|
1981
1981
|
}
|
|
1982
|
+
var MAX_PINNED_CONTRACTS = 20;
|
|
1983
|
+
function pinnedContracts(filter) {
|
|
1984
|
+
const f = filter;
|
|
1985
|
+
if (f.trait || f.factory)
|
|
1986
|
+
return null;
|
|
1987
|
+
const ids = Array.isArray(f.contractId) ? [...f.contractId] : f.contractId ? [f.contractId] : f.assetIdentifier ? [f.assetIdentifier.split("::")[0]] : [];
|
|
1988
|
+
if (ids.length === 0 || ids.length > MAX_PINNED_CONTRACTS)
|
|
1989
|
+
return null;
|
|
1990
|
+
if (ids.some((id) => !id || id.includes("*")))
|
|
1991
|
+
return null;
|
|
1992
|
+
return ids;
|
|
1993
|
+
}
|
|
1982
1994
|
function sparseProbeTargets(subgraph) {
|
|
1983
|
-
const
|
|
1995
|
+
const byType = new Map;
|
|
1984
1996
|
for (const f of sourceFilters(subgraph)) {
|
|
1985
1997
|
const eventType = EVENT_FILTER_TO_INDEX_TYPE[f.type];
|
|
1986
1998
|
if (!eventType)
|
|
1987
1999
|
continue;
|
|
1988
|
-
const
|
|
1989
|
-
const
|
|
1990
|
-
|
|
1991
|
-
|
|
2000
|
+
const pinned = pinnedContracts(f);
|
|
2001
|
+
const prev = byType.get(eventType);
|
|
2002
|
+
if (!pinned || prev === "all") {
|
|
2003
|
+
byType.set(eventType, "all");
|
|
2004
|
+
continue;
|
|
2005
|
+
}
|
|
2006
|
+
const set = prev ?? new Set;
|
|
2007
|
+
for (const id of pinned)
|
|
2008
|
+
set.add(id);
|
|
2009
|
+
byType.set(eventType, set);
|
|
1992
2010
|
}
|
|
1993
|
-
|
|
2011
|
+
const targets = [];
|
|
2012
|
+
for (const [eventType, scope] of byType) {
|
|
2013
|
+
if (scope === "all")
|
|
2014
|
+
targets.push({ eventType });
|
|
2015
|
+
else
|
|
2016
|
+
for (const contractId of scope)
|
|
2017
|
+
targets.push({ eventType, contractId });
|
|
2018
|
+
}
|
|
2019
|
+
return targets;
|
|
1994
2020
|
}
|
|
1995
2021
|
|
|
1996
2022
|
class PostgresBlockSource {
|
|
@@ -2069,6 +2095,16 @@ function isStreamsIndexEligible(subgraph) {
|
|
|
2069
2095
|
}
|
|
2070
2096
|
return true;
|
|
2071
2097
|
}
|
|
2098
|
+
function dedupeEvents(rows) {
|
|
2099
|
+
const seen = new Set;
|
|
2100
|
+
return rows.filter((e) => {
|
|
2101
|
+
const key = `${e.event_type}|${e.block_height}|${e.event_index}`;
|
|
2102
|
+
if (seen.has(key))
|
|
2103
|
+
return false;
|
|
2104
|
+
seen.add(key);
|
|
2105
|
+
return true;
|
|
2106
|
+
});
|
|
2107
|
+
}
|
|
2072
2108
|
|
|
2073
2109
|
class PublicApiBlockSource {
|
|
2074
2110
|
http;
|
|
@@ -2081,6 +2117,13 @@ class PublicApiBlockSource {
|
|
|
2081
2117
|
this.probeTargets = probeTargets;
|
|
2082
2118
|
this.needsTransactions = needsTransactions;
|
|
2083
2119
|
}
|
|
2120
|
+
walkTargets() {
|
|
2121
|
+
const scoped = this.needsTransactions ? undefined : this.probeTargets;
|
|
2122
|
+
return this.eventTypes.flatMap((eventType) => {
|
|
2123
|
+
const own = scoped?.filter((t) => t.eventType === eventType);
|
|
2124
|
+
return own?.length ? own : [{ eventType }];
|
|
2125
|
+
});
|
|
2126
|
+
}
|
|
2084
2127
|
async nextDataHeight(afterHeight, untilHeight) {
|
|
2085
2128
|
if (!this.probeTargets?.length)
|
|
2086
2129
|
return afterHeight + 1;
|
|
@@ -2102,8 +2145,9 @@ class PublicApiBlockSource {
|
|
|
2102
2145
|
const [blocks, txRows, eventLists] = await Promise.all([
|
|
2103
2146
|
this.http.walkBlocks(fromHeight, toHeight),
|
|
2104
2147
|
this.needsTransactions ? this.http.walkTransactions(fromHeight, toHeight) : Promise.resolve([]),
|
|
2105
|
-
Promise.all(this.
|
|
2148
|
+
Promise.all(this.walkTargets().map((t) => this.http.walkEvents(t.eventType, fromHeight, toHeight, withTx, t.contractId)))
|
|
2106
2149
|
]);
|
|
2150
|
+
const events = dedupeEvents(eventLists.flat());
|
|
2107
2151
|
const map = new Map;
|
|
2108
2152
|
for (const b of blocks) {
|
|
2109
2153
|
map.set(b.block_height, {
|
|
@@ -2112,21 +2156,19 @@ class PublicApiBlockSource {
|
|
|
2112
2156
|
events: []
|
|
2113
2157
|
});
|
|
2114
2158
|
}
|
|
2115
|
-
const txs = this.needsTransactions ? txRows.map(reconstructTransaction) : synthesizeTxsFromEvents(
|
|
2159
|
+
const txs = this.needsTransactions ? txRows.map(reconstructTransaction) : synthesizeTxsFromEvents(events);
|
|
2116
2160
|
for (const t of txs) {
|
|
2117
2161
|
map.get(t.block_height)?.txs.push(t);
|
|
2118
2162
|
}
|
|
2119
|
-
for (const
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
bd.events.push(reconstructEvent(e));
|
|
2129
|
-
}
|
|
2163
|
+
for (const e of events) {
|
|
2164
|
+
const bd = map.get(e.block_height);
|
|
2165
|
+
if (!bd)
|
|
2166
|
+
continue;
|
|
2167
|
+
if (VM_INDEX_EVENT_TYPES.has(e.event_type)) {
|
|
2168
|
+
bd.vmEvents ??= [];
|
|
2169
|
+
bd.vmEvents.push(reconstructEvent(e));
|
|
2170
|
+
} else {
|
|
2171
|
+
bd.events.push(reconstructEvent(e));
|
|
2130
2172
|
}
|
|
2131
2173
|
}
|
|
2132
2174
|
for (const bd of map.values()) {
|
|
@@ -2165,5 +2207,5 @@ export {
|
|
|
2165
2207
|
validateSubgraphDefinition
|
|
2166
2208
|
};
|
|
2167
2209
|
|
|
2168
|
-
//# debugId=
|
|
2210
|
+
//# debugId=9E0F3F4652CCD15164756E2164756E21
|
|
2169
2211
|
//# sourceMappingURL=index.js.map
|