@publish.os/nextjs 0.0.1-alpha.81 → 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 (200) 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.js +1 -1
  93. package/dist/kernel/components/mdx/components/image.js +77 -56
  94. package/dist/kernel/components/mdx/components/inline-code.js +1 -1
  95. package/dist/kernel/components/mdx/components/kbd.d.ts +2 -2
  96. package/dist/kernel/components/mdx/components/kbd.js +3 -2
  97. package/dist/kernel/components/mdx/components/link.d.ts +35 -4
  98. package/dist/kernel/components/mdx/components/link.js +1 -1
  99. package/dist/kernel/components/mdx/components/paragraph.js +1 -4
  100. package/dist/kernel/components/mdx/components/task-list.js +1 -1
  101. package/dist/kernel/components/mdx/components/video-player.js +2 -2
  102. package/dist/kernel/components/mdx/components/video.js +1 -1
  103. package/dist/kernel/components/mdx/error-boundary.d.ts +1 -1
  104. package/dist/kernel/components/mdx/mdx.d.ts +12 -8
  105. package/dist/kernel/components/mdx/mdx.js +115 -39
  106. package/dist/kernel/components/mdx/rehype-heading-ids.js +1 -1
  107. package/dist/kernel/components/mdx/types.d.ts +1 -1
  108. package/dist/kernel/components/ui/breadcrumb-trail.d.ts +6 -23
  109. package/dist/kernel/components/ui/breadcrumb.d.ts +11 -3
  110. package/dist/kernel/components/ui/breadcrumb.js +6 -4
  111. package/dist/kernel/components/ui/button-group.d.ts +1 -1
  112. package/dist/kernel/components/ui/button-group.js +5 -4
  113. package/dist/kernel/components/ui/button.d.ts +2 -2
  114. package/dist/kernel/components/ui/button.js +6 -6
  115. package/dist/kernel/components/ui/card.d.ts +2 -2
  116. package/dist/kernel/components/ui/drawer.d.ts +3 -1
  117. package/dist/kernel/components/ui/drawer.js +5 -1
  118. package/dist/kernel/components/ui/input.d.ts +4 -4
  119. package/dist/kernel/components/ui/kbd.d.ts +1 -1
  120. package/dist/kernel/components/ui/kbd.js +9 -16
  121. package/dist/kernel/components/ui/link.d.ts +5 -3
  122. package/dist/kernel/components/ui/link.js +10 -9
  123. package/dist/kernel/components/ui/menu.js +5 -5
  124. package/dist/kernel/components/ui/mod-key.d.ts +10 -0
  125. package/dist/kernel/components/ui/mod-key.js +36 -0
  126. package/dist/kernel/components/ui/navigation-menu.js +2 -2
  127. package/dist/kernel/components/ui/progress.js +1 -1
  128. package/dist/kernel/components/ui/scroll-area.d.ts +8 -8
  129. package/dist/kernel/components/ui/scroll-area.js +4 -4
  130. package/dist/kernel/components/ui/select.js +7 -10
  131. package/dist/kernel/components/ui/text.d.ts +2 -2
  132. package/dist/kernel/components/ui/theme-toggle.d.ts +3 -3
  133. package/dist/kernel/components/ui/theme-toggle.js +4 -9
  134. package/dist/kernel/defaults.registry.d.ts +9 -9
  135. package/dist/kernel/defaults.registry.js +9 -9
  136. package/dist/kernel/routes/agent/markdown.d.ts +0 -1
  137. package/dist/kernel/routes/layouts/group.d.ts +1 -1
  138. package/dist/kernel/routes/metadata/feed.d.ts +1 -1
  139. package/dist/kernel/routes/metadata/feed.js +13 -9
  140. package/dist/kernel/routes/metadata/llms.d.ts +2 -1
  141. package/dist/kernel/routes/metadata/llms.js +4 -4
  142. package/dist/kernel/routes/metadata/robots.d.ts +1 -1
  143. package/dist/kernel/routes/metadata/robots.js +2 -2
  144. package/dist/kernel/routes/metadata/sitemap.d.ts +6 -3
  145. package/dist/kernel/routes/metadata/sitemap.js +48 -20
  146. package/dist/kernel/routes/pages/group.d.ts +1 -1
  147. package/dist/kernel/routes/pages/group.js +20 -12
  148. package/dist/kernel/routes/pages/leaf.d.ts +2 -2
  149. package/dist/kernel/routes/pages/leaf.js +20 -12
  150. package/dist/kernel/routes/pages/root.d.ts +2 -2
  151. package/dist/kernel/routes/pages/root.js +18 -12
  152. package/dist/resolvers/manifest-resolver.js +29 -6
  153. package/dist/search.d.ts +6 -7
  154. package/dist/search.js +47 -22
  155. package/dist/{sidebar-types-Bgchdfd6.d.ts → sidebar-types-DKpR27II.d.ts} +1 -1
  156. package/dist/{types-CIwwieNw.d.ts → types-BzkZty3r.d.ts} +23 -3
  157. package/dist/{types-DHBm7-j6.d.ts → types-CJWRG05y.d.ts} +20 -1
  158. package/dist/{types-B_b3C0U6.d.ts → types-CUtrppxt.d.ts} +8 -2
  159. package/dist/types.d.ts +14 -6
  160. package/dist/validate-local-source-XRL2Y7XE.js +14 -0
  161. package/dist/validate-publish-os-source-DAPZ4QGE.js +12 -0
  162. package/init/seed/minimal/.gitignore +1 -0
  163. package/init/seed/minimal/publish.os/assets/favicon/favicon.dark.png +0 -0
  164. package/init/seed/minimal/publish.os/assets/favicon/favicon.png +0 -0
  165. package/init/seed/minimal/publish.os/docs/content/get-started.mdx +6 -10
  166. package/init/seed/minimal/publish.os/docs/content/groups.mdx +1 -1
  167. package/init/seed/minimal/publish.os/docs/content/{theme.mdx → themes.mdx} +14 -12
  168. package/init/seed/minimal/publish.os/publish.os.config.json +3 -7
  169. package/init/seed/minimal/publish.os/theme.css +52 -24
  170. package/init/seed/minimal/publish.os/tsconfig.json +3 -0
  171. package/init/seed/minimal/seed.json +4 -1
  172. package/init/seed/scratch/publish.os/docs/content/get-started.mdx +6 -0
  173. package/init/seed/scratch/publish.os/publish.os.config.json +4 -0
  174. package/init/seed/scratch/seed.json +5 -0
  175. package/package.json +12 -26
  176. package/release/app/phosphor/package.json +3 -3
  177. package/release/app/phosphor/pnpm-lock.yaml.template +523 -360
  178. package/release/app/phosphor/pnpm-workspace.yaml +3 -0
  179. package/release/compiler/package.json +1 -1
  180. package/release/compiler/pnpm-lock.yaml.template +439 -286
  181. package/release/compiler/pnpm-workspace.yaml +3 -0
  182. package/release/release.json +7 -36
  183. package/compiler-assets/nextjs/defaults/group/leaf.tsx +0 -48
  184. package/dist/icons.d.ts +0 -1
  185. package/dist/icons.js +0 -2
  186. package/dist/kernel/components/mdx/components/pre.d.ts +0 -6
  187. package/dist/kernel/components/mdx/components/pre.js +0 -18
  188. package/dist/kernel/components/ui/meta-key.d.ts +0 -17
  189. package/dist/kernel/components/ui/meta-key.js +0 -9
  190. package/dist/kernel/framework-icons.d.ts +0 -1
  191. package/dist/kernel/framework-icons.js +0 -39
  192. package/dist/link-CYaCRDb6.d.ts +0 -35
  193. package/dist/route-metadata-og-image-BeKKFHg7.d.ts +0 -58
  194. package/dist/types-sM2g9nW0.d.ts +0 -12
  195. package/release/app/lucide/package.json +0 -30
  196. package/release/app/lucide/pnpm-lock.yaml.template +0 -2905
  197. package/release/app/lucide/pnpm-workspace.yaml +0 -11
  198. package/release/app/tabler/package.json +0 -30
  199. package/release/app/tabler/pnpm-lock.yaml.template +0 -2911
  200. package/release/app/tabler/pnpm-workspace.yaml +0 -11
