@veryfront/ext-content-mdx 0.1.1186 → 0.1.1189

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 (163) hide show
  1. package/esm/_dnt.polyfills.d.ts +6 -6
  2. package/esm/_dnt.polyfills.d.ts.map +1 -1
  3. package/esm/deno.d.ts +18 -0
  4. package/esm/deno.js +30 -9
  5. package/esm/src/config/defaults.d.ts +31 -24
  6. package/esm/src/config/defaults.d.ts.map +1 -1
  7. package/esm/src/config/defaults.js +25 -18
  8. package/esm/src/errors/diagnostic-policy.d.ts +35 -0
  9. package/esm/src/errors/diagnostic-policy.d.ts.map +1 -0
  10. package/esm/src/errors/diagnostic-policy.js +100 -0
  11. package/esm/src/errors/error-registry/boundary.d.ts +2 -0
  12. package/esm/src/errors/error-registry/boundary.d.ts.map +1 -1
  13. package/esm/src/errors/error-registry/boundary.js +8 -0
  14. package/esm/src/errors/error-registry/config.d.ts.map +1 -1
  15. package/esm/src/errors/error-registry/config.js +3 -3
  16. package/esm/src/errors/error-registry/deploy.js +1 -1
  17. package/esm/src/errors/error-registry/server.d.ts +2 -0
  18. package/esm/src/errors/error-registry/server.d.ts.map +1 -1
  19. package/esm/src/errors/error-registry/server.js +8 -0
  20. package/esm/src/errors/error-registry-helpers.d.ts +11 -2
  21. package/esm/src/errors/error-registry-helpers.d.ts.map +1 -1
  22. package/esm/src/errors/error-registry-helpers.js +70 -1
  23. package/esm/src/errors/error-registry.d.ts +85 -73
  24. package/esm/src/errors/error-registry.d.ts.map +1 -1
  25. package/esm/src/errors/error-registry.js +2 -14
  26. package/esm/src/errors/types.d.ts +44 -5
  27. package/esm/src/errors/types.d.ts.map +1 -1
  28. package/esm/src/errors/types.js +148 -24
  29. package/esm/src/errors/veryfront-error.d.ts +25 -2
  30. package/esm/src/errors/veryfront-error.d.ts.map +1 -1
  31. package/esm/src/errors/veryfront-error.js +638 -28
  32. package/esm/src/observability/limits.d.ts +20 -0
  33. package/esm/src/observability/limits.d.ts.map +1 -0
  34. package/esm/src/observability/limits.js +19 -0
  35. package/esm/src/observability/telemetry-error.d.ts +22 -0
  36. package/esm/src/observability/telemetry-error.d.ts.map +1 -0
  37. package/esm/src/observability/telemetry-error.js +377 -0
  38. package/esm/src/observability/tracing/api-shim.d.ts +39 -0
  39. package/esm/src/observability/tracing/api-shim.d.ts.map +1 -1
  40. package/esm/src/observability/tracing/api-shim.js +196 -69
  41. package/esm/src/observability/tracing/context-callback.d.ts +14 -0
  42. package/esm/src/observability/tracing/context-callback.d.ts.map +1 -0
  43. package/esm/src/observability/tracing/context-callback.js +111 -0
  44. package/esm/src/observability/tracing/otlp-setup.d.ts.map +1 -1
  45. package/esm/src/observability/tracing/otlp-setup.js +190 -46
  46. package/esm/src/platform/adapters/base.d.ts +51 -7
  47. package/esm/src/platform/adapters/base.d.ts.map +1 -1
  48. package/esm/src/platform/adapters/base.js +4 -2
  49. package/esm/src/platform/adapters/bounded-file-read.d.ts +9 -0
  50. package/esm/src/platform/adapters/bounded-file-read.d.ts.map +1 -1
  51. package/esm/src/platform/adapters/bounded-file-read.js +11 -5
  52. package/esm/src/platform/adapters/file-snapshot-error.d.ts +2 -0
  53. package/esm/src/platform/adapters/file-snapshot-error.d.ts.map +1 -1
  54. package/esm/src/platform/adapters/file-snapshot-error.js +2 -0
  55. package/esm/src/platform/adapters/file-system-capabilities.d.ts +74 -0
  56. package/esm/src/platform/adapters/file-system-capabilities.d.ts.map +1 -0
  57. package/esm/src/platform/adapters/file-system-capabilities.js +508 -0
  58. package/esm/src/platform/adapters/native-file-system-provenance.d.ts +6 -0
  59. package/esm/src/platform/adapters/native-file-system-provenance.d.ts.map +1 -0
  60. package/esm/src/platform/adapters/native-file-system-provenance.js +15 -0
  61. package/esm/src/platform/adapters/runtime/deno/filesystem-adapter.d.ts +45 -0
  62. package/esm/src/platform/adapters/runtime/deno/filesystem-adapter.d.ts.map +1 -0
  63. package/esm/src/platform/adapters/runtime/deno/filesystem-adapter.js +291 -0
  64. package/esm/src/platform/adapters/runtime/shared/node-filesystem-adapter.d.ts +71 -0
  65. package/esm/src/platform/adapters/runtime/shared/node-filesystem-adapter.d.ts.map +1 -0
  66. package/esm/src/platform/adapters/runtime/shared/node-filesystem-adapter.js +471 -0
  67. package/esm/src/platform/adapters/runtime/shared/shared-watcher.d.ts +16 -0
  68. package/esm/src/platform/adapters/runtime/shared/shared-watcher.d.ts.map +1 -0
  69. package/esm/src/platform/adapters/runtime/shared/shared-watcher.js +140 -0
  70. package/esm/src/platform/adapters/runtime/shared/temp-dir.d.ts +2 -0
  71. package/esm/src/platform/adapters/runtime/shared/temp-dir.d.ts.map +1 -0
  72. package/esm/src/platform/adapters/runtime/shared/temp-dir.js +10 -0
  73. package/esm/src/platform/adapters/runtime/shared/watcher-queue.d.ts +5 -0
  74. package/esm/src/platform/adapters/runtime/shared/watcher-queue.d.ts.map +1 -0
  75. package/esm/src/platform/adapters/runtime/shared/watcher-queue.js +75 -0
  76. package/esm/src/platform/compat/abort-signal.d.ts +20 -0
  77. package/esm/src/platform/compat/abort-signal.d.ts.map +1 -0
  78. package/esm/src/platform/compat/abort-signal.js +64 -0
  79. package/esm/src/platform/compat/constants.d.ts +2 -2
  80. package/esm/src/platform/compat/constants.d.ts.map +1 -1
  81. package/esm/src/platform/compat/constants.js +2 -2
  82. package/esm/src/platform/compat/error-introspection.d.ts +37 -0
  83. package/esm/src/platform/compat/error-introspection.d.ts.map +1 -0
  84. package/esm/src/platform/compat/error-introspection.js +258 -0
  85. package/esm/src/platform/compat/fs.d.ts +29 -8
  86. package/esm/src/platform/compat/fs.d.ts.map +1 -1
  87. package/esm/src/platform/compat/fs.js +123 -57
  88. package/esm/src/platform/compat/native-brand-checks.d.ts +14 -0
  89. package/esm/src/platform/compat/native-brand-checks.d.ts.map +1 -0
  90. package/esm/src/platform/compat/native-brand-checks.js +68 -0
  91. package/esm/src/platform/compat/not-found-error.d.ts +8 -3
  92. package/esm/src/platform/compat/not-found-error.d.ts.map +1 -1
  93. package/esm/src/platform/compat/not-found-error.js +164 -31
  94. package/esm/src/platform/compat/path/security.d.ts.map +1 -1
  95. package/esm/src/platform/compat/path/security.js +3 -5
  96. package/esm/src/platform/compat/process/command.d.ts +24 -1
  97. package/esm/src/platform/compat/process/command.d.ts.map +1 -1
  98. package/esm/src/platform/compat/process/command.js +393 -78
  99. package/esm/src/platform/compat/process/env.d.ts +11 -0
  100. package/esm/src/platform/compat/process/env.d.ts.map +1 -1
  101. package/esm/src/platform/compat/process/env.js +28 -38
  102. package/esm/src/platform/compat/process/global-error.d.ts +19 -0
  103. package/esm/src/platform/compat/process/global-error.d.ts.map +1 -0
  104. package/esm/src/platform/compat/process/global-error.js +57 -0
  105. package/esm/src/platform/compat/process/lifecycle.d.ts +10 -3
  106. package/esm/src/platform/compat/process/lifecycle.d.ts.map +1 -1
  107. package/esm/src/platform/compat/process/lifecycle.js +74 -23
  108. package/esm/src/platform/compat/process/project-env-contract.d.ts +19 -0
  109. package/esm/src/platform/compat/process/project-env-contract.d.ts.map +1 -0
  110. package/esm/src/platform/compat/process/project-env-contract.js +19 -0
  111. package/esm/src/platform/compat/runtime.d.ts +14 -5
  112. package/esm/src/platform/compat/runtime.d.ts.map +1 -1
  113. package/esm/src/platform/compat/runtime.js +34 -9
  114. package/esm/src/platform/compat/std/front-matter-yaml.d.ts +12 -0
  115. package/esm/src/platform/compat/std/front-matter-yaml.d.ts.map +1 -1
  116. package/esm/src/platform/compat/std/front-matter-yaml.js +35 -3
  117. package/esm/src/platform/compat/temp-directory-prefix.d.ts +8 -0
  118. package/esm/src/platform/compat/temp-directory-prefix.d.ts.map +1 -0
  119. package/esm/src/platform/compat/temp-directory-prefix.js +15 -0
  120. package/esm/src/utils/abort.d.ts +10 -0
  121. package/esm/src/utils/abort.d.ts.map +1 -0
  122. package/esm/src/utils/abort.js +35 -0
  123. package/esm/src/utils/constants/build.d.ts +3 -0
  124. package/esm/src/utils/constants/build.d.ts.map +1 -1
  125. package/esm/src/utils/constants/build.js +5 -1
  126. package/esm/src/utils/constants/cache.d.ts +21 -0
  127. package/esm/src/utils/constants/cache.d.ts.map +1 -1
  128. package/esm/src/utils/constants/cache.js +101 -39
  129. package/esm/src/utils/constants/css.d.ts +20 -0
  130. package/esm/src/utils/constants/css.d.ts.map +1 -0
  131. package/esm/src/utils/constants/css.js +19 -0
  132. package/esm/src/utils/constants/limits.d.ts +4 -0
  133. package/esm/src/utils/constants/limits.d.ts.map +1 -1
  134. package/esm/src/utils/constants/limits.js +4 -0
  135. package/esm/src/utils/constants/project-identity.d.ts +5 -0
  136. package/esm/src/utils/constants/project-identity.d.ts.map +1 -0
  137. package/esm/src/utils/constants/project-identity.js +4 -0
  138. package/esm/src/utils/constants/retry.d.ts +18 -0
  139. package/esm/src/utils/constants/retry.d.ts.map +1 -1
  140. package/esm/src/utils/constants/retry.js +18 -0
  141. package/esm/src/utils/constants/security.d.ts +4 -0
  142. package/esm/src/utils/constants/security.d.ts.map +1 -1
  143. package/esm/src/utils/constants/security.js +4 -0
  144. package/esm/src/utils/index.d.ts +3 -1
  145. package/esm/src/utils/index.d.ts.map +1 -1
  146. package/esm/src/utils/index.js +3 -1
  147. package/esm/src/utils/logger/core.d.ts +5 -0
  148. package/esm/src/utils/logger/core.d.ts.map +1 -1
  149. package/esm/src/utils/logger/core.js +67 -2
  150. package/esm/src/utils/logger/redact.d.ts +36 -13
  151. package/esm/src/utils/logger/redact.d.ts.map +1 -1
  152. package/esm/src/utils/logger/redact.js +573 -83
  153. package/esm/src/utils/parallel.d.ts.map +1 -1
  154. package/esm/src/utils/parallel.js +11 -1
  155. package/esm/src/utils/project-identity.d.ts +11 -0
  156. package/esm/src/utils/project-identity.d.ts.map +1 -0
  157. package/esm/src/utils/project-identity.js +69 -0
  158. package/esm/src/utils/version-constant.d.ts +1 -1
  159. package/esm/src/utils/version-constant.js +1 -1
  160. package/package.json +3 -3
  161. package/esm/src/platform/adapters/runtime/shared/native-file-capabilities.d.ts +0 -33
  162. package/esm/src/platform/adapters/runtime/shared/native-file-capabilities.d.ts.map +0 -1
  163. package/esm/src/platform/adapters/runtime/shared/native-file-capabilities.js +0 -205
