everything-dev 1.12.4 → 1.13.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 (124) hide show
  1. package/cli.js +1 -1
  2. package/dist/app.cjs +17 -5
  3. package/dist/app.cjs.map +1 -1
  4. package/dist/app.mjs +17 -5
  5. package/dist/app.mjs.map +1 -1
  6. package/dist/cli/init.cjs +143 -66
  7. package/dist/cli/init.cjs.map +1 -1
  8. package/dist/cli/init.d.cts +1 -1
  9. package/dist/cli/init.d.cts.map +1 -1
  10. package/dist/cli/init.d.mts +1 -1
  11. package/dist/cli/init.d.mts.map +1 -1
  12. package/dist/cli/init.mjs +144 -67
  13. package/dist/cli/init.mjs.map +1 -1
  14. package/dist/cli/prompts.cjs +3 -3
  15. package/dist/cli/prompts.cjs.map +1 -1
  16. package/dist/cli/prompts.mjs +3 -3
  17. package/dist/cli/prompts.mjs.map +1 -1
  18. package/dist/cli/sync.cjs +15 -56
  19. package/dist/cli/sync.cjs.map +1 -1
  20. package/dist/cli/sync.mjs +15 -56
  21. package/dist/cli/sync.mjs.map +1 -1
  22. package/dist/cli/upgrade.cjs +3 -1
  23. package/dist/cli/upgrade.cjs.map +1 -1
  24. package/dist/cli/upgrade.mjs +3 -1
  25. package/dist/cli/upgrade.mjs.map +1 -1
  26. package/dist/config.cjs +206 -69
  27. package/dist/config.cjs.map +1 -1
  28. package/dist/config.d.cts +13 -6
  29. package/dist/config.d.cts.map +1 -1
  30. package/dist/config.d.mts +13 -6
  31. package/dist/config.d.mts.map +1 -1
  32. package/dist/config.mjs +201 -71
  33. package/dist/config.mjs.map +1 -1
  34. package/dist/contract.d.cts +104 -8
  35. package/dist/contract.d.cts.map +1 -1
  36. package/dist/contract.d.mts +104 -8
  37. package/dist/contract.d.mts.map +1 -1
  38. package/dist/host.cjs +34 -1
  39. package/dist/host.cjs.map +1 -1
  40. package/dist/host.d.cts.map +1 -1
  41. package/dist/host.d.mts.map +1 -1
  42. package/dist/host.mjs +34 -1
  43. package/dist/host.mjs.map +1 -1
  44. package/dist/index.cjs +16 -0
  45. package/dist/index.d.cts +5 -3
  46. package/dist/index.d.mts +5 -3
  47. package/dist/index.mjs +5 -3
  48. package/dist/merge.cjs +113 -0
  49. package/dist/merge.cjs.map +1 -0
  50. package/dist/merge.d.cts +7 -0
  51. package/dist/merge.d.cts.map +1 -0
  52. package/dist/merge.d.mts +7 -0
  53. package/dist/merge.d.mts.map +1 -0
  54. package/dist/merge.mjs +107 -0
  55. package/dist/merge.mjs.map +1 -0
  56. package/dist/plugin.cjs +117 -105
  57. package/dist/plugin.cjs.map +1 -1
  58. package/dist/plugin.d.cts +114 -8
  59. package/dist/plugin.d.cts.map +1 -1
  60. package/dist/plugin.d.mts +114 -8
  61. package/dist/plugin.d.mts.map +1 -1
  62. package/dist/plugin.mjs +117 -105
  63. package/dist/plugin.mjs.map +1 -1
  64. package/dist/service-descriptor.cjs +21 -0
  65. package/dist/service-descriptor.cjs.map +1 -1
  66. package/dist/service-descriptor.d.cts +23 -1
  67. package/dist/service-descriptor.d.cts.map +1 -1
  68. package/dist/service-descriptor.d.mts +23 -1
  69. package/dist/service-descriptor.d.mts.map +1 -1
  70. package/dist/service-descriptor.mjs +21 -0
  71. package/dist/service-descriptor.mjs.map +1 -1
  72. package/dist/shared.cjs +24 -2
  73. package/dist/shared.cjs.map +1 -1
  74. package/dist/shared.d.cts +3 -0
  75. package/dist/shared.d.cts.map +1 -1
  76. package/dist/shared.d.mts +3 -0
  77. package/dist/shared.d.mts.map +1 -1
  78. package/dist/shared.mjs +25 -3
  79. package/dist/shared.mjs.map +1 -1
  80. package/dist/sidebar.cjs +124 -0
  81. package/dist/sidebar.cjs.map +1 -0
  82. package/dist/sidebar.d.cts +8 -0
  83. package/dist/sidebar.d.cts.map +1 -0
  84. package/dist/sidebar.d.mts +8 -0
  85. package/dist/sidebar.d.mts.map +1 -0
  86. package/dist/sidebar.mjs +122 -0
  87. package/dist/sidebar.mjs.map +1 -0
  88. package/dist/types.cjs +104 -10
  89. package/dist/types.cjs.map +1 -1
  90. package/dist/types.d.cts +256 -29
  91. package/dist/types.d.cts.map +1 -1
  92. package/dist/types.d.mts +256 -29
  93. package/dist/types.d.mts.map +1 -1
  94. package/dist/types.mjs +100 -11
  95. package/dist/types.mjs.map +1 -1
  96. package/dist/utils/path-match.cjs +18 -0
  97. package/dist/utils/path-match.cjs.map +1 -0
  98. package/dist/utils/path-match.mjs +17 -0
  99. package/dist/utils/path-match.mjs.map +1 -0
  100. package/dist/utils/save-config.cjs +19 -0
  101. package/dist/utils/save-config.cjs.map +1 -0
  102. package/dist/utils/save-config.mjs +18 -0
  103. package/dist/utils/save-config.mjs.map +1 -0
  104. package/package.json +3 -2
  105. package/skills/dev-workflow/SKILL.md +8 -0
  106. package/skills/extends-config/SKILL.md +132 -0
  107. package/skills/init-upgrade/SKILL.md +128 -0
  108. package/skills/publish-sync/SKILL.md +30 -0
  109. package/src/app.ts +15 -5
  110. package/src/cli/init.ts +199 -100
  111. package/src/cli/prompts.ts +2 -2
  112. package/src/cli/sync.ts +27 -96
  113. package/src/cli/upgrade.ts +2 -0
  114. package/src/config.ts +306 -119
  115. package/src/host.ts +45 -0
  116. package/src/index.ts +1 -0
  117. package/src/merge.ts +198 -0
  118. package/src/plugin.ts +340 -318
  119. package/src/service-descriptor.ts +23 -0
  120. package/src/shared.ts +48 -5
  121. package/src/sidebar.ts +162 -0
  122. package/src/types.ts +134 -28
  123. package/src/utils/path-match.ts +16 -0
  124. package/src/utils/save-config.ts +20 -0
