@ic-reactor/vite-plugin 0.1.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -30,381 +30,167 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
30
30
  // src/index.ts
31
31
  var index_exports = {};
32
32
  __export(index_exports, {
33
- icReactorAdvancedPlugin: () => icReactorAdvancedPlugin,
34
33
  icReactorPlugin: () => icReactorPlugin
35
34
  });
36
35
  module.exports = __toCommonJS(index_exports);
37
-
38
- // src/simple.ts
39
- var import_core2 = require("@icp-sdk/bindgen/core");
40
- var import_fs2 = __toESM(require("fs"), 1);
41
- var import_path2 = __toESM(require("path"), 1);
42
-
43
- // src/advanced.ts
44
36
  var import_fs = __toESM(require("fs"), 1);
45
37
  var import_path = __toESM(require("path"), 1);
46
- var import_core = require("@icp-sdk/bindgen/core");
47
- function toPascalCase(str) {
48
- return str.split(/[-_]/).map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join("");
49
- }
50
- function toCamelCase(str) {
51
- const pascal = toPascalCase(str);
52
- return pascal.charAt(0).toLowerCase() + pascal.slice(1);
53
- }
54
- function extractMethods(didContent) {
55
- const methodRegex = /([a-zA-Z0-9_]+)\s*:\s*(?:func\s*)?\(([\s\S]*?)\)\s*->\s*\(([\s\S]*?)\)\s*(query|composite_query)?/g;
56
- const methods = [];
57
- let match;
58
- while ((match = methodRegex.exec(didContent)) !== null) {
59
- const name = match[1];
60
- const args = match[2].trim();
61
- const isQuery = !!match[4];
62
- methods.push({
63
- name,
64
- type: isQuery ? "query" : "mutation",
65
- hasArgs: args.length > 0
66
- });
38
+ var import_child_process = require("child_process");
39
+ var import_codegen = require("@ic-reactor/codegen");
40
+ function getIcEnvironmentInfo(canisterNames) {
41
+ const environment = process.env.ICP_ENVIRONMENT || "local";
42
+ try {
43
+ const networkStatus = JSON.parse(
44
+ (0, import_child_process.execFileSync)("icp", ["network", "status", "-e", environment, "--json"], {
45
+ encoding: "utf-8"
46
+ })
47
+ );
48
+ const rootKey = networkStatus.root_key;
49
+ const proxyTarget = `http://127.0.0.1:${networkStatus.port}`;
50
+ const canisterIds = {};
51
+ for (const name of canisterNames) {
52
+ try {
53
+ const canisterId = (0, import_child_process.execFileSync)(
54
+ "icp",
55
+ ["canister", "status", name, "-e", environment, "-i"],
56
+ {
57
+ encoding: "utf-8"
58
+ }
59
+ ).trim();
60
+ canisterIds[name] = canisterId;
61
+ } catch {
62
+ }
63
+ }
64
+ return { environment, rootKey, proxyTarget, canisterIds };
65
+ } catch {
66
+ return null;
67
67
  }
68
- return methods;
69
68
  }
70
- function generateAdvancedReactorFile(canisterName, useDisplayReactor, clientManagerPath, didContent) {
71
- const pascalName = toPascalCase(canisterName);
72
- const camelName = toCamelCase(canisterName);
73
- const reactorType = useDisplayReactor ? "DisplayReactor" : "Reactor";
74
- const methods = extractMethods(didContent);
75
- const hooks = methods.map(({ name, type, hasArgs }) => {
76
- const pascalMethod = toPascalCase(name);
77
- const camelMethod = toCamelCase(name);
78
- if (type === "query") {
79
- const hook = `
80
- export const use${pascalMethod}Query = (
81
- args: Parameters<${pascalName}Service["${name}"]>,
82
- options?: any
83
- ) =>
84
- useActorQuery({
85
- functionName: "${name}",
86
- args,
87
- ...options,
88
- })
89
- `;
90
- const staticQuery = !hasArgs ? `
91
- export const ${camelMethod}Query = createQuery(${camelName}Reactor, {
92
- functionName: "${name}",
93
- })
94
- ` : "";
95
- return hook + staticQuery;
96
- } else {
97
- const hook = `
98
- export const use${pascalMethod}Mutation = (
99
- options?: any
100
- ) =>
101
- useActorMutation({
102
- functionName: "${name}",
103
- ...options,
104
- })
105
- `;
106
- const staticMutation = !hasArgs ? `
107
- export const ${camelMethod}Mutation = createMutation(${camelName}Reactor, {
108
- functionName: "${name}",
109
- })
110
- ` : "";
111
- return hook + staticMutation;
112
- }
113
- });
114
- return `/**
115
- * AUTO-GENERATED BY @ic-reactor/vite-plugin
116
- * DO NOT EDIT MANUALLY
117
- *
118
- * Canister: ${canisterName}
119
- * Generated: ${(/* @__PURE__ */ new Date()).toISOString()}
120
- *
121
- * This file provides type-safe React hooks for interacting with the
122
- * ${canisterName} canister using ic-reactor.
123
- */
124
-
125
- import {
126
- ${reactorType},
127
- createActorHooks,
128
- createAuthHooks,
129
- createQuery,
130
- createMutation,
131
- } from "@ic-reactor/react"
132
-
133
- // \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
134
- // USER-PROVIDED CLIENT MANAGER
135
- // \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
136
- import { clientManager } from "${clientManagerPath}"
137
-
138
- // Import generated declarations from @icp-sdk/bindgen
139
- import {
140
- idlFactory,
141
- type _SERVICE,
142
- } from "./declarations/${canisterName}.did"
143
-
144
- // \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
145
- // REACTOR INSTANCE
146
- // \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
147
- type ${pascalName}Service = _SERVICE
148
-
149
- /**
150
- * ${pascalName} Reactor with ${useDisplayReactor ? "Display" : "Candid"} type transformations.
151
- * ${useDisplayReactor ? "Automatically converts bigint \u2192 string, Principal \u2192 string, etc." : "Uses raw Candid types."}
152
- */
153
- export const ${camelName}Reactor = new ${reactorType}<${pascalName}Service>({
154
- clientManager,
155
- idlFactory,
156
- name: "${canisterName}",
157
- })
158
-
159
- // \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
160
- // ACTOR & AUTH HOOKS
161
- // \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
162
- export const {
163
- useActorQuery,
164
- useActorMutation,
165
- useActorSuspenseQuery,
166
- useActorInfiniteQuery,
167
- useActorSuspenseInfiniteQuery,
168
- useActorMethod,
169
- } = createActorHooks(${camelName}Reactor)
170
-
171
- export const use${pascalName}Query = useActorQuery
172
- export const use${pascalName}Mutation = useActorMutation
173
- export const use${pascalName}SuspenseQuery = useActorSuspenseQuery
174
- export const use${pascalName}InfiniteQuery = useActorInfiniteQuery
175
- export const use${pascalName}SuspenseInfiniteQuery = useActorSuspenseInfiniteQuery
176
- export const use${pascalName}Method = useActorMethod
177
-
178
- export const { useAuth, useAgentState, useUserPrincipal } = createAuthHooks(
179
- clientManager
180
- )
181
-
182
- // \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
183
- // METHOD HOOKS
184
- // \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
185
- ${hooks.join("")}
186
-
187
- // \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
188
- // RE-EXPORTS
189
- // \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
190
- export { idlFactory }
191
- export type { ${pascalName}Service }
192
- `;
69
+ function buildIcEnvCookie(canisterIds, rootKey) {
70
+ const envParts = [`ic_root_key=${rootKey}`];
71
+ for (const [name, id] of Object.entries(canisterIds)) {
72
+ envParts.push(`PUBLIC_CANISTER_ID:${name}=${id}`);
73
+ }
74
+ return encodeURIComponent(envParts.join("&"));
193
75
  }
194
- function icReactorAdvancedPlugin(options) {
195
- const baseOutDir = options.outDir ?? "./src/canisters";
76
+ function icReactorPlugin(options) {
77
+ const baseOutDir = options.outDir ?? "./src/lib/canisters";
196
78
  return {
197
- name: "ic-reactor-advanced-plugin",
198
- async buildStart() {
199
- for (const canister of options.canisters) {
200
- const outDir = canister.outDir ?? import_path.default.join(baseOutDir, canister.name);
201
- if (!import_fs.default.existsSync(outDir)) {
202
- import_fs.default.mkdirSync(outDir, { recursive: true });
203
- }
204
- console.log(
205
- `[ic-reactor] Generating advanced hooks for ${canister.name} from ${canister.didFile}`
206
- );
207
- try {
208
- await (0, import_core.generate)({
209
- didFile: canister.didFile,
210
- outDir,
211
- output: {
212
- actor: {
213
- disabled: true
214
- },
215
- force: true
79
+ name: "ic-reactor-plugin",
80
+ config(_config, { command }) {
81
+ if (command !== "serve" || !(options.injectEnvironment ?? true)) {
82
+ return {};
83
+ }
84
+ const canisterNames = options.canisters.map((c) => c.name);
85
+ const icEnv = getIcEnvironmentInfo(canisterNames);
86
+ if (!icEnv) {
87
+ return {
88
+ server: {
89
+ proxy: {
90
+ "/api": {
91
+ target: "http://127.0.0.1:4943",
92
+ changeOrigin: true
93
+ }
216
94
  }
217
- });
218
- console.log(
219
- `[ic-reactor] Declarations generated at ${import_path.default.join(
220
- outDir,
221
- "declarations"
222
- )}`
223
- );
224
- } catch (error) {
225
- console.error(`[ic-reactor] Failed to generate declarations:`, error);
226
- continue;
227
- }
228
- const clientManagerPath = canister.clientManagerPath ?? options.clientManagerPath ?? "../../lib/client";
229
- let didContent = "";
230
- try {
231
- didContent = import_fs.default.readFileSync(canister.didFile, "utf-8");
232
- } catch (e) {
233
- console.warn(
234
- `[ic-reactor] Could not read DID file at ${canister.didFile}, skipping hook generation.`
235
- );
236
- continue;
95
+ }
96
+ };
97
+ }
98
+ const cookieValue = buildIcEnvCookie(icEnv.canisterIds, icEnv.rootKey);
99
+ return {
100
+ server: {
101
+ headers: {
102
+ "Set-Cookie": `ic_env=${cookieValue}; Path=/; SameSite=Lax;`
103
+ },
104
+ proxy: {
105
+ "/api": {
106
+ target: icEnv.proxyTarget,
107
+ changeOrigin: true
108
+ }
109
+ }
237
110
  }
238
- const reactorContent = generateAdvancedReactorFile(
239
- canister.name,
240
- canister.useDisplayReactor ?? true,
241
- clientManagerPath,
242
- didContent
243
- );
244
- const reactorPath = import_path.default.join(outDir, "index.ts");
245
- import_fs.default.writeFileSync(reactorPath, reactorContent);
111
+ };
112
+ },
113
+ async buildStart() {
114
+ const defaultClientPath = import_path.default.resolve(
115
+ process.cwd(),
116
+ "src/lib/clients.ts"
117
+ );
118
+ if (!import_fs.default.existsSync(defaultClientPath)) {
246
119
  console.log(
247
- `[ic-reactor] Advanced reactor hooks generated at ${reactorPath}`
120
+ `[ic-reactor] Default client manager not found. Creating at ${defaultClientPath}`
248
121
  );
122
+ const clientContent = (0, import_codegen.generateClientFile)();
123
+ import_fs.default.mkdirSync(import_path.default.dirname(defaultClientPath), { recursive: true });
124
+ import_fs.default.writeFileSync(defaultClientPath, clientContent);
249
125
  }
250
- },
251
- handleHotUpdate({ file, server }) {
252
- if (file.endsWith(".did")) {
253
- const canister = options.canisters.find(
254
- (c) => import_path.default.resolve(c.didFile) === file
255
- );
256
- if (canister) {
126
+ for (const canister of options.canisters) {
127
+ let didFile = canister.didFile;
128
+ const outDir = canister.outDir ?? import_path.default.join(baseOutDir, canister.name);
129
+ if (!didFile) {
130
+ const environment = process.env.ICP_ENVIRONMENT || "local";
257
131
  console.log(
258
- `[ic-reactor] Detected change in ${file}, regenerating...`
132
+ `[ic-reactor] didFile not specified for "${canister.name}". Attempting to download from canister...`
259
133
  );
260
- server.restart();
134
+ try {
135
+ const candidContent = (0, import_child_process.execFileSync)(
136
+ "icp",
137
+ [
138
+ "canister",
139
+ "metadata",
140
+ canister.name,
141
+ "candid:service",
142
+ "-e",
143
+ environment
144
+ ],
145
+ { encoding: "utf-8" }
146
+ ).trim();
147
+ const declarationsDir = import_path.default.join(outDir, "declarations");
148
+ if (!import_fs.default.existsSync(declarationsDir)) {
149
+ import_fs.default.mkdirSync(declarationsDir, { recursive: true });
150
+ }
151
+ didFile = import_path.default.join(declarationsDir, `${canister.name}.did`);
152
+ import_fs.default.writeFileSync(didFile, candidContent);
153
+ console.log(
154
+ `[ic-reactor] Candid downloaded and saved to ${didFile}`
155
+ );
156
+ } catch (error) {
157
+ console.error(
158
+ `[ic-reactor] Failed to download candid for ${canister.name}: ${error}`
159
+ );
160
+ continue;
161
+ }
261
162
  }
262
- }
263
- }
264
- };
265
- }
266
-
267
- // src/simple.ts
268
- function toPascalCase2(str) {
269
- return str.split(/[-_]/).map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join("");
270
- }
271
- function toCamelCase2(str) {
272
- const pascal = toPascalCase2(str);
273
- return pascal.charAt(0).toLowerCase() + pascal.slice(1);
274
- }
275
- function generateReactorFile(canisterName, useDisplayReactor, clientManagerPath) {
276
- const pascalName = toPascalCase2(canisterName);
277
- const camelName = toCamelCase2(canisterName);
278
- const reactorType = useDisplayReactor ? "DisplayReactor" : "Reactor";
279
- return `/**
280
- * AUTO-GENERATED BY @ic-reactor/vite-plugin
281
- *
282
- * Canister: ${canisterName}
283
- * Generated: ${(/* @__PURE__ */ new Date()).toISOString()}
284
- *
285
- * This file provides type-safe React hooks for interacting with the
286
- * ${canisterName} canister using ic-reactor.
287
- */
288
-
289
- import {
290
- ${reactorType},
291
- createActorHooks,
292
- } from "@ic-reactor/react"
293
-
294
- // \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
295
- // USER-PROVIDED CLIENT MANAGER
296
- // \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
297
- // The clientManager is imported from the user's own configuration file.
298
- // This allows full customization of agent options, network settings, etc.
299
- import { clientManager } from "${clientManagerPath}"
300
-
301
- // Import generated declarations from @icp-sdk/bindgen
302
- import {
303
- idlFactory,
304
- type _SERVICE,
305
- } from "./declarations/${canisterName}.did"
306
-
307
- // \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
308
- // REACTOR INSTANCE
309
- // \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
310
-
311
- /**
312
- * ${pascalName} Reactor with ${useDisplayReactor ? "Display" : "Candid"} type transformations.
313
- * ${useDisplayReactor ? "Automatically converts bigint \u2192 string, Principal \u2192 string, etc." : "Uses raw Candid types."}
314
- */
315
- export const ${camelName}Reactor = new ${reactorType}<_SERVICE>({
316
- clientManager,
317
- idlFactory,
318
- name: "${canisterName}",
319
- })
320
-
321
- // \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
322
- // HOOKS
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
-
325
- /**
326
- * React hooks for the ${canisterName} canister.
327
- */
328
- const {
329
- useActorQuery: use${pascalName}Query,
330
- useActorSuspenseQuery: use${pascalName}SuspenseQuery,
331
- useActorInfiniteQuery: use${pascalName}InfiniteQuery,
332
- useActorSuspenseInfiniteQuery: use${pascalName}SuspenseInfiniteQuery,
333
- useActorMutation: use${pascalName}Mutation,
334
- useActorMethod: use${pascalName}Method,
335
- } = createActorHooks(${camelName}Reactor)
336
-
337
- export {
338
- use${pascalName}Query,
339
- use${pascalName}SuspenseQuery,
340
- use${pascalName}InfiniteQuery,
341
- use${pascalName}SuspenseInfiniteQuery,
342
- use${pascalName}Mutation,
343
- use${pascalName}Method,
344
- }
345
-
346
- // \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
347
- // RE-EXPORTS
348
- // \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
349
-
350
- export { idlFactory }
351
- export type { _SERVICE as ${pascalName}Service }
352
- `;
353
- }
354
- function icReactorPlugin(options) {
355
- const baseOutDir = options.outDir ?? "./src/canisters";
356
- return {
357
- name: "ic-reactor-plugin",
358
- async buildStart() {
359
- for (const canister of options.canisters) {
360
- const outDir = canister.outDir ?? import_path2.default.join(baseOutDir, canister.name);
361
- const declarationsDir = import_path2.default.join(outDir, "declarations");
362
163
  console.log(
363
- `[ic-reactor] Generating hooks for ${canister.name} from ${canister.didFile}`
164
+ `[ic-reactor] Generating hooks for ${canister.name} from ${didFile}`
364
165
  );
365
- if (import_fs2.default.existsSync(declarationsDir)) {
366
- import_fs2.default.rmSync(declarationsDir, { recursive: true, force: true });
367
- }
368
- import_fs2.default.mkdirSync(declarationsDir, { recursive: true });
369
- try {
370
- if (!import_fs2.default.existsSync(outDir)) {
371
- import_fs2.default.mkdirSync(outDir, { recursive: true });
372
- }
373
- await (0, import_core2.generate)({
374
- didFile: canister.didFile,
375
- outDir,
376
- // Pass the parent directory; bindgen appends "declarations"
377
- output: {
378
- actor: {
379
- disabled: true
380
- },
381
- force: true
382
- }
383
- });
384
- console.log(
385
- `[ic-reactor] Declarations generated at ${declarationsDir}`
166
+ const result = await (0, import_codegen.generateDeclarations)({
167
+ didFile,
168
+ outDir,
169
+ canisterName: canister.name
170
+ });
171
+ if (!result.success) {
172
+ console.error(
173
+ `[ic-reactor] Failed to generate declarations: ${result.error}`
386
174
  );
387
- } catch (error) {
388
- console.error(`[ic-reactor] Failed to generate declarations:`, error);
389
175
  continue;
390
176
  }
391
- const clientManagerPath = canister.clientManagerPath ?? options.clientManagerPath ?? "../../lib/client";
392
- const reactorContent = generateReactorFile(
393
- canister.name,
394
- canister.useDisplayReactor ?? true,
395
- clientManagerPath
396
- );
397
- const reactorPath = import_path2.default.join(outDir, "index.ts");
398
- import_fs2.default.mkdirSync(outDir, { recursive: true });
399
- import_fs2.default.writeFileSync(reactorPath, reactorContent);
177
+ const reactorContent = (0, import_codegen.generateReactorFile)({
178
+ canisterName: canister.name,
179
+ didFile,
180
+ clientManagerPath: canister.clientManagerPath ?? options.clientManagerPath
181
+ });
182
+ const reactorPath = import_path.default.join(outDir, "index.ts");
183
+ import_fs.default.mkdirSync(outDir, { recursive: true });
184
+ import_fs.default.writeFileSync(reactorPath, reactorContent);
400
185
  console.log(`[ic-reactor] Reactor hooks generated at ${reactorPath}`);
401
186
  }
402
187
  },
403
188
  handleHotUpdate({ file, server }) {
404
189
  if (file.endsWith(".did")) {
405
- const canister = options.canisters.find(
406
- (c) => import_path2.default.resolve(c.didFile) === file
407
- );
190
+ const canister = options.canisters.find((c) => {
191
+ if (!c.didFile) return false;
192
+ return import_path.default.resolve(c.didFile) === file;
193
+ });
408
194
  if (canister) {
409
195
  console.log(
410
196
  `[ic-reactor] Detected change in ${file}, regenerating...`
@@ -417,6 +203,5 @@ function icReactorPlugin(options) {
417
203
  }
418
204
  // Annotate the CommonJS export names for ESM import in node:
419
205
  0 && (module.exports = {
420
- icReactorAdvancedPlugin,
421
206
  icReactorPlugin
422
207
  });
package/dist/index.d.cts CHANGED
@@ -1,18 +1,10 @@
1
1
  import { Plugin } from 'vite';
2
2
 
3
- declare function icReactorAdvancedPlugin(options: IcReactorPluginOptions): Plugin;
4
-
5
3
  /**
6
4
  * IC-Reactor Vite Plugin
7
5
  *
8
6
  * A Vite plugin that generates ic-reactor hooks from Candid .did files.
9
- *
10
- * ⚠️ IMPORTANT: This plugin ONLY generates the reactor and hooks.
11
- * The user is responsible for creating and configuring:
12
- * - ClientManager
13
- * - QueryClient
14
- *
15
- * The generated file will import the clientManager from a user-specified path.
7
+ * Uses @ic-reactor/codegen for all code generation logic.
16
8
  *
17
9
  * Usage:
18
10
  * ```ts
@@ -25,7 +17,7 @@ declare function icReactorAdvancedPlugin(options: IcReactorPluginOptions): Plugi
25
17
  * {
26
18
  * name: "backend",
27
19
  * didFile: "../backend/backend.did",
28
- * clientManagerPath: "../lib/client" // User provides their own ClientManager
20
+ * clientManagerPath: "../lib/client"
29
21
  * }
30
22
  * ]
31
23
  * })
@@ -35,33 +27,29 @@ declare function icReactorAdvancedPlugin(options: IcReactorPluginOptions): Plugi
35
27
  */
36
28
 
37
29
  interface CanisterConfig {
38
- /** Name of the canister (used for variable naming) */
39
30
  name: string;
40
- /** Path to the .did file */
41
- didFile: string;
42
- /** Output directory (default: ./src/canisters/<name>) */
43
31
  outDir?: string;
44
- /** Use DisplayReactor for React-friendly types (default: true) */
45
- useDisplayReactor?: boolean;
46
- /**
47
- * Path to import ClientManager from (relative to generated file).
48
- * The file at this path should export: { clientManager: ClientManager }
49
- * Default: "../../lib/client"
50
- */
32
+ didFile?: string;
51
33
  clientManagerPath?: string;
52
34
  }
53
35
  interface IcReactorPluginOptions {
54
36
  /** List of canisters to generate hooks for */
55
37
  canisters: CanisterConfig[];
56
- /** Base output directory (default: ./src/canisters) */
38
+ /** Base output directory (default: ./src/lib/canisters) */
57
39
  outDir?: string;
58
40
  /**
59
41
  * Path to import ClientManager from (relative to generated file).
60
- * The file at this path should export: { clientManager: ClientManager }
61
- * Default: "../../lib/client"
42
+ * Default: "../../clients"
62
43
  */
63
44
  clientManagerPath?: string;
45
+ /**
46
+ * Automatically inject the IC environment (canister IDs and root key)
47
+ * into the browser using an `ic_env` cookie. (default: true)
48
+ *
49
+ * This is useful for local development with `icp`.
50
+ */
51
+ injectEnvironment?: boolean;
64
52
  }
65
53
  declare function icReactorPlugin(options: IcReactorPluginOptions): Plugin;
66
54
 
67
- export { type CanisterConfig, type IcReactorPluginOptions, icReactorAdvancedPlugin, icReactorPlugin };
55
+ export { type CanisterConfig, type IcReactorPluginOptions, icReactorPlugin };