every-plugin 0.8.9 → 2.2.2

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.
Files changed (182) hide show
  1. package/dist/_virtual/{rolldown_runtime.cjs → _rolldown/runtime.cjs} +15 -1
  2. package/dist/_virtual/{rolldown_runtime.mjs → _rolldown/runtime.mjs} +15 -2
  3. package/dist/build/rspack/dev-server-middleware.cjs +15 -4
  4. package/dist/build/rspack/dev-server-middleware.cjs.map +1 -1
  5. package/dist/build/rspack/dev-server-middleware.mjs +15 -4
  6. package/dist/build/rspack/dev-server-middleware.mjs.map +1 -1
  7. package/dist/build/rspack/fix-mf-data-uri-plugin.cjs +44 -0
  8. package/dist/build/rspack/fix-mf-data-uri-plugin.cjs.map +1 -0
  9. package/dist/build/rspack/fix-mf-data-uri-plugin.d.cts +11 -0
  10. package/dist/build/rspack/fix-mf-data-uri-plugin.d.cts.map +1 -0
  11. package/dist/build/rspack/fix-mf-data-uri-plugin.d.mts +11 -0
  12. package/dist/build/rspack/fix-mf-data-uri-plugin.d.mts.map +1 -0
  13. package/dist/build/rspack/fix-mf-data-uri-plugin.mjs +43 -0
  14. package/dist/build/rspack/fix-mf-data-uri-plugin.mjs.map +1 -0
  15. package/dist/build/rspack/index.cjs +8 -6
  16. package/dist/build/rspack/index.d.cts +4 -3
  17. package/dist/build/rspack/index.d.mts +4 -3
  18. package/dist/build/rspack/index.mjs +4 -3
  19. package/dist/build/rspack/module-federation.cjs +3 -3
  20. package/dist/build/rspack/module-federation.cjs.map +1 -1
  21. package/dist/build/rspack/module-federation.mjs +1 -1
  22. package/dist/build/rspack/module-federation.mjs.map +1 -1
  23. package/dist/build/rspack/plugin.cjs +83 -5
  24. package/dist/build/rspack/plugin.cjs.map +1 -1
  25. package/dist/build/rspack/plugin.d.cts +12 -1
  26. package/dist/build/rspack/plugin.d.cts.map +1 -1
  27. package/dist/build/rspack/plugin.d.mts +12 -1
  28. package/dist/build/rspack/plugin.d.mts.map +1 -1
  29. package/dist/build/rspack/plugin.mjs +80 -5
  30. package/dist/build/rspack/plugin.mjs.map +1 -1
  31. package/dist/build/rspack/utils.cjs +5 -4
  32. package/dist/build/rspack/utils.cjs.map +1 -1
  33. package/dist/build/rspack/utils.mjs +3 -2
  34. package/dist/build/rspack/utils.mjs.map +1 -1
  35. package/dist/build/shared-deps.cjs +50 -65
  36. package/dist/build/shared-deps.cjs.map +1 -1
  37. package/dist/build/shared-deps.d.cts +27 -4
  38. package/dist/build/shared-deps.d.cts.map +1 -1
  39. package/dist/build/shared-deps.d.mts +27 -4
  40. package/dist/build/shared-deps.d.mts.map +1 -1
  41. package/dist/build/shared-deps.mjs +48 -64
  42. package/dist/build/shared-deps.mjs.map +1 -1
  43. package/dist/errors.cjs +1 -0
  44. package/dist/errors.cjs.map +1 -1
  45. package/dist/errors.d.cts.map +1 -1
  46. package/dist/errors.d.mts.map +1 -1
  47. package/dist/errors.mjs.map +1 -1
  48. package/dist/index.cjs +2 -0
  49. package/dist/index.d.cts +2 -2
  50. package/dist/index.d.mts +2 -2
  51. package/dist/index.mjs +2 -2
  52. package/dist/orpc-client.cjs +17 -0
  53. package/dist/orpc-client.d.cts +2 -0
  54. package/dist/orpc-client.d.mts +2 -0
  55. package/dist/orpc-client.mjs +5 -0
  56. package/dist/orpc-openapi.cjs +17 -0
  57. package/dist/orpc-openapi.d.cts +2 -0
  58. package/dist/orpc-openapi.d.mts +2 -0
  59. package/dist/orpc-openapi.mjs +5 -0
  60. package/dist/orpc.cjs +8 -7
  61. package/dist/plugin.cjs +10 -9
  62. package/dist/plugin.cjs.map +1 -1
  63. package/dist/plugin.d.cts +28 -29
  64. package/dist/plugin.d.cts.map +1 -1
  65. package/dist/plugin.d.mts +28 -29
  66. package/dist/plugin.d.mts.map +1 -1
  67. package/dist/plugin.mjs +10 -10
  68. package/dist/plugin.mjs.map +1 -1
  69. package/dist/runtime/errors.cjs +2 -2
  70. package/dist/runtime/errors.cjs.map +1 -1
  71. package/dist/runtime/errors.d.cts +4 -4
  72. package/dist/runtime/errors.d.cts.map +1 -1
  73. package/dist/runtime/errors.d.mts +4 -4
  74. package/dist/runtime/errors.d.mts.map +1 -1
  75. package/dist/runtime/errors.mjs +1 -1
  76. package/dist/runtime/errors.mjs.map +1 -1
  77. package/dist/runtime/index.cjs +24 -20
  78. package/dist/runtime/index.cjs.map +1 -1
  79. package/dist/runtime/index.d.cts +3 -3
  80. package/dist/runtime/index.d.cts.map +1 -1
  81. package/dist/runtime/index.d.mts +3 -3
  82. package/dist/runtime/index.d.mts.map +1 -1
  83. package/dist/runtime/index.mjs +12 -9
  84. package/dist/runtime/index.mjs.map +1 -1
  85. package/dist/runtime/mf-config.cjs +33 -0
  86. package/dist/runtime/mf-config.cjs.map +1 -0
  87. package/dist/runtime/mf-config.d.cts +41 -0
  88. package/dist/runtime/mf-config.d.cts.map +1 -0
  89. package/dist/runtime/mf-config.d.mts +41 -0
  90. package/dist/runtime/mf-config.d.mts.map +1 -0
  91. package/dist/runtime/mf-config.mjs +29 -0
  92. package/dist/runtime/mf-config.mjs.map +1 -0
  93. package/dist/runtime/services/module-federation.service.cjs +19 -56
  94. package/dist/runtime/services/module-federation.service.cjs.map +1 -1
  95. package/dist/runtime/services/module-federation.service.d.cts.map +1 -1
  96. package/dist/runtime/services/module-federation.service.d.mts.map +1 -1
  97. package/dist/runtime/services/module-federation.service.mjs +18 -55
  98. package/dist/runtime/services/module-federation.service.mjs.map +1 -1
  99. package/dist/runtime/services/normalize.cjs +3 -2
  100. package/dist/runtime/services/normalize.cjs.map +1 -1
  101. package/dist/runtime/services/normalize.d.cts.map +1 -1
  102. package/dist/runtime/services/normalize.d.mts.map +1 -1
  103. package/dist/runtime/services/normalize.mjs +2 -2
  104. package/dist/runtime/services/normalize.mjs.map +1 -1
  105. package/dist/runtime/services/plugin-lifecycle.service.cjs +1 -1
  106. package/dist/runtime/services/plugin-lifecycle.service.cjs.map +1 -1
  107. package/dist/runtime/services/plugin-lifecycle.service.d.cts.map +1 -1
  108. package/dist/runtime/services/plugin-lifecycle.service.d.mts.map +1 -1
  109. package/dist/runtime/services/plugin-lifecycle.service.mjs.map +1 -1
  110. package/dist/runtime/services/plugin-loader.service.cjs +3 -3
  111. package/dist/runtime/services/plugin-loader.service.cjs.map +1 -1
  112. package/dist/runtime/services/plugin-loader.service.d.cts +1 -1
  113. package/dist/runtime/services/plugin-loader.service.d.cts.map +1 -1
  114. package/dist/runtime/services/plugin-loader.service.d.mts +1 -1
  115. package/dist/runtime/services/plugin-loader.service.d.mts.map +1 -1
  116. package/dist/runtime/services/plugin-loader.service.mjs +2 -2
  117. package/dist/runtime/services/plugin-loader.service.mjs.map +1 -1
  118. package/dist/runtime/services/plugin.service.cjs +1 -1
  119. package/dist/runtime/services/plugin.service.cjs.map +1 -1
  120. package/dist/runtime/services/plugin.service.d.cts +6 -7
  121. package/dist/runtime/services/plugin.service.d.cts.map +1 -1
  122. package/dist/runtime/services/plugin.service.d.mts +6 -7
  123. package/dist/runtime/services/plugin.service.d.mts.map +1 -1
  124. package/dist/runtime/services/plugin.service.mjs.map +1 -1
  125. package/dist/runtime/services/secrets.service.cjs +4 -4
  126. package/dist/runtime/services/secrets.service.cjs.map +1 -1
  127. package/dist/runtime/services/secrets.service.d.cts.map +1 -1
  128. package/dist/runtime/services/secrets.service.d.mts.map +1 -1
  129. package/dist/runtime/services/secrets.service.mjs +3 -3
  130. package/dist/runtime/services/secrets.service.mjs.map +1 -1
  131. package/dist/runtime/validation.cjs +1 -1
  132. package/dist/runtime/validation.cjs.map +1 -1
  133. package/dist/runtime/validation.mjs.map +1 -1
  134. package/dist/testing/index.cjs +2 -1
  135. package/dist/testing/index.cjs.map +1 -1
  136. package/dist/testing/index.d.cts +0 -2
  137. package/dist/testing/index.d.cts.map +1 -1
  138. package/dist/testing/index.d.mts +0 -2
  139. package/dist/testing/index.d.mts.map +1 -1
  140. package/dist/testing/index.mjs +1 -1
  141. package/dist/testing/index.mjs.map +1 -1
  142. package/dist/types.d.cts +22 -22
  143. package/dist/types.d.cts.map +1 -1
  144. package/dist/types.d.mts +22 -22
  145. package/dist/types.d.mts.map +1 -1
  146. package/dist/zod.cjs +4 -3
  147. package/dist/zod.mjs +2 -2
  148. package/package.json +204 -194
  149. package/src/build/rspack/dev-server-middleware.ts +233 -0
  150. package/src/build/rspack/fix-mf-data-uri-plugin.ts +49 -0
  151. package/src/build/rspack/index.ts +14 -0
  152. package/src/build/rspack/module-federation.ts +6 -0
  153. package/src/build/rspack/plugin.ts +252 -0
  154. package/src/build/rspack/utils.ts +60 -0
  155. package/src/build/shared-deps.ts +79 -0
  156. package/src/effect.ts +1 -0
  157. package/src/errors.ts +140 -0
  158. package/src/index.ts +26 -0
  159. package/src/orpc-client.ts +2 -0
  160. package/src/orpc-openapi.ts +2 -0
  161. package/src/orpc.ts +9 -0
  162. package/src/plugin.ts +220 -0
  163. package/src/runtime/errors.ts +332 -0
  164. package/src/runtime/index.ts +258 -0
  165. package/src/runtime/mf-config.ts +29 -0
  166. package/src/runtime/services/module-federation.service.ts +181 -0
  167. package/src/runtime/services/normalize.ts +18 -0
  168. package/src/runtime/services/plugin-lifecycle.service.ts +86 -0
  169. package/src/runtime/services/plugin-loader.service.ts +254 -0
  170. package/src/runtime/services/plugin.service.ts +66 -0
  171. package/src/runtime/services/secrets.service.ts +74 -0
  172. package/src/runtime/services.ts +5 -0
  173. package/src/runtime/validation.ts +23 -0
  174. package/src/testing/index.ts +87 -0
  175. package/src/testing/mocks/module-federation.service.ts +41 -0
  176. package/src/types.ts +309 -0
  177. package/src/zod-core.ts +4 -0
  178. package/src/zod.ts +1 -0
  179. package/dist/package.cjs +0 -47
  180. package/dist/package.cjs.map +0 -1
  181. package/dist/package.mjs +0 -29
  182. package/dist/package.mjs.map +0 -1
