@ic-reactor/vite-plugin 0.5.0 → 0.6.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 CHANGED
@@ -38,12 +38,12 @@ pnpm add @ic-reactor/react @tanstack/react-query @icp-sdk/core
38
38
  // vite.config.ts
39
39
  import { defineConfig } from "vite"
40
40
  import react from "@vitejs/plugin-react"
41
- import { icReactorPlugin } from "@ic-reactor/vite-plugin"
41
+ import { icReactor } from "@ic-reactor/vite-plugin"
42
42
 
43
43
  export default defineConfig({
44
44
  plugins: [
45
45
  react(),
46
- icReactorPlugin({
46
+ icReactor({
47
47
  canisters: [
48
48
  {
49
49
  name: "backend",
@@ -87,6 +87,56 @@ function MyComponent() {
87
87
  }
88
88
  ```
89
89
 
90
+ ### Reactor Mode (raw vs display)
91
+
92
+ By default, generated hooks use `DisplayReactor` (backward compatible). You can switch the default globally, and override specific canisters that need raw Candid shapes.
93
+
94
+ ```ts
95
+ icReactor({
96
+ canisters: [
97
+ { name: "backend", didFile: "./backend/backend.did" },
98
+ { name: "workflow_engine", didFile: "./workflow/workflow_engine.did" },
99
+ ],
100
+ reactor: {
101
+ defaultMode: "display",
102
+ canisters: {
103
+ workflow_engine: "raw",
104
+ },
105
+ },
106
+ })
107
+ ```
108
+
109
+ Generated canister folders now contain:
110
+
111
+ - `index.generated.ts` (overwritten on regenerate)
112
+ - `index.ts` (created once if missing, never overwritten)
113
+
114
+ The generated implementation exports both factories so apps can opt in explicitly without editing generated files:
115
+
116
+ ```ts
117
+ // display-default canister (generated)
118
+ export function createBackendRawReactor() {
119
+ /* ... */
120
+ }
121
+ export function createBackendDisplayReactor() {
122
+ /* ... */
123
+ }
124
+ export const backendReactor = createBackendDisplayReactor()
125
+ export const BackendReactorMode = "display" as const
126
+ ```
127
+
128
+ ```ts
129
+ // raw-default canister (generated)
130
+ export function createWorkflowEngineRawReactor() {
131
+ /* ... */
132
+ }
133
+ export function createWorkflowEngineDisplayReactor() {
134
+ /* ... */
135
+ }
136
+ export const workflowEngineReactor = createWorkflowEngineRawReactor()
137
+ export const WorkflowEngineReactorMode = "raw" as const
138
+ ```
139
+
90
140
  ## Configuration
91
141
 
92
142
  ### Plugin Options
@@ -97,6 +147,7 @@ function MyComponent() {
97
147
  | `outDir` | `string` | Base output directory for generated files. | `"src/declarations"` |
98
148
  | `clientManagerPath` | `string` | Path to client manager import. | `"../../clients"` |
99
149
  | `injectEnvironment` | `boolean` | Inject `ic_env` cookie for local development. | `true` |
150
+ | `reactor` | `ReactorConfig` | Default/per-canister raw vs display reactor mode. | display default |
100
151
 
101
152
  ### Canister Config
102
153
 
@@ -108,6 +159,13 @@ function MyComponent() {
108
159
  | `clientManagerPath` | `string` | Override client manager path. | No |
109
160
  | `canisterId` | `string` | Optional fixed canister ID. | No |
110
161
 
162
+ ### ReactorConfig
163
+
164
+ | Option | Type | Description | Required |
165
+ | :------------ | :----------------------------------- | :--------------------------------------- | :------- |
166
+ | `defaultMode` | `"raw" \| "display"` | Global default mode for generated hooks. | No |
167
+ | `canisters` | `Record<string, "raw" \| "display">` | Per-canister overrides keyed by name. | No |
168
+
111
169
  ## Local Development (Environment Injection)
112
170
 
113
171
  When running `vite dev`, the plugin automatically handles local canister environment connection:
package/dist/index.cjs CHANGED
@@ -30,7 +30,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
30
30
  // src/index.ts
31
31
  var index_exports = {};
32
32
  __export(index_exports, {
33
- icReactorPlugin: () => icReactorPlugin
33
+ icReactor: () => icReactor
34
34
  });
35
35
  module.exports = __toCommonJS(index_exports);
36
36
  var import_node_path = __toESM(require("path"), 1);
@@ -78,18 +78,22 @@ function buildIcEnvCookie(canisterIds, rootKey) {
78
78
  }
79
79
 
80
80
  // src/index.ts
81
- function icReactorPlugin(options) {
81
+ function icReactor(options) {
82
82
  const {
83
83
  canisters,
84
84
  outDir = "src/declarations",
85
85
  clientManagerPath = "../../clients",
86
- injectEnvironment = true
86
+ injectEnvironment = true,
87
+ reactor
87
88
  } = options;
88
89
  const globalConfig = {
89
90
  outDir,
90
91
  clientManagerPath
91
92
  };
92
- return {
93
+ if (reactor != null) {
94
+ globalConfig.reactor = reactor;
95
+ }
96
+ const plugin = {
93
97
  name: "ic-reactor-plugin",
94
98
  enforce: "pre",
95
99
  // Run before other plugins
@@ -181,8 +185,9 @@ function icReactorPlugin(options) {
181
185
  }
182
186
  }
183
187
  };
188
+ return plugin;
184
189
  }
185
190
  // Annotate the CommonJS export names for ESM import in node:
186
191
  0 && (module.exports = {
187
- icReactorPlugin
192
+ icReactor
188
193
  });
package/dist/index.d.cts CHANGED
@@ -1,5 +1,4 @@
1
- import { Plugin } from 'vite';
2
- import { CanisterConfig } from '@ic-reactor/codegen';
1
+ import { CanisterConfig, ReactorGenerationConfig } from '@ic-reactor/codegen';
3
2
 
4
3
  /**
5
4
  * @ic-reactor/vite-plugin
@@ -31,7 +30,12 @@ interface IcReactorPluginOptions {
31
30
  * Default: true
32
31
  */
33
32
  injectEnvironment?: boolean;
33
+ /**
34
+ * Reactor generation behavior.
35
+ * Controls whether generated default hooks use raw (Reactor) or display (DisplayReactor).
36
+ */
37
+ reactor?: ReactorGenerationConfig;
34
38
  }
35
- declare function icReactorPlugin(options: IcReactorPluginOptions): Plugin;
39
+ declare function icReactor(options: IcReactorPluginOptions): any;
36
40
 
37
- export { type IcReactorPluginOptions, icReactorPlugin };
41
+ export { type IcReactorPluginOptions, icReactor };
package/dist/index.d.ts CHANGED
@@ -1,5 +1,4 @@
1
- import { Plugin } from 'vite';
2
- import { CanisterConfig } from '@ic-reactor/codegen';
1
+ import { CanisterConfig, ReactorGenerationConfig } from '@ic-reactor/codegen';
3
2
 
4
3
  /**
5
4
  * @ic-reactor/vite-plugin
@@ -31,7 +30,12 @@ interface IcReactorPluginOptions {
31
30
  * Default: true
32
31
  */
33
32
  injectEnvironment?: boolean;
33
+ /**
34
+ * Reactor generation behavior.
35
+ * Controls whether generated default hooks use raw (Reactor) or display (DisplayReactor).
36
+ */
37
+ reactor?: ReactorGenerationConfig;
34
38
  }
35
- declare function icReactorPlugin(options: IcReactorPluginOptions): Plugin;
39
+ declare function icReactor(options: IcReactorPluginOptions): any;
36
40
 
37
- export { type IcReactorPluginOptions, icReactorPlugin };
41
+ export { type IcReactorPluginOptions, icReactor };
package/dist/index.js CHANGED
@@ -46,18 +46,22 @@ function buildIcEnvCookie(canisterIds, rootKey) {
46
46
  }
47
47
 
48
48
  // src/index.ts
49
- function icReactorPlugin(options) {
49
+ function icReactor(options) {
50
50
  const {
51
51
  canisters,
52
52
  outDir = "src/declarations",
53
53
  clientManagerPath = "../../clients",
54
- injectEnvironment = true
54
+ injectEnvironment = true,
55
+ reactor
55
56
  } = options;
56
57
  const globalConfig = {
57
58
  outDir,
58
59
  clientManagerPath
59
60
  };
60
- return {
61
+ if (reactor != null) {
62
+ globalConfig.reactor = reactor;
63
+ }
64
+ const plugin = {
61
65
  name: "ic-reactor-plugin",
62
66
  enforce: "pre",
63
67
  // Run before other plugins
@@ -149,7 +153,8 @@ function icReactorPlugin(options) {
149
153
  }
150
154
  }
151
155
  };
156
+ return plugin;
152
157
  }
153
158
  export {
154
- icReactorPlugin
159
+ icReactor
155
160
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ic-reactor/vite-plugin",
3
- "version": "0.5.0",
3
+ "version": "0.6.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,16 @@
37
37
  "url": "https://github.com/B3Pay/ic-reactor/issues"
38
38
  },
39
39
  "dependencies": {
40
- "@ic-reactor/codegen": "0.5.0"
40
+ "@ic-reactor/codegen": "0.6.0"
41
41
  },
42
42
  "peerDependencies": {
43
- "vite": "^5.0.0 || ^6.0.0 || ^7.0.0"
43
+ "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0"
44
44
  },
45
45
  "devDependencies": {
46
46
  "@icp-sdk/bindgen": "^0.2.1",
47
47
  "@types/node": "^25.2.3",
48
48
  "tsup": "^8.5.1",
49
49
  "typescript": "^5.9.3",
50
- "vite": "^7.3.1",
51
50
  "vitest": "^4.0.18"
52
51
  },
53
52
  "scripts": {
package/src/index.test.ts CHANGED
@@ -1,6 +1,5 @@
1
1
  import { describe, it, expect, vi, beforeEach } from "vitest"
2
- import { icReactorPlugin, type IcReactorPluginOptions } from "./index"
3
- import fs from "fs"
2
+ import { icReactor, type IcReactorPluginOptions } from "./index"
4
3
  import path from "path"
5
4
  import { execFileSync } from "child_process"
6
5
  import { runCanisterPipeline } from "@ic-reactor/codegen"
@@ -25,7 +24,7 @@ vi.mock("fs", () => ({
25
24
  },
26
25
  }))
27
26
 
28
- describe("icReactorPlugin", () => {
27
+ describe("icReactor", () => {
29
28
  const mockOptions: IcReactorPluginOptions = {
30
29
  canisters: [
31
30
  {
@@ -61,7 +60,7 @@ describe("icReactorPlugin", () => {
61
60
  })
62
61
 
63
62
  it("should return correct plugin structure", () => {
64
- const plugin = icReactorPlugin(mockOptions)
63
+ const plugin = icReactor(mockOptions)
65
64
  expect(plugin.name).toBe("ic-reactor-plugin")
66
65
  expect(plugin.buildStart).toBeDefined()
67
66
  expect(plugin.handleHotUpdate).toBeDefined()
@@ -90,7 +89,7 @@ describe("icReactorPlugin", () => {
90
89
  }
91
90
  )
92
91
 
93
- const plugin = icReactorPlugin(mockOptions)
92
+ const plugin = icReactor(mockOptions)
94
93
  const config = (plugin as any).config({}, { command: "serve" })
95
94
 
96
95
  expect(config.server.headers["Set-Cookie"]).toContain("ic_env=")
@@ -108,7 +107,7 @@ describe("icReactorPlugin", () => {
108
107
  throw new Error("Command not found")
109
108
  })
110
109
 
111
- const plugin = icReactorPlugin(mockOptions)
110
+ const plugin = icReactor(mockOptions)
112
111
  const config = (plugin as any).config({}, { command: "serve" })
113
112
 
114
113
  expect(config.server.headers).toBeUndefined()
@@ -116,7 +115,7 @@ describe("icReactorPlugin", () => {
116
115
  })
117
116
 
118
117
  it("should return empty config for build command", () => {
119
- const plugin = icReactorPlugin(mockOptions)
118
+ const plugin = icReactor(mockOptions)
120
119
  const config = (plugin as any).config({}, { command: "build" })
121
120
 
122
121
  expect(config).toEqual({})
@@ -125,7 +124,7 @@ describe("icReactorPlugin", () => {
125
124
 
126
125
  describe("buildStart", () => {
127
126
  it("should generate declarations and reactor file", async () => {
128
- const plugin = icReactorPlugin(mockOptions)
127
+ const plugin = icReactor(mockOptions)
129
128
  await (plugin.buildStart as any)()
130
129
 
131
130
  expect(runCanisterPipeline).toHaveBeenCalledWith({
@@ -148,7 +147,7 @@ describe("icReactorPlugin", () => {
148
147
  error: "Failed to generate",
149
148
  })
150
149
 
151
- const plugin = icReactorPlugin(mockOptions)
150
+ const plugin = icReactor(mockOptions)
152
151
  await (plugin.buildStart as any)()
153
152
 
154
153
  expect(consoleErrorSpy).toHaveBeenCalledWith(
@@ -157,11 +156,40 @@ describe("icReactorPlugin", () => {
157
156
 
158
157
  consoleErrorSpy.mockRestore()
159
158
  })
159
+
160
+ it("should pass reactor mode config to codegen", async () => {
161
+ const plugin = icReactor({
162
+ ...mockOptions,
163
+ reactor: {
164
+ defaultMode: "display",
165
+ canisters: {
166
+ test_canister: "raw",
167
+ },
168
+ },
169
+ })
170
+
171
+ await (plugin.buildStart as any)()
172
+
173
+ expect(runCanisterPipeline).toHaveBeenCalledWith({
174
+ canisterConfig: mockOptions.canisters[0],
175
+ projectRoot: expect.any(String),
176
+ globalConfig: {
177
+ outDir: "src/declarations",
178
+ clientManagerPath: "../../clients",
179
+ reactor: {
180
+ defaultMode: "display",
181
+ canisters: {
182
+ test_canister: "raw",
183
+ },
184
+ },
185
+ },
186
+ })
187
+ })
160
188
  })
161
189
 
162
190
  describe("handleHotUpdate", () => {
163
191
  it("should restart server when .did file changes", async () => {
164
- const plugin = icReactorPlugin(mockOptions)
192
+ const plugin = icReactor(mockOptions)
165
193
  const ctx = {
166
194
  file: "/absolute/path/to/src/declarations/test.did",
167
195
  server: mockServer,
@@ -182,7 +210,7 @@ describe("icReactorPlugin", () => {
182
210
  })
183
211
 
184
212
  it("should ignore other files", () => {
185
- const plugin = icReactorPlugin(mockOptions)
213
+ const plugin = icReactor(mockOptions)
186
214
  const ctx = {
187
215
  file: "/some/other/file.ts",
188
216
  server: mockServer,
package/src/index.ts CHANGED
@@ -7,13 +7,13 @@
7
7
  * 3. Hot-reloads when .did files change
8
8
  */
9
9
 
10
- import type { Plugin, UserConfig } from "vite"
11
- import fs from "node:fs"
10
+ import type { Plugin } from "vite"
12
11
  import path from "node:path"
13
12
  import {
14
13
  runCanisterPipeline,
15
14
  type CanisterConfig,
16
15
  type CodegenConfig,
16
+ type ReactorGenerationConfig,
17
17
  } from "@ic-reactor/codegen"
18
18
  import { getIcEnvironmentInfo, buildIcEnvCookie } from "./env.js"
19
19
 
@@ -38,23 +38,35 @@ export interface IcReactorPluginOptions {
38
38
  * Default: true
39
39
  */
40
40
  injectEnvironment?: boolean
41
+ /**
42
+ * Reactor generation behavior.
43
+ * Controls whether generated default hooks use raw (Reactor) or display (DisplayReactor).
44
+ */
45
+ reactor?: ReactorGenerationConfig
41
46
  }
42
47
 
43
- export function icReactorPlugin(options: IcReactorPluginOptions): Plugin {
48
+ export function icReactor(options: IcReactorPluginOptions): any {
44
49
  const {
45
50
  canisters,
46
51
  outDir = "src/declarations",
47
52
  clientManagerPath = "../../clients",
48
53
  injectEnvironment = true,
54
+ reactor,
49
55
  } = options
50
56
 
51
57
  // Construct a partial CodegenConfig to pass to the pipeline
52
- const globalConfig: Pick<CodegenConfig, "outDir" | "clientManagerPath"> = {
58
+ const globalConfig: Pick<
59
+ CodegenConfig,
60
+ "outDir" | "clientManagerPath" | "reactor"
61
+ > = {
53
62
  outDir,
54
63
  clientManagerPath,
55
64
  }
65
+ if (reactor != null) {
66
+ globalConfig.reactor = reactor
67
+ }
56
68
 
57
- return {
69
+ const plugin: Plugin = {
58
70
  name: "ic-reactor-plugin",
59
71
  enforce: "pre", // Run before other plugins
60
72
 
@@ -176,4 +188,6 @@ export function icReactorPlugin(options: IcReactorPluginOptions): Plugin {
176
188
  }
177
189
  },
178
190
  }
191
+
192
+ return plugin
179
193
  }