@sm-lab/merkle 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +98 -0
- package/dist/cli.d.mts +1 -0
- package/dist/cli.mjs +796 -0
- package/dist/cli.mjs.map +1 -0
- package/dist/index.d.mts +178 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +2 -0
- package/dist/pipelines-Dxpjkr0j.mjs +238 -0
- package/dist/pipelines-Dxpjkr0j.mjs.map +1 -0
- package/package.json +56 -0
package/dist/cli.mjs
ADDED
|
@@ -0,0 +1,796 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { m as readJsonFile, n as makeRewards, p as readAddressFile, r as makeStrikes, t as makeAddresses } from "./pipelines-Dxpjkr0j.mjs";
|
|
3
|
+
import { readFileSync } from "node:fs";
|
|
4
|
+
import "dotenv/config";
|
|
5
|
+
import { Argument, Command } from "commander";
|
|
6
|
+
import { Readable } from "node:stream";
|
|
7
|
+
//#endregion
|
|
8
|
+
//#region ../../node_modules/.pnpm/@hono+node-server@2.0.6_hono@4.12.27/node_modules/@hono/node-server/dist/index.mjs
|
|
9
|
+
const GlobalRequest = global.Request;
|
|
10
|
+
var Request$1 = class extends GlobalRequest {
|
|
11
|
+
constructor(input, options) {
|
|
12
|
+
if (typeof input === "object" && getRequestCache in input) {
|
|
13
|
+
const hasReplacementBody = options !== void 0 && "body" in options && options.body != null;
|
|
14
|
+
if (input[bodyConsumedDirectlyKey] && !hasReplacementBody) throw new TypeError("Cannot construct a Request with a Request object that has already been used.");
|
|
15
|
+
input = input[getRequestCache]();
|
|
16
|
+
}
|
|
17
|
+
if (typeof (options?.body)?.getReader !== "undefined") options.duplex ??= "half";
|
|
18
|
+
super(input, options);
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
const newHeadersFromIncoming = (incoming) => {
|
|
22
|
+
const headerRecord = [];
|
|
23
|
+
const rawHeaders = incoming.rawHeaders;
|
|
24
|
+
for (let i = 0, len = rawHeaders.length; i < len; i += 2) {
|
|
25
|
+
const key = rawHeaders[i];
|
|
26
|
+
if (key.charCodeAt(0) !== 58) headerRecord.push([key, rawHeaders[i + 1]]);
|
|
27
|
+
}
|
|
28
|
+
return new Headers(headerRecord);
|
|
29
|
+
};
|
|
30
|
+
const wrapBodyStream = Symbol("wrapBodyStream");
|
|
31
|
+
const newRequestFromIncoming = (method, url, headers, incoming, abortController) => {
|
|
32
|
+
const init = {
|
|
33
|
+
method,
|
|
34
|
+
headers,
|
|
35
|
+
signal: abortController.signal
|
|
36
|
+
};
|
|
37
|
+
if (method === "TRACE") {
|
|
38
|
+
init.method = "GET";
|
|
39
|
+
const req = new Request$1(url, init);
|
|
40
|
+
Object.defineProperty(req, "method", { get() {
|
|
41
|
+
return "TRACE";
|
|
42
|
+
} });
|
|
43
|
+
return req;
|
|
44
|
+
}
|
|
45
|
+
if (!(method === "GET" || method === "HEAD")) if ("rawBody" in incoming && incoming.rawBody instanceof Buffer) init.body = new ReadableStream({ start(controller) {
|
|
46
|
+
controller.enqueue(incoming.rawBody);
|
|
47
|
+
controller.close();
|
|
48
|
+
} });
|
|
49
|
+
else if (incoming[wrapBodyStream]) {
|
|
50
|
+
let reader;
|
|
51
|
+
init.body = new ReadableStream({ async pull(controller) {
|
|
52
|
+
try {
|
|
53
|
+
reader ||= Readable.toWeb(incoming).getReader();
|
|
54
|
+
const { done, value } = await reader.read();
|
|
55
|
+
if (done) controller.close();
|
|
56
|
+
else controller.enqueue(value);
|
|
57
|
+
} catch (error) {
|
|
58
|
+
controller.error(error);
|
|
59
|
+
}
|
|
60
|
+
} });
|
|
61
|
+
} else init.body = Readable.toWeb(incoming);
|
|
62
|
+
return new Request$1(url, init);
|
|
63
|
+
};
|
|
64
|
+
const getRequestCache = Symbol("getRequestCache");
|
|
65
|
+
const requestCache = Symbol("requestCache");
|
|
66
|
+
const incomingKey = Symbol("incomingKey");
|
|
67
|
+
const urlKey = Symbol("urlKey");
|
|
68
|
+
const methodKey = Symbol("methodKey");
|
|
69
|
+
const headersKey = Symbol("headersKey");
|
|
70
|
+
const abortControllerKey = Symbol("abortControllerKey");
|
|
71
|
+
const getAbortController = Symbol("getAbortController");
|
|
72
|
+
const abortRequest = Symbol("abortRequest");
|
|
73
|
+
const bodyBufferKey = Symbol("bodyBuffer");
|
|
74
|
+
const bodyReadPromiseKey = Symbol("bodyReadPromise");
|
|
75
|
+
const bodyConsumedDirectlyKey = Symbol("bodyConsumedDirectly");
|
|
76
|
+
const bodyLockReaderKey = Symbol("bodyLockReader");
|
|
77
|
+
const abortReasonKey = Symbol("abortReason");
|
|
78
|
+
const newBodyUnusableError = () => {
|
|
79
|
+
return /* @__PURE__ */ new TypeError("Body is unusable");
|
|
80
|
+
};
|
|
81
|
+
const rejectBodyUnusable = () => {
|
|
82
|
+
return Promise.reject(newBodyUnusableError());
|
|
83
|
+
};
|
|
84
|
+
const textDecoder = new TextDecoder();
|
|
85
|
+
const consumeBodyDirectOnce = (request) => {
|
|
86
|
+
if (request[bodyConsumedDirectlyKey]) return rejectBodyUnusable();
|
|
87
|
+
request[bodyConsumedDirectlyKey] = true;
|
|
88
|
+
};
|
|
89
|
+
const toArrayBuffer = (buf) => {
|
|
90
|
+
return buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength);
|
|
91
|
+
};
|
|
92
|
+
const contentType = (request) => {
|
|
93
|
+
return (request[headersKey] ||= newHeadersFromIncoming(request[incomingKey])).get("content-type") || "";
|
|
94
|
+
};
|
|
95
|
+
const methodTokenRegExp = /^[!#$%&'*+\-.^_`|~0-9A-Za-z]+$/;
|
|
96
|
+
const validateDirectReadMethod = (method) => {
|
|
97
|
+
if (!methodTokenRegExp.test(method)) return /* @__PURE__ */ new TypeError(`'${method}' is not a valid HTTP method.`);
|
|
98
|
+
const normalized = method.toUpperCase();
|
|
99
|
+
if (normalized === "CONNECT" || normalized === "TRACK" || normalized === "TRACE" && method !== "TRACE") return /* @__PURE__ */ new TypeError(`'${method}' HTTP method is unsupported.`);
|
|
100
|
+
};
|
|
101
|
+
const readBodyWithFastPath = (request, method, fromBuffer) => {
|
|
102
|
+
if (request[bodyConsumedDirectlyKey]) return rejectBodyUnusable();
|
|
103
|
+
const methodName = request.method;
|
|
104
|
+
if (methodName === "GET" || methodName === "HEAD") return request[getRequestCache]()[method]();
|
|
105
|
+
const methodValidationError = validateDirectReadMethod(methodName);
|
|
106
|
+
if (methodValidationError) return Promise.reject(methodValidationError);
|
|
107
|
+
if (request[requestCache]) {
|
|
108
|
+
if (methodName !== "TRACE") return request[requestCache][method]();
|
|
109
|
+
}
|
|
110
|
+
const alreadyUsedError = consumeBodyDirectOnce(request);
|
|
111
|
+
if (alreadyUsedError) return alreadyUsedError;
|
|
112
|
+
const raw = readRawBodyIfAvailable(request);
|
|
113
|
+
if (raw) {
|
|
114
|
+
const result = Promise.resolve(fromBuffer(raw, request));
|
|
115
|
+
request[bodyBufferKey] = void 0;
|
|
116
|
+
return result;
|
|
117
|
+
}
|
|
118
|
+
return readBodyDirect(request).then((buf) => {
|
|
119
|
+
const result = fromBuffer(buf, request);
|
|
120
|
+
request[bodyBufferKey] = void 0;
|
|
121
|
+
return result;
|
|
122
|
+
});
|
|
123
|
+
};
|
|
124
|
+
const readRawBodyIfAvailable = (request) => {
|
|
125
|
+
const incoming = request[incomingKey];
|
|
126
|
+
if ("rawBody" in incoming && incoming.rawBody instanceof Buffer) return incoming.rawBody;
|
|
127
|
+
};
|
|
128
|
+
const readBodyDirect = (request) => {
|
|
129
|
+
if (request[bodyBufferKey]) return Promise.resolve(request[bodyBufferKey]);
|
|
130
|
+
if (request[bodyReadPromiseKey]) return request[bodyReadPromiseKey];
|
|
131
|
+
const incoming = request[incomingKey];
|
|
132
|
+
if (Readable.isDisturbed(incoming)) return rejectBodyUnusable();
|
|
133
|
+
const promise = new Promise((resolve, reject) => {
|
|
134
|
+
const chunks = [];
|
|
135
|
+
let settled = false;
|
|
136
|
+
const finish = (callback) => {
|
|
137
|
+
if (settled) return;
|
|
138
|
+
settled = true;
|
|
139
|
+
cleanup();
|
|
140
|
+
callback();
|
|
141
|
+
};
|
|
142
|
+
const onData = (chunk) => {
|
|
143
|
+
chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
|
|
144
|
+
};
|
|
145
|
+
const onEnd = () => {
|
|
146
|
+
finish(() => {
|
|
147
|
+
const buffer = chunks.length === 1 ? chunks[0] : Buffer.concat(chunks);
|
|
148
|
+
request[bodyBufferKey] = buffer;
|
|
149
|
+
resolve(buffer);
|
|
150
|
+
});
|
|
151
|
+
};
|
|
152
|
+
const onError = (error) => {
|
|
153
|
+
finish(() => {
|
|
154
|
+
reject(error);
|
|
155
|
+
});
|
|
156
|
+
};
|
|
157
|
+
const onClose = () => {
|
|
158
|
+
if (incoming.readableEnded) {
|
|
159
|
+
onEnd();
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
finish(() => {
|
|
163
|
+
if (incoming.errored) {
|
|
164
|
+
reject(incoming.errored);
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
const reason = request[abortReasonKey];
|
|
168
|
+
if (reason !== void 0) {
|
|
169
|
+
reject(reason instanceof Error ? reason : new Error(String(reason)));
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
reject(/* @__PURE__ */ new Error("Client connection prematurely closed."));
|
|
173
|
+
});
|
|
174
|
+
};
|
|
175
|
+
const cleanup = () => {
|
|
176
|
+
incoming.off("data", onData);
|
|
177
|
+
incoming.off("end", onEnd);
|
|
178
|
+
incoming.off("error", onError);
|
|
179
|
+
incoming.off("close", onClose);
|
|
180
|
+
request[bodyReadPromiseKey] = void 0;
|
|
181
|
+
};
|
|
182
|
+
incoming.on("data", onData);
|
|
183
|
+
incoming.on("end", onEnd);
|
|
184
|
+
incoming.on("error", onError);
|
|
185
|
+
incoming.on("close", onClose);
|
|
186
|
+
queueMicrotask(() => {
|
|
187
|
+
if (settled) return;
|
|
188
|
+
if (incoming.readableEnded) onEnd();
|
|
189
|
+
else if (incoming.errored) onError(incoming.errored);
|
|
190
|
+
else if (incoming.destroyed) onClose();
|
|
191
|
+
});
|
|
192
|
+
});
|
|
193
|
+
request[bodyReadPromiseKey] = promise;
|
|
194
|
+
return promise;
|
|
195
|
+
};
|
|
196
|
+
const requestPrototype = {
|
|
197
|
+
get method() {
|
|
198
|
+
return this[methodKey];
|
|
199
|
+
},
|
|
200
|
+
get url() {
|
|
201
|
+
return this[urlKey];
|
|
202
|
+
},
|
|
203
|
+
get headers() {
|
|
204
|
+
return this[headersKey] ||= newHeadersFromIncoming(this[incomingKey]);
|
|
205
|
+
},
|
|
206
|
+
[abortRequest](reason) {
|
|
207
|
+
if (this[abortReasonKey] === void 0) this[abortReasonKey] = reason;
|
|
208
|
+
const abortController = this[abortControllerKey];
|
|
209
|
+
if (abortController && !abortController.signal.aborted) abortController.abort(reason);
|
|
210
|
+
},
|
|
211
|
+
[getAbortController]() {
|
|
212
|
+
this[abortControllerKey] ||= new AbortController();
|
|
213
|
+
if (this[abortReasonKey] !== void 0 && !this[abortControllerKey].signal.aborted) this[abortControllerKey].abort(this[abortReasonKey]);
|
|
214
|
+
return this[abortControllerKey];
|
|
215
|
+
},
|
|
216
|
+
[getRequestCache]() {
|
|
217
|
+
const abortController = this[getAbortController]();
|
|
218
|
+
if (this[requestCache]) return this[requestCache];
|
|
219
|
+
const method = this.method;
|
|
220
|
+
if (this[bodyConsumedDirectlyKey] && !(method === "GET" || method === "HEAD")) {
|
|
221
|
+
this[bodyBufferKey] = void 0;
|
|
222
|
+
const init = {
|
|
223
|
+
method: method === "TRACE" ? "GET" : method,
|
|
224
|
+
headers: this.headers,
|
|
225
|
+
signal: abortController.signal
|
|
226
|
+
};
|
|
227
|
+
if (method !== "TRACE") {
|
|
228
|
+
init.body = new ReadableStream({ start(c) {
|
|
229
|
+
c.close();
|
|
230
|
+
} });
|
|
231
|
+
init.duplex = "half";
|
|
232
|
+
}
|
|
233
|
+
const req = new Request$1(this[urlKey], init);
|
|
234
|
+
if (method === "TRACE") Object.defineProperty(req, "method", { get() {
|
|
235
|
+
return "TRACE";
|
|
236
|
+
} });
|
|
237
|
+
return this[requestCache] = req;
|
|
238
|
+
}
|
|
239
|
+
return this[requestCache] = newRequestFromIncoming(this.method, this[urlKey], this.headers, this[incomingKey], abortController);
|
|
240
|
+
},
|
|
241
|
+
get body() {
|
|
242
|
+
if (!this[bodyConsumedDirectlyKey]) return this[getRequestCache]().body;
|
|
243
|
+
const request = this[getRequestCache]();
|
|
244
|
+
if (!this[bodyLockReaderKey] && request.body) this[bodyLockReaderKey] = request.body.getReader();
|
|
245
|
+
return request.body;
|
|
246
|
+
},
|
|
247
|
+
get bodyUsed() {
|
|
248
|
+
if (this[bodyConsumedDirectlyKey]) return true;
|
|
249
|
+
if (this[requestCache]) return this[requestCache].bodyUsed;
|
|
250
|
+
return false;
|
|
251
|
+
}
|
|
252
|
+
};
|
|
253
|
+
Object.defineProperty(requestPrototype, "signal", { get() {
|
|
254
|
+
return this[getAbortController]().signal;
|
|
255
|
+
} });
|
|
256
|
+
[
|
|
257
|
+
"cache",
|
|
258
|
+
"credentials",
|
|
259
|
+
"destination",
|
|
260
|
+
"integrity",
|
|
261
|
+
"mode",
|
|
262
|
+
"redirect",
|
|
263
|
+
"referrer",
|
|
264
|
+
"referrerPolicy",
|
|
265
|
+
"keepalive"
|
|
266
|
+
].forEach((k) => {
|
|
267
|
+
Object.defineProperty(requestPrototype, k, { get() {
|
|
268
|
+
return this[getRequestCache]()[k];
|
|
269
|
+
} });
|
|
270
|
+
});
|
|
271
|
+
["clone", "formData"].forEach((k) => {
|
|
272
|
+
Object.defineProperty(requestPrototype, k, { value: function() {
|
|
273
|
+
if (this[bodyConsumedDirectlyKey]) {
|
|
274
|
+
if (k === "clone") throw newBodyUnusableError();
|
|
275
|
+
return rejectBodyUnusable();
|
|
276
|
+
}
|
|
277
|
+
return this[getRequestCache]()[k]();
|
|
278
|
+
} });
|
|
279
|
+
});
|
|
280
|
+
Object.defineProperty(requestPrototype, "text", { value: function() {
|
|
281
|
+
return readBodyWithFastPath(this, "text", (buf) => textDecoder.decode(buf));
|
|
282
|
+
} });
|
|
283
|
+
Object.defineProperty(requestPrototype, "arrayBuffer", { value: function() {
|
|
284
|
+
return readBodyWithFastPath(this, "arrayBuffer", (buf) => toArrayBuffer(buf));
|
|
285
|
+
} });
|
|
286
|
+
Object.defineProperty(requestPrototype, "blob", { value: function() {
|
|
287
|
+
return readBodyWithFastPath(this, "blob", (buf, request) => {
|
|
288
|
+
const type = contentType(request);
|
|
289
|
+
return new Response(buf, type ? { headers: { "content-type": type } } : void 0).blob();
|
|
290
|
+
});
|
|
291
|
+
} });
|
|
292
|
+
Object.defineProperty(requestPrototype, "json", { value: function() {
|
|
293
|
+
if (this[bodyConsumedDirectlyKey]) return rejectBodyUnusable();
|
|
294
|
+
return this.text().then(JSON.parse);
|
|
295
|
+
} });
|
|
296
|
+
Object.defineProperty(requestPrototype, Symbol.for("nodejs.util.inspect.custom"), { value: function(depth, options, inspectFn) {
|
|
297
|
+
return `Request (lightweight) ${inspectFn({
|
|
298
|
+
method: this.method,
|
|
299
|
+
url: this.url,
|
|
300
|
+
headers: this.headers,
|
|
301
|
+
nativeRequest: this[requestCache]
|
|
302
|
+
}, {
|
|
303
|
+
...options,
|
|
304
|
+
depth: depth == null ? null : depth - 1
|
|
305
|
+
})}`;
|
|
306
|
+
} });
|
|
307
|
+
Object.setPrototypeOf(requestPrototype, Request$1.prototype);
|
|
308
|
+
const defaultContentType = "text/plain; charset=UTF-8";
|
|
309
|
+
const responseCache = Symbol("responseCache");
|
|
310
|
+
const getResponseCache = Symbol("getResponseCache");
|
|
311
|
+
const cacheKey = Symbol("cache");
|
|
312
|
+
const GlobalResponse = global.Response;
|
|
313
|
+
var Response$1 = class Response$1 {
|
|
314
|
+
#body;
|
|
315
|
+
#init;
|
|
316
|
+
[getResponseCache]() {
|
|
317
|
+
const cache = this[cacheKey];
|
|
318
|
+
const liveHeaders = cache && cache[2] instanceof Headers ? cache[2] : void 0;
|
|
319
|
+
delete this[cacheKey];
|
|
320
|
+
return this[responseCache] ||= new GlobalResponse(this.#body, liveHeaders ? {
|
|
321
|
+
status: this.#init?.status,
|
|
322
|
+
statusText: this.#init?.statusText,
|
|
323
|
+
headers: liveHeaders
|
|
324
|
+
} : this.#init);
|
|
325
|
+
}
|
|
326
|
+
constructor(body, init) {
|
|
327
|
+
let headers;
|
|
328
|
+
this.#body = body;
|
|
329
|
+
if (init instanceof Response$1) {
|
|
330
|
+
const cachedGlobalResponse = init[responseCache];
|
|
331
|
+
if (cachedGlobalResponse) {
|
|
332
|
+
this.#init = cachedGlobalResponse;
|
|
333
|
+
this[getResponseCache]();
|
|
334
|
+
return;
|
|
335
|
+
} else {
|
|
336
|
+
this.#init = init.#init;
|
|
337
|
+
headers = new Headers(init.headers);
|
|
338
|
+
}
|
|
339
|
+
} else this.#init = init;
|
|
340
|
+
if (body == null || typeof body === "string" || typeof body?.getReader !== "undefined" || body instanceof Blob || body instanceof Uint8Array) this[cacheKey] = [
|
|
341
|
+
init?.status || 200,
|
|
342
|
+
body ?? null,
|
|
343
|
+
headers || init?.headers
|
|
344
|
+
];
|
|
345
|
+
}
|
|
346
|
+
get headers() {
|
|
347
|
+
const cache = this[cacheKey];
|
|
348
|
+
if (cache) {
|
|
349
|
+
if (!(cache[2] instanceof Headers)) cache[2] = new Headers(cache[2] || (cache[1] === null ? void 0 : { "content-type": defaultContentType }));
|
|
350
|
+
return cache[2];
|
|
351
|
+
}
|
|
352
|
+
return this[getResponseCache]().headers;
|
|
353
|
+
}
|
|
354
|
+
get status() {
|
|
355
|
+
return this[cacheKey]?.[0] ?? this[getResponseCache]().status;
|
|
356
|
+
}
|
|
357
|
+
get ok() {
|
|
358
|
+
const status = this.status;
|
|
359
|
+
return status >= 200 && status < 300;
|
|
360
|
+
}
|
|
361
|
+
};
|
|
362
|
+
[
|
|
363
|
+
"body",
|
|
364
|
+
"bodyUsed",
|
|
365
|
+
"redirected",
|
|
366
|
+
"statusText",
|
|
367
|
+
"trailers",
|
|
368
|
+
"type",
|
|
369
|
+
"url"
|
|
370
|
+
].forEach((k) => {
|
|
371
|
+
Object.defineProperty(Response$1.prototype, k, { get() {
|
|
372
|
+
return this[getResponseCache]()[k];
|
|
373
|
+
} });
|
|
374
|
+
});
|
|
375
|
+
[
|
|
376
|
+
"arrayBuffer",
|
|
377
|
+
"blob",
|
|
378
|
+
"clone",
|
|
379
|
+
"formData",
|
|
380
|
+
"json",
|
|
381
|
+
"text"
|
|
382
|
+
].forEach((k) => {
|
|
383
|
+
Object.defineProperty(Response$1.prototype, k, { value: function() {
|
|
384
|
+
return this[getResponseCache]()[k]();
|
|
385
|
+
} });
|
|
386
|
+
});
|
|
387
|
+
Object.defineProperty(Response$1.prototype, Symbol.for("nodejs.util.inspect.custom"), { value: function(depth, options, inspectFn) {
|
|
388
|
+
return `Response (lightweight) ${inspectFn({
|
|
389
|
+
status: this.status,
|
|
390
|
+
headers: this.headers,
|
|
391
|
+
ok: this.ok,
|
|
392
|
+
nativeResponse: this[responseCache]
|
|
393
|
+
}, {
|
|
394
|
+
...options,
|
|
395
|
+
depth: depth == null ? null : depth - 1
|
|
396
|
+
})}`;
|
|
397
|
+
} });
|
|
398
|
+
Object.setPrototypeOf(Response$1, GlobalResponse);
|
|
399
|
+
Object.setPrototypeOf(Response$1.prototype, GlobalResponse.prototype);
|
|
400
|
+
const validRedirectUrl = /^https?:\/\/[!#-;=?-[\]_a-z~A-Z]+$/;
|
|
401
|
+
const parseRedirectUrl = (url) => {
|
|
402
|
+
if (url instanceof URL) return url.href;
|
|
403
|
+
if (validRedirectUrl.test(url)) return url;
|
|
404
|
+
return new URL(url).href;
|
|
405
|
+
};
|
|
406
|
+
const validRedirectStatuses = /* @__PURE__ */ new Set([
|
|
407
|
+
301,
|
|
408
|
+
302,
|
|
409
|
+
303,
|
|
410
|
+
307,
|
|
411
|
+
308
|
|
412
|
+
]);
|
|
413
|
+
Object.defineProperty(Response$1, "redirect", {
|
|
414
|
+
value: function redirect(url, status = 302) {
|
|
415
|
+
if (!validRedirectStatuses.has(status)) throw new RangeError("Invalid status code");
|
|
416
|
+
return new Response$1(null, {
|
|
417
|
+
status,
|
|
418
|
+
headers: { location: parseRedirectUrl(url) }
|
|
419
|
+
});
|
|
420
|
+
},
|
|
421
|
+
writable: true,
|
|
422
|
+
configurable: true
|
|
423
|
+
});
|
|
424
|
+
Object.defineProperty(Response$1, "json", {
|
|
425
|
+
value: function json(data, init) {
|
|
426
|
+
const body = JSON.stringify(data);
|
|
427
|
+
if (body === void 0) throw new TypeError("The data is not JSON serializable");
|
|
428
|
+
const initHeaders = init?.headers;
|
|
429
|
+
let headers;
|
|
430
|
+
if (initHeaders) {
|
|
431
|
+
headers = new Headers(initHeaders);
|
|
432
|
+
if (!headers.has("content-type")) headers.set("content-type", "application/json");
|
|
433
|
+
} else headers = { "content-type": "application/json" };
|
|
434
|
+
return new Response$1(body, {
|
|
435
|
+
status: init?.status ?? 200,
|
|
436
|
+
statusText: init?.statusText,
|
|
437
|
+
headers
|
|
438
|
+
});
|
|
439
|
+
},
|
|
440
|
+
writable: true,
|
|
441
|
+
configurable: true
|
|
442
|
+
});
|
|
443
|
+
globalThis.CloseEvent;
|
|
444
|
+
//#endregion
|
|
445
|
+
//#region ../../packages/core/src/admin.ts
|
|
446
|
+
/**
|
|
447
|
+
* Read the consuming package's version from its package.json at runtime.
|
|
448
|
+
*
|
|
449
|
+
* Pass `import.meta.url` from the CONSUMER module. core is bundled into each consumer, so
|
|
450
|
+
* after the build this code runs from the consumer's `dist/` and package.json sits one
|
|
451
|
+
* level up (`../package.json`). Never throws — returns 'unknown' on any failure.
|
|
452
|
+
*/
|
|
453
|
+
function readPackageVersion(metaUrl) {
|
|
454
|
+
try {
|
|
455
|
+
return JSON.parse(readFileSync(new URL("../package.json", metaUrl), "utf8")).version ?? "unknown";
|
|
456
|
+
} catch {
|
|
457
|
+
return "unknown";
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
//#endregion
|
|
461
|
+
//#region ../../packages/core/src/cli.ts
|
|
462
|
+
/** Climb to the root program so commands at any nesting depth can read root-level options (e.g. --url). */
|
|
463
|
+
function findRoot(cmd) {
|
|
464
|
+
let c = cmd;
|
|
465
|
+
while (c.parent) c = c.parent;
|
|
466
|
+
return c;
|
|
467
|
+
}
|
|
468
|
+
//#endregion
|
|
469
|
+
//#region ../../packages/core/src/completion.ts
|
|
470
|
+
const SHELLS = [
|
|
471
|
+
"bash",
|
|
472
|
+
"zsh",
|
|
473
|
+
"fish"
|
|
474
|
+
];
|
|
475
|
+
function firstLine(text) {
|
|
476
|
+
return (text.split("\n")[0] ?? "").trim();
|
|
477
|
+
}
|
|
478
|
+
function toNode(cmd, path) {
|
|
479
|
+
return {
|
|
480
|
+
name: cmd.name(),
|
|
481
|
+
aliases: [...cmd.aliases()],
|
|
482
|
+
description: firstLine(cmd.description()),
|
|
483
|
+
path,
|
|
484
|
+
options: cmd.options.filter((o) => !o.hidden).map((o) => ({
|
|
485
|
+
short: o.short,
|
|
486
|
+
long: o.long,
|
|
487
|
+
description: firstLine(o.description),
|
|
488
|
+
takesValue: o.required || o.optional,
|
|
489
|
+
choices: o.argChoices ? [...o.argChoices] : void 0
|
|
490
|
+
})),
|
|
491
|
+
args: cmd.registeredArguments.map((a) => ({
|
|
492
|
+
name: a.name(),
|
|
493
|
+
description: firstLine(a.description),
|
|
494
|
+
variadic: a.variadic,
|
|
495
|
+
choices: a.argChoices ? [...a.argChoices] : void 0
|
|
496
|
+
})),
|
|
497
|
+
children: cmd.commands.map((c) => toNode(c, [...path, c.name()]))
|
|
498
|
+
};
|
|
499
|
+
}
|
|
500
|
+
/** Flatten in registration order — the emitters iterate this, so output is deterministic. */
|
|
501
|
+
function walk(node) {
|
|
502
|
+
return [node, ...node.children.flatMap(walk)];
|
|
503
|
+
}
|
|
504
|
+
function namesOf(node) {
|
|
505
|
+
return [node.name, ...node.aliases];
|
|
506
|
+
}
|
|
507
|
+
function fishQuote(s) {
|
|
508
|
+
return `'${s.replace(/\\/g, "\\\\").replace(/'/g, "\\'")}'`;
|
|
509
|
+
}
|
|
510
|
+
function emitFish(bin, root) {
|
|
511
|
+
const lines = [
|
|
512
|
+
`# fish completion for ${bin}`,
|
|
513
|
+
`# Load with: ${bin} completion fish | source`,
|
|
514
|
+
`# Or install: ${bin} completion fish > ~/.config/fish/completions/${bin}.fish`
|
|
515
|
+
];
|
|
516
|
+
for (const node of walk(root)) {
|
|
517
|
+
const seen = node.path.map((p) => `__fish_seen_subcommand_from ${p}`);
|
|
518
|
+
const childNames = node.children.flatMap(namesOf);
|
|
519
|
+
const hereParts = [...seen];
|
|
520
|
+
if (childNames.length > 0) hereParts.push(`not __fish_seen_subcommand_from ${childNames.join(" ")}`);
|
|
521
|
+
const here = hereParts.length > 0 ? ` -n ${fishQuote(hereParts.join("; and "))}` : "";
|
|
522
|
+
for (const child of node.children) for (const name of namesOf(child)) lines.push(`complete -c ${bin}${here} -f -a ${name} -d ${fishQuote(child.description)}`);
|
|
523
|
+
for (const opt of node.options) {
|
|
524
|
+
let line = `complete -c ${bin}${here}`;
|
|
525
|
+
if (opt.short) line += ` -s ${opt.short.replace(/^-+/, "")}`;
|
|
526
|
+
if (opt.long) line += ` -l ${opt.long.replace(/^-+/, "")}`;
|
|
527
|
+
if (opt.takesValue) line += opt.choices ? ` -x -a ${fishQuote(opt.choices.join(" "))}` : " -r";
|
|
528
|
+
line += ` -d ${fishQuote(opt.description)}`;
|
|
529
|
+
lines.push(line);
|
|
530
|
+
}
|
|
531
|
+
const atArgs = seen.length > 0 ? ` -n ${fishQuote(seen.join("; and "))}` : "";
|
|
532
|
+
for (const arg of node.args) if (arg.choices) {
|
|
533
|
+
const desc = arg.description || arg.name;
|
|
534
|
+
lines.push(`complete -c ${bin}${atArgs} -f -a ${fishQuote(arg.choices.join(" "))} -d ${fishQuote(desc)}`);
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
return `${lines.join("\n")}\n`;
|
|
538
|
+
}
|
|
539
|
+
function sanitizeIdent(bin) {
|
|
540
|
+
return bin.replace(/[^A-Za-z0-9_]/g, "_");
|
|
541
|
+
}
|
|
542
|
+
/**
|
|
543
|
+
* Case arms that descend the known subcommand tree token by token, normalising
|
|
544
|
+
* aliases to the canonical path so a single lookup table serves both spellings.
|
|
545
|
+
*/
|
|
546
|
+
function descentCases(root, indent) {
|
|
547
|
+
return walk(root).filter((node) => node.path.length > 0).map((node) => {
|
|
548
|
+
const parent = node.path.slice(0, -1).join(" ");
|
|
549
|
+
return `${indent}${namesOf(node).map((name) => `"${parent ? `${parent} ${name}` : name}"`).join("|")}) path="${node.path.join(" ")}" ;;`;
|
|
550
|
+
});
|
|
551
|
+
}
|
|
552
|
+
function emitBash(bin, root) {
|
|
553
|
+
const fn = `_${sanitizeIdent(bin)}_completions`;
|
|
554
|
+
const optCases = walk(root).map((node) => {
|
|
555
|
+
const subs = node.children.flatMap(namesOf).join(" ");
|
|
556
|
+
const flags = node.options.flatMap((o) => [o.short, o.long]).filter((f) => f !== void 0).join(" ");
|
|
557
|
+
const args = node.args.flatMap((a) => a.choices ?? []).join(" ");
|
|
558
|
+
return ` "${node.path.join(" ")}") subs="${subs}"; flags="${flags}"; args="${args}" ;;`;
|
|
559
|
+
});
|
|
560
|
+
return [
|
|
561
|
+
`# bash completion for ${bin}`,
|
|
562
|
+
`# Load with: source <(${bin} completion bash)`,
|
|
563
|
+
`${fn}() {`,
|
|
564
|
+
" local cur path try w i subs flags args",
|
|
565
|
+
" cur=\"${COMP_WORDS[COMP_CWORD]}\"",
|
|
566
|
+
" path=\"\"",
|
|
567
|
+
" for ((i = 1; i < COMP_CWORD; i++)); do",
|
|
568
|
+
" w=\"${COMP_WORDS[i]}\"",
|
|
569
|
+
" [[ \"$w\" == -* ]] && continue",
|
|
570
|
+
" try=\"${path:+$path }$w\"",
|
|
571
|
+
" case \"$try\" in",
|
|
572
|
+
...descentCases(root, " "),
|
|
573
|
+
" *) ;;",
|
|
574
|
+
" esac",
|
|
575
|
+
" done",
|
|
576
|
+
" subs=\"\"; flags=\"\"; args=\"\"",
|
|
577
|
+
" case \"$path\" in",
|
|
578
|
+
...optCases,
|
|
579
|
+
" esac",
|
|
580
|
+
" if [[ \"$cur\" == -* ]]; then",
|
|
581
|
+
" COMPREPLY=($(compgen -W \"$flags\" -- \"$cur\"))",
|
|
582
|
+
" elif [[ -n \"$subs\" ]]; then",
|
|
583
|
+
" COMPREPLY=($(compgen -W \"$subs\" -- \"$cur\"))",
|
|
584
|
+
" elif [[ -n \"$args\" ]]; then",
|
|
585
|
+
" COMPREPLY=($(compgen -W \"$args\" -- \"$cur\"))",
|
|
586
|
+
" else",
|
|
587
|
+
" COMPREPLY=($(compgen -f -- \"$cur\"))",
|
|
588
|
+
" fi",
|
|
589
|
+
"}",
|
|
590
|
+
`complete -F ${fn} ${bin}`,
|
|
591
|
+
""
|
|
592
|
+
].join("\n");
|
|
593
|
+
}
|
|
594
|
+
function zshItem(name, description) {
|
|
595
|
+
return `'${`${name}:${description}`.replace(/'/g, `'\\''`)}'`;
|
|
596
|
+
}
|
|
597
|
+
function emitZsh(bin, root) {
|
|
598
|
+
const fn = `_${sanitizeIdent(bin)}`;
|
|
599
|
+
const optCases = walk(root).map((node) => {
|
|
600
|
+
const subs = node.children.flatMap((child) => namesOf(child).map((name) => zshItem(name, child.description))).join(" ");
|
|
601
|
+
const flags = node.options.flatMap((o) => [o.short, o.long].filter((f) => f !== void 0).map((f) => zshItem(f, o.description))).join(" ");
|
|
602
|
+
const args = node.args.flatMap((a) => (a.choices ?? []).map((c) => zshItem(c, a.description || a.name))).join(" ");
|
|
603
|
+
const body = [
|
|
604
|
+
subs ? `subs=(${subs})` : void 0,
|
|
605
|
+
flags ? `flags=(${flags})` : void 0,
|
|
606
|
+
args ? `argwords=(${args})` : void 0
|
|
607
|
+
].filter((p) => p !== void 0).join("; ");
|
|
608
|
+
return ` "${node.path.join(" ")}") ${body ? `${body} ` : ""};;`;
|
|
609
|
+
});
|
|
610
|
+
return [
|
|
611
|
+
`#compdef ${bin}`,
|
|
612
|
+
`# zsh completion for ${bin}`,
|
|
613
|
+
`# Install: ${bin} completion zsh > "\${fpath[1]}/_${bin}" (then restart zsh)`,
|
|
614
|
+
`${fn}() {`,
|
|
615
|
+
" local -a subs flags argwords",
|
|
616
|
+
" local path=\"\" try w",
|
|
617
|
+
" for w in \"${(@)words[2,CURRENT-1]}\"; do",
|
|
618
|
+
" [[ \"$w\" == -* ]] && continue",
|
|
619
|
+
" try=\"${path:+$path }$w\"",
|
|
620
|
+
" case \"$try\" in",
|
|
621
|
+
...descentCases(root, " "),
|
|
622
|
+
" *) ;;",
|
|
623
|
+
" esac",
|
|
624
|
+
" done",
|
|
625
|
+
" case \"$path\" in",
|
|
626
|
+
...optCases,
|
|
627
|
+
" esac",
|
|
628
|
+
" if [[ \"$PREFIX\" == -* ]]; then",
|
|
629
|
+
" (( ${#flags[@]} )) && _describe -t options 'option' flags",
|
|
630
|
+
" elif (( ${#subs[@]} )); then",
|
|
631
|
+
" _describe -t commands 'command' subs",
|
|
632
|
+
" elif (( ${#argwords[@]} )); then",
|
|
633
|
+
" _describe -t values 'value' argwords",
|
|
634
|
+
" else",
|
|
635
|
+
" _files",
|
|
636
|
+
" fi",
|
|
637
|
+
"}",
|
|
638
|
+
`if [[ "\${funcstack[1]}" == "${fn}" ]]; then`,
|
|
639
|
+
` ${fn} "$@"`,
|
|
640
|
+
"else",
|
|
641
|
+
` compdef ${fn} ${bin}`,
|
|
642
|
+
"fi",
|
|
643
|
+
""
|
|
644
|
+
].join("\n");
|
|
645
|
+
}
|
|
646
|
+
/**
|
|
647
|
+
* Build a fully static, self-contained shell-completion script for `root`'s command
|
|
648
|
+
* tree (subcommands at any depth, aliases, flags, option/argument choices). Pure:
|
|
649
|
+
* output depends only on the tree, iterated in registration order.
|
|
650
|
+
*/
|
|
651
|
+
function buildCompletionScript(root, shell) {
|
|
652
|
+
const bin = root.name();
|
|
653
|
+
const tree = toNode(root, []);
|
|
654
|
+
switch (shell) {
|
|
655
|
+
case "fish": return emitFish(bin, tree);
|
|
656
|
+
case "bash": return emitBash(bin, tree);
|
|
657
|
+
case "zsh": return emitZsh(bin, tree);
|
|
658
|
+
}
|
|
659
|
+
}
|
|
660
|
+
/**
|
|
661
|
+
* Build a `completion <shell>` subcommand that prints the static completion script
|
|
662
|
+
* for the ROOT program (resolved by walking `.parent`) to stdout.
|
|
663
|
+
*/
|
|
664
|
+
function createCompletionCommand() {
|
|
665
|
+
return new Command("completion").description("Print a static shell-completion script for bash, zsh or fish. Load it in your shell, e.g. fish: `sm-cl completion fish | source`").addArgument(new Argument("<shell>", "target shell").choices(SHELLS)).action((shell, _opts, cmd) => {
|
|
666
|
+
process.stdout.write(buildCompletionScript(findRoot(cmd), shell));
|
|
667
|
+
});
|
|
668
|
+
}
|
|
669
|
+
//#endregion
|
|
670
|
+
//#region src/cli/program.ts
|
|
671
|
+
/** Wrap an async action so thrown errors print cleanly and exit non-zero. */
|
|
672
|
+
function run(fn) {
|
|
673
|
+
fn().catch((err) => {
|
|
674
|
+
console.error("Error:", err instanceof Error ? err.message : String(err));
|
|
675
|
+
process.exit(1);
|
|
676
|
+
});
|
|
677
|
+
}
|
|
678
|
+
const bigintReplacer = (_k, v) => typeof v === "bigint" ? v.toString() : v;
|
|
679
|
+
function report(label, result) {
|
|
680
|
+
console.log(`${label} tree root: ${result.treeRoot}`);
|
|
681
|
+
console.log(`${label} tree CID: ${result.treeCid ?? "(upload skipped)"}`);
|
|
682
|
+
if (result.logCid) console.log(`${label} log CID: ${result.logCid}`);
|
|
683
|
+
if (result.configPath) console.log(`Wrote ${result.configPath}`);
|
|
684
|
+
}
|
|
685
|
+
function buildProgram(deps = {
|
|
686
|
+
makeAddresses,
|
|
687
|
+
makeStrikes,
|
|
688
|
+
makeRewards
|
|
689
|
+
}) {
|
|
690
|
+
const program = new Command().name("sm-merkle").description("Lido SM Merkle tree builder — build a tree, pin it to IPFS, print root + CID").version(readPackageVersion(import.meta.url)).helpCommand(false);
|
|
691
|
+
program.command("addresses", { isDefault: true }).description("Build the addresses (vetted gate) tree, pin it to IPFS, print root + CID").argument("[addresses...]", "whitelist addresses (inline, or use --input / --source)").option("--input <addr>", "repeatable: add one address to the list", (v, acc) => {
|
|
692
|
+
acc.push(v);
|
|
693
|
+
return acc;
|
|
694
|
+
}, []).option("--source <file>", "load address list from a JSON array or newline-delimited .txt").option("--no-upload", "build/print root only, skip IPFS pinning").option("-o, --out <path>", "also write { treeRoot, treeCid } JSON to this path").option("--json", "print result as JSON to stdout (machine-readable)").action((positionals, opts) => {
|
|
695
|
+
run(async () => {
|
|
696
|
+
const hasInline = positionals.length > 0 || opts.input.length > 0;
|
|
697
|
+
const hasFile = Boolean(opts.source);
|
|
698
|
+
if (hasInline && hasFile) throw new Error("Cannot combine inline addresses (positionals / --input) with --source <file>. Use one or the other.");
|
|
699
|
+
let addresses;
|
|
700
|
+
if (hasFile) addresses = readAddressFile(opts.source);
|
|
701
|
+
else addresses = [...positionals, ...opts.input];
|
|
702
|
+
if (addresses.length === 0) throw new Error("No addresses supplied. Provide positional addresses, --input <addr>, or --source <file>.");
|
|
703
|
+
const result = await deps.makeAddresses(addresses, {
|
|
704
|
+
noUpload: !opts.upload,
|
|
705
|
+
configPath: opts.out
|
|
706
|
+
});
|
|
707
|
+
if (opts.json) console.log(JSON.stringify(result, bigintReplacer, 2));
|
|
708
|
+
else report("Addresses", result);
|
|
709
|
+
});
|
|
710
|
+
});
|
|
711
|
+
program.command("strikes").description("Build the strikes tree, pin it to IPFS, print root + CID").argument("<strikes>", "path to strikes.json — JSON array [{ nodeOperatorId, pubkey, strikes: number[] }]").option("--source <file>", "alternative flag for the strikes file path (same as positional)").option("--no-upload", "build/print root only, skip IPFS pinning").option("-o, --out <path>", "also write { treeRoot, treeCid } JSON to this path").option("--json", "print result as JSON to stdout (machine-readable)").action((strikesArg, opts) => {
|
|
712
|
+
run(async () => {
|
|
713
|
+
const strikesPath = opts.source ?? strikesArg;
|
|
714
|
+
const result = await deps.makeStrikes(strikesPath, {
|
|
715
|
+
noUpload: !opts.upload,
|
|
716
|
+
configPath: opts.out
|
|
717
|
+
});
|
|
718
|
+
if (opts.json) console.log(JSON.stringify(result, bigintReplacer, 2));
|
|
719
|
+
else report("Strikes", result);
|
|
720
|
+
});
|
|
721
|
+
});
|
|
722
|
+
program.command("rewards").description("Build the rewards tree from [nodeOperatorId, cumulativeShares] pairs, pin it").requiredOption("--source <file>", "JSON array of [nodeOperatorId, cumulativeShares] pairs (number or numeric-string)").option("--no-upload", "build/print root only, skip IPFS pinning").option("-o, --out <path>", "also write { treeRoot, treeCid } JSON to this path").option("--json", "print result as JSON to stdout (machine-readable)").action((opts) => {
|
|
723
|
+
run(async () => {
|
|
724
|
+
const raw = readJsonFile(opts.source);
|
|
725
|
+
if (raw.length === 0) throw new Error("No leaves supplied. Provide a non-empty JSON array of [nodeOperatorId, cumulativeShares] pairs.");
|
|
726
|
+
const leaves = raw.map(([noId, shares], i) => {
|
|
727
|
+
const toBig = (v, field) => {
|
|
728
|
+
if (typeof v === "bigint") return v;
|
|
729
|
+
if (typeof v === "number" || typeof v === "string") return BigInt(v);
|
|
730
|
+
throw new Error(`rewards --source: entry [${i}].${field} must be a number or numeric string, got ${typeof v}`);
|
|
731
|
+
};
|
|
732
|
+
return [toBig(noId, "0"), toBig(shares, "1")];
|
|
733
|
+
});
|
|
734
|
+
const result = await deps.makeRewards(leaves, {
|
|
735
|
+
noUpload: !opts.upload,
|
|
736
|
+
configPath: opts.out
|
|
737
|
+
});
|
|
738
|
+
if (opts.json) console.log(JSON.stringify(result, bigintReplacer, 2));
|
|
739
|
+
else report("Rewards", result);
|
|
740
|
+
});
|
|
741
|
+
});
|
|
742
|
+
program.command("help").description("Print a self-contained usage cheat sheet").action(() => {
|
|
743
|
+
console.log(`sm-merkle — Lido SM Merkle tree builder
|
|
744
|
+
|
|
745
|
+
WHAT IT DOES
|
|
746
|
+
Build a Merkle tree from input, pin it to IPFS, and print the root + CID.
|
|
747
|
+
Pushing the root/CID on-chain is NOT this tool's job — that's @sm-lab/receipts.
|
|
748
|
+
|
|
749
|
+
COMMANDS
|
|
750
|
+
addresses [addresses...] build the addresses (vetted gate) tree (DEFAULT — bare args route here)
|
|
751
|
+
strikes <strikes> build the strikes tree, pin to IPFS, print root + CID
|
|
752
|
+
rewards --source <file> build the rewards tree from [noId, cumulativeShares] pairs
|
|
753
|
+
completion <shell> print a bash|zsh|fish completion script (sm-merkle completion fish | source)
|
|
754
|
+
help print this cheat sheet
|
|
755
|
+
|
|
756
|
+
FLAGS (all commands)
|
|
757
|
+
--no-upload build/print the root only, skip IPFS pinning
|
|
758
|
+
-o, --out <path> also write { treeRoot, treeCid } JSON to <path>
|
|
759
|
+
--json print result as a single JSON value to stdout (machine-readable)
|
|
760
|
+
|
|
761
|
+
FLAGS (addresses only)
|
|
762
|
+
--input <addr> repeatable: add one address (can mix with positionals)
|
|
763
|
+
--source <file> load from JSON array ["0x.."] or newline-delimited .txt
|
|
764
|
+
(mutually exclusive with inline positionals / --input)
|
|
765
|
+
|
|
766
|
+
ENV
|
|
767
|
+
IPFS_API_URL pinning endpoint; unset → local @sm-lab/ipfs (http://127.0.0.1:5001).
|
|
768
|
+
Pinata used only when PINATA_* creds are set (and IPFS_API_URL is unset).
|
|
769
|
+
PINATA_API_KEY/SECRET Pinata credentials (or PINATA_JWT). Ignored by the mock.
|
|
770
|
+
|
|
771
|
+
DATA FORMATS
|
|
772
|
+
addresses JSON array ["0x..", ...] or newline-delimited text (# comments ok)
|
|
773
|
+
strikes JSON array [{ nodeOperatorId, pubkey, strikes: number[] }]
|
|
774
|
+
rewards JSON array [[nodeOperatorId, cumulativeShares], ...] (numbers or numeric strings)
|
|
775
|
+
|
|
776
|
+
EXAMPLES
|
|
777
|
+
sm-merkle 0xABC 0xDEF # inline addresses → addresses (vetted gate) tree
|
|
778
|
+
sm-merkle addresses --source addrs.json --json
|
|
779
|
+
sm-merkle addresses --input 0xABC --input 0xDEF --no-upload
|
|
780
|
+
sm-merkle strikes strikes.json --no-upload --json
|
|
781
|
+
sm-merkle rewards --source rewards.json --json
|
|
782
|
+
sm-merkle addresses addrs.json -o config.json`);
|
|
783
|
+
});
|
|
784
|
+
program.addCommand(createCompletionCommand());
|
|
785
|
+
return program;
|
|
786
|
+
}
|
|
787
|
+
//#endregion
|
|
788
|
+
//#region src/cli/index.ts
|
|
789
|
+
buildProgram().parseAsync().catch((err) => {
|
|
790
|
+
console.error("Error:", err instanceof Error ? err.message : String(err));
|
|
791
|
+
process.exit(1);
|
|
792
|
+
});
|
|
793
|
+
//#endregion
|
|
794
|
+
export {};
|
|
795
|
+
|
|
796
|
+
//# sourceMappingURL=cli.mjs.map
|