@@ -1 +1 @@
1
- {"version":3,"file":"service-descriptor.mjs","names":[],"sources":["../src/service-descriptor.ts"],"sourcesContent":["import { Context, Layer } from \"effect\";\nimport type { RuntimeConfig, SourceMode } from \"./types\";\n\nexport interface ServiceDescriptor {\n key: string;\n source: SourceMode;\n url: string;\n remoteUrl?: string;\n entry: string;\n name: string;\n localPath?: string;\n port?: number;\n readinessPath: string;\n defaultPort: number;\n integrity?: string;\n proxy?: string;\n variables?: Record<string, string>;\n secrets?: string[];\n ssr?: boolean;\n command?: string;\n args?: string[];\n readyPatterns?: RegExp[];\n errorPatterns?: RegExp[];\n}\n\nexport class ServiceDescriptorMap extends Context.Tag(\"ServiceDescriptorMap\")<\n ServiceDescriptorMap,\n Map<string, ServiceDescriptor>\n>() {}\n\nexport class DevRuntimeConfig extends Context.Tag(\"DevRuntimeConfig\")<\n DevRuntimeConfig,\n RuntimeConfig\n>() {}\n\nconst PLUGIN_READY_PATTERNS = [/ready in/i, /compiled.*successfully/i, /listening/i, /started/i];\n\nconst PLUGIN_ERROR_PATTERNS = [/error/i, /failed/i];\n\nconst SERVICE_CONFIGS: Record<\n string,\n Pick<\n ServiceDescriptor,\n \"command\" | \"args\" | \"readyPatterns\" | \"errorPatterns\" | \"defaultPort\" | \"readinessPath\"\n >\n> = {\n host: {\n command: \"bun\",\n args: [\"run\", \"dev\"],\n readyPatterns: [/Host (dev|production) server running at/i, /Server running at/i],\n errorPatterns: [/error:/i, /failed/i, /exception/i],\n defaultPort: 3000,\n readinessPath: \"/health\",\n },\n auth: {\n command: \"bun\",\n args: [\"run\", \"dev\"],\n readyPatterns: PLUGIN_READY_PATTERNS,\n errorPatterns: PLUGIN_ERROR_PATTERNS,\n defaultPort: 3002,\n readinessPath: \"/remoteEntry.js\",\n },\n ui: {\n command: \"bun\",\n args: [\"run\", \"dev\"],\n readyPatterns: [/\\bready\\s+built in\\b/i, /\\bLocal:\\b/i, /\\bcompiled\\b.*successfully/i],\n errorPatterns: [/error/i, /failed to compile/i],\n defaultPort: 3003,\n readinessPath: \"/remoteEntry.js\",\n },\n \"ui-ssr\": {\n command: \"bun\",\n args: [\"run\", \"dev:ssr\"],\n readyPatterns: [/\\bready\\s+built in\\b/i, /\\bcompiled\\b.*successfully/i],\n errorPatterns: [/error/i, /failed/i],\n defaultPort: 3004,\n readinessPath: \"/\",\n },\n api: {\n command: \"bun\",\n args: [\"run\", \"dev\"],\n readyPatterns: PLUGIN_READY_PATTERNS,\n errorPatterns: PLUGIN_ERROR_PATTERNS,\n defaultPort: 3001,\n readinessPath: \"/remoteEntry.js\",\n },\n};\n\nexport function buildServiceDescriptorMap(\n runtimeConfig: RuntimeConfig,\n options?: { ssr?: boolean; proxy?: boolean },\n): Map<string, ServiceDescriptor> {\n const map = new Map<string, ServiceDescriptor>();\n const ssr = options?.ssr ?? false;\n\n const hostIsRemote = runtimeConfig.host.source === \"remote\";\n const hostProbeUrl = hostIsRemote\n ? (runtimeConfig.host.remoteUrl ?? runtimeConfig.host.url)\n : runtimeConfig.host.url;\n map.set(\"host\", {\n key: \"host\",\n source: runtimeConfig.host.source,\n url: hostProbeUrl,\n remoteUrl: runtimeConfig.host.remoteUrl,\n entry: hostIsRemote\n ? hostProbeUrl\n ? `${hostProbeUrl}/mf-manifest.json`\n : \"/mf-manifest.json\"\n : runtimeConfig.host.entry,\n name: runtimeConfig.host.name,\n localPath: runtimeConfig.host.localPath,\n port: runtimeConfig.host.port,\n integrity: runtimeConfig.host.integrity,\n secrets: runtimeConfig.host.secrets,\n ...SERVICE_CONFIGS.host,\n });\n\n map.set(\"ui\", {\n key: \"ui\",\n source: runtimeConfig.ui.source,\n url: runtimeConfig.ui.url,\n remoteUrl: runtimeConfig.ui.source === \"remote\" ? runtimeConfig.ui.url : undefined,\n entry: runtimeConfig.ui.entry,\n name: runtimeConfig.ui.name,\n localPath: runtimeConfig.ui.localPath,\n port: runtimeConfig.ui.port,\n integrity: runtimeConfig.ui.integrity,\n ssr,\n ...SERVICE_CONFIGS.ui,\n });\n\n if (ssr && runtimeConfig.ui.source === \"local\") {\n map.set(\"ui-ssr\", {\n key: \"ui-ssr\",\n source: runtimeConfig.ui.source,\n url: runtimeConfig.ui.ssrUrl ?? \"\",\n entry: \"\",\n name: \"ui-ssr\",\n localPath: runtimeConfig.ui.localPath,\n port: runtimeConfig.ui.ssrUrl\n ? Number.parseInt(new URL(runtimeConfig.ui.ssrUrl).port, 10)\n : (runtimeConfig.ui.port ?? 3003) + 1,\n ...SERVICE_CONFIGS[\"ui-ssr\"],\n });\n }\n\n map.set(\"api\", {\n key: \"api\",\n source: runtimeConfig.api.source,\n url: runtimeConfig.api.url,\n remoteUrl: runtimeConfig.api.source === \"remote\" ? runtimeConfig.api.url : undefined,\n entry: runtimeConfig.api.entry,\n name: runtimeConfig.api.name,\n localPath: runtimeConfig.api.localPath,\n port: runtimeConfig.api.port,\n integrity: runtimeConfig.api.integrity,\n proxy: runtimeConfig.api.proxy,\n variables: runtimeConfig.api.variables,\n secrets: runtimeConfig.api.secrets,\n ...SERVICE_CONFIGS.api,\n });\n\n if (runtimeConfig.auth) {\n map.set(\"auth\", {\n key: \"auth\",\n source: runtimeConfig.auth.source,\n url: runtimeConfig.auth.url,\n remoteUrl: runtimeConfig.auth.source === \"remote\" ? runtimeConfig.auth.url : undefined,\n entry: runtimeConfig.auth.entry,\n name: runtimeConfig.auth.name,\n localPath: runtimeConfig.auth.localPath,\n port: runtimeConfig.auth.port,\n integrity: runtimeConfig.auth.integrity,\n proxy: runtimeConfig.auth.proxy,\n variables: runtimeConfig.auth.variables,\n secrets: runtimeConfig.auth.secrets,\n ...SERVICE_CONFIGS.auth,\n });\n }\n\n if (runtimeConfig.plugins) {\n let pluginBasePort = 3010;\n for (const [pluginId, pluginConfig] of Object.entries(runtimeConfig.plugins)) {\n const pluginKey = `plugin:${pluginId}`;\n const resolvedPort = pluginConfig.port ?? pluginBasePort;\n pluginBasePort = resolvedPort + 1;\n\n map.set(pluginKey, {\n key: pluginKey,\n source: pluginConfig.source,\n url: pluginConfig.url,\n remoteUrl: pluginConfig.source === \"remote\" ? pluginConfig.url : undefined,\n entry: pluginConfig.entry,\n name: pluginConfig.name,\n localPath: pluginConfig.localPath,\n port: resolvedPort,\n integrity: pluginConfig.integrity,\n proxy: pluginConfig.proxy,\n variables: pluginConfig.variables,\n secrets: pluginConfig.secrets,\n command: \"bun\",\n args: [\"run\", \"dev\"],\n readyPatterns: PLUGIN_READY_PATTERNS,\n errorPatterns: PLUGIN_ERROR_PATTERNS,\n defaultPort: resolvedPort,\n readinessPath: \"/remoteEntry.js\",\n });\n }\n }\n\n return map;\n}\n\nexport interface AppOrchestrator {\n packages: string[];\n description: string;\n env: Record<string, string>;\n port?: number;\n interactive?: boolean;\n noLogs?: boolean;\n}\n\nexport const ServiceDescriptorMapLive = (map: Map<string, ServiceDescriptor>) =>\n Layer.succeed(ServiceDescriptorMap, map);\n\nexport const DevRuntimeConfigLive = (config: RuntimeConfig) =>\n Layer.succeed(DevRuntimeConfig, config);\n\nexport function buildDescription(map: Map<string, ServiceDescriptor>): string {\n const descriptors = [...map.values()].filter(\n (d) => d.key !== \"ui-ssr\" && !d.key.startsWith(\"plugin:\"),\n );\n\n const allLocal = descriptors.every((d) => d.source === \"local\");\n const hasProxy = [...map.values()].some((d) => d.proxy && d.source === \"local\");\n if (allLocal && !hasProxy) return \"Full Local Development\";\n\n const parts: string[] = [];\n for (const d of descriptors) {\n if (d.source === \"remote\") {\n const label =\n d.key === \"host\"\n ? \"Remote Host\"\n : d.key === \"ui\"\n ? \"Remote UI\"\n : d.key === \"api\"\n ? hasProxy\n ? undefined\n : \"Remote API\"\n : d.key === \"auth\"\n ? \"Remote Auth\"\n : undefined;\n if (label) parts.push(label);\n }\n }\n if (hasProxy) parts.push(\"Proxy API → Production\");\n return parts.join(\" + \") || \"Remote Mode\";\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"service-descriptor.mjs","names":[],"sources":["../src/service-descriptor.ts"],"sourcesContent":["import { Context, Layer } from \"effect\";\nimport type { RuntimeConfig, SourceMode } from \"./types\";\n\nexport interface ServiceDescriptor {\n key: string;\n source: SourceMode;\n url: string;\n remoteUrl?: string;\n entry: string;\n name: string;\n localPath?: string;\n port?: number;\n readinessPath: string;\n defaultPort: number;\n integrity?: string;\n proxy?: string;\n variables?: Record<string, string>;\n secrets?: string[];\n ssr?: boolean;\n command?: string;\n args?: string[];\n readyPatterns?: RegExp[];\n errorPatterns?: RegExp[];\n}\n\nexport class ServiceDescriptorMap extends Context.Tag(\"ServiceDescriptorMap\")<\n ServiceDescriptorMap,\n Map<string, ServiceDescriptor>\n>() {}\n\nexport class DevRuntimeConfig extends Context.Tag(\"DevRuntimeConfig\")<\n DevRuntimeConfig,\n RuntimeConfig\n>() {}\n\nconst PLUGIN_READY_PATTERNS = [/ready in/i, /compiled.*successfully/i, /listening/i, /started/i];\n\nconst PLUGIN_ERROR_PATTERNS = [/error/i, /failed/i];\n\nconst SERVICE_CONFIGS: Record<\n string,\n Pick<\n ServiceDescriptor,\n \"command\" | \"args\" | \"readyPatterns\" | \"errorPatterns\" | \"defaultPort\" | \"readinessPath\"\n >\n> = {\n host: {\n command: \"bun\",\n args: [\"run\", \"dev\"],\n readyPatterns: [/Host (dev|production) server running at/i, /Server running at/i],\n errorPatterns: [/error:/i, /failed/i, /exception/i],\n defaultPort: 3000,\n readinessPath: \"/health\",\n },\n auth: {\n command: \"bun\",\n args: [\"run\", \"dev\"],\n readyPatterns: PLUGIN_READY_PATTERNS,\n errorPatterns: PLUGIN_ERROR_PATTERNS,\n defaultPort: 3002,\n readinessPath: \"/remoteEntry.js\",\n },\n ui: {\n command: \"bun\",\n args: [\"run\", \"dev\"],\n readyPatterns: [/\\bready\\s+built in\\b/i, /\\bLocal:\\b/i, /\\bcompiled\\b.*successfully/i],\n errorPatterns: [/error/i, /failed to compile/i],\n defaultPort: 3003,\n readinessPath: \"/remoteEntry.js\",\n },\n \"ui-ssr\": {\n command: \"bun\",\n args: [\"run\", \"dev:ssr\"],\n readyPatterns: [/\\bready\\s+built in\\b/i, /\\bcompiled\\b.*successfully/i],\n errorPatterns: [/error/i, /failed/i],\n defaultPort: 3004,\n readinessPath: \"/\",\n },\n api: {\n command: \"bun\",\n args: [\"run\", \"dev\"],\n readyPatterns: PLUGIN_READY_PATTERNS,\n errorPatterns: PLUGIN_ERROR_PATTERNS,\n defaultPort: 3001,\n readinessPath: \"/remoteEntry.js\",\n },\n};\n\nexport function buildServiceDescriptorMap(\n runtimeConfig: RuntimeConfig,\n options?: { ssr?: boolean; proxy?: boolean },\n): Map<string, ServiceDescriptor> {\n const map = new Map<string, ServiceDescriptor>();\n const ssr = options?.ssr ?? false;\n\n const hostIsRemote = runtimeConfig.host.source === \"remote\";\n const hostProbeUrl = hostIsRemote\n ? (runtimeConfig.host.remoteUrl ?? runtimeConfig.host.url)\n : runtimeConfig.host.url;\n map.set(\"host\", {\n key: \"host\",\n source: runtimeConfig.host.source,\n url: hostProbeUrl,\n remoteUrl: runtimeConfig.host.remoteUrl,\n entry: hostIsRemote\n ? hostProbeUrl\n ? `${hostProbeUrl}/mf-manifest.json`\n : \"/mf-manifest.json\"\n : runtimeConfig.host.entry,\n name: runtimeConfig.host.name,\n localPath: runtimeConfig.host.localPath,\n port: runtimeConfig.host.port,\n integrity: runtimeConfig.host.integrity,\n secrets: runtimeConfig.host.secrets,\n ...SERVICE_CONFIGS.host,\n });\n\n map.set(\"ui\", {\n key: \"ui\",\n source: runtimeConfig.ui.source,\n url: runtimeConfig.ui.url,\n remoteUrl: runtimeConfig.ui.source === \"remote\" ? runtimeConfig.ui.url : undefined,\n entry: runtimeConfig.ui.entry,\n name: runtimeConfig.ui.name,\n localPath: runtimeConfig.ui.localPath,\n port: runtimeConfig.ui.port,\n integrity: runtimeConfig.ui.integrity,\n ssr,\n ...SERVICE_CONFIGS.ui,\n });\n\n if (ssr && runtimeConfig.ui.source === \"local\") {\n map.set(\"ui-ssr\", {\n key: \"ui-ssr\",\n source: runtimeConfig.ui.source,\n url: runtimeConfig.ui.ssrUrl ?? \"\",\n entry: \"\",\n name: \"ui-ssr\",\n localPath: runtimeConfig.ui.localPath,\n port: runtimeConfig.ui.ssrUrl\n ? Number.parseInt(new URL(runtimeConfig.ui.ssrUrl).port, 10)\n : (runtimeConfig.ui.port ?? 3003) + 1,\n ...SERVICE_CONFIGS[\"ui-ssr\"],\n });\n }\n\n map.set(\"api\", {\n key: \"api\",\n source: runtimeConfig.api.source,\n url: runtimeConfig.api.url,\n remoteUrl: runtimeConfig.api.source === \"remote\" ? runtimeConfig.api.url : undefined,\n entry: runtimeConfig.api.entry,\n name: runtimeConfig.api.name,\n localPath: runtimeConfig.api.localPath,\n port: runtimeConfig.api.port,\n integrity: runtimeConfig.api.integrity,\n proxy: runtimeConfig.api.proxy,\n variables: runtimeConfig.api.variables,\n secrets: runtimeConfig.api.secrets,\n ...SERVICE_CONFIGS.api,\n });\n\n if (runtimeConfig.auth) {\n map.set(\"auth\", {\n key: \"auth\",\n source: runtimeConfig.auth.source,\n url: runtimeConfig.auth.url,\n remoteUrl: runtimeConfig.auth.source === \"remote\" ? runtimeConfig.auth.url : undefined,\n entry: runtimeConfig.auth.entry,\n name: runtimeConfig.auth.name,\n localPath: runtimeConfig.auth.localPath,\n port: runtimeConfig.auth.port,\n integrity: runtimeConfig.auth.integrity,\n proxy: runtimeConfig.auth.proxy,\n variables: runtimeConfig.auth.variables,\n secrets: runtimeConfig.auth.secrets,\n ...SERVICE_CONFIGS.auth,\n });\n }\n\n if (runtimeConfig.plugins) {\n let pluginBasePort = 3010;\n for (const [pluginId, pluginConfig] of Object.entries(runtimeConfig.plugins)) {\n const pluginKey = `plugin:${pluginId}`;\n const resolvedPort = pluginConfig.port ?? pluginBasePort;\n pluginBasePort = resolvedPort + 1;\n\n map.set(pluginKey, {\n key: pluginKey,\n source: pluginConfig.source,\n url: pluginConfig.url,\n remoteUrl: pluginConfig.source === \"remote\" ? pluginConfig.url : undefined,\n entry: pluginConfig.entry,\n name: pluginConfig.name,\n localPath: pluginConfig.localPath,\n port: resolvedPort,\n integrity: pluginConfig.integrity,\n proxy: pluginConfig.proxy,\n variables: pluginConfig.variables,\n secrets: pluginConfig.secrets,\n command: \"bun\",\n args: [\"run\", \"dev\"],\n readyPatterns: PLUGIN_READY_PATTERNS,\n errorPatterns: PLUGIN_ERROR_PATTERNS,\n defaultPort: resolvedPort,\n readinessPath: \"/remoteEntry.js\",\n });\n\n if (pluginConfig.ui?.localPath && pluginConfig.ui.source === \"local\") {\n const uiKey = `plugin-ui:${pluginId}`;\n const uiPort = pluginConfig.ui.port ?? pluginBasePort;\n pluginBasePort = uiPort + 1;\n\n map.set(uiKey, {\n key: uiKey,\n source: pluginConfig.ui.source,\n url: pluginConfig.ui.url,\n entry: pluginConfig.ui.entry,\n name: pluginConfig.ui.name,\n localPath: pluginConfig.ui.localPath,\n port: uiPort,\n integrity: pluginConfig.ui.integrity,\n command: \"bun\",\n args: [\"run\", \"dev\"],\n readyPatterns: PLUGIN_READY_PATTERNS,\n errorPatterns: PLUGIN_ERROR_PATTERNS,\n defaultPort: uiPort,\n readinessPath: \"/remoteEntry.js\",\n });\n }\n }\n }\n\n return map;\n}\n\nexport interface AppOrchestrator {\n packages: string[];\n description: string;\n env: Record<string, string>;\n port?: number;\n interactive?: boolean;\n noLogs?: boolean;\n}\n\nexport const ServiceDescriptorMapLive = (map: Map<string, ServiceDescriptor>) =>\n Layer.succeed(ServiceDescriptorMap, map);\n\nexport const DevRuntimeConfigLive = (config: RuntimeConfig) =>\n Layer.succeed(DevRuntimeConfig, config);\n\nexport function buildDescription(map: Map<string, ServiceDescriptor>): string {\n const descriptors = [...map.values()].filter(\n (d) => d.key !== \"ui-ssr\" && !d.key.startsWith(\"plugin:\"),\n );\n\n const allLocal = descriptors.every((d) => d.source === \"local\");\n const hasProxy = [...map.values()].some((d) => d.proxy && d.source === \"local\");\n if (allLocal && !hasProxy) return \"Full Local Development\";\n\n const parts: string[] = [];\n for (const d of descriptors) {\n if (d.source === \"remote\") {\n const label =\n d.key === \"host\"\n ? \"Remote Host\"\n : d.key === \"ui\"\n ? \"Remote UI\"\n : d.key === \"api\"\n ? hasProxy\n ? undefined\n : \"Remote API\"\n : d.key === \"auth\"\n ? \"Remote Auth\"\n : undefined;\n if (label) parts.push(label);\n }\n }\n if (hasProxy) parts.push(\"Proxy API → Production\");\n return parts.join(\" + \") || \"Remote Mode\";\n}\n"],"mappings":";;;AAyBA,IAAa,uBAAb,cAA0C,QAAQ,IAAI,uBAAuB,EAG1E,CAAC;AAEJ,IAAa,mBAAb,cAAsC,QAAQ,IAAI,mBAAmB,EAGlE,CAAC;AAEJ,MAAM,wBAAwB;CAAC;CAAa;CAA2B;CAAc;CAAW;AAEhG,MAAM,wBAAwB,CAAC,UAAU,UAAU;AAEnD,MAAM,kBAMF;CACF,MAAM;EACJ,SAAS;EACT,MAAM,CAAC,OAAO,MAAM;EACpB,eAAe,CAAC,4CAA4C,qBAAqB;EACjF,eAAe;GAAC;GAAW;GAAW;GAAa;EACnD,aAAa;EACb,eAAe;EAChB;CACD,MAAM;EACJ,SAAS;EACT,MAAM,CAAC,OAAO,MAAM;EACpB,eAAe;EACf,eAAe;EACf,aAAa;EACb,eAAe;EAChB;CACD,IAAI;EACF,SAAS;EACT,MAAM,CAAC,OAAO,MAAM;EACpB,eAAe;GAAC;GAAyB;GAAe;GAA8B;EACtF,eAAe,CAAC,UAAU,qBAAqB;EAC/C,aAAa;EACb,eAAe;EAChB;CACD,UAAU;EACR,SAAS;EACT,MAAM,CAAC,OAAO,UAAU;EACxB,eAAe,CAAC,yBAAyB,8BAA8B;EACvE,eAAe,CAAC,UAAU,UAAU;EACpC,aAAa;EACb,eAAe;EAChB;CACD,KAAK;EACH,SAAS;EACT,MAAM,CAAC,OAAO,MAAM;EACpB,eAAe;EACf,eAAe;EACf,aAAa;EACb,eAAe;EAChB;CACF;AAED,SAAgB,0BACd,eACA,SACgC;CAChC,MAAM,sBAAM,IAAI,KAAgC;CAChD,MAAM,MAAM,SAAS,OAAO;CAE5B,MAAM,eAAe,cAAc,KAAK,WAAW;CACnD,MAAM,eAAe,eAChB,cAAc,KAAK,aAAa,cAAc,KAAK,MACpD,cAAc,KAAK;AACvB,KAAI,IAAI,QAAQ;EACd,KAAK;EACL,QAAQ,cAAc,KAAK;EAC3B,KAAK;EACL,WAAW,cAAc,KAAK;EAC9B,OAAO,eACH,eACE,GAAG,aAAa,qBAChB,sBACF,cAAc,KAAK;EACvB,MAAM,cAAc,KAAK;EACzB,WAAW,cAAc,KAAK;EAC9B,MAAM,cAAc,KAAK;EACzB,WAAW,cAAc,KAAK;EAC9B,SAAS,cAAc,KAAK;EAC5B,GAAG,gBAAgB;EACpB,CAAC;AAEF,KAAI,IAAI,MAAM;EACZ,KAAK;EACL,QAAQ,cAAc,GAAG;EACzB,KAAK,cAAc,GAAG;EACtB,WAAW,cAAc,GAAG,WAAW,WAAW,cAAc,GAAG,MAAM;EACzE,OAAO,cAAc,GAAG;EACxB,MAAM,cAAc,GAAG;EACvB,WAAW,cAAc,GAAG;EAC5B,MAAM,cAAc,GAAG;EACvB,WAAW,cAAc,GAAG;EAC5B;EACA,GAAG,gBAAgB;EACpB,CAAC;AAEF,KAAI,OAAO,cAAc,GAAG,WAAW,QACrC,KAAI,IAAI,UAAU;EAChB,KAAK;EACL,QAAQ,cAAc,GAAG;EACzB,KAAK,cAAc,GAAG,UAAU;EAChC,OAAO;EACP,MAAM;EACN,WAAW,cAAc,GAAG;EAC5B,MAAM,cAAc,GAAG,SACnB,OAAO,SAAS,IAAI,IAAI,cAAc,GAAG,OAAO,CAAC,MAAM,GAAG,IACzD,cAAc,GAAG,QAAQ,QAAQ;EACtC,GAAG,gBAAgB;EACpB,CAAC;AAGJ,KAAI,IAAI,OAAO;EACb,KAAK;EACL,QAAQ,cAAc,IAAI;EAC1B,KAAK,cAAc,IAAI;EACvB,WAAW,cAAc,IAAI,WAAW,WAAW,cAAc,IAAI,MAAM;EAC3E,OAAO,cAAc,IAAI;EACzB,MAAM,cAAc,IAAI;EACxB,WAAW,cAAc,IAAI;EAC7B,MAAM,cAAc,IAAI;EACxB,WAAW,cAAc,IAAI;EAC7B,OAAO,cAAc,IAAI;EACzB,WAAW,cAAc,IAAI;EAC7B,SAAS,cAAc,IAAI;EAC3B,GAAG,gBAAgB;EACpB,CAAC;AAEF,KAAI,cAAc,KAChB,KAAI,IAAI,QAAQ;EACd,KAAK;EACL,QAAQ,cAAc,KAAK;EAC3B,KAAK,cAAc,KAAK;EACxB,WAAW,cAAc,KAAK,WAAW,WAAW,cAAc,KAAK,MAAM;EAC7E,OAAO,cAAc,KAAK;EAC1B,MAAM,cAAc,KAAK;EACzB,WAAW,cAAc,KAAK;EAC9B,MAAM,cAAc,KAAK;EACzB,WAAW,cAAc,KAAK;EAC9B,OAAO,cAAc,KAAK;EAC1B,WAAW,cAAc,KAAK;EAC9B,SAAS,cAAc,KAAK;EAC5B,GAAG,gBAAgB;EACpB,CAAC;AAGJ,KAAI,cAAc,SAAS;EACzB,IAAI,iBAAiB;AACrB,OAAK,MAAM,CAAC,UAAU,iBAAiB,OAAO,QAAQ,cAAc,QAAQ,EAAE;GAC5E,MAAM,YAAY,UAAU;GAC5B,MAAM,eAAe,aAAa,QAAQ;AAC1C,oBAAiB,eAAe;AAEhC,OAAI,IAAI,WAAW;IACjB,KAAK;IACL,QAAQ,aAAa;IACrB,KAAK,aAAa;IAClB,WAAW,aAAa,WAAW,WAAW,aAAa,MAAM;IACjE,OAAO,aAAa;IACpB,MAAM,aAAa;IACnB,WAAW,aAAa;IACxB,MAAM;IACN,WAAW,aAAa;IACxB,OAAO,aAAa;IACpB,WAAW,aAAa;IACxB,SAAS,aAAa;IACtB,SAAS;IACT,MAAM,CAAC,OAAO,MAAM;IACpB,eAAe;IACf,eAAe;IACf,aAAa;IACb,eAAe;IAChB,CAAC;AAEF,OAAI,aAAa,IAAI,aAAa,aAAa,GAAG,WAAW,SAAS;IACpE,MAAM,QAAQ,aAAa;IAC3B,MAAM,SAAS,aAAa,GAAG,QAAQ;AACvC,qBAAiB,SAAS;AAE1B,QAAI,IAAI,OAAO;KACb,KAAK;KACL,QAAQ,aAAa,GAAG;KACxB,KAAK,aAAa,GAAG;KACrB,OAAO,aAAa,GAAG;KACvB,MAAM,aAAa,GAAG;KACtB,WAAW,aAAa,GAAG;KAC3B,MAAM;KACN,WAAW,aAAa,GAAG;KAC3B,SAAS;KACT,MAAM,CAAC,OAAO,MAAM;KACpB,eAAe;KACf,eAAe;KACf,aAAa;KACb,eAAe;KAChB,CAAC;;;;AAKR,QAAO;;AAYT,MAAa,4BAA4B,QACvC,MAAM,QAAQ,sBAAsB,IAAI;AAE1C,MAAa,wBAAwB,WACnC,MAAM,QAAQ,kBAAkB,OAAO;AAEzC,SAAgB,iBAAiB,KAA6C;CAC5E,MAAM,cAAc,CAAC,GAAG,IAAI,QAAQ,CAAC,CAAC,QACnC,MAAM,EAAE,QAAQ,YAAY,CAAC,EAAE,IAAI,WAAW,UAAU,CAC1D;CAED,MAAM,WAAW,YAAY,OAAO,MAAM,EAAE,WAAW,QAAQ;CAC/D,MAAM,WAAW,CAAC,GAAG,IAAI,QAAQ,CAAC,CAAC,MAAM,MAAM,EAAE,SAAS,EAAE,WAAW,QAAQ;AAC/E,KAAI,YAAY,CAAC,SAAU,QAAO;CAElC,MAAM,QAAkB,EAAE;AAC1B,MAAK,MAAM,KAAK,YACd,KAAI,EAAE,WAAW,UAAU;EACzB,MAAM,QACJ,EAAE,QAAQ,SACN,gBACA,EAAE,QAAQ,OACR,cACA,EAAE,QAAQ,QACR,WACE,SACA,eACF,EAAE,QAAQ,SACR,gBACA;AACZ,MAAI,MAAO,OAAM,KAAK,MAAM;;AAGhC,KAAI,SAAU,OAAM,KAAK,yBAAyB;AAClD,QAAO,MAAM,KAAK,MAAM,IAAI"}
package/dist/shared.cjs CHANGED
@@ -1,5 +1,7 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
2
  const require_runtime = require('./_virtual/_rolldown/runtime.cjs');
