everything-dev 1.5.0 → 1.7.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.
Files changed (108) hide show
  1. package/dist/api-contract.cjs +55 -8
  2. package/dist/api-contract.cjs.map +1 -1
  3. package/dist/api-contract.mjs +55 -8
  4. package/dist/api-contract.mjs.map +1 -1
  5. package/dist/app.cjs +26 -2
  6. package/dist/app.cjs.map +1 -1
  7. package/dist/app.mjs +27 -3
  8. package/dist/app.mjs.map +1 -1
  9. package/dist/cli/init.cjs +4 -4
  10. package/dist/cli/init.cjs.map +1 -1
  11. package/dist/cli/init.mjs +4 -4
  12. package/dist/cli/init.mjs.map +1 -1
  13. package/dist/cli/sync.cjs +4 -3
  14. package/dist/cli/sync.cjs.map +1 -1
  15. package/dist/cli/sync.mjs +4 -3
  16. package/dist/cli/sync.mjs.map +1 -1
  17. package/dist/cli.cjs +0 -1
  18. package/dist/cli.cjs.map +1 -1
  19. package/dist/cli.mjs +0 -1
  20. package/dist/cli.mjs.map +1 -1
  21. package/dist/components/streaming-view.cjs +0 -18
  22. package/dist/components/streaming-view.cjs.map +1 -1
  23. package/dist/components/streaming-view.mjs +0 -18
  24. package/dist/components/streaming-view.mjs.map +1 -1
  25. package/dist/config.cjs +21 -5
  26. package/dist/config.cjs.map +1 -1
  27. package/dist/config.d.cts +2 -1
  28. package/dist/config.d.cts.map +1 -1
  29. package/dist/config.d.mts +2 -1
  30. package/dist/config.d.mts.map +1 -1
  31. package/dist/config.mjs +21 -6
  32. package/dist/config.mjs.map +1 -1
  33. package/dist/contract.cjs +8 -1
  34. package/dist/contract.cjs.map +1 -1
  35. package/dist/contract.d.cts +44 -8
  36. package/dist/contract.d.cts.map +1 -1
  37. package/dist/contract.d.mts +44 -8
  38. package/dist/contract.d.mts.map +1 -1
  39. package/dist/contract.meta.cjs +1 -1
  40. package/dist/contract.meta.cjs.map +1 -1
  41. package/dist/contract.meta.d.cts +1 -1
  42. package/dist/contract.meta.d.mts +1 -1
  43. package/dist/contract.meta.mjs +1 -1
  44. package/dist/contract.meta.mjs.map +1 -1
  45. package/dist/contract.mjs +8 -1
  46. package/dist/contract.mjs.map +1 -1
  47. package/dist/dev-session.cjs +51 -66
  48. package/dist/dev-session.cjs.map +1 -1
  49. package/dist/dev-session.mjs +52 -67
  50. package/dist/dev-session.mjs.map +1 -1
  51. package/dist/fastkv.cjs +56 -0
  52. package/dist/fastkv.cjs.map +1 -1
  53. package/dist/fastkv.d.cts +45 -1
  54. package/dist/fastkv.d.cts.map +1 -1
  55. package/dist/fastkv.d.mts +45 -1
  56. package/dist/fastkv.d.mts.map +1 -1
  57. package/dist/fastkv.mjs +54 -1
  58. package/dist/fastkv.mjs.map +1 -1
  59. package/dist/host.cjs +1 -1
  60. package/dist/host.cjs.map +1 -1
  61. package/dist/host.mjs +1 -1
  62. package/dist/host.mjs.map +1 -1
  63. package/dist/index.cjs +4 -0
  64. package/dist/index.d.cts +4 -4
  65. package/dist/index.d.mts +4 -4
  66. package/dist/index.mjs +3 -3
  67. package/dist/near-cli.cjs +1 -1
  68. package/dist/near-cli.mjs +1 -1
  69. package/dist/orchestrator.cjs +55 -20
  70. package/dist/orchestrator.cjs.map +1 -1
  71. package/dist/orchestrator.d.cts +5 -4
  72. package/dist/orchestrator.d.cts.map +1 -1
  73. package/dist/orchestrator.d.mts +5 -4
  74. package/dist/orchestrator.d.mts.map +1 -1
  75. package/dist/orchestrator.mjs +55 -20
  76. package/dist/orchestrator.mjs.map +1 -1
  77. package/dist/plugin.cjs +135 -9
  78. package/dist/plugin.cjs.map +1 -1
  79. package/dist/plugin.d.cts +50 -9
  80. package/dist/plugin.d.cts.map +1 -1
  81. package/dist/plugin.d.mts +50 -9
  82. package/dist/plugin.d.mts.map +1 -1
  83. package/dist/plugin.mjs +137 -11
  84. package/dist/plugin.mjs.map +1 -1
  85. package/dist/types.cjs +15 -5
  86. package/dist/types.cjs.map +1 -1
  87. package/dist/types.d.cts +62 -11
  88. package/dist/types.d.cts.map +1 -1
  89. package/dist/types.d.mts +62 -11
  90. package/dist/types.d.mts.map +1 -1
  91. package/dist/types.mjs +15 -5
  92. package/dist/types.mjs.map +1 -1
  93. package/package.json +2 -2
  94. package/src/api-contract.ts +88 -9
  95. package/src/app.ts +55 -7
  96. package/src/cli/init.ts +6 -6
  97. package/src/cli/sync.ts +11 -4
  98. package/src/cli.ts +0 -1
  99. package/src/components/streaming-view.ts +0 -20
  100. package/src/config.ts +39 -23
  101. package/src/contract.meta.ts +4 -1
  102. package/src/contract.ts +7 -0
  103. package/src/dev-session.ts +85 -83
  104. package/src/fastkv.ts +95 -0
  105. package/src/host.ts +1 -1
  106. package/src/orchestrator.ts +61 -31
  107. package/src/plugin.ts +202 -5
  108. package/src/types.ts +38 -4
