@ic-reactor/cli 0.0.0-dev3 → 0.1.3
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/dist/index.js +191 -731
- package/package.json +14 -12
- package/schema.json +24 -2
- package/src/commands/add.ts +447 -0
- package/src/commands/fetch.ts +600 -0
- package/src/commands/index.ts +9 -0
- package/src/commands/init.ts +224 -0
- package/src/commands/list.ts +144 -0
- package/src/commands/sync.ts +259 -0
- package/src/generators/index.ts +8 -0
- package/src/generators/infiniteQuery.ts +34 -0
- package/src/generators/mutation.ts +29 -0
- package/src/generators/query.ts +32 -0
- package/src/generators/reactor.ts +41 -0
- package/src/index.ts +63 -0
- package/src/types.ts +26 -0
- package/src/utils/config.ts +114 -0
- package/src/utils/index.ts +6 -0
- package/src/utils/network.ts +139 -0
package/dist/index.js
CHANGED
|
@@ -227,652 +227,74 @@ export const clientManager = new ClientManager({
|
|
|
227
227
|
|
|
228
228
|
// src/commands/add.ts
|
|
229
229
|
import * as p2 from "@clack/prompts";
|
|
230
|
-
import fs5 from "fs";
|
|
231
|
-
import path4 from "path";
|
|
232
|
-
import pc2 from "picocolors";
|
|
233
|
-
|
|
234
|
-
// src/parsers/did.ts
|
|
235
230
|
import fs3 from "fs";
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
}
|
|
240
|
-
const content = fs3.readFileSync(didFilePath, "utf-8");
|
|
241
|
-
return extractMethods(content);
|
|
242
|
-
}
|
|
243
|
-
function extractMethods(didContent) {
|
|
244
|
-
const methods = [];
|
|
245
|
-
const cleanContent = didContent.replace(/\/\/.*$/gm, "").replace(/\/\*[\s\S]*?\*\//g, "");
|
|
246
|
-
const methodRegex = /([a-zA-Z_][a-zA-Z0-9_]*)\s*:\s*(?:func\s*)?\(([^)]*)\)\s*->\s*\(([^)]*)\)\s*(query|composite_query)?/g;
|
|
247
|
-
let match;
|
|
248
|
-
while ((match = methodRegex.exec(cleanContent)) !== null) {
|
|
249
|
-
const name = match[1];
|
|
250
|
-
const args = match[2].trim();
|
|
251
|
-
const returnType = match[3].trim();
|
|
252
|
-
const queryAnnotation = match[4];
|
|
253
|
-
const isQuery = queryAnnotation === "query" || queryAnnotation === "composite_query";
|
|
254
|
-
methods.push({
|
|
255
|
-
name,
|
|
256
|
-
type: isQuery ? "query" : "mutation",
|
|
257
|
-
hasArgs: args.length > 0 && args !== "",
|
|
258
|
-
argsDescription: args || void 0,
|
|
259
|
-
returnDescription: returnType || void 0
|
|
260
|
-
});
|
|
261
|
-
}
|
|
262
|
-
return methods;
|
|
263
|
-
}
|
|
264
|
-
function formatMethodForDisplay(method) {
|
|
265
|
-
const typeLabel = method.type === "query" ? "query" : "update";
|
|
266
|
-
const argsLabel = method.hasArgs ? "with args" : "no args";
|
|
267
|
-
return `${method.name} (${typeLabel}, ${argsLabel})`;
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
// src/utils/naming.ts
|
|
271
|
-
function toPascalCase(str) {
|
|
272
|
-
return str.split(/[-_]/).map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()).join("");
|
|
273
|
-
}
|
|
274
|
-
function toCamelCase(str) {
|
|
275
|
-
const pascal = toPascalCase(str);
|
|
276
|
-
return pascal.charAt(0).toLowerCase() + pascal.slice(1);
|
|
277
|
-
}
|
|
278
|
-
function getHookFileName(methodName, hookType) {
|
|
279
|
-
const camelMethod = toCamelCase(methodName);
|
|
280
|
-
const pascalType = toPascalCase(hookType);
|
|
281
|
-
return `${camelMethod}${pascalType}.ts`;
|
|
282
|
-
}
|
|
283
|
-
function getHookExportName(methodName, hookType) {
|
|
284
|
-
const camelMethod = toCamelCase(methodName);
|
|
285
|
-
const pascalType = toPascalCase(hookType);
|
|
286
|
-
return `${camelMethod}${pascalType}`;
|
|
287
|
-
}
|
|
288
|
-
function getReactHookName(methodName, hookType) {
|
|
289
|
-
const pascalMethod = toPascalCase(methodName);
|
|
290
|
-
const pascalType = toPascalCase(hookType);
|
|
291
|
-
return `use${pascalMethod}${pascalType}`;
|
|
292
|
-
}
|
|
293
|
-
function getReactorName(canisterName) {
|
|
294
|
-
return `${toCamelCase(canisterName)}Reactor`;
|
|
295
|
-
}
|
|
296
|
-
function getServiceTypeName(canisterName) {
|
|
297
|
-
return `${toPascalCase(canisterName)}Service`;
|
|
298
|
-
}
|
|
231
|
+
import path3 from "path";
|
|
232
|
+
import pc2 from "picocolors";
|
|
233
|
+
import { parseDIDFile, formatMethodForDisplay } from "@ic-reactor/codegen";
|
|
299
234
|
|
|
300
235
|
// src/generators/reactor.ts
|
|
236
|
+
import {
|
|
237
|
+
generateReactorFile as generateReactorFileFromCodegen
|
|
238
|
+
} from "@ic-reactor/codegen";
|
|
301
239
|
function generateReactorFile(options) {
|
|
302
|
-
const {
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
*/
|
|
318
|
-
|
|
319
|
-
import { ${reactorType}, createActorHooks, createAuthHooks } from "@ic-reactor/react"
|
|
320
|
-
import { clientManager } from "${clientManagerPath}"
|
|
321
|
-
import { idlFactory, type _SERVICE } from "${declarationsPath}"
|
|
322
|
-
|
|
323
|
-
// \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
|
|
324
|
-
// SERVICE TYPE
|
|
325
|
-
// \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
|
|
326
|
-
|
|
327
|
-
export type ${serviceName} = _SERVICE
|
|
328
|
-
|
|
329
|
-
// \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
|
|
330
|
-
// REACTOR INSTANCE
|
|
331
|
-
// \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
|
|
332
|
-
|
|
333
|
-
/**
|
|
334
|
-
* ${pascalName} Reactor with ${canisterConfig.useDisplayReactor !== false ? "Display" : "Candid"} type transformations.
|
|
335
|
-
* ${canisterConfig.useDisplayReactor !== false ? "Automatically converts bigint \u2192 string, Principal \u2192 string, etc." : "Uses raw Candid types."}
|
|
336
|
-
*/
|
|
337
|
-
export const ${reactorName} = new ${reactorType}<${serviceName}>({
|
|
338
|
-
clientManager,
|
|
339
|
-
idlFactory,
|
|
340
|
-
name: "${canisterName}",
|
|
341
|
-
})
|
|
342
|
-
|
|
343
|
-
// \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
|
|
344
|
-
// BASE HOOKS
|
|
345
|
-
// \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
|
|
346
|
-
|
|
347
|
-
/**
|
|
348
|
-
* Base actor hooks - use these directly or import method-specific hooks.
|
|
349
|
-
*/
|
|
350
|
-
export const {
|
|
351
|
-
useActorQuery,
|
|
352
|
-
useActorMutation,
|
|
353
|
-
useActorSuspenseQuery,
|
|
354
|
-
useActorInfiniteQuery,
|
|
355
|
-
useActorSuspenseInfiniteQuery,
|
|
356
|
-
useActorMethod,
|
|
357
|
-
} = createActorHooks(${reactorName})
|
|
358
|
-
|
|
359
|
-
/**
|
|
360
|
-
* Auth hooks for the client manager.
|
|
361
|
-
*/
|
|
362
|
-
export const { useAuth, useAgentState, useUserPrincipal } = createAuthHooks(clientManager)
|
|
363
|
-
|
|
364
|
-
// \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
|
|
365
|
-
// RE-EXPORTS
|
|
366
|
-
// \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
|
|
367
|
-
|
|
368
|
-
export { idlFactory }
|
|
369
|
-
`;
|
|
370
|
-
}
|
|
371
|
-
return `/**
|
|
372
|
-
* ${pascalName} Reactor
|
|
373
|
-
*
|
|
374
|
-
* Auto-generated by @ic-reactor/cli
|
|
375
|
-
* This file provides the shared reactor instance for the ${canisterName} canister.
|
|
376
|
-
*
|
|
377
|
-
* You can customize this file to add global configuration.
|
|
378
|
-
*/
|
|
379
|
-
|
|
380
|
-
import { ${reactorType}, createActorHooks, createAuthHooks } from "@ic-reactor/react"
|
|
381
|
-
import { clientManager } from "${clientManagerPath}"
|
|
382
|
-
|
|
383
|
-
// \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
|
|
384
|
-
// DECLARATIONS
|
|
385
|
-
// \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
|
|
386
|
-
|
|
387
|
-
// TODO: Generate proper types by running:
|
|
388
|
-
// npx @icp-sdk/bindgen --input <path-to-did> --output ./${canisterName}/declarations
|
|
389
|
-
|
|
390
|
-
// Then uncomment:
|
|
391
|
-
// import { idlFactory, type _SERVICE as ${serviceName} } from "${declarationsPath}"
|
|
392
|
-
|
|
393
|
-
// Fallback generic type - replace with generated types
|
|
394
|
-
type ${serviceName} = Record<string, (...args: unknown[]) => Promise<unknown>>
|
|
395
|
-
|
|
396
|
-
// You'll need to define idlFactory here or import from declarations
|
|
397
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
398
|
-
const idlFactory = ({ IDL }: { IDL: any }) => IDL.Service({})
|
|
399
|
-
|
|
400
|
-
// \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
|
|
401
|
-
// REACTOR INSTANCE
|
|
402
|
-
// \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
|
|
403
|
-
|
|
404
|
-
/**
|
|
405
|
-
* ${pascalName} Reactor with ${canisterConfig.useDisplayReactor !== false ? "Display" : "Candid"} type transformations.
|
|
406
|
-
* ${canisterConfig.useDisplayReactor !== false ? "Automatically converts bigint \u2192 string, Principal \u2192 string, etc." : "Uses raw Candid types."}
|
|
407
|
-
*/
|
|
408
|
-
export const ${reactorName} = new ${reactorType}<${serviceName}>({
|
|
409
|
-
clientManager,
|
|
410
|
-
idlFactory,
|
|
411
|
-
name: "${canisterName}",
|
|
412
|
-
})
|
|
413
|
-
|
|
414
|
-
// \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
|
|
415
|
-
// BASE HOOKS
|
|
416
|
-
// \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
|
|
417
|
-
|
|
418
|
-
/**
|
|
419
|
-
* Base actor hooks - use these directly or import method-specific hooks.
|
|
420
|
-
*/
|
|
421
|
-
export const {
|
|
422
|
-
useActorQuery,
|
|
423
|
-
useActorMutation,
|
|
424
|
-
useActorSuspenseQuery,
|
|
425
|
-
useActorInfiniteQuery,
|
|
426
|
-
useActorSuspenseInfiniteQuery,
|
|
427
|
-
useActorMethod,
|
|
428
|
-
} = createActorHooks(${reactorName})
|
|
429
|
-
|
|
430
|
-
/**
|
|
431
|
-
* Auth hooks for the client manager.
|
|
432
|
-
*/
|
|
433
|
-
export const { useAuth, useAgentState, useUserPrincipal } = createAuthHooks(clientManager)
|
|
434
|
-
|
|
435
|
-
// \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
|
|
436
|
-
// RE-EXPORTS
|
|
437
|
-
// \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
|
|
438
|
-
|
|
439
|
-
export { idlFactory }
|
|
440
|
-
export type { ${serviceName} }
|
|
441
|
-
`;
|
|
240
|
+
const {
|
|
241
|
+
canisterName,
|
|
242
|
+
canisterConfig,
|
|
243
|
+
config,
|
|
244
|
+
hasDeclarations = true
|
|
245
|
+
} = options;
|
|
246
|
+
return generateReactorFileFromCodegen({
|
|
247
|
+
canisterName,
|
|
248
|
+
canisterConfig,
|
|
249
|
+
hasDeclarations,
|
|
250
|
+
globalClientManagerPath: config.clientManagerPath,
|
|
251
|
+
// CLI doesn't currently expose advanced mode per-canister, but we default to false (simple mode)
|
|
252
|
+
// If we want to support it, we'd add 'advanced' to CanisterConfig or ReactorGeneratorOptions
|
|
253
|
+
advanced: false
|
|
254
|
+
});
|
|
442
255
|
}
|
|
443
256
|
|
|
444
257
|
// src/generators/query.ts
|
|
258
|
+
import {
|
|
259
|
+
generateQueryHook as generateQueryHookFromCodegen
|
|
260
|
+
} from "@ic-reactor/codegen";
|
|
445
261
|
function generateQueryHook(options) {
|
|
446
|
-
const { canisterName, method } = options;
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
if (method.hasArgs) {
|
|
453
|
-
return `/**
|
|
454
|
-
* Query Hook: ${method.name}
|
|
455
|
-
*
|
|
456
|
-
* Auto-generated by @ic-reactor/cli
|
|
457
|
-
* This hook wraps the ${method.name} query method.
|
|
458
|
-
*
|
|
459
|
-
* @example
|
|
460
|
-
* // With the factory (for dynamic args)
|
|
461
|
-
* const query = ${hookExportName}([arg1, arg2])
|
|
462
|
-
* const { data } = query.useQuery()
|
|
463
|
-
*
|
|
464
|
-
* // Or use the hook directly
|
|
465
|
-
* const { data } = ${reactHookName}([arg1, arg2])
|
|
466
|
-
*/
|
|
467
|
-
|
|
468
|
-
import { createQueryFactory } from "@ic-reactor/react"
|
|
469
|
-
import { ${reactorName}, type ${serviceName} } from "../reactor"
|
|
470
|
-
|
|
471
|
-
// \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
|
|
472
|
-
// QUERY FACTORY
|
|
473
|
-
// \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
|
|
474
|
-
|
|
475
|
-
/**
|
|
476
|
-
* Query factory for ${method.name}
|
|
477
|
-
*
|
|
478
|
-
* Creates a query instance with the provided arguments.
|
|
479
|
-
* Each unique set of args gets its own cached query.
|
|
480
|
-
*/
|
|
481
|
-
export const ${hookExportName} = createQueryFactory(${reactorName}, {
|
|
482
|
-
functionName: "${method.name}",
|
|
483
|
-
// Customize your query options:
|
|
484
|
-
// staleTime: 5 * 60 * 1000,
|
|
485
|
-
// select: (data) => data,
|
|
486
|
-
})
|
|
487
|
-
|
|
488
|
-
// \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
|
|
489
|
-
// CONVENIENCE HOOK
|
|
490
|
-
// \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
|
|
491
|
-
|
|
492
|
-
/**
|
|
493
|
-
* React hook for ${method.name}
|
|
494
|
-
*
|
|
495
|
-
* @param args - Arguments to pass to the canister method
|
|
496
|
-
* @param options - Additional React Query options
|
|
497
|
-
*/
|
|
498
|
-
export function ${reactHookName}(
|
|
499
|
-
args: Parameters<${serviceName}["${method.name}"]>,
|
|
500
|
-
options?: Parameters<ReturnType<typeof ${hookExportName}>["useQuery"]>[0]
|
|
501
|
-
) {
|
|
502
|
-
return ${hookExportName}(args).useQuery(options)
|
|
503
|
-
}
|
|
504
|
-
|
|
505
|
-
// \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
|
|
506
|
-
// UTILITY FUNCTIONS
|
|
507
|
-
// \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
|
|
508
|
-
|
|
509
|
-
/**
|
|
510
|
-
* Fetch ${method.name} directly (for loaders, server components, etc.)
|
|
511
|
-
*/
|
|
512
|
-
export function fetch${pascalMethod}(args: Parameters<${serviceName}["${method.name}"]>) {
|
|
513
|
-
return ${hookExportName}(args).fetch()
|
|
514
|
-
}
|
|
515
|
-
|
|
516
|
-
/**
|
|
517
|
-
* Invalidate ${method.name} query cache
|
|
518
|
-
*/
|
|
519
|
-
export function invalidate${pascalMethod}(args: Parameters<${serviceName}["${method.name}"]>) {
|
|
520
|
-
return ${hookExportName}(args).invalidate()
|
|
521
|
-
}
|
|
522
|
-
|
|
523
|
-
/**
|
|
524
|
-
* Get ${method.name} query key (for cache manipulation)
|
|
525
|
-
*/
|
|
526
|
-
export function get${pascalMethod}QueryKey(args: Parameters<${serviceName}["${method.name}"]>) {
|
|
527
|
-
return ${hookExportName}(args).getQueryKey()
|
|
528
|
-
}
|
|
529
|
-
`;
|
|
530
|
-
} else {
|
|
531
|
-
return `/**
|
|
532
|
-
* Query Hook: ${method.name}
|
|
533
|
-
*
|
|
534
|
-
* Auto-generated by @ic-reactor/cli
|
|
535
|
-
* This hook wraps the ${method.name} query method.
|
|
536
|
-
*
|
|
537
|
-
* @example
|
|
538
|
-
* // Use the hook
|
|
539
|
-
* const { data, isLoading } = ${reactHookName}()
|
|
540
|
-
*
|
|
541
|
-
* // Or access the query object directly
|
|
542
|
-
* const data = await ${hookExportName}.fetch()
|
|
543
|
-
* ${hookExportName}.invalidate()
|
|
544
|
-
*/
|
|
545
|
-
|
|
546
|
-
import { createQuery } from "@ic-reactor/react"
|
|
547
|
-
import { ${reactorName} } from "../reactor"
|
|
548
|
-
|
|
549
|
-
// \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
|
|
550
|
-
// QUERY INSTANCE
|
|
551
|
-
// \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
|
|
552
|
-
|
|
553
|
-
/**
|
|
554
|
-
* Query for ${method.name}
|
|
555
|
-
*
|
|
556
|
-
* Provides:
|
|
557
|
-
* - .useQuery() - React hook
|
|
558
|
-
* - .fetch() - Direct fetch (for loaders)
|
|
559
|
-
* - .invalidate() - Invalidate cache
|
|
560
|
-
* - .getQueryKey() - Get query key
|
|
561
|
-
* - .getCacheData() - Read from cache
|
|
562
|
-
*/
|
|
563
|
-
export const ${hookExportName} = createQuery(${reactorName}, {
|
|
564
|
-
functionName: "${method.name}",
|
|
565
|
-
// Customize your query options:
|
|
566
|
-
// staleTime: 5 * 60 * 1000,
|
|
567
|
-
// select: (data) => data,
|
|
568
|
-
})
|
|
569
|
-
|
|
570
|
-
// \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
|
|
571
|
-
// CONVENIENCE EXPORTS
|
|
572
|
-
// \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
|
|
573
|
-
|
|
574
|
-
/**
|
|
575
|
-
* React hook for ${method.name}
|
|
576
|
-
*/
|
|
577
|
-
export const ${reactHookName} = ${hookExportName}.useQuery
|
|
578
|
-
|
|
579
|
-
/**
|
|
580
|
-
* Fetch ${method.name} directly (for loaders, server components, etc.)
|
|
581
|
-
*/
|
|
582
|
-
export const fetch${pascalMethod} = ${hookExportName}.fetch
|
|
583
|
-
|
|
584
|
-
/**
|
|
585
|
-
* Invalidate ${method.name} query cache
|
|
586
|
-
*/
|
|
587
|
-
export const invalidate${pascalMethod} = ${hookExportName}.invalidate
|
|
588
|
-
|
|
589
|
-
/**
|
|
590
|
-
* Get ${method.name} query key (for cache manipulation)
|
|
591
|
-
*/
|
|
592
|
-
export const get${pascalMethod}QueryKey = ${hookExportName}.getQueryKey
|
|
593
|
-
|
|
594
|
-
/**
|
|
595
|
-
* Get cached data for ${method.name}
|
|
596
|
-
*/
|
|
597
|
-
export const get${pascalMethod}CacheData = ${hookExportName}.getCacheData
|
|
598
|
-
`;
|
|
599
|
-
}
|
|
262
|
+
const { canisterName, method, type } = options;
|
|
263
|
+
return generateQueryHookFromCodegen({
|
|
264
|
+
canisterName,
|
|
265
|
+
method,
|
|
266
|
+
type
|
|
267
|
+
});
|
|
600
268
|
}
|
|
601
269
|
|
|
602
270
|
// src/generators/mutation.ts
|
|
271
|
+
import {
|
|
272
|
+
generateMutationHook as generateMutationHookFromCodegen
|
|
273
|
+
} from "@ic-reactor/codegen";
|
|
603
274
|
function generateMutationHook(options) {
|
|
604
275
|
const { canisterName, method } = options;
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
const reactHookName = getReactHookName(method.name, "mutation");
|
|
610
|
-
return `/**
|
|
611
|
-
* Mutation Hook: ${method.name}
|
|
612
|
-
*
|
|
613
|
-
* Auto-generated by @ic-reactor/cli
|
|
614
|
-
* This hook wraps the ${method.name} update method.
|
|
615
|
-
*
|
|
616
|
-
* @example
|
|
617
|
-
* // Use the hook in a component
|
|
618
|
-
* const { mutate, isPending } = ${reactHookName}()
|
|
619
|
-
*
|
|
620
|
-
* // Call the mutation
|
|
621
|
-
* mutate(${method.hasArgs ? "[arg1, arg2]" : "[]"})
|
|
622
|
-
*
|
|
623
|
-
* // Or execute directly
|
|
624
|
-
* const result = await execute${pascalMethod}(${method.hasArgs ? "[arg1, arg2]" : "[]"})
|
|
625
|
-
*/
|
|
626
|
-
|
|
627
|
-
import { createMutation } from "@ic-reactor/react"
|
|
628
|
-
import { ${reactorName}, type ${serviceName} } from "../reactor"
|
|
629
|
-
|
|
630
|
-
// \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
|
|
631
|
-
// MUTATION INSTANCE
|
|
632
|
-
// \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
|
|
633
|
-
|
|
634
|
-
/**
|
|
635
|
-
* Mutation for ${method.name}
|
|
636
|
-
*
|
|
637
|
-
* Provides:
|
|
638
|
-
* - .useMutation() - React hook
|
|
639
|
-
* - .execute() - Direct execution
|
|
640
|
-
*/
|
|
641
|
-
export const ${hookExportName} = createMutation(${reactorName}, {
|
|
642
|
-
functionName: "${method.name}",
|
|
643
|
-
// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
644
|
-
// INVALIDATION
|
|
645
|
-
// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
646
|
-
// Uncomment and import query keys to auto-invalidate on success:
|
|
647
|
-
// invalidateQueries: [
|
|
648
|
-
// someQuery.getQueryKey(),
|
|
649
|
-
// ],
|
|
650
|
-
|
|
651
|
-
// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
652
|
-
// SUCCESS HANDLER
|
|
653
|
-
// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
654
|
-
// onSuccess: (data, variables, context) => {
|
|
655
|
-
// console.log("${method.name} succeeded:", data)
|
|
656
|
-
// },
|
|
657
|
-
|
|
658
|
-
// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
659
|
-
// ERROR HANDLERS
|
|
660
|
-
// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
661
|
-
// Handle canister-level errors (from Result { Err })
|
|
662
|
-
// onCanisterError: (error, variables) => {
|
|
663
|
-
// console.error("Canister error:", error)
|
|
664
|
-
// },
|
|
665
|
-
|
|
666
|
-
// Handle all errors (network, canister, etc.)
|
|
667
|
-
// onError: (error, variables, context) => {
|
|
668
|
-
// console.error("Error:", error)
|
|
669
|
-
// },
|
|
670
|
-
})
|
|
671
|
-
|
|
672
|
-
// \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
|
|
673
|
-
// CONVENIENCE EXPORTS
|
|
674
|
-
// \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
|
|
675
|
-
|
|
676
|
-
/**
|
|
677
|
-
* React hook for ${method.name}
|
|
678
|
-
*
|
|
679
|
-
* @param options - Mutation options (onSuccess, onError, etc.)
|
|
680
|
-
*/
|
|
681
|
-
export const ${reactHookName} = ${hookExportName}.useMutation
|
|
682
|
-
|
|
683
|
-
/**
|
|
684
|
-
* Execute ${method.name} directly (outside of React)
|
|
685
|
-
*
|
|
686
|
-
* @param args - Arguments to pass to the canister method
|
|
687
|
-
*/
|
|
688
|
-
export const execute${pascalMethod} = ${hookExportName}.execute
|
|
689
|
-
`;
|
|
276
|
+
return generateMutationHookFromCodegen({
|
|
277
|
+
canisterName,
|
|
278
|
+
method
|
|
279
|
+
});
|
|
690
280
|
}
|
|
691
281
|
|
|
692
282
|
// src/generators/infiniteQuery.ts
|
|
283
|
+
import {
|
|
284
|
+
generateInfiniteQueryHook as generateInfiniteQueryHookFromCodegen
|
|
285
|
+
} from "@ic-reactor/codegen";
|
|
693
286
|
function generateInfiniteQueryHook(options) {
|
|
694
|
-
const { canisterName, method } = options;
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
* Infinite Query Hook: ${method.name}
|
|
701
|
-
*
|
|
702
|
-
* Auto-generated by @ic-reactor/cli
|
|
703
|
-
* This hook wraps the ${method.name} method for infinite/paginated queries.
|
|
704
|
-
*
|
|
705
|
-
* \u26A0\uFE0F CUSTOMIZATION REQUIRED:
|
|
706
|
-
* You need to configure getArgs and getNextPageParam based on your API.
|
|
707
|
-
*
|
|
708
|
-
* @example
|
|
709
|
-
* const {
|
|
710
|
-
* data,
|
|
711
|
-
* fetchNextPage,
|
|
712
|
-
* hasNextPage,
|
|
713
|
-
* isFetching,
|
|
714
|
-
* } = ${camelMethod}InfiniteQuery.useInfiniteQuery()
|
|
715
|
-
*
|
|
716
|
-
* // Flatten all pages
|
|
717
|
-
* const allItems = data?.pages.flatMap(page => page.items) ?? []
|
|
718
|
-
*/
|
|
719
|
-
|
|
720
|
-
import { createInfiniteQuery } from "@ic-reactor/react"
|
|
721
|
-
import { ${reactorName}, type ${serviceName} } from "../reactor"
|
|
722
|
-
|
|
723
|
-
// \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
|
|
724
|
-
// CURSOR TYPE
|
|
725
|
-
// \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
|
|
726
|
-
|
|
727
|
-
/**
|
|
728
|
-
* Define your pagination cursor type here.
|
|
729
|
-
* Common patterns:
|
|
730
|
-
* - number (offset-based)
|
|
731
|
-
* - string (cursor-based)
|
|
732
|
-
* - { offset: number; limit: number }
|
|
733
|
-
*/
|
|
734
|
-
type PageCursor = number
|
|
735
|
-
|
|
736
|
-
// \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
|
|
737
|
-
// INFINITE QUERY INSTANCE
|
|
738
|
-
// \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
|
|
739
|
-
|
|
740
|
-
/**
|
|
741
|
-
* Infinite query for ${method.name}
|
|
742
|
-
*
|
|
743
|
-
* Provides:
|
|
744
|
-
* - .useInfiniteQuery() - React hook with pagination
|
|
745
|
-
* - .fetch() - Fetch first page
|
|
746
|
-
* - .invalidate() - Invalidate all pages
|
|
747
|
-
* - .getQueryKey() - Get query key
|
|
748
|
-
* - .getCacheData() - Read from cache
|
|
749
|
-
*/
|
|
750
|
-
export const ${camelMethod}InfiniteQuery = createInfiniteQuery(${reactorName}, {
|
|
751
|
-
functionName: "${method.name}",
|
|
752
|
-
|
|
753
|
-
// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
754
|
-
// PAGINATION CONFIG (CUSTOMIZE THESE)
|
|
755
|
-
// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
756
|
-
|
|
757
|
-
/**
|
|
758
|
-
* Initial page parameter (e.g., 0 for offset, null for cursor)
|
|
759
|
-
*/
|
|
760
|
-
initialPageParam: 0 as PageCursor,
|
|
761
|
-
|
|
762
|
-
/**
|
|
763
|
-
* Convert page param to method arguments.
|
|
764
|
-
* Customize this based on your canister API.
|
|
765
|
-
*/
|
|
766
|
-
getArgs: (pageParam: PageCursor) => {
|
|
767
|
-
// Example: offset-based pagination
|
|
768
|
-
return [{ offset: pageParam, limit: 10 }] as Parameters<${serviceName}["${method.name}"]>
|
|
769
|
-
|
|
770
|
-
// Example: cursor-based pagination
|
|
771
|
-
// return [{ cursor: pageParam, limit: 10 }] as Parameters<${serviceName}["${method.name}"]>
|
|
772
|
-
},
|
|
773
|
-
|
|
774
|
-
/**
|
|
775
|
-
* Extract next page param from the last page.
|
|
776
|
-
* Return undefined/null when there are no more pages.
|
|
777
|
-
*/
|
|
778
|
-
getNextPageParam: (lastPage, allPages, lastPageParam) => {
|
|
779
|
-
// Example: offset-based - return next offset or undefined if no more
|
|
780
|
-
// const items = lastPage.items ?? []
|
|
781
|
-
// if (items.length < 10) return undefined
|
|
782
|
-
// return lastPageParam + 10
|
|
783
|
-
|
|
784
|
-
// Example: cursor-based
|
|
785
|
-
// return lastPage.nextCursor ?? undefined
|
|
786
|
-
|
|
787
|
-
// Placeholder - customize for your API
|
|
788
|
-
return undefined
|
|
789
|
-
},
|
|
790
|
-
|
|
791
|
-
// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
792
|
-
// OPTIONAL CONFIG
|
|
793
|
-
// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
794
|
-
|
|
795
|
-
// Bi-directional scrolling (optional)
|
|
796
|
-
// getPreviousPageParam: (firstPage, allPages, firstPageParam) => {
|
|
797
|
-
// return firstPageParam > 0 ? firstPageParam - 10 : undefined
|
|
798
|
-
// },
|
|
799
|
-
|
|
800
|
-
// Max pages to keep in cache (for memory management)
|
|
801
|
-
// maxPages: 10,
|
|
802
|
-
|
|
803
|
-
// How long data stays fresh
|
|
804
|
-
// staleTime: 5 * 60 * 1000,
|
|
805
|
-
|
|
806
|
-
// Transform the data
|
|
807
|
-
// select: (data) => ({
|
|
808
|
-
// pages: data.pages,
|
|
809
|
-
// pageParams: data.pageParams,
|
|
810
|
-
// items: data.pages.flatMap(page => page.items),
|
|
811
|
-
// }),
|
|
812
|
-
})
|
|
813
|
-
|
|
814
|
-
// \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
|
|
815
|
-
// CONVENIENCE EXPORTS
|
|
816
|
-
// \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
|
|
817
|
-
|
|
818
|
-
/**
|
|
819
|
-
* React hook for paginated ${method.name}
|
|
820
|
-
*/
|
|
821
|
-
export const use${pascalMethod}InfiniteQuery = ${camelMethod}InfiniteQuery.useInfiniteQuery
|
|
822
|
-
|
|
823
|
-
/**
|
|
824
|
-
* Fetch first page of ${method.name}
|
|
825
|
-
*/
|
|
826
|
-
export const fetch${pascalMethod}FirstPage = ${camelMethod}InfiniteQuery.fetch
|
|
827
|
-
|
|
828
|
-
/**
|
|
829
|
-
* Invalidate all cached pages
|
|
830
|
-
*/
|
|
831
|
-
export const invalidate${pascalMethod}Pages = ${camelMethod}InfiniteQuery.invalidate
|
|
832
|
-
`;
|
|
833
|
-
}
|
|
834
|
-
|
|
835
|
-
// src/utils/bindgen.ts
|
|
836
|
-
import { generate } from "@icp-sdk/bindgen/core";
|
|
837
|
-
import path3 from "path";
|
|
838
|
-
import fs4 from "fs";
|
|
839
|
-
async function generateDeclarations(options) {
|
|
840
|
-
const { didFile, outDir } = options;
|
|
841
|
-
if (!fs4.existsSync(didFile)) {
|
|
842
|
-
return {
|
|
843
|
-
success: false,
|
|
844
|
-
declarationsDir: "",
|
|
845
|
-
error: `DID file not found: ${didFile}`
|
|
846
|
-
};
|
|
847
|
-
}
|
|
848
|
-
const declarationsDir = path3.join(outDir, "declarations");
|
|
849
|
-
try {
|
|
850
|
-
await generate({
|
|
851
|
-
didFile,
|
|
852
|
-
outDir: declarationsDir,
|
|
853
|
-
output: {
|
|
854
|
-
actor: {
|
|
855
|
-
disabled: true
|
|
856
|
-
// We don't need actor creation, we use Reactor
|
|
857
|
-
},
|
|
858
|
-
force: true
|
|
859
|
-
// Overwrite existing files
|
|
860
|
-
}
|
|
861
|
-
});
|
|
862
|
-
return {
|
|
863
|
-
success: true,
|
|
864
|
-
declarationsDir
|
|
865
|
-
};
|
|
866
|
-
} catch (error) {
|
|
867
|
-
return {
|
|
868
|
-
success: false,
|
|
869
|
-
declarationsDir,
|
|
870
|
-
error: error instanceof Error ? error.message : String(error)
|
|
871
|
-
};
|
|
872
|
-
}
|
|
287
|
+
const { canisterName, method, type } = options;
|
|
288
|
+
return generateInfiniteQueryHookFromCodegen({
|
|
289
|
+
canisterName,
|
|
290
|
+
method,
|
|
291
|
+
type
|
|
292
|
+
});
|
|
873
293
|
}
|
|
874
294
|
|
|
875
295
|
// src/commands/add.ts
|
|
296
|
+
import { getHookFileName } from "@ic-reactor/codegen";
|
|
297
|
+
import { generateDeclarations } from "@ic-reactor/codegen";
|
|
876
298
|
async function addCommand(options) {
|
|
877
299
|
console.log();
|
|
878
300
|
p2.intro(pc2.cyan("\u{1F527} Add Canister Hooks"));
|
|
@@ -934,7 +356,7 @@ async function addCommand(options) {
|
|
|
934
356
|
p2.log.error(`Canister ${pc2.yellow(selectedCanister)} not found in config.`);
|
|
935
357
|
process.exit(1);
|
|
936
358
|
}
|
|
937
|
-
const didFilePath =
|
|
359
|
+
const didFilePath = path3.resolve(projectRoot, canisterConfig.didFile);
|
|
938
360
|
let methods;
|
|
939
361
|
try {
|
|
940
362
|
methods = parseDIDFile(didFilePath);
|
|
@@ -1059,13 +481,13 @@ ${error.message}`
|
|
|
1059
481
|
p2.log.warn("All methods were skipped. Nothing to generate.");
|
|
1060
482
|
process.exit(0);
|
|
1061
483
|
}
|
|
1062
|
-
const canisterOutDir =
|
|
1063
|
-
const hooksOutDir =
|
|
484
|
+
const canisterOutDir = path3.join(projectRoot, config.outDir, selectedCanister);
|
|
485
|
+
const hooksOutDir = path3.join(canisterOutDir, "hooks");
|
|
1064
486
|
ensureDir(hooksOutDir);
|
|
1065
487
|
const spinner4 = p2.spinner();
|
|
1066
488
|
spinner4.start("Generating hooks...");
|
|
1067
489
|
const generatedFiles = [];
|
|
1068
|
-
const reactorPath =
|
|
490
|
+
const reactorPath = path3.join(canisterOutDir, "reactor.ts");
|
|
1069
491
|
if (!fileExists(reactorPath)) {
|
|
1070
492
|
spinner4.message("Generating TypeScript declarations...");
|
|
1071
493
|
const bindgenResult = await generateDeclarations({
|
|
@@ -1089,12 +511,12 @@ ${error.message}`
|
|
|
1089
511
|
outDir: canisterOutDir,
|
|
1090
512
|
hasDeclarations: bindgenResult.success
|
|
1091
513
|
});
|
|
1092
|
-
|
|
514
|
+
fs3.writeFileSync(reactorPath, reactorContent);
|
|
1093
515
|
generatedFiles.push("reactor.ts");
|
|
1094
516
|
}
|
|
1095
517
|
for (const { method, hookType } of methodsWithHookTypes) {
|
|
1096
518
|
const fileName = getHookFileName(method.name, hookType);
|
|
1097
|
-
const filePath =
|
|
519
|
+
const filePath = path3.join(hooksOutDir, fileName);
|
|
1098
520
|
let content;
|
|
1099
521
|
switch (hookType) {
|
|
1100
522
|
case "query":
|
|
@@ -1121,25 +543,49 @@ ${error.message}`
|
|
|
1121
543
|
});
|
|
1122
544
|
break;
|
|
1123
545
|
}
|
|
1124
|
-
|
|
1125
|
-
generatedFiles.push(
|
|
546
|
+
fs3.writeFileSync(filePath, content);
|
|
547
|
+
generatedFiles.push(path3.join("hooks", fileName));
|
|
1126
548
|
}
|
|
1127
|
-
const indexPath =
|
|
1128
|
-
|
|
1129
|
-
|
|
549
|
+
const indexPath = path3.join(hooksOutDir, "index.ts");
|
|
550
|
+
let existingExports = [];
|
|
551
|
+
if (fs3.existsSync(indexPath)) {
|
|
552
|
+
const content = fs3.readFileSync(indexPath, "utf-8");
|
|
553
|
+
existingExports = content.split("\n").filter((line) => line.trim().startsWith("export * from")).map((line) => line.trim());
|
|
554
|
+
}
|
|
555
|
+
const newExports = methodsWithHookTypes.map(({ method, hookType }) => {
|
|
556
|
+
const fileName = getHookFileName(method.name, hookType).replace(".ts", "");
|
|
557
|
+
return `export * from "./${fileName}"`;
|
|
558
|
+
});
|
|
559
|
+
const allExports = [.../* @__PURE__ */ new Set([...existingExports, ...newExports])];
|
|
560
|
+
const indexContent = `/**
|
|
561
|
+
* Hook barrel exports
|
|
562
|
+
*
|
|
563
|
+
* Auto-generated by @ic-reactor/cli
|
|
564
|
+
*/
|
|
565
|
+
|
|
566
|
+
${allExports.join("\n")}
|
|
567
|
+
`;
|
|
568
|
+
fs3.writeFileSync(indexPath, indexContent);
|
|
1130
569
|
generatedFiles.push("hooks/index.ts");
|
|
570
|
+
const existingHooks = config.generatedHooks[selectedCanister] ?? [];
|
|
571
|
+
const newHookConfigs = methodsWithHookTypes.map(({ method, hookType }) => ({
|
|
572
|
+
name: method.name,
|
|
573
|
+
type: hookType
|
|
574
|
+
}));
|
|
575
|
+
const filteredExisting = existingHooks.filter((h) => {
|
|
576
|
+
const name = typeof h === "string" ? h : h.name;
|
|
577
|
+
return !newHookConfigs.some((n) => n.name === name);
|
|
578
|
+
});
|
|
1131
579
|
config.generatedHooks[selectedCanister] = [
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
...selectedMethods.map((m) => m.name)
|
|
1135
|
-
])
|
|
580
|
+
...filteredExisting,
|
|
581
|
+
...newHookConfigs
|
|
1136
582
|
];
|
|
1137
583
|
saveConfig(config, configPath);
|
|
1138
584
|
spinner4.stop("Hooks generated!");
|
|
1139
585
|
console.log();
|
|
1140
586
|
p2.note(
|
|
1141
587
|
generatedFiles.map((f) => pc2.green(`\u2713 ${f}`)).join("\n"),
|
|
1142
|
-
`Generated in ${pc2.dim(
|
|
588
|
+
`Generated in ${pc2.dim(path3.relative(projectRoot, canisterOutDir))}`
|
|
1143
589
|
);
|
|
1144
590
|
p2.outro(pc2.green("\u2713 Done!"));
|
|
1145
591
|
}
|
|
@@ -1158,8 +604,8 @@ async function promptForNewCanister(projectRoot) {
|
|
|
1158
604
|
placeholder: "./backend.did",
|
|
1159
605
|
validate: (value) => {
|
|
1160
606
|
if (!value) return "DID file path is required";
|
|
1161
|
-
const fullPath =
|
|
1162
|
-
if (!
|
|
607
|
+
const fullPath = path3.resolve(projectRoot, value);
|
|
608
|
+
if (!fs3.existsSync(fullPath)) {
|
|
1163
609
|
return `File not found: ${value}`;
|
|
1164
610
|
}
|
|
1165
611
|
return void 0;
|
|
@@ -1170,31 +616,19 @@ async function promptForNewCanister(projectRoot) {
|
|
|
1170
616
|
name,
|
|
1171
617
|
config: {
|
|
1172
618
|
didFile,
|
|
1173
|
-
clientManagerPath: "../../lib/client",
|
|
1174
619
|
useDisplayReactor: true
|
|
1175
620
|
}
|
|
1176
621
|
};
|
|
1177
622
|
}
|
|
1178
|
-
function generateIndexFile(methods) {
|
|
1179
|
-
const exports = methods.map(({ method, hookType }) => {
|
|
1180
|
-
const fileName = getHookFileName(method.name, hookType).replace(".ts", "");
|
|
1181
|
-
return `export * from "./${fileName}"`;
|
|
1182
|
-
});
|
|
1183
|
-
return `/**
|
|
1184
|
-
* Hook barrel exports
|
|
1185
|
-
*
|
|
1186
|
-
* Auto-generated by @ic-reactor/cli
|
|
1187
|
-
*/
|
|
1188
|
-
|
|
1189
|
-
${exports.join("\n")}
|
|
1190
|
-
`;
|
|
1191
|
-
}
|
|
1192
623
|
|
|
1193
624
|
// src/commands/sync.ts
|
|
1194
625
|
import * as p3 from "@clack/prompts";
|
|
1195
|
-
import
|
|
1196
|
-
import
|
|
626
|
+
import fs4 from "fs";
|
|
627
|
+
import path4 from "path";
|
|
1197
628
|
import pc3 from "picocolors";
|
|
629
|
+
import { parseDIDFile as parseDIDFile2 } from "@ic-reactor/codegen";
|
|
630
|
+
import { getHookFileName as getHookFileName2 } from "@ic-reactor/codegen";
|
|
631
|
+
import { generateDeclarations as generateDeclarations2 } from "@ic-reactor/codegen";
|
|
1198
632
|
async function syncCommand(options) {
|
|
1199
633
|
console.log();
|
|
1200
634
|
p3.intro(pc3.cyan("\u{1F504} Sync Canister Hooks"));
|
|
@@ -1245,74 +679,104 @@ async function syncCommand(options) {
|
|
|
1245
679
|
if (generatedMethods.length === 0) {
|
|
1246
680
|
continue;
|
|
1247
681
|
}
|
|
1248
|
-
const didFilePath =
|
|
682
|
+
const didFilePath = path4.resolve(projectRoot, canisterConfig.didFile);
|
|
1249
683
|
let methods;
|
|
1250
684
|
try {
|
|
1251
|
-
methods =
|
|
685
|
+
methods = parseDIDFile2(didFilePath);
|
|
1252
686
|
} catch (error) {
|
|
1253
687
|
errors.push(
|
|
1254
688
|
`${canisterName}: Failed to parse DID file - ${error.message}`
|
|
1255
689
|
);
|
|
1256
690
|
continue;
|
|
1257
691
|
}
|
|
1258
|
-
const
|
|
1259
|
-
|
|
1260
|
-
(name) => !currentMethodNames.includes(name)
|
|
692
|
+
const hooks = generatedMethods.map(
|
|
693
|
+
(h) => typeof h === "string" ? { name: h } : h
|
|
1261
694
|
);
|
|
695
|
+
const currentMethodNames = methods.map((m) => m.name);
|
|
696
|
+
const removedMethods = hooks.filter((h) => !currentMethodNames.includes(h.name)).map((h) => h.name);
|
|
1262
697
|
if (removedMethods.length > 0) {
|
|
1263
698
|
p3.log.warn(
|
|
1264
699
|
`${canisterName}: Methods removed from DID: ${pc3.yellow(removedMethods.join(", "))}`
|
|
1265
700
|
);
|
|
1266
701
|
}
|
|
1267
|
-
const
|
|
702
|
+
const generatedNames = hooks.map((h) => h.name);
|
|
703
|
+
const newMethods = methods.filter((m) => !generatedNames.includes(m.name));
|
|
1268
704
|
if (newMethods.length > 0) {
|
|
1269
705
|
p3.log.info(
|
|
1270
706
|
`${canisterName}: New methods available: ${pc3.cyan(newMethods.map((m) => m.name).join(", "))}`
|
|
1271
707
|
);
|
|
1272
708
|
}
|
|
1273
|
-
const canisterOutDir =
|
|
1274
|
-
const
|
|
709
|
+
const canisterOutDir = path4.join(projectRoot, config.outDir, canisterName);
|
|
710
|
+
const declarationsDir = path4.join(canisterOutDir, "declarations");
|
|
711
|
+
const declarationsExist = fs4.existsSync(declarationsDir) && fs4.readdirSync(declarationsDir).some((f) => f.endsWith(".ts") || f.endsWith(".js"));
|
|
712
|
+
if (!declarationsExist) {
|
|
713
|
+
spinner4.message(`Regenerating declarations for ${canisterName}...`);
|
|
714
|
+
const bindgenResult = await generateDeclarations2({
|
|
715
|
+
didFile: didFilePath,
|
|
716
|
+
outDir: canisterOutDir,
|
|
717
|
+
canisterName
|
|
718
|
+
});
|
|
719
|
+
if (bindgenResult.success) {
|
|
720
|
+
totalUpdated++;
|
|
721
|
+
} else {
|
|
722
|
+
p3.log.warn(
|
|
723
|
+
`Could not regenerate declarations for ${canisterName}: ${bindgenResult.error}`
|
|
724
|
+
);
|
|
725
|
+
}
|
|
726
|
+
}
|
|
727
|
+
const reactorPath = path4.join(canisterOutDir, "reactor.ts");
|
|
1275
728
|
const reactorContent = generateReactorFile({
|
|
1276
729
|
canisterName,
|
|
1277
730
|
canisterConfig,
|
|
1278
731
|
config,
|
|
1279
732
|
outDir: canisterOutDir
|
|
1280
733
|
});
|
|
1281
|
-
|
|
734
|
+
fs4.writeFileSync(reactorPath, reactorContent);
|
|
1282
735
|
totalUpdated++;
|
|
1283
|
-
const hooksOutDir =
|
|
736
|
+
const hooksOutDir = path4.join(canisterOutDir, "hooks");
|
|
1284
737
|
ensureDir(hooksOutDir);
|
|
1285
|
-
for (const
|
|
738
|
+
for (const hookConfig of hooks) {
|
|
739
|
+
const methodName = hookConfig.name;
|
|
1286
740
|
const method = methods.find((m) => m.name === methodName);
|
|
1287
741
|
if (!method) {
|
|
1288
742
|
totalSkipped++;
|
|
1289
743
|
continue;
|
|
1290
744
|
}
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
745
|
+
let hookType = hookConfig.type || method.type;
|
|
746
|
+
if (!hookConfig.type) {
|
|
747
|
+
const infiniteQueryFileName = getHookFileName2(
|
|
748
|
+
methodName,
|
|
749
|
+
"infiniteQuery"
|
|
750
|
+
);
|
|
751
|
+
if (fs4.existsSync(path4.join(hooksOutDir, infiniteQueryFileName))) {
|
|
752
|
+
hookType = "infiniteQuery";
|
|
753
|
+
}
|
|
754
|
+
}
|
|
755
|
+
const fileName = getHookFileName2(methodName, hookType);
|
|
1294
756
|
let content;
|
|
1295
|
-
|
|
1296
|
-
if (fs6.existsSync(path5.join(hooksOutDir, infiniteQueryFileName))) {
|
|
1297
|
-
fileName = infiniteQueryFileName;
|
|
1298
|
-
totalSkipped++;
|
|
1299
|
-
continue;
|
|
1300
|
-
} else if (method.type === "query") {
|
|
1301
|
-
fileName = queryFileName;
|
|
757
|
+
if (hookType.includes("Query")) {
|
|
1302
758
|
content = generateQueryHook({
|
|
1303
759
|
canisterName,
|
|
1304
760
|
method,
|
|
1305
|
-
config
|
|
761
|
+
config,
|
|
762
|
+
type: hookType
|
|
1306
763
|
});
|
|
1307
764
|
} else {
|
|
1308
|
-
fileName = mutationFileName;
|
|
1309
765
|
content = generateMutationHook({
|
|
1310
766
|
canisterName,
|
|
1311
767
|
method,
|
|
1312
768
|
config
|
|
1313
769
|
});
|
|
1314
770
|
}
|
|
1315
|
-
|
|
771
|
+
const filePath = path4.join(hooksOutDir, fileName);
|
|
772
|
+
if (fs4.existsSync(filePath)) {
|
|
773
|
+
const existingContent = fs4.readFileSync(filePath, "utf-8");
|
|
774
|
+
if (existingContent !== content) {
|
|
775
|
+
totalSkipped++;
|
|
776
|
+
continue;
|
|
777
|
+
}
|
|
778
|
+
}
|
|
779
|
+
fs4.writeFileSync(filePath, content);
|
|
1316
780
|
totalUpdated++;
|
|
1317
781
|
}
|
|
1318
782
|
}
|
|
@@ -1335,8 +799,9 @@ Skipped: ${pc3.dim(totalSkipped.toString())} files (preserved customizations)`,
|
|
|
1335
799
|
|
|
1336
800
|
// src/commands/list.ts
|
|
1337
801
|
import * as p4 from "@clack/prompts";
|
|
1338
|
-
import
|
|
802
|
+
import path5 from "path";
|
|
1339
803
|
import pc4 from "picocolors";
|
|
804
|
+
import { parseDIDFile as parseDIDFile3 } from "@ic-reactor/codegen";
|
|
1340
805
|
async function listCommand(options) {
|
|
1341
806
|
console.log();
|
|
1342
807
|
p4.intro(pc4.cyan("\u{1F4CB} List Canister Methods"));
|
|
@@ -1384,9 +849,9 @@ async function listCommand(options) {
|
|
|
1384
849
|
p4.log.error(`Canister ${pc4.yellow(selectedCanister)} not found in config.`);
|
|
1385
850
|
process.exit(1);
|
|
1386
851
|
}
|
|
1387
|
-
const didFilePath =
|
|
852
|
+
const didFilePath = path5.resolve(projectRoot, canisterConfig.didFile);
|
|
1388
853
|
try {
|
|
1389
|
-
const methods =
|
|
854
|
+
const methods = parseDIDFile3(didFilePath);
|
|
1390
855
|
if (methods.length === 0) {
|
|
1391
856
|
p4.log.warn(`No methods found in ${pc4.yellow(didFilePath)}`);
|
|
1392
857
|
process.exit(0);
|
|
@@ -1445,14 +910,17 @@ ${error.message}`
|
|
|
1445
910
|
|
|
1446
911
|
// src/commands/fetch.ts
|
|
1447
912
|
import * as p5 from "@clack/prompts";
|
|
1448
|
-
import
|
|
1449
|
-
import
|
|
913
|
+
import fs5 from "fs";
|
|
914
|
+
import path6 from "path";
|
|
1450
915
|
import pc5 from "picocolors";
|
|
916
|
+
import { formatMethodForDisplay as formatMethodForDisplay2 } from "@ic-reactor/codegen";
|
|
917
|
+
import { getHookFileName as getHookFileName3, toCamelCase } from "@ic-reactor/codegen";
|
|
1451
918
|
|
|
1452
919
|
// src/utils/network.ts
|
|
1453
920
|
import { HttpAgent, Actor } from "@icp-sdk/core/agent";
|
|
1454
921
|
import { Principal } from "@icp-sdk/core/principal";
|
|
1455
922
|
import { IDL } from "@icp-sdk/core/candid";
|
|
923
|
+
import { extractMethods } from "@ic-reactor/codegen";
|
|
1456
924
|
var IC_HOST = "https://icp-api.io";
|
|
1457
925
|
var LOCAL_HOST = "http://127.0.0.1:4943";
|
|
1458
926
|
async function fetchCandidFromCanister(options) {
|
|
@@ -1524,6 +992,7 @@ function shortenCanisterId(canisterId) {
|
|
|
1524
992
|
}
|
|
1525
993
|
|
|
1526
994
|
// src/commands/fetch.ts
|
|
995
|
+
import { generateDeclarations as generateDeclarations3 } from "@ic-reactor/codegen";
|
|
1527
996
|
async function fetchCommand(options) {
|
|
1528
997
|
console.log();
|
|
1529
998
|
p5.intro(pc5.cyan("\u{1F310} Fetch from Live Canister"));
|
|
@@ -1624,7 +1093,7 @@ async function fetchCommand(options) {
|
|
|
1624
1093
|
message: "Select methods to generate hooks for",
|
|
1625
1094
|
options: methods.map((method) => ({
|
|
1626
1095
|
value: method.name,
|
|
1627
|
-
label:
|
|
1096
|
+
label: formatMethodForDisplay2(method)
|
|
1628
1097
|
})),
|
|
1629
1098
|
required: true
|
|
1630
1099
|
});
|
|
@@ -1712,7 +1181,7 @@ async function fetchCommand(options) {
|
|
|
1712
1181
|
let configPath = findConfigFile();
|
|
1713
1182
|
let config;
|
|
1714
1183
|
if (!configPath) {
|
|
1715
|
-
configPath =
|
|
1184
|
+
configPath = path6.join(projectRoot, CONFIG_FILE_NAME);
|
|
1716
1185
|
config = { ...DEFAULT_CONFIG };
|
|
1717
1186
|
p5.log.info(`Creating ${pc5.yellow(CONFIG_FILE_NAME)}`);
|
|
1718
1187
|
} else {
|
|
@@ -1720,24 +1189,23 @@ async function fetchCommand(options) {
|
|
|
1720
1189
|
}
|
|
1721
1190
|
const canisterConfig = {
|
|
1722
1191
|
didFile: `./candid/${canisterName}.did`,
|
|
1723
|
-
clientManagerPath: "../../lib/client",
|
|
1724
1192
|
useDisplayReactor: true,
|
|
1725
1193
|
canisterId
|
|
1726
1194
|
};
|
|
1727
1195
|
config.canisters[canisterName] = canisterConfig;
|
|
1728
|
-
const canisterOutDir =
|
|
1729
|
-
const hooksOutDir =
|
|
1730
|
-
const candidDir =
|
|
1196
|
+
const canisterOutDir = path6.join(projectRoot, config.outDir, canisterName);
|
|
1197
|
+
const hooksOutDir = path6.join(canisterOutDir, "hooks");
|
|
1198
|
+
const candidDir = path6.join(projectRoot, "candid");
|
|
1731
1199
|
ensureDir(hooksOutDir);
|
|
1732
1200
|
ensureDir(candidDir);
|
|
1733
1201
|
const genSpinner = p5.spinner();
|
|
1734
1202
|
genSpinner.start("Generating hooks...");
|
|
1735
1203
|
const generatedFiles = [];
|
|
1736
|
-
const candidPath =
|
|
1737
|
-
|
|
1204
|
+
const candidPath = path6.join(candidDir, `${canisterName}.did`);
|
|
1205
|
+
fs5.writeFileSync(candidPath, candidSource);
|
|
1738
1206
|
generatedFiles.push(`candid/${canisterName}.did`);
|
|
1739
1207
|
genSpinner.message("Generating TypeScript declarations...");
|
|
1740
|
-
const bindgenResult = await
|
|
1208
|
+
const bindgenResult = await generateDeclarations3({
|
|
1741
1209
|
didFile: candidPath,
|
|
1742
1210
|
outDir: canisterOutDir,
|
|
1743
1211
|
canisterName
|
|
@@ -1751,18 +1219,19 @@ async function fetchCommand(options) {
|
|
|
1751
1219
|
);
|
|
1752
1220
|
}
|
|
1753
1221
|
genSpinner.message("Generating reactor...");
|
|
1754
|
-
const reactorPath =
|
|
1222
|
+
const reactorPath = path6.join(canisterOutDir, "reactor.ts");
|
|
1755
1223
|
const reactorContent = generateReactorFileForFetch({
|
|
1756
1224
|
canisterName,
|
|
1757
1225
|
canisterConfig,
|
|
1226
|
+
config,
|
|
1758
1227
|
canisterId,
|
|
1759
1228
|
hasDeclarations: bindgenResult.success
|
|
1760
1229
|
});
|
|
1761
|
-
|
|
1230
|
+
fs5.writeFileSync(reactorPath, reactorContent);
|
|
1762
1231
|
generatedFiles.push("reactor.ts");
|
|
1763
1232
|
for (const { method, hookType } of methodsWithHookTypes) {
|
|
1764
|
-
const fileName =
|
|
1765
|
-
const filePath =
|
|
1233
|
+
const fileName = getHookFileName3(method.name, hookType);
|
|
1234
|
+
const filePath = path6.join(hooksOutDir, fileName);
|
|
1766
1235
|
let content;
|
|
1767
1236
|
switch (hookType) {
|
|
1768
1237
|
case "query":
|
|
@@ -1789,12 +1258,12 @@ async function fetchCommand(options) {
|
|
|
1789
1258
|
});
|
|
1790
1259
|
break;
|
|
1791
1260
|
}
|
|
1792
|
-
|
|
1793
|
-
generatedFiles.push(
|
|
1261
|
+
fs5.writeFileSync(filePath, content);
|
|
1262
|
+
generatedFiles.push(path6.join("hooks", fileName));
|
|
1794
1263
|
}
|
|
1795
|
-
const indexPath =
|
|
1796
|
-
const indexContent =
|
|
1797
|
-
|
|
1264
|
+
const indexPath = path6.join(hooksOutDir, "index.ts");
|
|
1265
|
+
const indexContent = generateIndexFile(methodsWithHookTypes);
|
|
1266
|
+
fs5.writeFileSync(indexPath, indexContent);
|
|
1798
1267
|
generatedFiles.push("hooks/index.ts");
|
|
1799
1268
|
config.generatedHooks[canisterName] = [
|
|
1800
1269
|
.../* @__PURE__ */ new Set([
|
|
@@ -1807,7 +1276,7 @@ async function fetchCommand(options) {
|
|
|
1807
1276
|
console.log();
|
|
1808
1277
|
p5.note(
|
|
1809
1278
|
generatedFiles.map((f) => pc5.green(`\u2713 ${f}`)).join("\n"),
|
|
1810
|
-
`Generated in ${pc5.dim(
|
|
1279
|
+
`Generated in ${pc5.dim(path6.relative(projectRoot, canisterOutDir))}`
|
|
1811
1280
|
);
|
|
1812
1281
|
console.log();
|
|
1813
1282
|
p5.note(
|
|
@@ -1820,12 +1289,13 @@ Methods: ${pc5.dim(selectedMethods.map((m) => m.name).join(", "))}`,
|
|
|
1820
1289
|
p5.outro(pc5.green("\u2713 Done!"));
|
|
1821
1290
|
}
|
|
1822
1291
|
function generateReactorFileForFetch(options) {
|
|
1823
|
-
const { canisterName, canisterConfig, canisterId, hasDeclarations } = options;
|
|
1292
|
+
const { canisterName, canisterConfig, config, canisterId, hasDeclarations } = options;
|
|
1824
1293
|
const pascalName = canisterName.charAt(0).toUpperCase() + canisterName.slice(1);
|
|
1825
1294
|
const reactorName = `${canisterName}Reactor`;
|
|
1826
1295
|
const serviceName = `${pascalName}Service`;
|
|
1827
1296
|
const reactorType = canisterConfig.useDisplayReactor !== false ? "DisplayReactor" : "Reactor";
|
|
1828
|
-
const clientManagerPath = canisterConfig.clientManagerPath ?? "../../lib/client";
|
|
1297
|
+
const clientManagerPath = canisterConfig.clientManagerPath ?? config.clientManagerPath ?? "../../lib/client";
|
|
1298
|
+
const didFileName = path6.basename(canisterConfig.didFile);
|
|
1829
1299
|
if (hasDeclarations) {
|
|
1830
1300
|
return `/**
|
|
1831
1301
|
* ${pascalName} Reactor
|
|
@@ -1836,11 +1306,11 @@ function generateReactorFileForFetch(options) {
|
|
|
1836
1306
|
* You can customize this file to add global configuration.
|
|
1837
1307
|
*/
|
|
1838
1308
|
|
|
1839
|
-
import { ${reactorType}, createActorHooks
|
|
1309
|
+
import { ${reactorType}, createActorHooks } from "@ic-reactor/react"
|
|
1840
1310
|
import { clientManager } from "${clientManagerPath}"
|
|
1841
1311
|
|
|
1842
1312
|
// Import generated declarations
|
|
1843
|
-
import { idlFactory, type _SERVICE as ${serviceName} } from "./declarations/${
|
|
1313
|
+
import { idlFactory, type _SERVICE as ${serviceName} } from "./declarations/${didFileName}"
|
|
1844
1314
|
|
|
1845
1315
|
// \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
|
|
1846
1316
|
// REACTOR INSTANCE
|
|
@@ -1859,11 +1329,11 @@ export const ${reactorName} = new ${reactorType}<${serviceName}>({
|
|
|
1859
1329
|
})
|
|
1860
1330
|
|
|
1861
1331
|
// \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
|
|
1862
|
-
//
|
|
1332
|
+
// ACTOR HOOKS
|
|
1863
1333
|
// \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
|
|
1864
1334
|
|
|
1865
1335
|
/**
|
|
1866
|
-
*
|
|
1336
|
+
* Actor hooks for ${canisterName} - use these directly or import method-specific hooks.
|
|
1867
1337
|
*/
|
|
1868
1338
|
export const {
|
|
1869
1339
|
useActorQuery,
|
|
@@ -1874,11 +1344,6 @@ export const {
|
|
|
1874
1344
|
useActorMethod,
|
|
1875
1345
|
} = createActorHooks(${reactorName})
|
|
1876
1346
|
|
|
1877
|
-
/**
|
|
1878
|
-
* Auth hooks for the client manager.
|
|
1879
|
-
*/
|
|
1880
|
-
export const { useAuth, useAgentState, useUserPrincipal } = createAuthHooks(clientManager)
|
|
1881
|
-
|
|
1882
1347
|
// \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
|
|
1883
1348
|
// RE-EXPORTS
|
|
1884
1349
|
// \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
|
|
@@ -1896,7 +1361,7 @@ export type { ${serviceName} }
|
|
|
1896
1361
|
* You can customize this file to add global configuration.
|
|
1897
1362
|
*/
|
|
1898
1363
|
|
|
1899
|
-
import { ${reactorType}, createActorHooks
|
|
1364
|
+
import { ${reactorType}, createActorHooks } from "@ic-reactor/react"
|
|
1900
1365
|
import { clientManager } from "${clientManagerPath}"
|
|
1901
1366
|
|
|
1902
1367
|
// \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
|
|
@@ -1907,7 +1372,7 @@ import { clientManager } from "${clientManagerPath}"
|
|
|
1907
1372
|
// npx @icp-sdk/bindgen --input ./candid/${canisterName}.did --output ./${canisterName}/declarations
|
|
1908
1373
|
|
|
1909
1374
|
// For now, import just the IDL factory (you may need to create this manually)
|
|
1910
|
-
// import { idlFactory, type _SERVICE as ${serviceName} } from "./declarations/${
|
|
1375
|
+
// import { idlFactory, type _SERVICE as ${serviceName} } from "./declarations/${didFileName}"
|
|
1911
1376
|
|
|
1912
1377
|
// Fallback generic type - replace with generated types
|
|
1913
1378
|
type ${serviceName} = Record<string, (...args: unknown[]) => Promise<unknown>>
|
|
@@ -1933,11 +1398,11 @@ export const ${reactorName} = new ${reactorType}<${serviceName}>({
|
|
|
1933
1398
|
})
|
|
1934
1399
|
|
|
1935
1400
|
// \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
|
|
1936
|
-
//
|
|
1401
|
+
// ACTOR HOOKS
|
|
1937
1402
|
// \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
|
|
1938
1403
|
|
|
1939
1404
|
/**
|
|
1940
|
-
*
|
|
1405
|
+
* Actor hooks for ${canisterName} - use these directly or import method-specific hooks.
|
|
1941
1406
|
*/
|
|
1942
1407
|
export const {
|
|
1943
1408
|
useActorQuery,
|
|
@@ -1948,11 +1413,6 @@ export const {
|
|
|
1948
1413
|
useActorMethod,
|
|
1949
1414
|
} = createActorHooks(${reactorName})
|
|
1950
1415
|
|
|
1951
|
-
/**
|
|
1952
|
-
* Auth hooks for the client manager.
|
|
1953
|
-
*/
|
|
1954
|
-
export const { useAuth, useAgentState, useUserPrincipal } = createAuthHooks(clientManager)
|
|
1955
|
-
|
|
1956
1416
|
// \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
|
|
1957
1417
|
// RE-EXPORTS
|
|
1958
1418
|
// \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
|
|
@@ -1961,9 +1421,9 @@ export { idlFactory }
|
|
|
1961
1421
|
export type { ${serviceName} }
|
|
1962
1422
|
`;
|
|
1963
1423
|
}
|
|
1964
|
-
function
|
|
1424
|
+
function generateIndexFile(methods) {
|
|
1965
1425
|
const exports = methods.map(({ method, hookType }) => {
|
|
1966
|
-
const fileName =
|
|
1426
|
+
const fileName = getHookFileName3(method.name, hookType).replace(".ts", "");
|
|
1967
1427
|
return `export * from "./${fileName}"`;
|
|
1968
1428
|
});
|
|
1969
1429
|
return `/**
|