@@ -0,0 +1,471 @@
1
+ import { createFileWatcher, createWatcherIterator, setupNodeFsWatcher } from "./shared-watcher.js";
2
+ import { makeNodeTempDir } from "./temp-dir.js";
3
+ import { isProxyWithoutHooks } from "../../../compat/error-introspection.js";
4
+ import { isCanonicalNotFoundError } from "../../../compat/not-found-error.js";
5
+ import { readBoundedFilePrefix, readFileWithinLimit, withFileHandle, } from "../../bounded-file-read.js";
6
+ import { markNativeFileSystemAdapter } from "../../native-file-system-provenance.js";
7
+ import { constants as nodeFsConstants } from "node:fs";
8
+ import { isAbsolute, relative, resolve, sep } from "../../../compat/path/index.js";
9
+ import { FileSnapshotChangedError } from "../../file-snapshot-error.js";
10
+ const silentLogger = {
11
+ error: () => { },
12
+ debug: () => { },
13
+ };
14
+ const getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor;
15
+ const hasOwnProperty = Object.prototype.hasOwnProperty;
16
+ const reflectApply = Reflect.apply;
17
+ function toSnapshotStat(stats) {
18
+ return {
19
+ dev: stats.dev,
20
+ ino: stats.ino,
21
+ size: stats.size,
22
+ mtimeNs: stats.mtimeNs,
23
+ ctimeNs: stats.ctimeNs,
24
+ isFile: () => stats.isFile(),
25
+ isSymbolicLink: () => stats.isSymbolicLink(),
26
+ };
27
+ }
28
+ const nodeFileSystemOperations = {
29
+ async realpath(path) {
30
+ const fs = await import("node:fs/promises");
31
+ return await fs.realpath(path);
32
+ },
33
+ async lstat(path) {
34
+ const fs = await import("node:fs/promises");
35
+ return toSnapshotStat(await fs.lstat(path, { bigint: true }));
36
+ },
37
+ async open(path, flags) {
38
+ const fs = await import("node:fs/promises");
39
+ const handle = await fs.open(path, flags);
40
+ return {
41
+ async stat() {
42
+ return toSnapshotStat(await handle.stat({ bigint: true }));
43
+ },
44
+ read(buffer, offset, length, position) {
45
+ return handle.read(buffer, offset, length, position);
46
+ },
47
+ writeFile(content) {
48
+ return handle.writeFile(content);
49
+ },
50
+ close() {
51
+ return handle.close();
52
+ },
53
+ };
54
+ },
55
+ };
56
+ function hasOwn(value, property) {
57
+ return Object.prototype.hasOwnProperty.call(value, property);
58
+ }
59
+ function isContainedPath(path, root) {
60
+ const relation = relative(root, path);
61
+ return relation === "" ||
62
+ (relation !== ".." && !relation.startsWith(`..${sep}`) && !isAbsolute(relation));
63
+ }
64
+ function requirePositiveSafeInteger(value) {
65
+ if (!Number.isSafeInteger(value) || value <= 0) {
66
+ throw new RangeError("Snapshot byte limit must be a positive safe integer");
67
+ }
68
+ }
69
+ function sameIdentity(left, right) {
70
+ return left.dev === right.dev && left.ino === right.ino;
71
+ }
72
+ function sameGeneration(left, right) {
73
+ return sameIdentity(left, right) &&
74
+ left.size === right.size &&
75
+ left.mtimeNs === right.mtimeNs &&
76
+ left.ctimeNs === right.ctimeNs;
77
+ }
78
+ function changed(message, cause) {
79
+ const error = new FileSnapshotChangedError(message);
80
+ if (cause !== undefined) {
81
+ Object.defineProperty(error, "cause", { value: cause, configurable: true });
82
+ }
83
+ return error;
84
+ }
85
+ function hasOwnDataErrorCode(error, expected) {
86
+ if (typeof error !== "object" || error === null || isProxyWithoutHooks(error)) {
87
+ return false;
88
+ }
89
+ try {
90
+ const descriptor = getOwnPropertyDescriptor(error, "code");
91
+ return descriptor !== undefined &&
92
+ reflectApply(hasOwnProperty, descriptor, ["value"]) === true &&
93
+ descriptor.value === expected;
94
+ }
95
+ catch {
96
+ return false;
97
+ }
98
+ }
99
+ function throwSnapshotChangeForMissingPath(message, cause) {
100
+ if (isCanonicalNotFoundError(cause)) {
101
+ throw changed(message, cause);
102
+ }
103
+ throw cause;
104
+ }
105
+ function throwSnapshotChangeForPathRace(message, cause) {
106
+ if (hasOwnDataErrorCode(cause, "ELOOP")) {
107
+ throw changed(message, cause);
108
+ }
109
+ throwSnapshotChangeForMissingPath(message, cause);
110
+ }
111
+ async function readNodeFileSnapshotWithinLimit(operations, noFollow, path, containmentRoot, byteLimit) {
112
+ requirePositiveSafeInteger(byteLimit);
113
+ const lexicalRoot = resolve(containmentRoot);
114
+ const candidate = resolve(path);
115
+ if (!isContainedPath(candidate, lexicalRoot)) {
116
+ throw new TypeError("Snapshot path must be contained by the requested root");
117
+ }
118
+ const canonicalRoot = await operations.realpath(lexicalRoot);
119
+ const pathnameBefore = await operations.lstat(candidate);
120
+ if (pathnameBefore.isSymbolicLink()) {
121
+ throw new TypeError("Snapshot path must not be a symbolic link");
122
+ }
123
+ if (!pathnameBefore.isFile()) {
124
+ throw new TypeError("Snapshot path must identify a regular file");
125
+ }
126
+ return await withFileHandle(async () => {
127
+ try {
128
+ return await operations.open(candidate, nodeFsConstants.O_RDONLY | noFollow);
129
+ }
130
+ catch (cause) {
131
+ throwSnapshotChangeForPathRace("File identity became uncertain while opening the snapshot", cause);
132
+ }
133
+ }, async (handle) => {
134
+ let handleBefore;
135
+ try {
136
+ handleBefore = await handle.stat();
137
+ }
138
+ catch (cause) {
139
+ throwSnapshotChangeForMissingPath("Opened file identity could not be verified", cause);
140
+ }
141
+ if (!handleBefore.isFile() || !sameGeneration(pathnameBefore, handleBefore)) {
142
+ throw changed("File identity changed while opening the snapshot");
143
+ }
144
+ let canonicalTarget;
145
+ let pathnameOpened;
146
+ try {
147
+ [canonicalTarget, pathnameOpened] = await Promise.all([
148
+ operations.realpath(candidate),
149
+ operations.lstat(candidate),
150
+ ]);
151
+ }
152
+ catch (cause) {
153
+ throwSnapshotChangeForPathRace("File target became uncertain while opening the snapshot", cause);
154
+ }
155
+ if (pathnameOpened.isSymbolicLink() ||
156
+ !pathnameOpened.isFile() ||
157
+ !sameGeneration(handleBefore, pathnameOpened)) {
158
+ throw changed("File identity changed while opening the snapshot");
159
+ }
160
+ if (!isContainedPath(canonicalTarget, canonicalRoot)) {
161
+ throw new TypeError("Snapshot target must be contained by the canonical root");
162
+ }
163
+ if (handleBefore.size < 0n) {
164
+ throw changed("File size became uncertain while opening the snapshot");
165
+ }
166
+ if (handleBefore.size > BigInt(byteLimit)) {
167
+ throw new RangeError(`File exceeds byte limit of ${byteLimit} bytes`);
168
+ }
169
+ const size = Number(handleBefore.size);
170
+ let bytes;
171
+ try {
172
+ bytes = new Uint8Array(size);
173
+ }
174
+ catch (cause) {
175
+ throw new Error("Unable to allocate the admitted snapshot buffer", { cause });
176
+ }
177
+ let offset = 0;
178
+ while (offset < size) {
179
+ const { bytesRead } = await handle.read(bytes, offset, size - offset, offset);
180
+ if (!Number.isSafeInteger(bytesRead) || bytesRead <= 0 || bytesRead > size - offset) {
181
+ throw changed("File size changed while reading the snapshot");
182
+ }
183
+ offset += bytesRead;
184
+ }
185
+ let handleAfter;
186
+ let pathnameAfter;
187
+ let canonicalTargetAfter;
188
+ try {
189
+ handleAfter = await handle.stat();
190
+ }
191
+ catch (cause) {
192
+ throwSnapshotChangeForMissingPath("Opened file identity could not be verified after reading the snapshot", cause);
193
+ }
194
+ try {
195
+ [pathnameAfter, canonicalTargetAfter] = await Promise.all([
196
+ operations.lstat(candidate),
197
+ operations.realpath(candidate),
198
+ ]);
199
+ }
200
+ catch (cause) {
201
+ throwSnapshotChangeForPathRace("File identity became uncertain after reading the snapshot", cause);
202
+ }
203
+ if (!pathnameAfter.isFile() ||
204
+ pathnameAfter.isSymbolicLink() ||
205
+ !sameGeneration(handleBefore, handleAfter) ||
206
+ !sameGeneration(handleBefore, pathnameAfter) ||
207
+ canonicalTargetAfter !== canonicalTarget ||
208
+ !isContainedPath(canonicalTargetAfter, canonicalRoot)) {
209
+ throw changed("File snapshot changed during the read");
210
+ }
211
+ return bytes;
212
+ }, "Filesystem snapshot and handle cleanup both failed");
213
+ }
214
+ async function createNodeFileBytesExclusive(operations, path, content) {
215
+ await withFileHandle(() => operations.open(path, "wx"), (handle) => handle.writeFile(content), "Filesystem exclusive create and handle cleanup both failed");
216
+ }
217
+ /**
218
+ * Filesystem implementation shared by runtimes that provide Node-compatible
219
+ * `node:fs` APIs (currently Node.js and Bun).
220
+ */
221
+ export class NodeCompatibleFileSystemAdapter {
222
+ logger;
223
+ constructor(logger = silentLogger, options = {}) {
224
+ this.logger = logger;
225
+ const operations = {
226
+ ...nodeFileSystemOperations,
227
+ ...options.operations,
228
+ };
229
+ const noFollow = hasOwn(options, "noFollow") ? options.noFollow : nodeFsConstants.O_NOFOLLOW;
230
+ if (typeof noFollow === "number" && noFollow !== 0) {
231
+ Object.defineProperty(this, "readFileSnapshotWithinLimit", {
232
+ value: (path, containmentRoot, byteLimit) => readNodeFileSnapshotWithinLimit(operations, noFollow, path, containmentRoot, byteLimit),
233
+ enumerable: true,
234
+ });
235
+ }
236
+ if (options.exclusiveCreate !== false) {
237
+ Object.defineProperty(this, "createFileBytesExclusive", {
238
+ value: (path, content) => createNodeFileBytesExclusive(operations, path, content),
239
+ enumerable: true,
240
+ });
241
+ }
242
+ if (globalThis[Symbol.for("import-meta-ponyfill-esmodule")](import.meta) === NodeCompatibleFileSystemAdapter) {
243
+ markNativeFileSystemAdapter(this);
244
+ }
245
+ }
246
+ async readFile(path) {
247
+ const fs = await import("node:fs/promises");
248
+ return fs.readFile(path, "utf-8");
249
+ }
250
+ async readFileBytes(path) {
251
+ const fs = await import("node:fs/promises");
252
+ const buffer = await fs.readFile(path);
253
+ return buffer instanceof Uint8Array ? buffer : new Uint8Array(buffer);
254
+ }
255
+ async readFileBytesBounded(path, byteLimit) {
256
+ const fs = await import("node:fs/promises");
257
+ return await readBoundedFilePrefix(async () => {
258
+ const handle = await fs.open(path, "r");
259
+ return {
260
+ close: () => handle.close(),
261
+ async read(buffer) {
262
+ const { bytesRead } = await handle.read(buffer, 0, buffer.byteLength, null);
263
+ return bytesRead === 0 ? null : bytesRead;
264
+ },
265
+ };
266
+ }, byteLimit);
267
+ }
268
+ async readFileBytesWithinLimit(path, byteLimit) {
269
+ const fs = await import("node:fs/promises");
270
+ return await readFileWithinLimit(async () => {
271
+ const handle = await fs.open(path, "r");
272
+ return {
273
+ close: () => handle.close(),
274
+ async read(buffer) {
275
+ const { bytesRead } = await handle.read(buffer, 0, buffer.byteLength, null);
276
+ return bytesRead === 0 ? null : bytesRead;
277
+ },
278
+ };
279
+ }, byteLimit);
280
+ }
281
+ async writeFile(path, content) {
282
+ const fs = await import("node:fs/promises");
283
+ await fs.writeFile(path, content, "utf-8");
284
+ }
285
+ async writeFileBytes(path, content) {
286
+ const fs = await import("node:fs/promises");
287
+ await fs.writeFile(path, content);
288
+ }
289
+ async rename(from, to) {
290
+ const fs = await import("node:fs/promises");
291
+ await fs.rename(from, to);
292
+ }
293
+ async exists(path) {
294
+ const fs = await import("node:fs/promises");
295
+ try {
296
+ await fs.access(path);
297
+ return true;
298
+ }
299
+ catch (error) {
300
+ if (isCanonicalNotFoundError(error))
301
+ return false;
302
+ throw error;
303
+ }
304
+ }
305
+ async *readDir(path) {
306
+ const fs = await import("node:fs/promises");
307
+ const entries = await fs.readdir(path, { withFileTypes: true });
308
+ for (const entry of entries) {
309
+ yield {
310
+ name: entry.name,
311
+ isFile: entry.isFile(),
312
+ isDirectory: entry.isDirectory(),
313
+ isSymlink: entry.isSymbolicLink(),
314
+ };
315
+ }
316
+ }
317
+ async stat(path) {
318
+ const fs = await import("node:fs/promises");
319
+ const stats = await fs.stat(path);
320
+ return {
321
+ size: stats.size,
322
+ isFile: stats.isFile(),
323
+ isDirectory: stats.isDirectory(),
324
+ isSymlink: stats.isSymbolicLink(),
325
+ mtime: stats.mtime,
326
+ };
327
+ }
328
+ async lstat(path) {
329
+ const fs = await import("node:fs/promises");
330
+ const stats = await fs.lstat(path);
331
+ return {
332
+ size: stats.size,
333
+ isFile: stats.isFile(),
334
+ isDirectory: stats.isDirectory(),
335
+ isSymlink: stats.isSymbolicLink(),
336
+ mtime: stats.mtime,
337
+ };
338
+ }
339
+ async realPath(path) {
340
+ const fs = await import("node:fs/promises");
341
+ return await fs.realpath(path);
342
+ }
343
+ async mkdir(path, options) {
344
+ const fs = await import("node:fs/promises");
345
+ await fs.mkdir(path, options);
346
+ }
347
+ async remove(path, options) {
348
+ const fs = await import("node:fs/promises");
349
+ await fs.rm(path, { recursive: options?.recursive, force: true });
350
+ }
351
+ async makeTempDir(prefix) {
352
+ return makeNodeTempDir(prefix);
353
+ }
354
+ setupWatcher(path, options) {
355
+ return setupNodeFsWatcher(path, options);
356
+ }
357
+ watch(paths, options) {
358
+ const pathArray = Array.isArray(paths) ? paths : [paths];
359
+ const recursive = options?.recursive ?? true;
360
+ const signal = options?.signal;
361
+ let closed = false;
362
+ const watchers = [];
363
+ const closedWatchers = new WeakSet();
364
+ const lifecycleFailures = [];
365
+ const pendingTasks = new Set();
366
+ const eventQueue = [];
367
+ let resolver = null;
368
+ let watcherFailure;
369
+ let closeWatcherGeneration = () => { };
370
+ let resolveClosed;
371
+ const closedSignal = new Promise((resolve) => {
372
+ resolveClosed = resolve;
373
+ });
374
+ const setResolver = (value) => {
375
+ resolver = value;
376
+ };
377
+ const trackTask = (task) => {
378
+ pendingTasks.add(task);
379
+ void task.then(() => pendingTasks.delete(task), () => pendingTasks.delete(task));
380
+ };
381
+ const recordLifecycleFailure = (failure) => {
382
+ const error = failure instanceof Error ? failure : new Error(String(failure));
383
+ if (!lifecycleFailures.includes(error))
384
+ lifecycleFailures.push(error);
385
+ };
386
+ const setupTasks = pathArray.map((path) => this.setupWatcher(path, {
387
+ recursive,
388
+ closed: () => closed,
389
+ signal,
390
+ eventQueue,
391
+ getResolver: () => resolver,
392
+ setResolver,
393
+ watchers,
394
+ trackTask,
395
+ onError: (error, watchPath) => {
396
+ this.logger.error(`File watcher error for ${watchPath}`, { error });
397
+ watcherFailure ??= error;
398
+ closeWatcherGeneration();
399
+ },
400
+ }));
401
+ const setup = Promise.all(setupTasks).then(() => undefined).catch((error) => {
402
+ closeWatcherGeneration();
403
+ throw error;
404
+ });
405
+ const iterator = createWatcherIterator(eventQueue, setResolver, () => closed, () => signal?.aborted ?? false);
406
+ const closeNativeWatchers = () => {
407
+ for (const watcher of watchers) {
408
+ if (closedWatchers.has(watcher))
409
+ continue;
410
+ try {
411
+ watcher.close();
412
+ closedWatchers.add(watcher);
413
+ }
414
+ catch (error) {
415
+ recordLifecycleFailure(error);
416
+ this.logger.debug("Error closing file watcher during cleanup", { error });
417
+ }
418
+ }
419
+ };
420
+ const cleanup = () => {
421
+ if (closed)
422
+ return;
423
+ closed = true;
424
+ signal?.removeEventListener("abort", cleanup);
425
+ closeNativeWatchers();
426
+ resolver?.({ done: true, value: undefined });
427
+ resolver = null;
428
+ resolveClosed();
429
+ };
430
+ closeWatcherGeneration = cleanup;
431
+ if (signal?.aborted)
432
+ cleanup();
433
+ else
434
+ signal?.addEventListener("abort", cleanup, { once: true });
435
+ const watcher = createFileWatcher(iterator, cleanup);
436
+ watcher.ready = setup;
437
+ watcher.done = (async () => {
438
+ const [setupResult] = await Promise.allSettled([setup, closedSignal]);
439
+ if (setupResult.status === "rejected") {
440
+ recordLifecycleFailure(setupResult.reason);
441
+ }
442
+ // ready remains fail-fast, but lifecycle completion must join every
443
+ // root acquisition. Promise.all(setupTasks) can reject while a sibling
444
+ // lstat/readdir is still in flight.
445
+ const setupTaskResults = await Promise.allSettled(setupTasks);
446
+ for (const result of setupTaskResults) {
447
+ if (result.status === "rejected")
448
+ recordLifecycleFailure(result.reason);
449
+ }
450
+ while (pendingTasks.size > 0) {
451
+ const results = await Promise.allSettled([...pendingTasks]);
452
+ for (const result of results) {
453
+ if (result.status === "rejected")
454
+ recordLifecycleFailure(result.reason);
455
+ }
456
+ }
457
+ // cleanup() already attempts this once. Retry any resource whose close()
458
+ // threw, but preserve every distinct failure so completion cannot be
459
+ // reported as clean after a partial teardown.
460
+ closeNativeWatchers();
461
+ if (watcherFailure)
462
+ recordLifecycleFailure(watcherFailure);
463
+ if (lifecycleFailures.length === 1)
464
+ throw lifecycleFailures[0];
465
+ if (lifecycleFailures.length > 1) {
466
+ throw new AggregateError(lifecycleFailures, "File watcher lifecycle did not complete cleanly");
467
+ }
468
+ })();
469
+ return watcher;
470
+ }
471
+ }
@@ -0,0 +1,16 @@
1
+ import type { FileChangeEvent } from "../../base.js";
2
+ import { createFileWatcher, createWatcherIterator, enqueueWatchEvent } from "./watcher-queue.js";
3
+ export { createFileWatcher, createWatcherIterator, enqueueWatchEvent };
4
+ interface NodeWatcherSetupOptions {
5
+ readonly recursive: boolean;
6
+ readonly closed: () => boolean;
7
+ readonly signal: AbortSignal | undefined;
8
+ readonly eventQueue: FileChangeEvent[];
9
+ readonly getResolver: () => ((value: IteratorResult<FileChangeEvent>) => void) | null;
10
+ readonly setResolver: (resolver: ((value: IteratorResult<FileChangeEvent>) => void) | null) => void;
11
+ readonly watchers: Array<import("node:fs").FSWatcher>;
12
+ readonly onError: (error: Error, path: string) => void;
13
+ readonly trackTask?: (task: Promise<void>) => void;
14
+ }
15
+ export declare function setupNodeFsWatcher(rootPath: string, options: NodeWatcherSetupOptions): Promise<void>;
16
+ //# sourceMappingURL=shared-watcher.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shared-watcher.d.ts","sourceRoot":"","sources":["../../../../../../src/src/platform/adapters/runtime/shared/shared-watcher.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAkB,MAAM,eAAe,CAAC;AACrE,OAAO,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAEjG,OAAO,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,iBAAiB,EAAE,CAAC;AAEvE,UAAU,uBAAuB;IAC/B,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAC5B,QAAQ,CAAC,MAAM,EAAE,MAAM,OAAO,CAAC;IAC/B,QAAQ,CAAC,MAAM,EAAE,WAAW,GAAG,SAAS,CAAC;IACzC,QAAQ,CAAC,UAAU,EAAE,eAAe,EAAE,CAAC;IACvC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC,KAAK,EAAE,cAAc,CAAC,eAAe,CAAC,KAAK,IAAI,CAAC,GAAG,IAAI,CAAC;IACtF,QAAQ,CAAC,WAAW,EAAE,CACpB,QAAQ,EAAE,CAAC,CAAC,KAAK,EAAE,cAAc,CAAC,eAAe,CAAC,KAAK,IAAI,CAAC,GAAG,IAAI,KAChE,IAAI,CAAC;IACV,QAAQ,CAAC,QAAQ,EAAE,KAAK,CAAC,OAAO,SAAS,EAAE,SAAS,CAAC,CAAC;IACtD,QAAQ,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACvD,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,CAAC,IAAI,CAAC,KAAK,IAAI,CAAC;CACpD;AAWD,wBAAsB,kBAAkB,CACtC,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,uBAAuB,GAC/B,OAAO,CAAC,IAAI,CAAC,CAmJf"}
@@ -0,0 +1,140 @@
1
+ import { createFileWatcher, createWatcherIterator, enqueueWatchEvent } from "./watcher-queue.js";
2
+ export { createFileWatcher, createWatcherIterator, enqueueWatchEvent };
3
+ function toError(error) {
4
+ return error instanceof Error ? error : new Error(String(error));
5
+ }
6
+ function isRecursiveWatchUnsupported(error) {
7
+ const code = error.code;
8
+ return code === "ERR_FEATURE_UNAVAILABLE_ON_PLATFORM";
9
+ }
10
+ export async function setupNodeFsWatcher(rootPath, options) {
11
+ try {
12
+ const fs = await import("node:fs");
13
+ const fsPromises = await import("node:fs/promises");
14
+ const { isAbsolute, relative, resolve, sep } = await import("node:path");
15
+ const isClosed = () => options.closed() || options.signal?.aborted === true;
16
+ if (isClosed())
17
+ return;
18
+ let rootInfo;
19
+ try {
20
+ rootInfo = await fsPromises.lstat(rootPath);
21
+ }
22
+ catch (error) {
23
+ throw toError(error);
24
+ }
25
+ if (isClosed())
26
+ return;
27
+ const emit = (kind, watchedPath, filename) => {
28
+ const candidate = filename === null ? watchedPath : resolve(watchedPath, String(filename));
29
+ const pathFromRoot = relative(resolve(rootPath), candidate);
30
+ const eventPath = pathFromRoot === "" || (pathFromRoot !== ".." &&
31
+ !pathFromRoot.startsWith(`..${sep}`) &&
32
+ !isAbsolute(pathFromRoot))
33
+ ? candidate
34
+ : watchedPath;
35
+ enqueueWatchEvent({ kind, paths: [eventPath] }, options.eventQueue, options.getResolver, options.setResolver);
36
+ return eventPath;
37
+ };
38
+ const registerWatcher = (watchedPath, recursive, listener) => {
39
+ const watcher = fs.watch(watchedPath, { recursive, encoding: "utf8" }, listener);
40
+ watcher.on("error", (error) => {
41
+ if (!isClosed())
42
+ options.onError(error, watchedPath);
43
+ });
44
+ if (isClosed()) {
45
+ watcher.close();
46
+ return watcher;
47
+ }
48
+ options.watchers.push(watcher);
49
+ return watcher;
50
+ };
51
+ if (options.recursive && rootInfo.isDirectory() && !rootInfo.isSymbolicLink()) {
52
+ try {
53
+ registerWatcher(rootPath, true, (eventType, filename) => {
54
+ if (isClosed())
55
+ return;
56
+ emit(eventType === "change" ? "modify" : "any", rootPath, filename);
57
+ });
58
+ return;
59
+ }
60
+ catch (error) {
61
+ if (!isRecursiveWatchUnsupported(error))
62
+ throw error;
63
+ }
64
+ // Compatible hosts and filesystems can reject recursive fs.watch.
65
+ // Maintain one non-recursive watcher per physical directory and
66
+ // reconcile the set whenever a directory entry is renamed.
67
+ const directoryWatchers = new Map();
68
+ let reconcileTail = Promise.resolve();
69
+ const removeSubtreeWatchers = (path) => {
70
+ const prefix = path.endsWith(sep) ? path : `${path}${sep}`;
71
+ for (const [directory, watcher] of directoryWatchers) {
72
+ if (directory !== path && !directory.startsWith(prefix))
73
+ continue;
74
+ directoryWatchers.delete(directory);
75
+ try {
76
+ watcher.close();
77
+ }
78
+ catch (error) {
79
+ if (!isClosed())
80
+ options.onError(toError(error), directory);
81
+ }
82
+ }
83
+ };
84
+ const watchDirectoryTree = async (path) => {
85
+ if (isClosed() || directoryWatchers.has(path))
86
+ return;
87
+ let info;
88
+ try {
89
+ info = await fsPromises.lstat(path);
90
+ }
91
+ catch (error) {
92
+ if (error.code === "ENOENT") {
93
+ removeSubtreeWatchers(path);
94
+ return;
95
+ }
96
+ throw error;
97
+ }
98
+ if (!info.isDirectory() || info.isSymbolicLink() || isClosed())
99
+ return;
100
+ const watcher = registerWatcher(path, false, (eventType, filename) => {
101
+ if (isClosed())
102
+ return;
103
+ const changedPath = emit(eventType === "change" ? "modify" : "any", path, filename);
104
+ if (eventType !== "rename")
105
+ return;
106
+ reconcileTail = reconcileTail
107
+ .then(() => watchDirectoryTree(changedPath))
108
+ .catch((error) => {
109
+ if (!isClosed())
110
+ options.onError(toError(error), changedPath);
111
+ });
112
+ options.trackTask?.(reconcileTail);
113
+ });
114
+ directoryWatchers.set(path, watcher);
115
+ watcher.once("close", () => {
116
+ if (directoryWatchers.get(path) === watcher)
117
+ directoryWatchers.delete(path);
118
+ });
119
+ const entries = await fsPromises.readdir(path, { withFileTypes: true });
120
+ for (const entry of entries) {
121
+ if (isClosed())
122
+ return;
123
+ if (entry.isDirectory() && !entry.isSymbolicLink()) {
124
+ await watchDirectoryTree(resolve(path, entry.name));
125
+ }
126
+ }
127
+ };
128
+ await watchDirectoryTree(resolve(rootPath));
129
+ return;
130
+ }
131
+ registerWatcher(rootPath, false, (eventType, filename) => {
132
+ if (isClosed())
133
+ return;
134
+ emit(eventType === "change" ? "modify" : "any", rootPath, filename);
135
+ });
136
+ }
137
+ catch (error) {
138
+ throw toError(error);
139
+ }
140
+ }
@@ -0,0 +1,2 @@
1
+ export declare function makeNodeTempDir(prefix: string): Promise<string>;
2
+ //# sourceMappingURL=temp-dir.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"temp-dir.d.ts","sourceRoot":"","sources":["../../../../../../src/src/platform/adapters/runtime/shared/temp-dir.ts"],"names":[],"mappings":"AAEA,wBAAsB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAQrE"}
@@ -0,0 +1,10 @@
1
+ import { validateTempDirectoryPrefix } from "../../../compat/temp-directory-prefix.js";
2
+ export async function makeNodeTempDir(prefix) {
3
+ const validatedPrefix = validateTempDirectoryPrefix(prefix);
4
+ const { mkdtemp } = await import("node:fs/promises");
5
+ const { sep } = await import("node:path");
6
+ const { tmpdir } = await import("node:os");
7
+ const tempRoot = tmpdir();
8
+ const rootPrefix = tempRoot.endsWith(sep) ? tempRoot : `${tempRoot}${sep}`;
9
+ return await mkdtemp(`${rootPrefix}${validatedPrefix}`);
10
+ }
@@ -0,0 +1,5 @@
1
+ import type { FileChangeEvent, FileWatcher } from "../../base.js";
2
+ export declare function createWatcherIterator(eventQueue: FileChangeEvent[], setResolver: (r: ((value: IteratorResult<FileChangeEvent>) => void) | null) => void, isClosed: () => boolean, isAborted: () => boolean): AsyncIterator<FileChangeEvent>;
3
+ export declare function enqueueWatchEvent(event: FileChangeEvent, eventQueue: FileChangeEvent[], getResolver: () => ((value: IteratorResult<FileChangeEvent>) => void) | null, setResolver: (resolver: ((value: IteratorResult<FileChangeEvent>) => void) | null) => void): void;
4
+ export declare function createFileWatcher(iterator: AsyncIterator<FileChangeEvent>, cleanup: () => void): FileWatcher;
5
+ //# sourceMappingURL=watcher-queue.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"watcher-queue.d.ts","sourceRoot":"","sources":["../../../../../../src/src/platform/adapters/runtime/shared/watcher-queue.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAElE,wBAAgB,qBAAqB,CACnC,UAAU,EAAE,eAAe,EAAE,EAC7B,WAAW,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,cAAc,CAAC,eAAe,CAAC,KAAK,IAAI,CAAC,GAAG,IAAI,KAAK,IAAI,EACnF,QAAQ,EAAE,MAAM,OAAO,EACvB,SAAS,EAAE,MAAM,OAAO,GACvB,aAAa,CAAC,eAAe,CAAC,CAyChC;AAED,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,eAAe,EACtB,UAAU,EAAE,eAAe,EAAE,EAC7B,WAAW,EAAE,MAAM,CAAC,CAAC,KAAK,EAAE,cAAc,CAAC,eAAe,CAAC,KAAK,IAAI,CAAC,GAAG,IAAI,EAC5E,WAAW,EAAE,CAAC,QAAQ,EAAE,CAAC,CAAC,KAAK,EAAE,cAAc,CAAC,eAAe,CAAC,KAAK,IAAI,CAAC,GAAG,IAAI,KAAK,IAAI,GACzF,IAAI,CASN;AAED,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,aAAa,CAAC,eAAe,CAAC,EACxC,OAAO,EAAE,MAAM,IAAI,GAClB,WAAW,CA2Bb"}