@@ -88,6 +88,15 @@ function localApiContractSource(configDir: string): ContractSource {
88
88
  };
89
89
  }
90
90
 
91
+ function localAuthContractSource(configDir: string): ContractSource {
92
+ const sourcePath = join(configDir, "plugins", "auth", "src", "contract.ts");
93
+ return {
94
+ key: "auth",
95
+ importName: "authContract",
96
+ sourceFilePath: sourcePath,
97
+ };
98
+ }
99
+
91
100
  async function remoteContractSource(opts: {
92
101
  configDir: string;
93
102
  runtimeDir: string;
@@ -134,6 +143,7 @@ async function resolveContractSource(opts: {
134
143
  source: RuntimePluginConfig | { url: string; localPath?: string; name: string } | null;
135
144
  baseUrl: string;
136
145
  generatedSubdir: string;
146
+ localSourceFactory?: (configDir: string) => ContractSource;
137
147
  }): Promise<ContractSource> {
138
148
  if (
139
149
  opts.key === "api" &&
@@ -153,6 +163,25 @@ async function resolveContractSource(opts: {
153
163
  }
154
164
  }
155
165
 
166
+ if (
167
+ opts.key === "auth" &&
168
+ opts.localSourceFactory &&
169
+ (!opts.source || !("localPath" in opts.source) || opts.source.localPath)
170
+ ) {
171
+ const localPath = opts.source && "localPath" in opts.source ? opts.source.localPath : undefined;
172
+ if (localPath) {
173
+ return {
174
+ key: opts.key,
175
+ importName: "authContract",
176
+ sourceFilePath: join(localPath, "src", "contract.ts"),
177
+ };
178
+ }
179
+
180
+ if (!opts.baseUrl) {
181
+ return opts.localSourceFactory(opts.configDir);
182
+ }
183
+ }
184
+
156
185
  if (opts.source && "localPath" in opts.source && opts.source.localPath) {
157
186
  return {
158
187
  key: opts.key,
@@ -170,10 +199,11 @@ async function resolveContractSource(opts: {
170
199
  });
171
200
  }
172
201
 
173
- function writeAggregateContractFile(opts: {
202
+ function writeGeneratedFiles(opts: {
174
203
  configDir: string;
175
204
  sources: ContractSource[];
176
205
  pluginKeys: string[];
206
+ authSource: ContractSource | null;
177
207
  }) {
178
208
  const baseSource = opts.sources.find((source) => source.key === "api");
179
209
  const pluginSources = opts.pluginKeys
@@ -194,15 +224,22 @@ function writeAggregateContractFile(opts: {
194
224
  }
195
225
 
196
226
  uiLines.push("");
197
- if (pluginSources.length === 0) {
227
+
228
+ const compositeParts: string[] = [];
229
+ if (opts.authSource) {
230
+ compositeParts.push(`auth: ${opts.authSource.importName}`);
231
+ }
232
+ for (const source of pluginSources) {
233
+ const key = /^[$A-Z_][0-9A-Z_$]*$/i.test(source.key) ? source.key : JSON.stringify(source.key);
234
+ compositeParts.push(`${key}: ${source.importName}`);
235
+ }
236
+
237
+ if (compositeParts.length === 0) {
198
238
  uiLines.push(`export type ApiContract = ${baseSource.importName};`);
199
239
  } else {
200
240
  uiLines.push(`export type ApiContract = ${baseSource.importName} & {`);
201
- for (const source of pluginSources) {
202
- const key = /^[$A-Z_][0-9A-Z_$]*$/i.test(source.key)
203
- ? source.key
204
- : JSON.stringify(source.key);
205
- uiLines.push(` ${key}: ${source.importName};`);
241
+ for (const part of compositeParts) {
242
+ uiLines.push(` ${part};`);
206
243
  }
207
244
  uiLines.push("};");
208
245
  }
@@ -244,6 +281,28 @@ function writeAggregateContractFile(opts: {
244
281
  mkdirSync(dirname(pluginsClientPath), { recursive: true });
245
282
  writeFileIfChanged(pluginsClientPath, `${pluginsClientLines.join("\n")}\n`);
246
283
 
284
+ // --- Generate api/src/auth-client.gen.ts ---
285
+ if (opts.authSource) {
286
+ const authClientPath = join(opts.configDir, "api", "src", "auth-client.gen.ts");
287
+ const authClientLines: string[] = [];
288
+
289
+ const importPath = toImportPath(authClientPath, opts.authSource.sourceFilePath);
290
+ authClientLines.push(
291
+ `import type { ContractType as ${opts.authSource.importName} } from "${importPath}";`,
292
+ );
293
+ authClientLines.push(
294
+ 'import type { ContractRouterClient, AnyContractRouter } from "@orpc/contract";',
295
+ );
296
+ authClientLines.push(
297
+ "type ClientFactory<C extends AnyContractRouter> = (context?: Record<string, unknown>) => ContractRouterClient<C>;",
298
+ );
299
+ authClientLines.push("");
300
+ authClientLines.push(`export type AuthClient = ClientFactory<${opts.authSource.importName}>;`);
301
+
302
+ mkdirSync(dirname(authClientPath), { recursive: true });
303
+ writeFileIfChanged(authClientPath, `${authClientLines.join("\n")}\n`);
304
+ }
305
+
247
306
  return uiContractPath;
248
307
  }
249
308
 
@@ -264,6 +323,7 @@ export async function syncApiContractBridge(opts: {
264
323
  const sources: ContractSource[] = [];
265
324
  let manifest: ApiPluginManifest | null = null;
266
325
  let generatedPath: string | null = null;
326
+ let authSource: ContractSource | null = null;
267
327
 
268
328
  const baseSource = await resolveContractSource({
269
329
  configDir: opts.configDir,
@@ -275,6 +335,22 @@ export async function syncApiContractBridge(opts: {
275
335
  });
276
336
  sources.push(baseSource);
277
337
 
338
+ if (opts.runtimeConfig.auth) {
339
+ authSource = await resolveContractSource({
340
+ configDir: opts.configDir,
341
+ runtimeDir,
342
+ key: "auth",
343
+ source: opts.runtimeConfig.auth,
344
+ baseUrl: opts.runtimeConfig.auth.url,
345
+ generatedSubdir: "auth",
346
+ localSourceFactory: localAuthContractSource,
347
+ });
348
+ sources.push(authSource);
349
+ if (authSource.generatedPath) {
350
+ generatedPath = authSource.generatedPath;
351
+ }
352
+ }
353
+
278
354
  for (const [key, plugin] of pluginEntries) {
279
355
  const source = await resolveContractSource({
280
356
  configDir: opts.configDir,
@@ -290,10 +366,13 @@ export async function syncApiContractBridge(opts: {
290
366
  }
291
367
  }
292
368
 
293
- writeAggregateContractFile({
369
+ const allPluginKeys = pluginEntries.map(([key]) => key);
370
+
371
+ writeGeneratedFiles({
294
372
  configDir: opts.configDir,
295
373
  sources,
296
- pluginKeys: pluginEntries.map(([key]) => key),
374
+ pluginKeys: allPluginKeys,
375
+ authSource,
297
376
  });
298
377
 
299
378
  if (opts.runtimeConfig.api.source !== "local") {
package/src/app.ts CHANGED
@@ -7,6 +7,7 @@ import {
7
7
  isLocalDevelopmentTarget,
8
8
  parsePort,
9
9
  resolveLocalDevelopmentPath,
10
+ resolvePluginRuntimeName,
10
11
  } from "./config";
11
12
  import { getNetworkIdForAccount } from "./network";
12
13
  import { makeDevProcess, type ProcessCallbacks, type ProcessHandle } from "./orchestrator";
@@ -23,10 +24,11 @@ export interface AppOrchestrator {
23
24
  interactive?: boolean;
24
25
  }
25
26
 
26
- const STARTUP_ORDER = ["ui-ssr", "ui", "api", "plugin", "host-build", "host"];
27
+ const STARTUP_ORDER = ["ui-ssr", "ui", "auth", "api", "plugin", "host-build", "host"];
27
28
  const DEFAULT_HOST_PORT = 3000;
28
29
  const DEFAULT_UI_PORT = 3002;
29
30
  const DEFAULT_API_PORT = 3014;
31
+ const DEFAULT_AUTH_PORT = 3020;
30
32
  const DEFAULT_PLUGIN_PORT_START = 3021;
31
33
 
32
34
  const sortByOrder = (packages: string[]): string[] => {
@@ -115,10 +117,7 @@ export const startDevServers = (
115
117
  const shutdown = Effect.gen(function* () {
116
118
  const reversed = [...handles].reverse();
117
119
  for (const handle of reversed) {
118
- yield* Effect.tryPromise({
119
- try: () => handle.kill(),
120
- catch: () => null,
121
- }).pipe(Effect.ignore);
120
+ yield* handle.kill.pipe(Effect.ignore);
122
121
  }
123
122
  });
124
123
 
@@ -162,6 +161,13 @@ export function detectLocalPackages(
162
161
  }
163
162
  }
164
163
 
164
+ const authLocalPath =
165
+ runtimeConfig?.auth?.localPath ??
166
+ resolveLocalDevelopmentPath(bosConfig?.app.auth?.development, configDir);
167
+ if (authLocalPath && existsSync(join(authLocalPath, "package.json"))) {
168
+ packages.push("auth");
169
+ }
170
+
165
171
  return packages;
166
172
  }
167
173
 
@@ -170,6 +176,7 @@ export function buildRuntimeConfig(
170
176
  options: {
171
177
  uiSource?: "local" | "remote";
172
178
  apiSource?: "local" | "remote";
179
+ authSource?: "local" | "remote";
173
180
  hostUrl: string;
174
181
  proxy?: string;
175
182
  env?: "development" | "production";
@@ -179,10 +186,15 @@ export function buildRuntimeConfig(
179
186
  const configDir = getProjectRoot();
180
187
  const uiConfig = bosConfig.app.ui;
181
188
  const apiConfig = bosConfig.app.api;
189
+ const authConfig = bosConfig.app.auth;
182
190
  const uiSource = options.uiSource ?? "local";
183
191
  const apiSource = options.apiSource ?? "local";
192
+ const authSource = options.authSource ?? "local";
184
193
  const uiLocalPath = resolveLocalDevelopmentPath(uiConfig.development, configDir);
185
194
  const apiLocalPath = resolveLocalDevelopmentPath(apiConfig.development, configDir);
195
+ const authLocalPath = authConfig
196
+ ? resolveLocalDevelopmentPath(authConfig.development, configDir)
197
+ : null;
186
198
  const uiLocalUrl =
187
199
  !uiLocalPath && uiConfig.development && !isLocalDevelopmentTarget(uiConfig.development)
188
200
  ? uiConfig.development
@@ -191,6 +203,13 @@ export function buildRuntimeConfig(
191
203
  !apiLocalPath && apiConfig.development && !isLocalDevelopmentTarget(apiConfig.development)
192
204
  ? apiConfig.development
193
205
  : "";
206
+ const authLocalUrl =
207
+ authConfig &&
208
+ !authLocalPath &&
209
+ authConfig.development &&
210
+ !isLocalDevelopmentTarget(authConfig.development)
211
+ ? authConfig.development
212
+ : "";
194
213
 
195
214
  return {
196
215
  env: options.env ?? "development",
@@ -213,7 +232,7 @@ export function buildRuntimeConfig(
213
232
  port: uiSource === "local" && uiLocalUrl ? parsePort(uiLocalUrl) : undefined,
214
233
  ssrUrl: uiSource === "remote" ? uiConfig.ssr : undefined,
215
234
  ssrIntegrity: uiSource === "remote" ? uiConfig.ssrIntegrity : undefined,
216
- integrity: uiSource === "remote" ? uiConfig.productionIntegrity : undefined,
235
+ integrity: uiSource === "remote" ? uiConfig.integrity : undefined,
217
236
  source: uiSource === "local" ? (uiLocalPath ? "local" : "remote") : "remote",
218
237
  }
219
238
  : {
@@ -238,7 +257,7 @@ export function buildRuntimeConfig(
238
257
  proxy: options.proxy ?? apiConfig.proxy,
239
258
  variables: apiConfig.variables,
240
259
  secrets: apiConfig.secrets,
241
- integrity: apiSource === "remote" ? apiConfig.productionIntegrity : undefined,
260
+ integrity: apiSource === "remote" ? apiConfig.integrity : undefined,
242
261
  }
243
262
  : {
244
263
  name: "api",
@@ -246,6 +265,29 @@ export function buildRuntimeConfig(
246
265
  entry: "/mf-manifest.json",
247
266
  source: apiSource,
248
267
  },
268
+ auth: authConfig
269
+ ? {
270
+ name: resolvePluginRuntimeName(
271
+ undefined,
272
+ authSource === "local" ? (authLocalPath ?? undefined) : undefined,
273
+ authConfig.name,
274
+ ),
275
+ url: authSource === "remote" ? (authConfig.production ?? "") : authLocalUrl,
276
+ entry:
277
+ authSource === "remote"
278
+ ? `${authConfig.production ?? ""}/mf-manifest.json`
279
+ : authLocalUrl
280
+ ? `${authLocalUrl}/mf-manifest.json`
281
+ : "/mf-manifest.json",
282
+ localPath: authSource === "local" ? (authLocalPath ?? undefined) : undefined,
283
+ port: authSource === "local" && authLocalUrl ? parsePort(authLocalUrl) : undefined,
284
+ source: authSource === "local" ? (authLocalPath ? "local" : "remote") : "remote",
285
+ proxy: authConfig.proxy,
286
+ variables: authConfig.variables,
287
+ secrets: authConfig.secrets,
288
+ integrity: authSource === "remote" ? authConfig.integrity : undefined,
289
+ }
290
+ : undefined,
249
291
  plugins: options.plugins,
250
292
  };
251
293
  }
@@ -308,6 +350,7 @@ export async function prepareDevelopmentRuntimeConfig(
308
350
  hostUrl: `http://localhost:${hostPort}`,
309
351
  ui: { ...runtimeConfig.ui },
310
352
  api: { ...runtimeConfig.api },
353
+ auth: runtimeConfig.auth ? { ...runtimeConfig.auth } : undefined,
311
354
  plugins: runtimeConfig.plugins ? { ...runtimeConfig.plugins } : undefined,
312
355
  };
313
356
 
@@ -342,5 +385,10 @@ export async function prepareDevelopmentRuntimeConfig(
342
385
  }
343
386
  }
344
387
 
388
+ if (next.auth?.source === "local" && next.auth.localPath) {
389
+ const authPort = await pickAvailablePort(next.auth.port ?? DEFAULT_AUTH_PORT, usedPorts);
390
+ next.auth = withLocalRuntimeUrl(next.auth, authPort);
391
+ }
392
+
345
393
  return next;
346
394
  }
package/src/cli/init.ts CHANGED
@@ -223,8 +223,8 @@ export async function copyFilteredFiles(
223
223
  const stat = lstatSync(src);
224
224
  if (!stat.isFile()) continue;
225
225
 
226
- const destPath = filePath.startsWith(".templates/")
227
- ? filePath.slice(".templates/".length)
226
+ const destPath = filePath.startsWith(".github/templates/")
227
+ ? filePath.replace(/^\.github\/templates\//, ".github/")
228
228
  : filePath;
229
229
  const dest = join(destination, destPath);
230
230
  mkdirSync(dirname(dest), { recursive: true });
@@ -281,7 +281,7 @@ export async function personalizeConfig(
281
281
  if (entry && typeof entry === "object") {
282
282
  const e = entry as Record<string, unknown>;
283
283
  delete e.production;
284
- delete e.productionIntegrity;
284
+ delete e.integrity;
285
285
  delete e.ssr;
286
286
  delete e.ssrIntegrity;
287
287
  }
@@ -304,7 +304,7 @@ export async function personalizeConfig(
304
304
  if (plugin && typeof plugin === "object") {
305
305
  const p = plugin as Record<string, unknown>;
306
306
  delete p.production;
307
- delete p.productionIntegrity;
307
+ delete p.integrity;
308
308
  }
309
309
  }
310
310
 
@@ -500,8 +500,8 @@ export async function writeInitSnapshot(
500
500
  const stat = lstatSync(src);
501
501
  if (!stat.isFile()) continue;
502
502
  const content = readFileSync(src);
503
- const destPath = filePath.startsWith(".templates/")
504
- ? filePath.slice(".templates/".length)
503
+ const destPath = filePath.startsWith(".github/templates/")
504
+ ? filePath.replace(/^\.github\/templates\//, ".github/")
505
505
  : filePath;
506
506
  fileHashes[destPath] = computeHash(content);
507
507
  }
package/src/cli/sync.ts CHANGED
@@ -80,7 +80,12 @@ function mergePackageJson(
80
80
  ): Record<string, unknown> {
81
81
  const merged = { ...template };
82
82
 
83
- for (const depField of ["dependencies", "devDependencies", "peerDependencies"] as const) {
83
+ for (const depField of [
84
+ "dependencies",
85
+ "devDependencies",
86
+ "peerDependencies",
87
+ "overrides",
88
+ ] as const) {
84
89
  const localDeps = local[depField] as Record<string, string> | undefined;
85
90
  const templateDeps = template[depField] as Record<string, string> | undefined;
86
91
 
@@ -112,13 +117,15 @@ function mergePackageJson(
112
117
  }
113
118
 
114
119
  function toDestPath(filePath: string): string {
115
- return filePath.startsWith(".templates/") ? filePath.slice(".templates/".length) : filePath;
120
+ return filePath.startsWith(".github/templates/")
121
+ ? filePath.replace(/^\.github\/templates\//, ".github/")
122
+ : filePath;
116
123
  }
117
124
 
118
125
  function writeSyncedFile(sourceDir: string, projectDir: string, filePath: string): void {
119
126
  const src = join(sourceDir, filePath);
120
- const destPath = filePath.startsWith(".templates/")
121
- ? filePath.slice(".templates/".length)
127
+ const destPath = filePath.startsWith(".github/templates/")
128
+ ? filePath.replace(/^\.github\/templates\//, ".github/")
122
129
  : filePath;
123
130
  const dest = join(projectDir, destPath);
124
131
  mkdirSync(dirname(dest), { recursive: true });
package/src/cli.ts CHANGED
@@ -119,7 +119,6 @@ async function main() {
119
119
  console.log();
120
120
  console.log(colors.dim(" Next steps:"));
121
121
  console.log(colors.dim(` cd ${result.directory}`));
122
- console.log(colors.dim(" cp .env.example .env # then fill in your values"));
123
122
  if (result.status === "initialized" && !(input as any)?.noInstall) {
124
123
  console.log(colors.dim(" bun run dev"));
125
124
  } else {
@@ -163,25 +163,5 @@ export function renderStreamingView(
163
163
 
164
164
  const unmount = () => onExit?.();
165
165
 
166
- let signalCount = 0;
167
- const forceExit = () => {
168
- console.log("\n[CLI] Force exit");
169
- process.exit(0);
170
- };
171
-
172
- process.on("SIGINT", () => {
173
- signalCount++;
174
- if (signalCount > 1) {
175
- forceExit();
176
- return;
177
- }
178
- console.log();
179
- console.log(colors.dim(`[${getTimestamp()}] Shutting down...`));
180
- const timeout = setTimeout(forceExit, 5000);
181
- Promise.resolve(unmount()).then(() => {
182
- clearTimeout(timeout);
183
- });
184
- });
185
-
186
166
  return { updateProcess, addLog, unmount };
187
167
  }
package/src/config.ts CHANGED
@@ -2,22 +2,9 @@ import { existsSync, readFileSync } from "node:fs";
2
2
  import { dirname, isAbsolute, join, resolve } from "node:path";
3
3
  import { fetchBosConfigFromFastKv } from "./fastkv";
4
4
  import { getNetworkIdForAccount } from "./network";
5
- import type { BosConfig, RuntimeConfig, RuntimePluginConfig } from "./types";
5
+ import type { BosConfig, BosConfigInput, RuntimeConfig, RuntimePluginConfig } from "./types";
6
6
  import { BosConfigSchema } from "./types";
7
7
 
8
- interface BosConfigInput extends Record<string, unknown> {
9
- extends?: string;
10
- development?: string;
11
- production?: string;
12
- productionIntegrity?: string;
13
- proxy?: string;
14
- variables?: Record<string, string>;
15
- secrets?: string[];
16
- app?: Record<string, Record<string, unknown>>;
17
- shared?: Record<string, Record<string, Record<string, unknown>>>;
18
- plugins?: Record<string, BosConfigInput>;
19
- }
20
-
21
8
  const LOCAL_PREFIX = "local:";
22
9
  const DEFAULT_HOST_PORT = 3000;
23
10
 
@@ -143,6 +130,7 @@ function buildRuntimeConfig(
143
130
  ): RuntimeConfig {
144
131
  const uiConfig = config.app.ui;
145
132
  const apiConfig = config.app.api;
133
+ const authConfig = config.app.auth;
146
134
  const uiRuntime =
147
135
  env === "development"
148
136
  ? resolveRuntimeTarget(uiConfig.development, baseDir)
@@ -151,6 +139,11 @@ function buildRuntimeConfig(
151
139
  env === "development"
152
140
  ? resolveRuntimeTarget(apiConfig.development, baseDir)
153
141
  : resolveRuntimeTarget(apiConfig.production, baseDir, "remote");
142
+ const authRuntime = authConfig
143
+ ? env === "development"
144
+ ? resolveRuntimeTarget(authConfig.development, baseDir)
145
+ : resolveRuntimeTarget(authConfig.production, baseDir, "remote")
146
+ : undefined;
154
147
 
155
148
  return {
156
149
  env,
@@ -171,7 +164,7 @@ function buildRuntimeConfig(
171
164
  port: uiRuntime.port,
172
165
  ssrUrl: uiConfig.ssr,
173
166
  ssrIntegrity: env === "production" ? uiConfig.ssrIntegrity : undefined,
174
- integrity: env === "production" ? uiConfig.productionIntegrity : undefined,
167
+ integrity: env === "production" ? uiConfig.integrity : undefined,
175
168
  source: uiRuntime.source,
176
169
  },
177
170
  api: {
@@ -184,8 +177,22 @@ function buildRuntimeConfig(
184
177
  proxy: apiConfig.proxy,
185
178
  variables: apiConfig.variables,
186
179
  secrets: apiConfig.secrets,
187
- integrity: env === "production" ? apiConfig.productionIntegrity : undefined,
180
+ integrity: env === "production" ? apiConfig.integrity : undefined,
188
181
  },
182
+ auth: authConfig
183
+ ? {
184
+ name: resolvePluginRuntimeName(undefined, authRuntime!.localPath, authConfig.name),
185
+ url: authRuntime!.url,
186
+ entry: authRuntime!.url ? `${authRuntime!.url}/mf-manifest.json` : "/mf-manifest.json",
187
+ localPath: authRuntime!.localPath,
188
+ port: authRuntime!.port,
189
+ source: authRuntime!.source,
190
+ proxy: authConfig.proxy,
191
+ variables: authConfig.variables,
192
+ secrets: authConfig.secrets,
193
+ integrity: env === "production" ? authConfig.integrity : undefined,
194
+ }
195
+ : undefined,
189
196
  plugins:
190
197
  options?.plugins && Object.keys(options.plugins).length > 0 ? options.plugins : undefined,
191
198
  };
@@ -264,11 +271,25 @@ async function resolveRuntimePlugins(
264
271
  env,
265
272
  pluginInput,
266
273
  );
274
+ if (
275
+ pluginInput.name &&
276
+ typeof pluginInput.name === "string" &&
277
+ !pluginRuntime.name.includes("/")
278
+ ) {
279
+ pluginRuntime.name = pluginInput.name;
280
+ }
281
+
282
+ const integrity = pluginInput.integrity;
283
+ if (env === "production" && integrity) {
284
+ pluginRuntime.integrity = integrity;
285
+ }
286
+
267
287
  if (
268
288
  pluginRuntime.source === "remote" &&
269
289
  pluginRuntime.url &&
270
290
  !pluginRuntime.localPath &&
271
- typeof resolvedConfig.app?.api?.name !== "string"
291
+ typeof resolvedConfig.app?.api?.name !== "string" &&
292
+ !pluginInput.name
272
293
  ) {
273
294
  pluginRuntime.name = await resolveRemotePluginRuntimeName(
274
295
  pluginRuntime.url,
@@ -276,11 +297,6 @@ async function resolveRuntimePlugins(
276
297
  );
277
298
  }
278
299
 
279
- const productionIntegrity = pluginInput.productionIntegrity;
280
- if (env === "production" && productionIntegrity) {
281
- pluginRuntime.integrity = productionIntegrity;
282
- }
283
-
284
300
  out[runtimeKey] = pluginRuntime;
285
301
 
286
302
  if (resolvedConfig.plugins && Object.keys(resolvedConfig.plugins).length > 0) {
@@ -353,7 +369,7 @@ function buildRuntimePluginConfig(
353
369
  };
354
370
  }
355
371
 
356
- function resolvePluginRuntimeName(
372
+ export function resolvePluginRuntimeName(
357
373
  explicitName: string | undefined,
358
374
  localPath: string | undefined,
359
375
  fallback: string,
@@ -42,7 +42,10 @@ export const cliCommandMeta = {
42
42
  summary: "Add a plugin attachment",
43
43
  interactive: false,
44
44
  fields: {
45
- source: { positional: true, description: "Plugin source (local:path or URL)" },
45
+ source: {
46
+ positional: true,
47
+ description: "Plugin source (local:path, bos://account/plugins/name, or URL)",
48
+ },
46
49
  as: { description: "Plugin alias" },
47
50
  production: { description: "Production URL override" },
48
51
  },
package/src/contract.ts CHANGED
@@ -60,6 +60,8 @@ export const PluginAddResultSchema = z.object({
60
60
  key: z.string(),
61
61
  development: z.string().optional(),
62
62
  production: z.string().optional(),
63
+ integrity: z.string().optional(),
64
+ version: z.string().optional(),
63
65
  error: z.string().optional(),
64
66
  });
65
67
 
@@ -82,6 +84,9 @@ export const PluginListResultSchema = z.object({
82
84
  production: z.string().optional(),
83
85
  localPath: z.string().optional(),
84
86
  source: z.enum(["local", "remote"]),
87
+ integrity: z.string().optional(),
88
+ version: z.string().optional(),
89
+ name: z.string().optional(),
85
90
  }),
86
91
  ),
87
92
  error: z.string().optional(),
@@ -97,6 +102,8 @@ export const PluginPublishResultSchema = z.object({
97
102
  path: z.string().optional(),
98
103
  script: z.string().optional(),
99
104
  production: z.string().optional(),
105
+ integrity: z.string().optional(),
106
+ version: z.string().optional(),
100
107
  error: z.string().optional(),
101
108
  });
102
109