@artblocks/abx-indexer 0.1.0-alpha.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/LICENSE +21 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -0
- package/dist/indexer.d.ts +43 -0
- package/dist/indexer.d.ts.map +1 -0
- package/dist/indexer.js +82 -0
- package/dist/indexer.js.map +1 -0
- package/dist/store.d.ts +146 -0
- package/dist/store.d.ts.map +1 -0
- package/dist/store.js +484 -0
- package/dist/store.js.map +1 -0
- package/package.json +47 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Art Blocks, Inc.
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @artblocks/abx-indexer — Layer 3 reference indexer.
|
|
3
|
+
*
|
|
4
|
+
* Replays the event spine from chain into a disposable, rebuildable projection.
|
|
5
|
+
* The canonical re-index: how every service onboards or exits a project.
|
|
6
|
+
*/
|
|
7
|
+
export { SelfHostIndexer, type IndexResult } from './indexer.js';
|
|
8
|
+
export { SqliteStore, type Store, type ProjectRegistration, type EffectStatusRow, type EffectArtifactRow, } from './store.js';
|
|
9
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAC,eAAe,EAAE,KAAK,WAAW,EAAC,MAAM,cAAc,CAAC;AAC/D,OAAO,EACL,WAAW,EACX,KAAK,KAAK,EACV,KAAK,mBAAmB,EACxB,KAAK,eAAe,EACpB,KAAK,iBAAiB,GACvB,MAAM,YAAY,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @artblocks/abx-indexer — Layer 3 reference indexer.
|
|
3
|
+
*
|
|
4
|
+
* Replays the event spine from chain into a disposable, rebuildable projection.
|
|
5
|
+
* The canonical re-index: how every service onboards or exits a project.
|
|
6
|
+
*/
|
|
7
|
+
export { SelfHostIndexer } from './indexer.js';
|
|
8
|
+
export { SqliteStore, } from './store.js';
|
|
9
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAC,eAAe,EAAmB,MAAM,cAAc,CAAC;AAC/D,OAAO,EACL,WAAW,GAKZ,MAAM,YAAY,CAAC"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { type Address, type ProjectState, type PublicClient } from '@artblocks/abx-sdk';
|
|
2
|
+
import { type Store, type ProjectRegistration } from './store.js';
|
|
3
|
+
export interface IndexResult {
|
|
4
|
+
state: ProjectState;
|
|
5
|
+
elapsedMs: number;
|
|
6
|
+
mode: 'full' | 'incremental';
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* The reference indexer (Layer 3). It does one thing well: replay the event
|
|
10
|
+
* spine from chain into the store. Because every state change rides a standard,
|
|
11
|
+
* versioned event, re-indexing is a *compute* cost, not an engineering one — and
|
|
12
|
+
* it needs no cooperation from whatever provider held the data before. This is
|
|
13
|
+
* the implementation everyone re-indexes with when they onboard or leave a
|
|
14
|
+
* service; running a different one changes nothing the protocol guarantees.
|
|
15
|
+
*/
|
|
16
|
+
export declare class SelfHostIndexer {
|
|
17
|
+
readonly store: Store;
|
|
18
|
+
private clients;
|
|
19
|
+
constructor(store?: Store);
|
|
20
|
+
private client;
|
|
21
|
+
/** The RPC client for a chain — exposed for reads that aren't a reindex (e.g. deploy-block
|
|
22
|
+
* discovery in the admin control plane). Reuses the same pooled client as `reindex`. */
|
|
23
|
+
publicClient(chainKey: string): PublicClient;
|
|
24
|
+
/** Register a project to index (the minimum needed to replay it). */
|
|
25
|
+
register(reg: Omit<ProjectRegistration, 'registeredAt'>): ProjectRegistration;
|
|
26
|
+
/**
|
|
27
|
+
* Re-index a single project. By default this is **incremental**: it resumes from
|
|
28
|
+
* the stored checkpoint and only fetches blocks added since — so re-indexing is
|
|
29
|
+
* fast no matter how far head has moved — yet yields state identical to a full
|
|
30
|
+
* replay. `{full: true}` forces a replay from the deploy block (the durability
|
|
31
|
+
* proof, and what runs automatically when there's no prior state). Idempotent.
|
|
32
|
+
*/
|
|
33
|
+
reindex(address: Address, opts?: {
|
|
34
|
+
full?: boolean;
|
|
35
|
+
}): Promise<IndexResult>;
|
|
36
|
+
/** Re-index every registered project. */
|
|
37
|
+
reindexAll(opts?: {
|
|
38
|
+
full?: boolean;
|
|
39
|
+
}): Promise<IndexResult[]>;
|
|
40
|
+
getProject(address: Address): ProjectState | null;
|
|
41
|
+
listProjects(): ProjectState[];
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=indexer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"indexer.d.ts","sourceRoot":"","sources":["../src/indexer.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,OAAO,EACZ,KAAK,YAAY,EACjB,KAAK,YAAY,EAClB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAc,KAAK,KAAK,EAAE,KAAK,mBAAmB,EAAC,MAAM,YAAY,CAAC;AAE7E,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,YAAY,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,GAAG,aAAa,CAAC;CAC9B;AAED;;;;;;;GAOG;AACH,qBAAa,eAAe;IAC1B,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;IACtB,OAAO,CAAC,OAAO,CAAmC;gBAEtC,KAAK,CAAC,EAAE,KAAK;IAIzB,OAAO,CAAC,MAAM;IAMd;6FACyF;IACzF,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,YAAY;IAI5C,qEAAqE;IACrE,QAAQ,CAAC,GAAG,EAAE,IAAI,CAAC,mBAAmB,EAAE,cAAc,CAAC,GAAG,mBAAmB;IAM7E;;;;;;OAMG;IACG,OAAO,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,GAAE;QAAC,IAAI,CAAC,EAAE,OAAO,CAAA;KAAM,GAAG,OAAO,CAAC,WAAW,CAAC;IA2BlF,yCAAyC;IACnC,UAAU,CAAC,IAAI,GAAE;QAAC,IAAI,CAAC,EAAE,OAAO,CAAA;KAAM,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;IAQrE,UAAU,CAAC,OAAO,EAAE,OAAO,GAAG,YAAY,GAAG,IAAI;IAIjD,YAAY,IAAI,YAAY,EAAE;CAG/B"}
|
package/dist/indexer.js
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { makePublicClient, reconstructIncremental, reconstructProject, } from '@artblocks/abx-sdk';
|
|
2
|
+
import { SqliteStore } from './store.js';
|
|
3
|
+
/**
|
|
4
|
+
* The reference indexer (Layer 3). It does one thing well: replay the event
|
|
5
|
+
* spine from chain into the store. Because every state change rides a standard,
|
|
6
|
+
* versioned event, re-indexing is a *compute* cost, not an engineering one — and
|
|
7
|
+
* it needs no cooperation from whatever provider held the data before. This is
|
|
8
|
+
* the implementation everyone re-indexes with when they onboard or leave a
|
|
9
|
+
* service; running a different one changes nothing the protocol guarantees.
|
|
10
|
+
*/
|
|
11
|
+
export class SelfHostIndexer {
|
|
12
|
+
store;
|
|
13
|
+
clients = new Map();
|
|
14
|
+
constructor(store) {
|
|
15
|
+
this.store = store ?? new SqliteStore();
|
|
16
|
+
}
|
|
17
|
+
client(chainKey) {
|
|
18
|
+
let c = this.clients.get(chainKey);
|
|
19
|
+
if (!c)
|
|
20
|
+
this.clients.set(chainKey, (c = makePublicClient({ chainKey })));
|
|
21
|
+
return c;
|
|
22
|
+
}
|
|
23
|
+
/** The RPC client for a chain — exposed for reads that aren't a reindex (e.g. deploy-block
|
|
24
|
+
* discovery in the admin control plane). Reuses the same pooled client as `reindex`. */
|
|
25
|
+
publicClient(chainKey) {
|
|
26
|
+
return this.client(chainKey);
|
|
27
|
+
}
|
|
28
|
+
/** Register a project to index (the minimum needed to replay it). */
|
|
29
|
+
register(reg) {
|
|
30
|
+
const full = { ...reg, registeredAt: new Date().toISOString() };
|
|
31
|
+
this.store.register(full);
|
|
32
|
+
return full;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Re-index a single project. By default this is **incremental**: it resumes from
|
|
36
|
+
* the stored checkpoint and only fetches blocks added since — so re-indexing is
|
|
37
|
+
* fast no matter how far head has moved — yet yields state identical to a full
|
|
38
|
+
* replay. `{full: true}` forces a replay from the deploy block (the durability
|
|
39
|
+
* proof, and what runs automatically when there's no prior state). Idempotent.
|
|
40
|
+
*/
|
|
41
|
+
async reindex(address, opts = {}) {
|
|
42
|
+
const reg = this.store.getRegistration(address);
|
|
43
|
+
// User-facing: this surfaces through `abx index`/`abx verify`. Name the real command a creator
|
|
44
|
+
// runs (`abx add`), never the internal `register()` (there is no `abx register` — a dead end).
|
|
45
|
+
if (!reg)
|
|
46
|
+
throw new Error(`${address} isn't registered on this node yet — add it first: abx add ${address}`);
|
|
47
|
+
const started = Date.now();
|
|
48
|
+
const factory = reg.factory ? reg.factory : undefined;
|
|
49
|
+
const prior = opts.full ? null : this.store.getProject(address);
|
|
50
|
+
let state;
|
|
51
|
+
let mode;
|
|
52
|
+
if (prior && prior.deployBlock && prior.events.length > 0) {
|
|
53
|
+
state = await reconstructIncremental(this.client(reg.chainKey), prior, { factory });
|
|
54
|
+
mode = 'incremental';
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
state = await reconstructProject(this.client(reg.chainKey), {
|
|
58
|
+
address,
|
|
59
|
+
fromBlock: BigInt(reg.fromBlock),
|
|
60
|
+
factory,
|
|
61
|
+
});
|
|
62
|
+
mode = 'full';
|
|
63
|
+
}
|
|
64
|
+
this.store.putProject(state);
|
|
65
|
+
return { state, elapsedMs: Date.now() - started, mode };
|
|
66
|
+
}
|
|
67
|
+
/** Re-index every registered project. */
|
|
68
|
+
async reindexAll(opts = {}) {
|
|
69
|
+
const out = [];
|
|
70
|
+
for (const reg of this.store.listRegistrations()) {
|
|
71
|
+
out.push(await this.reindex(reg.address, opts));
|
|
72
|
+
}
|
|
73
|
+
return out;
|
|
74
|
+
}
|
|
75
|
+
getProject(address) {
|
|
76
|
+
return this.store.getProject(address);
|
|
77
|
+
}
|
|
78
|
+
listProjects() {
|
|
79
|
+
return this.store.listProjects();
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
//# sourceMappingURL=indexer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"indexer.js","sourceRoot":"","sources":["../src/indexer.ts"],"names":[],"mappings":"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"}
|
package/dist/store.d.ts
ADDED
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import type { ProjectState } from '@artblocks/abx-sdk';
|
|
2
|
+
/** How a project was registered for indexing — the minimum to replay it. */
|
|
3
|
+
export interface ProjectRegistration {
|
|
4
|
+
address: string;
|
|
5
|
+
chainKey: string;
|
|
6
|
+
fromBlock: string;
|
|
7
|
+
factory: string | null;
|
|
8
|
+
label?: string;
|
|
9
|
+
/** Operator display metadata served in the token's ERC-721 JSON (the creator's words). */
|
|
10
|
+
description?: string;
|
|
11
|
+
externalUrl?: string;
|
|
12
|
+
/** Operator's off-chain OpenSea attributes (JSON array), stitched UNDER any on-chain `attributes`.
|
|
13
|
+
* Collection-scope: a 1/1's traits, or a Series' shared/fallback traits. */
|
|
14
|
+
attributes?: string;
|
|
15
|
+
/** Operator's off-chain PER-TOKEN attributes (JSON `{ "<tokenId>": OpenSeaAttribute[] }`) — a Series'
|
|
16
|
+
* editable, resolver-served traits (the per-token twin of `attributes`; a token's entry wins over
|
|
17
|
+
* the collection-scope `attributes`, and any on-chain `attributes` still wins over both). */
|
|
18
|
+
tokenAttributes?: string;
|
|
19
|
+
/** Durable content locators keyed by on-chain hash (JSON `{ "0x<keccak>": "ipfs://<cid>" }`) —
|
|
20
|
+
* bridged from the deployer so this store can point `image` at IPFS/Arweave without the bytes. */
|
|
21
|
+
contentLocators?: string;
|
|
22
|
+
registeredAt: string;
|
|
23
|
+
}
|
|
24
|
+
/** One producer-published effect artifact — a row in the data plane's enumeration registry
|
|
25
|
+
* (`specs/protocol/data-plane.md`). The resolver lists a token's rows and keeps only those whose
|
|
26
|
+
* `key` matches the recomputed address at the CURRENT settled inputsHash, so stale rows go
|
|
27
|
+
* silently unlisted (self-invalidation). `locator === null` means the bytes live in custody
|
|
28
|
+
* (the shared backend at `key`, or resolver-held published bytes). Producer-published, NOT
|
|
29
|
+
* chain-derived: rows survive a projection wipe and self-heal from a runner's next sweep. */
|
|
30
|
+
export interface EffectArtifactRow {
|
|
31
|
+
/** renderArtifactKey (keccak hex; encodes effectKey + settled inputsHash). */
|
|
32
|
+
key: string;
|
|
33
|
+
address: string;
|
|
34
|
+
tokenId: string;
|
|
35
|
+
effectKey: string;
|
|
36
|
+
outputKey: string;
|
|
37
|
+
inputsHash: string;
|
|
38
|
+
/** The effect's DECLARED output mimeType — what the manifest and byte route serve. */
|
|
39
|
+
contentType: string | null;
|
|
40
|
+
locator: string | null;
|
|
41
|
+
updatedAt?: string;
|
|
42
|
+
}
|
|
43
|
+
/** Transient per-(artifact key) effect observability — `rendering`/`failed` between triggers.
|
|
44
|
+
* Rebuildable state ONLY: "up to date" is always artifact-presence at the current settled
|
|
45
|
+
* inputsHash, never a row here; a lost table costs history, not correctness. */
|
|
46
|
+
export interface EffectStatusRow {
|
|
47
|
+
/** The artifact key (renderArtifactKey at the settled inputsHash) this run is producing. */
|
|
48
|
+
key: string;
|
|
49
|
+
address: string;
|
|
50
|
+
tokenId: string;
|
|
51
|
+
effectKey: string;
|
|
52
|
+
status: 'rendering' | 'failed';
|
|
53
|
+
error?: string | null;
|
|
54
|
+
attempts?: number;
|
|
55
|
+
updatedAt?: string;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* The projection store contract. Two responsibilities, kept distinct:
|
|
59
|
+
*
|
|
60
|
+
* - **registrations** — the minimum needed to replay a project (operator input).
|
|
61
|
+
* - **projects** — the reconstructed state, the *disposable, replay-rebuildable
|
|
62
|
+
* projection*. `wipeProjections()` clears only this; registrations survive.
|
|
63
|
+
*
|
|
64
|
+
* The reference implementation is {@link SqliteStore}. A platform-scale deploy
|
|
65
|
+
* swaps in a Postgres-backed implementation behind this same interface — nothing
|
|
66
|
+
* upstream (indexer, token API) changes.
|
|
67
|
+
*/
|
|
68
|
+
export interface Store {
|
|
69
|
+
/** Where the projection lives on disk (for display / ops). */
|
|
70
|
+
readonly path: string;
|
|
71
|
+
register(reg: ProjectRegistration): void;
|
|
72
|
+
listRegistrations(): ProjectRegistration[];
|
|
73
|
+
getRegistration(address: string): ProjectRegistration | null;
|
|
74
|
+
/** Forget a project entirely — drop its registration and its projection (on-chain data is untouched). */
|
|
75
|
+
deregister(address: string): void;
|
|
76
|
+
/** Register one effect artifact (the data plane's enumeration registry). Effect-agnostic —
|
|
77
|
+
* producers declare the (effectKey, outputKey, mimeType); the store never interprets them.
|
|
78
|
+
* Idempotent — last write wins per key. */
|
|
79
|
+
putEffectArtifact(row: EffectArtifactRow): void;
|
|
80
|
+
/** The registered artifact row for an effect artifact key, or null. */
|
|
81
|
+
getEffectArtifact(key: string): EffectArtifactRow | null;
|
|
82
|
+
/** Every registered artifact row for (project, token) — the manifest's effect-source listing.
|
|
83
|
+
* Callers filter by recomputing the current-inputsHash key per row (stale rows unlisted). */
|
|
84
|
+
listEffectArtifacts(address: string, tokenId: string): EffectArtifactRow[];
|
|
85
|
+
/** Node-level key/value metadata (e.g. the chain watcher's persisted watermark). */
|
|
86
|
+
putMeta(key: string, value: string): void;
|
|
87
|
+
getMeta(key: string): string | null;
|
|
88
|
+
/** Upsert transient effect observability (`rendering` / `failed`) for an artifact key. */
|
|
89
|
+
putEffectStatus(row: EffectStatusRow): void;
|
|
90
|
+
/** Clear one artifact key's status — the run finished; artifact presence takes over as truth. */
|
|
91
|
+
clearEffectStatus(key: string): void;
|
|
92
|
+
listEffectStatuses(address: string): EffectStatusRow[];
|
|
93
|
+
putProject(state: ProjectState): void;
|
|
94
|
+
getProject(address: string): ProjectState | null;
|
|
95
|
+
listProjects(): ProjectState[];
|
|
96
|
+
/** Drop the rebuildable projection (keeps registrations). Proves replay. */
|
|
97
|
+
wipeProjections(): void;
|
|
98
|
+
/** Close and remove the underlying store entirely. */
|
|
99
|
+
destroy(): void;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* The reference store: a single SQLite file (`.abx-self-host/index.db`).
|
|
103
|
+
*
|
|
104
|
+
* It keeps the elegant property of the file-based projection — *one disposable
|
|
105
|
+
* artifact you can delete and replay* — while adding real indexes, queries, and
|
|
106
|
+
* transactional writes. No server, no second container, no connection string:
|
|
107
|
+
* SQLite is embedded, the indexer is the only writer, and the token API is
|
|
108
|
+
* read-heavy, so WAL mode fits the access pattern exactly.
|
|
109
|
+
*
|
|
110
|
+
* The reconstructed state is normalized across `projects` / `tokens` /
|
|
111
|
+
* `commitments` / `extensions` / `events`. Wiping those tables (keeping
|
|
112
|
+
* `registrations`) and replaying yields identical state — that's the whole point.
|
|
113
|
+
*/
|
|
114
|
+
export declare class SqliteStore implements Store {
|
|
115
|
+
readonly path: string;
|
|
116
|
+
private db;
|
|
117
|
+
constructor(dataDir?: string);
|
|
118
|
+
/** Shape changes that must land BEFORE the schema exec (its indexes reference new columns).
|
|
119
|
+
* effect_artifacts pre-data-plane shape (key/address/locator only) → drop; the schema recreates
|
|
120
|
+
* it. Dropping is safe pre-release: rows are producer-published and self-heal from a runner's
|
|
121
|
+
* next sweep (record-on-skip / republish) — no chain data is lost. */
|
|
122
|
+
private premigrate;
|
|
123
|
+
/** Idempotently add columns introduced after a DB was first created (CREATE IF NOT
|
|
124
|
+
* EXISTS won't backfill them). Keeps an existing projection working across upgrades. */
|
|
125
|
+
private migrate;
|
|
126
|
+
register(reg: ProjectRegistration): void;
|
|
127
|
+
listRegistrations(): ProjectRegistration[];
|
|
128
|
+
getRegistration(address: string): ProjectRegistration | null;
|
|
129
|
+
deregister(address: string): void;
|
|
130
|
+
putEffectArtifact(row: EffectArtifactRow): void;
|
|
131
|
+
getEffectArtifact(key: string): EffectArtifactRow | null;
|
|
132
|
+
listEffectArtifacts(address: string, tokenId: string): EffectArtifactRow[];
|
|
133
|
+
putMeta(key: string, value: string): void;
|
|
134
|
+
getMeta(key: string): string | null;
|
|
135
|
+
putEffectStatus(row: EffectStatusRow): void;
|
|
136
|
+
clearEffectStatus(key: string): void;
|
|
137
|
+
listEffectStatuses(address: string): EffectStatusRow[];
|
|
138
|
+
putProject(state: ProjectState): void;
|
|
139
|
+
getProject(address: string): ProjectState | null;
|
|
140
|
+
listProjects(): ProjectState[];
|
|
141
|
+
wipeProjections(): void;
|
|
142
|
+
destroy(): void;
|
|
143
|
+
private deleteProjection;
|
|
144
|
+
private hydrate;
|
|
145
|
+
}
|
|
146
|
+
//# sourceMappingURL=store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"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"}
|
package/dist/store.js
ADDED
|
@@ -0,0 +1,484 @@
|
|
|
1
|
+
import { DatabaseSync } from 'node:sqlite';
|
|
2
|
+
import { existsSync, mkdirSync, rmSync } from 'node:fs';
|
|
3
|
+
import { resolve } from 'node:path';
|
|
4
|
+
// The data plane's effect-artifact registry (`specs/protocol/data-plane.md`): one row per declared
|
|
5
|
+
// output a runner produced, keyed by renderArtifactKey at the CURRENT settled inputsHash (a param
|
|
6
|
+
// change re-addresses → old rows go silently unlisted). Effect-agnostic — producers declare the
|
|
7
|
+
// (effect_key, output_key, content_type); the store never interprets them. locator NULL = the bytes
|
|
8
|
+
// live in custody (shared backend, or published bytes at `key`). Producer-published, NOT chain-
|
|
9
|
+
// derived, so like registrations rows survive a projection wipe/replay — and a lost table self-heals
|
|
10
|
+
// from a runner's next sweep (record-on-skip / republish).
|
|
11
|
+
const EFFECT_ARTIFACTS_DDL = `
|
|
12
|
+
CREATE TABLE IF NOT EXISTS effect_artifacts (
|
|
13
|
+
key TEXT PRIMARY KEY, -- renderArtifactKey (keccak hex; encodes effectKey + settled inputsHash)
|
|
14
|
+
address TEXT NOT NULL, -- lowercased project address
|
|
15
|
+
token_id TEXT NOT NULL,
|
|
16
|
+
effect_key TEXT NOT NULL, -- 'render' | any registered effect
|
|
17
|
+
output_key TEXT NOT NULL, -- 'image' | 'traits' | any declared output
|
|
18
|
+
inputs_hash TEXT NOT NULL, -- the settled inputsHash this row was produced at
|
|
19
|
+
locator TEXT, -- ipfs://<cid> | ar://<txid> | https://… | NULL (bytes in custody)
|
|
20
|
+
content_type TEXT, -- the effect's DECLARED output mimeType
|
|
21
|
+
updated_at TEXT NOT NULL
|
|
22
|
+
);
|
|
23
|
+
CREATE INDEX IF NOT EXISTS idx_effect_artifacts_token ON effect_artifacts(address, token_id);
|
|
24
|
+
`;
|
|
25
|
+
const SCHEMA = `
|
|
26
|
+
PRAGMA journal_mode = WAL;
|
|
27
|
+
PRAGMA foreign_keys = ON;
|
|
28
|
+
-- Cross-process co-located writes (a local effect runner records artifact rows into this same
|
|
29
|
+
-- file while the resolver serves): wait out a writer instead of failing fast. WAL keeps readers
|
|
30
|
+
-- unblocked; artifact writes are rare (one per rendered output) and touch a table the indexer
|
|
31
|
+
-- never writes.
|
|
32
|
+
PRAGMA busy_timeout = 5000;
|
|
33
|
+
|
|
34
|
+
CREATE TABLE IF NOT EXISTS registrations (
|
|
35
|
+
address TEXT PRIMARY KEY, -- lowercased
|
|
36
|
+
chain_key TEXT NOT NULL,
|
|
37
|
+
from_block TEXT NOT NULL,
|
|
38
|
+
factory TEXT,
|
|
39
|
+
label TEXT,
|
|
40
|
+
description TEXT,
|
|
41
|
+
external_url TEXT,
|
|
42
|
+
attributes TEXT, -- JSON OpenSeaAttribute[] (off-chain operator traits, collection-scope)
|
|
43
|
+
token_attributes TEXT, -- JSON { "<tokenId>": OpenSeaAttribute[] } (off-chain per-token traits)
|
|
44
|
+
content_locators TEXT, -- JSON { "0x<keccak>": "ipfs://<cid>" }
|
|
45
|
+
registered_at TEXT NOT NULL
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
CREATE TABLE IF NOT EXISTS projects (
|
|
49
|
+
address TEXT PRIMARY KEY, -- lowercased
|
|
50
|
+
address_original TEXT NOT NULL, -- checksummed, as reconstructed
|
|
51
|
+
chain_id INTEGER NOT NULL,
|
|
52
|
+
abx_version INTEGER,
|
|
53
|
+
deploy_block TEXT,
|
|
54
|
+
deploy_tx TEXT,
|
|
55
|
+
factory TEXT,
|
|
56
|
+
implementation TEXT,
|
|
57
|
+
is_canonical INTEGER, -- 0 | 1 | NULL
|
|
58
|
+
name TEXT,
|
|
59
|
+
symbol TEXT,
|
|
60
|
+
owner TEXT,
|
|
61
|
+
contract_uri TEXT,
|
|
62
|
+
token_uri_renderer TEXT, -- non-null => tokenURI resolves on-chain
|
|
63
|
+
token_uri_locked INTEGER, -- 0 | 1 | NULL
|
|
64
|
+
contract_uri_renderer TEXT,
|
|
65
|
+
contract_uri_locked INTEGER,
|
|
66
|
+
royalty_receiver TEXT, -- NULL => no royalty
|
|
67
|
+
royalty_bps INTEGER,
|
|
68
|
+
collection_fields TEXT, -- JSON MetadataField[] (collection scope)
|
|
69
|
+
locked_collection_fields TEXT, -- JSON string[]
|
|
70
|
+
contract_type TEXT, -- '1of1' | 'series' (from enabled extensions)
|
|
71
|
+
max_invocations TEXT, -- Series supply cap (decimal string) or NULL
|
|
72
|
+
minter TEXT, -- the single authorized minter or NULL
|
|
73
|
+
paused INTEGER, -- Paused extension: 1 | 0 | NULL (NULL/0 ⇒ unpaused)
|
|
74
|
+
primary_payee TEXT, -- Primary Payee destination or NULL
|
|
75
|
+
from_block TEXT NOT NULL,
|
|
76
|
+
to_block TEXT NOT NULL,
|
|
77
|
+
event_count INTEGER NOT NULL,
|
|
78
|
+
reconstructed_at TEXT NOT NULL,
|
|
79
|
+
rpc_url TEXT
|
|
80
|
+
);
|
|
81
|
+
|
|
82
|
+
CREATE TABLE IF NOT EXISTS tokens (
|
|
83
|
+
project_address TEXT NOT NULL,
|
|
84
|
+
token_id TEXT NOT NULL,
|
|
85
|
+
minted INTEGER NOT NULL DEFAULT 0,
|
|
86
|
+
owner TEXT,
|
|
87
|
+
token_uri TEXT,
|
|
88
|
+
fields TEXT, -- JSON MetadataField[] (on-chain token fields)
|
|
89
|
+
locked_fields TEXT, -- JSON string[] (locked field names)
|
|
90
|
+
PRIMARY KEY (project_address, token_id)
|
|
91
|
+
);
|
|
92
|
+
|
|
93
|
+
CREATE TABLE IF NOT EXISTS extensions (
|
|
94
|
+
project_address TEXT NOT NULL,
|
|
95
|
+
id TEXT NOT NULL,
|
|
96
|
+
name TEXT NOT NULL,
|
|
97
|
+
version INTEGER NOT NULL,
|
|
98
|
+
PRIMARY KEY (project_address, id)
|
|
99
|
+
);
|
|
100
|
+
|
|
101
|
+
CREATE TABLE IF NOT EXISTS events (
|
|
102
|
+
project_address TEXT NOT NULL,
|
|
103
|
+
seq INTEGER NOT NULL, -- chain order (block, logIndex)
|
|
104
|
+
name TEXT NOT NULL,
|
|
105
|
+
register INTEGER NOT NULL,
|
|
106
|
+
what TEXT NOT NULL,
|
|
107
|
+
block_number TEXT NOT NULL,
|
|
108
|
+
log_index INTEGER NOT NULL,
|
|
109
|
+
tx_hash TEXT NOT NULL,
|
|
110
|
+
args TEXT NOT NULL, -- JSON
|
|
111
|
+
PRIMARY KEY (project_address, seq)
|
|
112
|
+
);
|
|
113
|
+
|
|
114
|
+
CREATE INDEX IF NOT EXISTS idx_tokens_project ON tokens(project_address);
|
|
115
|
+
CREATE INDEX IF NOT EXISTS idx_extensions_project ON extensions(project_address);
|
|
116
|
+
CREATE INDEX IF NOT EXISTS idx_events_project ON events(project_address);
|
|
117
|
+
|
|
118
|
+
${EFFECT_ARTIFACTS_DDL}
|
|
119
|
+
|
|
120
|
+
-- Node-level key/value metadata: the chain watcher's persisted watermark, etc. NOT chain-derived
|
|
121
|
+
-- (survives a projection wipe; losing it merely re-notifies once, which idempotency absorbs).
|
|
122
|
+
CREATE TABLE IF NOT EXISTS meta (
|
|
123
|
+
key TEXT PRIMARY KEY,
|
|
124
|
+
value TEXT NOT NULL
|
|
125
|
+
);
|
|
126
|
+
|
|
127
|
+
-- Transient effect observability: 'rendering' / 'failed' between triggers, reported by a runner.
|
|
128
|
+
-- REBUILDABLE ONLY — "up to date" is artifact-presence at the current settled inputsHash, never a
|
|
129
|
+
-- row here. A wiped table loses history (attempt counts, error text), not correctness.
|
|
130
|
+
CREATE TABLE IF NOT EXISTS effect_status (
|
|
131
|
+
key TEXT PRIMARY KEY, -- the artifact key this run produces
|
|
132
|
+
address TEXT NOT NULL, -- lowercased project address
|
|
133
|
+
token_id TEXT NOT NULL,
|
|
134
|
+
effect_key TEXT NOT NULL, -- 'render' | any registered effect
|
|
135
|
+
status TEXT NOT NULL, -- 'rendering' | 'failed'
|
|
136
|
+
error TEXT,
|
|
137
|
+
attempts INTEGER,
|
|
138
|
+
updated_at TEXT NOT NULL
|
|
139
|
+
);
|
|
140
|
+
CREATE INDEX IF NOT EXISTS idx_effect_status_address ON effect_status(address);
|
|
141
|
+
`;
|
|
142
|
+
const b = (v) => v === null || v === undefined ? null : v ? 1 : 0;
|
|
143
|
+
const lc = (address) => address.toLowerCase();
|
|
144
|
+
/**
|
|
145
|
+
* The reference store: a single SQLite file (`.abx-self-host/index.db`).
|
|
146
|
+
*
|
|
147
|
+
* It keeps the elegant property of the file-based projection — *one disposable
|
|
148
|
+
* artifact you can delete and replay* — while adding real indexes, queries, and
|
|
149
|
+
* transactional writes. No server, no second container, no connection string:
|
|
150
|
+
* SQLite is embedded, the indexer is the only writer, and the token API is
|
|
151
|
+
* read-heavy, so WAL mode fits the access pattern exactly.
|
|
152
|
+
*
|
|
153
|
+
* The reconstructed state is normalized across `projects` / `tokens` /
|
|
154
|
+
* `commitments` / `extensions` / `events`. Wiping those tables (keeping
|
|
155
|
+
* `registrations`) and replaying yields identical state — that's the whole point.
|
|
156
|
+
*/
|
|
157
|
+
export class SqliteStore {
|
|
158
|
+
path;
|
|
159
|
+
db;
|
|
160
|
+
constructor(dataDir) {
|
|
161
|
+
const dir = dataDir ?? process.env.ABX_DATA_DIR ?? resolve(process.cwd(), '.abx-self-host');
|
|
162
|
+
mkdirSync(dir, { recursive: true });
|
|
163
|
+
this.path = resolve(dir, 'index.db');
|
|
164
|
+
this.db = new DatabaseSync(this.path);
|
|
165
|
+
this.premigrate();
|
|
166
|
+
this.db.exec(SCHEMA);
|
|
167
|
+
this.migrate();
|
|
168
|
+
}
|
|
169
|
+
/** Shape changes that must land BEFORE the schema exec (its indexes reference new columns).
|
|
170
|
+
* effect_artifacts pre-data-plane shape (key/address/locator only) → drop; the schema recreates
|
|
171
|
+
* it. Dropping is safe pre-release: rows are producer-published and self-heal from a runner's
|
|
172
|
+
* next sweep (record-on-skip / republish) — no chain data is lost. */
|
|
173
|
+
premigrate() {
|
|
174
|
+
const cols = this.db.prepare(`PRAGMA table_info(effect_artifacts)`).all();
|
|
175
|
+
if (cols.length > 0 && !cols.some((c) => c.name === 'token_id')) {
|
|
176
|
+
this.db.exec(`DROP TABLE effect_artifacts`);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
/** Idempotently add columns introduced after a DB was first created (CREATE IF NOT
|
|
180
|
+
* EXISTS won't backfill them). Keeps an existing projection working across upgrades. */
|
|
181
|
+
migrate() {
|
|
182
|
+
const add = (table, col) => {
|
|
183
|
+
try {
|
|
184
|
+
this.db.exec(`ALTER TABLE ${table} ADD COLUMN ${col}`);
|
|
185
|
+
}
|
|
186
|
+
catch {
|
|
187
|
+
/* column already exists */
|
|
188
|
+
}
|
|
189
|
+
};
|
|
190
|
+
add('registrations', 'description TEXT');
|
|
191
|
+
add('registrations', 'external_url TEXT');
|
|
192
|
+
add('registrations', 'attributes TEXT');
|
|
193
|
+
add('registrations', 'token_attributes TEXT');
|
|
194
|
+
add('registrations', 'content_locators TEXT');
|
|
195
|
+
add('tokens', 'minted INTEGER NOT NULL DEFAULT 0');
|
|
196
|
+
add('tokens', 'fields TEXT');
|
|
197
|
+
add('tokens', 'locked_fields TEXT');
|
|
198
|
+
add('projects', 'collection_fields TEXT');
|
|
199
|
+
add('projects', 'locked_collection_fields TEXT');
|
|
200
|
+
add('projects', 'token_uri_renderer TEXT');
|
|
201
|
+
add('projects', 'token_uri_locked INTEGER');
|
|
202
|
+
add('projects', 'contract_uri_renderer TEXT');
|
|
203
|
+
add('projects', 'contract_uri_locked INTEGER');
|
|
204
|
+
add('projects', 'contract_type TEXT');
|
|
205
|
+
add('projects', 'max_invocations TEXT');
|
|
206
|
+
add('projects', 'minter TEXT');
|
|
207
|
+
add('projects', 'paused INTEGER');
|
|
208
|
+
add('projects', 'primary_payee TEXT');
|
|
209
|
+
// code-project state (params, schemas, hooks, seed source, script, dependencies) —
|
|
210
|
+
// one JSON column; the shape is the ProjectState fields, spread back on hydrate.
|
|
211
|
+
add('projects', 'code_state TEXT');
|
|
212
|
+
add('tokens', 'params TEXT');
|
|
213
|
+
}
|
|
214
|
+
// ── registrations ──────────────────────────────────────────────────────────
|
|
215
|
+
register(reg) {
|
|
216
|
+
this.db
|
|
217
|
+
.prepare(`INSERT INTO registrations (address, chain_key, from_block, factory, label, description, external_url, attributes, token_attributes, content_locators, registered_at)
|
|
218
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
219
|
+
ON CONFLICT(address) DO UPDATE SET
|
|
220
|
+
chain_key=excluded.chain_key, from_block=excluded.from_block,
|
|
221
|
+
factory=excluded.factory, label=excluded.label,
|
|
222
|
+
description=excluded.description, external_url=excluded.external_url,
|
|
223
|
+
attributes=excluded.attributes, token_attributes=excluded.token_attributes,
|
|
224
|
+
content_locators=excluded.content_locators,
|
|
225
|
+
registered_at=excluded.registered_at`)
|
|
226
|
+
.run(lc(reg.address), reg.chainKey, reg.fromBlock, reg.factory, reg.label ?? null, reg.description ?? null, reg.externalUrl ?? null, reg.attributes ?? null, reg.tokenAttributes ?? null, reg.contentLocators ?? null, reg.registeredAt);
|
|
227
|
+
}
|
|
228
|
+
listRegistrations() {
|
|
229
|
+
return this.db
|
|
230
|
+
.prepare(`SELECT * FROM registrations ORDER BY registered_at`)
|
|
231
|
+
.all()
|
|
232
|
+
.map(rowToRegistration);
|
|
233
|
+
}
|
|
234
|
+
getRegistration(address) {
|
|
235
|
+
const row = this.db.prepare(`SELECT * FROM registrations WHERE address = ?`).get(lc(address));
|
|
236
|
+
return row ? rowToRegistration(row) : null;
|
|
237
|
+
}
|
|
238
|
+
deregister(address) {
|
|
239
|
+
const key = lc(address);
|
|
240
|
+
this.deleteProjection(key);
|
|
241
|
+
this.db.prepare(`DELETE FROM effect_artifacts WHERE address = ?`).run(key);
|
|
242
|
+
this.db.prepare(`DELETE FROM effect_status WHERE address = ?`).run(key);
|
|
243
|
+
this.db.prepare(`DELETE FROM registrations WHERE address = ?`).run(key);
|
|
244
|
+
}
|
|
245
|
+
// ── effect artifacts (the data plane's registry; producer-published) ──────────
|
|
246
|
+
putEffectArtifact(row) {
|
|
247
|
+
this.db
|
|
248
|
+
.prepare(`INSERT INTO effect_artifacts (key, address, token_id, effect_key, output_key, inputs_hash, locator, content_type, updated_at)
|
|
249
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
250
|
+
ON CONFLICT(key) DO UPDATE SET
|
|
251
|
+
address=excluded.address, token_id=excluded.token_id, effect_key=excluded.effect_key,
|
|
252
|
+
output_key=excluded.output_key, inputs_hash=excluded.inputs_hash,
|
|
253
|
+
locator=excluded.locator, content_type=excluded.content_type, updated_at=excluded.updated_at`)
|
|
254
|
+
.run(row.key.toLowerCase(), lc(row.address), row.tokenId, row.effectKey, row.outputKey, row.inputsHash.toLowerCase(), row.locator, row.contentType, row.updatedAt ?? new Date().toISOString());
|
|
255
|
+
}
|
|
256
|
+
getEffectArtifact(key) {
|
|
257
|
+
const row = this.db
|
|
258
|
+
.prepare(`SELECT * FROM effect_artifacts WHERE key = ?`)
|
|
259
|
+
.get(key.toLowerCase());
|
|
260
|
+
return row ? rowToArtifact(row) : null;
|
|
261
|
+
}
|
|
262
|
+
listEffectArtifacts(address, tokenId) {
|
|
263
|
+
return this.db
|
|
264
|
+
.prepare(`SELECT * FROM effect_artifacts WHERE address = ? AND token_id = ? ORDER BY effect_key, output_key`)
|
|
265
|
+
.all(lc(address), tokenId).map(rowToArtifact);
|
|
266
|
+
}
|
|
267
|
+
// ── node metadata (watcher watermark, …) ─────────────────────────────────────
|
|
268
|
+
putMeta(key, value) {
|
|
269
|
+
this.db
|
|
270
|
+
.prepare(`INSERT INTO meta (key, value) VALUES (?, ?) ON CONFLICT(key) DO UPDATE SET value=excluded.value`)
|
|
271
|
+
.run(key, value);
|
|
272
|
+
}
|
|
273
|
+
getMeta(key) {
|
|
274
|
+
const row = this.db.prepare(`SELECT value FROM meta WHERE key = ?`).get(key);
|
|
275
|
+
return row?.value ?? null;
|
|
276
|
+
}
|
|
277
|
+
// ── transient effect status (runner-reported observability; rebuildable) ─────
|
|
278
|
+
putEffectStatus(row) {
|
|
279
|
+
this.db
|
|
280
|
+
.prepare(`INSERT INTO effect_status (key, address, token_id, effect_key, status, error, attempts, updated_at)
|
|
281
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
|
282
|
+
ON CONFLICT(key) DO UPDATE SET
|
|
283
|
+
address=excluded.address, token_id=excluded.token_id, effect_key=excluded.effect_key,
|
|
284
|
+
status=excluded.status, error=excluded.error, attempts=excluded.attempts, updated_at=excluded.updated_at`)
|
|
285
|
+
.run(row.key.toLowerCase(), lc(row.address), row.tokenId, row.effectKey, row.status, row.error ?? null, row.attempts ?? null, row.updatedAt ?? new Date().toISOString());
|
|
286
|
+
}
|
|
287
|
+
clearEffectStatus(key) {
|
|
288
|
+
this.db.prepare(`DELETE FROM effect_status WHERE key = ?`).run(key.toLowerCase());
|
|
289
|
+
}
|
|
290
|
+
listEffectStatuses(address) {
|
|
291
|
+
const rows = this.db
|
|
292
|
+
.prepare(`SELECT key, address, token_id, effect_key, status, error, attempts, updated_at FROM effect_status WHERE address = ?`)
|
|
293
|
+
.all(lc(address));
|
|
294
|
+
return rows.map((r) => ({
|
|
295
|
+
key: r.key,
|
|
296
|
+
address: r.address,
|
|
297
|
+
tokenId: r.token_id,
|
|
298
|
+
effectKey: r.effect_key,
|
|
299
|
+
status: r.status,
|
|
300
|
+
error: r.error,
|
|
301
|
+
attempts: r.attempts ?? undefined,
|
|
302
|
+
updatedAt: r.updated_at,
|
|
303
|
+
}));
|
|
304
|
+
}
|
|
305
|
+
// ── projection ───────────────────────────────────────────────────────────--
|
|
306
|
+
putProject(state) {
|
|
307
|
+
const key = lc(state.address);
|
|
308
|
+
this.db.exec('BEGIN');
|
|
309
|
+
try {
|
|
310
|
+
this.deleteProjection(key);
|
|
311
|
+
this.db
|
|
312
|
+
.prepare(`INSERT INTO projects (
|
|
313
|
+
address, address_original, chain_id, abx_version, deploy_block, deploy_tx,
|
|
314
|
+
factory, implementation, is_canonical, name, symbol, owner, contract_uri,
|
|
315
|
+
token_uri_renderer, token_uri_locked, contract_uri_renderer, contract_uri_locked,
|
|
316
|
+
royalty_receiver, royalty_bps, collection_fields, locked_collection_fields,
|
|
317
|
+
contract_type, max_invocations, minter, paused, primary_payee, code_state,
|
|
318
|
+
from_block, to_block, event_count, reconstructed_at, rpc_url
|
|
319
|
+
) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)`)
|
|
320
|
+
.run(key, state.address, state.chainId, state.abxVersion, state.deployBlock, state.deployTx, state.factory, state.implementation, b(state.isCanonical), state.name, state.symbol, state.owner, state.contractURI, state.tokenURIRenderer, b(state.tokenURILocked), state.contractURIRenderer, b(state.contractURILocked), state.royalty?.receiver ?? null, state.royalty?.bps ?? null, JSON.stringify(state.collectionFields), JSON.stringify(state.lockedCollectionFields), state.contractType ?? null, state.maxInvocations ?? null, state.minter ?? null, b(state.paused), state.primaryPayee ?? null, JSON.stringify({
|
|
321
|
+
contractParams: state.contractParams ?? null,
|
|
322
|
+
paramSchemas: state.paramSchemas ?? null,
|
|
323
|
+
paramHooks: state.paramHooks ?? null,
|
|
324
|
+
delegateRegistry: state.delegateRegistry ?? null,
|
|
325
|
+
seedSource: state.seedSource ?? null,
|
|
326
|
+
script: state.script ?? null,
|
|
327
|
+
dependencies: state.dependencies ?? null,
|
|
328
|
+
}), state.fromBlock, state.toBlock, state.eventCount, state.reconstructedAt, state.rpcUrl ?? null);
|
|
329
|
+
const insToken = this.db.prepare(`INSERT INTO tokens (project_address, token_id, minted, owner, token_uri, fields, locked_fields, params)
|
|
330
|
+
VALUES (?,?,?,?,?,?,?,?)`);
|
|
331
|
+
for (const t of state.tokens) {
|
|
332
|
+
insToken.run(key, t.tokenId, b(t.minted), t.owner, t.tokenURI, JSON.stringify(t.fields), JSON.stringify(t.lockedFields), t.params?.length ? JSON.stringify(t.params) : null);
|
|
333
|
+
}
|
|
334
|
+
const insExt = this.db.prepare(`INSERT INTO extensions (project_address, id, name, version) VALUES (?,?,?,?)`);
|
|
335
|
+
for (const e of state.extensions)
|
|
336
|
+
insExt.run(key, e.id, e.name, e.version);
|
|
337
|
+
const insEvent = this.db.prepare(`INSERT INTO events (project_address, seq, name, register, what, block_number, log_index, tx_hash, args)
|
|
338
|
+
VALUES (?,?,?,?,?,?,?,?,?)`);
|
|
339
|
+
state.events.forEach((ev, i) => {
|
|
340
|
+
insEvent.run(key, i, ev.name, ev.register, ev.what, ev.blockNumber, ev.logIndex, ev.txHash, JSON.stringify(ev.args));
|
|
341
|
+
});
|
|
342
|
+
this.db.exec('COMMIT');
|
|
343
|
+
}
|
|
344
|
+
catch (err) {
|
|
345
|
+
this.db.exec('ROLLBACK');
|
|
346
|
+
throw err;
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
getProject(address) {
|
|
350
|
+
const row = this.db.prepare(`SELECT * FROM projects WHERE address = ?`).get(lc(address));
|
|
351
|
+
return row ? this.hydrate(row) : null;
|
|
352
|
+
}
|
|
353
|
+
listProjects() {
|
|
354
|
+
return this.db
|
|
355
|
+
.prepare(`SELECT * FROM projects ORDER BY reconstructed_at`)
|
|
356
|
+
.all()
|
|
357
|
+
.map((r) => this.hydrate(r));
|
|
358
|
+
}
|
|
359
|
+
wipeProjections() {
|
|
360
|
+
this.db.exec(`DELETE FROM events; DELETE FROM extensions; DELETE FROM tokens; DELETE FROM projects;`);
|
|
361
|
+
}
|
|
362
|
+
destroy() {
|
|
363
|
+
this.db.close();
|
|
364
|
+
for (const suffix of ['', '-wal', '-shm']) {
|
|
365
|
+
const f = this.path + suffix;
|
|
366
|
+
if (existsSync(f))
|
|
367
|
+
rmSync(f);
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
deleteProjection(key) {
|
|
371
|
+
for (const table of ['events', 'extensions', 'tokens', 'projects']) {
|
|
372
|
+
this.db.prepare(`DELETE FROM ${table} WHERE ${table === 'projects' ? 'address' : 'project_address'} = ?`).run(key);
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
hydrate(p) {
|
|
376
|
+
const key = p.address;
|
|
377
|
+
const tokens = this.db.prepare(`SELECT * FROM tokens WHERE project_address = ? ORDER BY CAST(token_id AS INTEGER)`).all(key).map((t) => ({
|
|
378
|
+
tokenId: t.token_id,
|
|
379
|
+
minted: !!t.minted,
|
|
380
|
+
owner: t.owner ?? null,
|
|
381
|
+
tokenURI: t.token_uri ?? null,
|
|
382
|
+
fields: JSON.parse(t.fields ?? '[]'),
|
|
383
|
+
lockedFields: JSON.parse(t.locked_fields ?? '[]'),
|
|
384
|
+
...(t.params ? { params: JSON.parse(t.params) } : {}),
|
|
385
|
+
}));
|
|
386
|
+
const extensions = this.db.prepare(`SELECT * FROM extensions WHERE project_address = ? ORDER BY name`).all(key).map((e) => ({ id: e.id, name: e.name, version: e.version }));
|
|
387
|
+
const events = this.db.prepare(`SELECT * FROM events WHERE project_address = ? ORDER BY seq`).all(key).map((e) => ({
|
|
388
|
+
name: e.name,
|
|
389
|
+
register: e.register,
|
|
390
|
+
what: e.what,
|
|
391
|
+
blockNumber: e.block_number,
|
|
392
|
+
logIndex: e.log_index,
|
|
393
|
+
txHash: e.tx_hash,
|
|
394
|
+
args: JSON.parse(e.args),
|
|
395
|
+
}));
|
|
396
|
+
return {
|
|
397
|
+
address: p.address_original,
|
|
398
|
+
chainId: p.chain_id,
|
|
399
|
+
abxVersion: p.abx_version,
|
|
400
|
+
deployBlock: p.deploy_block,
|
|
401
|
+
deployTx: p.deploy_tx ?? null,
|
|
402
|
+
factory: p.factory ?? null,
|
|
403
|
+
implementation: p.implementation ?? null,
|
|
404
|
+
isCanonical: p.is_canonical === null ? null : !!p.is_canonical,
|
|
405
|
+
name: p.name,
|
|
406
|
+
symbol: p.symbol,
|
|
407
|
+
owner: p.owner ?? null,
|
|
408
|
+
contractURI: p.contract_uri,
|
|
409
|
+
tokenURIRenderer: p.token_uri_renderer ?? null,
|
|
410
|
+
tokenURILocked: p.token_uri_locked === null ? null : !!p.token_uri_locked,
|
|
411
|
+
contractURIRenderer: p.contract_uri_renderer ?? null,
|
|
412
|
+
contractURILocked: p.contract_uri_locked === null ? null : !!p.contract_uri_locked,
|
|
413
|
+
royalty: p.royalty_receiver ? { receiver: p.royalty_receiver, bps: p.royalty_bps ?? 0 } : null,
|
|
414
|
+
collectionFields: JSON.parse(p.collection_fields ?? '[]'),
|
|
415
|
+
lockedCollectionFields: JSON.parse(p.locked_collection_fields ?? '[]'),
|
|
416
|
+
contractType: p.contract_type ?? undefined,
|
|
417
|
+
maxInvocations: p.max_invocations ?? null,
|
|
418
|
+
minter: p.minter ?? null,
|
|
419
|
+
paused: !!p.paused,
|
|
420
|
+
primaryPayee: p.primary_payee ?? null,
|
|
421
|
+
...hydrateCodeState(p.code_state),
|
|
422
|
+
extensions,
|
|
423
|
+
tokens,
|
|
424
|
+
events,
|
|
425
|
+
fromBlock: p.from_block,
|
|
426
|
+
toBlock: p.to_block,
|
|
427
|
+
eventCount: p.event_count,
|
|
428
|
+
reconstructedAt: p.reconstructed_at,
|
|
429
|
+
rpcUrl: p.rpc_url ?? undefined,
|
|
430
|
+
};
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
/** Spread the code-project JSON column back into its ProjectState fields (see putProject). */
|
|
434
|
+
function hydrateCodeState(json) {
|
|
435
|
+
if (!json) {
|
|
436
|
+
return {
|
|
437
|
+
paramHooks: null,
|
|
438
|
+
delegateRegistry: null,
|
|
439
|
+
seedSource: null,
|
|
440
|
+
script: null,
|
|
441
|
+
dependencies: null,
|
|
442
|
+
};
|
|
443
|
+
}
|
|
444
|
+
const c = JSON.parse(json);
|
|
445
|
+
return {
|
|
446
|
+
contractParams: c.contractParams ?? undefined,
|
|
447
|
+
paramSchemas: c.paramSchemas ?? undefined,
|
|
448
|
+
paramHooks: c.paramHooks ?? null,
|
|
449
|
+
delegateRegistry: c.delegateRegistry ?? null,
|
|
450
|
+
seedSource: c.seedSource ?? null,
|
|
451
|
+
script: c.script ?? null,
|
|
452
|
+
dependencies: c.dependencies ?? null,
|
|
453
|
+
};
|
|
454
|
+
}
|
|
455
|
+
function rowToArtifact(row) {
|
|
456
|
+
return {
|
|
457
|
+
key: row.key,
|
|
458
|
+
address: row.address,
|
|
459
|
+
tokenId: row.token_id,
|
|
460
|
+
effectKey: row.effect_key,
|
|
461
|
+
outputKey: row.output_key,
|
|
462
|
+
inputsHash: row.inputs_hash,
|
|
463
|
+
contentType: row.content_type ?? null,
|
|
464
|
+
locator: row.locator ?? null,
|
|
465
|
+
updatedAt: row.updated_at,
|
|
466
|
+
};
|
|
467
|
+
}
|
|
468
|
+
function rowToRegistration(row) {
|
|
469
|
+
const r = row;
|
|
470
|
+
return {
|
|
471
|
+
address: r.address,
|
|
472
|
+
chainKey: r.chain_key,
|
|
473
|
+
fromBlock: r.from_block,
|
|
474
|
+
factory: r.factory,
|
|
475
|
+
label: r.label ?? undefined,
|
|
476
|
+
description: r.description ?? undefined,
|
|
477
|
+
externalUrl: r.external_url ?? undefined,
|
|
478
|
+
attributes: r.attributes ?? undefined,
|
|
479
|
+
tokenAttributes: r.token_attributes ?? undefined,
|
|
480
|
+
contentLocators: r.content_locators ?? undefined,
|
|
481
|
+
registeredAt: r.registered_at,
|
|
482
|
+
};
|
|
483
|
+
}
|
|
484
|
+
//# sourceMappingURL=store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store.js","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@artblocks/abx-indexer",
|
|
3
|
+
"version": "0.1.0-alpha.0",
|
|
4
|
+
"license": "MIT",
|
|
5
|
+
"description": "ABX Self-Host Toolkit (Layer 3) — the reference indexer. Replays the event spine from chain into a disposable, rebuildable projection. The canonical re-index.",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"main": "./dist/index.js",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.js"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"dist",
|
|
16
|
+
"LICENSE"
|
|
17
|
+
],
|
|
18
|
+
"sideEffects": false,
|
|
19
|
+
"engines": {
|
|
20
|
+
"node": ">=22.5.0"
|
|
21
|
+
},
|
|
22
|
+
"repository": {
|
|
23
|
+
"type": "git",
|
|
24
|
+
"url": "git+https://github.com/ArtBlocks/abx.git",
|
|
25
|
+
"directory": "packages/indexer"
|
|
26
|
+
},
|
|
27
|
+
"homepage": "https://github.com/ArtBlocks/abx#readme",
|
|
28
|
+
"bugs": "https://github.com/ArtBlocks/abx/issues",
|
|
29
|
+
"keywords": [
|
|
30
|
+
"abx",
|
|
31
|
+
"nft",
|
|
32
|
+
"indexer",
|
|
33
|
+
"ethereum",
|
|
34
|
+
"art-blocks"
|
|
35
|
+
],
|
|
36
|
+
"publishConfig": {
|
|
37
|
+
"access": "public"
|
|
38
|
+
},
|
|
39
|
+
"dependencies": {
|
|
40
|
+
"viem": "^2.21.0",
|
|
41
|
+
"@artblocks/abx-sdk": "0.1.0-alpha.0"
|
|
42
|
+
},
|
|
43
|
+
"scripts": {
|
|
44
|
+
"build": "tsc -b tsconfig.build.json"
|
|
45
|
+
},
|
|
46
|
+
"types": "./dist/index.d.ts"
|
|
47
|
+
}
|