@inodra/sui 0.1.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 +202 -0
- package/README.md +237 -0
- package/bin/inodra-sui.mjs +2 -0
- package/dist/chunk-3CBLVI6J.js +426 -0
- package/dist/chunk-3CBLVI6J.js.map +1 -0
- package/dist/chunk-4HKKW5QN.js +80 -0
- package/dist/chunk-4HKKW5QN.js.map +1 -0
- package/dist/chunk-74XGJJJI.js +33 -0
- package/dist/chunk-74XGJJJI.js.map +1 -0
- package/dist/chunk-D6FZYWG7.js +99 -0
- package/dist/chunk-D6FZYWG7.js.map +1 -0
- package/dist/chunk-LZZMTSLH.js +31 -0
- package/dist/chunk-LZZMTSLH.js.map +1 -0
- package/dist/chunk-M3M2L6BW.js +29 -0
- package/dist/chunk-M3M2L6BW.js.map +1 -0
- package/dist/chunk-NSXRC5XW.js +298 -0
- package/dist/chunk-NSXRC5XW.js.map +1 -0
- package/dist/chunk-OGMBYWTG.js +537 -0
- package/dist/chunk-OGMBYWTG.js.map +1 -0
- package/dist/chunk-U6D5LGNF.js +111 -0
- package/dist/chunk-U6D5LGNF.js.map +1 -0
- package/dist/chunk-ZSW3EWGF.js +539 -0
- package/dist/chunk-ZSW3EWGF.js.map +1 -0
- package/dist/cli.js +665 -0
- package/dist/cli.js.map +1 -0
- package/dist/events.cjs +3273 -0
- package/dist/events.cjs.map +1 -0
- package/dist/events.d.cts +47 -0
- package/dist/events.d.ts +47 -0
- package/dist/events.js +2578 -0
- package/dist/events.js.map +1 -0
- package/dist/graphql.cjs +129 -0
- package/dist/graphql.cjs.map +1 -0
- package/dist/graphql.d.cts +36 -0
- package/dist/graphql.d.ts +36 -0
- package/dist/graphql.js +10 -0
- package/dist/graphql.js.map +1 -0
- package/dist/grpc-web.cjs +129 -0
- package/dist/grpc-web.cjs.map +1 -0
- package/dist/grpc-web.d.cts +31 -0
- package/dist/grpc-web.d.ts +31 -0
- package/dist/grpc-web.js +10 -0
- package/dist/grpc-web.js.map +1 -0
- package/dist/grpc.cjs +131 -0
- package/dist/grpc.cjs.map +1 -0
- package/dist/grpc.d.cts +34 -0
- package/dist/grpc.d.ts +34 -0
- package/dist/grpc.js +10 -0
- package/dist/grpc.js.map +1 -0
- package/dist/index-CGBN_EI5.d.ts +4800 -0
- package/dist/index-CVO2Kj8a.d.cts +4800 -0
- package/dist/index.cjs +4723 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +504 -0
- package/dist/index.d.ts +504 -0
- package/dist/index.js +59 -0
- package/dist/index.js.map +1 -0
- package/dist/manage.cjs +376 -0
- package/dist/manage.cjs.map +1 -0
- package/dist/manage.d.cts +2 -0
- package/dist/manage.d.ts +2 -0
- package/dist/manage.js +8 -0
- package/dist/manage.js.map +1 -0
- package/dist/network-CEg2MJY3.d.cts +60 -0
- package/dist/network-CEg2MJY3.d.ts +60 -0
- package/dist/node.cjs +4759 -0
- package/dist/node.cjs.map +1 -0
- package/dist/node.d.cts +28 -0
- package/dist/node.d.ts +28 -0
- package/dist/node.js +73 -0
- package/dist/node.js.map +1 -0
- package/dist/reflection-Bx44-Fs1.d.ts +4639 -0
- package/dist/reflection-Cf7WFH6H.d.cts +4639 -0
- package/dist/reflection-FEGYA7DU.js +9 -0
- package/dist/reflection-FEGYA7DU.js.map +1 -0
- package/dist/runtime-OWKF3LZ7.js +37 -0
- package/dist/runtime-OWKF3LZ7.js.map +1 -0
- package/dist/warp.cjs +633 -0
- package/dist/warp.cjs.map +1 -0
- package/dist/warp.d.cts +195 -0
- package/dist/warp.d.ts +195 -0
- package/dist/warp.js +12 -0
- package/dist/warp.js.map +1 -0
- package/dist/webhooks.cjs +104 -0
- package/dist/webhooks.cjs.map +1 -0
- package/dist/webhooks.d.cts +35 -0
- package/dist/webhooks.d.ts +35 -0
- package/dist/webhooks.js +7 -0
- package/dist/webhooks.js.map +1 -0
- package/llms.txt +189 -0
- package/package.json +119 -0
package/dist/cli.js
ADDED
|
@@ -0,0 +1,665 @@
|
|
|
1
|
+
// src/cli.ts
|
|
2
|
+
import { writeFileSync } from "fs";
|
|
3
|
+
|
|
4
|
+
// src/events/move-types.ts
|
|
5
|
+
import { z as z2 } from "zod";
|
|
6
|
+
|
|
7
|
+
// src/events/runtime.ts
|
|
8
|
+
import { z } from "zod";
|
|
9
|
+
var moveSmallUint = z.number();
|
|
10
|
+
var moveUint = z.union([z.string(), z.number()]).transform((value) => String(value));
|
|
11
|
+
var moveBool = z.boolean();
|
|
12
|
+
var moveAddress = z.string();
|
|
13
|
+
var moveString = z.string();
|
|
14
|
+
var moveTypeName = z.union([z.string(), z.looseObject({ name: z.string() })]).transform((value) => typeof value === "string" ? value : value.name);
|
|
15
|
+
var moveBalance = z.union([
|
|
16
|
+
z.string(),
|
|
17
|
+
z.number(),
|
|
18
|
+
z.looseObject({ value: z.union([z.string(), z.number()]) })
|
|
19
|
+
]).transform(
|
|
20
|
+
(value) => typeof value === "object" ? String(value.value) : String(value)
|
|
21
|
+
);
|
|
22
|
+
var moveBytes = z.union([z.string(), z.array(z.number())]);
|
|
23
|
+
var warpEventPayloadSchema = z.looseObject({
|
|
24
|
+
activityType: z.literal("package_event"),
|
|
25
|
+
txDigest: z.string(),
|
|
26
|
+
eventSequence: z.number(),
|
|
27
|
+
checkpoint: z.number(),
|
|
28
|
+
timestamp: z.number(),
|
|
29
|
+
/** Full concrete Move event type. */
|
|
30
|
+
type: z.string(),
|
|
31
|
+
sender: z.string(),
|
|
32
|
+
/** Decoded Move event payload — type with the generated catalog schemas. */
|
|
33
|
+
data: z.unknown()
|
|
34
|
+
});
|
|
35
|
+
var warpAddressPayloadSchema = z.looseObject({
|
|
36
|
+
address: z.string(),
|
|
37
|
+
activityType: z.string(),
|
|
38
|
+
txDigest: z.string(),
|
|
39
|
+
checkpoint: z.number(),
|
|
40
|
+
timestamp: z.number(),
|
|
41
|
+
objectId: z.string().optional(),
|
|
42
|
+
objectType: z.string().optional()
|
|
43
|
+
});
|
|
44
|
+
var warpCoinPayloadSchema = z.looseObject({
|
|
45
|
+
activityType: z.literal("balance_change"),
|
|
46
|
+
address: z.string(),
|
|
47
|
+
coin_type: z.string(),
|
|
48
|
+
/** Signed amount, string for precision. */
|
|
49
|
+
amount: z.string(),
|
|
50
|
+
txDigest: z.string(),
|
|
51
|
+
checkpoint: z.number(),
|
|
52
|
+
timestamp: z.number()
|
|
53
|
+
});
|
|
54
|
+
var warpObjectPayloadSchema = z.looseObject({
|
|
55
|
+
activityType: z.literal("object_change"),
|
|
56
|
+
object_id: z.string(),
|
|
57
|
+
transactionDirection: z.string(),
|
|
58
|
+
writeKind: z.string(),
|
|
59
|
+
owner: z.string().optional(),
|
|
60
|
+
previousOwner: z.string().optional(),
|
|
61
|
+
txDigest: z.string(),
|
|
62
|
+
checkpoint: z.number(),
|
|
63
|
+
timestamp: z.number()
|
|
64
|
+
});
|
|
65
|
+
var webhookEventBodySchema = z.looseObject({
|
|
66
|
+
payloadVersion: z.number(),
|
|
67
|
+
payload: warpEventPayloadSchema.extend({ webhookId: z.string() })
|
|
68
|
+
});
|
|
69
|
+
function baseEventType(eventType) {
|
|
70
|
+
const idx = eventType.indexOf("<");
|
|
71
|
+
return idx === -1 ? eventType : eventType.slice(0, idx);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// src/events/move-types.ts
|
|
75
|
+
var PRIMITIVES = /* @__PURE__ */ new Set([
|
|
76
|
+
"u8",
|
|
77
|
+
"u16",
|
|
78
|
+
"u32",
|
|
79
|
+
"u64",
|
|
80
|
+
"u128",
|
|
81
|
+
"u256",
|
|
82
|
+
"bool",
|
|
83
|
+
"address",
|
|
84
|
+
"signer"
|
|
85
|
+
]);
|
|
86
|
+
function splitArgs(inner) {
|
|
87
|
+
const parts = [];
|
|
88
|
+
let depth = 0;
|
|
89
|
+
let current = "";
|
|
90
|
+
for (const char of inner) {
|
|
91
|
+
if (char === "<") depth++;
|
|
92
|
+
if (char === ">") depth--;
|
|
93
|
+
if (char === "," && depth === 0) {
|
|
94
|
+
parts.push(current.trim());
|
|
95
|
+
current = "";
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
current += char;
|
|
99
|
+
}
|
|
100
|
+
if (current.trim()) parts.push(current.trim());
|
|
101
|
+
return parts;
|
|
102
|
+
}
|
|
103
|
+
function parseMoveType(input) {
|
|
104
|
+
const type = input.trim();
|
|
105
|
+
if (PRIMITIVES.has(type)) {
|
|
106
|
+
return { kind: "prim", prim: type };
|
|
107
|
+
}
|
|
108
|
+
if (type.startsWith("vector<") && type.endsWith(">")) {
|
|
109
|
+
return { kind: "vector", inner: parseMoveType(type.slice(7, -1)) };
|
|
110
|
+
}
|
|
111
|
+
const param = /^\$(\d+)$/.exec(type);
|
|
112
|
+
if (param) {
|
|
113
|
+
return { kind: "param", index: Number(param[1]) };
|
|
114
|
+
}
|
|
115
|
+
const generic = type.indexOf("<");
|
|
116
|
+
const base = generic === -1 ? type : type.slice(0, generic);
|
|
117
|
+
const args = generic === -1 || !type.endsWith(">") ? [] : splitArgs(type.slice(generic + 1, -1)).map(parseMoveType);
|
|
118
|
+
const [address, module, name, ...rest2] = base.split("::");
|
|
119
|
+
if (address?.startsWith("0x") && module && name && rest2.length === 0) {
|
|
120
|
+
return {
|
|
121
|
+
kind: "struct",
|
|
122
|
+
address: normalizeAddress(address),
|
|
123
|
+
module,
|
|
124
|
+
name,
|
|
125
|
+
args
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
return { kind: "opaque", raw: type };
|
|
129
|
+
}
|
|
130
|
+
function normalizeAddress(address) {
|
|
131
|
+
return address.replace(/^0x0+(?=[0-9a-fA-F])/, "0x");
|
|
132
|
+
}
|
|
133
|
+
function formatMoveType(node) {
|
|
134
|
+
switch (node.kind) {
|
|
135
|
+
case "prim":
|
|
136
|
+
return node.prim;
|
|
137
|
+
case "vector":
|
|
138
|
+
return `vector<${formatMoveType(node.inner)}>`;
|
|
139
|
+
case "param":
|
|
140
|
+
return `$${node.index}`;
|
|
141
|
+
case "opaque":
|
|
142
|
+
return node.raw;
|
|
143
|
+
case "struct": {
|
|
144
|
+
const base = `${node.address}::${node.module}::${node.name}`;
|
|
145
|
+
return node.args.length === 0 ? base : `${base}<${node.args.map(formatMoveType).join(", ")}>`;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
function substituteTypeParams(node, args) {
|
|
150
|
+
switch (node.kind) {
|
|
151
|
+
case "param":
|
|
152
|
+
return args[node.index] ?? node;
|
|
153
|
+
case "vector":
|
|
154
|
+
return { kind: "vector", inner: substituteTypeParams(node.inner, args) };
|
|
155
|
+
case "struct":
|
|
156
|
+
return {
|
|
157
|
+
...node,
|
|
158
|
+
args: node.args.map((a) => substituteTypeParams(a, args))
|
|
159
|
+
};
|
|
160
|
+
default:
|
|
161
|
+
return node;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
var MAX_DEPTH = 6;
|
|
165
|
+
async function resolveShape(node, resolveStruct, depth = 0, stack = []) {
|
|
166
|
+
switch (node.kind) {
|
|
167
|
+
case "prim":
|
|
168
|
+
switch (node.prim) {
|
|
169
|
+
case "u8":
|
|
170
|
+
case "u16":
|
|
171
|
+
case "u32":
|
|
172
|
+
return { kind: "smallUint" };
|
|
173
|
+
case "u64":
|
|
174
|
+
case "u128":
|
|
175
|
+
case "u256":
|
|
176
|
+
return { kind: "uint" };
|
|
177
|
+
case "bool":
|
|
178
|
+
return { kind: "bool" };
|
|
179
|
+
case "address":
|
|
180
|
+
case "signer":
|
|
181
|
+
return { kind: "address" };
|
|
182
|
+
default:
|
|
183
|
+
return { kind: "unknown" };
|
|
184
|
+
}
|
|
185
|
+
case "vector":
|
|
186
|
+
if (node.inner.kind === "prim" && node.inner.prim === "u8") {
|
|
187
|
+
return { kind: "bytes" };
|
|
188
|
+
}
|
|
189
|
+
return {
|
|
190
|
+
kind: "vector",
|
|
191
|
+
inner: await resolveShape(node.inner, resolveStruct, depth, stack)
|
|
192
|
+
};
|
|
193
|
+
case "param":
|
|
194
|
+
case "opaque":
|
|
195
|
+
return { kind: "unknown" };
|
|
196
|
+
case "struct": {
|
|
197
|
+
const base = `${node.address}::${node.module}::${node.name}`;
|
|
198
|
+
switch (base) {
|
|
199
|
+
case "0x1::string::String":
|
|
200
|
+
case "0x1::ascii::String":
|
|
201
|
+
case "0x2::url::Url":
|
|
202
|
+
return { kind: "string" };
|
|
203
|
+
case "0x1::type_name::TypeName":
|
|
204
|
+
return { kind: "typeName" };
|
|
205
|
+
case "0x2::object::ID":
|
|
206
|
+
return { kind: "address" };
|
|
207
|
+
case "0x2::balance::Balance":
|
|
208
|
+
return { kind: "balance" };
|
|
209
|
+
case "0x1::option::Option": {
|
|
210
|
+
const inner = node.args[0];
|
|
211
|
+
if (node.args.length === 1 && inner) {
|
|
212
|
+
return {
|
|
213
|
+
kind: "option",
|
|
214
|
+
inner: await resolveShape(inner, resolveStruct, depth, stack)
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
return { kind: "unknown" };
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
const key = formatMoveType(node);
|
|
221
|
+
if (depth >= MAX_DEPTH || stack.includes(key)) {
|
|
222
|
+
return { kind: "unknown" };
|
|
223
|
+
}
|
|
224
|
+
const definition = await resolveStruct(node);
|
|
225
|
+
if (!definition) {
|
|
226
|
+
return { kind: "unknown" };
|
|
227
|
+
}
|
|
228
|
+
const fields = await Promise.all(
|
|
229
|
+
definition.map(async (field) => ({
|
|
230
|
+
name: field.name,
|
|
231
|
+
value: await resolveShape(
|
|
232
|
+
substituteTypeParams(field.type, node.args),
|
|
233
|
+
resolveStruct,
|
|
234
|
+
depth + 1,
|
|
235
|
+
[...stack, key]
|
|
236
|
+
)
|
|
237
|
+
}))
|
|
238
|
+
);
|
|
239
|
+
return { kind: "object", fields };
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
function shapeToZod(shape) {
|
|
244
|
+
switch (shape.kind) {
|
|
245
|
+
case "smallUint":
|
|
246
|
+
return moveSmallUint;
|
|
247
|
+
case "uint":
|
|
248
|
+
return moveUint;
|
|
249
|
+
case "bool":
|
|
250
|
+
return moveBool;
|
|
251
|
+
case "address":
|
|
252
|
+
return moveAddress;
|
|
253
|
+
case "string":
|
|
254
|
+
return moveString;
|
|
255
|
+
case "typeName":
|
|
256
|
+
return moveTypeName;
|
|
257
|
+
case "balance":
|
|
258
|
+
return moveBalance;
|
|
259
|
+
case "bytes":
|
|
260
|
+
return moveBytes;
|
|
261
|
+
case "option":
|
|
262
|
+
return shapeToZod(shape.inner).nullable();
|
|
263
|
+
case "vector":
|
|
264
|
+
return z2.array(shapeToZod(shape.inner));
|
|
265
|
+
case "object":
|
|
266
|
+
return z2.looseObject(
|
|
267
|
+
Object.fromEntries(
|
|
268
|
+
shape.fields.map((f) => [f.name, shapeToZod(f.value)])
|
|
269
|
+
)
|
|
270
|
+
);
|
|
271
|
+
case "unknown":
|
|
272
|
+
return z2.unknown();
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
var PRIMITIVE_EXPRS = {
|
|
276
|
+
smallUint: "moveSmallUint",
|
|
277
|
+
uint: "moveUint",
|
|
278
|
+
bool: "moveBool",
|
|
279
|
+
address: "moveAddress",
|
|
280
|
+
string: "moveString",
|
|
281
|
+
typeName: "moveTypeName",
|
|
282
|
+
balance: "moveBalance",
|
|
283
|
+
bytes: "moveBytes"
|
|
284
|
+
};
|
|
285
|
+
function shapeToExpr(shape, used, indent = "") {
|
|
286
|
+
const primitive = PRIMITIVE_EXPRS[shape.kind];
|
|
287
|
+
if (primitive) {
|
|
288
|
+
used.add(primitive);
|
|
289
|
+
return primitive;
|
|
290
|
+
}
|
|
291
|
+
switch (shape.kind) {
|
|
292
|
+
case "option":
|
|
293
|
+
return `${shapeToExpr(shape.inner, used, indent)}.nullable()`;
|
|
294
|
+
case "vector":
|
|
295
|
+
return `z.array(${shapeToExpr(shape.inner, used, indent)})`;
|
|
296
|
+
case "object": {
|
|
297
|
+
const lines = ["z.looseObject({"];
|
|
298
|
+
for (const field of shape.fields) {
|
|
299
|
+
lines.push(
|
|
300
|
+
`${indent} ${JSON.stringify(field.name)}: ${shapeToExpr(field.value, used, `${indent} `)},`
|
|
301
|
+
);
|
|
302
|
+
}
|
|
303
|
+
lines.push(`${indent}})`);
|
|
304
|
+
return lines.join("\n");
|
|
305
|
+
}
|
|
306
|
+
default:
|
|
307
|
+
return "z.unknown()";
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
// src/core/auth.ts
|
|
312
|
+
function resolveAuth(auth) {
|
|
313
|
+
if (typeof auth === "string") {
|
|
314
|
+
return staticAuth(apiKeyCredentials(auth));
|
|
315
|
+
}
|
|
316
|
+
if ("apiKey" in auth) {
|
|
317
|
+
return staticAuth(apiKeyCredentials(auth.apiKey));
|
|
318
|
+
}
|
|
319
|
+
if ("sessionToken" in auth) {
|
|
320
|
+
return staticAuth({
|
|
321
|
+
headers: { authorization: `Bearer ${auth.sessionToken}` }
|
|
322
|
+
});
|
|
323
|
+
}
|
|
324
|
+
return {
|
|
325
|
+
credentials: async () => auth.getCredentials(),
|
|
326
|
+
staticCredentials: () => void 0
|
|
327
|
+
};
|
|
328
|
+
}
|
|
329
|
+
function authFromOptions(options, context) {
|
|
330
|
+
if (options.auth !== void 0) {
|
|
331
|
+
return resolveAuth(options.auth);
|
|
332
|
+
}
|
|
333
|
+
if (options.apiKey) {
|
|
334
|
+
return resolveAuth(options.apiKey);
|
|
335
|
+
}
|
|
336
|
+
throw new Error(`${context} requires auth (or the apiKey shorthand)`);
|
|
337
|
+
}
|
|
338
|
+
function apiKeyCredentials(apiKey) {
|
|
339
|
+
if (!apiKey) {
|
|
340
|
+
throw new Error("Inodra auth: apiKey must be a non-empty string");
|
|
341
|
+
}
|
|
342
|
+
return {
|
|
343
|
+
headers: { "x-api-key": apiKey },
|
|
344
|
+
queryParams: { api_key: apiKey }
|
|
345
|
+
};
|
|
346
|
+
}
|
|
347
|
+
function staticAuth(credentials) {
|
|
348
|
+
return {
|
|
349
|
+
credentials: async () => credentials,
|
|
350
|
+
staticCredentials: () => credentials
|
|
351
|
+
};
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
// src/core/network.ts
|
|
355
|
+
var INODRA_ENDPOINTS = {
|
|
356
|
+
mainnet: {
|
|
357
|
+
rest: "https://mainnet-api.inodra.com/v1",
|
|
358
|
+
graphql: "https://mainnet-api.inodra.com/v1/graphql",
|
|
359
|
+
/** host:port for native gRPC transports */
|
|
360
|
+
grpc: "mainnet-grpc.inodra.com:443",
|
|
361
|
+
/** base URL for gRPC-Web transports */
|
|
362
|
+
grpcWeb: "https://mainnet-grpc.inodra.com",
|
|
363
|
+
warpWs: "wss://mainnet-api.inodra.com/v1"
|
|
364
|
+
},
|
|
365
|
+
testnet: {
|
|
366
|
+
rest: "https://testnet-api.inodra.com/v1",
|
|
367
|
+
graphql: "https://testnet-api.inodra.com/v1/graphql",
|
|
368
|
+
grpc: "testnet-grpc.inodra.com:443",
|
|
369
|
+
grpcWeb: "https://testnet-grpc.inodra.com",
|
|
370
|
+
warpWs: "wss://testnet-api.inodra.com/v1"
|
|
371
|
+
}
|
|
372
|
+
};
|
|
373
|
+
function graphqlUrl(network) {
|
|
374
|
+
return INODRA_ENDPOINTS[network].graphql;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
// src/core/version.ts
|
|
378
|
+
var SDK_VERSION = "0.1.0";
|
|
379
|
+
var SDK_HEADER_NAME = "x-inodra-sdk";
|
|
380
|
+
var SDK_HEADER_VALUE = `inodra-sdk-ts/${SDK_VERSION}`;
|
|
381
|
+
|
|
382
|
+
// src/events/reflection.ts
|
|
383
|
+
var STRUCT_QUERY = `query($pkg: SuiAddress!, $module: String!, $struct: String!) {
|
|
384
|
+
package(address: $pkg) {
|
|
385
|
+
module(name: $module) { struct(name: $struct) { fields { name type { repr } } } }
|
|
386
|
+
}
|
|
387
|
+
}`;
|
|
388
|
+
var EventSchemaReflector = class {
|
|
389
|
+
url;
|
|
390
|
+
headers;
|
|
391
|
+
fetchImpl;
|
|
392
|
+
/** Struct-definition cache, keyed by `address::module::name`. */
|
|
393
|
+
structs = /* @__PURE__ */ new Map();
|
|
394
|
+
/** Resolved shape cache, keyed by the canonical concrete type string. */
|
|
395
|
+
shapes = /* @__PURE__ */ new Map();
|
|
396
|
+
schemas = /* @__PURE__ */ new Map();
|
|
397
|
+
constructor(options = {}) {
|
|
398
|
+
this.url = options.url ?? graphqlUrl(options.network ?? "mainnet");
|
|
399
|
+
this.fetchImpl = options.fetch ?? globalThis.fetch;
|
|
400
|
+
const headers = {
|
|
401
|
+
"content-type": "application/json",
|
|
402
|
+
[SDK_HEADER_NAME]: SDK_HEADER_VALUE
|
|
403
|
+
};
|
|
404
|
+
if (options.auth !== void 0 || options.apiKey) {
|
|
405
|
+
const credentials = authFromOptions(
|
|
406
|
+
options,
|
|
407
|
+
"EventSchemaReflector"
|
|
408
|
+
).staticCredentials();
|
|
409
|
+
if (!credentials) {
|
|
410
|
+
throw new Error(
|
|
411
|
+
"EventSchemaReflector does not support dynamic credential providers"
|
|
412
|
+
);
|
|
413
|
+
}
|
|
414
|
+
Object.assign(headers, credentials.headers);
|
|
415
|
+
}
|
|
416
|
+
this.headers = headers;
|
|
417
|
+
}
|
|
418
|
+
/**
|
|
419
|
+
* Resolved schema shape for a concrete Move type (cached). Useful for
|
|
420
|
+
* codegen and introspection; most callers want {@link schemaFor}.
|
|
421
|
+
*/
|
|
422
|
+
shapeFor(type) {
|
|
423
|
+
const node = parseMoveType(type);
|
|
424
|
+
const key = formatMoveType(node);
|
|
425
|
+
let pending = this.shapes.get(key);
|
|
426
|
+
if (!pending) {
|
|
427
|
+
pending = resolveShape(node, (struct) => this.structFields(struct));
|
|
428
|
+
this.shapes.set(key, pending);
|
|
429
|
+
pending.catch(() => this.shapes.delete(key));
|
|
430
|
+
}
|
|
431
|
+
return pending;
|
|
432
|
+
}
|
|
433
|
+
/**
|
|
434
|
+
* Build (and cache) a loose, normalizing zod schema for any concrete Move
|
|
435
|
+
* event type. Same encoding rules as the generated catalog schemas.
|
|
436
|
+
*/
|
|
437
|
+
schemaFor(type) {
|
|
438
|
+
const key = formatMoveType(parseMoveType(type));
|
|
439
|
+
let pending = this.schemas.get(key);
|
|
440
|
+
if (!pending) {
|
|
441
|
+
pending = this.shapeFor(type).then((shape) => {
|
|
442
|
+
if (shape.kind !== "object") {
|
|
443
|
+
throw new Error(
|
|
444
|
+
`${type} did not resolve to a struct \u2014 is it a Move event type on this network?`
|
|
445
|
+
);
|
|
446
|
+
}
|
|
447
|
+
return shapeToZod(shape);
|
|
448
|
+
});
|
|
449
|
+
this.schemas.set(key, pending);
|
|
450
|
+
pending.catch(() => this.schemas.delete(key));
|
|
451
|
+
}
|
|
452
|
+
return pending;
|
|
453
|
+
}
|
|
454
|
+
/**
|
|
455
|
+
* Validate + normalize an event payload against the reflected schema.
|
|
456
|
+
* Accepts a Warp stream message, a bare `{type, data}` event payload, or
|
|
457
|
+
* a webhook body. Returns undefined when the message carries a different
|
|
458
|
+
* event type; throws when the payload doesn't fit the reflected schema.
|
|
459
|
+
*
|
|
460
|
+
* Matching: exact when `type` is fully instantiated; base-type when
|
|
461
|
+
* `type` has no generics (all instantiations match).
|
|
462
|
+
*/
|
|
463
|
+
async parseEvent(message, type) {
|
|
464
|
+
const payload = extractEventPayload(message);
|
|
465
|
+
if (!payload) {
|
|
466
|
+
return void 0;
|
|
467
|
+
}
|
|
468
|
+
const canonical = (t) => formatMoveType(parseMoveType(t));
|
|
469
|
+
const requested = canonical(type);
|
|
470
|
+
const matches = type.includes("<") ? canonical(payload.type) === requested : canonical(baseEventType(payload.type)) === requested;
|
|
471
|
+
if (!matches) {
|
|
472
|
+
return void 0;
|
|
473
|
+
}
|
|
474
|
+
const schema = await this.schemaFor(
|
|
475
|
+
type.includes("<") ? type : payload.type
|
|
476
|
+
);
|
|
477
|
+
return schema.parse(payload.data);
|
|
478
|
+
}
|
|
479
|
+
structFields(struct) {
|
|
480
|
+
const key = `${struct.address}::${struct.module}::${struct.name}`;
|
|
481
|
+
let pending = this.structs.get(key);
|
|
482
|
+
if (!pending) {
|
|
483
|
+
pending = this.fetchStruct(struct);
|
|
484
|
+
this.structs.set(key, pending);
|
|
485
|
+
pending.catch(() => this.structs.delete(key));
|
|
486
|
+
}
|
|
487
|
+
return pending;
|
|
488
|
+
}
|
|
489
|
+
async fetchStruct(struct) {
|
|
490
|
+
let lastError;
|
|
491
|
+
for (let attempt = 0; attempt < 3; attempt++) {
|
|
492
|
+
try {
|
|
493
|
+
const response = await this.fetchImpl(this.url, {
|
|
494
|
+
method: "POST",
|
|
495
|
+
headers: this.headers,
|
|
496
|
+
body: JSON.stringify({
|
|
497
|
+
query: STRUCT_QUERY,
|
|
498
|
+
variables: {
|
|
499
|
+
pkg: struct.address,
|
|
500
|
+
module: struct.module,
|
|
501
|
+
struct: struct.name
|
|
502
|
+
}
|
|
503
|
+
})
|
|
504
|
+
});
|
|
505
|
+
if (!response.ok) {
|
|
506
|
+
throw new Error(`GraphQL reflection failed: HTTP ${response.status}`);
|
|
507
|
+
}
|
|
508
|
+
const body = await response.json();
|
|
509
|
+
if (body.errors) {
|
|
510
|
+
throw new Error(
|
|
511
|
+
`GraphQL reflection errors: ${JSON.stringify(body.errors)}`
|
|
512
|
+
);
|
|
513
|
+
}
|
|
514
|
+
const fields = body.data?.package?.module?.struct?.fields;
|
|
515
|
+
if (!fields) {
|
|
516
|
+
return void 0;
|
|
517
|
+
}
|
|
518
|
+
return fields.map((field) => ({
|
|
519
|
+
name: field.name,
|
|
520
|
+
type: parseMoveType(field.type.repr)
|
|
521
|
+
}));
|
|
522
|
+
} catch (error) {
|
|
523
|
+
lastError = error;
|
|
524
|
+
await new Promise((r) => setTimeout(r, 300 * 2 ** attempt));
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
throw lastError;
|
|
528
|
+
}
|
|
529
|
+
};
|
|
530
|
+
function extractEventPayload(input, depth = 0) {
|
|
531
|
+
if (depth > 3 || typeof input !== "object" || input === null) {
|
|
532
|
+
return void 0;
|
|
533
|
+
}
|
|
534
|
+
const record = input;
|
|
535
|
+
if (typeof record.type === "string" && record.type.includes("::") && "data" in record) {
|
|
536
|
+
return { type: record.type, data: record.data };
|
|
537
|
+
}
|
|
538
|
+
return extractEventPayload(record.payload, depth + 1) ?? extractEventPayload(record.data, depth + 1);
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
// src/cli.ts
|
|
542
|
+
function fail(message) {
|
|
543
|
+
console.error(`inodra-sui: ${message}`);
|
|
544
|
+
process.exit(1);
|
|
545
|
+
}
|
|
546
|
+
function pascal(value) {
|
|
547
|
+
const name = value.split(/[^a-zA-Z0-9]+/).filter(Boolean).map((part) => (part[0]?.toUpperCase() ?? "") + part.slice(1)).join("");
|
|
548
|
+
return /^[0-9]/.test(name) ? `_${name}` : name;
|
|
549
|
+
}
|
|
550
|
+
function parseArgs(argv) {
|
|
551
|
+
const args = {
|
|
552
|
+
types: [],
|
|
553
|
+
network: "mainnet",
|
|
554
|
+
importFrom: "@inodra/sui/events"
|
|
555
|
+
};
|
|
556
|
+
for (let i = 0; i < argv.length; i++) {
|
|
557
|
+
const arg = argv[i];
|
|
558
|
+
switch (arg) {
|
|
559
|
+
case "-o":
|
|
560
|
+
case "--out":
|
|
561
|
+
args.out = argv[++i];
|
|
562
|
+
break;
|
|
563
|
+
case "--network":
|
|
564
|
+
args.network = argv[++i];
|
|
565
|
+
break;
|
|
566
|
+
case "--url":
|
|
567
|
+
args.url = argv[++i];
|
|
568
|
+
break;
|
|
569
|
+
case "--import-from":
|
|
570
|
+
args.importFrom = argv[++i] ?? args.importFrom;
|
|
571
|
+
break;
|
|
572
|
+
default:
|
|
573
|
+
if (arg.startsWith("-")) {
|
|
574
|
+
fail(`unknown option ${arg}`);
|
|
575
|
+
}
|
|
576
|
+
args.types.push(arg);
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
return args;
|
|
580
|
+
}
|
|
581
|
+
async function codegenEvents(args) {
|
|
582
|
+
if (args.types.length === 0) {
|
|
583
|
+
fail("pass at least one Move event type");
|
|
584
|
+
}
|
|
585
|
+
const apiKey = process.env.INODRA_API_KEY;
|
|
586
|
+
const url = args.url ?? (apiKey ? void 0 : `https://graphql.${args.network}.sui.io/graphql`);
|
|
587
|
+
const reflector = new EventSchemaReflector({
|
|
588
|
+
...apiKey && !args.url ? { apiKey } : {},
|
|
589
|
+
network: args.network,
|
|
590
|
+
url
|
|
591
|
+
});
|
|
592
|
+
const used = /* @__PURE__ */ new Set();
|
|
593
|
+
const blocks = [];
|
|
594
|
+
const mapEntries = [];
|
|
595
|
+
const seenNames = /* @__PURE__ */ new Map();
|
|
596
|
+
for (const rawType of args.types) {
|
|
597
|
+
const node = parseMoveType(rawType);
|
|
598
|
+
if (node.kind !== "struct") {
|
|
599
|
+
fail(`${rawType} is not a struct event type`);
|
|
600
|
+
}
|
|
601
|
+
const canonical = formatMoveType(node);
|
|
602
|
+
let shape;
|
|
603
|
+
try {
|
|
604
|
+
shape = await reflector.shapeFor(canonical);
|
|
605
|
+
} catch (error) {
|
|
606
|
+
fail(`reflection failed for ${canonical}: ${error.message}`);
|
|
607
|
+
}
|
|
608
|
+
if (shape.kind !== "object") {
|
|
609
|
+
fail(`${canonical} did not resolve to a struct on ${args.network}`);
|
|
610
|
+
}
|
|
611
|
+
let name = pascal(`${node.module} ${node.name}`);
|
|
612
|
+
const clashes = seenNames.get(name) ?? 0;
|
|
613
|
+
seenNames.set(name, clashes + 1);
|
|
614
|
+
if (clashes > 0) {
|
|
615
|
+
name = `${name}${clashes + 1}`;
|
|
616
|
+
}
|
|
617
|
+
blocks.push(
|
|
618
|
+
[
|
|
619
|
+
`/** ${canonical} */`,
|
|
620
|
+
`export const ${name}Schema = ${shapeToExpr(shape, used)};`,
|
|
621
|
+
`export type ${name}Event = z.infer<typeof ${name}Schema>;`
|
|
622
|
+
].join("\n")
|
|
623
|
+
);
|
|
624
|
+
mapEntries.push(` ${JSON.stringify(canonical)}: ${name}Schema,`);
|
|
625
|
+
}
|
|
626
|
+
const primitiveImports = used.size > 0 ? `import {
|
|
627
|
+
${[...used].sort().join(",\n ")},
|
|
628
|
+
} from ${JSON.stringify(args.importFrom)};
|
|
629
|
+
` : "";
|
|
630
|
+
const source = `// Generated by inodra-sui v${SDK_VERSION} (codegen-events). DO NOT EDIT.
|
|
631
|
+
// Regenerate: inodra-sui codegen-events ${args.types.map((t) => JSON.stringify(t)).join(" ")}${args.out ? ` -o ${args.out}` : ""}
|
|
632
|
+
import { z } from "zod";
|
|
633
|
+
${primitiveImports}
|
|
634
|
+
${blocks.join("\n\n")}
|
|
635
|
+
|
|
636
|
+
/** Reflected schemas keyed by canonical Move event type. */
|
|
637
|
+
export const reflectedEventSchemas = {
|
|
638
|
+
${mapEntries.join("\n")}
|
|
639
|
+
} as const;
|
|
640
|
+
`;
|
|
641
|
+
if (args.out) {
|
|
642
|
+
writeFileSync(args.out, source);
|
|
643
|
+
console.error(
|
|
644
|
+
`inodra-sui: wrote ${args.out} (${args.types.length} event type(s))`
|
|
645
|
+
);
|
|
646
|
+
} else {
|
|
647
|
+
process.stdout.write(source);
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
var [command, ...rest] = process.argv.slice(2);
|
|
651
|
+
switch (command) {
|
|
652
|
+
case "codegen-events":
|
|
653
|
+
await codegenEvents(parseArgs(rest));
|
|
654
|
+
break;
|
|
655
|
+
case void 0:
|
|
656
|
+
case "help":
|
|
657
|
+
case "--help":
|
|
658
|
+
console.log(
|
|
659
|
+
"Usage: inodra-sui codegen-events <moveEventType...> [-o out.ts] [--network mainnet|testnet] [--url <graphql>] [--import-from <spec>]"
|
|
660
|
+
);
|
|
661
|
+
break;
|
|
662
|
+
default:
|
|
663
|
+
fail(`unknown command ${command} \u2014 try: inodra-sui help`);
|
|
664
|
+
}
|
|
665
|
+
//# sourceMappingURL=cli.js.map
|