everything-dev 1.27.0 → 1.28.1

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 (114) hide show
  1. package/dist/cli/infra.cjs +1 -1
  2. package/dist/cli/infra.mjs +1 -1
  3. package/dist/cli/init.cjs +34 -9
  4. package/dist/cli/init.cjs.map +1 -1
  5. package/dist/cli/init.d.cts +2 -1
  6. package/dist/cli/init.d.cts.map +1 -1
  7. package/dist/cli/init.d.mts +2 -1
  8. package/dist/cli/init.d.mts.map +1 -1
  9. package/dist/cli/init.mjs +34 -9
  10. package/dist/cli/init.mjs.map +1 -1
  11. package/dist/cli/prompts.cjs +28 -24
  12. package/dist/cli/prompts.cjs.map +1 -1
  13. package/dist/cli/prompts.mjs +27 -24
  14. package/dist/cli/prompts.mjs.map +1 -1
  15. package/dist/cli/sync.cjs +40 -3
  16. package/dist/cli/sync.cjs.map +1 -1
  17. package/dist/cli/sync.mjs +40 -3
  18. package/dist/cli/sync.mjs.map +1 -1
  19. package/dist/cli.cjs +187 -12
  20. package/dist/cli.cjs.map +1 -1
  21. package/dist/cli.mjs +186 -11
  22. package/dist/cli.mjs.map +1 -1
  23. package/dist/config.cjs +1 -0
  24. package/dist/config.cjs.map +1 -1
  25. package/dist/config.d.cts.map +1 -1
  26. package/dist/config.d.mts.map +1 -1
  27. package/dist/config.mjs +1 -0
  28. package/dist/config.mjs.map +1 -1
  29. package/dist/contract.cjs +1 -1
  30. package/dist/contract.cjs.map +1 -1
  31. package/dist/contract.d.cts +38 -34
  32. package/dist/contract.d.cts.map +1 -1
  33. package/dist/contract.d.mts +38 -34
  34. package/dist/contract.d.mts.map +1 -1
  35. package/dist/contract.mjs +1 -0
  36. package/dist/contract.mjs.map +1 -1
  37. package/dist/dev-session.cjs +0 -1
  38. package/dist/dev-session.mjs +1 -1
  39. package/dist/index.cjs +0 -2
  40. package/dist/index.d.cts +2 -2
  41. package/dist/index.d.mts +2 -2
  42. package/dist/index.mjs +0 -1
  43. package/dist/near-cli.cjs +1 -1
  44. package/dist/near-cli.mjs +1 -1
  45. package/dist/orchestrator.cjs +1 -1
  46. package/dist/orchestrator.mjs +1 -1
  47. package/dist/plugin.cjs +183 -151
  48. package/dist/plugin.cjs.map +1 -1
  49. package/dist/plugin.d.cts +67 -34
  50. package/dist/plugin.d.cts.map +1 -1
  51. package/dist/plugin.d.mts +66 -34
  52. package/dist/plugin.d.mts.map +1 -1
  53. package/dist/plugin.mjs +173 -142
  54. package/dist/plugin.mjs.map +1 -1
  55. package/dist/service-descriptor.d.cts +34 -0
  56. package/dist/service-descriptor.d.cts.map +1 -0
  57. package/dist/service-descriptor.d.mts +36 -0
  58. package/dist/service-descriptor.d.mts.map +1 -0
  59. package/dist/types.d.cts +2 -2
  60. package/dist/types.d.mts +2 -2
  61. package/dist/utils/run.cjs +9 -20
  62. package/dist/utils/run.cjs.map +1 -1
  63. package/dist/utils/run.mjs +9 -20
  64. package/dist/utils/run.mjs.map +1 -1
  65. package/package.json +2 -2
  66. package/src/api-contract.ts +0 -623
  67. package/src/app.ts +0 -193
  68. package/src/cli/catalog.ts +0 -49
  69. package/src/cli/framework-version.ts +0 -61
  70. package/src/cli/help.ts +0 -13
  71. package/src/cli/infra.ts +0 -190
  72. package/src/cli/init.ts +0 -1145
  73. package/src/cli/parse.ts +0 -147
  74. package/src/cli/prompts.ts +0 -135
  75. package/src/cli/snapshot.ts +0 -46
  76. package/src/cli/status.ts +0 -99
  77. package/src/cli/sync.ts +0 -429
  78. package/src/cli/timing.ts +0 -63
  79. package/src/cli/upgrade.ts +0 -869
  80. package/src/cli.ts +0 -516
  81. package/src/components/dev-view.tsx +0 -352
  82. package/src/components/streaming-view.ts +0 -177
  83. package/src/config.ts +0 -893
  84. package/src/contract.meta.ts +0 -140
  85. package/src/contract.ts +0 -326
  86. package/src/dev-logs.ts +0 -92
  87. package/src/dev-session.ts +0 -283
  88. package/src/fastkv.ts +0 -181
  89. package/src/index.ts +0 -8
  90. package/src/integrity.ts +0 -138
  91. package/src/internal/manifest-normalizer.ts +0 -290
  92. package/src/merge.ts +0 -187
  93. package/src/mf.ts +0 -147
  94. package/src/near-cli.ts +0 -259
  95. package/src/network.ts +0 -3
  96. package/src/orchestrator.ts +0 -493
  97. package/src/plugin.ts +0 -1799
  98. package/src/sdk.ts +0 -14
  99. package/src/service-descriptor.ts +0 -281
  100. package/src/shared.ts +0 -249
  101. package/src/sidebar.ts +0 -140
  102. package/src/types.ts +0 -330
  103. package/src/ui/head.ts +0 -83
  104. package/src/ui/index.ts +0 -5
  105. package/src/ui/metadata.ts +0 -95
  106. package/src/ui/router.ts +0 -88
  107. package/src/ui/runtime.ts +0 -42
  108. package/src/ui/types.ts +0 -65
  109. package/src/utils/banner.ts +0 -21
  110. package/src/utils/linkify.ts +0 -11
  111. package/src/utils/path-match.ts +0 -16
  112. package/src/utils/run.ts +0 -31
  113. package/src/utils/save-config.ts +0 -20
  114. package/src/utils/theme.ts +0 -39
