@publish.os/nextjs 0.0.1-alpha.8 → 0.0.1-alpha.90

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 (201) hide show
  1. package/compiler-assets/nextjs/defaults/app/globals.css +1 -0
  2. package/compiler-assets/nextjs/defaults/group/index.tsx +50 -0
  3. package/compiler-assets/nextjs/defaults/group/layout.tsx +7 -3
  4. package/compiler-assets/nextjs/defaults/group/page.tsx +35 -43
  5. package/compiler-assets/nextjs/defaults/project/next.config.mjs +22 -11
  6. package/compiler-assets/nextjs/defaults/project/tsconfig.json.template +1 -4
  7. package/compiler-assets/nextjs/defaults/root/css/animation.css +131 -0
  8. package/compiler-assets/nextjs/defaults/root/css/components/dialog.css +4 -1
  9. package/compiler-assets/nextjs/defaults/root/css/components/menu.css +1 -1
  10. package/compiler-assets/nextjs/defaults/root/css/components/navigation-menu.css +1 -1
  11. package/compiler-assets/nextjs/defaults/root/css/components/popover.css +1 -1
  12. package/compiler-assets/nextjs/defaults/root/css/components/select.css +1 -1
  13. package/compiler-assets/nextjs/defaults/root/css/components/tooltip.css +1 -1
  14. package/compiler-assets/nextjs/defaults/root/css/shadow.css +6 -25
  15. package/compiler-assets/nextjs/defaults/root/css/typography.css +51 -68
  16. package/compiler-assets/nextjs/defaults/root/globals.css +25 -0
  17. package/compiler-assets/nextjs/defaults/root/{page.tsx → index.tsx} +6 -2
  18. package/compiler-assets/nextjs/defaults/root/layout.tsx +7 -1
  19. package/compiler-assets/nextjs/defaults/root/theme.css +22 -22
  20. package/compiler-assets/nextjs/shims/generated-group-page.tsx +19 -2
  21. package/compiler-assets/nextjs/shims/generated-leaf-page.tsx +16 -2
  22. package/compiler-assets/nextjs/shims/global-layout.tsx +11 -43
  23. package/compiler-assets/nextjs/shims/proxy.ts +21 -9
  24. package/compiler-assets/nextjs/shims/publish-os-theme-provider.tsx +76 -15
  25. package/compiler-assets/nextjs/shims/root-page.tsx +7 -1
  26. package/compiler-assets/nextjs/shims/site-fenced-code-block.tsx +34 -0
  27. package/compiler-assets/nextjs/shims/site-heading-level.tsx +14 -0
  28. package/compiler-assets/nextjs/shims/site-mdx-components.tsx +100 -0
  29. package/compiler-assets/nextjs/shims/site-mdx.tsx +12 -0
  30. package/compiler-assets/nextjs/shims/theme-defaults.css +41 -25
  31. package/dist/build-operation-2JAYBSKF.js +83 -0
  32. package/dist/button-CtzUJB8u.d.ts +11 -0
  33. package/dist/{button-CFdx-ohV.d.ts → button-c3WGnxIj.d.ts} +3 -3
  34. package/dist/chunk-535TM4A5.js +1455 -0
  35. package/dist/chunk-726GV2NF.js +2344 -0
  36. package/dist/chunk-7OGTPSKI.js +156 -0
  37. package/dist/chunk-AI2UULNX.js +9 -0
  38. package/dist/chunk-B2V22WRT.js +297 -0
  39. package/dist/chunk-DLDFHU7Y.js +191 -0
  40. package/dist/chunk-DWA3ZRGW.js +142 -0
  41. package/dist/chunk-GGKFQ3MA.js +621 -0
  42. package/dist/chunk-H6XILMZX.js +6154 -0
  43. package/dist/chunk-NECL5IBJ.js +318 -0
  44. package/dist/chunk-SVYGXXYR.js +36 -0
  45. package/dist/chunk-UF6ATARM.js +1100 -0
  46. package/dist/chunk-VO2I7MTM.js +56 -0
  47. package/dist/chunk-WDY4IK6Z.js +128 -0
  48. package/dist/chunk-WKTEO6RS.js +586 -0
  49. package/dist/chunk-YLTOLYWM.js +92 -0
  50. package/dist/compiler.d.ts +41 -7
  51. package/dist/compiler.js +48 -13143
  52. package/dist/compose-NN23UJGC.js +13 -0
  53. package/dist/config/createNextConfig.js +13 -0
  54. package/dist/dev-operation-TZDVJCN7.js +1055 -0
  55. package/dist/framework-selection-X4U6Y6QC.js +10 -0
  56. package/dist/ide-support-ZNW7ODFY.js +15 -0
  57. package/dist/index.d.ts +15 -3
  58. package/dist/kernel/components/blocks/AgentActions.js +71 -61
  59. package/dist/kernel/components/blocks/design-system-preview.d.ts +1 -1
  60. package/dist/kernel/components/blocks/design-system-preview.js +32 -13
  61. package/dist/kernel/components/blocks/link-playground.js +2 -2
  62. package/dist/kernel/components/blocks/logo-block.js +2 -2
  63. package/dist/kernel/components/blocks/nav-breadcrumb.d.ts +10 -2
  64. package/dist/kernel/components/blocks/nav-breadcrumb.js +20 -5
  65. package/dist/kernel/components/blocks/navbar.d.ts +2 -2
  66. package/dist/kernel/components/blocks/navbar.js +401 -60
  67. package/dist/kernel/components/blocks/navigation-progress-playground.js +4 -4
  68. package/dist/kernel/components/blocks/navigation-progress.js +4 -1
  69. package/dist/kernel/components/blocks/next-prev.d.ts +1 -1
  70. package/dist/kernel/components/blocks/next-prev.js +11 -23
  71. package/dist/kernel/components/blocks/page-list.d.ts +1 -1
  72. package/dist/kernel/components/blocks/page-list.js +5 -4
  73. package/dist/kernel/components/blocks/search.d.ts +83 -58
  74. package/dist/kernel/components/blocks/search.js +553 -426
  75. package/dist/kernel/components/blocks/sidebar-node.d.ts +2 -2
  76. package/dist/kernel/components/blocks/sidebar-node.js +11 -9
  77. package/dist/kernel/components/blocks/sidebar.d.ts +3 -3
  78. package/dist/kernel/components/blocks/sidebar.js +18 -11
  79. package/dist/kernel/components/blocks/theme-toggle.d.ts +2 -2
  80. package/dist/kernel/components/blocks/theme-toggle.js +48 -2
  81. package/dist/kernel/components/blocks/toc.js +3 -3
  82. package/dist/kernel/components/mdx/components/blockquote.js +1 -1
  83. package/dist/kernel/components/mdx/components/callout.d.ts +5 -7
  84. package/dist/kernel/components/mdx/components/callout.js +66 -35
  85. package/dist/kernel/components/mdx/components/code-block.d.ts +5 -2
  86. package/dist/kernel/components/mdx/components/code-block.js +106 -5
  87. package/dist/kernel/components/mdx/components/copy-code-button.d.ts +8 -0
  88. package/dist/kernel/components/mdx/components/copy-code-button.js +60 -0
  89. package/dist/kernel/components/mdx/components/figure-caption.js +1 -1
  90. package/dist/kernel/components/mdx/components/figure.js +1 -1
  91. package/dist/kernel/components/mdx/components/heading-copy-link.js +3 -3
  92. package/dist/kernel/components/mdx/components/image-zoom.d.ts +2 -2
  93. package/dist/kernel/components/mdx/components/image-zoom.js +1 -1
  94. package/dist/kernel/components/mdx/components/image.js +77 -56
  95. package/dist/kernel/components/mdx/components/inline-code.js +1 -1
  96. package/dist/kernel/components/mdx/components/kbd.d.ts +2 -2
  97. package/dist/kernel/components/mdx/components/kbd.js +3 -2
  98. package/dist/kernel/components/mdx/components/link.d.ts +35 -4
  99. package/dist/kernel/components/mdx/components/link.js +1 -1
  100. package/dist/kernel/components/mdx/components/paragraph.js +1 -4
  101. package/dist/kernel/components/mdx/components/task-list.js +1 -1
  102. package/dist/kernel/components/mdx/components/video-player.js +2 -2
  103. package/dist/kernel/components/mdx/components/video.js +1 -1
  104. package/dist/kernel/components/mdx/error-boundary.d.ts +1 -1
  105. package/dist/kernel/components/mdx/mdx.d.ts +12 -8
  106. package/dist/kernel/components/mdx/mdx.js +115 -39
  107. package/dist/kernel/components/mdx/rehype-heading-ids.js +1 -1
  108. package/dist/kernel/components/mdx/types.d.ts +1 -1
  109. package/dist/kernel/components/ui/breadcrumb-trail.d.ts +6 -23
  110. package/dist/kernel/components/ui/breadcrumb.d.ts +11 -3
  111. package/dist/kernel/components/ui/breadcrumb.js +6 -4
  112. package/dist/kernel/components/ui/button-group.d.ts +1 -1
  113. package/dist/kernel/components/ui/button-group.js +5 -4
  114. package/dist/kernel/components/ui/button.d.ts +2 -2
  115. package/dist/kernel/components/ui/button.js +6 -6
  116. package/dist/kernel/components/ui/card.d.ts +2 -2
  117. package/dist/kernel/components/ui/drawer.d.ts +3 -1
  118. package/dist/kernel/components/ui/drawer.js +5 -1
  119. package/dist/kernel/components/ui/input.d.ts +4 -4
  120. package/dist/kernel/components/ui/kbd.d.ts +1 -1
  121. package/dist/kernel/components/ui/kbd.js +9 -16
  122. package/dist/kernel/components/ui/link.d.ts +5 -3
  123. package/dist/kernel/components/ui/link.js +10 -9
  124. package/dist/kernel/components/ui/menu.js +5 -5
  125. package/dist/kernel/components/ui/mod-key.d.ts +10 -0
  126. package/dist/kernel/components/ui/mod-key.js +36 -0
  127. package/dist/kernel/components/ui/navigation-menu.js +2 -2
  128. package/dist/kernel/components/ui/progress.js +1 -1
  129. package/dist/kernel/components/ui/scroll-area.d.ts +8 -8
  130. package/dist/kernel/components/ui/scroll-area.js +4 -4
  131. package/dist/kernel/components/ui/select.js +7 -10
  132. package/dist/kernel/components/ui/text.d.ts +2 -2
  133. package/dist/kernel/components/ui/theme-toggle.d.ts +3 -3
  134. package/dist/kernel/components/ui/theme-toggle.js +4 -9
  135. package/dist/kernel/defaults.registry.d.ts +9 -9
  136. package/dist/kernel/defaults.registry.js +9 -9
  137. package/dist/kernel/routes/agent/markdown.d.ts +0 -1
  138. package/dist/kernel/routes/layouts/group.d.ts +1 -1
  139. package/dist/kernel/routes/metadata/feed.d.ts +1 -1
  140. package/dist/kernel/routes/metadata/feed.js +13 -9
  141. package/dist/kernel/routes/metadata/llms.d.ts +2 -1
  142. package/dist/kernel/routes/metadata/llms.js +4 -4
  143. package/dist/kernel/routes/metadata/robots.d.ts +1 -1
  144. package/dist/kernel/routes/metadata/robots.js +2 -2
  145. package/dist/kernel/routes/metadata/sitemap.d.ts +6 -3
  146. package/dist/kernel/routes/metadata/sitemap.js +48 -20
  147. package/dist/kernel/routes/pages/group.d.ts +1 -1
  148. package/dist/kernel/routes/pages/group.js +20 -12
  149. package/dist/kernel/routes/pages/leaf.d.ts +2 -2
  150. package/dist/kernel/routes/pages/leaf.js +20 -12
  151. package/dist/kernel/routes/pages/root.d.ts +2 -2
  152. package/dist/kernel/routes/pages/root.js +18 -12
  153. package/dist/resolvers/manifest-resolver.js +29 -6
  154. package/dist/search.d.ts +6 -7
  155. package/dist/search.js +47 -22
  156. package/dist/{sidebar-types-Bgchdfd6.d.ts → sidebar-types-DKpR27II.d.ts} +1 -1
  157. package/dist/{types-CIwwieNw.d.ts → types-BzkZty3r.d.ts} +23 -3
  158. package/dist/{types-DHBm7-j6.d.ts → types-CJWRG05y.d.ts} +20 -1
  159. package/dist/{types-B_b3C0U6.d.ts → types-CUtrppxt.d.ts} +8 -2
  160. package/dist/types.d.ts +14 -6
  161. package/dist/validate-local-source-XRL2Y7XE.js +14 -0
  162. package/dist/validate-publish-os-source-DAPZ4QGE.js +12 -0
  163. package/init/seed/minimal/.gitignore +1 -0
  164. package/init/seed/minimal/publish.os/assets/favicon/favicon.dark.png +0 -0
  165. package/init/seed/minimal/publish.os/assets/favicon/favicon.png +0 -0
  166. package/init/seed/minimal/publish.os/docs/content/get-started.mdx +6 -10
  167. package/init/seed/minimal/publish.os/docs/content/groups.mdx +1 -1
  168. package/init/seed/minimal/publish.os/docs/content/{theme.mdx → themes.mdx} +14 -12
  169. package/init/seed/minimal/publish.os/publish.os.config.json +3 -7
  170. package/init/seed/minimal/publish.os/theme.css +52 -24
  171. package/init/seed/minimal/publish.os/tsconfig.json +3 -0
  172. package/init/seed/minimal/seed.json +4 -1
  173. package/init/seed/scratch/publish.os/docs/content/get-started.mdx +6 -0
  174. package/init/seed/scratch/publish.os/publish.os.config.json +4 -0
  175. package/init/seed/scratch/seed.json +5 -0
  176. package/package.json +12 -26
  177. package/release/app/phosphor/package.json +3 -3
  178. package/release/app/phosphor/pnpm-lock.yaml.template +523 -360
  179. package/release/app/phosphor/pnpm-workspace.yaml +3 -0
  180. package/release/compiler/package.json +1 -1
  181. package/release/compiler/pnpm-lock.yaml.template +439 -286
  182. package/release/compiler/pnpm-workspace.yaml +3 -0
  183. package/release/release.json +7 -36
  184. package/compiler-assets/nextjs/defaults/group/leaf.tsx +0 -48
  185. package/dist/icons.d.ts +0 -1
  186. package/dist/icons.js +0 -2
  187. package/dist/kernel/components/mdx/components/pre.d.ts +0 -6
  188. package/dist/kernel/components/mdx/components/pre.js +0 -18
  189. package/dist/kernel/components/ui/meta-key.d.ts +0 -17
  190. package/dist/kernel/components/ui/meta-key.js +0 -9
  191. package/dist/kernel/framework-icons.d.ts +0 -1
  192. package/dist/kernel/framework-icons.js +0 -39
  193. package/dist/link-CYaCRDb6.d.ts +0 -35
  194. package/dist/route-metadata-og-image-BeKKFHg7.d.ts +0 -58
  195. package/dist/types-sM2g9nW0.d.ts +0 -12
  196. package/release/app/lucide/package.json +0 -30
  197. package/release/app/lucide/pnpm-lock.yaml.template +0 -2905
  198. package/release/app/lucide/pnpm-workspace.yaml +0 -11
  199. package/release/app/tabler/package.json +0 -30
  200. package/release/app/tabler/pnpm-lock.yaml.template +0 -2911
  201. package/release/app/tabler/pnpm-workspace.yaml +0 -11
