@ic-reactor/vite-plugin 0.8.0 → 0.10.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 +12 -2
- package/dist/index.cjs +23 -20
- package/dist/index.d.cts +6 -1
- package/dist/index.d.ts +6 -1
- package/dist/index.js +23 -20
- package/package.json +5 -5
- package/src/env.ts +2 -5
- package/src/index.test.ts +23 -2
- package/src/index.ts +37 -27
package/README.md
CHANGED
|
@@ -31,7 +31,7 @@ export default defineConfig({
|
|
|
31
31
|
|
|
32
32
|
```ts
|
|
33
33
|
// src/clients.ts
|
|
34
|
-
import { ClientManager } from "@ic-reactor/
|
|
34
|
+
import { ClientManager } from "@ic-reactor/core"
|
|
35
35
|
import { QueryClient } from "@tanstack/react-query"
|
|
36
36
|
|
|
37
37
|
export const queryClient = new QueryClient()
|
|
@@ -43,6 +43,9 @@ export const clientManager = new ClientManager({
|
|
|
43
43
|
|
|
44
44
|
The plugin generates files under `src/declarations/<canister>/` by default.
|
|
45
45
|
|
|
46
|
+
If you want non-React output, set `target: "core"` and install the matching
|
|
47
|
+
runtime package instead of `@ic-reactor/react`.
|
|
48
|
+
|
|
46
49
|
## Options
|
|
47
50
|
|
|
48
51
|
```ts
|
|
@@ -56,6 +59,7 @@ icReactor({
|
|
|
56
59
|
],
|
|
57
60
|
outDir: "src/declarations",
|
|
58
61
|
clientManagerPath: "../../clients",
|
|
62
|
+
target: "react",
|
|
59
63
|
injectEnvironment: true,
|
|
60
64
|
})
|
|
61
65
|
```
|
|
@@ -66,6 +70,7 @@ icReactor({
|
|
|
66
70
|
- `didFile`
|
|
67
71
|
- `outDir`
|
|
68
72
|
- `clientManagerPath`
|
|
73
|
+
- `target`
|
|
69
74
|
- `mode`
|
|
70
75
|
- `canisterId`
|
|
71
76
|
|
|
@@ -77,11 +82,16 @@ Supported `mode` values:
|
|
|
77
82
|
- `CandidDisplayReactor`
|
|
78
83
|
- `MetadataDisplayReactor`
|
|
79
84
|
|
|
85
|
+
Supported `target` values:
|
|
86
|
+
|
|
87
|
+
- `react` (default): generates the reactor plus bound React hooks
|
|
88
|
+
- `core`: generates only the typed reactor exports with no React dependency
|
|
89
|
+
|
|
80
90
|
## Local Development Behavior
|
|
81
91
|
|
|
82
92
|
When `injectEnvironment` is enabled during `vite dev`, the plugin:
|
|
83
93
|
|
|
84
|
-
1. asks `icp
|
|
94
|
+
1. asks `icp` for the local network status
|
|
85
95
|
2. resolves configured canister IDs
|
|
86
96
|
3. sets the `ic_env` cookie
|
|
87
97
|
4. proxies `/api` to the local replica
|
package/dist/index.cjs
CHANGED
|
@@ -83,11 +83,13 @@ function icReactor(options) {
|
|
|
83
83
|
canisters,
|
|
84
84
|
outDir = "src/declarations",
|
|
85
85
|
clientManagerPath = "../../clients",
|
|
86
|
+
target = "react",
|
|
86
87
|
injectEnvironment = true
|
|
87
88
|
} = options;
|
|
88
89
|
const globalConfig = {
|
|
89
90
|
outDir,
|
|
90
|
-
clientManagerPath
|
|
91
|
+
clientManagerPath,
|
|
92
|
+
target
|
|
91
93
|
};
|
|
92
94
|
const projectRoot = process.cwd();
|
|
93
95
|
const resolveDidPath = (didFile) => import_node_path.default.normalize(
|
|
@@ -100,7 +102,7 @@ function icReactor(options) {
|
|
|
100
102
|
name: "ic-reactor-plugin",
|
|
101
103
|
enforce: "pre",
|
|
102
104
|
// Run before other plugins
|
|
103
|
-
config(
|
|
105
|
+
config(_config, { command }) {
|
|
104
106
|
if (command !== "serve" || !injectEnvironment) {
|
|
105
107
|
return {};
|
|
106
108
|
}
|
|
@@ -148,28 +150,29 @@ function icReactor(options) {
|
|
|
148
150
|
},
|
|
149
151
|
async buildStart() {
|
|
150
152
|
console.log(
|
|
151
|
-
`[ic-reactor] Generating
|
|
153
|
+
`[ic-reactor] Generating canister bindings for ${canisters.length} canisters...`
|
|
152
154
|
);
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
155
|
+
await Promise.allSettled(
|
|
156
|
+
canisters.map(async (canisterConfig) => {
|
|
157
|
+
try {
|
|
158
|
+
const result = await (0, import_codegen.runCanisterPipeline)({
|
|
159
|
+
canisterConfig,
|
|
160
|
+
projectRoot,
|
|
161
|
+
globalConfig
|
|
162
|
+
});
|
|
163
|
+
if (!result.success) {
|
|
164
|
+
console.error(
|
|
165
|
+
`[ic-reactor] Failed to generate ${canisterConfig.name}: ${result.error}`
|
|
166
|
+
);
|
|
167
|
+
}
|
|
168
|
+
} catch (err) {
|
|
161
169
|
console.error(
|
|
162
|
-
`[ic-reactor]
|
|
170
|
+
`[ic-reactor] Error generating ${canisterConfig.name}:`,
|
|
171
|
+
err
|
|
163
172
|
);
|
|
164
|
-
} else {
|
|
165
173
|
}
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
`[ic-reactor] Error generating ${canisterConfig.name}:`,
|
|
169
|
-
err
|
|
170
|
-
);
|
|
171
|
-
}
|
|
172
|
-
}
|
|
174
|
+
})
|
|
175
|
+
);
|
|
173
176
|
},
|
|
174
177
|
handleHotUpdate({ file, server }) {
|
|
175
178
|
if (file.endsWith(".did")) {
|
package/dist/index.d.cts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { CanisterConfig } from '@ic-reactor/codegen';
|
|
1
|
+
import { CanisterConfig, CodegenTarget } from '@ic-reactor/codegen';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* @ic-reactor/vite-plugin
|
|
@@ -25,6 +25,11 @@ interface IcReactorPluginOptions {
|
|
|
25
25
|
* Default: "../../clients"
|
|
26
26
|
*/
|
|
27
27
|
clientManagerPath?: string;
|
|
28
|
+
/**
|
|
29
|
+
* Default generated runtime target.
|
|
30
|
+
* Default: "react"
|
|
31
|
+
*/
|
|
32
|
+
target?: CodegenTarget;
|
|
28
33
|
/**
|
|
29
34
|
* Automatically inject `ic_env` cookie for local development?
|
|
30
35
|
* Default: true
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { CanisterConfig } from '@ic-reactor/codegen';
|
|
1
|
+
import { CanisterConfig, CodegenTarget } from '@ic-reactor/codegen';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* @ic-reactor/vite-plugin
|
|
@@ -25,6 +25,11 @@ interface IcReactorPluginOptions {
|
|
|
25
25
|
* Default: "../../clients"
|
|
26
26
|
*/
|
|
27
27
|
clientManagerPath?: string;
|
|
28
|
+
/**
|
|
29
|
+
* Default generated runtime target.
|
|
30
|
+
* Default: "react"
|
|
31
|
+
*/
|
|
32
|
+
target?: CodegenTarget;
|
|
28
33
|
/**
|
|
29
34
|
* Automatically inject `ic_env` cookie for local development?
|
|
30
35
|
* Default: true
|
package/dist/index.js
CHANGED
|
@@ -51,11 +51,13 @@ function icReactor(options) {
|
|
|
51
51
|
canisters,
|
|
52
52
|
outDir = "src/declarations",
|
|
53
53
|
clientManagerPath = "../../clients",
|
|
54
|
+
target = "react",
|
|
54
55
|
injectEnvironment = true
|
|
55
56
|
} = options;
|
|
56
57
|
const globalConfig = {
|
|
57
58
|
outDir,
|
|
58
|
-
clientManagerPath
|
|
59
|
+
clientManagerPath,
|
|
60
|
+
target
|
|
59
61
|
};
|
|
60
62
|
const projectRoot = process.cwd();
|
|
61
63
|
const resolveDidPath = (didFile) => path.normalize(
|
|
@@ -68,7 +70,7 @@ function icReactor(options) {
|
|
|
68
70
|
name: "ic-reactor-plugin",
|
|
69
71
|
enforce: "pre",
|
|
70
72
|
// Run before other plugins
|
|
71
|
-
config(
|
|
73
|
+
config(_config, { command }) {
|
|
72
74
|
if (command !== "serve" || !injectEnvironment) {
|
|
73
75
|
return {};
|
|
74
76
|
}
|
|
@@ -116,28 +118,29 @@ function icReactor(options) {
|
|
|
116
118
|
},
|
|
117
119
|
async buildStart() {
|
|
118
120
|
console.log(
|
|
119
|
-
`[ic-reactor] Generating
|
|
121
|
+
`[ic-reactor] Generating canister bindings for ${canisters.length} canisters...`
|
|
120
122
|
);
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
123
|
+
await Promise.allSettled(
|
|
124
|
+
canisters.map(async (canisterConfig) => {
|
|
125
|
+
try {
|
|
126
|
+
const result = await runCanisterPipeline({
|
|
127
|
+
canisterConfig,
|
|
128
|
+
projectRoot,
|
|
129
|
+
globalConfig
|
|
130
|
+
});
|
|
131
|
+
if (!result.success) {
|
|
132
|
+
console.error(
|
|
133
|
+
`[ic-reactor] Failed to generate ${canisterConfig.name}: ${result.error}`
|
|
134
|
+
);
|
|
135
|
+
}
|
|
136
|
+
} catch (err) {
|
|
129
137
|
console.error(
|
|
130
|
-
`[ic-reactor]
|
|
138
|
+
`[ic-reactor] Error generating ${canisterConfig.name}:`,
|
|
139
|
+
err
|
|
131
140
|
);
|
|
132
|
-
} else {
|
|
133
141
|
}
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
`[ic-reactor] Error generating ${canisterConfig.name}:`,
|
|
137
|
-
err
|
|
138
|
-
);
|
|
139
|
-
}
|
|
140
|
-
}
|
|
142
|
+
})
|
|
143
|
+
);
|
|
141
144
|
},
|
|
142
145
|
handleHotUpdate({ file, server }) {
|
|
143
146
|
if (file.endsWith(".did")) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ic-reactor/vite-plugin",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.0",
|
|
4
4
|
"description": "Vite plugin for zero-config IC reactor generation from Candid files",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
@@ -37,17 +37,17 @@
|
|
|
37
37
|
"url": "https://github.com/B3Pay/ic-reactor/issues"
|
|
38
38
|
},
|
|
39
39
|
"dependencies": {
|
|
40
|
-
"@ic-reactor/codegen": "0.
|
|
40
|
+
"@ic-reactor/codegen": "0.10.0"
|
|
41
41
|
},
|
|
42
42
|
"peerDependencies": {
|
|
43
43
|
"vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0"
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|
|
46
|
-
"@icp-sdk/bindgen": "^0.
|
|
47
|
-
"@types/node": "^25.
|
|
46
|
+
"@icp-sdk/bindgen": "^0.3.0",
|
|
47
|
+
"@types/node": "^25.5.2",
|
|
48
48
|
"tsup": "^8.5.1",
|
|
49
49
|
"typescript": "^5.9.3",
|
|
50
|
-
"vitest": "^4.
|
|
50
|
+
"vitest": "^4.1.2"
|
|
51
51
|
},
|
|
52
52
|
"scripts": {
|
|
53
53
|
"build": "tsup src/index.ts --format esm,cjs --dts --tsconfig tsconfig.json",
|
package/src/env.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Environment Injection Utilities
|
|
3
3
|
*
|
|
4
|
-
* Handles detecting the local IC environment
|
|
4
|
+
* Handles detecting the local IC environment via the `icp` CLI
|
|
5
5
|
* and building the `ic_env` cookie for the browser.
|
|
6
6
|
*/
|
|
7
7
|
|
|
@@ -15,16 +15,13 @@ export interface IcEnvironment {
|
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
/**
|
|
18
|
-
* Detect the IC environment using the `icp`
|
|
18
|
+
* Detect the IC environment using the `icp` CLI.
|
|
19
19
|
*/
|
|
20
20
|
export function getIcEnvironmentInfo(
|
|
21
21
|
canisterNames: string[]
|
|
22
22
|
): IcEnvironment | null {
|
|
23
23
|
const environment = process.env.ICP_ENVIRONMENT || "local"
|
|
24
24
|
|
|
25
|
-
// We try `icp` first, but could fallback to `dfx` logic if needed.
|
|
26
|
-
// For now, assuming `icp` CLI is available based on previous code.
|
|
27
|
-
|
|
28
25
|
try {
|
|
29
26
|
const networkStatus = JSON.parse(
|
|
30
27
|
execFileSync("icp", ["network", "status", "-e", environment, "--json"], {
|
package/src/index.test.ts
CHANGED
|
@@ -78,7 +78,7 @@ describe("icReactor", () => {
|
|
|
78
78
|
describe("config", () => {
|
|
79
79
|
it("should set up API proxy and headers when icp-cli is available", () => {
|
|
80
80
|
;(execFileSync as any).mockImplementation(
|
|
81
|
-
(command: string, args: string[],
|
|
81
|
+
(command: string, args: string[], _options: any) => {
|
|
82
82
|
if (
|
|
83
83
|
command === "icp" &&
|
|
84
84
|
args.includes("network") &&
|
|
@@ -112,7 +112,7 @@ describe("icReactor", () => {
|
|
|
112
112
|
|
|
113
113
|
it("should prefer configured canisterId over CLI-discovered env values", () => {
|
|
114
114
|
;(execFileSync as any).mockImplementation(
|
|
115
|
-
(command: string, args: string[],
|
|
115
|
+
(command: string, args: string[], _options: any) => {
|
|
116
116
|
if (
|
|
117
117
|
command === "icp" &&
|
|
118
118
|
args.includes("network") &&
|
|
@@ -181,6 +181,7 @@ describe("icReactor", () => {
|
|
|
181
181
|
globalConfig: {
|
|
182
182
|
outDir: "src/declarations",
|
|
183
183
|
clientManagerPath: "../../clients",
|
|
184
|
+
target: "react",
|
|
184
185
|
},
|
|
185
186
|
})
|
|
186
187
|
})
|
|
@@ -227,6 +228,26 @@ describe("icReactor", () => {
|
|
|
227
228
|
globalConfig: {
|
|
228
229
|
outDir: "src/declarations",
|
|
229
230
|
clientManagerPath: "../../clients",
|
|
231
|
+
target: "react",
|
|
232
|
+
},
|
|
233
|
+
})
|
|
234
|
+
})
|
|
235
|
+
|
|
236
|
+
it("should pass the configured runtime target to codegen", async () => {
|
|
237
|
+
const plugin = createVitePlugin({
|
|
238
|
+
...mockOptions,
|
|
239
|
+
target: "core",
|
|
240
|
+
})
|
|
241
|
+
|
|
242
|
+
await (plugin.buildStart as any)()
|
|
243
|
+
|
|
244
|
+
expect(runCanisterPipeline).toHaveBeenCalledWith({
|
|
245
|
+
canisterConfig: mockOptions.canisters[0],
|
|
246
|
+
projectRoot: expect.any(String),
|
|
247
|
+
globalConfig: {
|
|
248
|
+
outDir: "src/declarations",
|
|
249
|
+
clientManagerPath: "../../clients",
|
|
250
|
+
target: "core",
|
|
230
251
|
},
|
|
231
252
|
})
|
|
232
253
|
})
|
package/src/index.ts
CHANGED
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
runCanisterPipeline,
|
|
14
14
|
type CanisterConfig,
|
|
15
15
|
type CodegenConfig,
|
|
16
|
+
type CodegenTarget,
|
|
16
17
|
} from "@ic-reactor/codegen"
|
|
17
18
|
import { getIcEnvironmentInfo, buildIcEnvCookie } from "./env.js"
|
|
18
19
|
|
|
@@ -32,6 +33,11 @@ export interface IcReactorPluginOptions {
|
|
|
32
33
|
* Default: "../../clients"
|
|
33
34
|
*/
|
|
34
35
|
clientManagerPath?: string
|
|
36
|
+
/**
|
|
37
|
+
* Default generated runtime target.
|
|
38
|
+
* Default: "react"
|
|
39
|
+
*/
|
|
40
|
+
target?: CodegenTarget
|
|
35
41
|
/**
|
|
36
42
|
* Automatically inject `ic_env` cookie for local development?
|
|
37
43
|
* Default: true
|
|
@@ -44,13 +50,18 @@ export function icReactor(options: IcReactorPluginOptions): any {
|
|
|
44
50
|
canisters,
|
|
45
51
|
outDir = "src/declarations",
|
|
46
52
|
clientManagerPath = "../../clients",
|
|
53
|
+
target = "react",
|
|
47
54
|
injectEnvironment = true,
|
|
48
55
|
} = options
|
|
49
56
|
|
|
50
57
|
// Construct a partial CodegenConfig to pass to the pipeline
|
|
51
|
-
const globalConfig: Pick<
|
|
58
|
+
const globalConfig: Pick<
|
|
59
|
+
CodegenConfig,
|
|
60
|
+
"outDir" | "clientManagerPath" | "target"
|
|
61
|
+
> = {
|
|
52
62
|
outDir,
|
|
53
63
|
clientManagerPath,
|
|
64
|
+
target,
|
|
54
65
|
}
|
|
55
66
|
const projectRoot = process.cwd()
|
|
56
67
|
const resolveDidPath = (didFile: string) =>
|
|
@@ -67,7 +78,7 @@ export function icReactor(options: IcReactorPluginOptions): any {
|
|
|
67
78
|
name: "ic-reactor-plugin",
|
|
68
79
|
enforce: "pre", // Run before other plugins
|
|
69
80
|
|
|
70
|
-
config(
|
|
81
|
+
config(_config, { command }) {
|
|
71
82
|
if (command !== "serve" || !injectEnvironment) {
|
|
72
83
|
return {}
|
|
73
84
|
}
|
|
@@ -131,36 +142,35 @@ export function icReactor(options: IcReactorPluginOptions): any {
|
|
|
131
142
|
// ── Code Generation ──────────────────────────────────────────────────
|
|
132
143
|
|
|
133
144
|
console.log(
|
|
134
|
-
`[ic-reactor] Generating
|
|
145
|
+
`[ic-reactor] Generating canister bindings for ${canisters.length} canisters...`
|
|
135
146
|
)
|
|
136
147
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
148
|
+
await Promise.allSettled(
|
|
149
|
+
canisters.map(async (canisterConfig) => {
|
|
150
|
+
try {
|
|
151
|
+
// If .did file is missing, we might want to attempt pulling it?
|
|
152
|
+
// For now, pipeline fails if missing. The old plugin logic to "download"
|
|
153
|
+
// is omitted for simplicity unless requested, to keep "codegen" pure.
|
|
154
|
+
|
|
155
|
+
const result = await runCanisterPipeline({
|
|
156
|
+
canisterConfig,
|
|
157
|
+
projectRoot,
|
|
158
|
+
globalConfig,
|
|
159
|
+
})
|
|
160
|
+
|
|
161
|
+
if (!result.success) {
|
|
162
|
+
console.error(
|
|
163
|
+
`[ic-reactor] Failed to generate ${canisterConfig.name}: ${result.error}`
|
|
164
|
+
)
|
|
165
|
+
}
|
|
166
|
+
} catch (err) {
|
|
150
167
|
console.error(
|
|
151
|
-
`[ic-reactor]
|
|
168
|
+
`[ic-reactor] Error generating ${canisterConfig.name}:`,
|
|
169
|
+
err
|
|
152
170
|
)
|
|
153
|
-
} else {
|
|
154
|
-
// Optional: log success
|
|
155
|
-
// console.log(`[ic-reactor] Generated ${canisterConfig.name} hooks`)
|
|
156
171
|
}
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
`[ic-reactor] Error generating ${canisterConfig.name}:`,
|
|
160
|
-
err
|
|
161
|
-
)
|
|
162
|
-
}
|
|
163
|
-
}
|
|
172
|
+
})
|
|
173
|
+
)
|
|
164
174
|
},
|
|
165
175
|
|
|
166
176
|
handleHotUpdate({ file, server }) {
|