@@ -0,0 +1,621 @@
1
+ import {
2
+ PUBLIC_PAGEFIND_DIRECTORY
3
+ } from "./chunk-YLTOLYWM.js";
4
+ import {
5
+ AppError
6
+ } from "./chunk-WDY4IK6Z.js";
7
+
8
+ // src/lib/compiler/lifecycle/output-ownership.ts
9
+ import { createHash, randomUUID } from "crypto";
10
+ import { constants } from "fs";
11
+ import {
12
+ link,
13
+ lstat,
14
+ mkdir,
15
+ open,
16
+ readdir,
17
+ realpath,
18
+ rename,
19
+ unlink,
20
+ writeFile
21
+ } from "fs/promises";
22
+ import { basename, dirname, join } from "path";
23
+ var MUTABLE_PREVIEW_ENTRIES = /* @__PURE__ */ new Set([
24
+ "node_modules",
25
+ ".next",
26
+ "next-env.d.ts",
27
+ "tsconfig.tsbuildinfo",
28
+ ".operation-owner.json",
29
+ ".preview-cache.json",
30
+ PUBLIC_PAGEFIND_DIRECTORY
31
+ ]);
32
+ async function generatedInventory(outputDir, stagingDir) {
33
+ if (stagingDir && (dirname(stagingDir) !== outputDir || !/^\.refresh-[a-zA-Z0-9]{6}$/u.test(basename(stagingDir))))
34
+ throw modifiedOutput(stagingDir);
35
+ let inventory = /* @__PURE__ */ Object.create(null);
36
+ async function assertMutable(path) {
37
+ try {
38
+ let entry = await lstat(path);
39
+ if (entry.isDirectory()) {
40
+ if (await assertLocalDirectory(path), path === join(outputDir, ".next/dev/node_modules")) return;
41
+ for (let name of await readdir(path))
42
+ await assertMutable(join(path, name));
43
+ } else if (!entry.isFile()) throw redirectedOutput(path);
44
+ } catch (error) {
45
+ if (error.code !== "ENOENT") throw error;
46
+ }
47
+ }
48
+ async function visit(path) {
49
+ let absolute = join(outputDir, path), entry = await lstat(absolute);
50
+ if (stagingDir && absolute === stagingDir) {
51
+ await assertLocalDirectory(absolute);
52
+ return;
53
+ }
54
+ if (MUTABLE_PREVIEW_ENTRIES.has(path)) {
55
+ if (["node_modules", ".next", PUBLIC_PAGEFIND_DIRECTORY].includes(path))
56
+ await assertLocalDirectory(absolute), path !== "node_modules" && await assertMutable(absolute);
57
+ else if (!entry.isFile()) throw redirectedOutput(absolute);
58
+ return;
59
+ }
60
+ if (entry.isDirectory()) {
61
+ await assertLocalDirectory(absolute), inventory[path] = "directory";
62
+ for (let name of (await readdir(absolute)).sort())
63
+ await visit(path ? `${path}/${name}` : name);
64
+ } else if (entry.isFile()) {
65
+ let file = await open(
66
+ absolute,
67
+ constants.O_RDONLY | constants.O_NOFOLLOW | constants.O_NONBLOCK
68
+ );
69
+ try {
70
+ if (!(await file.stat()).isFile()) throw modifiedOutput(path);
71
+ inventory[path] = createHash("sha256").update(await file.readFile()).digest("hex");
72
+ } finally {
73
+ await file.close();
74
+ }
75
+ } else throw modifiedOutput(path);
76
+ }
77
+ return await visit(""), inventory;
78
+ }
79
+ function modifiedOutput(path) {
80
+ return new AppError({
81
+ code: "FRAMEWORK_LOCAL_OUTPUT_MODIFIED",
82
+ message: `Generated preview contains unverified or modified files: ${path || ".operation-owner.json"}. The files were preserved.`,
83
+ fix: "Move custom work into the authored source, or restore the generated file before restarting this preview."
84
+ });
85
+ }
86
+ async function assertGeneratedOutput(options) {
87
+ if (options.scope === void 0 || !await lstat(options.outputDir).then(() => !0).catch((error) => {
88
+ if (error.code !== "ENOENT") throw error;
89
+ return !1;
90
+ })) return;
91
+ let owner = await readGeneratedOwner(options.outputDir, options.scope), actual = await generatedInventory(
92
+ options.outputDir,
93
+ options.stagingDir
94
+ );
95
+ assertInventory(actual, [owner.generated]);
96
+ }
97
+ async function readGeneratedOwner(outputDir, scope) {
98
+ let owner = await readOwnership(
99
+ join(outputDir, ".operation-owner.json"),
100
+ 16777216
101
+ );
102
+ if (!owner || owner.scope !== scope || owner.operation !== "dev" || !owner.generated || typeof owner.generated != "object" || Array.isArray(owner.generated))
103
+ throw modifiedOutput("");
104
+ return { ...owner, generated: owner.generated };
105
+ }
106
+ function assertInventory(actual, expected) {
107
+ for (let [path, digest] of Object.entries(actual))
108
+ if (!expected.some((inventory) => inventory[path] === digest))
109
+ throw modifiedOutput(path);
110
+ }
111
+ async function prepareGeneratedOutputUpdate(options) {
112
+ let scope = options.scope;
113
+ if (scope === void 0) return;
114
+ let output = { ...options, operation: "dev" };
115
+ await assertOperationOutput(output);
116
+ let identity = await assertLocalDirectory(options.outputDir), stagingIdentity = await assertLocalDirectory(options.stagingDir), owner = await readGeneratedOwner(options.outputDir, scope), current = await generatedInventory(
117
+ options.outputDir,
118
+ options.stagingDir
119
+ );
120
+ assertInventory(current, [owner.generated]);
121
+ let incoming = await generatedInventory(options.incoming), assertCurrent = async () => {
122
+ await assertLocalDirectory(options.outputDir, identity), await assertLocalDirectory(options.stagingDir, stagingIdentity), await assertOperationOutput(output);
123
+ let latest = await readGeneratedOwner(options.outputDir, scope);
124
+ if (JSON.stringify(latest) !== JSON.stringify(owner))
125
+ throw ownershipError();
126
+ };
127
+ return async () => {
128
+ await assertCurrent();
129
+ let actual = await generatedInventory(
130
+ options.outputDir,
131
+ options.stagingDir
132
+ );
133
+ assertInventory(actual, [owner.generated, incoming]);
134
+ let temporary = join(
135
+ options.stagingDir,
136
+ `.operation-owner-${randomUUID()}.tmp`
137
+ );
138
+ await writeFile(
139
+ temporary,
140
+ `${JSON.stringify({ ...owner, generated: actual })}
141
+ `,
142
+ { flag: "wx" }
143
+ ), await assertCurrent(), await rename(temporary, join(options.outputDir, ".operation-owner.json"));
144
+ };
145
+ }
146
+ function localOperationName({
147
+ operation,
148
+ scope
149
+ }) {
150
+ if (scope !== void 0 && (operation !== "dev" || typeof scope != "string" || !/^[a-f0-9]{64}$/u.test(scope)))
151
+ throw new AppError({
152
+ code: "FRAMEWORK_LOCAL_OPERATION_INVALID",
153
+ message: "A scoped development operation requires a lowercase SHA-256 identity. Retry with the selected preview's internal identity."
154
+ });
155
+ return scope === void 0 ? operation : `dev-${scope}`;
156
+ }
157
+ async function assertOperationOutput(options) {
158
+ if (localOperationName(options), !!await lstat(options.outputDir).then(() => !0).catch((error) => {
159
+ if (error.code !== "ENOENT") throw error;
160
+ return !1;
161
+ })) {
162
+ await assertLocalDirectory(options.outputDir);
163
+ try {
164
+ let owner = await readOwnership(
165
+ join(options.outputDir, ".operation-owner.json"),
166
+ options.scope === void 0 ? 16384 : 16777216
167
+ );
168
+ if (!owner || owner.schemaVersion !== 1 || owner.sourceRoot !== options.sourceRoot || owner.operation !== options.operation || owner.scope !== options.scope)
169
+ throw ownershipError();
170
+ } catch {
171
+ throw ownershipError();
172
+ }
173
+ }
174
+ }
175
+ async function markOperationOutput(options) {
176
+ localOperationName(options);
177
+ let identity = await assertLocalDirectory(options.outputDir), owner = {
178
+ schemaVersion: 1,
179
+ sourceRoot: options.sourceRoot,
180
+ operation: options.operation,
181
+ scope: options.scope,
182
+ ...options.scope === void 0 ? {} : { generated: await generatedInventory(options.outputDir) }
183
+ }, marker = join(options.outputDir, ".operation-owner.json"), temporary = join(
184
+ options.outputDir,
185
+ `.operation-owner-init-${randomUUID()}.tmp`
186
+ );
187
+ await writeFile(temporary, `${JSON.stringify(owner)}
188
+ `, {
189
+ flag: "wx",
190
+ mode: 384
191
+ });
192
+ let failure;
193
+ try {
194
+ await assertLocalDirectory(options.outputDir, identity), await link(temporary, marker);
195
+ } catch (error) {
196
+ failure = { error };
197
+ }
198
+ try {
199
+ await assertLocalDirectory(options.outputDir, identity), await unlink(temporary);
200
+ } catch (error) {
201
+ if (!failure) throw error;
202
+ failure.error instanceof Error && (failure.error.cause = {
203
+ previous: failure.error.cause,
204
+ cleanup: error,
205
+ retained: temporary
206
+ });
207
+ }
208
+ if (failure) throw failure.error;
209
+ }
210
+ function ownershipError() {
211
+ return new AppError({
212
+ code: "FRAMEWORK_LOCAL_OUTPUT_OWNERSHIP",
213
+ message: "The generated output owner cannot be verified. Restore this source's output metadata before continuing."
214
+ });
215
+ }
216
+ function redirectedOutput(path) {
217
+ return new AppError({
218
+ code: "FRAMEWORK_LOCAL_OUTPUT_REDIRECTED",
219
+ message: `The source-owned preview state was redirected at ${path}. Restore it before continuing. Linked targets were preserved.`
220
+ });
221
+ }
222
+ async function assertLocalDirectory(path, expected) {
223
+ let entry = await lstat(path);
224
+ if (!entry.isDirectory() || entry.isSymbolicLink() || await realpath(path) !== path || expected && (entry.dev !== expected.dev || entry.ino !== expected.ino))
225
+ throw new AppError({
226
+ code: "FRAMEWORK_LOCAL_OUTPUT_REDIRECTED",
227
+ message: "The source-owned output directory was redirected or replaced. Restore it before continuing."
228
+ });
229
+ return entry;
230
+ }
231
+ async function readOwnership(path, maximumSize = 16384) {
232
+ let file = await open(
233
+ path,
234
+ constants.O_RDONLY | constants.O_NOFOLLOW | constants.O_NONBLOCK
235
+ );
236
+ try {
237
+ let entry = await file.stat();
238
+ if (!entry.isFile() || entry.size > maximumSize) throw ownershipError();
239
+ return JSON.parse(await file.readFile("utf8"));
240
+ } finally {
241
+ await file.close();
242
+ }
243
+ }
244
+ async function ensureOutputOwnership({
245
+ sourceRoot,
246
+ ownerSourceRoot = sourceRoot
247
+ }) {
248
+ let sourceIdentity = await assertLocalDirectory(sourceRoot), outputRoot = join(sourceRoot, ".publish.os");
249
+ await mkdir(outputRoot).catch((error) => {
250
+ if (error.code !== "EEXIST") throw error;
251
+ });
252
+ let outputIdentity = await assertLocalDirectory(outputRoot), ownerPath = join(outputRoot, ".owner.json"), owner = { schemaVersion: 1, sourceRoot: ownerSourceRoot }, assertDirectories = async () => {
253
+ await assertLocalDirectory(sourceRoot, sourceIdentity), await assertLocalDirectory(outputRoot, outputIdentity);
254
+ for (let name of [
255
+ ".locks",
256
+ ".stages",
257
+ "build",
258
+ "dev",
259
+ "ide",
260
+ ".ide-lock"
261
+ ])
262
+ await assertLocalDirectory(join(outputRoot, name)).catch(
263
+ (error) => {
264
+ if (error.code !== "ENOENT") throw error;
265
+ }
266
+ );
267
+ }, assertOwner = async () => {
268
+ try {
269
+ let current = await readOwnership(ownerPath);
270
+ if (!current || current.schemaVersion !== 1 || current.sourceRoot !== ownerSourceRoot)
271
+ throw ownershipError();
272
+ } catch {
273
+ throw ownershipError();
274
+ }
275
+ };
276
+ if (!await lstat(ownerPath).then(() => !0).catch((error) => {
277
+ if (error.code !== "ENOENT") throw error;
278
+ return !1;
279
+ })) {
280
+ let entries = await readdir(outputRoot), isIdeOwned = (name) => name === "ide" || name === ".ide-lock" || name.startsWith(".ide.tmp-") || name.startsWith("ide.previous-");
281
+ if (entries.some(
282
+ (name) => !isIdeOwned(name) && !/^\.owner-init-[a-f0-9-]+\.tmp$/.test(name)
283
+ ))
284
+ await assertOwner();
285
+ else {
286
+ await assertDirectories();
287
+ let temporary = join(outputRoot, `.owner-init-${randomUUID()}.tmp`);
288
+ await writeFile(temporary, `${JSON.stringify(owner)}
289
+ `, { flag: "wx" });
290
+ try {
291
+ await assertDirectories(), await link(temporary, ownerPath).catch(
292
+ (error) => {
293
+ if (error.code !== "EEXIST") throw error;
294
+ }
295
+ );
296
+ } finally {
297
+ await assertDirectories(), await unlink(temporary);
298
+ }
299
+ }
300
+ }
301
+ return await assertOwner(), await assertDirectories(), {
302
+ outputRoot,
303
+ assertCurrent: async () => {
304
+ await assertDirectories(), await assertOwner();
305
+ }
306
+ };
307
+ }
308
+
309
+ // src/lib/compiler/lifecycle/operation-lock.ts
310
+ import { randomUUID as randomUUID2 } from "crypto";
311
+ import { constants as constants2 } from "fs";
312
+ import {
313
+ lstat as lstat2,
314
+ mkdir as mkdir2,
315
+ open as open2,
316
+ readdir as readdir2,
317
+ realpath as realpath2,
318
+ rmdir,
319
+ unlink as unlink2,
320
+ writeFile as writeFile2
321
+ } from "fs/promises";
322
+ import { hostname } from "os";
323
+ import { join as join2, resolve } from "path";
324
+ function lockError({
325
+ code,
326
+ message,
327
+ sourceRoot
328
+ }) {
329
+ return new AppError({ code, message, details: { sourceRoot } });
330
+ }
331
+ async function directoryIdentity({
332
+ path,
333
+ sourceRoot
334
+ }) {
335
+ let identity = await lstat2(path);
336
+ if (!identity.isDirectory() || identity.isSymbolicLink() || await realpath2(path) !== path)
337
+ throw lockError({
338
+ code: "FRAMEWORK_LOCAL_LOCK_REDIRECTED",
339
+ message: "The operation lock directory is redirected. Restore the source-owned output directory before retrying.",
340
+ sourceRoot
341
+ });
342
+ return identity;
343
+ }
344
+ async function verifyDirectory({
345
+ directory,
346
+ sourceRoot
347
+ }) {
348
+ let current = await directoryIdentity({ path: directory.path, sourceRoot });
349
+ if (current.dev !== directory.identity.dev || current.ino !== directory.identity.ino)
350
+ throw lockError({
351
+ code: "FRAMEWORK_LOCAL_LOCK_REDIRECTED",
352
+ message: "The operation lock directory changed. Restore the source-owned output directory before retrying.",
353
+ sourceRoot
354
+ });
355
+ }
356
+ async function createLock({
357
+ path,
358
+ owner
359
+ }) {
360
+ await mkdir2(path);
361
+ let identity = await directoryIdentity({
362
+ path,
363
+ sourceRoot: owner.sourceRoot
364
+ });
365
+ return await writeFile2(join2(path, "owner.json"), `${JSON.stringify(owner)}
366
+ `, {
367
+ flag: "wx"
368
+ }), { path, identity };
369
+ }
370
+ async function readOwner({
371
+ directory,
372
+ sourceRoot
373
+ }) {
374
+ await verifyDirectory({ directory, sourceRoot });
375
+ try {
376
+ let file = await open2(
377
+ join2(directory.path, "owner.json"),
378
+ constants2.O_RDONLY | constants2.O_NOFOLLOW | constants2.O_NONBLOCK
379
+ );
380
+ try {
381
+ let identity = await file.stat();
382
+ if (!identity.isFile() || identity.size > 16384)
383
+ throw new Error("Invalid lock metadata file.");
384
+ let owner = JSON.parse(await file.readFile("utf8"));
385
+ if (!owner || typeof owner != "object")
386
+ throw new Error("Invalid lock metadata.");
387
+ let value = owner;
388
+ if (value.sourceRoot !== sourceRoot || !["build", "dev", "ide", "dependencies"].includes(
389
+ value.operation ?? ""
390
+ ) || value.scope !== void 0 && (value.operation !== "dev" || typeof value.scope != "string" || !/^[a-f0-9]{64}$/u.test(value.scope)) || !Number.isSafeInteger(value.pid) || (value.pid ?? 0) <= 0 || typeof value.hostname != "string" || !value.hostname || typeof value.token != "string" || !/^[a-f0-9]{8}-[a-f0-9]{4}-4[a-f0-9]{3}-[89ab][a-f0-9]{3}-[a-f0-9]{12}$/u.test(
391
+ value.token
392
+ ))
393
+ throw new Error("Invalid lock metadata.");
394
+ return await verifyDirectory({ directory, sourceRoot }), value;
395
+ } finally {
396
+ await file.close();
397
+ }
398
+ } catch {
399
+ throw lockError({
400
+ code: "FRAMEWORK_LOCAL_LOCK_UNVERIFIED",
401
+ message: "The operation lock owner cannot be verified. Inspect the source-owned lock before retrying.",
402
+ sourceRoot
403
+ });
404
+ }
405
+ }
406
+ async function assertOwnedLock({
407
+ directory,
408
+ parent,
409
+ owner,
410
+ activePreparation = !1
411
+ }) {
412
+ await verifyDirectory({ directory: parent, sourceRoot: owner.sourceRoot });
413
+ let current = await readOwner({ directory, sourceRoot: owner.sourceRoot });
414
+ if (current.token !== owner.token || current.operation !== owner.operation || current.scope !== owner.scope)
415
+ throw lockError({
416
+ code: "FRAMEWORK_LOCAL_LOCK_UNVERIFIED",
417
+ message: "The operation lock now belongs to another owner. Leave it in place and inspect the active operation.",
418
+ sourceRoot: owner.sourceRoot
419
+ });
420
+ let files = await readdir2(directory.path);
421
+ if (activePreparation && owner.operation === "dependencies" && files.length === 2 && files.includes("owner.json") && files.includes("active-preparation.json"))
422
+ await assertPreparationMarker({ directory, owner });
423
+ else if (files.length !== 1 || files[0] !== "owner.json")
424
+ throw lockError({
425
+ code: "FRAMEWORK_LOCAL_LOCK_UNVERIFIED",
426
+ message: "The operation lock contains unknown files. Leave it in place and inspect the lock before retrying.",
427
+ sourceRoot: owner.sourceRoot
428
+ });
429
+ await verifyDirectory({ directory: parent, sourceRoot: owner.sourceRoot }), await verifyDirectory({ directory, sourceRoot: owner.sourceRoot });
430
+ }
431
+ async function assertPreparationMarker({
432
+ directory,
433
+ owner
434
+ }) {
435
+ try {
436
+ let file = await open2(
437
+ join2(directory.path, "active-preparation.json"),
438
+ constants2.O_RDONLY | constants2.O_NOFOLLOW | constants2.O_NONBLOCK
439
+ );
440
+ try {
441
+ let identity = await file.stat();
442
+ if (!identity.isFile() || identity.size > 16384 || await file.readFile("utf8") !== `${JSON.stringify(owner)}
443
+ `)
444
+ throw new Error("Invalid active preparation marker.");
445
+ } finally {
446
+ await file.close();
447
+ }
448
+ await verifyDirectory({ directory, sourceRoot: owner.sourceRoot });
449
+ } catch {
450
+ throw lockError({
451
+ code: "FRAMEWORK_LOCAL_LOCK_UNVERIFIED",
452
+ message: "Dependency preparation shutdown cannot be verified. Preserve the checkout lock and verify its recorded processes before recovery.",
453
+ sourceRoot: owner.sourceRoot
454
+ });
455
+ }
456
+ }
457
+ async function removeOwnedLock({
458
+ directory,
459
+ parent,
460
+ owner,
461
+ beforeRemoval
462
+ }) {
463
+ await assertOwnedLock({ directory, parent, owner }), beforeRemoval?.(), await unlink2(join2(directory.path, "owner.json")), await rmdir(directory.path);
464
+ }
465
+ function assertDeadOwner({
466
+ owner,
467
+ operation,
468
+ scope
469
+ }) {
470
+ if (owner.operation !== operation || owner.scope !== scope || owner.hostname !== hostname())
471
+ throw lockError({
472
+ code: "FRAMEWORK_LOCAL_LOCK_UNVERIFIED",
473
+ message: "The operation lock owner cannot be verified on this host. Inspect the recorded owner before retrying.",
474
+ sourceRoot: owner.sourceRoot
475
+ });
476
+ try {
477
+ process.kill(owner.pid, 0);
478
+ } catch (error) {
479
+ if (error.code === "ESRCH") return;
480
+ throw lockError({
481
+ code: "FRAMEWORK_LOCAL_LOCK_UNVERIFIED",
482
+ message: "The operation lock owner may still be running. Verify that process has stopped before retrying.",
483
+ sourceRoot: owner.sourceRoot
484
+ });
485
+ }
486
+ throw lockError({
487
+ code: "FRAMEWORK_LOCAL_OPERATION_ACTIVE",
488
+ message: `A ${operation} operation already owns ${owner.sourceRoot}. Stop that operation before starting another writer.`,
489
+ sourceRoot: owner.sourceRoot
490
+ });
491
+ }
492
+ async function acquireOperationLock({
493
+ sourceRoot,
494
+ outputRoot,
495
+ operation,
496
+ scope,
497
+ signal
498
+ }) {
499
+ signal?.throwIfAborted();
500
+ let operationName = localOperationName({ operation, scope }), canonicalSource = await realpath2(sourceRoot), root = resolve(outputRoot);
501
+ await directoryIdentity({ path: root, sourceRoot: canonicalSource });
502
+ let locksPath = join2(root, ".locks");
503
+ await mkdir2(locksPath).catch((error) => {
504
+ if (error.code !== "EEXIST") throw error;
505
+ });
506
+ let locks = {
507
+ path: locksPath,
508
+ identity: await directoryIdentity({
509
+ path: locksPath,
510
+ sourceRoot: canonicalSource
511
+ })
512
+ }, owner = {
513
+ sourceRoot: canonicalSource,
514
+ operation,
515
+ scope,
516
+ pid: process.pid,
517
+ hostname: hostname(),
518
+ token: randomUUID2()
519
+ }, transitionPath = join2(locksPath, `${operationName}.transition`), transition = async ({
520
+ waitForActive = !1
521
+ } = {}) => {
522
+ for (let attempt = 0; ; attempt += 1) {
523
+ await verifyDirectory({ directory: locks, sourceRoot: canonicalSource });
524
+ try {
525
+ return await createLock({ path: transitionPath, owner });
526
+ } catch (error) {
527
+ if (error.code !== "EEXIST") throw error;
528
+ if (waitForActive && attempt < 50) {
529
+ await new Promise((resolve2) => setTimeout(resolve2, 10));
530
+ continue;
531
+ }
532
+ throw lockError({
533
+ code: "FRAMEWORK_LOCAL_LOCK_UNVERIFIED",
534
+ message: "Another operation is changing or recovering this lock. Wait for it to finish; inspect an abandoned transition before retrying.",
535
+ sourceRoot: canonicalSource
536
+ });
537
+ }
538
+ }
539
+ }, guard = await transition({
540
+ waitForActive: operation === "ide" || operation === "dependencies"
541
+ }), lock, interruptedRecovery = !1;
542
+ try {
543
+ signal?.throwIfAborted();
544
+ try {
545
+ lock = await createLock({ path: join2(locksPath, operationName), owner });
546
+ } catch (error) {
547
+ if (error.code !== "EEXIST") throw error;
548
+ let existing = {
549
+ path: join2(locksPath, operationName),
550
+ identity: await directoryIdentity({
551
+ path: join2(locksPath, operationName),
552
+ sourceRoot: canonicalSource
553
+ })
554
+ }, previous = await readOwner({
555
+ directory: existing,
556
+ sourceRoot: canonicalSource
557
+ });
558
+ operation === "dependencies" && await assertOwnedLock({
559
+ directory: existing,
560
+ parent: locks,
561
+ owner: previous,
562
+ activePreparation: !0
563
+ }), assertDeadOwner({ owner: previous, operation, scope }), signal?.throwIfAborted(), await removeOwnedLock({
564
+ directory: existing,
565
+ parent: locks,
566
+ owner: previous,
567
+ beforeRemoval: () => {
568
+ interruptedRecovery = !0;
569
+ }
570
+ }), signal?.throwIfAborted(), lock = await createLock({ path: join2(locksPath, operationName), owner }), interruptedRecovery = !1;
571
+ }
572
+ signal?.aborted && (await removeOwnedLock({ directory: lock, parent: locks, owner }), signal.throwIfAborted()), operation === "dependencies" && (interruptedRecovery = !0, await writeFile2(
573
+ join2(lock.path, "active-preparation.json"),
574
+ `${JSON.stringify(owner)}
575
+ `,
576
+ { flag: "wx", mode: 384 }
577
+ ), interruptedRecovery = !1);
578
+ } finally {
579
+ interruptedRecovery || await removeOwnedLock({
580
+ directory: guard,
581
+ parent: locks,
582
+ owner
583
+ });
584
+ }
585
+ let released = !1;
586
+ return async ({ shutdownUnverified = !1 } = {}) => {
587
+ if (released) return;
588
+ let guard2 = await transition({ waitForActive: !0 }), preserveGuard = shutdownUnverified;
589
+ try {
590
+ shutdownUnverified ? (await assertOwnedLock({
591
+ directory: lock,
592
+ parent: locks,
593
+ owner,
594
+ activePreparation: operation === "dependencies"
595
+ }), await writeFile2(
596
+ join2(lock.path, "shutdown-unverified.json"),
597
+ `${JSON.stringify(owner)}
598
+ `,
599
+ { flag: "wx", mode: 384 }
600
+ ), preserveGuard = !1) : (operation === "dependencies" && (await assertOwnedLock({
601
+ directory: lock,
602
+ parent: locks,
603
+ owner,
604
+ activePreparation: !0
605
+ }), await unlink2(join2(lock.path, "active-preparation.json"))), await removeOwnedLock({ directory: lock, parent: locks, owner })), released = !0;
606
+ } finally {
607
+ preserveGuard || await removeOwnedLock({ directory: guard2, parent: locks, owner });
608
+ }
609
+ };
610
+ }
611
+
612
+ export {
613
+ assertGeneratedOutput,
614
+ prepareGeneratedOutputUpdate,
615
+ localOperationName,
616
+ assertOperationOutput,
617
+ markOperationOutput,
618
+ assertLocalDirectory,
619
+ ensureOutputOwnership,
620
+ acquireOperationLock
621
+ };