@@ -0,0 +1,1100 @@
1
+ import {
2
+ createIdeSourceArtifacts,
3
+ materializeAppInstallation,
4
+ prepareAppInstallation
5
+ } from "./chunk-H6XILMZX.js";
6
+ import {
7
+ supportedNextjsSourceImports
8
+ } from "./chunk-NECL5IBJ.js";
9
+ import {
10
+ installLocalApp
11
+ } from "./chunk-WKTEO6RS.js";
12
+ import {
13
+ acquireOperationLock,
14
+ assertLocalDirectory,
15
+ ensureOutputOwnership
16
+ } from "./chunk-GGKFQ3MA.js";
17
+ import {
18
+ assertFrameworkSelection,
19
+ readCheckoutTypeScriptConfig
20
+ } from "./chunk-DLDFHU7Y.js";
21
+ import {
22
+ runtimePackageVersion
23
+ } from "./chunk-AI2UULNX.js";
24
+ import {
25
+ AppError
26
+ } from "./chunk-WDY4IK6Z.js";
27
+
28
+ // src/lib/compiler/ide/ide-support.ts
29
+ import { createHash, randomUUID } from "crypto";
30
+ import {
31
+ cp,
32
+ link,
33
+ lstat,
34
+ mkdir,
35
+ readdir,
36
+ readFile,
37
+ realpath,
38
+ rm as rm2,
39
+ stat,
40
+ writeFile
41
+ } from "fs/promises";
42
+ import { createRequire } from "module";
43
+ import {
44
+ basename as basename2,
45
+ dirname as dirname2,
46
+ isAbsolute,
47
+ join as join2,
48
+ relative,
49
+ resolve,
50
+ sep
51
+ } from "path";
52
+ import { isDeepStrictEqual } from "util";
53
+ import { parseConfigFileTextToJson } from "typescript";
54
+
55
+ // src/lib/compiler/ide/ide-install.ts
56
+ async function runIdeInstall(options) {
57
+ let shutdown = /* @__PURE__ */ new Set(), failure;
58
+ try {
59
+ await installLocalApp({
60
+ ...options,
61
+ purpose: "ide",
62
+ lifetime: {
63
+ signal: options.options.signal ?? new AbortController().signal,
64
+ onShutdown: (stop) => (shutdown.add(stop), () => {
65
+ shutdown.delete(stop);
66
+ })
67
+ }
68
+ });
69
+ } catch (error) {
70
+ failure = error;
71
+ }
72
+ if ((await Promise.allSettled([...shutdown].map((stop) => stop()))).some((result) => result.status === "rejected"))
73
+ throw new AppError({
74
+ code: "FRAMEWORK_PROCESS_SHUTDOWN_FAILED",
75
+ message: "The IDE installer did not stop. Its staging files and lock remain in place.",
76
+ fix: "Stop and verify all installer descendants before recovering the retained IDE paths.",
77
+ details: { cause: failure }
78
+ });
79
+ if (failure) throw failure;
80
+ }
81
+
82
+ // src/lib/compiler/ide/ide-output.ts
83
+ import { mkdtemp, rename, rm, symlink, unlink } from "fs/promises";
84
+ import { basename, dirname, join } from "path";
85
+ var IDE_CLEANUP_TIMEOUT_MS = 3e4;
86
+ async function cleanupIdeFiles({
87
+ cleanup,
88
+ label
89
+ }) {
90
+ let timer;
91
+ try {
92
+ await Promise.race([
93
+ cleanup(),
94
+ new Promise((_resolve, reject) => {
95
+ timer = setTimeout(
96
+ () => reject(
97
+ new AppError({
98
+ code: "IDE_CLEANUP_TIMEOUT",
99
+ message: `${label} did not finish within ${IDE_CLEANUP_TIMEOUT_MS} ms.`,
100
+ fix: "Stop and verify owned processes before you recover the retained IDE files."
101
+ })
102
+ ),
103
+ IDE_CLEANUP_TIMEOUT_MS
104
+ );
105
+ })
106
+ ]);
107
+ } finally {
108
+ clearTimeout(timer);
109
+ }
110
+ }
111
+ async function withIdeOutput({
112
+ outputDir,
113
+ assertOutputCurrent,
114
+ run,
115
+ assertReadyToCommit,
116
+ onCleanupError,
117
+ reuseDependencies
118
+ }) {
119
+ let parent = dirname(outputDir);
120
+ await assertOutputCurrent();
121
+ let stage = await mkdtemp(join(parent, `.${basename(outputDir)}.tmp-`)), stageIdentity = await assertLocalDirectory(stage), assertStageCurrent = async () => {
122
+ await assertOutputCurrent(), await assertLocalDirectory(stage, stageIdentity);
123
+ }, backup = `${stage}.previous`, previous = !1, replaced = !1, dependenciesMoved = !1, backupIdentity;
124
+ try {
125
+ reuseDependencies && await symlink(
126
+ join(outputDir, "node_modules"),
127
+ join(stage, "node_modules"),
128
+ process.platform === "win32" ? "junction" : "dir"
129
+ ), await run(stage, assertStageCurrent), await assertStageCurrent(), await assertReadyToCommit(), await assertStageCurrent();
130
+ try {
131
+ await rename(outputDir, backup), previous = !0, backupIdentity = await assertLocalDirectory(backup);
132
+ } catch (error) {
133
+ if (reuseDependencies || error.code !== "ENOENT")
134
+ throw error;
135
+ }
136
+ try {
137
+ await assertStageCurrent(), reuseDependencies && (await unlink(join(stage, "node_modules")), await assertLocalDirectory(backup, backupIdentity), await rename(join(backup, "node_modules"), join(stage, "node_modules")), dependenciesMoved = !0), await rename(stage, outputDir), replaced = !0;
138
+ } catch (error) {
139
+ if (previous)
140
+ try {
141
+ await assertOutputCurrent(), await assertLocalDirectory(backup, backupIdentity), dependenciesMoved && await rename(
142
+ join(stage, "node_modules"),
143
+ join(backup, "node_modules")
144
+ ), await rename(backup, outputDir);
145
+ } catch (rollbackError) {
146
+ throw new AppError({
147
+ code: "IDE_ROLLBACK_FAILED",
148
+ message: `IDE output replacement failed. Previous output remains at ${backup}.`,
149
+ fix: "Restore the previous IDE output after all command processes stop.",
150
+ details: { error, rollbackError }
151
+ });
152
+ }
153
+ throw error;
154
+ }
155
+ } catch (error) {
156
+ if (error instanceof AppError && ["FRAMEWORK_PROCESS_SHUTDOWN_FAILED", "IDE_ROLLBACK_FAILED"].includes(
157
+ error.code
158
+ ))
159
+ throw error;
160
+ try {
161
+ await cleanupIdeFiles({
162
+ cleanup: async () => {
163
+ await assertStageCurrent(), await rm(stage, { recursive: !0, force: !0 });
164
+ },
165
+ label: "Temporary IDE output cleanup"
166
+ });
167
+ } catch (cleanupError) {
168
+ onCleanupError(cleanupError);
169
+ }
170
+ throw error;
171
+ }
172
+ if (previous && replaced)
173
+ try {
174
+ await cleanupIdeFiles({
175
+ cleanup: async () => {
176
+ await assertOutputCurrent(), await assertLocalDirectory(backup, backupIdentity), await rm(backup, { recursive: !0, force: !0 });
177
+ },
178
+ label: "Previous IDE output cleanup"
179
+ });
180
+ } catch (cleanupError) {
181
+ onCleanupError(cleanupError);
182
+ }
183
+ }
184
+
185
+ // src/lib/compiler/ide/ide-support.ts
186
+ var IDE_SCHEMA_VERSION = 1, IDE_TSCONFIG = `${JSON.stringify(
187
+ { extends: "./.publish.os/ide/tsconfig.json" },
188
+ null,
189
+ 2
190
+ )}
191
+ `, IDE_LOCK_TIMEOUT_MS = 3e4, IDE_LOCK_RETRY_MS = 50, IDE_RELEASE_GRAPH_FILES = [
192
+ "framework.tgz",
193
+ "package.json",
194
+ "pnpm-lock.yaml",
195
+ "pnpm-workspace.yaml"
196
+ ], IDE_GENERATED_FILES = [
197
+ ...IDE_RELEASE_GRAPH_FILES,
198
+ "tsconfig.json",
199
+ "source/.publishos/media-manifest.generated.ts",
200
+ "source/.publishos/icons.generated.tsx"
201
+ ], require2 = createRequire(import.meta.url);
202
+ function portableIdeTsconfig() {
203
+ return IDE_TSCONFIG;
204
+ }
205
+ function ideDir(publishOsDir) {
206
+ return resolve(publishOsDir, ".publish.os", "ide");
207
+ }
208
+ function posixPath(path) {
209
+ return path.split(sep).join("/");
210
+ }
211
+ function relativeIdePath(ideRoot, path) {
212
+ let value = posixPath(relative(ideRoot, path));
213
+ return value.startsWith(".") ? value : `./${value}`;
214
+ }
215
+ function fileHash(value) {
216
+ return createHash("sha256").update(value).digest("hex");
217
+ }
218
+ function isMissing(error) {
219
+ return typeof error == "object" && error !== null && "code" in error && error.code === "ENOENT";
220
+ }
221
+ async function readOptional(path) {
222
+ try {
223
+ return await readFile(path, "utf8");
224
+ } catch (error) {
225
+ if (isMissing(error)) return;
226
+ throw error;
227
+ }
228
+ }
229
+ async function readOptionalBytes(path) {
230
+ try {
231
+ return await readFile(path);
232
+ } catch (error) {
233
+ if (isMissing(error)) return;
234
+ throw error;
235
+ }
236
+ }
237
+ async function exists(path) {
238
+ return await stat(path).then(() => !0).catch((error) => {
239
+ if (isMissing(error)) return !1;
240
+ throw error;
241
+ });
242
+ }
243
+ function sourceRuntimeVersion(runtime) {
244
+ let version = runtimePackageVersion(runtime);
245
+ if (version === void 0)
246
+ throw new AppError({
247
+ code: "IDE_SOURCE_SELECTION_INVALID",
248
+ fix: 'Set runtime to "@publish.os/nextjs@<exact-version>" in publish.os.config.json. Use the exact framework version for this source.',
249
+ message: "IDE support could not read the current runtime pin."
250
+ });
251
+ return version;
252
+ }
253
+ async function sourceSelection(publishOsDir) {
254
+ let document;
255
+ try {
256
+ document = JSON.parse(
257
+ await readFile(resolve(publishOsDir, "publish.os.config.json"), "utf8")
258
+ );
259
+ } catch {
260
+ throw new AppError({
261
+ code: "IDE_SOURCE_SELECTION_INVALID",
262
+ fix: "Restore publish.os.config.json, then run publish.os init again.",
263
+ message: "IDE support could not read the current source selection."
264
+ });
265
+ }
266
+ return { runtimeVersion: sourceRuntimeVersion(document?.runtime) };
267
+ }
268
+ function assertSelectionCurrent(options) {
269
+ if (options.actual.runtimeVersion !== options.expected.runtimeVersion)
270
+ throw new AppError({
271
+ code: "IDE_SELECTION_STALE",
272
+ fix: "Run publish.os init again after the source change is complete.",
273
+ message: "The source runtime pin changed while IDE support was being prepared."
274
+ });
275
+ }
276
+ async function acquireIdeLock(options) {
277
+ let legacyLock = resolve(options.publishOsDir, ".publish.os", ".ide-lock"), deadline = Date.now() + IDE_LOCK_TIMEOUT_MS;
278
+ for (; ; ) {
279
+ options.signal.throwIfAborted(), await options.assertCurrent();
280
+ try {
281
+ if (!await lstat(legacyLock).then(
282
+ () => !0,
283
+ (error) => {
284
+ if (isMissing(error)) return !1;
285
+ throw error;
286
+ }
287
+ ))
288
+ return await acquireOperationLock({
289
+ sourceRoot: options.publishOsDir,
290
+ outputRoot: join2(options.publishOsDir, ".publish.os"),
291
+ operation: "ide",
292
+ signal: options.signal
293
+ });
294
+ } catch (error) {
295
+ if (!(error instanceof AppError)) throw error;
296
+ if (error.code !== "FRAMEWORK_LOCAL_OPERATION_ACTIVE")
297
+ throw new AppError({
298
+ code: "IDE_PREPARATION_PROTECTED",
299
+ message: `IDE preparation cannot verify the lock owner for ${options.publishOsDir}.`,
300
+ fix: `Inspect ${join2(options.publishOsDir, ".publish.os", ".locks", "ide")} and its recorded owner. Retry only after ownership and process shutdown can be verified; leave uncertain locks and source in place.`,
301
+ details: { sourceRoot: options.publishOsDir, causeCode: error.code }
302
+ });
303
+ }
304
+ if (Date.now() >= deadline)
305
+ throw new AppError({
306
+ code: "IDE_PREPARATION_BUSY",
307
+ fix: `Wait for the IDE preparation owner of ${options.publishOsDir} to finish, then retry. If the legacy lock ${legacyLock} remains, inspect its owner before recovering it.`,
308
+ message: `IDE support is already being prepared for ${options.publishOsDir}.`,
309
+ details: { sourceRoot: options.publishOsDir }
310
+ });
311
+ await new Promise((resolve2) => setTimeout(resolve2, IDE_LOCK_RETRY_MS)), options.signal.throwIfAborted();
312
+ }
313
+ }
314
+ function readIdeMetadata(source) {
315
+ if (source)
316
+ try {
317
+ let value = JSON.parse(source), files = value.files, selection = value.selection;
318
+ return value.schemaVersion !== IDE_SCHEMA_VERSION || !files || typeof files != "object" || Array.isArray(files) || ![
319
+ "tsconfig.json",
320
+ "source/.publishos/media-manifest.generated.ts",
321
+ ...IDE_RELEASE_GRAPH_FILES.filter(
322
+ (path) => path !== "framework.tgz" || selection?.inputKind !== "checkout"
323
+ )
324
+ ].every((path) => Object.hasOwn(files, path)) || Object.entries(files).some(
325
+ ([path, hash]) => !IDE_GENERATED_FILES.includes(path) || typeof hash != "string" || !/^[a-f0-9]{64}$/.test(hash)
326
+ ) || !selection || typeof selection.runtimeVersion != "string" || runtimePackageVersion(
327
+ `@publish.os/nextjs@${selection.runtimeVersion}`
328
+ ) === void 0 || selection.inputKind !== void 0 && !["customer", "checkout", "candidate"].includes(selection.inputKind) || (selection.integrity === void 0 ? selection.inputKind !== void 0 : typeof selection.integrity != "string" || !(selection.inputKind === "checkout" ? /^checkout:[a-f0-9]{64}$/u : /^sha512-[A-Za-z0-9+/]{86}==$/u).test(selection.integrity)) ? void 0 : value;
329
+ } catch {
330
+ return;
331
+ }
332
+ }
333
+ async function assertGeneratedIdeOutputUnchanged(options) {
334
+ let metadataSource = await readOptional(
335
+ join2(options.ideRoot, "metadata.json")
336
+ );
337
+ if (!metadataSource) {
338
+ if (await exists(options.ideRoot))
339
+ throw new AppError({
340
+ code: "IDE_OUTPUT_UNRECOGNIZED",
341
+ fix: `Inspect ${options.ideRoot} and preserve its custom files. Retry IDE preparation only after its generated ownership can be verified.`,
342
+ message: `IDE support found unrecognized output at ${options.ideRoot}.`
343
+ });
344
+ return;
345
+ }
346
+ let metadata = readIdeMetadata(metadataSource);
347
+ if (!metadata)
348
+ throw new AppError({
349
+ code: "IDE_OUTPUT_UNRECOGNIZED",
350
+ fix: `Inspect and restore recognized metadata at ${join2(options.ideRoot, "metadata.json")}, then retry. Preserve custom files and source.`,
351
+ message: `IDE support metadata is invalid at ${options.ideRoot}.`
352
+ });
353
+ let generatedFiles = /* @__PURE__ */ new Set([...IDE_GENERATED_FILES, "metadata.json"]), generatedDirectories = /* @__PURE__ */ new Set(["source", "source/.publishos"]), inspect = async (parent) => {
354
+ for (let entry of await readdir(join2(options.ideRoot, parent), {
355
+ withFileTypes: !0
356
+ })) {
357
+ let path = parent ? `${parent}/${entry.name}` : entry.name;
358
+ if (!(["node_modules", ".pnpm-store"].includes(path) && entry.isDirectory()) && !(generatedFiles.has(path) && entry.isFile())) {
359
+ if (generatedDirectories.has(path) && entry.isDirectory()) {
360
+ await inspect(path);
361
+ continue;
362
+ }
363
+ throw new AppError({
364
+ code: "IDE_OUTPUT_UNRECOGNIZED",
365
+ message: `IDE support found an unknown or redirected entry at ${join2(options.ideRoot, path)}.`,
366
+ fix: `Preserve custom files at ${options.ideRoot} and inspect their ownership before retrying IDE preparation.`
367
+ });
368
+ }
369
+ }
370
+ };
371
+ await inspect("");
372
+ let complete = !0;
373
+ for (let [path, expectedHash] of Object.entries(metadata.files)) {
374
+ let source = await readOptionalBytes(join2(options.ideRoot, path));
375
+ if (!source) {
376
+ complete = !1;
377
+ continue;
378
+ }
379
+ if (fileHash(source) !== expectedHash)
380
+ throw new AppError({
381
+ code: "IDE_OUTPUT_MODIFIED",
382
+ fix: `Inspect and restore the generated files at ${options.ideRoot}, then retry IDE preparation. Preserve custom files and source.`,
383
+ message: `PublishOS will not replace modified IDE output at ${options.ideRoot}.`
384
+ });
385
+ }
386
+ return { metadata, complete };
387
+ }
388
+ async function assertPortableIdeConfig(publishOsDir) {
389
+ let path = resolve(publishOsDir, "tsconfig.json"), source = await readOptional(path);
390
+ if (source === void 0) return "missing";
391
+ let parsed = parseConfigFileTextToJson(path, source), bases = Array.isArray(parsed.config?.extends) ? parsed.config.extends : [parsed.config?.extends];
392
+ if (!parsed.error && bases.some((base) => {
393
+ if (typeof base != "string" || !base.startsWith(".")) return !1;
394
+ let target = resolve(publishOsDir, base), generated = join2(ideDir(publishOsDir), "tsconfig.json");
395
+ return target === generated || `${target}.json` === generated;
396
+ }))
397
+ return "present";
398
+ throw new AppError({
399
+ code: "IDE_TSCONFIG_INCOMPATIBLE",
400
+ fix: `Set extends to "./.publish.os/ide/tsconfig.json" in ${path}, then retry IDE preparation.`,
401
+ message: `${path} must extend the generated IDE configuration. Custom source configuration was not replaced.`,
402
+ details: { sourceRoot: publishOsDir }
403
+ });
404
+ }
405
+ async function writePortableIdeConfig(options) {
406
+ let target = resolve(options.publishOsDir, "tsconfig.json"), temporary = `${target}.publishos-tmp-${process.pid}-${randomUUID()}`;
407
+ await options.assertCurrent(), await writeFile(temporary, portableIdeTsconfig(), { flag: "wx" });
408
+ try {
409
+ try {
410
+ return await options.assertCurrent(), await link(temporary, target), !0;
411
+ } catch (error) {
412
+ if (typeof error == "object" && error !== null && "code" in error && error.code === "EEXIST") {
413
+ if (await assertPortableIdeConfig(options.publishOsDir) === "missing")
414
+ throw new AppError({
415
+ code: "IDE_TSCONFIG_CHANGED",
416
+ fix: "Run publish.os init again after the source change is complete.",
417
+ message: "publish.os/tsconfig.json changed while IDE support was being prepared."
418
+ });
419
+ return !1;
420
+ }
421
+ throw error;
422
+ }
423
+ } finally {
424
+ try {
425
+ await cleanupIdeFiles({
426
+ cleanup: async () => {
427
+ await options.assertCurrent(), await rm2(temporary, { force: !0 });
428
+ },
429
+ label: "Temporary IDE configuration cleanup"
430
+ });
431
+ } catch {
432
+ options.warn(
433
+ "Could not remove a temporary IDE configuration file. Remove publish.os/tsconfig.json.publishos-tmp-* after this command finishes."
434
+ );
435
+ }
436
+ }
437
+ }
438
+ async function removePortableIdeConfigIfUnchanged(publishOsDir) {
439
+ let target = resolve(publishOsDir, "tsconfig.json");
440
+ await readOptional(target) === portableIdeTsconfig() && await rm2(target, { force: !0 });
441
+ }
442
+ async function assertIdeStateCurrent(options) {
443
+ let [rootConfig] = await Promise.all([
444
+ assertPortableIdeConfig(options.publishOsDir),
445
+ assertGeneratedIdeOutputUnchanged({ ideRoot: options.target })
446
+ ]);
447
+ if (rootConfig === "missing" && options.expectedRootConfig !== "missing")
448
+ throw new AppError({
449
+ code: "IDE_TSCONFIG_CHANGED",
450
+ fix: "Run publish.os init again after the source change is complete.",
451
+ message: "publish.os/tsconfig.json changed while IDE support was being prepared."
452
+ });
453
+ if (Object.hasOwn(options, "expectedRootConfigSource") && await readOptional(join2(options.publishOsDir, "tsconfig.json")) !== options.expectedRootConfigSource)
454
+ throw new AppError({
455
+ code: "IDE_TSCONFIG_CHANGED",
456
+ fix: "Run publish.os init again after the source change is complete.",
457
+ message: "The authored TypeScript configuration changed after IDE verification."
458
+ });
459
+ assertSelectionCurrent({
460
+ actual: await sourceSelection(options.publishOsDir),
461
+ expected: options.expectedSelection
462
+ });
463
+ }
464
+ async function packageTypePath(options) {
465
+ let packageName = options.specifier.split("/").slice(0, options.specifier.startsWith("@") ? 2 : 1).join("/"), packageRoot = join2(options.ideRoot, "node_modules", packageName);
466
+ try {
467
+ JSON.parse(await readFile(join2(packageRoot, "package.json"), "utf8"));
468
+ } catch {
469
+ throw new AppError({
470
+ code: "IDE_PACKAGE_MANIFEST_INVALID",
471
+ fix: "Run publish.os init again. If this continues, update the selected framework.",
472
+ message: `IDE support could not read ${options.specifier} package metadata.`
473
+ });
474
+ }
475
+ let resolved = options.typescript.resolveModuleName(
476
+ options.specifier,
477
+ join2(options.ideRoot, "source-check.tsx"),
478
+ {
479
+ module: options.typescript.ModuleKind.ESNext,
480
+ moduleResolution: options.typescript.ModuleResolutionKind.Bundler,
481
+ preserveSymlinks: !0
482
+ },
483
+ options.typescript.sys
484
+ ).resolvedModule;
485
+ if (!resolved || !/\.d\.[cm]?ts$/.test(resolved.resolvedFileName) || relativeIdePath(options.ideRoot, resolved.resolvedFileName).startsWith(
486
+ "../"
487
+ ))
488
+ throw new AppError({
489
+ code: "IDE_DECLARATION_MISSING",
490
+ fix: "Run publish.os init again. If this continues, update the selected framework.",
491
+ message: `The selected framework is missing types for ${options.specifier}.`
492
+ });
493
+ return relativeIdePath(options.ideRoot, resolved.resolvedFileName);
494
+ }
495
+ async function sourceImportPaths(options) {
496
+ let checkoutRoot = options.checkoutRoot, paths = {}, checkoutPaths = checkoutRoot ? (await readCheckoutTypeScriptConfig({ packageRoot: checkoutRoot })).paths : void 0, typescript = typescriptApi(options.ideRoot);
497
+ for (let specifier of supportedNextjsSourceImports()) {
498
+ if (options.checkoutRoot && (specifier === "@publish.os/nextjs" || specifier.startsWith("@publish.os/nextjs/"))) {
499
+ let source = checkoutPaths?.[specifier]?.[0];
500
+ if (!source)
501
+ throw new AppError({
502
+ code: "IDE_DECLARATION_MISSING",
503
+ message: `The selected checkout is missing the source entry for ${specifier}.`,
504
+ fix: "Select a complete framework checkout and repeat IDE preparation."
505
+ });
506
+ paths[specifier] = [posixPath(join2(options.checkoutRoot, source))];
507
+ continue;
508
+ }
509
+ paths[specifier] = [
510
+ await packageTypePath({
511
+ ideRoot: options.ideRoot,
512
+ specifier,
513
+ typescript
514
+ })
515
+ ];
516
+ }
517
+ if (checkoutRoot) {
518
+ paths["@/*"] = [posixPath(join2(checkoutRoot, "src/*"))];
519
+ for (let [specifier, sources] of Object.entries(checkoutPaths ?? {}))
520
+ specifier.startsWith("@components/") && (paths[specifier] = [
521
+ posixPath(
522
+ join2(
523
+ options.publishOsDir,
524
+ "components",
525
+ specifier.slice(12)
526
+ )
527
+ ),
528
+ ...sources.map((source) => posixPath(join2(checkoutRoot, source)))
529
+ ]);
530
+ }
531
+ return paths;
532
+ }
533
+ async function ideTsconfig(options) {
534
+ let frameworkComponents = join2(
535
+ options.ideRoot,
536
+ "node_modules",
537
+ "@publish.os",
538
+ "nextjs",
539
+ "dist",
540
+ "kernel",
541
+ "components",
542
+ "*"
543
+ ), paths = await sourceImportPaths({
544
+ ideRoot: options.ideRoot,
545
+ checkoutRoot: options.checkoutRoot,
546
+ publishOsDir: options.publishOsDir
547
+ });
548
+ return paths["@components/*"] = [
549
+ posixPath(resolve(options.publishOsDir, "components", "*")),
550
+ relativeIdePath(options.ideRoot, frameworkComponents)
551
+ ], paths["@source/*"] = [
552
+ posixPath(resolve(options.publishOsDir, "*")),
553
+ "./source/*"
554
+ ], `${JSON.stringify(
555
+ {
556
+ compilerOptions: {
557
+ allowJs: !0,
558
+ baseUrl: ".",
559
+ esModuleInterop: !0,
560
+ isolatedModules: !0,
561
+ jsx: "react-jsx",
562
+ lib: ["dom", "dom.iterable", "esnext"],
563
+ module: "esnext",
564
+ moduleResolution: "bundler",
565
+ noEmit: !0,
566
+ paths,
567
+ resolveJsonModule: !0,
568
+ skipLibCheck: !0,
569
+ strict: !0,
570
+ target: "ES2022",
571
+ typeRoots: ["./node_modules/@types"]
572
+ },
573
+ exclude: [
574
+ posixPath(resolve(options.publishOsDir, ".publish.os", "**/*"))
575
+ ],
576
+ include: [posixPath(resolve(options.publishOsDir, "**/*"))]
577
+ },
578
+ null,
579
+ 2
580
+ )}
581
+ `;
582
+ }
583
+ async function assertIdeDependencies(options) {
584
+ let required = [
585
+ join2(
586
+ options.ideRoot,
587
+ "node_modules",
588
+ "@publish.os",
589
+ "nextjs",
590
+ "package.json"
591
+ ),
592
+ join2(
593
+ options.ideRoot,
594
+ "node_modules",
595
+ "@phosphor-icons",
596
+ "react",
597
+ "package.json"
598
+ ),
599
+ join2(options.ideRoot, "node_modules", "typescript", "lib", "typescript.js"),
600
+ join2(options.ideRoot, "node_modules", "@types", "react", "index.d.ts")
601
+ ];
602
+ if (!(await Promise.all(required.map(exists))).every(Boolean))
603
+ throw new AppError({
604
+ code: "IDE_DEPENDENCIES_MISSING",
605
+ fix: "Run publish.os init again. If this continues, update the selected framework.",
606
+ message: "The selected framework app dependencies are incomplete."
607
+ });
608
+ }
609
+ function typescriptApi(ideRoot) {
610
+ try {
611
+ return require2(
612
+ join2(ideRoot, "node_modules", "typescript", "lib", "typescript.js")
613
+ );
614
+ } catch {
615
+ throw new AppError({
616
+ code: "IDE_TYPESCRIPT_MISSING",
617
+ fix: "Run publish.os init again. If this continues, update the selected framework.",
618
+ message: "The selected framework does not provide TypeScript for IDE support."
619
+ });
620
+ }
621
+ }
622
+ function assertResolvedModule(options) {
623
+ let file = options.typescript.resolveModuleName(
624
+ options.specifier,
625
+ join2(options.sourceRoot, "source-check.tsx"),
626
+ options.compilerOptions,
627
+ options.host
628
+ ).resolvedModule?.resolvedFileName;
629
+ if (file && /\.[cm]?tsx?$/u.test(file)) {
630
+ let local = relative(options.ideRoot, file);
631
+ if (!isAbsolute(local) && local !== ".." && !local.startsWith(`..${sep}`))
632
+ return;
633
+ if (options.specifier.startsWith("@components/") || options.specifier.startsWith("@source/") || options.specifier === "@publish.os/nextjs" || options.specifier.startsWith("@publish.os/nextjs/"))
634
+ for (let [alias, paths] of Object.entries(
635
+ options.compilerOptions.paths ?? {}
636
+ )) {
637
+ let [prefix = "", suffix] = alias.split("*");
638
+ if (suffix === void 0 ? alias !== options.specifier : !options.specifier.startsWith(prefix) || !options.specifier.endsWith(suffix))
639
+ continue;
640
+ let wildcard = options.specifier.slice(
641
+ prefix.length,
642
+ suffix ? -suffix.length : void 0
643
+ );
644
+ for (let path of paths) {
645
+ let target = resolve(
646
+ options.compilerOptions.baseUrl ?? options.ideRoot,
647
+ path.replace("*", wildcard)
648
+ );
649
+ if (file === target || file.replace(/(?:\.d)?\.[cm]?tsx?$/u, "") === target || file.replace(/[/\\]index(?:\.d)?\.[cm]?tsx?$/u, "") === target)
650
+ return;
651
+ }
652
+ }
653
+ }
654
+ throw new AppError({
655
+ code: "IDE_DECLARATION_UNRESOLVED",
656
+ fix: "Run publish.os init again. If this continues, update the selected framework.",
657
+ message: `IDE support could not resolve ${options.specifier}.`
658
+ });
659
+ }
660
+ async function verifyIdeConfiguration(options) {
661
+ let typescript = typescriptApi(options.ideRoot), finalIdeRoot = ideDir(options.finalPublishOsDir), rootConfigPath = join2(options.finalPublishOsDir, "tsconfig.json"), rootConfigSource = await readOptional(
662
+ join2(options.publishOsDir, "tsconfig.json")
663
+ ), authoredConfig = rootConfigSource ?? portableIdeTsconfig(), replaceRoot = (path, from, to) => {
664
+ let suffix = relative(from, path);
665
+ return suffix === "" || !isAbsolute(suffix) && !suffix.startsWith(`..${sep}`) && suffix !== ".." ? join2(to, suffix) : void 0;
666
+ }, stagedPath = (path) => replaceRoot(path, finalIdeRoot, options.ideRoot) ?? replaceRoot(path, options.finalPublishOsDir, options.publishOsDir) ?? path, finalPath = (path) => replaceRoot(path, options.ideRoot, finalIdeRoot) ?? replaceRoot(path, options.publishOsDir, options.finalPublishOsDir) ?? path, host = {
667
+ ...typescript.sys,
668
+ fileExists: (path) => path === rootConfigPath || typescript.sys.fileExists(stagedPath(path)),
669
+ directoryExists: (path) => typescript.sys.directoryExists(stagedPath(path)),
670
+ readFile: (path) => path === rootConfigPath ? authoredConfig : typescript.sys.readFile(stagedPath(path)),
671
+ readDirectory: (path, extensions, excludes, includes, depth) => typescript.sys.readDirectory(
672
+ stagedPath(path),
673
+ extensions,
674
+ excludes?.map(stagedPath),
675
+ includes?.map(stagedPath),
676
+ depth
677
+ ).map(finalPath),
678
+ getDirectories: (path) => typescript.sys.getDirectories(stagedPath(path)).map(finalPath),
679
+ realpath: (path) => path
680
+ }, configPath = join2(finalIdeRoot, "tsconfig.json"), read = typescript.readConfigFile(configPath, host.readFile);
681
+ if (read.error || !read.config)
682
+ throw new AppError({
683
+ code: "IDE_CONFIG_INVALID",
684
+ fix: "Run publish.os init again. If this continues, update the selected framework.",
685
+ message: "PublishOS could not read the generated IDE configuration."
686
+ });
687
+ let parsed = typescript.parseJsonConfigFileContent(
688
+ read.config,
689
+ host,
690
+ finalIdeRoot
691
+ ), authored = typescript.readConfigFile(rootConfigPath, host.readFile), project = typescript.parseJsonConfigFileContent(
692
+ authored.config,
693
+ host,
694
+ options.finalPublishOsDir
695
+ ), incompatible = (edit) => {
696
+ throw new AppError({
697
+ code: "IDE_TSCONFIG_INCOMPATIBLE",
698
+ fix: `${edit} in ${rootConfigPath}, then retry IDE preparation.`,
699
+ message: `The authored TypeScript configuration at ${rootConfigPath} does not preserve IDE support. Custom source configuration was not replaced.`,
700
+ details: { sourceRoot: options.publishOsDir }
701
+ });
702
+ };
703
+ for (let [specifier, paths] of Object.entries(parsed.options.paths ?? {})) {
704
+ let expected = paths.map(
705
+ (path) => resolve(parsed.options.baseUrl ?? finalIdeRoot, path)
706
+ ), actual = project.options.paths?.[specifier]?.map(
707
+ (path) => resolve(project.options.baseUrl ?? options.finalPublishOsDir, path)
708
+ );
709
+ if (!isDeepStrictEqual(actual, expected)) {
710
+ let override = Object.hasOwn(
711
+ authored.config.compilerOptions ?? {},
712
+ "paths"
713
+ ) ? "paths" : "baseUrl";
714
+ incompatible(
715
+ `Remove the compilerOptions.${override} override to restore ${specifier}`
716
+ );
717
+ }
718
+ }
719
+ if (parsed.fileNames.some((path) => !project.fileNames.includes(path))) {
720
+ let fields = ["files", "include", "exclude"].filter(
721
+ (field) => Object.hasOwn(authored.config, field)
722
+ );
723
+ incompatible(
724
+ `Remove the ${fields.join(", ")} overrides to include all authored files`
725
+ );
726
+ }
727
+ let configurationErrors = project.errors.filter(
728
+ (diagnostic) => diagnostic.code !== 18003 || parsed.fileNames.length > 0
729
+ );
730
+ if (authored.error || configurationErrors.length > 0) {
731
+ let diagnostic = authored.error ?? configurationErrors[0];
732
+ incompatible(
733
+ `Correct the TypeScript configuration error: ${typescript.flattenDiagnosticMessageText(diagnostic?.messageText ?? "Invalid configuration", " ")}`
734
+ );
735
+ }
736
+ for (let specifier of [
737
+ "react",
738
+ "react/jsx-runtime",
739
+ "next/link",
740
+ "@components/blocks/navbar",
741
+ ...supportedNextjsSourceImports()
742
+ ])
743
+ assertResolvedModule({
744
+ compilerOptions: project.options,
745
+ host,
746
+ ideRoot: finalIdeRoot,
747
+ sourceRoot: options.finalPublishOsDir,
748
+ specifier,
749
+ typescript
750
+ });
751
+ return { rootConfigSource };
752
+ }
753
+ async function copyReleaseGraph(options) {
754
+ let archive = options.frameworkOptions.request.context?.archive;
755
+ if (!archive && options.frameworkOptions.request.context?.framework?.kind !== "checkout")
756
+ throw new AppError({
757
+ code: "IDE_RELEASE_ARCHIVE_MISSING",
758
+ fix: "Use the exact selected framework archive, then run publish.os init again.",
759
+ message: "IDE support needs the selected framework archive."
760
+ });
761
+ let plan = await prepareAppInstallation({
762
+ archivePath: archive?.path,
763
+ archiveIntegrity: archive?.integrity,
764
+ framework: options.frameworkOptions.request.context?.framework
765
+ });
766
+ await materializeAppInstallation({
767
+ plan,
768
+ outputDir: options.ideRoot,
769
+ signal: options.frameworkOptions.signal
770
+ });
771
+ }
772
+ async function writeIdeFiles(options) {
773
+ let artifacts = await createIdeSourceArtifacts({
774
+ mediaManifest: options.source.assets.media.manifest
775
+ }), config = await ideTsconfig({
776
+ ideRoot: options.ideRoot,
777
+ publishOsDir: options.finalPublishOsDir,
778
+ checkoutRoot: options.checkoutRoot
779
+ }), files = {
780
+ "source/.publishos/media-manifest.generated.ts": artifacts.mediaModule,
781
+ "tsconfig.json": config
782
+ };
783
+ return await Promise.all(
784
+ Object.entries(files).map(async ([path, source]) => {
785
+ let destination = join2(options.ideRoot, path);
786
+ await mkdir(dirname2(destination), { recursive: !0 }), await writeFile(destination, source);
787
+ })
788
+ ), {
789
+ files: Object.fromEntries(
790
+ Object.entries(files).map(([path, source]) => [path, fileHash(source)])
791
+ ),
792
+ schemaVersion: IDE_SCHEMA_VERSION,
793
+ selection: options.selection
794
+ };
795
+ }
796
+ async function releaseGraphFileHashes(ideRoot, selection) {
797
+ let hashes = {};
798
+ for (let path of IDE_RELEASE_GRAPH_FILES) {
799
+ if (path === "framework.tgz" && selection.inputKind === "checkout")
800
+ continue;
801
+ let source = await readOptionalBytes(join2(ideRoot, path));
802
+ if (!source)
803
+ throw new AppError({
804
+ code: "IDE_RELEASE_GRAPH_INVALID",
805
+ fix: "Run publish.os init again. If this continues, update the selected framework.",
806
+ message: `IDE support is missing generated ${path}.`
807
+ });
808
+ hashes[path] = fileHash(source);
809
+ }
810
+ return hashes;
811
+ }
812
+ async function copyExistingIdeOutput(options) {
813
+ let entries = (await readdir(options.ideRoot)).filter(
814
+ (entry) => entry !== "node_modules"
815
+ );
816
+ await Promise.all(
817
+ entries.map(
818
+ async (entry) => await cp(join2(options.ideRoot, entry), join2(options.stageRoot, entry), {
819
+ force: !0,
820
+ recursive: !0
821
+ })
822
+ )
823
+ );
824
+ }
825
+ async function canonicalSourceLocation(path) {
826
+ let parent = dirname2(path), canonicalParent = await realpath(parent).catch(
827
+ async (error) => {
828
+ if (error.code !== "ENOENT") throw error;
829
+ return await canonicalSourceLocation(parent);
830
+ }
831
+ );
832
+ return join2(canonicalParent, basename2(path));
833
+ }
834
+ async function prepareIdeSupport(input) {
835
+ let requestedFinalLocation = input.finalPublishOsDir ?? input.publishOsDir;
836
+ if (!isAbsolute(requestedFinalLocation) || basename2(requestedFinalLocation) !== "publish.os" || requestedFinalLocation.split(sep).some((part) => [".publish.os", "node_modules", ".git"].includes(part)))
837
+ throw new AppError({
838
+ code: "IDE_FINAL_SOURCE_INVALID",
839
+ fix: "Choose an absolute source path whose final folder is publish.os, outside generated or dependency folders.",
840
+ message: "IDE support received an invalid final source location."
841
+ });
842
+ let options = {
843
+ ...input,
844
+ publishOsDir: await canonicalSourceLocation(input.publishOsDir)
845
+ }, finalPublishOsDir = await canonicalSourceLocation(
846
+ requestedFinalLocation
847
+ ), authoredSelection = await sourceSelection(options.publishOsDir);
848
+ typeof options.source != "function" && assertSelectionCurrent({
849
+ actual: authoredSelection,
850
+ expected: {
851
+ runtimeVersion: sourceRuntimeVersion(options.source.config.runtime)
852
+ }
853
+ });
854
+ let identity = await assertFrameworkSelection({
855
+ context: options.frameworkOptions.request.context,
856
+ framework: options.framework,
857
+ runtime: `@publish.os/nextjs@${authoredSelection.runtimeVersion}`
858
+ }), selection = {
859
+ runtimeVersion: options.framework.version,
860
+ inputKind: options.frameworkOptions.request.context?.framework?.kind ?? "customer",
861
+ integrity: identity
862
+ }, signal = options.frameworkOptions.signal ?? new AbortController().signal, throwIfInterrupted = () => signal.throwIfAborted(), warn = (message) => options.frameworkOptions.onEvent?.({
863
+ type: "diagnostics",
864
+ diagnostics: {
865
+ diagnostics: [
866
+ { code: "IDE_CLEANUP_WARNING", severity: "warning", message }
867
+ ]
868
+ }
869
+ }), releaseLock, lockIdentity, releaseLockError, retainInstallerState = !1, stagedIdeDirectory, ownership = await ensureOutputOwnership({
870
+ sourceRoot: options.publishOsDir,
871
+ ownerSourceRoot: finalPublishOsDir
872
+ }).catch((error) => {
873
+ throw !(error instanceof AppError) || ![
874
+ "FRAMEWORK_LOCAL_OUTPUT_OWNERSHIP",
875
+ "FRAMEWORK_LOCAL_OUTPUT_REDIRECTED"
876
+ ].includes(error.code) ? error : new AppError({
877
+ code: "IDE_PREPARATION_PROTECTED",
878
+ message: `IDE preparation cannot verify source-owned output for ${options.publishOsDir}.`,
879
+ fix: `Inspect ${join2(options.publishOsDir, ".publish.os")} ownership, including ${join2(options.publishOsDir, ".publish.os", ".ide-lock")} and ${join2(options.publishOsDir, ".publish.os", ".locks", "ide")}. Preserve redirected or uncertain entries until their ownership can be verified, then retry.`,
880
+ details: { sourceRoot: options.publishOsDir, causeCode: error.code }
881
+ });
882
+ }), lockDirectory = join2(ownership.outputRoot, ".locks", "ide");
883
+ try {
884
+ releaseLock = await acquireIdeLock({
885
+ assertCurrent: ownership.assertCurrent,
886
+ publishOsDir: options.publishOsDir,
887
+ signal
888
+ }), lockIdentity = await assertLocalDirectory(lockDirectory), throwIfInterrupted(), await ownership.assertCurrent();
889
+ let target = ideDir(options.publishOsDir), targetIdentity = await assertLocalDirectory(target).catch(
890
+ (error) => {
891
+ if (error.code !== "ENOENT") throw error;
892
+ }
893
+ ), assertTargetCurrent = async () => {
894
+ await ownership.assertCurrent(), targetIdentity && await assertLocalDirectory(target, targetIdentity);
895
+ }, [existingOutput, rootConfig] = await Promise.all([
896
+ assertGeneratedIdeOutputUnchanged({ ideRoot: target }),
897
+ assertPortableIdeConfig(options.publishOsDir)
898
+ ]), existingMetadata = existingOutput?.metadata, dependenciesReady = existingMetadata ? await assertIdeDependencies({ ideRoot: target }).then(
899
+ () => !0,
900
+ (error) => {
901
+ if (error instanceof AppError && error.code === "IDE_DEPENDENCIES_MISSING")
902
+ return !1;
903
+ throw error;
904
+ }
905
+ ) : !1, preserve = options.frameworkOptions.request.context?.ide?.policy === "preserve" && existingOutput?.complete === !0 && dependenciesReady, checkoutGraphUnchanged = !1;
906
+ if (!preserve && selection.inputKind === "checkout" && existingMetadata?.selection.inputKind === "checkout") {
907
+ let plan = await prepareAppInstallation({
908
+ framework: options.frameworkOptions.request.context?.framework
909
+ });
910
+ checkoutGraphUnchanged = (await Promise.all(
911
+ [
912
+ ["package.json", plan.files.packageJsonSource],
913
+ ["pnpm-workspace.yaml", plan.files.pnpmWorkspaceSource],
914
+ ["pnpm-lock.yaml", plan.files.lockfileSource]
915
+ ].map(
916
+ async ([path, contents]) => await readOptional(join2(target, path)) === contents
917
+ )
918
+ )).every(Boolean);
919
+ }
920
+ let reusable = existingOutput?.complete === !0 && existingMetadata?.selection.runtimeVersion === selection.runtimeVersion && existingMetadata.selection.inputKind === selection.inputKind && (existingMetadata.selection.integrity === selection.integrity || checkoutGraphUnchanged) && !Object.keys(existingMetadata.files).some(
921
+ (path) => path.endsWith("icons.generated.tsx")
922
+ ) && dependenciesReady;
923
+ if (preserve || reusable) {
924
+ let verified = await verifyIdeConfiguration({
925
+ ideRoot: target,
926
+ finalPublishOsDir,
927
+ publishOsDir: options.publishOsDir
928
+ }).catch((error) => {
929
+ if (error instanceof AppError && error.code === "IDE_DECLARATION_UNRESOLVED") {
930
+ reusable = !1;
931
+ return;
932
+ }
933
+ throw error;
934
+ });
935
+ if (verified && rootConfig === "present" && (preserve || typeof options.source == "function")) {
936
+ await assertTargetCurrent(), await assertIdeStateCurrent({
937
+ expectedRootConfig: rootConfig,
938
+ expectedRootConfigSource: verified.rootConfigSource,
939
+ expectedSelection: authoredSelection,
940
+ publishOsDir: options.publishOsDir,
941
+ target
942
+ }), throwIfInterrupted();
943
+ let release = releaseLock;
944
+ releaseLock = void 0, await cleanupIdeFiles({ cleanup: release, label: "IDE lock cleanup" });
945
+ return;
946
+ }
947
+ }
948
+ let source = typeof options.source == "function" ? await options.source() : options.source;
949
+ assertSelectionCurrent({
950
+ actual: await sourceSelection(options.publishOsDir),
951
+ expected: { runtimeVersion: sourceRuntimeVersion(source.config.runtime) }
952
+ }), reusable || options.frameworkOptions.onEvent?.({
953
+ type: "progress",
954
+ message: "Installing the selected framework app dependencies for IDE support..."
955
+ });
956
+ let wroteRootConfig = !1;
957
+ try {
958
+ await assertPortableIdeConfig(options.publishOsDir);
959
+ let stagedMetadata, verifiedConfiguration;
960
+ await withIdeOutput({
961
+ assertOutputCurrent: ownership.assertCurrent,
962
+ onCleanupError: () => {
963
+ warn(
964
+ "Could not remove temporary IDE output. The original error remains the command error."
965
+ );
966
+ },
967
+ outputDir: target,
968
+ reuseDependencies: reusable,
969
+ run: async (stageRoot, assertStageCurrent) => {
970
+ if (stagedIdeDirectory = stageRoot, await assertStageCurrent(), await assertTargetCurrent(), reusable)
971
+ await copyExistingIdeOutput({ ideRoot: target, stageRoot });
972
+ else {
973
+ await copyReleaseGraph({
974
+ ideRoot: stageRoot,
975
+ frameworkOptions: options.frameworkOptions,
976
+ selection
977
+ });
978
+ let expectedGraph = await releaseGraphFileHashes(
979
+ stageRoot,
980
+ selection
981
+ ), assertInstallGraph = async () => {
982
+ if (await assertStageCurrent(), await assertTargetCurrent(), !isDeepStrictEqual(
983
+ await releaseGraphFileHashes(stageRoot, selection),
984
+ expectedGraph
985
+ ))
986
+ throw new AppError({
987
+ code: "IDE_INSTALL_GRAPH_CHANGED",
988
+ message: "IDE installation changed the released dependency graph.",
989
+ fix: "Use the unchanged selected framework release. IDE output was not replaced."
990
+ });
991
+ };
992
+ await runIdeInstall({
993
+ outputDir: stageRoot,
994
+ framework: options.framework,
995
+ options: options.frameworkOptions,
996
+ assertInstallGraph: async () => {
997
+ await assertInstallGraph(), await assertPortableIdeConfig(options.publishOsDir);
998
+ }
999
+ }), throwIfInterrupted(), await assertInstallGraph();
1000
+ }
1001
+ await assertStageCurrent(), await assertTargetCurrent(), await assertIdeDependencies({
1002
+ ideRoot: stageRoot
1003
+ }), await assertStageCurrent(), stagedMetadata = await writeIdeFiles({
1004
+ finalPublishOsDir,
1005
+ ideRoot: stageRoot,
1006
+ publishOsDir: options.publishOsDir,
1007
+ selection,
1008
+ source,
1009
+ checkoutRoot: options.frameworkOptions.request.context?.framework?.kind === "checkout" ? options.framework.packageRoot : void 0
1010
+ }), await assertStageCurrent(), stagedMetadata.files = {
1011
+ ...await releaseGraphFileHashes(stageRoot, selection),
1012
+ ...stagedMetadata.files
1013
+ }, verifiedConfiguration = await verifyIdeConfiguration({
1014
+ ideRoot: stageRoot,
1015
+ finalPublishOsDir,
1016
+ publishOsDir: options.publishOsDir
1017
+ }), await assertStageCurrent(), await assertTargetCurrent(), await assertIdeStateCurrent({
1018
+ expectedRootConfig: rootConfig,
1019
+ expectedRootConfigSource: verifiedConfiguration.rootConfigSource,
1020
+ expectedSelection: authoredSelection,
1021
+ publishOsDir: options.publishOsDir,
1022
+ target
1023
+ }), throwIfInterrupted(), await assertStageCurrent(), await writeFile(
1024
+ join2(stageRoot, "metadata.json"),
1025
+ `${JSON.stringify(stagedMetadata, null, 2)}
1026
+ `
1027
+ );
1028
+ },
1029
+ assertReadyToCommit: async () => {
1030
+ await assertTargetCurrent(), await assertIdeStateCurrent({
1031
+ expectedRootConfig: rootConfig,
1032
+ expectedRootConfigSource: verifiedConfiguration?.rootConfigSource,
1033
+ expectedSelection: authoredSelection,
1034
+ publishOsDir: options.publishOsDir,
1035
+ target
1036
+ }), throwIfInterrupted(), rootConfig === "missing" && (wroteRootConfig = await writePortableIdeConfig({
1037
+ assertCurrent: ownership.assertCurrent,
1038
+ publishOsDir: options.publishOsDir,
1039
+ warn
1040
+ })), await assertTargetCurrent(), await assertIdeStateCurrent({
1041
+ expectedRootConfigSource: wroteRootConfig ? portableIdeTsconfig() : verifiedConfiguration?.rootConfigSource,
1042
+ expectedSelection: authoredSelection,
1043
+ publishOsDir: options.publishOsDir,
1044
+ target
1045
+ }), throwIfInterrupted();
1046
+ }
1047
+ });
1048
+ } catch (error) {
1049
+ if (isShutdownFailure(error)) {
1050
+ retainInstallerState = !0;
1051
+ try {
1052
+ await ownership.assertCurrent(), await assertLocalDirectory(lockDirectory, lockIdentity), await writeFile(
1053
+ join2(lockDirectory, "shutdown-unverified.json"),
1054
+ `${JSON.stringify({ stage: stagedIdeDirectory })}
1055
+ `,
1056
+ { flag: "wx" }
1057
+ );
1058
+ } catch {
1059
+ warn(
1060
+ "Could not mark the retained IDE lock as unverified. Inspect its installer descendants before recovering it."
1061
+ );
1062
+ }
1063
+ throw warn(
1064
+ `Could not confirm that the IDE installer stopped. Temporary files remain at ${stagedIdeDirectory}. The lock remains at ${lockDirectory}. Stop the installer and its child processes before you inspect these paths.`
1065
+ ), error;
1066
+ }
1067
+ if (wroteRootConfig)
1068
+ try {
1069
+ await cleanupIdeFiles({
1070
+ cleanup: async () => {
1071
+ await ownership.assertCurrent(), await removePortableIdeConfigIfUnchanged(options.publishOsDir);
1072
+ },
1073
+ label: "Generated IDE configuration rollback"
1074
+ });
1075
+ } catch {
1076
+ warn(
1077
+ "Could not remove generated TypeScript configuration after IDE preparation failed. The original error remains the command error."
1078
+ );
1079
+ }
1080
+ throw error;
1081
+ }
1082
+ } finally {
1083
+ try {
1084
+ releaseLock && !retainInstallerState && await cleanupIdeFiles({
1085
+ cleanup: releaseLock,
1086
+ label: "IDE lock cleanup"
1087
+ });
1088
+ } catch (error) {
1089
+ releaseLockError = error;
1090
+ }
1091
+ }
1092
+ if (releaseLockError) throw releaseLockError;
1093
+ }
1094
+ function isShutdownFailure(error) {
1095
+ return error instanceof AppError && error.code === "FRAMEWORK_PROCESS_SHUTDOWN_FAILED";
1096
+ }
1097
+
1098
+ export {
1099
+ prepareIdeSupport
1100
+ };