@@ -0,0 +1,233 @@
1
+ import type { PluginInfo } from "./utils";
2
+
3
+ const corsHeaders = {
4
+ "Access-Control-Allow-Origin": "*",
5
+ "Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, PATCH, OPTIONS",
6
+ "Access-Control-Allow-Headers": "X-Requested-With, content-type, Authorization",
7
+ };
8
+
9
+ const applyCorsHeaders = (res: any) => {
10
+ Object.entries(corsHeaders).forEach(([key, value]) => {
11
+ res.setHeader(key, value);
12
+ });
13
+ };
14
+
15
+ const normalizePrefix = (prefix?: string): string => {
16
+ if (!prefix) return "";
17
+ const cleaned = prefix.replace(/^\/+|\/+$/g, "");
18
+ return cleaned ? `/${cleaned}` : "";
19
+ };
20
+
21
+ export function setupPluginMiddleware(
22
+ devServer: any,
23
+ pluginInfo: PluginInfo,
24
+ devConfig: any,
25
+ port: number,
26
+ ) {
27
+ const rpcPrefix = normalizePrefix(devConfig?.prefix);
28
+ const handlers: { rpc: any; api: any } = { rpc: null, api: null };
29
+ let cleanup: (() => Promise<void>) | null = null;
30
+
31
+ const performCleanup = async () => {
32
+ if (cleanup) {
33
+ await cleanup();
34
+ cleanup = null;
35
+ }
36
+ };
37
+
38
+ (async () => {
39
+ await performCleanup();
40
+
41
+ try {
42
+ const { createPluginRuntime } = await import("every-plugin");
43
+ const { RPCHandler } = await import("@orpc/server/fetch");
44
+ const { OpenAPIHandler } = await import("@orpc/openapi/fetch");
45
+ const { OpenAPIReferencePlugin } = await import("@orpc/openapi/plugins");
46
+ const { ZodToJsonSchemaConverter } = await import("@orpc/zod/zod4");
47
+ const { onError } = await import("every-plugin/orpc");
48
+ const { formatORPCError } = await import("every-plugin/errors");
49
+
50
+ const pluginId = devConfig?.pluginId || pluginInfo.normalizedName;
51
+
52
+ const runtime = createPluginRuntime({
53
+ registry: {
54
+ [pluginId]: {
55
+ remote: `http://localhost:${port}/remoteEntry.js`,
56
+ },
57
+ },
58
+ });
59
+
60
+ const defaultConfig = { variables: {}, secrets: {} };
61
+
62
+ // @ts-expect-error we don't know the plugin id
63
+ const loaded = await runtime.usePlugin(pluginId, (devConfig?.config ?? defaultConfig) as any);
64
+
65
+ cleanup = async () => {
66
+ if (loaded && typeof (loaded as any).dispose === "function") {
67
+ await (loaded as any).dispose();
68
+ }
69
+ if (runtime && typeof (runtime as any).cleanup === "function") {
70
+ await (runtime as any).cleanup();
71
+ }
72
+ handlers.rpc = null;
73
+ handlers.api = null;
74
+ if (devServer.app.locals.handlers) {
75
+ devServer.app.locals.handlers = null;
76
+ }
77
+ };
78
+
79
+ handlers.rpc = new RPCHandler(loaded.router, {
80
+ interceptors: [
81
+ onError((error: any) => {
82
+ formatORPCError(error);
83
+ }),
84
+ ],
85
+ });
86
+
87
+ handlers.api = new OpenAPIHandler(loaded.router, {
88
+ plugins: [
89
+ new OpenAPIReferencePlugin({
90
+ schemaConverters: [new ZodToJsonSchemaConverter()],
91
+ }),
92
+ ],
93
+ interceptors: [
94
+ onError((error: any) => {
95
+ formatORPCError(error);
96
+ }),
97
+ ],
98
+ });
99
+
100
+ console.log(`╭─────────────────────────────────────────────`);
101
+ console.log(`│ ✅ Plugin dev server ready: `);
102
+ console.log(`├─────────────────────────────────────────────`);
103
+ console.log(`│ 📡 RPC: http://localhost:${port}/api/rpc${rpcPrefix}`);
104
+ console.log(`│ 📖 Docs: http://localhost:${port}/api`);
105
+ console.log(`│ 💚 Health: http://localhost:${port}/`);
106
+ console.log(`╰─────────────────────────────────────────────`);
107
+
108
+ devServer.app.locals.handlers = handlers;
109
+
110
+ if (devServer.server) {
111
+ devServer.server.once("close", async () => {
112
+ await performCleanup();
113
+ });
114
+ }
115
+ } catch (error) {
116
+ console.error("❌ Failed to load plugin:", error);
117
+ await performCleanup();
118
+ }
119
+ })();
120
+
121
+ process.once("SIGINT", async () => {
122
+ const timeout = setTimeout(() => process.exit(0), 3000);
123
+ await performCleanup();
124
+ clearTimeout(timeout);
125
+ });
126
+ process.once("SIGTERM", async () => {
127
+ const timeout = setTimeout(() => process.exit(0), 3000);
128
+ await performCleanup();
129
+ clearTimeout(timeout);
130
+ });
131
+
132
+ devServer.app.options("*", (_req: any, res: any) => {
133
+ applyCorsHeaders(res);
134
+ res.status(200).end();
135
+ });
136
+
137
+ devServer.app.get("/", (_req: any, res: any) => {
138
+ applyCorsHeaders(res);
139
+ res.json({
140
+ ok: true,
141
+ plugin: pluginInfo.normalizedName,
142
+ version: pluginInfo.version,
143
+ status: devServer.app.locals.handlers?.rpc ? "ready" : "loading",
144
+ endpoints: {
145
+ health: "/",
146
+ docs: "/api",
147
+ rpc: `/api/rpc${rpcPrefix}`,
148
+ },
149
+ });
150
+ });
151
+
152
+ devServer.app.get("/health", (_req: any, res: any) => {
153
+ applyCorsHeaders(res);
154
+ res.status(200).send("OK");
155
+ });
156
+
157
+ const handleApiRequest = async (req: any, res: any) => {
158
+ applyCorsHeaders(res);
159
+ const apiHandler = devServer.app.locals.handlers?.api;
160
+ if (!apiHandler) {
161
+ return res.status(503).json({ error: "Plugin still loading..." });
162
+ }
163
+
164
+ try {
165
+ const url = `http://${req.headers.host}${req.url}`;
166
+ const webRequest = new Request(url, {
167
+ method: req.method,
168
+ headers: req.headers,
169
+ body: req.method !== "GET" && req.method !== "HEAD" ? req : undefined,
170
+ duplex: req.method !== "GET" && req.method !== "HEAD" ? "half" : undefined,
171
+ } as RequestInit);
172
+
173
+ const result = await apiHandler.handle(webRequest, {
174
+ prefix: "/api",
175
+ context: {},
176
+ });
177
+
178
+ if (result.response) {
179
+ res.status(result.response.status);
180
+ result.response.headers.forEach((value: string, key: string) => {
181
+ res.setHeader(key, value);
182
+ });
183
+ const text = await result.response.text();
184
+ res.send(text);
185
+ } else {
186
+ res.status(404).send("Not Found");
187
+ }
188
+ } catch (error) {
189
+ console.error("OpenAPI error:", error);
190
+ res.status(500).json({ error: (error as Error).message });
191
+ }
192
+ };
193
+
194
+ devServer.app.all(`/api/rpc${rpcPrefix}/*`, async (req: any, res: any) => {
195
+ applyCorsHeaders(res);
196
+ const rpcHandler = devServer.app.locals.handlers?.rpc;
197
+ if (!rpcHandler) {
198
+ return res.status(503).json({ error: "Plugin still loading..." });
199
+ }
200
+
201
+ try {
202
+ const url = `http://${req.headers.host}${req.url}`;
203
+ const webRequest = new Request(url, {
204
+ method: req.method,
205
+ headers: req.headers,
206
+ body: req.method !== "GET" && req.method !== "HEAD" ? req : undefined,
207
+ duplex: req.method !== "GET" && req.method !== "HEAD" ? "half" : undefined,
208
+ } as RequestInit);
209
+
210
+ const result = await rpcHandler.handle(webRequest, {
211
+ prefix: `/api/rpc${rpcPrefix}`,
212
+ context: {},
213
+ });
214
+
215
+ if (result.response) {
216
+ res.status(result.response.status);
217
+ result.response.headers.forEach((value: string, key: string) => {
218
+ res.setHeader(key, value);
219
+ });
220
+ const text = await result.response.text();
221
+ res.send(text);
222
+ } else {
223
+ res.status(404).send("Not Found");
224
+ }
225
+ } catch (error) {
226
+ console.error("RPC error:", error);
227
+ res.status(500).json({ error: (error as Error).message });
228
+ }
229
+ });
230
+
231
+ devServer.app.all("/api", handleApiRequest);
232
+ devServer.app.all("/api/*", handleApiRequest);
233
+ }
@@ -0,0 +1,49 @@
1
+ import type { Compiler, RspackPluginInstance } from "@rspack/core";
2
+
3
+ const MF_DATA_URI_MARKER = "data:text/javascript,";
4
+
5
+ export class FixMfDataUriPlugin implements RspackPluginInstance {
6
+ name = "FixMfDataUriPlugin";
7
+
8
+ apply(compiler: Compiler) {
9
+ compiler.hooks.compilation.tap(this.name, (_compilation, { normalModuleFactory }) => {
10
+ normalModuleFactory.hooks.beforeResolve.tap(this.name, (resolveData) => {
11
+ if (!resolveData?.request) return;
12
+ if (!resolveData.request.includes(MF_DATA_URI_MARKER)) return;
13
+ this.reencodeDataUri(resolveData);
14
+ });
15
+ });
16
+ }
17
+
18
+ private reencodeDataUri(resolveData: { request: string }) {
19
+ const { request } = resolveData;
20
+ const idx = request.indexOf(MF_DATA_URI_MARKER);
21
+ if (idx === -1) return;
22
+
23
+ const contentStart = idx + MF_DATA_URI_MARKER.length;
24
+ const prefix = request.substring(0, contentStart);
25
+ const rawContent = request.substring(contentStart);
26
+
27
+ if (isAlreadyEncoded(rawContent)) return;
28
+
29
+ const decoded = safeDecode(rawContent);
30
+ resolveData.request = prefix + encodeURIComponent(decoded);
31
+ }
32
+ }
33
+
34
+ function isAlreadyEncoded(content: string): boolean {
35
+ try {
36
+ const decoded = decodeURIComponent(content);
37
+ return decoded !== content;
38
+ } catch {
39
+ return false;
40
+ }
41
+ }
42
+
43
+ function safeDecode(content: string): string {
44
+ try {
45
+ return decodeURIComponent(content);
46
+ } catch {
47
+ return content.replace(/%(?![0-9A-Fa-f]{2})/g, "%25");
48
+ }
49
+ }
@@ -0,0 +1,14 @@
1
+ export {
2
+ getMajorMinorVersion,
3
+ getPluginSharedDependencies,
4
+ getPluginSharedDependenciesVersionRange,
5
+ type SharedDependencies,
6
+ type SharedDependencyConfig,
7
+ } from "../shared-deps";
8
+ export { FixMfDataUriPlugin } from "./fix-mf-data-uri-plugin";
9
+ export {
10
+ EmitPluginManifest,
11
+ EveryPluginDevServer,
12
+ type EveryPluginOptions,
13
+ type PluginManifestEmitterOptions,
14
+ } from "./plugin";
@@ -0,0 +1,6 @@
1
+ import { getPluginSharedDependencies } from "../shared-deps";
2
+ import type { PluginInfo } from "./utils";
3
+
4
+ export function buildSharedDependencies(_pluginInfo: PluginInfo) {
5
+ return getPluginSharedDependencies();
6
+ }
@@ -0,0 +1,252 @@
1
+ import crypto from "node:crypto";
2
+ import fs from "node:fs";
3
+ import path from "node:path";
4
+ import { ModuleFederationPlugin } from "@module-federation/enhanced/rspack";
5
+ import type { Compiler, RspackPluginInstance } from "@rspack/core";
6
+ import { setupPluginMiddleware } from "./dev-server-middleware";
7
+ import { buildSharedDependencies } from "./module-federation";
8
+ import { getPluginInfo, loadDevConfig } from "./utils";
9
+
10
+ export interface EveryPluginOptions {
11
+ devConfigPath?: string;
12
+ port?: number;
13
+ pluginId?: string;
14
+ dts?: boolean;
15
+ }
16
+
17
+ export interface PluginManifestEmitterOptions {
18
+ manifestFileName?: string;
19
+ contractFileName?: string;
20
+ }
21
+
22
+ export class EmitPluginManifest implements RspackPluginInstance {
23
+ name = "EmitPluginManifest";
24
+
25
+ constructor(private options: PluginManifestEmitterOptions = {}) {}
26
+
27
+ apply(compiler: Compiler) {
28
+ compiler.hooks.thisCompilation.tap(this.name, (compilation) => {
29
+ const webpack = (compiler as Compiler & { webpack?: any }).webpack;
30
+ const rawSource = webpack?.sources?.RawSource;
31
+ const stage = webpack?.Compilation?.PROCESS_ASSETS_STAGE_ADDITIONS ?? 1000;
32
+
33
+ compilation.hooks.processAssets.tapPromise({ name: this.name, stage }, async () => {
34
+ const context = compiler.options.context || process.cwd();
35
+ const pluginInfo = getPluginInfo(context);
36
+ const contractFileName = this.options.contractFileName ?? "contract.d.ts";
37
+ const manifestFileName = this.options.manifestFileName ?? "plugin.manifest.json";
38
+
39
+ const sourceContractPath = path.join(context, "types", contractFileName);
40
+
41
+ let contractTypes: string;
42
+
43
+ const tryReadFile = async (filePath: string): Promise<string | null> => {
44
+ if (!fs.existsSync(filePath)) {
45
+ return null;
46
+ }
47
+ const stats = fs.statSync(filePath);
48
+ if (!stats.isFile()) {
49
+ return null;
50
+ }
51
+ try {
52
+ return await fs.promises.readFile(filePath, "utf8");
53
+ } catch {
54
+ return null;
55
+ }
56
+ };
57
+
58
+ contractTypes = (await tryReadFile(sourceContractPath)) ?? "";
59
+
60
+ if (!contractTypes) {
61
+ const packageDir = context.split("/").pop();
62
+ const nestedPath = path.join(context, "types", packageDir ?? "", "src", contractFileName);
63
+
64
+ contractTypes = (await tryReadFile(nestedPath)) ?? "";
65
+
66
+ if (!contractTypes) {
67
+ console.warn(
68
+ `[EmitPluginManifest] Contract file not found at ${sourceContractPath} or ${nestedPath}. ` +
69
+ `Skipping manifest generation.`,
70
+ );
71
+ return;
72
+ }
73
+ }
74
+
75
+ const contractSha256 = crypto.createHash("sha256").update(contractTypes).digest("hex");
76
+ const manifest = {
77
+ schemaVersion: 1,
78
+ kind: "every-plugin/manifest",
79
+ plugin: {
80
+ name: pluginInfo.name,
81
+ version: pluginInfo.version,
82
+ },
83
+ runtime: {
84
+ remoteEntry: "./remoteEntry.js",
85
+ },
86
+ contract: {
87
+ kind: "orpc",
88
+ types: {
89
+ path: `./types/${contractFileName}`,
90
+ exportName: "contract",
91
+ typeName: "ContractType",
92
+ sha256: contractSha256,
93
+ },
94
+ },
95
+ };
96
+
97
+ if (rawSource) {
98
+ compilation.emitAsset(
99
+ manifestFileName,
100
+ new rawSource(`${JSON.stringify(manifest, null, 2)}\n`),
101
+ );
102
+ compilation.emitAsset(`types/${contractFileName}`, new rawSource(`${contractTypes}`));
103
+ }
104
+ });
105
+ });
106
+ }
107
+ }
108
+
109
+ export class EveryPluginDevServer implements RspackPluginInstance {
110
+ name = "EveryPluginDevServer";
111
+
112
+ constructor(private options: EveryPluginOptions = {}) {}
113
+
114
+ apply(compiler: Compiler) {
115
+ const pluginInfo = getPluginInfo(compiler.options.context || process.cwd());
116
+ const devConfig = loadDevConfig(this.options.devConfigPath || "./plugin.dev.ts");
117
+ const port = Number(process.env.PORT) || this.options.port || devConfig?.port || 3999;
118
+
119
+ this.configureDefaults(compiler, pluginInfo);
120
+
121
+ if (!compiler.options.devServer) {
122
+ compiler.options.devServer = {};
123
+ }
124
+
125
+ this.configureDevServer(compiler, pluginInfo, devConfig, port);
126
+
127
+ new ModuleFederationPlugin({
128
+ name: pluginInfo.normalizedName,
129
+ filename: "remoteEntry.js",
130
+ dts: this.options.dts !== false,
131
+ manifest: {},
132
+ runtimePlugins: [require.resolve("@module-federation/node/runtimePlugin")],
133
+ library: { type: "commonjs-module" },
134
+ exposes: {
135
+ "./plugin": "./src/index.ts",
136
+ },
137
+ shared: buildSharedDependencies(pluginInfo),
138
+ shareStrategy: "version-first",
139
+ }).apply(compiler);
140
+
141
+ if (this.options.dts === false) {
142
+ compiler.options.plugins = (compiler.options.plugins ?? []).filter(
143
+ (p) =>
144
+ !p ||
145
+ typeof p !== "object" ||
146
+ ((p as any).name !== "MFDevPlugin" && (p as any).name !== "ModuleFederationDtsPlugin"),
147
+ );
148
+ }
149
+ }
150
+
151
+ private configureDefaults(compiler: Compiler, pluginInfo: any) {
152
+ const context = compiler.options.context || process.cwd();
153
+
154
+ if (!compiler.options.output) {
155
+ compiler.options.output = {};
156
+ }
157
+ compiler.options.output.uniqueName = pluginInfo.normalizedName;
158
+ compiler.options.output.publicPath = "auto";
159
+ compiler.options.output.path = path.resolve(context, "dist");
160
+ compiler.options.output.clean = true;
161
+ compiler.options.output.library = { type: "commonjs-module" };
162
+
163
+ if (!compiler.options.target) {
164
+ compiler.options.target = "async-node";
165
+ }
166
+
167
+ if (!compiler.options.mode) {
168
+ compiler.options.mode = process.env.NODE_ENV === "development" ? "development" : "production";
169
+ }
170
+
171
+ if (!compiler.options.devtool) {
172
+ compiler.options.devtool = "source-map";
173
+ }
174
+
175
+ if (!compiler.options.infrastructureLogging) {
176
+ compiler.options.infrastructureLogging = {
177
+ level: "warn",
178
+ };
179
+ }
180
+
181
+ this.ensureTypeScriptLoader(compiler);
182
+
183
+ if (!compiler.options.resolve) {
184
+ compiler.options.resolve = {};
185
+ }
186
+ compiler.options.resolve.extensions = ["...", ".tsx", ".ts"];
187
+ compiler.options.resolve.fallback = {
188
+ ...compiler.options.resolve.fallback,
189
+ bufferutil: false,
190
+ "utf-8-validate": false,
191
+ };
192
+ }
193
+
194
+ private ensureTypeScriptLoader(compiler: Compiler) {
195
+ if (!compiler.options.module) {
196
+ compiler.options.module = { rules: [] } as any;
197
+ }
198
+
199
+ if (!compiler.options.module.rules) {
200
+ compiler.options.module.rules = [];
201
+ }
202
+
203
+ const hasTsLoader = compiler.options.module.rules.some(
204
+ (rule: any) =>
205
+ typeof rule === "object" &&
206
+ rule !== null &&
207
+ "test" in rule &&
208
+ rule.test instanceof RegExp &&
209
+ rule.test.test(".ts"),
210
+ );
211
+
212
+ if (!hasTsLoader) {
213
+ compiler.options.module.rules.push({
214
+ test: /\.tsx?$/,
215
+ use: "builtin:swc-loader",
216
+ exclude: /node_modules/,
217
+ });
218
+ }
219
+ }
220
+
221
+ private configureDevServer(compiler: Compiler, pluginInfo: any, devConfig: any, port: number) {
222
+ if (!compiler.options.devServer) {
223
+ return;
224
+ }
225
+
226
+ const context = compiler.options.context || process.cwd();
227
+ const originalSetup = compiler.options.devServer.setupMiddlewares;
228
+
229
+ compiler.options.devServer.port = port;
230
+ compiler.options.devServer.static = path.join(context, "dist");
231
+ compiler.options.devServer.hot = true;
232
+ compiler.options.devServer.devMiddleware = { writeToDisk: true };
233
+ compiler.options.devServer.headers = {
234
+ "Access-Control-Allow-Origin": "*",
235
+ "Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, PATCH, OPTIONS",
236
+ "Access-Control-Allow-Headers": "X-Requested-With, content-type, Authorization",
237
+ };
238
+
239
+ compiler.options.devServer.client = {
240
+ logging: "warn",
241
+ overlay: {
242
+ warnings: false,
243
+ errors: true,
244
+ },
245
+ };
246
+
247
+ compiler.options.devServer.setupMiddlewares = (middlewares, devServer) => {
248
+ setupPluginMiddleware(devServer, pluginInfo, devConfig, port);
249
+ return originalSetup ? originalSetup(middlewares, devServer) : middlewares;
250
+ };
251
+ }
252
+ }
@@ -0,0 +1,60 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import { getNormalizedRemoteName } from "every-plugin/normalize";
4
+
5
+ export interface PluginInfo {
6
+ name: string;
7
+ version: string;
8
+ normalizedName: string;
9
+ dependencies: Record<string, string>;
10
+ peerDependencies: Record<string, string>;
11
+ }
12
+
13
+ export function getPluginInfo(context: string): PluginInfo {
14
+ const pkgPath = path.join(context, "package.json");
15
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf-8"));
16
+
17
+ return {
18
+ name: pkg.name,
19
+ version: pkg.version,
20
+ normalizedName: getNormalizedRemoteName(pkg.name),
21
+ dependencies: pkg.dependencies || {},
22
+ peerDependencies: pkg.peerDependencies || {},
23
+ };
24
+ }
25
+
26
+ const loadedModules = new Set<string>();
27
+
28
+ export function loadDevConfig(devConfigPath: string) {
29
+ if (process.env.DEPLOY === "true") {
30
+ return null;
31
+ }
32
+
33
+ try {
34
+ const fullPath = path.resolve(devConfigPath);
35
+
36
+ if (loadedModules.has(fullPath)) {
37
+ delete require.cache[fullPath];
38
+ const dirPath = path.dirname(fullPath);
39
+ for (const key of Object.keys(require.cache)) {
40
+ if (key.startsWith(dirPath) && key !== fullPath) {
41
+ delete require.cache[key];
42
+ }
43
+ }
44
+ }
45
+
46
+ const module = require(fullPath).default;
47
+ loadedModules.add(fullPath);
48
+ return module;
49
+ } catch (error) {
50
+ console.warn(`Could not load dev config from ${devConfigPath}:`, (error as Error).message);
51
+ return null;
52
+ }
53
+ }
54
+
55
+ export function cleanupDevConfig() {
56
+ for (const modulePath of loadedModules) {
57
+ delete require.cache[modulePath];
58
+ }
59
+ loadedModules.clear();
60
+ }
@@ -0,0 +1,79 @@
1
+ import { readFileSync } from "node:fs";
2
+ import { createRequire } from "node:module";
3
+ import { dirname, join } from "node:path";
4
+ import { fileURLToPath } from "node:url";
5
+
6
+ const __dirname = dirname(fileURLToPath(import.meta.url));
7
+ const require = createRequire(import.meta.url);
8
+
9
+ let pkg: typeof import("../../package.json");
10
+
11
+ try {
12
+ pkg = JSON.parse(readFileSync(join(__dirname, "../../package.json"), "utf-8"));
13
+ } catch {
14
+ pkg = require("every-plugin/package.json");
15
+ }
16
+
17
+ export interface SharedDependencyConfig {
18
+ version: string;
19
+ requiredVersion: string | false;
20
+ singleton: boolean;
21
+ strictVersion: boolean;
22
+ eager: boolean;
23
+ }
24
+
25
+ export type SharedDependencies = Record<string, SharedDependencyConfig>;
26
+
27
+ const DEFAULT_SHARE_CONFIG: Omit<SharedDependencyConfig, "version"> = {
28
+ requiredVersion: false,
29
+ singleton: true,
30
+ strictVersion: false,
31
+ eager: false,
32
+ };
33
+
34
+ function extractExactVersion(input: string): string {
35
+ const match = input.match(/\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?/);
36
+ return match ? match[0] : input.replace(/^[\^~>=<\s]+/, "");
37
+ }
38
+
39
+ function getInstalledPackageVersion(packageName: string, fallbackVersion: string): string {
40
+ try {
41
+ return require(`${packageName}/package.json`).version as string;
42
+ } catch {
43
+ return extractExactVersion(fallbackVersion);
44
+ }
45
+ }
46
+
47
+ export const pluginSharedDependencies = {
48
+ "every-plugin": { version: pkg.version, ...DEFAULT_SHARE_CONFIG },
49
+ effect: {
50
+ version: getInstalledPackageVersion("effect", pkg.peerDependencies.effect),
51
+ ...DEFAULT_SHARE_CONFIG,
52
+ },
53
+ zod: {
54
+ version: getInstalledPackageVersion("zod", pkg.peerDependencies.zod),
55
+ ...DEFAULT_SHARE_CONFIG,
56
+ },
57
+ } satisfies SharedDependencies;
58
+
59
+ export type PluginSharedDependencyName = keyof typeof pluginSharedDependencies;
60
+
61
+ export function getPluginSharedDependencies(): SharedDependencies {
62
+ return pluginSharedDependencies;
63
+ }
64
+
65
+ export function getPluginSharedDependenciesVersionRange(): Record<string, string> {
66
+ return Object.fromEntries(
67
+ Object.entries(getPluginSharedDependencies()).map(([name, config]) => [
68
+ name,
69
+ getMajorMinorVersion(config.version),
70
+ ]),
71
+ );
72
+ }
73
+
74
+ export function getMajorMinorVersion(version: string): string {
75
+ const clean = version.replace(/^[\^~>=<]+/, "");
76
+ const match = clean.match(/^(\d+)\.(\d+)/);
77
+ if (!match) return "^0.0.0";
78
+ return `^${match[1]}.${match[2]}.0`;
79
+ }
package/src/effect.ts ADDED
@@ -0,0 +1 @@
1
+ export * from "effect";