@ic-reactor/vite-plugin 0.1.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 ADDED
@@ -0,0 +1,323 @@
1
+ # @ic-reactor/vite-plugin
2
+
3
+ <div align="center">
4
+ <strong>Zero-config Vite plugin for auto-generating IC reactor hooks from Candid files.</strong>
5
+ <br><br>
6
+
7
+ [![npm version](https://img.shields.io/npm/v/@ic-reactor/vite-plugin.svg)](https://www.npmjs.com/package/@ic-reactor/vite-plugin)
8
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
9
+ [![TypeScript](https://img.shields.io/badge/TypeScript-5.0+-blue.svg)](https://www.typescriptlang.org/)
10
+ </div>
11
+
12
+ ---
13
+
14
+ Automatically generate type-safe React hooks for your Internet Computer canisters. This plugin watches your `.did` files and generates ready-to-use hooks with full TypeScript support.
15
+
16
+ ## Features
17
+
18
+ - ⚡ **Zero Config** — Point to your `.did` file and get hooks instantly
19
+ - 🔄 **Hot Reload** — Automatically regenerates hooks when `.did` files change
20
+ - 📦 **TypeScript Declarations** — Full type safety with auto-generated types
21
+ - 🎯 **Display Types** — Optional `DisplayReactor` support for React-friendly types
22
+ - 🔌 **Flexible** — Works with any `ClientManager` configuration
23
+
24
+ ## Installation
25
+
26
+ ```bash
27
+ # With npm
28
+ npm install -D @ic-reactor/vite-plugin
29
+
30
+ # With pnpm
31
+ pnpm add -D @ic-reactor/vite-plugin
32
+
33
+ # Required peer dependencies
34
+ npm install @ic-reactor/react @tanstack/react-query @icp-sdk/core
35
+ npm install -D @icp-sdk/bindgen
36
+ ```
37
+
38
+ ## Quick Start
39
+
40
+ ### 1. Configure the Plugin
41
+
42
+ ```typescript
43
+ // vite.config.ts
44
+ import { defineConfig } from "vite"
45
+ import react from "@vitejs/plugin-react"
46
+ import { icReactorPlugin } from "@ic-reactor/vite-plugin"
47
+
48
+ export default defineConfig({
49
+ plugins: [
50
+ react(),
51
+ icReactorPlugin({
52
+ canisters: [
53
+ {
54
+ name: "backend",
55
+ didFile: "./backend/backend.did",
56
+ },
57
+ ],
58
+ }),
59
+ ],
60
+ })
61
+ ```
62
+
63
+ ### 2. Create Your ClientManager
64
+
65
+ The plugin expects you to have a `ClientManager` exported from a file. By default, it looks for `./src/lib/client.ts`:
66
+
67
+ ```typescript
68
+ // src/lib/client.ts
69
+ import { ClientManager } from "@ic-reactor/react"
70
+ import { QueryClient } from "@tanstack/react-query"
71
+
72
+ export const queryClient = new QueryClient()
73
+
74
+ export const clientManager = new ClientManager({
75
+ queryClient,
76
+ withCanisterEnv: true, // Enable environment-based canister ID resolution
77
+ })
78
+ ```
79
+
80
+ ### 3. Use Generated Hooks
81
+
82
+ The plugin generates hooks in `./src/canisters/<name>/index.ts`:
83
+
84
+ ```tsx
85
+ // Generated at: ./src/canisters/backend/index.ts
86
+ import {
87
+ backendReactor,
88
+ useBackendQuery,
89
+ useBackendMutation,
90
+ useBackendSuspenseQuery,
91
+ } from "./canisters/backend"
92
+
93
+ function MyComponent() {
94
+ // Query data
95
+ const { data, isPending } = useBackendQuery({
96
+ functionName: "get_message",
97
+ })
98
+
99
+ // Mutate data
100
+ const { mutate } = useBackendMutation({
101
+ functionName: "set_message",
102
+ onSuccess: () => console.log("Message updated!"),
103
+ })
104
+
105
+ return (
106
+ <div>
107
+ <p>{isPending ? "Loading..." : data}</p>
108
+ <button onClick={() => mutate(["Hello IC!"])}>Update</button>
109
+ </div>
110
+ )
111
+ }
112
+ ```
113
+
114
+ ## Configuration
115
+
116
+ ### Plugin Options
117
+
118
+ ```typescript
119
+ interface IcReactorPluginOptions {
120
+ /** List of canisters to generate hooks for */
121
+ canisters: CanisterConfig[]
122
+ /** Base output directory (default: "./src/canisters") */
123
+ outDir?: string
124
+ /** Path to import ClientManager from (default: "../../lib/client") */
125
+ clientManagerPath?: string
126
+ }
127
+
128
+ interface CanisterConfig {
129
+ /** Name of the canister (used for variable naming) */
130
+ name: string
131
+ /** Path to the .did file */
132
+ didFile: string
133
+ /** Output directory (default: ./src/canisters/<name>) */
134
+ outDir?: string
135
+ /** Use DisplayReactor for React-friendly types (default: true) */
136
+ useDisplayReactor?: boolean
137
+ /** Path to import ClientManager from (relative to generated file) */
138
+ clientManagerPath?: string
139
+ }
140
+ ```
141
+
142
+ ### Example: Multiple Canisters
143
+
144
+ ```typescript
145
+ // vite.config.ts
146
+ import { icReactorPlugin } from "@ic-reactor/vite-plugin"
147
+
148
+ export default defineConfig({
149
+ plugins: [
150
+ icReactorPlugin({
151
+ clientManagerPath: "@/lib/client", // Global default
152
+ canisters: [
153
+ {
154
+ name: "backend",
155
+ didFile: "./backend/backend.did",
156
+ },
157
+ {
158
+ name: "ledger",
159
+ didFile: "./ledger/ledger.did",
160
+ useDisplayReactor: true, // BigInt → string, etc.
161
+ },
162
+ {
163
+ name: "nft",
164
+ didFile: "./nft/nft.did",
165
+ outDir: "./src/services/nft", // Custom output
166
+ clientManagerPath: "@/lib/nft-client", // Custom client
167
+ },
168
+ ],
169
+ }),
170
+ ],
171
+ })
172
+ ```
173
+
174
+ ## Advanced Plugin
175
+
176
+ For more granular control, use `icReactorAdvancedPlugin` which generates individual hooks per method:
177
+
178
+ ```typescript
179
+ import { icReactorAdvancedPlugin } from "@ic-reactor/vite-plugin"
180
+
181
+ export default defineConfig({
182
+ plugins: [
183
+ icReactorAdvancedPlugin({
184
+ canisters: [
185
+ {
186
+ name: "backend",
187
+ didFile: "./backend/backend.did",
188
+ },
189
+ ],
190
+ }),
191
+ ],
192
+ })
193
+ ```
194
+
195
+ This generates method-specific hooks:
196
+
197
+ ```tsx
198
+ import {
199
+ useGetMessageQuery,
200
+ useSetMessageMutation,
201
+ getMessageQuery, // Static query for no-arg methods
202
+ } from "./canisters/backend"
203
+
204
+ function MyComponent() {
205
+ // Method-specific hook
206
+ const { data } = useGetMessageQuery([], { staleTime: 5000 })
207
+
208
+ // Static query usage
209
+ const { data: cached } = getMessageQuery.useQuery()
210
+
211
+ const { mutate } = useSetMessageMutation()
212
+
213
+ return <div>{data}</div>
214
+ }
215
+ ```
216
+
217
+ ## Generated File Structure
218
+
219
+ ```
220
+ src/
221
+ ├── canisters/
222
+ │ └── backend/
223
+ │ ├── index.ts # Reactor + hooks
224
+ │ └── declarations/
225
+ │ └── backend.did.ts # Type declarations
226
+ ├── lib/
227
+ │ └── client.ts # Your ClientManager (not generated)
228
+ ```
229
+
230
+ ## How It Works
231
+
232
+ 1. **Build Start**: The plugin reads your `.did` files and uses `@icp-sdk/bindgen` to generate TypeScript declarations
233
+ 2. **Code Generation**: Creates a reactor instance and typed hooks for each canister
234
+ 3. **Hot Reload**: Watches for `.did` file changes and regenerates hooks automatically
235
+
236
+ ## DisplayReactor vs Reactor
237
+
238
+ By default, the plugin uses `DisplayReactor` which transforms Candid types into React-friendly formats:
239
+
240
+ | Candid Type | Reactor | DisplayReactor |
241
+ | ----------- | ------------ | -------------- |
242
+ | `nat` | `bigint` | `string` |
243
+ | `int` | `bigint` | `string` |
244
+ | `principal` | `Principal` | `string` |
245
+ | `vec nat8` | `Uint8Array` | `string` (hex) |
246
+
247
+ To use raw Candid types:
248
+
249
+ ```typescript
250
+ icReactorPlugin({
251
+ canisters: [
252
+ {
253
+ name: "backend",
254
+ didFile: "./backend/backend.did",
255
+ useDisplayReactor: false, // Use Reactor instead
256
+ },
257
+ ],
258
+ })
259
+ ```
260
+
261
+ ## Integration with ICP CLI
262
+
263
+ If you're using [icp-cli](https://github.com/AstroxNetwork/icp-cli), configure your `vite.config.ts` to pass canister IDs via the `ic_env` cookie:
264
+
265
+ ```typescript
266
+ // vite.config.ts
267
+ 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
+
282
+ export default defineConfig({
283
+ plugins: [
284
+ icReactorPlugin({
285
+ canisters: [
286
+ {
287
+ name: "backend",
288
+ didFile: "./backend/backend.did",
289
+ },
290
+ ],
291
+ }),
292
+ ],
293
+ server: {
294
+ headers: {
295
+ "Set-Cookie": `ic_env=${encodeURIComponent(
296
+ Object.entries(canisterIds)
297
+ .map(([name, id]) => `PUBLIC_CANISTER_ID:${name}=${id}`)
298
+ .join("&")
299
+ )}; SameSite=Lax;`,
300
+ },
301
+ },
302
+ })
303
+ ```
304
+
305
+ ## Requirements
306
+
307
+ - **Vite 5.x, 6.x, or 7.x**
308
+ - **Node.js 18+**
309
+ - **TypeScript 5.0+**
310
+
311
+ ## Related Packages
312
+
313
+ - [@ic-reactor/react](https://www.npmjs.com/package/@ic-reactor/react) — React hooks for IC
314
+ - [@ic-reactor/core](https://www.npmjs.com/package/@ic-reactor/core) — Core reactor functionality
315
+ - [@icp-sdk/bindgen](https://www.npmjs.com/package/@icp-sdk/bindgen) — Candid binding generator
316
+
317
+ ## Documentation
318
+
319
+ For comprehensive guides and API reference, visit the [documentation site](https://b3pay.github.io/ic-reactor/v3).
320
+
321
+ ## License
322
+
323
+ MIT © [Behrad Deylami](https://github.com/b3hr4d)
package/dist/index.cjs ADDED
@@ -0,0 +1,422 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/index.ts
31
+ var index_exports = {};
32
+ __export(index_exports, {
33
+ icReactorAdvancedPlugin: () => icReactorAdvancedPlugin,
34
+ icReactorPlugin: () => icReactorPlugin
35
+ });
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
+ var import_fs = __toESM(require("fs"), 1);
45
+ 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
+ });
67
+ }
68
+ return methods;
69
+ }
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
+ `;
193
+ }
194
+ function icReactorAdvancedPlugin(options) {
195
+ const baseOutDir = options.outDir ?? "./src/canisters";
196
+ 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
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}`
248
+ );
249
+ }
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
+ }
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
+ console.log(
363
+ `[ic-reactor] Generating hooks for ${canister.name} from ${canister.didFile}`
364
+ );
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}`
386
+ );
387
+ } catch (error) {
388
+ console.error(`[ic-reactor] Failed to generate declarations:`, error);
389
+ continue;
390
+ }
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);
400
+ console.log(`[ic-reactor] Reactor hooks generated at ${reactorPath}`);
401
+ }
402
+ },
403
+ handleHotUpdate({ file, server }) {
404
+ if (file.endsWith(".did")) {
405
+ const canister = options.canisters.find(
406
+ (c) => import_path2.default.resolve(c.didFile) === file
407
+ );
408
+ if (canister) {
409
+ console.log(
410
+ `[ic-reactor] Detected change in ${file}, regenerating...`
411
+ );
412
+ server.restart();
413
+ }
414
+ }
415
+ }
416
+ };
417
+ }
418
+ // Annotate the CommonJS export names for ESM import in node:
419
+ 0 && (module.exports = {
420
+ icReactorAdvancedPlugin,
421
+ icReactorPlugin
422
+ });
@@ -0,0 +1,67 @@
1
+ import { Plugin } from 'vite';
2
+
3
+ declare function icReactorAdvancedPlugin(options: IcReactorPluginOptions): Plugin;
4
+
5
+ /**
6
+ * IC-Reactor Vite Plugin
7
+ *
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.
16
+ *
17
+ * Usage:
18
+ * ```ts
19
+ * import { icReactorPlugin } from "@ic-reactor/vite-plugin"
20
+ *
21
+ * export default defineConfig({
22
+ * plugins: [
23
+ * icReactorPlugin({
24
+ * canisters: [
25
+ * {
26
+ * name: "backend",
27
+ * didFile: "../backend/backend.did",
28
+ * clientManagerPath: "../lib/client" // User provides their own ClientManager
29
+ * }
30
+ * ]
31
+ * })
32
+ * ]
33
+ * })
34
+ * ```
35
+ */
36
+
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
+ interface IcReactorPluginOptions {
54
+ /** List of canisters to generate hooks for */
55
+ canisters: CanisterConfig[];
56
+ /** Base output directory (default: ./src/canisters) */
57
+ outDir?: string;
58
+ /**
59
+ * Path to import ClientManager from (relative to generated file).
60
+ * The file at this path should export: { clientManager: ClientManager }
61
+ * Default: "../../lib/client"
62
+ */
63
+ clientManagerPath?: string;
64
+ }
65
+ declare function icReactorPlugin(options: IcReactorPluginOptions): Plugin;
66
+
67
+ export { type CanisterConfig, type IcReactorPluginOptions, icReactorAdvancedPlugin, icReactorPlugin };
@@ -0,0 +1,67 @@
1
+ import { Plugin } from 'vite';
2
+
3
+ declare function icReactorAdvancedPlugin(options: IcReactorPluginOptions): Plugin;
4
+
5
+ /**
6
+ * IC-Reactor Vite Plugin
7
+ *
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.
16
+ *
17
+ * Usage:
18
+ * ```ts
19
+ * import { icReactorPlugin } from "@ic-reactor/vite-plugin"
20
+ *
21
+ * export default defineConfig({
22
+ * plugins: [
23
+ * icReactorPlugin({
24
+ * canisters: [
25
+ * {
26
+ * name: "backend",
27
+ * didFile: "../backend/backend.did",
28
+ * clientManagerPath: "../lib/client" // User provides their own ClientManager
29
+ * }
30
+ * ]
31
+ * })
32
+ * ]
33
+ * })
34
+ * ```
35
+ */
36
+
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
+ interface IcReactorPluginOptions {
54
+ /** List of canisters to generate hooks for */
55
+ canisters: CanisterConfig[];
56
+ /** Base output directory (default: ./src/canisters) */
57
+ outDir?: string;
58
+ /**
59
+ * Path to import ClientManager from (relative to generated file).
60
+ * The file at this path should export: { clientManager: ClientManager }
61
+ * Default: "../../lib/client"
62
+ */
63
+ clientManagerPath?: string;
64
+ }
65
+ declare function icReactorPlugin(options: IcReactorPluginOptions): Plugin;
66
+
67
+ export { type CanisterConfig, type IcReactorPluginOptions, icReactorAdvancedPlugin, icReactorPlugin };
package/dist/index.js ADDED
@@ -0,0 +1,384 @@
1
+ // src/simple.ts
2
+ import { generate as generate2 } from "@icp-sdk/bindgen/core";
3
+ import fs2 from "fs";
4
+ import path2 from "path";
5
+
6
+ // src/advanced.ts
7
+ import fs from "fs";
8
+ import path from "path";
9
+ import { generate } from "@icp-sdk/bindgen/core";
10
+ function toPascalCase(str) {
11
+ return str.split(/[-_]/).map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join("");
12
+ }
13
+ function toCamelCase(str) {
14
+ const pascal = toPascalCase(str);
15
+ return pascal.charAt(0).toLowerCase() + pascal.slice(1);
16
+ }
17
+ function extractMethods(didContent) {
18
+ const methodRegex = /([a-zA-Z0-9_]+)\s*:\s*(?:func\s*)?\(([\s\S]*?)\)\s*->\s*\(([\s\S]*?)\)\s*(query|composite_query)?/g;
19
+ const methods = [];
20
+ let match;
21
+ while ((match = methodRegex.exec(didContent)) !== null) {
22
+ const name = match[1];
23
+ const args = match[2].trim();
24
+ const isQuery = !!match[4];
25
+ methods.push({
26
+ name,
27
+ type: isQuery ? "query" : "mutation",
28
+ hasArgs: args.length > 0
29
+ });
30
+ }
31
+ return methods;
32
+ }
33
+ function generateAdvancedReactorFile(canisterName, useDisplayReactor, clientManagerPath, didContent) {
34
+ const pascalName = toPascalCase(canisterName);
35
+ const camelName = toCamelCase(canisterName);
36
+ const reactorType = useDisplayReactor ? "DisplayReactor" : "Reactor";
37
+ const methods = extractMethods(didContent);
38
+ const hooks = methods.map(({ name, type, hasArgs }) => {
39
+ const pascalMethod = toPascalCase(name);
40
+ const camelMethod = toCamelCase(name);
41
+ if (type === "query") {
42
+ const hook = `
43
+ export const use${pascalMethod}Query = (
44
+ args: Parameters<${pascalName}Service["${name}"]>,
45
+ options?: any
46
+ ) =>
47
+ useActorQuery({
48
+ functionName: "${name}",
49
+ args,
50
+ ...options,
51
+ })
52
+ `;
53
+ const staticQuery = !hasArgs ? `
54
+ export const ${camelMethod}Query = createQuery(${camelName}Reactor, {
55
+ functionName: "${name}",
56
+ })
57
+ ` : "";
58
+ return hook + staticQuery;
59
+ } else {
60
+ const hook = `
61
+ export const use${pascalMethod}Mutation = (
62
+ options?: any
63
+ ) =>
64
+ useActorMutation({
65
+ functionName: "${name}",
66
+ ...options,
67
+ })
68
+ `;
69
+ const staticMutation = !hasArgs ? `
70
+ export const ${camelMethod}Mutation = createMutation(${camelName}Reactor, {
71
+ functionName: "${name}",
72
+ })
73
+ ` : "";
74
+ return hook + staticMutation;
75
+ }
76
+ });
77
+ return `/**
78
+ * AUTO-GENERATED BY @ic-reactor/vite-plugin
79
+ * DO NOT EDIT MANUALLY
80
+ *
81
+ * Canister: ${canisterName}
82
+ * Generated: ${(/* @__PURE__ */ new Date()).toISOString()}
83
+ *
84
+ * This file provides type-safe React hooks for interacting with the
85
+ * ${canisterName} canister using ic-reactor.
86
+ */
87
+
88
+ import {
89
+ ${reactorType},
90
+ createActorHooks,
91
+ createAuthHooks,
92
+ createQuery,
93
+ createMutation,
94
+ } from "@ic-reactor/react"
95
+
96
+ // \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
97
+ // USER-PROVIDED CLIENT MANAGER
98
+ // \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
99
+ import { clientManager } from "${clientManagerPath}"
100
+
101
+ // Import generated declarations from @icp-sdk/bindgen
102
+ import {
103
+ idlFactory,
104
+ type _SERVICE,
105
+ } from "./declarations/${canisterName}.did"
106
+
107
+ // \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
108
+ // REACTOR INSTANCE
109
+ // \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
110
+ type ${pascalName}Service = _SERVICE
111
+
112
+ /**
113
+ * ${pascalName} Reactor with ${useDisplayReactor ? "Display" : "Candid"} type transformations.
114
+ * ${useDisplayReactor ? "Automatically converts bigint \u2192 string, Principal \u2192 string, etc." : "Uses raw Candid types."}
115
+ */
116
+ export const ${camelName}Reactor = new ${reactorType}<${pascalName}Service>({
117
+ clientManager,
118
+ idlFactory,
119
+ name: "${canisterName}",
120
+ })
121
+
122
+ // \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
123
+ // ACTOR & AUTH HOOKS
124
+ // \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
125
+ export const {
126
+ useActorQuery,
127
+ useActorMutation,
128
+ useActorSuspenseQuery,
129
+ useActorInfiniteQuery,
130
+ useActorSuspenseInfiniteQuery,
131
+ useActorMethod,
132
+ } = createActorHooks(${camelName}Reactor)
133
+
134
+ export const use${pascalName}Query = useActorQuery
135
+ export const use${pascalName}Mutation = useActorMutation
136
+ export const use${pascalName}SuspenseQuery = useActorSuspenseQuery
137
+ export const use${pascalName}InfiniteQuery = useActorInfiniteQuery
138
+ export const use${pascalName}SuspenseInfiniteQuery = useActorSuspenseInfiniteQuery
139
+ export const use${pascalName}Method = useActorMethod
140
+
141
+ export const { useAuth, useAgentState, useUserPrincipal } = createAuthHooks(
142
+ clientManager
143
+ )
144
+
145
+ // \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
146
+ // METHOD HOOKS
147
+ // \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
148
+ ${hooks.join("")}
149
+
150
+ // \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
151
+ // RE-EXPORTS
152
+ // \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
153
+ export { idlFactory }
154
+ export type { ${pascalName}Service }
155
+ `;
156
+ }
157
+ function icReactorAdvancedPlugin(options) {
158
+ const baseOutDir = options.outDir ?? "./src/canisters";
159
+ return {
160
+ name: "ic-reactor-advanced-plugin",
161
+ async buildStart() {
162
+ for (const canister of options.canisters) {
163
+ const outDir = canister.outDir ?? path.join(baseOutDir, canister.name);
164
+ if (!fs.existsSync(outDir)) {
165
+ fs.mkdirSync(outDir, { recursive: true });
166
+ }
167
+ console.log(
168
+ `[ic-reactor] Generating advanced hooks for ${canister.name} from ${canister.didFile}`
169
+ );
170
+ try {
171
+ await generate({
172
+ didFile: canister.didFile,
173
+ outDir,
174
+ output: {
175
+ actor: {
176
+ disabled: true
177
+ },
178
+ force: true
179
+ }
180
+ });
181
+ console.log(
182
+ `[ic-reactor] Declarations generated at ${path.join(
183
+ outDir,
184
+ "declarations"
185
+ )}`
186
+ );
187
+ } catch (error) {
188
+ console.error(`[ic-reactor] Failed to generate declarations:`, error);
189
+ continue;
190
+ }
191
+ const clientManagerPath = canister.clientManagerPath ?? options.clientManagerPath ?? "../../lib/client";
192
+ let didContent = "";
193
+ try {
194
+ didContent = fs.readFileSync(canister.didFile, "utf-8");
195
+ } catch (e) {
196
+ console.warn(
197
+ `[ic-reactor] Could not read DID file at ${canister.didFile}, skipping hook generation.`
198
+ );
199
+ continue;
200
+ }
201
+ const reactorContent = generateAdvancedReactorFile(
202
+ canister.name,
203
+ canister.useDisplayReactor ?? true,
204
+ clientManagerPath,
205
+ didContent
206
+ );
207
+ const reactorPath = path.join(outDir, "index.ts");
208
+ fs.writeFileSync(reactorPath, reactorContent);
209
+ console.log(
210
+ `[ic-reactor] Advanced reactor hooks generated at ${reactorPath}`
211
+ );
212
+ }
213
+ },
214
+ handleHotUpdate({ file, server }) {
215
+ if (file.endsWith(".did")) {
216
+ const canister = options.canisters.find(
217
+ (c) => path.resolve(c.didFile) === file
218
+ );
219
+ if (canister) {
220
+ console.log(
221
+ `[ic-reactor] Detected change in ${file}, regenerating...`
222
+ );
223
+ server.restart();
224
+ }
225
+ }
226
+ }
227
+ };
228
+ }
229
+
230
+ // src/simple.ts
231
+ function toPascalCase2(str) {
232
+ return str.split(/[-_]/).map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join("");
233
+ }
234
+ function toCamelCase2(str) {
235
+ const pascal = toPascalCase2(str);
236
+ return pascal.charAt(0).toLowerCase() + pascal.slice(1);
237
+ }
238
+ function generateReactorFile(canisterName, useDisplayReactor, clientManagerPath) {
239
+ const pascalName = toPascalCase2(canisterName);
240
+ const camelName = toCamelCase2(canisterName);
241
+ const reactorType = useDisplayReactor ? "DisplayReactor" : "Reactor";
242
+ return `/**
243
+ * AUTO-GENERATED BY @ic-reactor/vite-plugin
244
+ *
245
+ * Canister: ${canisterName}
246
+ * Generated: ${(/* @__PURE__ */ new Date()).toISOString()}
247
+ *
248
+ * This file provides type-safe React hooks for interacting with the
249
+ * ${canisterName} canister using ic-reactor.
250
+ */
251
+
252
+ import {
253
+ ${reactorType},
254
+ createActorHooks,
255
+ } from "@ic-reactor/react"
256
+
257
+ // \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
258
+ // USER-PROVIDED CLIENT MANAGER
259
+ // \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
260
+ // The clientManager is imported from the user's own configuration file.
261
+ // This allows full customization of agent options, network settings, etc.
262
+ import { clientManager } from "${clientManagerPath}"
263
+
264
+ // Import generated declarations from @icp-sdk/bindgen
265
+ import {
266
+ idlFactory,
267
+ type _SERVICE,
268
+ } from "./declarations/${canisterName}.did"
269
+
270
+ // \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
271
+ // REACTOR INSTANCE
272
+ // \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
273
+
274
+ /**
275
+ * ${pascalName} Reactor with ${useDisplayReactor ? "Display" : "Candid"} type transformations.
276
+ * ${useDisplayReactor ? "Automatically converts bigint \u2192 string, Principal \u2192 string, etc." : "Uses raw Candid types."}
277
+ */
278
+ export const ${camelName}Reactor = new ${reactorType}<_SERVICE>({
279
+ clientManager,
280
+ idlFactory,
281
+ name: "${canisterName}",
282
+ })
283
+
284
+ // \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
285
+ // HOOKS
286
+ // \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
287
+
288
+ /**
289
+ * React hooks for the ${canisterName} canister.
290
+ */
291
+ const {
292
+ useActorQuery: use${pascalName}Query,
293
+ useActorSuspenseQuery: use${pascalName}SuspenseQuery,
294
+ useActorInfiniteQuery: use${pascalName}InfiniteQuery,
295
+ useActorSuspenseInfiniteQuery: use${pascalName}SuspenseInfiniteQuery,
296
+ useActorMutation: use${pascalName}Mutation,
297
+ useActorMethod: use${pascalName}Method,
298
+ } = createActorHooks(${camelName}Reactor)
299
+
300
+ export {
301
+ use${pascalName}Query,
302
+ use${pascalName}SuspenseQuery,
303
+ use${pascalName}InfiniteQuery,
304
+ use${pascalName}SuspenseInfiniteQuery,
305
+ use${pascalName}Mutation,
306
+ use${pascalName}Method,
307
+ }
308
+
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
+ // RE-EXPORTS
311
+ // \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
312
+
313
+ export { idlFactory }
314
+ export type { _SERVICE as ${pascalName}Service }
315
+ `;
316
+ }
317
+ function icReactorPlugin(options) {
318
+ const baseOutDir = options.outDir ?? "./src/canisters";
319
+ return {
320
+ name: "ic-reactor-plugin",
321
+ async buildStart() {
322
+ for (const canister of options.canisters) {
323
+ const outDir = canister.outDir ?? path2.join(baseOutDir, canister.name);
324
+ const declarationsDir = path2.join(outDir, "declarations");
325
+ console.log(
326
+ `[ic-reactor] Generating hooks for ${canister.name} from ${canister.didFile}`
327
+ );
328
+ if (fs2.existsSync(declarationsDir)) {
329
+ fs2.rmSync(declarationsDir, { recursive: true, force: true });
330
+ }
331
+ fs2.mkdirSync(declarationsDir, { recursive: true });
332
+ try {
333
+ if (!fs2.existsSync(outDir)) {
334
+ fs2.mkdirSync(outDir, { recursive: true });
335
+ }
336
+ await generate2({
337
+ didFile: canister.didFile,
338
+ outDir,
339
+ // Pass the parent directory; bindgen appends "declarations"
340
+ output: {
341
+ actor: {
342
+ disabled: true
343
+ },
344
+ force: true
345
+ }
346
+ });
347
+ console.log(
348
+ `[ic-reactor] Declarations generated at ${declarationsDir}`
349
+ );
350
+ } catch (error) {
351
+ console.error(`[ic-reactor] Failed to generate declarations:`, error);
352
+ continue;
353
+ }
354
+ const clientManagerPath = canister.clientManagerPath ?? options.clientManagerPath ?? "../../lib/client";
355
+ const reactorContent = generateReactorFile(
356
+ canister.name,
357
+ canister.useDisplayReactor ?? true,
358
+ clientManagerPath
359
+ );
360
+ const reactorPath = path2.join(outDir, "index.ts");
361
+ fs2.mkdirSync(outDir, { recursive: true });
362
+ fs2.writeFileSync(reactorPath, reactorContent);
363
+ console.log(`[ic-reactor] Reactor hooks generated at ${reactorPath}`);
364
+ }
365
+ },
366
+ handleHotUpdate({ file, server }) {
367
+ if (file.endsWith(".did")) {
368
+ const canister = options.canisters.find(
369
+ (c) => path2.resolve(c.didFile) === file
370
+ );
371
+ if (canister) {
372
+ console.log(
373
+ `[ic-reactor] Detected change in ${file}, regenerating...`
374
+ );
375
+ server.restart();
376
+ }
377
+ }
378
+ }
379
+ };
380
+ }
381
+ export {
382
+ icReactorAdvancedPlugin,
383
+ icReactorPlugin
384
+ };
package/package.json ADDED
@@ -0,0 +1,52 @@
1
+ {
2
+ "name": "@ic-reactor/vite-plugin",
3
+ "version": "0.1.0",
4
+ "description": "Vite plugin for zero-config IC reactor generation from Candid files",
5
+ "type": "module",
6
+ "main": "./dist/index.cjs",
7
+ "module": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "import": "./dist/index.js",
13
+ "require": "./dist/index.cjs"
14
+ }
15
+ },
16
+ "files": [
17
+ "dist"
18
+ ],
19
+ "scripts": {
20
+ "build": "tsup src/index.ts --format esm,cjs --dts --tsconfig tsconfig.json",
21
+ "dev": "tsup src/index.ts --format esm,cjs --dts --watch --tsconfig tsconfig.json"
22
+ },
23
+ "keywords": [
24
+ "vite",
25
+ "vite-plugin",
26
+ "internet-computer",
27
+ "candid",
28
+ "ic-reactor",
29
+ "dfinity",
30
+ "icp"
31
+ ],
32
+ "author": "Behrad Deylami",
33
+ "license": "MIT",
34
+ "peerDependencies": {
35
+ "@icp-sdk/bindgen": "^0.2.0",
36
+ "vite": "^5.0.0 || ^6.0.0 || ^7.0.0"
37
+ },
38
+ "peerDependenciesMeta": {
39
+ "@icp-sdk/bindgen": {
40
+ "optional": true
41
+ }
42
+ },
43
+ "dependencies": {
44
+ "chokidar": "^4.0.0"
45
+ },
46
+ "devDependencies": {
47
+ "@types/node": "^25.0.3",
48
+ "tsup": "^8.5.1",
49
+ "typescript": "^5.9.0",
50
+ "vite": "^7.3.1"
51
+ }
52
+ }