3
+ const require_merge = require('./merge.cjs');
4
+ const require_types = require('./types.cjs');
3
5
  let node_fs = require("node:fs");
4
6
  let node_path = require("node:path");
5
7
  let node_crypto = require("node:crypto");
@@ -38,9 +40,15 @@ function getSharedUiDeps(bosConfig) {
38
40
  }
39
41
  async function syncAndGenerateSharedUi(opts) {
40
42
  const bosConfigPath = (0, node_path.join)(opts.configDir, "bos.config.json");
43
+ const resolvedConfigPath = (0, node_path.join)(opts.configDir, ".bos", "bos.resolved-config.json");
41
44
  const packageJsonPath = (0, node_path.join)(opts.configDir, "package.json");
42
45
  const generatedPath = (0, node_path.join)(opts.configDir, ".bos", "generated", "shared-ui.json");
43
- const bosConfig = opts.bosConfig ?? JSON.parse((0, node_fs.readFileSync)(bosConfigPath, "utf-8"));
46
+ let bosConfig;
47
+ if (opts.bosConfig) bosConfig = opts.bosConfig;
48
+ else {
49
+ const raw = JSON.parse((0, node_fs.readFileSync)(bosConfigPath, "utf-8"));
50
+ bosConfig = require_types.BosConfigSchema.parse(raw);
51
+ }
44
52
  let pkgJson = {};
45
53
  try {
46
54
  pkgJson = JSON.parse((0, node_fs.readFileSync)(packageJsonPath, "utf-8"));
@@ -78,7 +86,21 @@ async function syncAndGenerateSharedUi(opts) {
78
86
  const nextPkg = JSON.stringify(pkgJson);
79
87
  const bosConfigChanged = nextBos !== originalBos;
80
88
  const catalogChanged = nextPkg !== originalPkg;
81
- if (bosConfigChanged) writeFileIfChanged(bosConfigPath, `${JSON.stringify(bosConfig, null, 2)}\n`);
89
+ if (bosConfigChanged) if (mode === "catalog->bos") {
90
+ const resolvedDir = (0, node_path.dirname)(resolvedConfigPath);
91
+ if (!(0, node_fs.existsSync)(resolvedDir)) (0, node_fs.mkdirSync)(resolvedDir, { recursive: true });
92
+ const ordered = require_merge.rebuildOrderedConfig(bosConfig);
93
+ const resolvedOutput = {
94
+ _resolved: {
95
+ env: opts.env ?? "development",
96
+ resolvedAt: (/* @__PURE__ */ new Date()).toISOString(),
97
+ extendsChain: opts.extendsChain ?? [],
98
+ source: "shared-sync"
99
+ },
100
+ ...ordered
101
+ };
102
+ writeFileIfChanged(resolvedConfigPath, `${JSON.stringify(resolvedOutput, null, 2)}\n`);
103
+ } else writeFileIfChanged(bosConfigPath, `${JSON.stringify(bosConfig, null, 2)}\n`);
82
104
  if (catalogChanged) writeFileIfChanged(packageJsonPath, `${JSON.stringify(pkgJson, null, 2)}\n`);
83
105
  const resolvedDeps = {};
84
106
  for (const [name, cfg] of Object.entries(getSharedUiDeps(bosConfig))) {
@@ -1 +1 @@
1
- {"version":3,"file":"shared.cjs","names":[],"sources":["../src/shared.ts"],"sourcesContent":["import { createHash } from \"node:crypto\";\nimport { mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport type { BosConfig, SharedDepConfig } from \"./types\";\n\nexport interface SharedUiResolvedDep {\n name: string;\n version: string;\n requiredVersion: string;\n shareScope: string;\n singleton: boolean;\n eager: boolean;\n strictVersion: boolean;\n}\n\nexport interface SharedUiResolved {\n deps: Record<string, SharedUiResolvedDep>;\n fingerprintSha256: string;\n}\n\nexport interface SharedSyncResult {\n mode: \"catalog->bos\" | \"bos->catalog\";\n hostMode: \"local\" | \"remote\";\n bosConfigChanged: boolean;\n catalogChanged: boolean;\n generatedChanged: boolean;\n resolved: SharedUiResolved;\n}\n\nfunction sha256(input: string): string {\n return createHash(\"sha256\").update(input).digest(\"hex\");\n}\n\nfunction extractSemverExact(input: unknown): string | null {\n if (typeof input !== \"string\") return null;\n const match = input.match(/\\d+\\.\\d+\\.\\d+(?:-[0-9A-Za-z.-]+)?/);\n return match ? match[0] : null;\n}\n\nfunction caretRange(version: string): string {\n return `^${version}`;\n}\n\nfunction stableDepsObject(\n deps: Record<string, SharedUiResolvedDep>,\n): Record<string, SharedUiResolvedDep> {\n const keys = Object.keys(deps).sort((a, b) => a.localeCompare(b));\n const out: Record<string, SharedUiResolvedDep> = {};\n for (const k of keys) out[k] = deps[k]!;\n return out;\n}\n\nfunction writeFileIfChanged(filePath: string, nextContent: string): boolean {\n try {\n const current = readFileSync(filePath, \"utf-8\");\n if (current === nextContent) return false;\n } catch {\n // ignore\n }\n\n writeFileSync(filePath, nextContent);\n return true;\n}\n\nfunction fingerprintResolved(deps: Record<string, SharedUiResolvedDep>): string {\n const stable = stableDepsObject(deps);\n return sha256(JSON.stringify(stable));\n}\n\nfunction getSharedUiDeps(bosConfig: BosConfig): Record<string, SharedDepConfig> {\n const shared = bosConfig.shared ?? {};\n const ui = shared.ui ?? {};\n return ui;\n}\n\nexport async function syncAndGenerateSharedUi(opts: {\n configDir: string;\n hostMode: \"local\" | \"remote\";\n bosConfig?: BosConfig;\n}): Promise<SharedSyncResult> {\n const bosConfigPath = join(opts.configDir, \"bos.config.json\");\n const packageJsonPath = join(opts.configDir, \"package.json\");\n const generatedPath = join(opts.configDir, \".bos\", \"generated\", \"shared-ui.json\");\n\n const bosConfig: BosConfig = opts.bosConfig ?? JSON.parse(readFileSync(bosConfigPath, \"utf-8\"));\n let pkgJson: any = {};\n try {\n pkgJson = JSON.parse(readFileSync(packageJsonPath, \"utf-8\"));\n } catch {\n // package.json might not exist\n }\n\n const originalBos = JSON.stringify(bosConfig);\n const originalPkg = JSON.stringify(pkgJson);\n\n const catalog = pkgJson?.workspaces?.catalog ?? {};\n const sharedUi = getSharedUiDeps(bosConfig);\n\n const mode = opts.hostMode === \"local\" ? \"catalog->bos\" : \"bos->catalog\";\n\n if (mode === \"catalog->bos\") {\n for (const [name, cfg] of Object.entries(sharedUi)) {\n const dep = cfg as SharedDepConfig;\n const version =\n catalog[name] ?? extractSemverExact(dep.version) ?? extractSemverExact(dep.requiredVersion);\n if (!version) continue;\n dep.version = version;\n dep.requiredVersion = caretRange(version);\n dep.shareScope = dep.shareScope ?? \"default\";\n }\n } else {\n for (const [name, cfg] of Object.entries(sharedUi)) {\n const dep = cfg as SharedDepConfig;\n const version = extractSemverExact(dep.version) ?? extractSemverExact(dep.requiredVersion);\n if (!version) continue;\n dep.version = version;\n dep.requiredVersion = caretRange(version);\n dep.shareScope = dep.shareScope ?? \"default\";\n if (catalog[name] !== version) {\n catalog[name] = version;\n }\n }\n if (!pkgJson.workspaces) pkgJson.workspaces = { packages: [], catalog: {} };\n pkgJson.workspaces.catalog = catalog;\n }\n\n const nextBos = JSON.stringify(bosConfig);\n const nextPkg = JSON.stringify(pkgJson);\n const bosConfigChanged = nextBos !== originalBos;\n const catalogChanged = nextPkg !== originalPkg;\n\n if (bosConfigChanged) {\n writeFileIfChanged(bosConfigPath, `${JSON.stringify(bosConfig, null, 2)}\\n`);\n }\n if (catalogChanged) {\n writeFileIfChanged(packageJsonPath, `${JSON.stringify(pkgJson, null, 2)}\\n`);\n }\n\n const resolvedDeps: Record<string, SharedUiResolvedDep> = {};\n for (const [name, cfg] of Object.entries(getSharedUiDeps(bosConfig))) {\n const version =\n catalog[name] ?? extractSemverExact(cfg.version) ?? extractSemverExact(cfg.requiredVersion);\n if (!version) continue;\n resolvedDeps[name] = {\n name,\n version,\n requiredVersion: caretRange(version),\n shareScope: cfg.shareScope ?? \"default\",\n singleton: cfg.singleton ?? false,\n eager: cfg.eager ?? false,\n strictVersion: cfg.strictVersion ?? false,\n };\n }\n\n const stableResolvedDeps = stableDepsObject(resolvedDeps);\n const resolved: SharedUiResolved = {\n deps: stableResolvedDeps,\n fingerprintSha256: fingerprintResolved(stableResolvedDeps),\n };\n\n const nextGenerated = {\n schemaVersion: 1,\n kind: \"everything-dev/shared-ui\",\n generatedAt: new Date().toISOString(),\n ui: {\n deps: stableResolvedDeps,\n fingerprintSha256: resolved.fingerprintSha256,\n },\n inputs: {\n mode,\n hostMode: opts.hostMode,\n },\n };\n\n let prevFingerprint: string | null = null;\n try {\n const prev = JSON.parse(readFileSync(generatedPath, \"utf-8\"));\n prevFingerprint = prev?.ui?.fingerprintSha256 ?? null;\n } catch {\n // ignore\n }\n\n mkdirSync(dirname(generatedPath), { recursive: true });\n writeFileIfChanged(generatedPath, `${JSON.stringify(nextGenerated, null, 2)}\\n`);\n\n const generatedChanged = prevFingerprint !== nextGenerated.ui.fingerprintSha256;\n\n return {\n mode,\n hostMode: opts.hostMode,\n bosConfigChanged,\n catalogChanged,\n generatedChanged,\n resolved,\n };\n}\n\nexport function loadGeneratedSharedUi(configDir: string): SharedUiResolved | null {\n const generatedPath = join(configDir, \".bos\", \"generated\", \"shared-ui.json\");\n try {\n const content = JSON.parse(readFileSync(generatedPath, \"utf-8\"));\n return content?.ui ?? null;\n } catch {\n return null;\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"shared.cjs","names":["BosConfigSchema","rebuildOrderedConfig"],"sources":["../src/shared.ts"],"sourcesContent":["import { createHash } from \"node:crypto\";\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport { type BosEnv, type ResolvedConfigMeta, rebuildOrderedConfig } from \"./merge\";\nimport type { BosConfig, SharedDepConfig } from \"./types\";\nimport { BosConfigSchema } from \"./types\";\n\ninterface PackageJson {\n name?: string;\n private?: boolean;\n version?: string;\n workspaces?: {\n packages?: string[];\n catalog?: Record<string, string>;\n };\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n scripts?: Record<string, string>;\n}\n\nexport interface SharedUiResolvedDep {\n name: string;\n version: string;\n requiredVersion: string;\n shareScope: string;\n singleton: boolean;\n eager: boolean;\n strictVersion: boolean;\n}\n\nexport interface SharedUiResolved {\n deps: Record<string, SharedUiResolvedDep>;\n fingerprintSha256: string;\n}\n\nexport interface SharedSyncResult {\n mode: \"catalog->bos\" | \"bos->catalog\";\n hostMode: \"local\" | \"remote\";\n bosConfigChanged: boolean;\n catalogChanged: boolean;\n generatedChanged: boolean;\n resolved: SharedUiResolved;\n}\n\nfunction sha256(input: string): string {\n return createHash(\"sha256\").update(input).digest(\"hex\");\n}\n\nfunction extractSemverExact(input: unknown): string | null {\n if (typeof input !== \"string\") return null;\n const match = input.match(/\\d+\\.\\d+\\.\\d+(?:-[0-9A-Za-z.-]+)?/);\n return match ? match[0] : null;\n}\n\nfunction caretRange(version: string): string {\n return `^${version}`;\n}\n\nfunction stableDepsObject(\n deps: Record<string, SharedUiResolvedDep>,\n): Record<string, SharedUiResolvedDep> {\n const keys = Object.keys(deps).sort((a, b) => a.localeCompare(b));\n const out: Record<string, SharedUiResolvedDep> = {};\n for (const k of keys) out[k] = deps[k]!;\n return out;\n}\n\nfunction writeFileIfChanged(filePath: string, nextContent: string): boolean {\n try {\n const current = readFileSync(filePath, \"utf-8\");\n if (current === nextContent) return false;\n } catch {\n // ignore\n }\n\n writeFileSync(filePath, nextContent);\n return true;\n}\n\nfunction fingerprintResolved(deps: Record<string, SharedUiResolvedDep>): string {\n const stable = stableDepsObject(deps);\n return sha256(JSON.stringify(stable));\n}\n\nfunction getSharedUiDeps(bosConfig: BosConfig): Record<string, SharedDepConfig> {\n const shared = bosConfig.shared ?? {};\n const ui = shared.ui ?? {};\n return ui;\n}\n\nexport async function syncAndGenerateSharedUi(opts: {\n configDir: string;\n hostMode: \"local\" | \"remote\";\n bosConfig?: BosConfig;\n env?: BosEnv;\n extendsChain?: string[];\n}): Promise<SharedSyncResult> {\n const bosConfigPath = join(opts.configDir, \"bos.config.json\");\n const resolvedConfigPath = join(opts.configDir, \".bos\", \"bos.resolved-config.json\");\n const packageJsonPath = join(opts.configDir, \"package.json\");\n const generatedPath = join(opts.configDir, \".bos\", \"generated\", \"shared-ui.json\");\n\n let bosConfig: BosConfig;\n if (opts.bosConfig) {\n bosConfig = opts.bosConfig;\n } else {\n const raw = JSON.parse(readFileSync(bosConfigPath, \"utf-8\")) as Record<string, unknown>;\n bosConfig = BosConfigSchema.parse(raw);\n }\n let pkgJson: PackageJson = {};\n try {\n pkgJson = JSON.parse(readFileSync(packageJsonPath, \"utf-8\")) as PackageJson;\n } catch {\n // package.json might not exist\n }\n\n const originalBos = JSON.stringify(bosConfig);\n const originalPkg = JSON.stringify(pkgJson);\n\n const catalog = pkgJson?.workspaces?.catalog ?? {};\n const sharedUi = getSharedUiDeps(bosConfig);\n\n const mode = opts.hostMode === \"local\" ? \"catalog->bos\" : \"bos->catalog\";\n\n if (mode === \"catalog->bos\") {\n for (const [name, cfg] of Object.entries(sharedUi)) {\n const dep = cfg as SharedDepConfig;\n const version =\n catalog[name] ?? extractSemverExact(dep.version) ?? extractSemverExact(dep.requiredVersion);\n if (!version) continue;\n dep.version = version;\n dep.requiredVersion = caretRange(version);\n dep.shareScope = dep.shareScope ?? \"default\";\n }\n } else {\n for (const [name, cfg] of Object.entries(sharedUi)) {\n const dep = cfg as SharedDepConfig;\n const version = extractSemverExact(dep.version) ?? extractSemverExact(dep.requiredVersion);\n if (!version) continue;\n dep.version = version;\n dep.requiredVersion = caretRange(version);\n dep.shareScope = dep.shareScope ?? \"default\";\n if (catalog[name] !== version) {\n catalog[name] = version;\n }\n }\n if (!pkgJson.workspaces) pkgJson.workspaces = { packages: [], catalog: {} };\n pkgJson.workspaces.catalog = catalog;\n }\n\n const nextBos = JSON.stringify(bosConfig);\n const nextPkg = JSON.stringify(pkgJson);\n const bosConfigChanged = nextBos !== originalBos;\n const catalogChanged = nextPkg !== originalPkg;\n\n if (bosConfigChanged) {\n if (mode === \"catalog->bos\") {\n const resolvedDir = dirname(resolvedConfigPath);\n if (!existsSync(resolvedDir)) {\n mkdirSync(resolvedDir, { recursive: true });\n }\n const ordered = rebuildOrderedConfig(bosConfig);\n const meta: ResolvedConfigMeta = {\n env: opts.env ?? \"development\",\n resolvedAt: new Date().toISOString(),\n extendsChain: opts.extendsChain ?? [],\n source: \"shared-sync\",\n };\n const resolvedOutput = {\n _resolved: meta,\n ...ordered,\n };\n writeFileIfChanged(resolvedConfigPath, `${JSON.stringify(resolvedOutput, null, 2)}\\n`);\n } else {\n writeFileIfChanged(bosConfigPath, `${JSON.stringify(bosConfig, null, 2)}\\n`);\n }\n }\n if (catalogChanged) {\n writeFileIfChanged(packageJsonPath, `${JSON.stringify(pkgJson, null, 2)}\\n`);\n }\n\n const resolvedDeps: Record<string, SharedUiResolvedDep> = {};\n for (const [name, cfg] of Object.entries(getSharedUiDeps(bosConfig))) {\n const version =\n catalog[name] ?? extractSemverExact(cfg.version) ?? extractSemverExact(cfg.requiredVersion);\n if (!version) continue;\n resolvedDeps[name] = {\n name,\n version,\n requiredVersion: caretRange(version),\n shareScope: cfg.shareScope ?? \"default\",\n singleton: cfg.singleton ?? false,\n eager: cfg.eager ?? false,\n strictVersion: cfg.strictVersion ?? false,\n };\n }\n\n const stableResolvedDeps = stableDepsObject(resolvedDeps);\n const resolved: SharedUiResolved = {\n deps: stableResolvedDeps,\n fingerprintSha256: fingerprintResolved(stableResolvedDeps),\n };\n\n const nextGenerated = {\n schemaVersion: 1,\n kind: \"everything-dev/shared-ui\",\n generatedAt: new Date().toISOString(),\n ui: {\n deps: stableResolvedDeps,\n fingerprintSha256: resolved.fingerprintSha256,\n },\n inputs: {\n mode,\n hostMode: opts.hostMode,\n },\n };\n\n let prevFingerprint: string | null = null;\n try {\n const prev = JSON.parse(readFileSync(generatedPath, \"utf-8\"));\n prevFingerprint = prev?.ui?.fingerprintSha256 ?? null;\n } catch {\n // ignore\n }\n\n mkdirSync(dirname(generatedPath), { recursive: true });\n writeFileIfChanged(generatedPath, `${JSON.stringify(nextGenerated, null, 2)}\\n`);\n\n const generatedChanged = prevFingerprint !== nextGenerated.ui.fingerprintSha256;\n\n return {\n mode,\n hostMode: opts.hostMode,\n bosConfigChanged,\n catalogChanged,\n generatedChanged,\n resolved,\n };\n}\n\nexport function loadGeneratedSharedUi(configDir: string): SharedUiResolved | null {\n const generatedPath = join(configDir, \".bos\", \"generated\", \"shared-ui.json\");\n try {\n const content = JSON.parse(readFileSync(generatedPath, \"utf-8\"));\n return content?.ui ?? null;\n } catch {\n return null;\n }\n}\n"],"mappings":"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"}
package/dist/shared.d.cts CHANGED
@@ -1,4 +1,5 @@
1
1
  import { BosConfig } from "./types.cjs";
2
+ import { BosEnv } from "./merge.cjs";
2
3
 
3
4
  //#region src/shared.d.ts
4
5
  interface SharedUiResolvedDep {
@@ -26,6 +27,8 @@ declare function syncAndGenerateSharedUi(opts: {
26
27
  configDir: string;
27
28
  hostMode: "local" | "remote";
28
29
  bosConfig?: BosConfig;
30
+ env?: BosEnv;
31
+ extendsChain?: string[];
29
32
  }): Promise<SharedSyncResult>;
30
33
  declare function loadGeneratedSharedUi(configDir: string): SharedUiResolved | null;
31
34
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"shared.d.cts","names":[],"sources":["../src/shared.ts"],"mappings":";;;UAKiB,mBAAA;EACf,IAAA;EACA,OAAA;EACA,eAAA;EACA,UAAA;EACA,SAAA;EACA,KAAA;EACA,aAAA;AAAA;AAAA,UAGe,gBAAA;EACf,IAAA,EAAM,MAAA,SAAe,mBAAA;EACrB,iBAAA;AAAA;AAAA,UAGe,gBAAA;EACf,IAAA;EACA,QAAA;EACA,gBAAA;EACA,cAAA;EACA,gBAAA;EACA,QAAA,EAAU,gBAAA;AAAA;AAAA,iBAiDU,uBAAA,CAAwB,IAAA;EAC5C,SAAA;EACA,QAAA;EACA,SAAA,GAAY,SAAA;AAAA,IACV,OAAA,CAAQ,gBAAA;AAAA,iBAsHI,qBAAA,CAAsB,SAAA,WAAoB,gBAAA"}
1
+ {"version":3,"file":"shared.d.cts","names":[],"sources":["../src/shared.ts"],"mappings":";;;;UAoBiB,mBAAA;EACf,IAAA;EACA,OAAA;EACA,eAAA;EACA,UAAA;EACA,SAAA;EACA,KAAA;EACA,aAAA;AAAA;AAAA,UAGe,gBAAA;EACf,IAAA,EAAM,MAAA,SAAe,mBAAA;EACrB,iBAAA;AAAA;AAAA,UAGe,gBAAA;EACf,IAAA;EACA,QAAA;EACA,gBAAA;EACA,cAAA;EACA,gBAAA;EACA,QAAA,EAAU,gBAAA;AAAA;AAAA,iBAiDU,uBAAA,CAAwB,IAAA;EAC5C,SAAA;EACA,QAAA;EACA,SAAA,GAAY,SAAA;EACZ,GAAA,GAAM,MAAA;EACN,YAAA;AAAA,IACE,OAAA,CAAQ,gBAAA;AAAA,iBAgJI,qBAAA,CAAsB,SAAA,WAAoB,gBAAA"}
package/dist/shared.d.mts CHANGED
@@ -1,4 +1,5 @@
1
1
  import { BosConfig } from "./types.mjs";
2
+ import { BosEnv } from "./merge.mjs";
2
3
 
3
4
  //#region src/shared.d.ts
4
5
  interface SharedUiResolvedDep {
@@ -26,6 +27,8 @@ declare function syncAndGenerateSharedUi(opts: {
26
27
  configDir: string;
27
28
  hostMode: "local" | "remote";
28
29
  bosConfig?: BosConfig;
30
+ env?: BosEnv;
31
+ extendsChain?: string[];
29
32
  }): Promise<SharedSyncResult>;
30
33
  declare function loadGeneratedSharedUi(configDir: string): SharedUiResolved | null;
31
34
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"shared.d.mts","names":[],"sources":["../src/shared.ts"],"mappings":";;;UAKiB,mBAAA;EACf,IAAA;EACA,OAAA;EACA,eAAA;EACA,UAAA;EACA,SAAA;EACA,KAAA;EACA,aAAA;AAAA;AAAA,UAGe,gBAAA;EACf,IAAA,EAAM,MAAA,SAAe,mBAAA;EACrB,iBAAA;AAAA;AAAA,UAGe,gBAAA;EACf,IAAA;EACA,QAAA;EACA,gBAAA;EACA,cAAA;EACA,gBAAA;EACA,QAAA,EAAU,gBAAA;AAAA;AAAA,iBAiDU,uBAAA,CAAwB,IAAA;EAC5C,SAAA;EACA,QAAA;EACA,SAAA,GAAY,SAAA;AAAA,IACV,OAAA,CAAQ,gBAAA;AAAA,iBAsHI,qBAAA,CAAsB,SAAA,WAAoB,gBAAA"}
1
+ {"version":3,"file":"shared.d.mts","names":[],"sources":["../src/shared.ts"],"mappings":";;;;UAoBiB,mBAAA;EACf,IAAA;EACA,OAAA;EACA,eAAA;EACA,UAAA;EACA,SAAA;EACA,KAAA;EACA,aAAA;AAAA;AAAA,UAGe,gBAAA;EACf,IAAA,EAAM,MAAA,SAAe,mBAAA;EACrB,iBAAA;AAAA;AAAA,UAGe,gBAAA;EACf,IAAA;EACA,QAAA;EACA,gBAAA;EACA,cAAA;EACA,gBAAA;EACA,QAAA,EAAU,gBAAA;AAAA;AAAA,iBAiDU,uBAAA,CAAwB,IAAA;EAC5C,SAAA;EACA,QAAA;EACA,SAAA,GAAY,SAAA;EACZ,GAAA,GAAM,MAAA;EACN,YAAA;AAAA,IACE,OAAA,CAAQ,gBAAA;AAAA,iBAgJI,qBAAA,CAAsB,SAAA,WAAoB,gBAAA"}
package/dist/shared.mjs CHANGED
@@ -1,4 +1,6 @@
1
- import { mkdirSync, readFileSync, writeFileSync } from "node:fs";
1
+ import { rebuildOrderedConfig } from "./merge.mjs";
2
+ import { BosConfigSchema } from "./types.mjs";
3
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
2
4
  import { dirname, join } from "node:path";
3
5
  import { createHash } from "node:crypto";
4
6
 
@@ -36,9 +38,15 @@ function getSharedUiDeps(bosConfig) {
36
38
  }
37
39
  async function syncAndGenerateSharedUi(opts) {
38
40
  const bosConfigPath = join(opts.configDir, "bos.config.json");
41
+ const resolvedConfigPath = join(opts.configDir, ".bos", "bos.resolved-config.json");
39
42
  const packageJsonPath = join(opts.configDir, "package.json");
40
43
  const generatedPath = join(opts.configDir, ".bos", "generated", "shared-ui.json");
41
- const bosConfig = opts.bosConfig ?? JSON.parse(readFileSync(bosConfigPath, "utf-8"));
44
+ let bosConfig;
45
+ if (opts.bosConfig) bosConfig = opts.bosConfig;
46
+ else {
47
+ const raw = JSON.parse(readFileSync(bosConfigPath, "utf-8"));
48
+ bosConfig = BosConfigSchema.parse(raw);
49
+ }
42
50
  let pkgJson = {};
43
51
  try {
44
52
  pkgJson = JSON.parse(readFileSync(packageJsonPath, "utf-8"));
@@ -76,7 +84,21 @@ async function syncAndGenerateSharedUi(opts) {
76
84
  const nextPkg = JSON.stringify(pkgJson);
77
85
  const bosConfigChanged = nextBos !== originalBos;
78
86
  const catalogChanged = nextPkg !== originalPkg;
79
- if (bosConfigChanged) writeFileIfChanged(bosConfigPath, `${JSON.stringify(bosConfig, null, 2)}\n`);
87
+ if (bosConfigChanged) if (mode === "catalog->bos") {
88
+ const resolvedDir = dirname(resolvedConfigPath);
89
+ if (!existsSync(resolvedDir)) mkdirSync(resolvedDir, { recursive: true });
90
+ const ordered = rebuildOrderedConfig(bosConfig);
91
+ const resolvedOutput = {
92
+ _resolved: {
93
+ env: opts.env ?? "development",
94
+ resolvedAt: (/* @__PURE__ */ new Date()).toISOString(),
95
+ extendsChain: opts.extendsChain ?? [],
96
+ source: "shared-sync"
97
+ },
98
+ ...ordered
99
+ };
100
+ writeFileIfChanged(resolvedConfigPath, `${JSON.stringify(resolvedOutput, null, 2)}\n`);
101
+ } else writeFileIfChanged(bosConfigPath, `${JSON.stringify(bosConfig, null, 2)}\n`);
80
102
  if (catalogChanged) writeFileIfChanged(packageJsonPath, `${JSON.stringify(pkgJson, null, 2)}\n`);
81
103
  const resolvedDeps = {};
82
104
  for (const [name, cfg] of Object.entries(getSharedUiDeps(bosConfig))) {
@@ -1 +1 @@
1
- {"version":3,"file":"shared.mjs","names":[],"sources":["../src/shared.ts"],"sourcesContent":["import { createHash } from \"node:crypto\";\nimport { mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport type { BosConfig, SharedDepConfig } from \"./types\";\n\nexport interface SharedUiResolvedDep {\n name: string;\n version: string;\n requiredVersion: string;\n shareScope: string;\n singleton: boolean;\n eager: boolean;\n strictVersion: boolean;\n}\n\nexport interface SharedUiResolved {\n deps: Record<string, SharedUiResolvedDep>;\n fingerprintSha256: string;\n}\n\nexport interface SharedSyncResult {\n mode: \"catalog->bos\" | \"bos->catalog\";\n hostMode: \"local\" | \"remote\";\n bosConfigChanged: boolean;\n catalogChanged: boolean;\n generatedChanged: boolean;\n resolved: SharedUiResolved;\n}\n\nfunction sha256(input: string): string {\n return createHash(\"sha256\").update(input).digest(\"hex\");\n}\n\nfunction extractSemverExact(input: unknown): string | null {\n if (typeof input !== \"string\") return null;\n const match = input.match(/\\d+\\.\\d+\\.\\d+(?:-[0-9A-Za-z.-]+)?/);\n return match ? match[0] : null;\n}\n\nfunction caretRange(version: string): string {\n return `^${version}`;\n}\n\nfunction stableDepsObject(\n deps: Record<string, SharedUiResolvedDep>,\n): Record<string, SharedUiResolvedDep> {\n const keys = Object.keys(deps).sort((a, b) => a.localeCompare(b));\n const out: Record<string, SharedUiResolvedDep> = {};\n for (const k of keys) out[k] = deps[k]!;\n return out;\n}\n\nfunction writeFileIfChanged(filePath: string, nextContent: string): boolean {\n try {\n const current = readFileSync(filePath, \"utf-8\");\n if (current === nextContent) return false;\n } catch {\n // ignore\n }\n\n writeFileSync(filePath, nextContent);\n return true;\n}\n\nfunction fingerprintResolved(deps: Record<string, SharedUiResolvedDep>): string {\n const stable = stableDepsObject(deps);\n return sha256(JSON.stringify(stable));\n}\n\nfunction getSharedUiDeps(bosConfig: BosConfig): Record<string, SharedDepConfig> {\n const shared = bosConfig.shared ?? {};\n const ui = shared.ui ?? {};\n return ui;\n}\n\nexport async function syncAndGenerateSharedUi(opts: {\n configDir: string;\n hostMode: \"local\" | \"remote\";\n bosConfig?: BosConfig;\n}): Promise<SharedSyncResult> {\n const bosConfigPath = join(opts.configDir, \"bos.config.json\");\n const packageJsonPath = join(opts.configDir, \"package.json\");\n const generatedPath = join(opts.configDir, \".bos\", \"generated\", \"shared-ui.json\");\n\n const bosConfig: BosConfig = opts.bosConfig ?? JSON.parse(readFileSync(bosConfigPath, \"utf-8\"));\n let pkgJson: any = {};\n try {\n pkgJson = JSON.parse(readFileSync(packageJsonPath, \"utf-8\"));\n } catch {\n // package.json might not exist\n }\n\n const originalBos = JSON.stringify(bosConfig);\n const originalPkg = JSON.stringify(pkgJson);\n\n const catalog = pkgJson?.workspaces?.catalog ?? {};\n const sharedUi = getSharedUiDeps(bosConfig);\n\n const mode = opts.hostMode === \"local\" ? \"catalog->bos\" : \"bos->catalog\";\n\n if (mode === \"catalog->bos\") {\n for (const [name, cfg] of Object.entries(sharedUi)) {\n const dep = cfg as SharedDepConfig;\n const version =\n catalog[name] ?? extractSemverExact(dep.version) ?? extractSemverExact(dep.requiredVersion);\n if (!version) continue;\n dep.version = version;\n dep.requiredVersion = caretRange(version);\n dep.shareScope = dep.shareScope ?? \"default\";\n }\n } else {\n for (const [name, cfg] of Object.entries(sharedUi)) {\n const dep = cfg as SharedDepConfig;\n const version = extractSemverExact(dep.version) ?? extractSemverExact(dep.requiredVersion);\n if (!version) continue;\n dep.version = version;\n dep.requiredVersion = caretRange(version);\n dep.shareScope = dep.shareScope ?? \"default\";\n if (catalog[name] !== version) {\n catalog[name] = version;\n }\n }\n if (!pkgJson.workspaces) pkgJson.workspaces = { packages: [], catalog: {} };\n pkgJson.workspaces.catalog = catalog;\n }\n\n const nextBos = JSON.stringify(bosConfig);\n const nextPkg = JSON.stringify(pkgJson);\n const bosConfigChanged = nextBos !== originalBos;\n const catalogChanged = nextPkg !== originalPkg;\n\n if (bosConfigChanged) {\n writeFileIfChanged(bosConfigPath, `${JSON.stringify(bosConfig, null, 2)}\\n`);\n }\n if (catalogChanged) {\n writeFileIfChanged(packageJsonPath, `${JSON.stringify(pkgJson, null, 2)}\\n`);\n }\n\n const resolvedDeps: Record<string, SharedUiResolvedDep> = {};\n for (const [name, cfg] of Object.entries(getSharedUiDeps(bosConfig))) {\n const version =\n catalog[name] ?? extractSemverExact(cfg.version) ?? extractSemverExact(cfg.requiredVersion);\n if (!version) continue;\n resolvedDeps[name] = {\n name,\n version,\n requiredVersion: caretRange(version),\n shareScope: cfg.shareScope ?? \"default\",\n singleton: cfg.singleton ?? false,\n eager: cfg.eager ?? false,\n strictVersion: cfg.strictVersion ?? false,\n };\n }\n\n const stableResolvedDeps = stableDepsObject(resolvedDeps);\n const resolved: SharedUiResolved = {\n deps: stableResolvedDeps,\n fingerprintSha256: fingerprintResolved(stableResolvedDeps),\n };\n\n const nextGenerated = {\n schemaVersion: 1,\n kind: \"everything-dev/shared-ui\",\n generatedAt: new Date().toISOString(),\n ui: {\n deps: stableResolvedDeps,\n fingerprintSha256: resolved.fingerprintSha256,\n },\n inputs: {\n mode,\n hostMode: opts.hostMode,\n },\n };\n\n let prevFingerprint: string | null = null;\n try {\n const prev = JSON.parse(readFileSync(generatedPath, \"utf-8\"));\n prevFingerprint = prev?.ui?.fingerprintSha256 ?? null;\n } catch {\n // ignore\n }\n\n mkdirSync(dirname(generatedPath), { recursive: true });\n writeFileIfChanged(generatedPath, `${JSON.stringify(nextGenerated, null, 2)}\\n`);\n\n const generatedChanged = prevFingerprint !== nextGenerated.ui.fingerprintSha256;\n\n return {\n mode,\n hostMode: opts.hostMode,\n bosConfigChanged,\n catalogChanged,\n generatedChanged,\n resolved,\n };\n}\n\nexport function loadGeneratedSharedUi(configDir: string): SharedUiResolved | null {\n const generatedPath = join(configDir, \".bos\", \"generated\", \"shared-ui.json\");\n try {\n const content = JSON.parse(readFileSync(generatedPath, \"utf-8\"));\n return content?.ui ?? null;\n } catch {\n return null;\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"shared.mjs","names":[],"sources":["../src/shared.ts"],"sourcesContent":["import { createHash } from \"node:crypto\";\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport { type BosEnv, type ResolvedConfigMeta, rebuildOrderedConfig } from \"./merge\";\nimport type { BosConfig, SharedDepConfig } from \"./types\";\nimport { BosConfigSchema } from \"./types\";\n\ninterface PackageJson {\n name?: string;\n private?: boolean;\n version?: string;\n workspaces?: {\n packages?: string[];\n catalog?: Record<string, string>;\n };\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n scripts?: Record<string, string>;\n}\n\nexport interface SharedUiResolvedDep {\n name: string;\n version: string;\n requiredVersion: string;\n shareScope: string;\n singleton: boolean;\n eager: boolean;\n strictVersion: boolean;\n}\n\nexport interface SharedUiResolved {\n deps: Record<string, SharedUiResolvedDep>;\n fingerprintSha256: string;\n}\n\nexport interface SharedSyncResult {\n mode: \"catalog->bos\" | \"bos->catalog\";\n hostMode: \"local\" | \"remote\";\n bosConfigChanged: boolean;\n catalogChanged: boolean;\n generatedChanged: boolean;\n resolved: SharedUiResolved;\n}\n\nfunction sha256(input: string): string {\n return createHash(\"sha256\").update(input).digest(\"hex\");\n}\n\nfunction extractSemverExact(input: unknown): string | null {\n if (typeof input !== \"string\") return null;\n const match = input.match(/\\d+\\.\\d+\\.\\d+(?:-[0-9A-Za-z.-]+)?/);\n return match ? match[0] : null;\n}\n\nfunction caretRange(version: string): string {\n return `^${version}`;\n}\n\nfunction stableDepsObject(\n deps: Record<string, SharedUiResolvedDep>,\n): Record<string, SharedUiResolvedDep> {\n const keys = Object.keys(deps).sort((a, b) => a.localeCompare(b));\n const out: Record<string, SharedUiResolvedDep> = {};\n for (const k of keys) out[k] = deps[k]!;\n return out;\n}\n\nfunction writeFileIfChanged(filePath: string, nextContent: string): boolean {\n try {\n const current = readFileSync(filePath, \"utf-8\");\n if (current === nextContent) return false;\n } catch {\n // ignore\n }\n\n writeFileSync(filePath, nextContent);\n return true;\n}\n\nfunction fingerprintResolved(deps: Record<string, SharedUiResolvedDep>): string {\n const stable = stableDepsObject(deps);\n return sha256(JSON.stringify(stable));\n}\n\nfunction getSharedUiDeps(bosConfig: BosConfig): Record<string, SharedDepConfig> {\n const shared = bosConfig.shared ?? {};\n const ui = shared.ui ?? {};\n return ui;\n}\n\nexport async function syncAndGenerateSharedUi(opts: {\n configDir: string;\n hostMode: \"local\" | \"remote\";\n bosConfig?: BosConfig;\n env?: BosEnv;\n extendsChain?: string[];\n}): Promise<SharedSyncResult> {\n const bosConfigPath = join(opts.configDir, \"bos.config.json\");\n const resolvedConfigPath = join(opts.configDir, \".bos\", \"bos.resolved-config.json\");\n const packageJsonPath = join(opts.configDir, \"package.json\");\n const generatedPath = join(opts.configDir, \".bos\", \"generated\", \"shared-ui.json\");\n\n let bosConfig: BosConfig;\n if (opts.bosConfig) {\n bosConfig = opts.bosConfig;\n } else {\n const raw = JSON.parse(readFileSync(bosConfigPath, \"utf-8\")) as Record<string, unknown>;\n bosConfig = BosConfigSchema.parse(raw);\n }\n let pkgJson: PackageJson = {};\n try {\n pkgJson = JSON.parse(readFileSync(packageJsonPath, \"utf-8\")) as PackageJson;\n } catch {\n // package.json might not exist\n }\n\n const originalBos = JSON.stringify(bosConfig);\n const originalPkg = JSON.stringify(pkgJson);\n\n const catalog = pkgJson?.workspaces?.catalog ?? {};\n const sharedUi = getSharedUiDeps(bosConfig);\n\n const mode = opts.hostMode === \"local\" ? \"catalog->bos\" : \"bos->catalog\";\n\n if (mode === \"catalog->bos\") {\n for (const [name, cfg] of Object.entries(sharedUi)) {\n const dep = cfg as SharedDepConfig;\n const version =\n catalog[name] ?? extractSemverExact(dep.version) ?? extractSemverExact(dep.requiredVersion);\n if (!version) continue;\n dep.version = version;\n dep.requiredVersion = caretRange(version);\n dep.shareScope = dep.shareScope ?? \"default\";\n }\n } else {\n for (const [name, cfg] of Object.entries(sharedUi)) {\n const dep = cfg as SharedDepConfig;\n const version = extractSemverExact(dep.version) ?? extractSemverExact(dep.requiredVersion);\n if (!version) continue;\n dep.version = version;\n dep.requiredVersion = caretRange(version);\n dep.shareScope = dep.shareScope ?? \"default\";\n if (catalog[name] !== version) {\n catalog[name] = version;\n }\n }\n if (!pkgJson.workspaces) pkgJson.workspaces = { packages: [], catalog: {} };\n pkgJson.workspaces.catalog = catalog;\n }\n\n const nextBos = JSON.stringify(bosConfig);\n const nextPkg = JSON.stringify(pkgJson);\n const bosConfigChanged = nextBos !== originalBos;\n const catalogChanged = nextPkg !== originalPkg;\n\n if (bosConfigChanged) {\n if (mode === \"catalog->bos\") {\n const resolvedDir = dirname(resolvedConfigPath);\n if (!existsSync(resolvedDir)) {\n mkdirSync(resolvedDir, { recursive: true });\n }\n const ordered = rebuildOrderedConfig(bosConfig);\n const meta: ResolvedConfigMeta = {\n env: opts.env ?? \"development\",\n resolvedAt: new Date().toISOString(),\n extendsChain: opts.extendsChain ?? [],\n source: \"shared-sync\",\n };\n const resolvedOutput = {\n _resolved: meta,\n ...ordered,\n };\n writeFileIfChanged(resolvedConfigPath, `${JSON.stringify(resolvedOutput, null, 2)}\\n`);\n } else {\n writeFileIfChanged(bosConfigPath, `${JSON.stringify(bosConfig, null, 2)}\\n`);\n }\n }\n if (catalogChanged) {\n writeFileIfChanged(packageJsonPath, `${JSON.stringify(pkgJson, null, 2)}\\n`);\n }\n\n const resolvedDeps: Record<string, SharedUiResolvedDep> = {};\n for (const [name, cfg] of Object.entries(getSharedUiDeps(bosConfig))) {\n const version =\n catalog[name] ?? extractSemverExact(cfg.version) ?? extractSemverExact(cfg.requiredVersion);\n if (!version) continue;\n resolvedDeps[name] = {\n name,\n version,\n requiredVersion: caretRange(version),\n shareScope: cfg.shareScope ?? \"default\",\n singleton: cfg.singleton ?? false,\n eager: cfg.eager ?? false,\n strictVersion: cfg.strictVersion ?? false,\n };\n }\n\n const stableResolvedDeps = stableDepsObject(resolvedDeps);\n const resolved: SharedUiResolved = {\n deps: stableResolvedDeps,\n fingerprintSha256: fingerprintResolved(stableResolvedDeps),\n };\n\n const nextGenerated = {\n schemaVersion: 1,\n kind: \"everything-dev/shared-ui\",\n generatedAt: new Date().toISOString(),\n ui: {\n deps: stableResolvedDeps,\n fingerprintSha256: resolved.fingerprintSha256,\n },\n inputs: {\n mode,\n hostMode: opts.hostMode,\n },\n };\n\n let prevFingerprint: string | null = null;\n try {\n const prev = JSON.parse(readFileSync(generatedPath, \"utf-8\"));\n prevFingerprint = prev?.ui?.fingerprintSha256 ?? null;\n } catch {\n // ignore\n }\n\n mkdirSync(dirname(generatedPath), { recursive: true });\n writeFileIfChanged(generatedPath, `${JSON.stringify(nextGenerated, null, 2)}\\n`);\n\n const generatedChanged = prevFingerprint !== nextGenerated.ui.fingerprintSha256;\n\n return {\n mode,\n hostMode: opts.hostMode,\n bosConfigChanged,\n catalogChanged,\n generatedChanged,\n resolved,\n };\n}\n\nexport function loadGeneratedSharedUi(configDir: string): SharedUiResolved | null {\n const generatedPath = join(configDir, \".bos\", \"generated\", \"shared-ui.json\");\n try {\n const content = JSON.parse(readFileSync(generatedPath, \"utf-8\"));\n return content?.ui ?? null;\n } catch {\n return null;\n }\n}\n"],"mappings":"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"}
@@ -0,0 +1,124 @@
1
+ const require_runtime = require('./_virtual/_rolldown/runtime.cjs');
2
+ let node_fs = require("node:fs");
3
+ let node_path = require("node:path");
4
+
5
+ //#region src/sidebar.ts
6
+ const ICON_IMPORTS = {
7
+ Home: "lucide-react",
8
+ Globe: "lucide-react",
9
+ FolderKanban: "lucide-react",
10
+ Building2: "lucide-react",
11
+ Settings: "lucide-react",
12
+ User: "lucide-react",
13
+ Users: "lucide-react",
14
+ Shield: "lucide-react",
15
+ LayoutDashboard: "lucide-react",
16
+ CreditCard: "lucide-react",
17
+ Bell: "lucide-react",
18
+ Key: "lucide-react",
19
+ FileText: "lucide-react",
20
+ Database: "lucide-react",
21
+ Activity: "lucide-react",
22
+ BarChart3: "lucide-react",
23
+ Zap: "lucide-react",
24
+ Terminal: "lucide-react",
25
+ Code: "lucide-react",
26
+ Package: "lucide-react",
27
+ Store: "lucide-react",
28
+ ShoppingBag: "lucide-react",
29
+ Wallet: "lucide-react",
30
+ Coins: "lucide-react",
31
+ Plug: "lucide-react",
32
+ Link: "lucide-react",
33
+ ExternalLink: "lucide-react",
34
+ Puzzle: "lucide-react",
35
+ Layers: "lucide-react",
36
+ Grid3X3: "lucide-react",
37
+ AppWindow: "lucide-react"
38
+ };
39
+ function resolveIconModule(iconName) {
40
+ if (ICON_IMPORTS[iconName]) return ICON_IMPORTS[iconName];
41
+ return "lucide-react";
42
+ }
43
+ function collectIconImports(items) {
44
+ const moduleMap = /* @__PURE__ */ new Map();
45
+ for (const item of items) {
46
+ const module = resolveIconModule(item.icon);
47
+ if (!moduleMap.has(module)) moduleMap.set(module, /* @__PURE__ */ new Set());
48
+ moduleMap.get(module).add(item.icon);
49
+ }
50
+ return moduleMap;
51
+ }
52
+ function generatePluginSidebarContent(config, configDir) {
53
+ const coreItems = [{
54
+ icon: "Home",
55
+ label: "home",
56
+ to: "/",
57
+ roleRequired: "anon"
58
+ }];
59
+ if (config.app.auth?.sidebar) for (const item of config.app.auth.sidebar) coreItems.push({
60
+ ...item,
61
+ to: item.to ?? "/auth",
62
+ roleRequired: item.roleRequired ?? "member"
63
+ });
64
+ const pluginItems = [];
65
+ if (config.plugins) for (const [key, entry] of Object.entries(config.plugins)) {
66
+ let sidebar;
67
+ if (typeof entry === "object" && entry.sidebar) sidebar = entry.sidebar;
68
+ else if (typeof entry === "object" && entry.development?.startsWith("local:") && configDir) {
69
+ const pluginConfigPath = (0, node_path.join)((0, node_path.join)(configDir, entry.development.slice(6).trim()), "bos.config.json");
70
+ if ((0, node_fs.existsSync)(pluginConfigPath)) try {
71
+ const pluginConfig = JSON.parse((0, node_fs.readFileSync)(pluginConfigPath, "utf-8"));
72
+ if (pluginConfig.sidebar) sidebar = pluginConfig.sidebar;
73
+ } catch {}
74
+ }
75
+ if (!sidebar) continue;
76
+ for (const item of sidebar) pluginItems.push({
77
+ ...item,
78
+ to: item.to ?? `/${key}`,
79
+ roleRequired: item.roleRequired ?? "member"
80
+ });
81
+ }
82
+ const allItems = [...coreItems, ...pluginItems];
83
+ const moduleMap = collectIconImports(allItems);
84
+ const importLines = [];
85
+ for (const [module, icons] of moduleMap) {
86
+ const iconList = [...icons].join(", ");
87
+ importLines.push(`import { ${iconList} } from "${module}";`);
88
+ }
89
+ const itemsCode = allItems.map((item) => ` { icon: ${item.icon}, label: "${item.label}", to: "${item.to}" as const, roleRequired: "${item.roleRequired}" as const },`).join("\n");
90
+ return `// Auto-generated by bos sync/pluginAdd/pluginRemove. Do not edit.
91
+ ${importLines.join("\n")}
92
+
93
+ export type SidebarRole = "anon" | "member" | "admin";
94
+
95
+ export interface SidebarItem {
96
+ icon: React.ComponentType<{ className?: string }>;
97
+ label: string;
98
+ to: string;
99
+ roleRequired: SidebarRole;
100
+ }
101
+
102
+ export const pluginSidebarItems: SidebarItem[] = [
103
+ ${itemsCode}
104
+ ];
105
+ `;
106
+ }
107
+ function writePluginSidebarGen(configDir, config) {
108
+ const outputPath = (0, node_path.join)(configDir, "ui/src/lib/plugin-sidebar.gen.ts");
109
+ const content = generatePluginSidebarContent(config, configDir);
110
+ const outputDir = (0, node_path.dirname)(outputPath);
111
+ if (!(0, node_fs.existsSync)(outputDir)) (0, node_fs.mkdirSync)(outputDir, { recursive: true });
112
+ let existingContent = null;
113
+ try {
114
+ existingContent = (0, node_fs.existsSync)(outputPath) ? (0, node_fs.readFileSync)(outputPath, "utf-8") : null;
115
+ } catch {}
116
+ if (existingContent === content) return outputPath;
117
+ (0, node_fs.writeFileSync)(outputPath, content);
118
+ return outputPath;
119
+ }
120
+
121
+ //#endregion
122
+ exports.generatePluginSidebarContent = generatePluginSidebarContent;
123
+ exports.writePluginSidebarGen = writePluginSidebarGen;
124
+ //# sourceMappingURL=sidebar.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sidebar.cjs","names":[],"sources":["../src/sidebar.ts"],"sourcesContent":["import { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport type { BosConfig, SidebarItem } from \"./types\";\n\nconst ICON_IMPORTS: Record<string, string> = {\n Home: \"lucide-react\",\n Globe: \"lucide-react\",\n FolderKanban: \"lucide-react\",\n Building2: \"lucide-react\",\n Settings: \"lucide-react\",\n User: \"lucide-react\",\n Users: \"lucide-react\",\n Shield: \"lucide-react\",\n LayoutDashboard: \"lucide-react\",\n CreditCard: \"lucide-react\",\n Bell: \"lucide-react\",\n Key: \"lucide-react\",\n FileText: \"lucide-react\",\n Database: \"lucide-react\",\n Activity: \"lucide-react\",\n BarChart3: \"lucide-react\",\n Zap: \"lucide-react\",\n Terminal: \"lucide-react\",\n Code: \"lucide-react\",\n Package: \"lucide-react\",\n Store: \"lucide-react\",\n ShoppingBag: \"lucide-react\",\n Wallet: \"lucide-react\",\n Coins: \"lucide-react\",\n Plug: \"lucide-react\",\n Link: \"lucide-react\",\n ExternalLink: \"lucide-react\",\n Puzzle: \"lucide-react\",\n Layers: \"lucide-react\",\n Grid3X3: \"lucide-react\",\n AppWindow: \"lucide-react\",\n};\n\nfunction resolveIconModule(iconName: string): string {\n if (ICON_IMPORTS[iconName]) return ICON_IMPORTS[iconName];\n return \"lucide-react\";\n}\n\nfunction collectIconImports(items: SidebarItem[]): Map<string, Set<string>> {\n const moduleMap = new Map<string, Set<string>>();\n for (const item of items) {\n const module = resolveIconModule(item.icon);\n if (!moduleMap.has(module)) moduleMap.set(module, new Set());\n moduleMap.get(module)!.add(item.icon);\n }\n return moduleMap;\n}\n\nexport function generatePluginSidebarContent(config: BosConfig, configDir?: string): string {\n const coreItems: SidebarItem[] = [{ icon: \"Home\", label: \"home\", to: \"/\", roleRequired: \"anon\" }];\n\n if (config.app.auth?.sidebar) {\n for (const item of config.app.auth.sidebar) {\n coreItems.push({\n ...item,\n to: item.to ?? \"/auth\",\n roleRequired: item.roleRequired ?? \"member\",\n });\n }\n }\n\n const pluginItems: SidebarItem[] = [];\n if (config.plugins) {\n for (const [key, entry] of Object.entries(config.plugins)) {\n let sidebar: SidebarItem[] | undefined;\n\n if (typeof entry === \"object\" && entry.sidebar) {\n sidebar = entry.sidebar;\n } else if (\n typeof entry === \"object\" &&\n entry.development?.startsWith(\"local:\") &&\n configDir\n ) {\n const localPath = join(configDir, entry.development.slice(\"local:\".length).trim());\n const pluginConfigPath = join(localPath, \"bos.config.json\");\n if (existsSync(pluginConfigPath)) {\n try {\n const pluginConfig = JSON.parse(readFileSync(pluginConfigPath, \"utf-8\")) as {\n sidebar?: SidebarItem[];\n };\n if (pluginConfig.sidebar) {\n sidebar = pluginConfig.sidebar;\n }\n } catch {}\n }\n }\n\n if (!sidebar) continue;\n for (const item of sidebar) {\n pluginItems.push({\n ...item,\n to: item.to ?? `/${key}`,\n roleRequired: item.roleRequired ?? \"member\",\n });\n }\n }\n }\n\n const allItems = [...coreItems, ...pluginItems];\n const moduleMap = collectIconImports(allItems);\n\n const importLines: string[] = [];\n for (const [module, icons] of moduleMap) {\n const iconList = [...icons].join(\", \");\n importLines.push(`import { ${iconList} } from \"${module}\";`);\n }\n\n const itemsCode = allItems\n .map(\n (item) =>\n ` { icon: ${item.icon}, label: \"${item.label}\", to: \"${item.to}\" as const, roleRequired: \"${item.roleRequired}\" as const },`,\n )\n .join(\"\\n\");\n\n return `// Auto-generated by bos sync/pluginAdd/pluginRemove. Do not edit.\n${importLines.join(\"\\n\")}\n\nexport type SidebarRole = \"anon\" | \"member\" | \"admin\";\n\nexport interface SidebarItem {\n icon: React.ComponentType<{ className?: string }>;\n label: string;\n to: string;\n roleRequired: SidebarRole;\n}\n\nexport const pluginSidebarItems: SidebarItem[] = [\n${itemsCode}\n];\n`;\n}\n\nexport function writePluginSidebarGen(configDir: string, config: BosConfig): string {\n const outputPath = join(configDir, \"ui/src/lib/plugin-sidebar.gen.ts\");\n\n const content = generatePluginSidebarContent(config, configDir);\n\n const outputDir = dirname(outputPath);\n if (!existsSync(outputDir)) {\n mkdirSync(outputDir, { recursive: true });\n }\n\n let existingContent: string | null = null;\n try {\n existingContent = existsSync(outputPath)\n ? // eslint-disable-next-line no-restricted-syntax\n readFileSync(outputPath, \"utf-8\")\n : null;\n } catch {\n // file doesn't exist yet\n }\n\n if (existingContent === content) return outputPath;\n\n writeFileSync(outputPath, content);\n return outputPath;\n}\n"],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ import { BosConfig } from "./types.cjs";
2
+
3
+ //#region src/sidebar.d.ts
4
+ declare function generatePluginSidebarContent(config: BosConfig, configDir?: string): string;
5
+ declare function writePluginSidebarGen(configDir: string, config: BosConfig): string;
6
+ //#endregion
7
+ export { generatePluginSidebarContent, writePluginSidebarGen };
8
+ //# sourceMappingURL=sidebar.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sidebar.d.cts","names":[],"sources":["../src/sidebar.ts"],"mappings":";;;iBAqDgB,4BAAA,CAA6B,MAAA,EAAQ,SAAA,EAAW,SAAA;AAAA,iBAoFhD,qBAAA,CAAsB,SAAA,UAAmB,MAAA,EAAQ,SAAA"}
@@ -0,0 +1,8 @@
1
+ import { BosConfig } from "./types.mjs";
2
+
3
+ //#region src/sidebar.d.ts
4
+ declare function generatePluginSidebarContent(config: BosConfig, configDir?: string): string;
5
+ declare function writePluginSidebarGen(configDir: string, config: BosConfig): string;
6
+ //#endregion
7
+ export { generatePluginSidebarContent, writePluginSidebarGen };
8
+ //# sourceMappingURL=sidebar.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sidebar.d.mts","names":[],"sources":["../src/sidebar.ts"],"mappings":";;;iBAqDgB,4BAAA,CAA6B,MAAA,EAAQ,SAAA,EAAW,SAAA;AAAA,iBAoFhD,qBAAA,CAAsB,SAAA,UAAmB,MAAA,EAAQ,SAAA"}
@@ -0,0 +1,122 @@
1
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
2
+ import { dirname, join } from "node:path";
3
+
4
+ //#region src/sidebar.ts
5
+ const ICON_IMPORTS = {
6
+ Home: "lucide-react",
7
+ Globe: "lucide-react",
8
+ FolderKanban: "lucide-react",
9
+ Building2: "lucide-react",
10
+ Settings: "lucide-react",
11
+ User: "lucide-react",
12
+ Users: "lucide-react",
13
+ Shield: "lucide-react",
14
+ LayoutDashboard: "lucide-react",
15
+ CreditCard: "lucide-react",
16
+ Bell: "lucide-react",
17
+ Key: "lucide-react",
18
+ FileText: "lucide-react",
19
+ Database: "lucide-react",
20
+ Activity: "lucide-react",
21
+ BarChart3: "lucide-react",
22
+ Zap: "lucide-react",
23
+ Terminal: "lucide-react",
24
+ Code: "lucide-react",
25
+ Package: "lucide-react",
26
+ Store: "lucide-react",
27
+ ShoppingBag: "lucide-react",
28
+ Wallet: "lucide-react",
29
+ Coins: "lucide-react",
30
+ Plug: "lucide-react",
31
+ Link: "lucide-react",
32
+ ExternalLink: "lucide-react",
33
+ Puzzle: "lucide-react",
34
+ Layers: "lucide-react",
35
+ Grid3X3: "lucide-react",
36
+ AppWindow: "lucide-react"
37
+ };
38
+ function resolveIconModule(iconName) {
39
+ if (ICON_IMPORTS[iconName]) return ICON_IMPORTS[iconName];
40
+ return "lucide-react";
41
+ }
42
+ function collectIconImports(items) {
43
+ const moduleMap = /* @__PURE__ */ new Map();
44
+ for (const item of items) {
45
+ const module = resolveIconModule(item.icon);
46
+ if (!moduleMap.has(module)) moduleMap.set(module, /* @__PURE__ */ new Set());
47
+ moduleMap.get(module).add(item.icon);
48
+ }
49
+ return moduleMap;
50
+ }
51
+ function generatePluginSidebarContent(config, configDir) {
52
+ const coreItems = [{
53
+ icon: "Home",
54
+ label: "home",
55
+ to: "/",
56
+ roleRequired: "anon"
57
+ }];
58
+ if (config.app.auth?.sidebar) for (const item of config.app.auth.sidebar) coreItems.push({
59
+ ...item,
60
+ to: item.to ?? "/auth",
61
+ roleRequired: item.roleRequired ?? "member"
62
+ });
63
+ const pluginItems = [];
64
+ if (config.plugins) for (const [key, entry] of Object.entries(config.plugins)) {
65
+ let sidebar;
66
+ if (typeof entry === "object" && entry.sidebar) sidebar = entry.sidebar;
67
+ else if (typeof entry === "object" && entry.development?.startsWith("local:") && configDir) {
68
+ const pluginConfigPath = join(join(configDir, entry.development.slice(6).trim()), "bos.config.json");
69
+ if (existsSync(pluginConfigPath)) try {
70
+ const pluginConfig = JSON.parse(readFileSync(pluginConfigPath, "utf-8"));
71
+ if (pluginConfig.sidebar) sidebar = pluginConfig.sidebar;
72
+ } catch {}
73
+ }
74
+ if (!sidebar) continue;
75
+ for (const item of sidebar) pluginItems.push({
76
+ ...item,
77
+ to: item.to ?? `/${key}`,
78
+ roleRequired: item.roleRequired ?? "member"
79
+ });
80
+ }
81
+ const allItems = [...coreItems, ...pluginItems];
82
+ const moduleMap = collectIconImports(allItems);
83
+ const importLines = [];
84
+ for (const [module, icons] of moduleMap) {
85
+ const iconList = [...icons].join(", ");
86
+ importLines.push(`import { ${iconList} } from "${module}";`);
87
+ }
88
+ const itemsCode = allItems.map((item) => ` { icon: ${item.icon}, label: "${item.label}", to: "${item.to}" as const, roleRequired: "${item.roleRequired}" as const },`).join("\n");
89
+ return `// Auto-generated by bos sync/pluginAdd/pluginRemove. Do not edit.
90
+ ${importLines.join("\n")}
91
+
92
+ export type SidebarRole = "anon" | "member" | "admin";
93
+
94
+ export interface SidebarItem {
95
+ icon: React.ComponentType<{ className?: string }>;
96
+ label: string;
97
+ to: string;
98
+ roleRequired: SidebarRole;
99
+ }
100
+
101
+ export const pluginSidebarItems: SidebarItem[] = [
102
+ ${itemsCode}
103
+ ];
104
+ `;
105
+ }
106
+ function writePluginSidebarGen(configDir, config) {
107
+ const outputPath = join(configDir, "ui/src/lib/plugin-sidebar.gen.ts");
108
+ const content = generatePluginSidebarContent(config, configDir);
109
+ const outputDir = dirname(outputPath);
110
+ if (!existsSync(outputDir)) mkdirSync(outputDir, { recursive: true });
111
+ let existingContent = null;
112
+ try {
113
+ existingContent = existsSync(outputPath) ? readFileSync(outputPath, "utf-8") : null;
114
+ } catch {}
115
+ if (existingContent === content) return outputPath;
116
+ writeFileSync(outputPath, content);
117
+ return outputPath;
118
+ }
119
+
120
+ //#endregion
121
+ export { generatePluginSidebarContent, writePluginSidebarGen };
122
+ //# sourceMappingURL=sidebar.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sidebar.mjs","names":[],"sources":["../src/sidebar.ts"],"sourcesContent":["import { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport type { BosConfig, SidebarItem } from \"./types\";\n\nconst ICON_IMPORTS: Record<string, string> = {\n Home: \"lucide-react\",\n Globe: \"lucide-react\",\n FolderKanban: \"lucide-react\",\n Building2: \"lucide-react\",\n Settings: \"lucide-react\",\n User: \"lucide-react\",\n Users: \"lucide-react\",\n Shield: \"lucide-react\",\n LayoutDashboard: \"lucide-react\",\n CreditCard: \"lucide-react\",\n Bell: \"lucide-react\",\n Key: \"lucide-react\",\n FileText: \"lucide-react\",\n Database: \"lucide-react\",\n Activity: \"lucide-react\",\n BarChart3: \"lucide-react\",\n Zap: \"lucide-react\",\n Terminal: \"lucide-react\",\n Code: \"lucide-react\",\n Package: \"lucide-react\",\n Store: \"lucide-react\",\n ShoppingBag: \"lucide-react\",\n Wallet: \"lucide-react\",\n Coins: \"lucide-react\",\n Plug: \"lucide-react\",\n Link: \"lucide-react\",\n ExternalLink: \"lucide-react\",\n Puzzle: \"lucide-react\",\n Layers: \"lucide-react\",\n Grid3X3: \"lucide-react\",\n AppWindow: \"lucide-react\",\n};\n\nfunction resolveIconModule(iconName: string): string {\n if (ICON_IMPORTS[iconName]) return ICON_IMPORTS[iconName];\n return \"lucide-react\";\n}\n\nfunction collectIconImports(items: SidebarItem[]): Map<string, Set<string>> {\n const moduleMap = new Map<string, Set<string>>();\n for (const item of items) {\n const module = resolveIconModule(item.icon);\n if (!moduleMap.has(module)) moduleMap.set(module, new Set());\n moduleMap.get(module)!.add(item.icon);\n }\n return moduleMap;\n}\n\nexport function generatePluginSidebarContent(config: BosConfig, configDir?: string): string {\n const coreItems: SidebarItem[] = [{ icon: \"Home\", label: \"home\", to: \"/\", roleRequired: \"anon\" }];\n\n if (config.app.auth?.sidebar) {\n for (const item of config.app.auth.sidebar) {\n coreItems.push({\n ...item,\n to: item.to ?? \"/auth\",\n roleRequired: item.roleRequired ?? \"member\",\n });\n }\n }\n\n const pluginItems: SidebarItem[] = [];\n if (config.plugins) {\n for (const [key, entry] of Object.entries(config.plugins)) {\n let sidebar: SidebarItem[] | undefined;\n\n if (typeof entry === \"object\" && entry.sidebar) {\n sidebar = entry.sidebar;\n } else if (\n typeof entry === \"object\" &&\n entry.development?.startsWith(\"local:\") &&\n configDir\n ) {\n const localPath = join(configDir, entry.development.slice(\"local:\".length).trim());\n const pluginConfigPath = join(localPath, \"bos.config.json\");\n if (existsSync(pluginConfigPath)) {\n try {\n const pluginConfig = JSON.parse(readFileSync(pluginConfigPath, \"utf-8\")) as {\n sidebar?: SidebarItem[];\n };\n if (pluginConfig.sidebar) {\n sidebar = pluginConfig.sidebar;\n }\n } catch {}\n }\n }\n\n if (!sidebar) continue;\n for (const item of sidebar) {\n pluginItems.push({\n ...item,\n to: item.to ?? `/${key}`,\n roleRequired: item.roleRequired ?? \"member\",\n });\n }\n }\n }\n\n const allItems = [...coreItems, ...pluginItems];\n const moduleMap = collectIconImports(allItems);\n\n const importLines: string[] = [];\n for (const [module, icons] of moduleMap) {\n const iconList = [...icons].join(\", \");\n importLines.push(`import { ${iconList} } from \"${module}\";`);\n }\n\n const itemsCode = allItems\n .map(\n (item) =>\n ` { icon: ${item.icon}, label: \"${item.label}\", to: \"${item.to}\" as const, roleRequired: \"${item.roleRequired}\" as const },`,\n )\n .join(\"\\n\");\n\n return `// Auto-generated by bos sync/pluginAdd/pluginRemove. Do not edit.\n${importLines.join(\"\\n\")}\n\nexport type SidebarRole = \"anon\" | \"member\" | \"admin\";\n\nexport interface SidebarItem {\n icon: React.ComponentType<{ className?: string }>;\n label: string;\n to: string;\n roleRequired: SidebarRole;\n}\n\nexport const pluginSidebarItems: SidebarItem[] = [\n${itemsCode}\n];\n`;\n}\n\nexport function writePluginSidebarGen(configDir: string, config: BosConfig): string {\n const outputPath = join(configDir, \"ui/src/lib/plugin-sidebar.gen.ts\");\n\n const content = generatePluginSidebarContent(config, configDir);\n\n const outputDir = dirname(outputPath);\n if (!existsSync(outputDir)) {\n mkdirSync(outputDir, { recursive: true });\n }\n\n let existingContent: string | null = null;\n try {\n existingContent = existsSync(outputPath)\n ? // eslint-disable-next-line no-restricted-syntax\n readFileSync(outputPath, \"utf-8\")\n : null;\n } catch {\n // file doesn't exist yet\n }\n\n if (existingContent === content) return outputPath;\n\n writeFileSync(outputPath, content);\n return outputPath;\n}\n"],"mappings":"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"}