@logrix/sdk 0.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.
@@ -0,0 +1,364 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.codegenCommand = codegenCommand;
37
+ const commander_1 = require("commander");
38
+ const fs = __importStar(require("fs"));
39
+ const path = __importStar(require("path"));
40
+ const yaml_1 = require("yaml");
41
+ // ---------------------------------------------------------------------------
42
+ // Code generators
43
+ // ---------------------------------------------------------------------------
44
+ function solTypeToAs(solType) {
45
+ if (solType === "address")
46
+ return "Address";
47
+ if (solType === "bool")
48
+ return "bool";
49
+ if (solType.startsWith("uint") || solType.startsWith("int"))
50
+ return "BigInt";
51
+ if (solType === "bytes32" || solType === "bytes")
52
+ return "Bytes";
53
+ if (solType === "string")
54
+ return "string";
55
+ return "string";
56
+ }
57
+ function generateEventsTs(dataSources, projectDir) {
58
+ const lines = [
59
+ "// Auto-generated by `logrix codegen`. Do not edit.",
60
+ 'import { EventLog, BigInt, Address, Bytes } from "@logrix/sdk";',
61
+ "",
62
+ ];
63
+ // Contract address constants for multi-contract indexers
64
+ lines.push("// ---------------------------------------------------------------------------");
65
+ lines.push("// Multi-Contract Address Constants");
66
+ lines.push("// ---------------------------------------------------------------------------");
67
+ for (const ds of dataSources) {
68
+ const constName = `${ds.name.toUpperCase()}_ADDRESS`;
69
+ const addr = ds.source?.address?.toLowerCase() || "0x0000000000000000000000000000000000000000";
70
+ lines.push(`export const ${constName}: string = "${addr}";`);
71
+ }
72
+ lines.push("");
73
+ // Multi-contract event routing helper
74
+ lines.push("/** Helper to verify if an event belongs to a target contract address */");
75
+ lines.push("export function isFromContract(raw: EventLog, targetAddress: string): bool {");
76
+ lines.push(" return raw.address.toLowerCase() == targetAddress.toLowerCase();");
77
+ lines.push("}");
78
+ lines.push("");
79
+ const seenEventNames = new Set();
80
+ for (const ds of dataSources) {
81
+ if (!ds.mapping || !ds.mapping.abis)
82
+ continue;
83
+ for (const abiRef of ds.mapping.abis) {
84
+ const abiPath = path.resolve(projectDir, abiRef.file);
85
+ if (!fs.existsSync(abiPath)) {
86
+ console.warn(` Warning: ABI file not found: ${abiRef.file}`);
87
+ continue;
88
+ }
89
+ let rawAbi;
90
+ try {
91
+ rawAbi = JSON.parse(fs.readFileSync(abiPath, "utf-8"));
92
+ }
93
+ catch (e) {
94
+ console.warn(` Warning: Failed to parse ABI ${abiRef.file}: ${e.message}`);
95
+ continue;
96
+ }
97
+ const events = Array.isArray(rawAbi) ? rawAbi.filter((x) => x.type === "event") : [];
98
+ for (const ev of events) {
99
+ const scopedParamsClass = `${ds.name}_${ev.name}Params`;
100
+ const scopedEventClass = `${ds.name}_${ev.name}Event`;
101
+ const isFirstOccurrence = !seenEventNames.has(ev.name);
102
+ seenEventNames.add(ev.name);
103
+ // Params class
104
+ lines.push(`export class ${scopedParamsClass} {`);
105
+ for (const inp of ev.inputs) {
106
+ const asType = solTypeToAs(inp.type);
107
+ const defaultVal = asType === "Address"
108
+ ? 'Address.fromString("0x0000000000000000000000000000000000000000")'
109
+ : asType === "Bytes"
110
+ ? 'Bytes.fromHexString("0x")'
111
+ : asType === "BigInt"
112
+ ? "BigInt.zero()"
113
+ : asType === "bool"
114
+ ? "false"
115
+ : '""';
116
+ lines.push(` ${inp.name}: ${asType} = ${defaultVal};`);
117
+ }
118
+ lines.push("");
119
+ lines.push(` constructor(raw: EventLog) {`);
120
+ let topicIdx = 1;
121
+ let nonIndexedIdx = 0;
122
+ for (const inp of ev.inputs) {
123
+ const asType = solTypeToAs(inp.type);
124
+ if (inp.indexed) {
125
+ const readTopic = `raw.topics.length > ${topicIdx} ? raw.topics[${topicIdx}] : ""`;
126
+ if (asType === "BigInt") {
127
+ lines.push(` this.${inp.name} = BigInt.fromString(${readTopic});`);
128
+ }
129
+ else if (asType === "Address") {
130
+ lines.push(` this.${inp.name} = Address.fromString(${readTopic});`);
131
+ }
132
+ else if (asType === "Bytes") {
133
+ lines.push(` this.${inp.name} = Bytes.fromHexString(${readTopic});`);
134
+ }
135
+ else {
136
+ lines.push(` this.${inp.name} = ${readTopic};`);
137
+ }
138
+ topicIdx++;
139
+ }
140
+ else {
141
+ lines.push(` {`);
142
+ lines.push(` const dataHex = raw.data.startsWith("0x") ? raw.data.slice(2) : raw.data;`);
143
+ lines.push(` const offset = ${nonIndexedIdx * 64};`);
144
+ lines.push(` const rawWord = dataHex.length >= offset + 64 ? "0x" + dataHex.slice(offset, offset + 64) : (offset == 0 ? raw.data : "");`);
145
+ if (asType === "BigInt") {
146
+ lines.push(` this.${inp.name} = BigInt.fromString(rawWord);`);
147
+ }
148
+ else if (asType === "Address") {
149
+ lines.push(` this.${inp.name} = Address.fromString(rawWord);`);
150
+ }
151
+ else if (asType === "Bytes") {
152
+ lines.push(` this.${inp.name} = Bytes.fromHexString(rawWord);`);
153
+ }
154
+ else {
155
+ lines.push(` this.${inp.name} = rawWord;`);
156
+ }
157
+ lines.push(` }`);
158
+ nonIndexedIdx++;
159
+ }
160
+ }
161
+ lines.push(" }");
162
+ lines.push("}");
163
+ lines.push("");
164
+ // Event class
165
+ lines.push(`export class ${scopedEventClass} {`);
166
+ lines.push(" address: Address;");
167
+ lines.push(" blockNumber: BigInt;");
168
+ lines.push(" blockHash: string;");
169
+ lines.push(" transactionHash: string;");
170
+ lines.push(" logIndex: u32;");
171
+ lines.push(" blockTimestamp: BigInt;");
172
+ lines.push(` params: ${scopedParamsClass};`);
173
+ lines.push("");
174
+ lines.push(" constructor(raw: EventLog) {");
175
+ lines.push(" this.address = Address.fromString(raw.address);");
176
+ lines.push(" this.blockNumber = BigInt.fromU64(raw.block_number);");
177
+ lines.push(" this.blockHash = raw.block_hash;");
178
+ lines.push(" this.transactionHash = raw.transaction_hash;");
179
+ lines.push(" this.logIndex = raw.log_index;");
180
+ lines.push(" this.blockTimestamp = BigInt.fromU64(raw.block_timestamp);");
181
+ lines.push(` this.params = new ${scopedParamsClass}(raw);`);
182
+ lines.push(" }");
183
+ lines.push("}");
184
+ lines.push("");
185
+ // Export convenience aliases if this is the primary occurrence
186
+ if (isFirstOccurrence) {
187
+ lines.push(`export { ${scopedParamsClass} as ${ev.name}Params };`);
188
+ lines.push(`export { ${scopedEventClass} as ${ev.name}Event };`);
189
+ lines.push("");
190
+ }
191
+ }
192
+ }
193
+ }
194
+ return lines.join("\n");
195
+ }
196
+ function parseSchemaFields(body) {
197
+ const fields = [];
198
+ for (const rawLine of body.split("\n")) {
199
+ const trimmed = rawLine.trim();
200
+ if (!trimmed || trimmed.startsWith("#"))
201
+ continue;
202
+ // Detect @derivedFrom(field: "...")
203
+ const isDerived = trimmed.includes("@derivedFrom");
204
+ let derivedField;
205
+ if (isDerived) {
206
+ const match = /@derivedFrom\s*\(\s*field\s*:\s*["']([^"']+)["']\s*\)/.exec(trimmed);
207
+ if (match) {
208
+ derivedField = match[1];
209
+ }
210
+ }
211
+ const cleanLine = trimmed.replace(/@\w+(\([^)]*\))?/g, "").trim();
212
+ const colonIdx = cleanLine.indexOf(":");
213
+ if (colonIdx === -1)
214
+ continue;
215
+ const name = cleanLine.slice(0, colonIdx).trim();
216
+ const typePart = cleanLine.slice(colonIdx + 1).trim();
217
+ const required = typePart.endsWith("!");
218
+ const type = typePart.replace("!", "").trim();
219
+ fields.push({ name, type, required, isDerived, derivedField });
220
+ }
221
+ return fields;
222
+ }
223
+ function graphqlTypeToAs(gqlType) {
224
+ if (gqlType === "ID" || gqlType === "String" || gqlType === "Bytes")
225
+ return "string";
226
+ if (gqlType === "Int")
227
+ return "i32";
228
+ if (gqlType === "BigInt")
229
+ return "BigInt";
230
+ if (gqlType === "Boolean")
231
+ return "bool";
232
+ if (gqlType === "Float")
233
+ return "f64";
234
+ return "string";
235
+ }
236
+ function generateSchemaTs(projectDir) {
237
+ const schemaPath = path.join(projectDir, "schema.graphql");
238
+ const lines = [
239
+ "// Auto-generated by `logrix codegen`. Do not edit.",
240
+ 'import { store, BigInt, extractJsonField } from "@logrix/sdk";',
241
+ "",
242
+ ];
243
+ if (!fs.existsSync(schemaPath)) {
244
+ console.warn(" Warning: schema.graphql not found, skipping entity generation.");
245
+ return lines.join("\n");
246
+ }
247
+ const content = fs.readFileSync(schemaPath, "utf-8");
248
+ const entityRegex = /type\s+(\w+)\s+@entity\s*\{([^}]+)\}/g;
249
+ let match;
250
+ while ((match = entityRegex.exec(content)) !== null) {
251
+ const entityName = match[1];
252
+ const fields = parseSchemaFields(match[2]);
253
+ lines.push(`export class ${entityName} {`);
254
+ for (const f of fields) {
255
+ if (f.name === "id") {
256
+ lines.push(" id: string;");
257
+ }
258
+ else if (f.isDerived) {
259
+ // Virtual reverse-lookup field; not stored directly in DB payload
260
+ lines.push(` // @derivedFrom(field: "${f.derivedField || ""}") virtual relation`);
261
+ }
262
+ else {
263
+ const asType = graphqlTypeToAs(f.type);
264
+ const defaultVal = asType === "string" ? '""'
265
+ : asType === "BigInt" ? "BigInt.zero()"
266
+ : asType === "bool" ? "false"
267
+ : asType === "f64" ? "0.0"
268
+ : "0";
269
+ lines.push(` ${f.name}: ${asType} = ${defaultVal};`);
270
+ }
271
+ }
272
+ lines.push("");
273
+ lines.push(" constructor(id: string) {");
274
+ lines.push(" this.id = id;");
275
+ lines.push(" }");
276
+ lines.push("");
277
+ // static load(id: string): Entity | null
278
+ lines.push(` static load(id: string): ${entityName} | null {`);
279
+ lines.push(` const raw = store.get("${entityName}", id);`);
280
+ lines.push(` if (raw.length == 0) return null;`);
281
+ lines.push(` const entity = new ${entityName}(id);`);
282
+ for (const f of fields) {
283
+ if (f.name === "id" || f.isDerived)
284
+ continue;
285
+ const asType = graphqlTypeToAs(f.type);
286
+ if (asType === "string") {
287
+ lines.push(` entity.${f.name} = extractJsonField(raw, "${f.name}");`);
288
+ }
289
+ else if (asType === "BigInt") {
290
+ lines.push(` entity.${f.name} = BigInt.fromString(extractJsonField(raw, "${f.name}"));`);
291
+ }
292
+ else if (asType === "bool") {
293
+ lines.push(` entity.${f.name} = extractJsonField(raw, "${f.name}") == "true";`);
294
+ }
295
+ else if (asType === "i32") {
296
+ lines.push(` {`);
297
+ lines.push(` const valStr = extractJsonField(raw, "${f.name}");`);
298
+ lines.push(` if (valStr.length > 0) entity.${f.name} = parseInt(valStr) as i32;`);
299
+ lines.push(` }`);
300
+ }
301
+ else if (asType === "f64") {
302
+ lines.push(` {`);
303
+ lines.push(` const valStr = extractJsonField(raw, "${f.name}");`);
304
+ lines.push(` if (valStr.length > 0) entity.${f.name} = parseFloat(valStr);`);
305
+ lines.push(` }`);
306
+ }
307
+ }
308
+ lines.push(" return entity;");
309
+ lines.push(" }");
310
+ lines.push("");
311
+ // static remove(id: string): void
312
+ lines.push(` static remove(id: string): void {`);
313
+ lines.push(` store.remove("${entityName}", id);`);
314
+ lines.push(" }");
315
+ lines.push("");
316
+ // save(): void
317
+ lines.push(" save(): void {");
318
+ const jsonParts = [];
319
+ for (const f of fields) {
320
+ if (f.isDerived)
321
+ continue; // Skip virtual reverse-lookup relations in database payload
322
+ const asType = graphqlTypeToAs(f.type);
323
+ if (asType === "BigInt" || asType === "string") {
324
+ jsonParts.push(`"\\"${f.name}\\":\\"" + this.${f.name}.toString() + "\\""`);
325
+ }
326
+ else {
327
+ jsonParts.push(`"\\"${f.name}\\":" + this.${f.name}.toString()`);
328
+ }
329
+ }
330
+ lines.push(` const payload = "{" + ${jsonParts.join(' + "," + ')} + "}";`);
331
+ lines.push(` store.set("${entityName}", this.id, payload);`);
332
+ lines.push(" }");
333
+ lines.push("}");
334
+ lines.push("");
335
+ }
336
+ return lines.join("\n");
337
+ }
338
+ // ---------------------------------------------------------------------------
339
+ // Command
340
+ // ---------------------------------------------------------------------------
341
+ function codegenCommand() {
342
+ const cmd = new commander_1.Command("codegen");
343
+ cmd
344
+ .description("Generate typed AssemblyScript bindings from ABI files and schema.graphql")
345
+ .action(() => {
346
+ const projectDir = process.cwd();
347
+ const configPath = path.join(projectDir, "logrix.yaml");
348
+ if (!fs.existsSync(configPath)) {
349
+ console.error("Error: logrix.yaml not found. Run this command from your project root.");
350
+ process.exit(1);
351
+ }
352
+ const config = (0, yaml_1.parse)(fs.readFileSync(configPath, "utf-8"));
353
+ const generatedDir = path.join(projectDir, "src", "generated");
354
+ fs.mkdirSync(generatedDir, { recursive: true });
355
+ console.log("Generating src/generated/events.ts ...");
356
+ const eventsTs = generateEventsTs(config.dataSources, projectDir);
357
+ fs.writeFileSync(path.join(generatedDir, "events.ts"), eventsTs);
358
+ console.log("Generating src/generated/schema.ts ...");
359
+ const schemaTs = generateSchemaTs(projectDir);
360
+ fs.writeFileSync(path.join(generatedDir, "schema.ts"), schemaTs);
361
+ console.log("Done.");
362
+ });
363
+ return cmd;
364
+ }
@@ -0,0 +1,127 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.exportValuesCommand = exportValuesCommand;
37
+ const commander_1 = require("commander");
38
+ const fs = __importStar(require("fs"));
39
+ const path = __importStar(require("path"));
40
+ const yaml_1 = require("yaml");
41
+ /**
42
+ * logrix export-values
43
+ *
44
+ * Reads logrix.yaml, schema.graphql, and build/mapping.wasm then writes an
45
+ * indexer-values.yaml that is ready to be passed to:
46
+ * helm install logrix oci://ghcr.io/vishal-770/charts/logrix \
47
+ * -f cluster-infra.yaml -f indexer-values.yaml
48
+ */
49
+ function exportValuesCommand() {
50
+ const cmd = new commander_1.Command("export-values");
51
+ cmd
52
+ .description("Export a Helm-compatible indexer-values.yaml from this project")
53
+ .option("--out <file>", "Output file path", "indexer-values.yaml")
54
+ .option("--chain-id <id>", "Override chain ID (default: from logrix.yaml)")
55
+ .option("--rpc <url>", "Override RPC URL (default: from logrix.yaml)")
56
+ .action((opts) => {
57
+ const projectDir = process.cwd();
58
+ const configPath = path.join(projectDir, "logrix.yaml");
59
+ if (!fs.existsSync(configPath)) {
60
+ console.error("Error: logrix.yaml not found. Run this command from your project root.");
61
+ process.exit(1);
62
+ }
63
+ let config;
64
+ try {
65
+ config = (0, yaml_1.parse)(fs.readFileSync(configPath, "utf-8"));
66
+ }
67
+ catch (e) {
68
+ console.error(`Error parsing logrix.yaml: ${e.message}`);
69
+ process.exit(1);
70
+ }
71
+ // Resolve network settings
72
+ const chainId = opts.chainId
73
+ ? parseInt(opts.chainId, 10)
74
+ : config.network?.chainId ?? 1;
75
+ const rpcUrl = opts.rpc ?? config.network?.rpcUrl ?? "";
76
+ if (!rpcUrl) {
77
+ console.error("Error: RPC URL not found in logrix.yaml (network.rpcUrl) and --rpc was not passed.");
78
+ process.exit(1);
79
+ }
80
+ // Build contracts manifest array (Rust engine format)
81
+ const contracts = [];
82
+ for (const ds of config.dataSources ?? []) {
83
+ const events = (ds.mapping?.eventHandlers ?? []).map((h) => h.event);
84
+ contracts.push({
85
+ name: ds.name,
86
+ address: ds.source?.address ?? "",
87
+ events,
88
+ wasm_handler: "./mapping.wasm",
89
+ });
90
+ }
91
+ const manifest = {
92
+ schema_version: "1",
93
+ chain_id: chainId,
94
+ contracts,
95
+ };
96
+ // Read schema.graphql
97
+ const schemaPath = path.join(projectDir, "schema.graphql");
98
+ if (!fs.existsSync(schemaPath)) {
99
+ console.error("Error: schema.graphql not found. Run this command from your project root.");
100
+ process.exit(1);
101
+ }
102
+ const schemaContent = fs.readFileSync(schemaPath, "utf-8");
103
+ // Read compiled WASM (base64)
104
+ const wasmPath = path.join(projectDir, "build", "mapping.wasm");
105
+ if (!fs.existsSync(wasmPath)) {
106
+ console.error("Error: build/mapping.wasm not found. Run `logrix build` first.");
107
+ process.exit(1);
108
+ }
109
+ const wasmBase64 = fs.readFileSync(wasmPath).toString("base64");
110
+ // Build indexer-values.yaml
111
+ const values = {
112
+ config: {
113
+ chainId,
114
+ rpcUrl,
115
+ manifestContent: (0, yaml_1.stringify)(manifest, { indent: 2 }),
116
+ schemaContent,
117
+ wasmBase64,
118
+ },
119
+ };
120
+ const outPath = path.resolve(projectDir, opts.out);
121
+ fs.writeFileSync(outPath, (0, yaml_1.stringify)(values, { indent: 2 }));
122
+ console.log(`\nExported Helm values to: ${opts.out}`);
123
+ console.log("\nDeploy with:");
124
+ console.log(` helm install logrix oci://ghcr.io/vishal-770/charts/logrix -f cluster-infra.yaml -f ${opts.out}\n`);
125
+ });
126
+ return cmd;
127
+ }