@ic-reactor/vite-plugin 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +24 -23
- package/dist/index.cjs +80 -343
- package/dist/index.d.cts +21 -29
- package/dist/index.d.ts +21 -29
- package/dist/index.js +84 -341
- package/package.json +21 -17
- package/src/index.ts +226 -0
package/README.md
CHANGED
|
@@ -260,27 +260,28 @@ icReactorPlugin({
|
|
|
260
260
|
|
|
261
261
|
## Integration with ICP CLI
|
|
262
262
|
|
|
263
|
-
|
|
263
|
+
`@ic-reactor/vite-plugin` now supports **zero-config local `icp-cli` canister env injection** during `vite dev`.
|
|
264
|
+
|
|
265
|
+
When dev server starts, the plugin automatically tries to read:
|
|
266
|
+
|
|
267
|
+
- `.icp/cache/mappings/local.ids.json`
|
|
268
|
+
|
|
269
|
+
If present, it sets an `ic_env` cookie with:
|
|
270
|
+
|
|
271
|
+
- `ic_root_key=<local-root-key>`
|
|
272
|
+
- `PUBLIC_CANISTER_ID:<name>=<canister-id>`
|
|
273
|
+
|
|
274
|
+
This means `withCanisterEnv: true` works out of the box after `icp deploy`, without custom cookie code in `vite.config.ts`.
|
|
264
275
|
|
|
265
276
|
```typescript
|
|
266
277
|
// vite.config.ts
|
|
278
|
+
import { defineConfig } from "vite"
|
|
279
|
+
import react from "@vitejs/plugin-react"
|
|
267
280
|
import { icReactorPlugin } from "@ic-reactor/vite-plugin"
|
|
268
|
-
import fs from "fs"
|
|
269
|
-
import path from "path"
|
|
270
|
-
|
|
271
|
-
function loadCanisterIds(): Record<string, string> {
|
|
272
|
-
const idsPath = path.resolve(__dirname, ".icp/cache/mappings/local.ids.json")
|
|
273
|
-
try {
|
|
274
|
-
return JSON.parse(fs.readFileSync(idsPath, "utf-8"))
|
|
275
|
-
} catch {
|
|
276
|
-
return {}
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
const canisterIds = loadCanisterIds()
|
|
281
281
|
|
|
282
282
|
export default defineConfig({
|
|
283
283
|
plugins: [
|
|
284
|
+
react(),
|
|
284
285
|
icReactorPlugin({
|
|
285
286
|
canisters: [
|
|
286
287
|
{
|
|
@@ -290,15 +291,15 @@ export default defineConfig({
|
|
|
290
291
|
],
|
|
291
292
|
}),
|
|
292
293
|
],
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
294
|
+
})
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
If you need to disable this behavior:
|
|
298
|
+
|
|
299
|
+
```typescript
|
|
300
|
+
icReactorPlugin({
|
|
301
|
+
canisters: [...],
|
|
302
|
+
autoInjectIcEnv: false,
|
|
302
303
|
})
|
|
303
304
|
```
|
|
304
305
|
|
package/dist/index.cjs
CHANGED
|
@@ -30,380 +30,117 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
30
30
|
// src/index.ts
|
|
31
31
|
var index_exports = {};
|
|
32
32
|
__export(index_exports, {
|
|
33
|
-
|
|
33
|
+
default: () => index_default,
|
|
34
34
|
icReactorPlugin: () => icReactorPlugin
|
|
35
35
|
});
|
|
36
36
|
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
37
|
var import_fs = __toESM(require("fs"), 1);
|
|
45
38
|
var import_path = __toESM(require("path"), 1);
|
|
46
|
-
var
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
39
|
+
var import_codegen = require("@ic-reactor/codegen");
|
|
40
|
+
var ICP_LOCAL_IDS_PATH = ".icp/cache/mappings/local.ids.json";
|
|
41
|
+
var IC_ROOT_KEY_HEX = "308182301d060d2b0601040182dc7c0503010201060c2b0601040182dc7c050302010361008b52b4994f94c7ce4be1c1542d7c81dc79fea17d49efe8fa42e8566373581d4b969c4a59e96a0ef51b711fe5027ec01601182519d0a788f4bfe388e593b97cd1d7e44904de79422430bca686ac8c21305b3397b5ba4d7037d17877312fb7ee34";
|
|
42
|
+
function loadLocalCanisterIds(rootDir) {
|
|
43
|
+
const idsPath = import_path.default.resolve(rootDir, ICP_LOCAL_IDS_PATH);
|
|
44
|
+
try {
|
|
45
|
+
return JSON.parse(import_fs.default.readFileSync(idsPath, "utf-8"));
|
|
46
|
+
} catch {
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
53
49
|
}
|
|
54
|
-
function
|
|
55
|
-
const
|
|
56
|
-
const
|
|
57
|
-
|
|
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
|
-
});
|
|
50
|
+
function buildIcEnvCookie(canisterIds) {
|
|
51
|
+
const envParts = [`ic_root_key=${IC_ROOT_KEY_HEX}`];
|
|
52
|
+
for (const [name, id] of Object.entries(canisterIds)) {
|
|
53
|
+
envParts.push(`PUBLIC_CANISTER_ID:${name}=${id}`);
|
|
67
54
|
}
|
|
68
|
-
return
|
|
55
|
+
return encodeURIComponent(envParts.join("&"));
|
|
69
56
|
}
|
|
70
|
-
function
|
|
71
|
-
const
|
|
72
|
-
const
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
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
|
-
`;
|
|
57
|
+
function addOrReplaceSetCookie(existing, cookie) {
|
|
58
|
+
const cookieEntries = typeof existing === "string" ? [existing] : Array.isArray(existing) ? existing.filter((value) => typeof value === "string") : [];
|
|
59
|
+
const nonIcEnvCookies = cookieEntries.filter(
|
|
60
|
+
(entry) => !entry.trim().startsWith("ic_env=")
|
|
61
|
+
);
|
|
62
|
+
return [...nonIcEnvCookies, cookie];
|
|
193
63
|
}
|
|
194
|
-
function
|
|
195
|
-
const
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
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
|
|
216
|
-
}
|
|
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;
|
|
237
|
-
}
|
|
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);
|
|
246
|
-
console.log(
|
|
247
|
-
`[ic-reactor] Advanced reactor hooks generated at ${reactorPath}`
|
|
64
|
+
function setupIcEnvMiddleware(server) {
|
|
65
|
+
const rootDir = server.config.root || process.cwd();
|
|
66
|
+
const idsPath = import_path.default.resolve(rootDir, ICP_LOCAL_IDS_PATH);
|
|
67
|
+
let hasLoggedHint = false;
|
|
68
|
+
server.middlewares.use((req, res, next) => {
|
|
69
|
+
const canisterIds = loadLocalCanisterIds(rootDir);
|
|
70
|
+
if (!canisterIds) {
|
|
71
|
+
if (!hasLoggedHint) {
|
|
72
|
+
server.config.logger.info(
|
|
73
|
+
`[ic-reactor] icp-cli local IDs not found at ${idsPath}. Run \`icp deploy\` to enable automatic ic_env cookie injection.`
|
|
248
74
|
);
|
|
75
|
+
hasLoggedHint = true;
|
|
249
76
|
}
|
|
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) {
|
|
257
|
-
console.log(
|
|
258
|
-
`[ic-reactor] Detected change in ${file}, regenerating...`
|
|
259
|
-
);
|
|
260
|
-
server.restart();
|
|
261
|
-
}
|
|
262
|
-
}
|
|
77
|
+
return next();
|
|
263
78
|
}
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
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
|
-
`;
|
|
79
|
+
const cookie = `ic_env=${buildIcEnvCookie(canisterIds)}; Path=/; SameSite=Lax;`;
|
|
80
|
+
const current = res.getHeader("Set-Cookie");
|
|
81
|
+
res.setHeader("Set-Cookie", addOrReplaceSetCookie(current, cookie));
|
|
82
|
+
next();
|
|
83
|
+
});
|
|
353
84
|
}
|
|
354
85
|
function icReactorPlugin(options) {
|
|
355
86
|
const baseOutDir = options.outDir ?? "./src/canisters";
|
|
356
87
|
return {
|
|
357
88
|
name: "ic-reactor-plugin",
|
|
89
|
+
configureServer(server) {
|
|
90
|
+
if (options.autoInjectIcEnv ?? true) {
|
|
91
|
+
setupIcEnvMiddleware(server);
|
|
92
|
+
}
|
|
93
|
+
},
|
|
358
94
|
async buildStart() {
|
|
359
95
|
for (const canister of options.canisters) {
|
|
360
|
-
const outDir = canister.outDir ??
|
|
361
|
-
const declarationsDir = import_path2.default.join(outDir, "declarations");
|
|
96
|
+
const outDir = canister.outDir ?? import_path.default.join(baseOutDir, canister.name);
|
|
362
97
|
console.log(
|
|
363
98
|
`[ic-reactor] Generating hooks for ${canister.name} from ${canister.didFile}`
|
|
364
99
|
);
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
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}`
|
|
100
|
+
const result = await (0, import_codegen.generateDeclarations)({
|
|
101
|
+
didFile: canister.didFile,
|
|
102
|
+
outDir,
|
|
103
|
+
canisterName: canister.name
|
|
104
|
+
});
|
|
105
|
+
if (!result.success) {
|
|
106
|
+
console.error(
|
|
107
|
+
`[ic-reactor] Failed to generate declarations: ${result.error}`
|
|
386
108
|
);
|
|
387
|
-
} catch (error) {
|
|
388
|
-
console.error(`[ic-reactor] Failed to generate declarations:`, error);
|
|
389
109
|
continue;
|
|
390
110
|
}
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
canister.name,
|
|
394
|
-
canister.useDisplayReactor ?? true,
|
|
395
|
-
clientManagerPath
|
|
111
|
+
console.log(
|
|
112
|
+
`[ic-reactor] Declarations generated at ${result.declarationsDir}`
|
|
396
113
|
);
|
|
397
|
-
const
|
|
398
|
-
|
|
399
|
-
|
|
114
|
+
const useAdvanced = canister.advanced ?? options.advanced ?? false;
|
|
115
|
+
let didContent;
|
|
116
|
+
if (useAdvanced) {
|
|
117
|
+
try {
|
|
118
|
+
didContent = import_fs.default.readFileSync(canister.didFile, "utf-8");
|
|
119
|
+
} catch (e) {
|
|
120
|
+
console.warn(
|
|
121
|
+
`[ic-reactor] Could not read DID file at ${canister.didFile}, skipping advanced hook generation for ${canister.name}.`
|
|
122
|
+
);
|
|
123
|
+
continue;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
const reactorContent = (0, import_codegen.generateReactorFile)({
|
|
127
|
+
canisterName: canister.name,
|
|
128
|
+
canisterConfig: canister,
|
|
129
|
+
globalClientManagerPath: options.clientManagerPath,
|
|
130
|
+
hasDeclarations: true,
|
|
131
|
+
advanced: useAdvanced,
|
|
132
|
+
didContent
|
|
133
|
+
});
|
|
134
|
+
const reactorPath = import_path.default.join(outDir, "index.ts");
|
|
135
|
+
import_fs.default.mkdirSync(outDir, { recursive: true });
|
|
136
|
+
import_fs.default.writeFileSync(reactorPath, reactorContent);
|
|
400
137
|
console.log(`[ic-reactor] Reactor hooks generated at ${reactorPath}`);
|
|
401
138
|
}
|
|
402
139
|
},
|
|
403
140
|
handleHotUpdate({ file, server }) {
|
|
404
141
|
if (file.endsWith(".did")) {
|
|
405
142
|
const canister = options.canisters.find(
|
|
406
|
-
(c) =>
|
|
143
|
+
(c) => import_path.default.resolve(c.didFile) === file
|
|
407
144
|
);
|
|
408
145
|
if (canister) {
|
|
409
146
|
console.log(
|
|
@@ -415,8 +152,8 @@ function icReactorPlugin(options) {
|
|
|
415
152
|
}
|
|
416
153
|
};
|
|
417
154
|
}
|
|
155
|
+
var index_default = icReactorPlugin;
|
|
418
156
|
// Annotate the CommonJS export names for ESM import in node:
|
|
419
157
|
0 && (module.exports = {
|
|
420
|
-
icReactorAdvancedPlugin,
|
|
421
158
|
icReactorPlugin
|
|
422
159
|
});
|
package/dist/index.d.cts
CHANGED
|
@@ -1,18 +1,12 @@
|
|
|
1
1
|
import { Plugin } from 'vite';
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
import { CanisterConfig } from '@ic-reactor/codegen';
|
|
3
|
+
export { CanisterConfig } from '@ic-reactor/codegen';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* IC-Reactor Vite Plugin
|
|
7
7
|
*
|
|
8
8
|
* 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.
|
|
9
|
+
* Uses @ic-reactor/codegen for all code generation logic.
|
|
16
10
|
*
|
|
17
11
|
* Usage:
|
|
18
12
|
* ```ts
|
|
@@ -25,7 +19,7 @@ declare function icReactorAdvancedPlugin(options: IcReactorPluginOptions): Plugi
|
|
|
25
19
|
* {
|
|
26
20
|
* name: "backend",
|
|
27
21
|
* didFile: "../backend/backend.did",
|
|
28
|
-
* clientManagerPath: "../lib/client"
|
|
22
|
+
* clientManagerPath: "../lib/client"
|
|
29
23
|
* }
|
|
30
24
|
* ]
|
|
31
25
|
* })
|
|
@@ -34,34 +28,32 @@ declare function icReactorAdvancedPlugin(options: IcReactorPluginOptions): Plugi
|
|
|
34
28
|
* ```
|
|
35
29
|
*/
|
|
36
30
|
|
|
37
|
-
interface CanisterConfig {
|
|
38
|
-
/** Name of the canister (used for variable naming) */
|
|
39
|
-
name: string;
|
|
40
|
-
/** Path to the .did file */
|
|
41
|
-
didFile: string;
|
|
42
|
-
/** Output directory (default: ./src/canisters/<name>) */
|
|
43
|
-
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
|
-
*/
|
|
51
|
-
clientManagerPath?: string;
|
|
52
|
-
}
|
|
53
31
|
interface IcReactorPluginOptions {
|
|
54
32
|
/** List of canisters to generate hooks for */
|
|
55
|
-
canisters: CanisterConfig
|
|
33
|
+
canisters: (CanisterConfig & {
|
|
34
|
+
name: string;
|
|
35
|
+
advanced?: boolean;
|
|
36
|
+
})[];
|
|
56
37
|
/** Base output directory (default: ./src/canisters) */
|
|
57
38
|
outDir?: string;
|
|
58
39
|
/**
|
|
59
40
|
* Path to import ClientManager from (relative to generated file).
|
|
60
|
-
* The file at this path should export: { clientManager: ClientManager }
|
|
61
41
|
* Default: "../../lib/client"
|
|
62
42
|
*/
|
|
63
43
|
clientManagerPath?: string;
|
|
44
|
+
/**
|
|
45
|
+
* Generate advanced per-method hooks with createQuery/createMutation
|
|
46
|
+
* instead of generic actor hooks (default: false).
|
|
47
|
+
* Can be overridden per-canister by setting `advanced` on the individual canister entry.
|
|
48
|
+
*/
|
|
49
|
+
advanced?: boolean;
|
|
50
|
+
/**
|
|
51
|
+
* Automatically set the `ic_env` cookie in Vite dev server from
|
|
52
|
+
* `.icp/cache/mappings/local.ids.json` (default: true).
|
|
53
|
+
*/
|
|
54
|
+
autoInjectIcEnv?: boolean;
|
|
64
55
|
}
|
|
56
|
+
|
|
65
57
|
declare function icReactorPlugin(options: IcReactorPluginOptions): Plugin;
|
|
66
58
|
|
|
67
|
-
export { type
|
|
59
|
+
export { type IcReactorPluginOptions, icReactorPlugin as default, icReactorPlugin };
|