@@ -1 +1 @@
1
- {"version":3,"file":"run.mjs","names":[],"sources":["../../src/utils/run.ts"],"sourcesContent":["type RunResult = { stdout: string; stderr: string; exitCode: number };\n\nexport async function run(\n cmd: string,\n args: string[],\n options: { cwd?: string; env?: Record<string, string>; capture?: boolean } = {},\n): Promise<RunResult | undefined> {\n const proc = Bun.spawn({\n cmd: [cmd, ...args],\n cwd: options.cwd,\n env: options.env ? { ...(process.env as Record<string, string>), ...options.env } : process.env,\n stdio: options.capture ? [\"inherit\", \"pipe\", \"pipe\"] : [\"inherit\", \"inherit\", \"inherit\"],\n });\n\n if (!options.capture) {\n const exitCode = await proc.exited;\n if (exitCode !== 0) {\n throw new Error(`${cmd} ${args.join(\" \")} failed with exit code ${exitCode}`);\n }\n return;\n }\n\n const [stdout, stderr, exitCode] = await Promise.all([\n new Response(proc.stdout).text(),\n new Response(proc.stderr).text(),\n proc.exited,\n ]);\n\n const result = { stdout, stderr, exitCode };\n return result;\n}\n"],"mappings":";AAEA,eAAsB,IACpB,KACA,MACA,UAA6E,EAAE,EAC/C;CAChC,MAAM,OAAO,IAAI,MAAM;EACrB,KAAK,CAAC,KAAK,GAAG,KAAK;EACnB,KAAK,QAAQ;EACb,KAAK,QAAQ,MAAM;GAAE,GAAI,QAAQ;GAAgC,GAAG,QAAQ;GAAK,GAAG,QAAQ;EAC5F,OAAO,QAAQ,UAAU;GAAC;GAAW;GAAQ;GAAO,GAAG;GAAC;GAAW;GAAW;GAAU;EACzF,CAAC;AAEF,KAAI,CAAC,QAAQ,SAAS;EACpB,MAAM,WAAW,MAAM,KAAK;AAC5B,MAAI,aAAa,EACf,OAAM,IAAI,MAAM,GAAG,IAAI,GAAG,KAAK,KAAK,IAAI,CAAC,yBAAyB,WAAW;AAE/E;;CAGF,MAAM,CAAC,QAAQ,QAAQ,YAAY,MAAM,QAAQ,IAAI;EACnD,IAAI,SAAS,KAAK,OAAO,CAAC,MAAM;EAChC,IAAI,SAAS,KAAK,OAAO,CAAC,MAAM;EAChC,KAAK;EACN,CAAC;AAGF,QAAO;EADU;EAAQ;EAAQ;EACpB"}
1
+ {"version":3,"file":"run.mjs","names":[],"sources":["../../src/utils/run.ts"],"sourcesContent":["import { execa } from \"execa\";\n\ntype RunResult = { stdout: string; stderr: string; exitCode: number };\n\nexport async function run(\n cmd: string,\n args: string[],\n options: { cwd?: string; env?: Record<string, string>; capture?: boolean } = {},\n): Promise<RunResult | undefined> {\n const proc = await execa(cmd, args, {\n cwd: options.cwd,\n env: options.env ? { ...(process.env as Record<string, string>), ...options.env } : process.env,\n stdio: options.capture ? \"pipe\" : \"inherit\",\n reject: false,\n });\n\n if (!options.capture) {\n const exitCode = proc.exitCode ?? 0;\n if (exitCode !== 0) {\n throw new Error(`${cmd} ${args.join(\" \")} failed with exit code ${exitCode}`);\n }\n return;\n }\n\n const result = {\n stdout: proc.stdout ?? \"\",\n stderr: proc.stderr ?? \"\",\n exitCode: proc.exitCode ?? 0,\n };\n return result;\n}\n"],"mappings":";;;AAIA,eAAsB,IACpB,KACA,MACA,UAA6E,EAAE,EAC/C;CAChC,MAAM,OAAO,MAAM,MAAM,KAAK,MAAM;EAClC,KAAK,QAAQ;EACb,KAAK,QAAQ,MAAM;GAAE,GAAI,QAAQ;GAAgC,GAAG,QAAQ;GAAK,GAAG,QAAQ;EAC5F,OAAO,QAAQ,UAAU,SAAS;EAClC,QAAQ;EACT,CAAC;AAEF,KAAI,CAAC,QAAQ,SAAS;EACpB,MAAM,WAAW,KAAK,YAAY;AAClC,MAAI,aAAa,EACf,OAAM,IAAI,MAAM,GAAG,IAAI,GAAG,KAAK,KAAK,IAAI,CAAC,yBAAyB,WAAW;AAE/E;;AAQF,QAAO;EAJL,QAAQ,KAAK,UAAU;EACvB,QAAQ,KAAK,UAAU;EACvB,UAAU,KAAK,YAAY;EAEhB"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "everything-dev",
3
- "version": "1.27.0",
3
+ "version": "1.28.1",
4
4
  "type": "module",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -95,10 +95,10 @@
95
95
  },
96
96
  "files": [
97
97
  "dist",
98
- "src",
99
98
  "skills",
100
99
  "!skills/_artifacts"
101
100
  ],
101
+ "sideEffects": false,
102
102
  "bin": {
103
103
  "everything-dev": "./dist/cli.mjs",
104
104
  "bos": "./dist/cli.mjs"
@@ -1,623 +0,0 @@
1
- import { createHash } from "node:crypto";
2
- import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
3
- import { dirname, join, relative } from "node:path";
4
- import type { RuntimeConfig, RuntimePluginConfig } from "./types";
5
-
6
- const REMOTE_FETCH_TIMEOUT_MS = 10_000;
7
-
8
- export interface ApiPluginManifest {
9
- schemaVersion: 1;
10
- kind: "every-plugin/manifest";
11
- plugin: {
12
- name: string;
13
- version: string;
14
- };
15
- runtime: {
16
- remoteEntry: string;
17
- };
18
- contract?: {
19
- kind: "orpc";
20
- types: {
21
- path: string;
22
- exportName: string;
23
- typeName: string;
24
- sha256?: string;
25
- };
26
- };
27
- additionalExports?: Array<{
28
- path: string;
29
- exports: string[];
30
- sha256?: string;
31
- }>;
32
- }
33
-
34
- interface ContractSource {
35
- key: string;
36
- importName: string;
37
- sourceFilePath: string;
38
- generatedPath?: string;
39
- }
40
-
41
- function sha256(input: string): string {
42
- return createHash("sha256").update(input).digest("hex");
43
- }
44
-
45
- function trimTrailingSlash(input: string): string {
46
- return input.replace(/\/$/, "");
47
- }
48
-
49
- function sanitizeIdentifier(input: string): string {
50
- return input.replace(/[^A-Za-z0-9_]/g, "_").replace(/^[^A-Za-z_]+/, "_");
51
- }
52
-
53
- function toImportPath(fromFile: string, targetFile: string): string {
54
- const rel = relative(dirname(fromFile), targetFile).replace(/\\/g, "/");
55
- return rel.startsWith(".") ? rel : `./${rel}`;
56
- }
57
-
58
- function writeFileIfChanged(filePath: string, content: string) {
59
- try {
60
- if (readFileSync(filePath, "utf8") === content) return false;
61
- } catch {
62
- // file does not exist yet
63
- }
64
-
65
- writeFileSync(filePath, content);
66
- return true;
67
- }
68
-
69
- function getApiPluginManifestUrl(apiBaseUrl: string): string {
70
- return `${trimTrailingSlash(apiBaseUrl)}/plugin.manifest.json`;
71
- }
72
-
73
- async function fetchWithTimeout(url: string): Promise<Response> {
74
- const controller = new AbortController();
75
- const timeout = setTimeout(() => controller.abort(), REMOTE_FETCH_TIMEOUT_MS);
76
-
77
- try {
78
- return await fetch(url, { signal: controller.signal });
79
- } catch (error) {
80
- if (error instanceof Error && error.name === "AbortError") {
81
- throw new Error(`Timed out fetching ${url} after ${REMOTE_FETCH_TIMEOUT_MS}ms`);
82
- }
83
- throw error;
84
- } finally {
85
- clearTimeout(timeout);
86
- }
87
- }
88
-
89
- async function fetchApiPluginManifest(apiBaseUrl: string): Promise<ApiPluginManifest> {
90
- const response = await fetchWithTimeout(getApiPluginManifestUrl(apiBaseUrl));
91
- if (!response.ok) {
92
- throw new Error(
93
- `Failed to fetch API plugin manifest: ${response.status} ${response.statusText}`,
94
- );
95
- }
96
-
97
- const manifest = (await response.json()) as ApiPluginManifest;
98
- if (manifest.schemaVersion !== 1 || manifest.kind !== "every-plugin/manifest") {
99
- throw new Error("Unsupported API plugin manifest format");
100
- }
101
-
102
- return manifest;
103
- }
104
-
105
- function localApiContractSource(configDir: string): ContractSource {
106
- const sourcePath = join(configDir, "api", "src", "contract.ts");
107
- return {
108
- key: "api",
109
- importName: "BaseApiContract",
110
- sourceFilePath: sourcePath,
111
- };
112
- }
113
-
114
- function localAuthContractSource(configDir: string): ContractSource {
115
- const sourcePath = join(configDir, "plugins", "auth", "src", "contract.ts");
116
- return {
117
- key: "auth",
118
- importName: "authContract",
119
- sourceFilePath: sourcePath,
120
- };
121
- }
122
-
123
- async function remoteContractSource(opts: {
124
- configDir: string;
125
- runtimeDir: string;
126
- name: string;
127
- baseUrl: string;
128
- generatedSubdir: string;
129
- }): Promise<ContractSource> {
130
- const manifest = await fetchApiPluginManifest(opts.baseUrl);
131
- if (!manifest.contract) {
132
- throw new Error(
133
- `Plugin manifest for ${manifest.plugin.name} does not advertise contract types`,
134
- );
135
- }
136
-
137
- const contractUrl = `${trimTrailingSlash(opts.baseUrl)}/${manifest.contract.types.path.replace(/^\.\//, "")}`;
138
- const contractResponse = await fetchWithTimeout(contractUrl);
139
- if (!contractResponse.ok) {
140
- throw new Error(
141
- `Failed to fetch contract types: ${contractResponse.status} ${contractResponse.statusText}`,
142
- );
143
- }
144
-
145
- const contractTypes = await contractResponse.text();
146
- if (manifest.contract.types.sha256 && manifest.contract.types.sha256 !== sha256(contractTypes)) {
147
- throw new Error("Fetched contract types failed checksum verification");
148
- }
149
-
150
- const generatedPath = join(opts.runtimeDir, opts.generatedSubdir, "contract.d.ts");
151
- mkdirSync(dirname(generatedPath), { recursive: true });
152
- writeFileIfChanged(generatedPath, contractTypes);
153
-
154
- return {
155
- key: opts.name,
156
- importName: `${sanitizeIdentifier(opts.name)}Contract`,
157
- sourceFilePath: generatedPath,
158
- generatedPath,
159
- };
160
- }
161
-
162
- async function fetchAuthExportTypes(opts: {
163
- baseUrl: string;
164
- runtimeDir: string;
165
- manifest: ApiPluginManifest;
166
- }): Promise<string | null> {
167
- if (!opts.manifest.additionalExports || opts.manifest.additionalExports.length === 0) {
168
- return null;
169
- }
170
-
171
- const authExportEntry = opts.manifest.additionalExports.find(
172
- (entry) => entry.path.includes("auth-export") || entry.path.endsWith("auth-export.d.ts"),
173
- );
174
-
175
- if (!authExportEntry) {
176
- return null;
177
- }
178
-
179
- const exportUrl = `${trimTrailingSlash(opts.baseUrl)}/${authExportEntry.path.replace(/^\.\//, "")}`;
180
- const response = await fetchWithTimeout(exportUrl);
181
- if (!response.ok) {
182
- console.warn(`[API Contract] Failed to fetch auth export types: ${response.status}`);
183
- return null;
184
- }
185
-
186
- const content = await response.text();
187
- if (authExportEntry.sha256 && authExportEntry.sha256 !== sha256(content)) {
188
- console.warn("[API Contract] Auth export types checksum mismatch");
189
- return null;
190
- }
191
-
192
- const generatedPath = join(opts.runtimeDir, "auth", "auth-export.d.ts");
193
- mkdirSync(dirname(generatedPath), { recursive: true });
194
- writeFileIfChanged(generatedPath, content);
195
-
196
- return generatedPath;
197
- }
198
-
199
- function writeAuthTypesGen(targetPath: string, authExportPath: string) {
200
- const exportImportPath = toImportPath(targetPath, authExportPath);
201
- const content = [
202
- `export type {`,
203
- ` Auth,`,
204
- ` AuthOrganizationContext,`,
205
- ` AuthOrganization,`,
206
- ` AuthOrganizationSummary,`,
207
- ` AuthOrganizationMember,`,
208
- ` AuthApiKey,`,
209
- ` AuthInvitation,`,
210
- ` GetActiveMemberInput,`,
211
- ` GetOrganizationInput,`,
212
- ` ListMembersInput,`,
213
- ` ListInvitationsInput,`,
214
- ` ListApiKeysInput,`,
215
- ` AuthServices,`,
216
- ` createAuthInstance,`,
217
- `} from "${exportImportPath}";`,
218
- `import type { InferOutput, ContractType as AuthContract } from "${toImportPath(targetPath, join(dirname(authExportPath), "contract.d.ts"))}";`,
219
- `import type { Auth as BaseAuth } from "${exportImportPath}";`,
220
- "",
221
- 'type RawAuthSession = InferOutput<"getSession">;',
222
- 'type RawAuthRequestContext = InferOutput<"getContext">;',
223
- 'type RawAuthActiveMember = InferOutput<"getActiveMember">;',
224
- "",
225
- 'export type AuthSessionUser = NonNullable<RawAuthSession["user"]> & {',
226
- " role?: string | null;",
227
- " isAnonymous?: boolean | null;",
228
- " walletAddress?: string | null;",
229
- " banned?: boolean | null;",
230
- "};",
231
- 'export type AuthSessionData = NonNullable<RawAuthSession["session"]> & {',
232
- " activeOrganizationId?: string | null;",
233
- "};",
234
- "export type AuthSession = {",
235
- " user: AuthSessionUser | null;",
236
- " session: AuthSessionData | null;",
237
- "};",
238
- "export type AuthRequestContext = RawAuthRequestContext;",
239
- "export type AuthActiveMember = RawAuthActiveMember;",
240
- 'export type AuthBaseSession = BaseAuth["$Infer"]["Session"];',
241
- "export type AuthContractType = AuthContract;",
242
- "",
243
- ].join("\n");
244
- mkdirSync(dirname(targetPath), { recursive: true });
245
- writeFileIfChanged(targetPath, content);
246
- }
247
-
248
- function writeFallbackAuthTypesGen(targetPath: string) {
249
- const content = [
250
- 'import type { Auth } from "better-auth";',
251
- 'export type { Auth } from "better-auth";',
252
- 'export type AuthSession = Auth["$Infer"]["Session"];',
253
- "export type AuthSessionData = AuthSession;",
254
- 'export type AuthSessionUser = NonNullable<AuthSession["user"]>;',
255
- "export interface AuthOrganizationContext {",
256
- " activeOrganizationId: string | null;",
257
- " organization: { id: string; name: string; slug: string; logo?: string | null; metadata?: Record<string, unknown> } | null;",
258
- " member: { id: string; role: string } | null;",
259
- " isPersonal: boolean;",
260
- " hasOrganization: boolean;",
261
- "}",
262
- "export interface AuthRequestContext {",
263
- " user: AuthSessionUser | null;",
264
- " userId: string | null;",
265
- " isAuthenticated: boolean;",
266
- ' authMethod: "session" | "apiKey" | "anonymous" | "none";',
267
- " near: {",
268
- " primaryAccountId: string | null;",
269
- " linkedAccounts: Array<{ accountId: string; network: string; publicKey: string; isPrimary: boolean }>;",
270
- " hasNearAccount: boolean;",
271
- " };",
272
- " organization: AuthOrganizationContext;",
273
- " organizations?: Array<{ id: string; role: string; name?: string; slug?: string }>;",
274
- "}",
275
- "export type AuthActiveMember = { id: string | null; role: string | null; organizationId: string | null };",
276
- "export type AuthOrganization = {",
277
- " id: string;",
278
- " name: string;",
279
- " slug: string;",
280
- " logo?: string | null;",
281
- " metadata?: Record<string, unknown> | null;",
282
- " createdAt: Date;",
283
- "};",
284
- 'export type AuthOrganizationSummary = NonNullable<AuthOrganizationContext["organization"]>;',
285
- 'export type AuthOrganizationMember = NonNullable<AuthOrganizationContext["member"]>;',
286
- "export type AuthApiKey = {",
287
- " id: string;",
288
- " name: string | null;",
289
- " prefix: string | null;",
290
- " start: string | null;",
291
- " expiresAt: Date | null;",
292
- " createdAt: Date;",
293
- " updatedAt: Date;",
294
- " metadata: unknown | null;",
295
- " permissions: Record<string, string[]> | null;",
296
- "};",
297
- "export type AuthInvitation = {",
298
- " id: string;",
299
- " organizationId: string;",
300
- " email: string;",
301
- " role: string | null;",
302
- " status: string;",
303
- " expiresAt: Date;",
304
- " inviterId: string;",
305
- "};",
306
- "export type GetActiveMemberInput = { organizationId?: string };",
307
- "export type GetOrganizationInput = { id: string };",
308
- "export type ListMembersInput = { organizationId: string };",
309
- "export type ListInvitationsInput = { organizationId: string };",
310
- "export type ListApiKeysInput = { organizationId?: string };",
311
- "export type createAuthInstance = never;",
312
- "export interface AuthServices {",
313
- " auth: Auth;",
314
- " db: unknown;",
315
- " driver: { close(): Promise<void> };",
316
- " handler: (req: Request) => Promise<Response>;",
317
- "}",
318
- "",
319
- ].join("\n");
320
- mkdirSync(dirname(targetPath), { recursive: true });
321
- writeFileIfChanged(targetPath, content);
322
- }
323
-
324
- async function resolveContractSource(opts: {
325
- configDir: string;
326
- runtimeDir: string;
327
- key: string;
328
- source: RuntimePluginConfig | { url: string; localPath?: string; name: string } | null;
329
- baseUrl: string;
330
- generatedSubdir: string;
331
- localSourceFactory?: (configDir: string) => ContractSource;
332
- }): Promise<ContractSource> {
333
- if (opts.key === "api") {
334
- const localPath = opts.source && "localPath" in opts.source ? opts.source.localPath : undefined;
335
- if (localPath != null && localPath !== "") {
336
- return {
337
- key: opts.key,
338
- importName: "BaseApiContract",
339
- sourceFilePath: join(localPath, "src", "contract.ts"),
340
- };
341
- }
342
-
343
- if (!opts.baseUrl) {
344
- return localApiContractSource(opts.configDir);
345
- }
346
- }
347
-
348
- if (opts.key === "auth" && opts.localSourceFactory) {
349
- const localPath = opts.source && "localPath" in opts.source ? opts.source.localPath : undefined;
350
- if (localPath != null && localPath !== "") {
351
- return {
352
- key: opts.key,
353
- importName: "authContract",
354
- sourceFilePath: join(localPath, "src", "contract.ts"),
355
- };
356
- }
357
-
358
- if (!opts.baseUrl) {
359
- return opts.localSourceFactory(opts.configDir);
360
- }
361
- }
362
-
363
- if (
364
- opts.source &&
365
- "localPath" in opts.source &&
366
- opts.source.localPath != null &&
367
- opts.source.localPath !== ""
368
- ) {
369
- return {
370
- key: opts.key,
371
- importName: `${sanitizeIdentifier(opts.key)}Contract`,
372
- sourceFilePath: join(opts.source.localPath, "src", "contract.ts"),
373
- };
374
- }
375
-
376
- return remoteContractSource({
377
- configDir: opts.configDir,
378
- runtimeDir: opts.runtimeDir,
379
- name: opts.key,
380
- baseUrl: opts.baseUrl,
381
- generatedSubdir: opts.generatedSubdir,
382
- });
383
- }
384
-
385
- function writeGeneratedFiles(opts: {
386
- configDir: string;
387
- sources: ContractSource[];
388
- pluginKeys: string[];
389
- authSource: ContractSource | null;
390
- authExportPath?: string | null;
391
- }) {
392
- const baseSource = opts.sources.find((source) => source.key === "api");
393
- const pluginSources = opts.pluginKeys
394
- .map((key) => opts.sources.find((entry) => entry.key === key))
395
- .filter((source): source is ContractSource => Boolean(source));
396
-
397
- if (!baseSource) {
398
- throw new Error("API contract source is required to generate the aggregate contract");
399
- }
400
-
401
- // --- Generate ui/src/lib/api-types.gen.ts ---
402
- const uiContractPath = join(opts.configDir, "ui", "src", "lib", "api-types.gen.ts");
403
- const uiLines: string[] = [];
404
-
405
- for (const source of opts.sources) {
406
- const importPath = toImportPath(uiContractPath, source.sourceFilePath);
407
- uiLines.push(`import type { ContractType as ${source.importName} } from "${importPath}";`);
408
- }
409
-
410
- uiLines.push("");
411
-
412
- const compositeParts: string[] = [];
413
- if (opts.authSource) {
414
- compositeParts.push(`auth: ${opts.authSource.importName}`);
415
- }
416
- for (const source of pluginSources) {
417
- const key = /^[$A-Z_][0-9A-Z_$]*$/i.test(source.key) ? source.key : JSON.stringify(source.key);
418
- compositeParts.push(`${key}: ${source.importName}`);
419
- }
420
-
421
- if (compositeParts.length === 0) {
422
- uiLines.push(`export type ApiContract = ${baseSource.importName};`);
423
- } else {
424
- uiLines.push(`export type ApiContract = ${baseSource.importName} & {`);
425
- for (const part of compositeParts) {
426
- uiLines.push(` ${part};`);
427
- }
428
- uiLines.push("};");
429
- }
430
- mkdirSync(dirname(uiContractPath), { recursive: true });
431
- writeFileIfChanged(uiContractPath, `${uiLines.join("\n")}\n`);
432
-
433
- // --- Generate api/src/lib/plugins-types.gen.ts ---
434
- // Includes both plugin contracts AND auth as a unified PluginsClient type
435
- const pluginsClientPath = join(opts.configDir, "api", "src", "lib", "plugins-types.gen.ts");
436
- const pluginsClientLines: string[] = [];
437
-
438
- for (const source of pluginSources) {
439
- const importPath = toImportPath(pluginsClientPath, source.sourceFilePath);
440
- pluginsClientLines.push(
441
- `import type { ContractType as ${source.importName} } from "${importPath}";`,
442
- );
443
- }
444
-
445
- if (opts.authSource) {
446
- const authImportPath = toImportPath(pluginsClientPath, opts.authSource.sourceFilePath);
447
- pluginsClientLines.push(
448
- `import type { ContractType as ${opts.authSource.importName} } from "${authImportPath}";`,
449
- );
450
- }
451
-
452
- pluginsClientLines.push(
453
- 'import type { ContractRouterClient, AnyContractRouter } from "@orpc/contract";',
454
- );
455
- pluginsClientLines.push(
456
- "type ClientFactory<C extends AnyContractRouter> = (context?: Record<string, unknown>) => ContractRouterClient<C>;",
457
- );
458
- pluginsClientLines.push("");
459
-
460
- const allPluginSources = [...pluginSources];
461
- if (opts.authSource) {
462
- allPluginSources.push({ ...opts.authSource, key: "auth" });
463
- }
464
-
465
- if (allPluginSources.length === 0) {
466
- pluginsClientLines.push("export type PluginsClient = Record<string, never>;");
467
- } else {
468
- pluginsClientLines.push("export type PluginsClient = {");
469
- for (const source of allPluginSources) {
470
- const key = /^[$A-Z_][0-9A-Z_$]*$/i.test(source.key)
471
- ? source.key
472
- : JSON.stringify(source.key);
473
- pluginsClientLines.push(` ${key}: ClientFactory<${source.importName}>;`);
474
- }
475
- pluginsClientLines.push("};");
476
- }
477
-
478
- mkdirSync(dirname(pluginsClientPath), { recursive: true });
479
- writeFileIfChanged(pluginsClientPath, `${pluginsClientLines.join("\n")}\n`);
480
-
481
- // --- Generate */src/lib/auth-types.gen.ts ---
482
- const authTypeTargets = [join(opts.configDir, "ui", "src", "lib", "auth-types.gen.ts")];
483
- const apiLibDir = join(opts.configDir, "api", "src", "lib");
484
- if (existsSync(apiLibDir)) {
485
- authTypeTargets.push(join(apiLibDir, "auth-types.gen.ts"));
486
- }
487
- const hostLibDir = join(opts.configDir, "host", "src", "lib");
488
- if (existsSync(join(opts.configDir, "host", "src"))) {
489
- authTypeTargets.push(join(hostLibDir, "auth-types.gen.ts"));
490
- }
491
-
492
- if (opts.authExportPath) {
493
- for (const authTypesPath of authTypeTargets) {
494
- writeAuthTypesGen(authTypesPath, opts.authExportPath);
495
- }
496
- } else if (opts.authSource) {
497
- for (const authTypesPath of authTypeTargets) {
498
- writeFallbackAuthTypesGen(authTypesPath);
499
- }
500
- }
501
-
502
- return uiContractPath;
503
- }
504
-
505
- export async function syncApiContractBridge(opts: {
506
- configDir: string;
507
- runtimeConfig: RuntimeConfig;
508
- apiBaseUrl: string;
509
- }): Promise<{
510
- bridgePath: string;
511
- generatedPath: string | null;
512
- manifest: ApiPluginManifest | null;
513
- source: "local" | "remote";
514
- }> {
515
- const runtimeDir = join(opts.configDir, ".bos", "generated");
516
- const pluginEntries = Object.entries(opts.runtimeConfig.plugins ?? {}).sort(([a], [b]) =>
517
- a.localeCompare(b),
518
- );
519
- const sources: ContractSource[] = [];
520
- let manifest: ApiPluginManifest | null = null;
521
- let generatedPath: string | null = null;
522
- let authSource: ContractSource | null = null;
523
- let authExportPath: string | null = null;
524
-
525
- const baseSource = await resolveContractSource({
526
- configDir: opts.configDir,
527
- runtimeDir,
528
- key: "api",
529
- source: opts.runtimeConfig.api,
530
- baseUrl: opts.apiBaseUrl,
531
- generatedSubdir: "api",
532
- });
533
- sources.push(baseSource);
534
-
535
- if (opts.runtimeConfig.auth) {
536
- authSource = await resolveContractSource({
537
- configDir: opts.configDir,
538
- runtimeDir,
539
- key: "auth",
540
- source: opts.runtimeConfig.auth,
541
- baseUrl: opts.runtimeConfig.auth.url,
542
- generatedSubdir: "auth",
543
- localSourceFactory: localAuthContractSource,
544
- });
545
- sources.push(authSource);
546
- if (authSource.generatedPath) {
547
- generatedPath = authSource.generatedPath;
548
- }
549
-
550
- // Fetch auth additional exports (auth-export.d.ts) for remote auth
551
- if (opts.runtimeConfig.auth.url && opts.runtimeConfig.auth.source !== "local") {
552
- try {
553
- const authManifest = await fetchApiPluginManifest(opts.runtimeConfig.auth.url);
554
- const fetchedAuthExportPath = await fetchAuthExportTypes({
555
- baseUrl: opts.runtimeConfig.auth.url,
556
- runtimeDir,
557
- manifest: authManifest,
558
- });
559
- if (fetchedAuthExportPath) {
560
- authExportPath = fetchedAuthExportPath;
561
- }
562
- } catch (error) {
563
- console.warn(
564
- `[API Contract] Failed to fetch auth additional exports: ${error instanceof Error ? error.message : String(error)}`,
565
- );
566
- }
567
- }
568
-
569
- if (!authExportPath) {
570
- const localAuthExport = join(opts.configDir, "plugins", "auth", "src", "auth-export.ts");
571
- if (existsSync(localAuthExport)) {
572
- authExportPath = localAuthExport;
573
- } else {
574
- const generatedAuthExport = join(runtimeDir, "auth", "auth-export.d.ts");
575
- if (existsSync(generatedAuthExport)) {
576
- authExportPath = generatedAuthExport;
577
- }
578
- }
579
- }
580
- }
581
-
582
- for (const [key, plugin] of pluginEntries) {
583
- if (!plugin.url && !plugin.localPath) {
584
- console.warn(
585
- `[API Contract] Skipping plugin "${key}" — no URL resolved (local path missing and no production URL configured)`,
586
- );
587
- continue;
588
- }
589
- const source = await resolveContractSource({
590
- configDir: opts.configDir,
591
- runtimeDir,
592
- key,
593
- source: plugin,
594
- baseUrl: plugin.url,
595
- generatedSubdir: `plugins/${key}`,
596
- });
597
- sources.push(source);
598
- if (source.generatedPath) {
599
- generatedPath = source.generatedPath;
600
- }
601
- }
602
-
603
- const allPluginKeys = pluginEntries.map(([key]) => key);
604
-
605
- writeGeneratedFiles({
606
- configDir: opts.configDir,
607
- sources,
608
- pluginKeys: allPluginKeys,
609
- authSource,
610
- authExportPath,
611
- });
612
-
613
- if (opts.runtimeConfig.api.source !== "local") {
614
- manifest = await fetchApiPluginManifest(opts.apiBaseUrl);
615
- }
616
-
617
- return {
618
- bridgePath: join(opts.configDir, "ui", "src", "lib", "api-types.gen.ts"),
619
- generatedPath,
620
- manifest,
621
- source: opts.runtimeConfig.api.source,
622
- };
623
- }