@graftland/hmr 0.3.3 → 0.4.0
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.
- package/dist/index.d.ts +14 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +68 -1
- package/dist/index.js.map +1 -1
- package/dist/internal/changes.js.map +1 -1
- package/dist/internal/modules.js.map +1 -1
- package/dist/internal/sourceObservation.js +57 -0
- package/dist/internal/sourceObservation.js.map +1 -0
- package/package.json +2 -2
- package/src/index.ts +174 -4
- package/src/internal/changes.ts +10 -8
- package/src/internal/modules.ts +3 -1
- package/src/internal/sourceObservation.ts +147 -0
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { Graft } from "@graftland/graft";
|
|
2
1
|
import { Cause, Data, Duration, Effect, FileSystem, PlatformError, Schema, Scope, Stream } from "effect";
|
|
2
|
+
import { Graft } from "@graftland/graft";
|
|
3
3
|
declare const HmrError_base: Schema.Class<HmrError, Schema.TaggedStruct<"HmrError", {
|
|
4
4
|
readonly stage: Schema.Literals<readonly ["import", "exports", "closed"]>;
|
|
5
5
|
readonly specifier: Schema.String;
|
|
@@ -51,11 +51,24 @@ export interface WatchOptions extends FileSystem.WatchOptions {
|
|
|
51
51
|
export interface ImportOptions {
|
|
52
52
|
readonly observationScope: Scope.Scope;
|
|
53
53
|
}
|
|
54
|
+
/** An entry-owned observation collection; successful imports replace old dependencies, failures retain them. */
|
|
55
|
+
export interface Observation {
|
|
56
|
+
readonly scope: Scope.Scope;
|
|
57
|
+
/** Files registered by one activation accumulate; the next activation's files replace them. */
|
|
58
|
+
readonly watch: (files: ReadonlyArray<string>, activation: Scope.Scope) => Effect.Effect<void, PlatformError.PlatformError>;
|
|
59
|
+
readonly changes: Stream.Stream<void>;
|
|
60
|
+
}
|
|
54
61
|
export interface Hmr {
|
|
62
|
+
/** Makes a collection independent of individual activation and retry scopes. */
|
|
63
|
+
readonly observation: Effect.Effect<Observation, never, Scope.Scope | FileSystem.FileSystem>;
|
|
55
64
|
/** Keeps imported entries registered until this HMR session closes. */
|
|
56
65
|
readonly importer: (specifier: string) => Promise<unknown>;
|
|
57
66
|
/** Uses the application context and Node cache, without watching or replacing the module. */
|
|
58
67
|
readonly importModule: (specifier: string) => Effect.Effect<unknown, HmrError>;
|
|
68
|
+
/** Imports a fresh non-plugin graph in the caller's scope; failed observations survive in observationScope when supplied. */
|
|
69
|
+
readonly importModuleScoped: (specifier: string, options?: ImportOptions) => Effect.Effect<unknown, HmrError, Scope.Scope>;
|
|
70
|
+
/** Observes file URLs and dependencies of leased modules without importing the other files. */
|
|
71
|
+
readonly observe: (files: ReadonlyArray<string>) => Stream.Stream<void, PlatformError.PlatformError, FileSystem.FileSystem>;
|
|
59
72
|
/** Registers an observation lease in observationScope, or the caller's scope when omitted. */
|
|
60
73
|
readonly importerScoped: (specifier: string, options?: ImportOptions) => Effect.Effect<unknown, HmrError, Scope.Scope>;
|
|
61
74
|
/** Imports every entry before replacing anything. Activation failures belong to Graft. */
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/index.ts"],"mappings":";;;;;;;
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/index.ts"],"mappings":";;;;;;;WA6CmB;;qBAFN,iBAAiB;MAQhB;;YAKF,cAAc,KAAK;EAC9B;aAAqB,SAAS;;EAC9B;aACU,SAAS;aACT;;EAGV;aAAmB,OAAO,MAAM,MAAM;;;qBAG1B,aAAW,KAAA,WAAA;;WAHG,OAAA,MAAM,MAAM;;;WANR,SAAA;;;WAEX,SAAA;WAEjB;;YAOS,eAAe,QAAQ;WAAwB;;iBAE1C;;WAEP;;WAEA,WAAW;;iBAGJ,qBAAqB,WAAW;WACvC,WAAW,SAAS;;WAEpB,UAAU;;;iBAIH;WACP,kBAAkB,MAAM;;;iBAIjB;WACP,OAAO,MAAM;;WAEb,QACR,OAAO,uBACP,YAAY,MAAM,UACd,OAAO,aAAa,cAAc;WAC9B,SAAS,OAAO;;iBAGT;;WAEP,aAAa,OAAO,OAC5B,oBAEA,MAAM,QAAQ,WAAW;;WAGjB,WAAW,sBAAsB;;WAEjC,eAAe,sBAAsB,OAAO,gBAAgB;;WAE5D,qBACR,mBACA,UAAU,kBACN,OAAO,gBAAgB,UAAU,MAAM;;WAEnC,UACR,OAAO,0BACH,OAAO,aAAa,cAAc,eAAe,WAAW;;WAExD,iBACR,mBACA,UAAU,kBACN,OAAO,gBAAgB,UAAU,MAAM;;WAEnC,QAAQ,OAAO,OAAO,cAAc;;;;;;WAMpC,QACR,OAAO,uBACP,UAAU,iBACN,OAAO,OACX,aACA,cAAc,eACd,WAAW;;;;;;qBAQA,OACZ,SAAS,YACL,OAAO,OAAO,YAAY,MAAM,QAAQ,MAAM"}
|
package/dist/index.js
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { changes } from "./internal/changes.js";
|
|
2
|
+
import { digest } from "./internal/digest.js";
|
|
2
3
|
import { RestartRequired, isMissingEntry, modules } from "./internal/modules.js";
|
|
4
|
+
import { make as make$1 } from "./internal/sourceObservation.js";
|
|
3
5
|
import { realpath } from "node:fs/promises";
|
|
4
6
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
7
|
+
import { Array, Cause, Data, Deferred, Effect, Exit, FiberSet, FileSystem, HashMap, HashSet, Option, Ref, Result, Schema, Scope, Semaphore, Stream, String } from "effect";
|
|
5
8
|
import { Graft, Plugin } from "@graftland/graft";
|
|
6
|
-
import { Array, Cause, Data, Deferred, Effect, Exit, FiberSet, HashMap, HashSet, Option, Ref, Result, Schema, Scope, Semaphore, Stream, String } from "effect";
|
|
7
9
|
// src/index.ts
|
|
8
10
|
/**
|
|
9
11
|
* Hot module replacement for Graft plugins on Node.js.
|
|
@@ -30,6 +32,12 @@ const make = Effect.fnUntraced(function* (options) {
|
|
|
30
32
|
const graft = yield* Graft.Graft;
|
|
31
33
|
const semaphore = yield* Semaphore.make(1);
|
|
32
34
|
const owners = yield* Ref.make(HashMap.empty());
|
|
35
|
+
const sourceObservers = yield* Ref.make([]);
|
|
36
|
+
const observation = Effect.gen(function* () {
|
|
37
|
+
const source = yield* make$1();
|
|
38
|
+
yield* Effect.acquireRelease(Ref.update(sourceObservers, Array.append(source)), () => Ref.update(sourceObservers, Array.filter((current) => current !== source)));
|
|
39
|
+
return source;
|
|
40
|
+
});
|
|
33
41
|
const closed = yield* Ref.make(false);
|
|
34
42
|
const session = yield* Effect.scope;
|
|
35
43
|
const preserveExit = Effect.fnUntraced(function* (effect) {
|
|
@@ -209,6 +217,62 @@ const make = Effect.fnUntraced(function* (options) {
|
|
|
209
217
|
cause
|
|
210
218
|
})
|
|
211
219
|
}))));
|
|
220
|
+
const importModuleScoped = (specifier, options) => Effect.uninterruptibleMask((restore) => Effect.gen(function* () {
|
|
221
|
+
const caller = yield* Effect.scope;
|
|
222
|
+
const { token, exit, managed } = yield* serial(Effect.gen(function* () {
|
|
223
|
+
yield* checkOpen;
|
|
224
|
+
const generation = hooks.prepare();
|
|
225
|
+
hooks.start(generation);
|
|
226
|
+
const token = Symbol();
|
|
227
|
+
const exit = yield* Effect.exit(Effect.tryPromise({
|
|
228
|
+
try: () => import(
|
|
229
|
+
/* @vite-ignore */
|
|
230
|
+
hooks.request(specifier)
|
|
231
|
+
),
|
|
232
|
+
catch: (cause) => HmrError.make({
|
|
233
|
+
stage: "import",
|
|
234
|
+
specifier,
|
|
235
|
+
cause
|
|
236
|
+
})
|
|
237
|
+
}));
|
|
238
|
+
const root = Option.orElse(hooks.resolved(), () => String.startsWith("file:")(specifier) ? Option.some(specifier) : Option.none());
|
|
239
|
+
const attempt = Option.map(root, (url) => ({
|
|
240
|
+
url,
|
|
241
|
+
generation,
|
|
242
|
+
...Option.match(hooks.fileRequest(specifier), {
|
|
243
|
+
onNone: () => ({}),
|
|
244
|
+
onSome: (request) => ({ request })
|
|
245
|
+
})
|
|
246
|
+
}));
|
|
247
|
+
const observers = yield* Ref.get(sourceObservers);
|
|
248
|
+
const observer = options === void 0 ? Option.none() : Array.findFirst(observers, (source) => source.scope === options.observationScope);
|
|
249
|
+
if (Option.isSome(observer)) yield* observer.value.imported(Option.match(attempt, {
|
|
250
|
+
onNone: () => specifier,
|
|
251
|
+
onSome: (value) => value.request ?? value.url
|
|
252
|
+
}), hooks.files(Option.toArray(attempt)), Exit.isSuccess(exit));
|
|
253
|
+
else yield* Ref.update(owners, HashMap.set(token, {
|
|
254
|
+
active: Exit.isSuccess(exit) ? attempt : Option.none(),
|
|
255
|
+
pending: Exit.isFailure(exit) ? attempt : Option.none()
|
|
256
|
+
}));
|
|
257
|
+
return {
|
|
258
|
+
token,
|
|
259
|
+
exit,
|
|
260
|
+
managed: Option.isSome(observer)
|
|
261
|
+
};
|
|
262
|
+
}).pipe(Effect.ensuring(Effect.sync(hooks.discard))));
|
|
263
|
+
yield* Scope.addFinalizer(!managed && Exit.isFailure(exit) ? options?.observationScope ?? caller : caller, serial(Ref.update(owners, HashMap.remove(token)).pipe(Effect.ensuring(collect))));
|
|
264
|
+
return yield* restore(exit);
|
|
265
|
+
})).pipe(preserveExit);
|
|
266
|
+
const observe = (files) => Stream.unwrap(Effect.gen(function* () {
|
|
267
|
+
const fs = yield* FileSystem.FileSystem;
|
|
268
|
+
const observed = yield* Effect.forEach(files, (url) => fs.readFile(fileURLToPath(url)).pipe(Effect.map((bytes) => [url, {
|
|
269
|
+
generation: -1,
|
|
270
|
+
content: digest(bytes)
|
|
271
|
+
}])));
|
|
272
|
+
const baseline = HashMap.fromIterable(observed);
|
|
273
|
+
const snapshot = yield* observations.pipe(Effect.map((attempts) => HashMap.union(baseline, hooks.files(Array.filter(attempts, (attempt) => Array.contains(files, attempt.url) || attempt.request !== void 0 && Array.contains(files, attempt.request))))), semaphore.withPermits(1));
|
|
274
|
+
return changes((use) => use(snapshot), Array.map(Array.fromIterable(HashMap.keys(snapshot)), (url) => fileURLToPath(url))).pipe(Stream.as(void 0));
|
|
275
|
+
}));
|
|
212
276
|
const importerScoped = (specifier, options) => options === void 0 ? importWithLease(specifier) : importWithLease(specifier).pipe(Scope.provide(options.observationScope));
|
|
213
277
|
const importer = (specifier) => Ref.getUnsafe(closed) ? Promise.reject(closedError()) : run(importerScoped(specifier).pipe(Effect.provideService(Scope.Scope, imports)));
|
|
214
278
|
const unsupportedAttempts = (attempts) => Array.reduce(attempts, HashSet.empty(), (all, attempt) => HashSet.union(all, hooks.unsupported(attempt.generation, [attempt.url])));
|
|
@@ -323,6 +387,9 @@ const make = Effect.fnUntraced(function* (options) {
|
|
|
323
387
|
importer,
|
|
324
388
|
importerScoped,
|
|
325
389
|
importModule,
|
|
390
|
+
observation,
|
|
391
|
+
importModuleScoped,
|
|
392
|
+
observe,
|
|
326
393
|
reload: reloadChanged(void 0),
|
|
327
394
|
watch: (paths, watchOptions) => paths.length === 0 ? Stream.empty : changes((use) => Ref.get(owners).pipe(Effect.map((owners) => hooks.files([...Array.getSomes(Array.map(HashMap.toValues(owners), (owner) => owner.active)), ...Array.getSomes(Array.map(HashMap.toValues(owners), (owner) => owner.pending))])), Effect.flatMap(use), semaphore.withPermits(1)), paths, watchOptions).pipe(Stream.mapEffect((dirty) => Effect.map(Effect.exit(reloadChanged(dirty)), (exit) => Exit.isSuccess(exit) ? exit.value : WatchResult.Failed({ cause: exit.cause }))), Stream.merge(Stream.tick("1 second").pipe(Stream.mapEffect(() => unsupportedModules.pipe(semaphore.withPermits(1))), Stream.changes, Stream.filter((modules) => HashSet.size(modules) > 0), Stream.map((modules) => WatchResult.Skipped({
|
|
328
395
|
reason: "restart-required",
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["/**\n * Hot module replacement for Graft plugins on Node.js.\n */\n// @effect-diagnostics-next-line nodeBuiltinImport:off -- native import resolution must work without requiring a platform layer\nimport { realpath } from \"node:fs/promises\"\nimport { fileURLToPath, pathToFileURL } from \"node:url\"\nimport { Graft, Plugin } from \"@graftland/graft\"\nimport {\n\tArray,\n\tCause,\n\tData,\n\tDeferred,\n\tEffect,\n\tExit,\n\tFiberSet,\n\tFileSystem,\n\tHashMap,\n\tHashSet,\n\tOption,\n\tRef,\n\tResult,\n\tString,\n\tSchema,\n\tSemaphore,\n\tStream,\n\tScope,\n} from \"effect\"\nimport type { Duration, PlatformError } from \"effect\"\nimport { changes } from \"./internal/changes\"\nimport {\n\tisMissingEntry,\n\tmodules,\n\tRestartRequired,\n\ttype Attempt,\n} from \"./internal/modules\"\n\nexport class HmrError extends Schema.TaggedError<\n\tHmrError,\n\t{ readonly brand: unique symbol }\n>()(\"HmrError\", {\n\tstage: Schema.Literals([\"import\", \"exports\", \"closed\"]),\n\tspecifier: Schema.String,\n\tcause: Schema.Unknown,\n}) {\n\toverride get message(): string {\n\t\treturn `HMR ${this.stage} failed for ${this.specifier || \"the closed session\"}`\n\t}\n}\n\nexport type WatchResult = Data.TaggedEnum<{\n\tReloaded: { readonly entries: ReadonlyArray<string> }\n\tSkipped: {\n\t\treadonly modules: ReadonlyArray<string>\n\t\treadonly reason:\n\t\t\t\"restart-required\" | \"ambiguous-exports\" | \"identity-conflict\"\n\t}\n\tFailed: { readonly cause: Cause.Cause<HmrError> }\n}>\n\nexport const WatchResult = Data.taggedEnum<WatchResult>()\n\nexport type ReloadResult = Exclude<WatchResult, { readonly _tag: \"Failed\" }>\n\nexport interface Options {\n\t/** Application module URL, usually import.meta.url; used for bare and relative resolution. */\n\treadonly base: string\n\t/** Files to version. Defaults to file URLs outside node_modules. Entries are always included. */\n\treadonly include?: (url: string) => boolean\n}\n\nexport interface WatchOptions extends FileSystem.WatchOptions {\n\treadonly debounce?: Duration.Input\n\t/** Receives an absolute file path; applies to native events and reconciliation. */\n\treadonly filter?: (path: string) => boolean\n}\n\n/** Separates retry observations from an importer's temporary resource scope. */\nexport interface ImportOptions {\n\treadonly observationScope: Scope.Scope\n}\n\nexport interface Hmr {\n\t/** Keeps imported entries registered until this HMR session closes. */\n\treadonly importer: (specifier: string) => Promise<unknown>\n\t/** Uses the application context and Node cache, without watching or replacing the module. */\n\treadonly importModule: (specifier: string) => Effect.Effect<unknown, HmrError>\n\t/** Registers an observation lease in observationScope, or the caller's scope when omitted. */\n\treadonly importerScoped: (\n\t\tspecifier: string,\n\t\toptions?: ImportOptions,\n\t) => Effect.Effect<unknown, HmrError, Scope.Scope>\n\t/** Imports every entry before replacing anything. Activation failures belong to Graft. */\n\treadonly reload: Effect.Effect<ReloadResult, HmrError>\n\t/**\n\t * Consuming this stream installs graph-driven directory watchers, polls stat once\n\t * per second, and audits contents every ten seconds to recover missed events. Known native loading limitations emit\n\t * Skipped even without a file event. The consumer owns the stream's lifetimes.\n\t */\n\treadonly watch: (\n\t\tpaths: ReadonlyArray<string>,\n\t\toptions?: WatchOptions,\n\t) => Stream.Stream<\n\t\tWatchResult,\n\t\tPlatformError.PlatformError,\n\t\tFileSystem.FileSystem\n\t>\n}\n\n/**\n * Installs Node module hooks until the enclosing scope closes. Module evaluation\n * must be side-effect free. Versioned ESM cache entries are not reclaimed.\n */\nexport const make: (\n\toptions: Options,\n) => Effect.Effect<Hmr, never, Graft.Graft | Scope.Scope> = Effect.fnUntraced(\n\tfunction* (options: Options) {\n\t\tconst graft = yield* Graft.Graft\n\t\tconst semaphore = yield* Semaphore.make(1)\n\t\t// A lease owns both the running graph and its latest uncommitted attempt.\n\t\tconst owners = yield* Ref.make(\n\t\t\tHashMap.empty<\n\t\t\t\tsymbol,\n\t\t\t\t{\n\t\t\t\t\treadonly active: Option.Option<Attempt>\n\t\t\t\t\treadonly pending: Option.Option<Attempt>\n\t\t\t\t}\n\t\t\t>(),\n\t\t)\n\t\tconst closed = yield* Ref.make(false)\n\t\tconst session = yield* Effect.scope\n\t\t// Transfer the complete Exit before restoring interruption. Effect may replace\n\t\t// a failed masked operation with pending interruption at that boundary.\n\t\tconst preserveExit = Effect.fnUntraced(function* <A, E, R>(\n\t\t\teffect: Effect.Effect<A, E, R>,\n\t\t): Effect.fn.Return<A, E, R> {\n\t\t\tconst completed = yield* Deferred.make<Exit.Exit<A, E>>()\n\t\t\treturn yield* effect.pipe(\n\t\t\t\tEffect.exit,\n\t\t\t\tEffect.tap((exit) => Deferred.succeed(completed, exit)),\n\t\t\t\tEffect.uninterruptible,\n\t\t\t\tEffect.flatten,\n\t\t\t\tEffect.onExit(\n\t\t\t\t\tEffect.fnUntraced(function* (exit: Exit.Exit<A, E>) {\n\t\t\t\t\t\tif (Exit.isSuccess(exit) || !Cause.hasInterrupts(exit.cause)) return\n\t\t\t\t\t\tconst saved = yield* Deferred.poll(completed)\n\t\t\t\t\t\tif (Option.isNone(saved)) return\n\t\t\t\t\t\tconst original = yield* saved.value\n\t\t\t\t\t\tif (Exit.isFailure(original))\n\t\t\t\t\t\t\tyield* Effect.logError(\n\t\t\t\t\t\t\t\t\"HMR operation failed during cancellation\",\n\t\t\t\t\t\t\t\toriginal.cause,\n\t\t\t\t\t\t\t)\n\t\t\t\t\t}),\n\t\t\t\t),\n\t\t\t)\n\t\t})\n\t\t// Native imports cannot be cancelled: keep the lock until their promises settle.\n\t\tconst serial = <A, E, R>(effect: Effect.Effect<A, E, R>) =>\n\t\t\teffect.pipe(preserveExit, semaphore.withPermits(1))\n\t\tconst hooks = yield* Effect.acquireRelease(\n\t\t\tEffect.sync(() =>\n\t\t\t\tmodules(\n\t\t\t\t\toptions.base,\n\t\t\t\t\toptions.include ??\n\t\t\t\t\t\t((url) =>\n\t\t\t\t\t\t\t!String.includes(\"/node_modules/\")(new URL(url).pathname)),\n\t\t\t\t),\n\t\t\t),\n\t\t\t(hooks) =>\n\t\t\t\tserial(\n\t\t\t\t\tRef.set(closed, true).pipe(Effect.andThen(Effect.sync(hooks.close))),\n\t\t\t\t),\n\t\t)\n\t\t// Node can return a cached entry after its last observation lease closes.\n\t\t// Keep current entry attempts without polling or reloading unleased entries.\n\t\t// The hooks also retain cached instance facts for older resolution views.\n\t\tconst cached = yield* Ref.make(HashMap.empty<string, Attempt>())\n\n\t\tconst retryDirty = yield* Ref.make(HashSet.empty<string>())\n\t\tconst retryAll = yield* Ref.make(false)\n\t\tconst observations = Ref.get(owners).pipe(\n\t\t\tEffect.map((owners) =>\n\t\t\t\tArray.flatMap(HashMap.toValues(owners), (owner) =>\n\t\t\t\t\tArray.getSomes([owner.active, owner.pending]),\n\t\t\t\t),\n\t\t\t),\n\t\t)\n\t\tconst collect = Effect.gen(function* () {\n\t\t\tconst attempts = yield* observations\n\t\t\tconst currentCache = yield* Ref.get(cached)\n\t\t\thooks.collect([...attempts, ...HashMap.toValues(currentCache)])\n\t\t\tconst files = hooks.files(attempts)\n\t\t\tyield* Ref.update(\n\t\t\t\tretryDirty,\n\t\t\t\tHashSet.filter((url) => HashMap.has(files, url)),\n\t\t\t)\n\t\t\tif (attempts.length === 0) yield* Ref.set(retryAll, false)\n\t\t})\n\n\t\tconst state = yield* Ref.make({\n\t\t\tgeneration: hooks.prepare(),\n\t\t\tentries: HashMap.empty<\n\t\t\t\tstring,\n\t\t\t\t{\n\t\t\t\t\treadonly plugin: Plugin.Plugin\n\t\t\t\t\treadonly leases: HashSet.HashSet<symbol>\n\t\t\t\t}\n\t\t\t>(),\n\t\t})\n\t\t// Stop Promise-backed operations before releasing their leases. Otherwise\n\t\t// a lease finalizer could wait on an import before its owner interrupts it.\n\t\tconst imports = yield* Scope.fork(session)\n\t\tconst run = yield* FiberSet.makeRuntimePromise<never, unknown, HmrError>()\n\t\tconst closedError = () =>\n\t\t\tHmrError.make({\n\t\t\t\tstage: \"closed\",\n\t\t\t\tspecifier: \"\",\n\t\t\t\tcause: \"HMR scope is closed\",\n\t\t\t})\n\t\tconst checkOpen = Ref.get(closed).pipe(\n\t\t\tEffect.flatMap((closed) =>\n\t\t\t\tclosed ? Effect.fail(closedError()) : Effect.void,\n\t\t\t),\n\t\t)\n\t\tconst physicalTarget = (request: string) =>\n\t\t\tEffect.tryPromise({\n\t\t\t\ttry: () => realpath(fileURLToPath(request)),\n\t\t\t\tcatch: (cause) =>\n\t\t\t\t\tHmrError.make({ stage: \"import\", specifier: request, cause }),\n\t\t\t}).pipe(\n\t\t\t\tEffect.map((path) => pathToFileURL(path).href),\n\t\t\t\tEffect.catchIf(\n\t\t\t\t\t(error) => isMissingEntry(request, error.cause),\n\t\t\t\t\t() => Effect.undefined,\n\t\t\t\t),\n\t\t\t)\n\t\tconst changedResolution = Effect.fnUntraced(function* (\n\t\t\tattempt: Pick<Attempt, \"url\" | \"request\">,\n\t\t) {\n\t\t\tif (attempt.request === undefined) return Option.none<string>()\n\t\t\tconst request = attempt.request\n\t\t\tconst expected = pathToFileURL(fileURLToPath(attempt.url)).href\n\t\t\tconst actual = yield* physicalTarget(request)\n\t\t\tif (actual === expected) return Option.none<string>()\n\t\t\t// If both paths disappeared, this is ordinary entry deletion. A\n\t\t\t// missing link with a surviving old target must never reload that target.\n\t\t\tif (actual === undefined) {\n\t\t\t\tconst remaining = yield* physicalTarget(attempt.url)\n\t\t\t\tif (remaining === undefined) return Option.none<string>()\n\t\t\t}\n\t\t\treturn Option.some(request)\n\t\t})\n\n\t\tconst changedResolutions = Effect.gen(function* () {\n\t\t\tconst current = yield* Ref.get(owners)\n\t\t\tconst attempts = hooks.resolutions(\n\t\t\t\tArray.flatMap(HashMap.toValues(current), (owner) =>\n\t\t\t\t\tArray.getSomes([owner.active, owner.pending]),\n\t\t\t\t),\n\t\t\t)\n\t\t\tconst requests = HashSet.fromIterable(\n\t\t\t\tArray.filterMap(attempts, (attempt) =>\n\t\t\t\t\tattempt.request === undefined\n\t\t\t\t\t\t? Result.fail(undefined)\n\t\t\t\t\t\t: Result.succeed(attempt.request),\n\t\t\t\t),\n\t\t\t)\n\t\t\tconst resolveAll = (requests: HashSet.HashSet<string>) =>\n\t\t\t\tEffect.forEach(\n\t\t\t\t\trequests,\n\t\t\t\t\t(request) =>\n\t\t\t\t\t\tphysicalTarget(request).pipe(\n\t\t\t\t\t\t\tEffect.map((target) => [request, target] as const),\n\t\t\t\t\t\t),\n\t\t\t\t\t{ concurrency: 8 },\n\t\t\t\t).pipe(Effect.map(HashMap.fromIterable))\n\t\t\tconst actual = yield* resolveAll(requests)\n\t\t\tconst missingTargets = HashSet.fromIterable(\n\t\t\t\tArray.filterMap(attempts, (attempt) =>\n\t\t\t\t\tattempt.request !== undefined &&\n\t\t\t\t\tOption.getOrUndefined(HashMap.get(actual, attempt.request)) ===\n\t\t\t\t\t\tundefined &&\n\t\t\t\t\t!HashMap.has(actual, attempt.url)\n\t\t\t\t\t\t? Result.succeed(attempt.url)\n\t\t\t\t\t\t: Result.fail(undefined),\n\t\t\t\t),\n\t\t\t)\n\t\t\tconst remaining = yield* resolveAll(missingTargets)\n\t\t\tconst targets = HashMap.union(actual, remaining)\n\n\t\t\treturn Array.fromIterable(\n\t\t\t\tHashSet.fromIterable(\n\t\t\t\t\tArray.filterMap(attempts, (attempt) => {\n\t\t\t\t\t\tif (attempt.request === undefined) return Result.fail(undefined)\n\t\t\t\t\t\tconst actual = Option.getOrUndefined(\n\t\t\t\t\t\t\tHashMap.get(targets, attempt.request),\n\t\t\t\t\t\t)\n\t\t\t\t\t\tconst expected = pathToFileURL(fileURLToPath(attempt.url)).href\n\t\t\t\t\t\treturn actual === expected ||\n\t\t\t\t\t\t\t(actual === undefined &&\n\t\t\t\t\t\t\t\tOption.getOrUndefined(HashMap.get(targets, attempt.url)) ===\n\t\t\t\t\t\t\t\t\tundefined)\n\t\t\t\t\t\t\t? Result.fail(undefined)\n\t\t\t\t\t\t\t: Result.succeed(attempt.request)\n\t\t\t\t\t}),\n\t\t\t\t),\n\t\t\t)\n\t\t})\n\n\t\tconst load = Effect.fnUntraced(function* (specifier: string) {\n\t\t\tconst namespace = yield* Effect.tryPromise({\n\t\t\t\ttry: () => import(/* @vite-ignore */ hooks.request(specifier)),\n\t\t\t\t// The module hooks throw RestartRequired through import(); keep its tag.\n\t\t\t\tcatch: (cause) =>\n\t\t\t\t\tSchema.is(RestartRequired)(cause)\n\t\t\t\t\t\t? cause\n\t\t\t\t\t\t: HmrError.make({ stage: \"import\", specifier, cause }),\n\t\t\t})\n\t\t\tconst plugin = Plugin.fromModule(namespace)\n\t\t\tif (Option.isNone(plugin))\n\t\t\t\treturn yield* HmrError.make({\n\t\t\t\t\tstage: \"exports\",\n\t\t\t\t\tspecifier,\n\t\t\t\t\tcause: \"Expected a default or named plugin export\",\n\t\t\t\t})\n\t\t\tconst url = yield* Effect.fromOption(hooks.resolved()).pipe(\n\t\t\t\tEffect.mapError((cause) =>\n\t\t\t\t\tHmrError.make({ stage: \"import\", specifier, cause }),\n\t\t\t\t),\n\t\t\t)\n\t\t\tconst request = hooks.fileRequest(specifier)\n\t\t\tconst attempt = {\n\t\t\t\turl,\n\t\t\t\t...Option.match(request, {\n\t\t\t\t\tonNone: () => ({}),\n\t\t\t\t\tonSome: (request) => ({ request }),\n\t\t\t\t}),\n\t\t\t}\n\t\t\tconst changed = yield* changedResolution(attempt)\n\t\t\tif (Option.isSome(changed))\n\t\t\t\treturn yield* RestartRequired.make({ url: changed.value })\n\t\t\treturn { namespace, plugin: plugin.value, url }\n\t\t})\n\t\tconst acquireLease = Effect.fnUntraced(\n\t\t\tfunction* (specifier: string) {\n\t\t\t\tyield* checkOpen\n\t\t\t\tconst current = yield* Ref.get(state)\n\t\t\t\thooks.start(current.generation)\n\t\t\t\t// Acquire an owner for either Exit. Rethrow only after its finalizer\n\t\t\t\t// is registered, so failed imports remain available for scoped retry.\n\t\t\t\tconst exit = yield* Effect.exit(load(specifier))\n\t\t\t\tconst token: symbol = Symbol()\n\t\t\t\tconst root = Option.orElse(hooks.resolved(), () =>\n\t\t\t\t\tString.startsWith(\"file:\")(specifier)\n\t\t\t\t\t\t? Option.some(specifier)\n\t\t\t\t\t\t: Option.none(),\n\t\t\t\t)\n\t\t\t\tconst attempt = Option.map(root, (url) => ({\n\t\t\t\t\turl,\n\t\t\t\t\tgeneration: current.generation,\n\t\t\t\t\t...Option.match(hooks.fileRequest(specifier), {\n\t\t\t\t\t\tonNone: () => ({}),\n\t\t\t\t\t\tonSome: (request) => ({ request }),\n\t\t\t\t\t}),\n\t\t\t\t}))\n\t\t\t\tif (Option.isSome(attempt))\n\t\t\t\t\tyield* Ref.update(\n\t\t\t\t\t\tcached,\n\t\t\t\t\t\tHashMap.set(attempt.value.url, attempt.value),\n\t\t\t\t\t)\n\t\t\t\tyield* Ref.update(\n\t\t\t\t\towners,\n\t\t\t\t\tHashMap.set(token, {\n\t\t\t\t\t\tactive: Exit.isSuccess(exit) ? attempt : Option.none(),\n\t\t\t\t\t\tpending: Exit.isFailure(exit) ? attempt : Option.none(),\n\t\t\t\t\t}),\n\t\t\t\t)\n\t\t\t\tif (Exit.isSuccess(exit)) {\n\t\t\t\t\tconst entry = exit.value\n\t\t\t\t\tconst previous = HashMap.get(current.entries, entry.url)\n\t\t\t\t\tconst leases = Option.match(previous, {\n\t\t\t\t\t\tonNone: () => HashSet.empty<symbol>(),\n\t\t\t\t\t\tonSome: (entry) => entry.leases,\n\t\t\t\t\t})\n\t\t\t\t\tyield* Ref.set(state, {\n\t\t\t\t\t\t...current,\n\t\t\t\t\t\tentries: HashMap.set(current.entries, entry.url, {\n\t\t\t\t\t\t\tplugin: entry.plugin,\n\t\t\t\t\t\t\tleases: HashSet.add(leases, token),\n\t\t\t\t\t\t}),\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t\treturn { token, exit: Exit.map(exit, (entry) => entry.namespace) }\n\t\t\t},\n\t\t\tEffect.ensuring(Effect.sync(hooks.discard)),\n\t\t\tEffect.ensuring(collect),\n\t\t\tserial,\n\t\t)\n\t\tconst releaseLease = Effect.fnUntraced(\n\t\t\tfunction* ({ token }: { readonly token: symbol }) {\n\t\t\t\tyield* Ref.update(owners, HashMap.remove(token))\n\t\t\t\tyield* Ref.update(state, (current) => ({\n\t\t\t\t\t...current,\n\t\t\t\t\tentries: HashMap.filterMap(current.entries, (entry) => {\n\t\t\t\t\t\tconst leases = HashSet.remove(entry.leases, token)\n\t\t\t\t\t\treturn HashSet.size(leases) === 0\n\t\t\t\t\t\t\t? Result.fail(undefined)\n\t\t\t\t\t\t\t: Result.succeed({ ...entry, leases })\n\t\t\t\t\t}),\n\t\t\t\t}))\n\t\t\t},\n\t\t\tEffect.ensuring(collect),\n\t\t\tserial,\n\t\t)\n\t\tconst importWithLease = (specifier: string) =>\n\t\t\tEffect.acquireRelease(acquireLease(specifier), releaseLease).pipe(\n\t\t\t\tEffect.flatMap(({ exit }) => exit),\n\t\t\t\t// Importers cannot act on a restart; reloadChanged handles it by tag.\n\t\t\t\tEffect.catchTag(\"RestartRequired\", (cause) =>\n\t\t\t\t\tEffect.fail(HmrError.make({ stage: \"import\", specifier, cause })),\n\t\t\t\t),\n\t\t\t\tpreserveExit,\n\t\t\t)\n\n\t\tconst importModule: Hmr[\"importModule\"] = (specifier) =>\n\t\t\tserial(\n\t\t\t\tcheckOpen.pipe(\n\t\t\t\t\tEffect.andThen(\n\t\t\t\t\t\tEffect.tryPromise({\n\t\t\t\t\t\t\ttry: () => import(/* @vite-ignore */ hooks.rawRequest(specifier)),\n\t\t\t\t\t\t\tcatch: (cause) =>\n\t\t\t\t\t\t\t\tHmrError.make({ stage: \"import\", specifier, cause }),\n\t\t\t\t\t\t}),\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\t)\n\n\t\tconst importerScoped: Hmr[\"importerScoped\"] = (specifier, options) =>\n\t\t\toptions === undefined\n\t\t\t\t? importWithLease(specifier)\n\t\t\t\t: importWithLease(specifier).pipe(\n\t\t\t\t\t\tScope.provide(options.observationScope),\n\t\t\t\t\t)\n\n\t\tconst importer = (specifier: string): Promise<unknown> =>\n\t\t\t// A closed FiberSet interrupts new work before checkOpen can execute.\n\t\t\tRef.getUnsafe(closed)\n\t\t\t\t? Promise.reject(closedError())\n\t\t\t\t: run(\n\t\t\t\t\t\timporterScoped(specifier).pipe(\n\t\t\t\t\t\t\tEffect.provideService(Scope.Scope, imports),\n\t\t\t\t\t\t),\n\t\t\t\t\t)\n\n\t\tconst unsupportedAttempts = (attempts: ReadonlyArray<Attempt>) =>\n\t\t\tArray.reduce(attempts, HashSet.empty<string>(), (all, attempt) =>\n\t\t\t\tHashSet.union(\n\t\t\t\t\tall,\n\t\t\t\t\thooks.unsupported(attempt.generation, [attempt.url]),\n\t\t\t\t),\n\t\t\t)\n\t\tconst unsupportedModules = Ref.get(owners).pipe(\n\t\t\tEffect.map((owned) =>\n\t\t\t\tunsupportedAttempts(\n\t\t\t\t\tArray.getSomes(\n\t\t\t\t\t\tArray.map(HashMap.toValues(owned), (owner) => owner.active),\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\t),\n\t\t)\n\n\t\tconst reloadChanged = Effect.fnUntraced(function* (\n\t\t\tdirty: HashSet.HashSet<string> | undefined,\n\t\t) {\n\t\t\tyield* checkOpen\n\t\t\tconst fullRetry = yield* Ref.get(retryAll)\n\t\t\tconst force = dirty === undefined || fullRetry\n\t\t\tconst pendingDirty = yield* Ref.get(retryDirty)\n\t\t\tconst changedFiles =\n\t\t\t\tdirty === undefined ? pendingDirty : HashSet.union(pendingDirty, dirty)\n\t\t\tyield* Ref.set(retryDirty, changedFiles)\n\t\t\tyield* Ref.set(retryAll, force)\n\t\t\tconst changed = yield* changedResolutions\n\t\t\tif (changed.length > 0)\n\t\t\t\treturn WatchResult.Skipped({\n\t\t\t\t\treason: \"restart-required\",\n\t\t\t\t\tmodules: changed,\n\t\t\t\t})\n\t\t\tconst { entries } = yield* Ref.get(state)\n\t\t\tconst unsupported = yield* unsupportedModules\n\t\t\tif (HashSet.size(unsupported) > 0)\n\t\t\t\treturn WatchResult.Skipped({\n\t\t\t\t\tmodules: Array.fromIterable(unsupported),\n\t\t\t\t\treason: \"restart-required\",\n\t\t\t\t})\n\t\t\tconst owned = yield* Ref.get(owners)\n\t\t\tconst attempts = Array.flatMap(HashMap.toValues(owned), (owner) =>\n\t\t\t\tArray.getSomes([owner.active, owner.pending]),\n\t\t\t)\n\t\t\tconst active = Array.getSomes(\n\t\t\t\tArray.map(HashMap.toValues(owned), (owner) => owner.active),\n\t\t\t)\n\t\t\tlet selected = entries\n\t\t\tlet invalid = HashSet.empty<string>()\n\t\t\tif (!force) {\n\t\t\t\tlet affected = changedFiles\n\t\t\t\t// Plugin identity groups and importer closure can expand each other.\n\t\t\t\t// Reach a fixed point before allocating any candidate instance.\n\t\t\t\twhile (true) {\n\t\t\t\t\tinvalid = hooks.invalidated(attempts, affected)\n\t\t\t\t\tconst plugins = HashSet.fromIterable(\n\t\t\t\t\t\tArray.filterMap(Array.fromIterable(entries), ([url, entry]) =>\n\t\t\t\t\t\t\tHashSet.has(affected, url) ||\n\t\t\t\t\t\t\tArray.some(Array.fromIterable(entry.leases), (token) =>\n\t\t\t\t\t\t\t\tOption.exists(HashMap.get(owned, token), (owner) =>\n\t\t\t\t\t\t\t\t\tArray.some(\n\t\t\t\t\t\t\t\t\t\tArray.getSomes([owner.active, owner.pending]),\n\t\t\t\t\t\t\t\t\t\t(attempt) => hooks.affected(attempt, invalid),\n\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t? Result.succeed(entry.plugin)\n\t\t\t\t\t\t\t\t: Result.fail(undefined),\n\t\t\t\t\t\t),\n\t\t\t\t\t)\n\t\t\t\t\tselected = HashMap.filter(entries, (entry) =>\n\t\t\t\t\t\tHashSet.has(plugins, entry.plugin),\n\t\t\t\t\t)\n\t\t\t\t\tconst expanded = HashSet.union(\n\t\t\t\t\t\taffected,\n\t\t\t\t\t\tHashSet.fromIterable(HashMap.keys(selected)),\n\t\t\t\t\t)\n\t\t\t\t\tif (HashSet.size(expanded) === HashSet.size(affected)) break\n\t\t\t\t\taffected = expanded\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Advance even without entries so retries bypass cached failed imports.\n\t\t\tconst candidate = force ? hooks.prepare() : hooks.prepare(active, invalid)\n\n\t\t\thooks.start(candidate, true)\n\t\t\treturn yield* Effect.gen(function* () {\n\t\t\t\tconst loaded = yield* Effect.forEach(selected, ([url, previous]) =>\n\t\t\t\t\tRef.update(\n\t\t\t\t\t\towners,\n\t\t\t\t\t\tHashMap.map((owner, token) =>\n\t\t\t\t\t\t\tHashSet.has(previous.leases, token)\n\t\t\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\t\t\t...owner,\n\t\t\t\t\t\t\t\t\t\tpending: Option.map(owner.active, (attempt) => ({\n\t\t\t\t\t\t\t\t\t\t\t...attempt,\n\t\t\t\t\t\t\t\t\t\t\turl,\n\t\t\t\t\t\t\t\t\t\t\tgeneration: candidate,\n\t\t\t\t\t\t\t\t\t\t})),\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t: owner,\n\t\t\t\t\t\t),\n\t\t\t\t\t).pipe(\n\t\t\t\t\t\tEffect.andThen(load(url)),\n\t\t\t\t\t\tEffect.map((entry) =>\n\t\t\t\t\t\t\tOption.some({\n\t\t\t\t\t\t\t\turl,\n\t\t\t\t\t\t\t\tprevious: previous.plugin,\n\t\t\t\t\t\t\t\tleases: previous.leases,\n\t\t\t\t\t\t\t\tplugin: entry.plugin,\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t),\n\t\t\t\t\t\tEffect.catchIf(\n\t\t\t\t\t\t\t(error) =>\n\t\t\t\t\t\t\t\terror._tag === \"HmrError\" &&\n\t\t\t\t\t\t\t\terror.stage === \"import\" &&\n\t\t\t\t\t\t\t\tisMissingEntry(url, error.cause),\n\t\t\t\t\t\t\t() => Effect.succeedNone,\n\t\t\t\t\t\t),\n\t\t\t\t\t),\n\t\t\t\t)\n\t\t\t\tconst candidates = Array.getSomes(loaded)\n\t\t\t\tconst alternatives = Array.reduce(\n\t\t\t\t\tcandidates,\n\t\t\t\t\tHashMap.empty<Plugin.Plugin, HashSet.HashSet<Plugin.Plugin>>(),\n\t\t\t\t\t(groups, { previous, plugin }) =>\n\t\t\t\t\t\tHashMap.set(\n\t\t\t\t\t\t\tgroups,\n\t\t\t\t\t\t\tprevious,\n\t\t\t\t\t\t\tHashSet.add(\n\t\t\t\t\t\t\t\tOption.getOrElse(\n\t\t\t\t\t\t\t\t\tHashMap.get(groups, previous),\n\t\t\t\t\t\t\t\t\tHashSet.empty<Plugin.Plugin>,\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\tplugin,\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t),\n\t\t\t\t)\n\t\t\t\tconst ambiguous = Array.filter(candidates, ({ previous }) =>\n\t\t\t\t\tOption.exists(\n\t\t\t\t\t\tHashMap.get(alternatives, previous),\n\t\t\t\t\t\t(plugins) => HashSet.size(plugins) > 1,\n\t\t\t\t\t),\n\t\t\t\t)\n\t\t\t\tif (ambiguous.length > 0)\n\t\t\t\t\treturn WatchResult.Skipped({\n\t\t\t\t\t\treason: \"ambiguous-exports\",\n\t\t\t\t\t\tmodules: Array.map(ambiguous, ({ url }) => url),\n\t\t\t\t\t})\n\t\t\t\tconst replacements = HashMap.fromIterable(\n\t\t\t\t\tArray.map(\n\t\t\t\t\t\tcandidates,\n\t\t\t\t\t\t({ url, plugin, leases }) => [url, { plugin, leases }] as const,\n\t\t\t\t\t),\n\t\t\t\t)\n\t\t\t\t// A missing entry still owns its running plugin until the last lease closes.\n\t\t\t\tconst next = HashMap.union(entries, replacements)\n\n\t\t\t\tconst pairs = Array.map(\n\t\t\t\t\tcandidates,\n\t\t\t\t\t({ previous, plugin }) => [previous, plugin] as const,\n\t\t\t\t)\n\t\t\t\tconst changed = yield* changedResolutions\n\t\t\t\tif (changed.length > 0)\n\t\t\t\t\treturn WatchResult.Skipped({\n\t\t\t\t\t\treason: \"restart-required\",\n\t\t\t\t\t\tmodules: changed,\n\t\t\t\t\t})\n\t\t\t\t// A reused instance can acquire a native loading capability while the\n\t\t\t\t// candidate imports. Observe it without throwing into concurrent old code.\n\t\t\t\tconst unsafe = unsupportedAttempts(\n\t\t\t\t\tArray.map(active, (attempt) =>\n\t\t\t\t\t\tHashMap.has(replacements, attempt.url)\n\t\t\t\t\t\t\t? { ...attempt, generation: candidate }\n\t\t\t\t\t\t\t: attempt,\n\t\t\t\t\t),\n\t\t\t\t)\n\t\t\t\tif (HashSet.size(unsafe) > 0)\n\t\t\t\t\treturn WatchResult.Skipped({\n\t\t\t\t\t\treason: \"restart-required\",\n\t\t\t\t\t\tmodules: Array.fromIterable(unsafe),\n\t\t\t\t\t})\n\n\t\t\t\tconst replacement = yield* Graft.replace(pairs).pipe(\n\t\t\t\t\tEffect.provideService(Graft.Graft, graft),\n\t\t\t\t\tEffect.result,\n\t\t\t\t)\n\t\t\t\tif (Result.isFailure(replacement))\n\t\t\t\t\treturn WatchResult.Skipped({\n\t\t\t\t\t\treason: \"identity-conflict\",\n\t\t\t\t\t\tmodules: Array.filterMap(candidates, ({ url }, index) =>\n\t\t\t\t\t\t\tArray.contains(replacement.failure.indices, index)\n\t\t\t\t\t\t\t\t? Result.succeed(url)\n\t\t\t\t\t\t\t\t: Result.fail(undefined),\n\t\t\t\t\t\t),\n\t\t\t\t\t})\n\t\t\t\tyield* Ref.update(owners, (owners) =>\n\t\t\t\t\tArray.reduce(candidates, owners, (owners, { url, leases }) =>\n\t\t\t\t\t\tHashMap.map(owners, (owner, token) =>\n\t\t\t\t\t\t\tHashSet.has(leases, token)\n\t\t\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\t\t\tactive: Option.map(owner.pending, (attempt) => ({\n\t\t\t\t\t\t\t\t\t\t\t...attempt,\n\t\t\t\t\t\t\t\t\t\t\turl,\n\t\t\t\t\t\t\t\t\t\t\tgeneration: candidate,\n\t\t\t\t\t\t\t\t\t\t})),\n\t\t\t\t\t\t\t\t\t\tpending: Option.none(),\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t: owner,\n\t\t\t\t\t\t),\n\t\t\t\t\t),\n\t\t\t\t)\n\t\t\t\tyield* Ref.set(state, { entries: next, generation: candidate })\n\t\t\t\tyield* Ref.update(cached, (cached) =>\n\t\t\t\t\tHashMap.union(\n\t\t\t\t\t\tHashMap.filter(cached, (_, url) => HashMap.has(next, url)),\n\t\t\t\t\t\tHashMap.map(replacements, (_, url) => ({\n\t\t\t\t\t\t\turl,\n\t\t\t\t\t\t\tgeneration: candidate,\n\t\t\t\t\t\t})),\n\t\t\t\t\t),\n\t\t\t\t)\n\t\t\t\tyield* Ref.set(retryDirty, HashSet.empty())\n\t\t\t\tyield* Ref.set(retryAll, false)\n\t\t\t\treturn WatchResult.Reloaded({\n\t\t\t\t\tentries: Array.map(candidates, (candidate) => candidate.url),\n\t\t\t\t})\n\t\t\t}).pipe(\n\t\t\t\tEffect.catchTag(\"RestartRequired\", (error) =>\n\t\t\t\t\tEffect.succeed(\n\t\t\t\t\t\tWatchResult.Skipped({\n\t\t\t\t\t\t\tmodules: Array.fromIterable(\n\t\t\t\t\t\t\t\tHashSet.add(hooks.unsupported(candidate), error.url),\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\treason: \"restart-required\",\n\t\t\t\t\t\t}),\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\t\tEffect.ensuring(Effect.sync(hooks.discard)),\n\t\t\t\tEffect.ensuring(collect),\n\t\t\t)\n\t\t}, serial)\n\t\treturn {\n\t\t\timporter,\n\t\t\timporterScoped,\n\t\t\timportModule,\n\t\t\treload: reloadChanged(undefined),\n\t\t\twatch: (paths, watchOptions) =>\n\t\t\t\tpaths.length === 0\n\t\t\t\t\t? Stream.empty\n\t\t\t\t\t: changes(\n\t\t\t\t\t\t\t(use) =>\n\t\t\t\t\t\t\t\tRef.get(owners).pipe(\n\t\t\t\t\t\t\t\t\tEffect.map((owners) =>\n\t\t\t\t\t\t\t\t\t\thooks.files([\n\t\t\t\t\t\t\t\t\t\t\t...Array.getSomes(\n\t\t\t\t\t\t\t\t\t\t\t\tArray.map(\n\t\t\t\t\t\t\t\t\t\t\t\t\tHashMap.toValues(owners),\n\t\t\t\t\t\t\t\t\t\t\t\t\t(owner) => owner.active,\n\t\t\t\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\t\t\t...Array.getSomes(\n\t\t\t\t\t\t\t\t\t\t\t\tArray.map(\n\t\t\t\t\t\t\t\t\t\t\t\t\tHashMap.toValues(owners),\n\t\t\t\t\t\t\t\t\t\t\t\t\t(owner) => owner.pending,\n\t\t\t\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\t\t]),\n\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\tEffect.flatMap(use),\n\t\t\t\t\t\t\t\t\t// Only snapshot and validation callbacks run under the lock.\n\t\t\t\t\t\t\t\t\t// File reads operate on the retained immutable snapshot outside it.\n\t\t\t\t\t\t\t\t\tsemaphore.withPermits(1),\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\tpaths,\n\t\t\t\t\t\t\twatchOptions,\n\t\t\t\t\t\t).pipe(\n\t\t\t\t\t\t\tStream.mapEffect((dirty) =>\n\t\t\t\t\t\t\t\tEffect.map(\n\t\t\t\t\t\t\t\t\tEffect.exit(reloadChanged(dirty)),\n\t\t\t\t\t\t\t\t\t(exit): WatchResult =>\n\t\t\t\t\t\t\t\t\t\tExit.isSuccess(exit)\n\t\t\t\t\t\t\t\t\t\t\t? exit.value\n\t\t\t\t\t\t\t\t\t\t\t: WatchResult.Failed({ cause: exit.cause }),\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t// Native caches may hide both dependency edges and the first save.\n\t\t\t\t\t\t\t// Report known restart requirements independently of filesystem events.\n\t\t\t\t\t\t\tStream.merge(\n\t\t\t\t\t\t\t\tStream.tick(\"1 second\").pipe(\n\t\t\t\t\t\t\t\t\tStream.mapEffect(() =>\n\t\t\t\t\t\t\t\t\t\tunsupportedModules.pipe(semaphore.withPermits(1)),\n\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\tStream.changes,\n\t\t\t\t\t\t\t\t\tStream.filter((modules) => HashSet.size(modules) > 0),\n\t\t\t\t\t\t\t\t\tStream.map((modules) =>\n\t\t\t\t\t\t\t\t\t\tWatchResult.Skipped({\n\t\t\t\t\t\t\t\t\t\t\treason: \"restart-required\",\n\t\t\t\t\t\t\t\t\t\t\tmodules: Array.fromIterable(modules),\n\t\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t),\n\t\t}\n\t},\n)\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["SourceObservation.make"],"sources":["../src/index.ts"],"sourcesContent":["/**\n * Hot module replacement for Graft plugins on Node.js.\n */\n// @effect-diagnostics-next-line nodeBuiltinImport:off -- native import resolution must work without requiring a platform layer\nimport { realpath } from \"node:fs/promises\"\nimport { fileURLToPath, pathToFileURL } from \"node:url\"\n\nimport {\n\tArray,\n\tCause,\n\tData,\n\tDeferred,\n\tEffect,\n\tExit,\n\tFiberSet,\n\tFileSystem,\n\tHashMap,\n\tHashSet,\n\tOption,\n\tRef,\n\tResult,\n\tSchema,\n\tScope,\n\tSemaphore,\n\tStream,\n\tString,\n\ttype Duration,\n\ttype PlatformError,\n} from \"effect\"\n\nimport { Graft, Plugin } from \"@graftland/graft\"\n\nimport { changes } from \"./internal/changes\"\nimport { digest } from \"./internal/digest\"\nimport {\n\tisMissingEntry,\n\tmodules,\n\tRestartRequired,\n\ttype Attempt,\n\ttype FileVersion,\n} from \"./internal/modules\"\nimport * as SourceObservation from \"./internal/sourceObservation\"\n\nexport class HmrError extends Schema.TaggedError<\n\tHmrError,\n\t{ readonly brand: unique symbol }\n>()(\"HmrError\", {\n\tstage: Schema.Literals([\"import\", \"exports\", \"closed\"]),\n\tspecifier: Schema.String,\n\tcause: Schema.Unknown,\n}) {\n\toverride get message(): string {\n\t\treturn `HMR ${this.stage} failed for ${this.specifier || \"the closed session\"}`\n\t}\n}\n\nexport type WatchResult = Data.TaggedEnum<{\n\tReloaded: { readonly entries: ReadonlyArray<string> }\n\tSkipped: {\n\t\treadonly modules: ReadonlyArray<string>\n\t\treadonly reason:\n\t\t\t\"restart-required\" | \"ambiguous-exports\" | \"identity-conflict\"\n\t}\n\tFailed: { readonly cause: Cause.Cause<HmrError> }\n}>\n\nexport const WatchResult = Data.taggedEnum<WatchResult>()\n\nexport type ReloadResult = Exclude<WatchResult, { readonly _tag: \"Failed\" }>\n\nexport interface Options {\n\t/** Application module URL, usually import.meta.url; used for bare and relative resolution. */\n\treadonly base: string\n\t/** Files to version. Defaults to file URLs outside node_modules. Entries are always included. */\n\treadonly include?: (url: string) => boolean\n}\n\nexport interface WatchOptions extends FileSystem.WatchOptions {\n\treadonly debounce?: Duration.Input\n\t/** Receives an absolute file path; applies to native events and reconciliation. */\n\treadonly filter?: (path: string) => boolean\n}\n\n/** Separates retry observations from an importer's temporary resource scope. */\nexport interface ImportOptions {\n\treadonly observationScope: Scope.Scope\n}\n\n/** An entry-owned observation collection; successful imports replace old dependencies, failures retain them. */\nexport interface Observation {\n\treadonly scope: Scope.Scope\n\t/** Files registered by one activation accumulate; the next activation's files replace them. */\n\treadonly watch: (\n\t\tfiles: ReadonlyArray<string>,\n\t\tactivation: Scope.Scope,\n\t) => Effect.Effect<void, PlatformError.PlatformError>\n\treadonly changes: Stream.Stream<void>\n}\n\nexport interface Hmr {\n\t/** Makes a collection independent of individual activation and retry scopes. */\n\treadonly observation: Effect.Effect<\n\t\tObservation,\n\t\tnever,\n\t\tScope.Scope | FileSystem.FileSystem\n\t>\n\t/** Keeps imported entries registered until this HMR session closes. */\n\treadonly importer: (specifier: string) => Promise<unknown>\n\t/** Uses the application context and Node cache, without watching or replacing the module. */\n\treadonly importModule: (specifier: string) => Effect.Effect<unknown, HmrError>\n\t/** Imports a fresh non-plugin graph in the caller's scope; failed observations survive in observationScope when supplied. */\n\treadonly importModuleScoped: (\n\t\tspecifier: string,\n\t\toptions?: ImportOptions,\n\t) => Effect.Effect<unknown, HmrError, Scope.Scope>\n\t/** Observes file URLs and dependencies of leased modules without importing the other files. */\n\treadonly observe: (\n\t\tfiles: ReadonlyArray<string>,\n\t) => Stream.Stream<void, PlatformError.PlatformError, FileSystem.FileSystem>\n\t/** Registers an observation lease in observationScope, or the caller's scope when omitted. */\n\treadonly importerScoped: (\n\t\tspecifier: string,\n\t\toptions?: ImportOptions,\n\t) => Effect.Effect<unknown, HmrError, Scope.Scope>\n\t/** Imports every entry before replacing anything. Activation failures belong to Graft. */\n\treadonly reload: Effect.Effect<ReloadResult, HmrError>\n\t/**\n\t * Consuming this stream installs graph-driven directory watchers, polls stat once\n\t * per second, and audits contents every ten seconds to recover missed events. Known native loading limitations emit\n\t * Skipped even without a file event. The consumer owns the stream's lifetimes.\n\t */\n\treadonly watch: (\n\t\tpaths: ReadonlyArray<string>,\n\t\toptions?: WatchOptions,\n\t) => Stream.Stream<\n\t\tWatchResult,\n\t\tPlatformError.PlatformError,\n\t\tFileSystem.FileSystem\n\t>\n}\n\n/**\n * Installs Node module hooks until the enclosing scope closes. Module evaluation\n * must be side-effect free. Versioned ESM cache entries are not reclaimed.\n */\nexport const make: (\n\toptions: Options,\n) => Effect.Effect<Hmr, never, Graft.Graft | Scope.Scope> = Effect.fnUntraced(\n\tfunction* (options: Options) {\n\t\tconst graft = yield* Graft.Graft\n\t\tconst semaphore = yield* Semaphore.make(1)\n\t\t// A lease owns both the running graph and its latest uncommitted attempt.\n\t\tconst owners = yield* Ref.make(\n\t\t\tHashMap.empty<\n\t\t\t\tsymbol,\n\t\t\t\t{\n\t\t\t\t\treadonly active: Option.Option<Attempt>\n\t\t\t\t\treadonly pending: Option.Option<Attempt>\n\t\t\t\t}\n\t\t\t>(),\n\t\t)\n\t\tconst sourceObservers = yield* Ref.make<\n\t\t\tReadonlyArray<Effect.Success<ReturnType<typeof SourceObservation.make>>>\n\t\t>([])\n\t\tconst observation = Effect.gen(function* () {\n\t\t\tconst source = yield* SourceObservation.make()\n\t\t\tyield* Effect.acquireRelease(\n\t\t\t\tRef.update(sourceObservers, Array.append(source)),\n\t\t\t\t() =>\n\t\t\t\t\tRef.update(\n\t\t\t\t\t\tsourceObservers,\n\t\t\t\t\t\tArray.filter((current) => current !== source),\n\t\t\t\t\t),\n\t\t\t)\n\t\t\treturn source\n\t\t})\n\t\tconst closed = yield* Ref.make(false)\n\t\tconst session = yield* Effect.scope\n\t\t// Transfer the complete Exit before restoring interruption. Effect may replace\n\t\t// a failed masked operation with pending interruption at that boundary.\n\t\tconst preserveExit = Effect.fnUntraced(function* <A, E, R>(\n\t\t\teffect: Effect.Effect<A, E, R>,\n\t\t): Effect.fn.Return<A, E, R> {\n\t\t\tconst completed = yield* Deferred.make<Exit.Exit<A, E>>()\n\t\t\treturn yield* effect.pipe(\n\t\t\t\tEffect.exit,\n\t\t\t\tEffect.tap((exit) => Deferred.succeed(completed, exit)),\n\t\t\t\tEffect.uninterruptible,\n\t\t\t\tEffect.flatten,\n\t\t\t\tEffect.onExit(\n\t\t\t\t\tEffect.fnUntraced(function* (exit: Exit.Exit<A, E>) {\n\t\t\t\t\t\tif (Exit.isSuccess(exit) || !Cause.hasInterrupts(exit.cause)) return\n\t\t\t\t\t\tconst saved = yield* Deferred.poll(completed)\n\t\t\t\t\t\tif (Option.isNone(saved)) return\n\t\t\t\t\t\tconst original = yield* saved.value\n\t\t\t\t\t\tif (Exit.isFailure(original))\n\t\t\t\t\t\t\tyield* Effect.logError(\n\t\t\t\t\t\t\t\t\"HMR operation failed during cancellation\",\n\t\t\t\t\t\t\t\toriginal.cause,\n\t\t\t\t\t\t\t)\n\t\t\t\t\t}),\n\t\t\t\t),\n\t\t\t)\n\t\t})\n\t\t// Native imports cannot be cancelled: keep the lock until their promises settle.\n\t\tconst serial = <A, E, R>(effect: Effect.Effect<A, E, R>) =>\n\t\t\teffect.pipe(preserveExit, semaphore.withPermits(1))\n\t\tconst hooks = yield* Effect.acquireRelease(\n\t\t\tEffect.sync(() =>\n\t\t\t\tmodules(\n\t\t\t\t\toptions.base,\n\t\t\t\t\toptions.include ??\n\t\t\t\t\t\t((url) =>\n\t\t\t\t\t\t\t!String.includes(\"/node_modules/\")(new URL(url).pathname)),\n\t\t\t\t),\n\t\t\t),\n\t\t\t(hooks) =>\n\t\t\t\tserial(\n\t\t\t\t\tRef.set(closed, true).pipe(Effect.andThen(Effect.sync(hooks.close))),\n\t\t\t\t),\n\t\t)\n\t\t// Node can return a cached entry after its last observation lease closes.\n\t\t// Keep current entry attempts without polling or reloading unleased entries.\n\t\t// The hooks also retain cached instance facts for older resolution views.\n\t\tconst cached = yield* Ref.make(HashMap.empty<string, Attempt>())\n\n\t\tconst retryDirty = yield* Ref.make(HashSet.empty<string>())\n\t\tconst retryAll = yield* Ref.make(false)\n\t\tconst observations = Ref.get(owners).pipe(\n\t\t\tEffect.map((owners) =>\n\t\t\t\tArray.flatMap(HashMap.toValues(owners), (owner) =>\n\t\t\t\t\tArray.getSomes([owner.active, owner.pending]),\n\t\t\t\t),\n\t\t\t),\n\t\t)\n\t\tconst collect = Effect.gen(function* () {\n\t\t\tconst attempts = yield* observations\n\t\t\tconst currentCache = yield* Ref.get(cached)\n\t\t\thooks.collect([...attempts, ...HashMap.toValues(currentCache)])\n\t\t\tconst files = hooks.files(attempts)\n\t\t\tyield* Ref.update(\n\t\t\t\tretryDirty,\n\t\t\t\tHashSet.filter((url) => HashMap.has(files, url)),\n\t\t\t)\n\t\t\tif (attempts.length === 0) yield* Ref.set(retryAll, false)\n\t\t})\n\n\t\tconst state = yield* Ref.make({\n\t\t\tgeneration: hooks.prepare(),\n\t\t\tentries: HashMap.empty<\n\t\t\t\tstring,\n\t\t\t\t{\n\t\t\t\t\treadonly plugin: Plugin.Plugin\n\t\t\t\t\treadonly leases: HashSet.HashSet<symbol>\n\t\t\t\t}\n\t\t\t>(),\n\t\t})\n\t\t// Stop Promise-backed operations before releasing their leases. Otherwise\n\t\t// a lease finalizer could wait on an import before its owner interrupts it.\n\t\tconst imports = yield* Scope.fork(session)\n\t\tconst run = yield* FiberSet.makeRuntimePromise<never, unknown, HmrError>()\n\t\tconst closedError = () =>\n\t\t\tHmrError.make({\n\t\t\t\tstage: \"closed\",\n\t\t\t\tspecifier: \"\",\n\t\t\t\tcause: \"HMR scope is closed\",\n\t\t\t})\n\t\tconst checkOpen = Ref.get(closed).pipe(\n\t\t\tEffect.flatMap((closed) =>\n\t\t\t\tclosed ? Effect.fail(closedError()) : Effect.void,\n\t\t\t),\n\t\t)\n\t\tconst physicalTarget = (request: string) =>\n\t\t\tEffect.tryPromise({\n\t\t\t\ttry: () => realpath(fileURLToPath(request)),\n\t\t\t\tcatch: (cause) =>\n\t\t\t\t\tHmrError.make({ stage: \"import\", specifier: request, cause }),\n\t\t\t}).pipe(\n\t\t\t\tEffect.map((path) => pathToFileURL(path).href),\n\t\t\t\tEffect.catchIf(\n\t\t\t\t\t(error) => isMissingEntry(request, error.cause),\n\t\t\t\t\t() => Effect.undefined,\n\t\t\t\t),\n\t\t\t)\n\t\tconst changedResolution = Effect.fnUntraced(function* (\n\t\t\tattempt: Pick<Attempt, \"url\" | \"request\">,\n\t\t) {\n\t\t\tif (attempt.request === undefined) return Option.none<string>()\n\t\t\tconst request = attempt.request\n\t\t\tconst expected = pathToFileURL(fileURLToPath(attempt.url)).href\n\t\t\tconst actual = yield* physicalTarget(request)\n\t\t\tif (actual === expected) return Option.none<string>()\n\t\t\t// If both paths disappeared, this is ordinary entry deletion. A\n\t\t\t// missing link with a surviving old target must never reload that target.\n\t\t\tif (actual === undefined) {\n\t\t\t\tconst remaining = yield* physicalTarget(attempt.url)\n\t\t\t\tif (remaining === undefined) return Option.none<string>()\n\t\t\t}\n\t\t\treturn Option.some(request)\n\t\t})\n\n\t\tconst changedResolutions = Effect.gen(function* () {\n\t\t\tconst current = yield* Ref.get(owners)\n\t\t\tconst attempts = hooks.resolutions(\n\t\t\t\tArray.flatMap(HashMap.toValues(current), (owner) =>\n\t\t\t\t\tArray.getSomes([owner.active, owner.pending]),\n\t\t\t\t),\n\t\t\t)\n\t\t\tconst requests = HashSet.fromIterable(\n\t\t\t\tArray.filterMap(attempts, (attempt) =>\n\t\t\t\t\tattempt.request === undefined\n\t\t\t\t\t\t? Result.fail(undefined)\n\t\t\t\t\t\t: Result.succeed(attempt.request),\n\t\t\t\t),\n\t\t\t)\n\t\t\tconst resolveAll = (requests: HashSet.HashSet<string>) =>\n\t\t\t\tEffect.forEach(\n\t\t\t\t\trequests,\n\t\t\t\t\t(request) =>\n\t\t\t\t\t\tphysicalTarget(request).pipe(\n\t\t\t\t\t\t\tEffect.map((target) => [request, target] as const),\n\t\t\t\t\t\t),\n\t\t\t\t\t{ concurrency: 8 },\n\t\t\t\t).pipe(Effect.map(HashMap.fromIterable))\n\t\t\tconst actual = yield* resolveAll(requests)\n\t\t\tconst missingTargets = HashSet.fromIterable(\n\t\t\t\tArray.filterMap(attempts, (attempt) =>\n\t\t\t\t\tattempt.request !== undefined &&\n\t\t\t\t\tOption.getOrUndefined(HashMap.get(actual, attempt.request)) ===\n\t\t\t\t\t\tundefined &&\n\t\t\t\t\t!HashMap.has(actual, attempt.url)\n\t\t\t\t\t\t? Result.succeed(attempt.url)\n\t\t\t\t\t\t: Result.fail(undefined),\n\t\t\t\t),\n\t\t\t)\n\t\t\tconst remaining = yield* resolveAll(missingTargets)\n\t\t\tconst targets = HashMap.union(actual, remaining)\n\n\t\t\treturn Array.fromIterable(\n\t\t\t\tHashSet.fromIterable(\n\t\t\t\t\tArray.filterMap(attempts, (attempt) => {\n\t\t\t\t\t\tif (attempt.request === undefined) return Result.fail(undefined)\n\t\t\t\t\t\tconst actual = Option.getOrUndefined(\n\t\t\t\t\t\t\tHashMap.get(targets, attempt.request),\n\t\t\t\t\t\t)\n\t\t\t\t\t\tconst expected = pathToFileURL(fileURLToPath(attempt.url)).href\n\t\t\t\t\t\treturn actual === expected ||\n\t\t\t\t\t\t\t(actual === undefined &&\n\t\t\t\t\t\t\t\tOption.getOrUndefined(HashMap.get(targets, attempt.url)) ===\n\t\t\t\t\t\t\t\t\tundefined)\n\t\t\t\t\t\t\t? Result.fail(undefined)\n\t\t\t\t\t\t\t: Result.succeed(attempt.request)\n\t\t\t\t\t}),\n\t\t\t\t),\n\t\t\t)\n\t\t})\n\n\t\tconst load = Effect.fnUntraced(function* (specifier: string) {\n\t\t\tconst namespace = yield* Effect.tryPromise({\n\t\t\t\ttry: () => import(/* @vite-ignore */ hooks.request(specifier)),\n\t\t\t\t// The module hooks throw RestartRequired through import(); keep its tag.\n\t\t\t\tcatch: (cause) =>\n\t\t\t\t\tSchema.is(RestartRequired)(cause)\n\t\t\t\t\t\t? cause\n\t\t\t\t\t\t: HmrError.make({ stage: \"import\", specifier, cause }),\n\t\t\t})\n\t\t\tconst plugin = Plugin.fromModule(namespace)\n\t\t\tif (Option.isNone(plugin))\n\t\t\t\treturn yield* HmrError.make({\n\t\t\t\t\tstage: \"exports\",\n\t\t\t\t\tspecifier,\n\t\t\t\t\tcause: \"Expected a default or named plugin export\",\n\t\t\t\t})\n\t\t\tconst url = yield* Effect.fromOption(hooks.resolved()).pipe(\n\t\t\t\tEffect.mapError((cause) =>\n\t\t\t\t\tHmrError.make({ stage: \"import\", specifier, cause }),\n\t\t\t\t),\n\t\t\t)\n\t\t\tconst request = hooks.fileRequest(specifier)\n\t\t\tconst attempt = {\n\t\t\t\turl,\n\t\t\t\t...Option.match(request, {\n\t\t\t\t\tonNone: () => ({}),\n\t\t\t\t\tonSome: (request) => ({ request }),\n\t\t\t\t}),\n\t\t\t}\n\t\t\tconst changed = yield* changedResolution(attempt)\n\t\t\tif (Option.isSome(changed))\n\t\t\t\treturn yield* RestartRequired.make({ url: changed.value })\n\t\t\treturn { namespace, plugin: plugin.value, url }\n\t\t})\n\t\tconst acquireLease = Effect.fnUntraced(\n\t\t\tfunction* (specifier: string) {\n\t\t\t\tyield* checkOpen\n\t\t\t\tconst current = yield* Ref.get(state)\n\t\t\t\thooks.start(current.generation)\n\t\t\t\t// Acquire an owner for either Exit. Rethrow only after its finalizer\n\t\t\t\t// is registered, so failed imports remain available for scoped retry.\n\t\t\t\tconst exit = yield* Effect.exit(load(specifier))\n\t\t\t\tconst token: symbol = Symbol()\n\t\t\t\tconst root = Option.orElse(hooks.resolved(), () =>\n\t\t\t\t\tString.startsWith(\"file:\")(specifier)\n\t\t\t\t\t\t? Option.some(specifier)\n\t\t\t\t\t\t: Option.none(),\n\t\t\t\t)\n\t\t\t\tconst attempt = Option.map(root, (url) => ({\n\t\t\t\t\turl,\n\t\t\t\t\tgeneration: current.generation,\n\t\t\t\t\t...Option.match(hooks.fileRequest(specifier), {\n\t\t\t\t\t\tonNone: () => ({}),\n\t\t\t\t\t\tonSome: (request) => ({ request }),\n\t\t\t\t\t}),\n\t\t\t\t}))\n\t\t\t\tif (Option.isSome(attempt))\n\t\t\t\t\tyield* Ref.update(\n\t\t\t\t\t\tcached,\n\t\t\t\t\t\tHashMap.set(attempt.value.url, attempt.value),\n\t\t\t\t\t)\n\t\t\t\tyield* Ref.update(\n\t\t\t\t\towners,\n\t\t\t\t\tHashMap.set(token, {\n\t\t\t\t\t\tactive: Exit.isSuccess(exit) ? attempt : Option.none(),\n\t\t\t\t\t\tpending: Exit.isFailure(exit) ? attempt : Option.none(),\n\t\t\t\t\t}),\n\t\t\t\t)\n\t\t\t\tif (Exit.isSuccess(exit)) {\n\t\t\t\t\tconst entry = exit.value\n\t\t\t\t\tconst previous = HashMap.get(current.entries, entry.url)\n\t\t\t\t\tconst leases = Option.match(previous, {\n\t\t\t\t\t\tonNone: () => HashSet.empty<symbol>(),\n\t\t\t\t\t\tonSome: (entry) => entry.leases,\n\t\t\t\t\t})\n\t\t\t\t\tyield* Ref.set(state, {\n\t\t\t\t\t\t...current,\n\t\t\t\t\t\tentries: HashMap.set(current.entries, entry.url, {\n\t\t\t\t\t\t\tplugin: entry.plugin,\n\t\t\t\t\t\t\tleases: HashSet.add(leases, token),\n\t\t\t\t\t\t}),\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t\treturn { token, exit: Exit.map(exit, (entry) => entry.namespace) }\n\t\t\t},\n\t\t\tEffect.ensuring(Effect.sync(hooks.discard)),\n\t\t\tEffect.ensuring(collect),\n\t\t\tserial,\n\t\t)\n\t\tconst releaseLease = Effect.fnUntraced(\n\t\t\tfunction* ({ token }: { readonly token: symbol }) {\n\t\t\t\tyield* Ref.update(owners, HashMap.remove(token))\n\t\t\t\tyield* Ref.update(state, (current) => ({\n\t\t\t\t\t...current,\n\t\t\t\t\tentries: HashMap.filterMap(current.entries, (entry) => {\n\t\t\t\t\t\tconst leases = HashSet.remove(entry.leases, token)\n\t\t\t\t\t\treturn HashSet.size(leases) === 0\n\t\t\t\t\t\t\t? Result.fail(undefined)\n\t\t\t\t\t\t\t: Result.succeed({ ...entry, leases })\n\t\t\t\t\t}),\n\t\t\t\t}))\n\t\t\t},\n\t\t\tEffect.ensuring(collect),\n\t\t\tserial,\n\t\t)\n\t\tconst importWithLease = (specifier: string) =>\n\t\t\tEffect.acquireRelease(acquireLease(specifier), releaseLease).pipe(\n\t\t\t\tEffect.flatMap(({ exit }) => exit),\n\t\t\t\t// Importers cannot act on a restart; reloadChanged handles it by tag.\n\t\t\t\tEffect.catchTag(\"RestartRequired\", (cause) =>\n\t\t\t\t\tEffect.fail(HmrError.make({ stage: \"import\", specifier, cause })),\n\t\t\t\t),\n\t\t\t\tpreserveExit,\n\t\t\t)\n\n\t\tconst importModule: Hmr[\"importModule\"] = (specifier) =>\n\t\t\tserial(\n\t\t\t\tcheckOpen.pipe(\n\t\t\t\t\tEffect.andThen(\n\t\t\t\t\t\tEffect.tryPromise({\n\t\t\t\t\t\t\ttry: () => import(/* @vite-ignore */ hooks.rawRequest(specifier)),\n\t\t\t\t\t\t\tcatch: (cause) =>\n\t\t\t\t\t\t\t\tHmrError.make({ stage: \"import\", specifier, cause }),\n\t\t\t\t\t\t}),\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\t)\n\n\t\tconst importModuleScoped: Hmr[\"importModuleScoped\"] = (\n\t\t\tspecifier,\n\t\t\toptions,\n\t\t) =>\n\t\t\tEffect.uninterruptibleMask((restore) =>\n\t\t\t\tEffect.gen(function* () {\n\t\t\t\t\tconst caller = yield* Effect.scope\n\t\t\t\t\tconst { token, exit, managed } = yield* serial(\n\t\t\t\t\t\tEffect.gen(function* () {\n\t\t\t\t\t\t\tyield* checkOpen\n\t\t\t\t\t\t\tconst generation = hooks.prepare()\n\t\t\t\t\t\t\thooks.start(generation)\n\t\t\t\t\t\t\tconst token: symbol = Symbol()\n\t\t\t\t\t\t\tconst exit = yield* Effect.exit(\n\t\t\t\t\t\t\t\tEffect.tryPromise({\n\t\t\t\t\t\t\t\t\ttry: () =>\n\t\t\t\t\t\t\t\t\t\timport(/* @vite-ignore */ hooks.request(specifier)),\n\t\t\t\t\t\t\t\t\tcatch: (cause) =>\n\t\t\t\t\t\t\t\t\t\tHmrError.make({ stage: \"import\", specifier, cause }),\n\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\tconst root = Option.orElse(hooks.resolved(), () =>\n\t\t\t\t\t\t\t\tString.startsWith(\"file:\")(specifier)\n\t\t\t\t\t\t\t\t\t? Option.some(specifier)\n\t\t\t\t\t\t\t\t\t: Option.none(),\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\tconst attempt = Option.map(root, (url) => ({\n\t\t\t\t\t\t\t\turl,\n\t\t\t\t\t\t\t\tgeneration,\n\t\t\t\t\t\t\t\t...Option.match(hooks.fileRequest(specifier), {\n\t\t\t\t\t\t\t\t\tonNone: () => ({}),\n\t\t\t\t\t\t\t\t\tonSome: (request) => ({ request }),\n\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t}))\n\t\t\t\t\t\t\tconst observers = yield* Ref.get(sourceObservers)\n\t\t\t\t\t\t\tconst observer =\n\t\t\t\t\t\t\t\toptions === undefined\n\t\t\t\t\t\t\t\t\t? Option.none()\n\t\t\t\t\t\t\t\t\t: Array.findFirst(\n\t\t\t\t\t\t\t\t\t\t\tobservers,\n\t\t\t\t\t\t\t\t\t\t\t(source) => source.scope === options.observationScope,\n\t\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\tif (Option.isSome(observer)) {\n\t\t\t\t\t\t\t\tyield* observer.value.imported(\n\t\t\t\t\t\t\t\t\tOption.match(attempt, {\n\t\t\t\t\t\t\t\t\t\tonNone: () => specifier,\n\t\t\t\t\t\t\t\t\t\tonSome: (value) => value.request ?? value.url,\n\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t\thooks.files(Option.toArray(attempt)),\n\t\t\t\t\t\t\t\t\tExit.isSuccess(exit),\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t} else\n\t\t\t\t\t\t\t\tyield* Ref.update(\n\t\t\t\t\t\t\t\t\towners,\n\t\t\t\t\t\t\t\t\tHashMap.set(token, {\n\t\t\t\t\t\t\t\t\t\tactive: Exit.isSuccess(exit) ? attempt : Option.none(),\n\t\t\t\t\t\t\t\t\t\tpending: Exit.isFailure(exit) ? attempt : Option.none(),\n\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\treturn { token, exit, managed: Option.isSome(observer) }\n\t\t\t\t\t\t}).pipe(Effect.ensuring(Effect.sync(hooks.discard))),\n\t\t\t\t\t)\n\t\t\t\t\t// Collections already copied the observed digests; they do not retain per-attempt leases.\n\t\t\t\t\t// Without a collection, failed imports keep the caller's explicit observation lease.\n\t\t\t\t\tyield* Scope.addFinalizer(\n\t\t\t\t\t\t!managed && Exit.isFailure(exit)\n\t\t\t\t\t\t\t? (options?.observationScope ?? caller)\n\t\t\t\t\t\t\t: caller,\n\t\t\t\t\t\tserial(\n\t\t\t\t\t\t\tRef.update(owners, HashMap.remove(token)).pipe(\n\t\t\t\t\t\t\t\tEffect.ensuring(collect),\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t),\n\t\t\t\t\t)\n\t\t\t\t\treturn yield* restore(exit)\n\t\t\t\t}),\n\t\t\t).pipe(preserveExit)\n\n\t\tconst observe: Hmr[\"observe\"] = (files) =>\n\t\t\tStream.unwrap(\n\t\t\t\tEffect.gen(function* () {\n\t\t\t\t\tconst fs = yield* FileSystem.FileSystem\n\t\t\t\t\tconst observed = yield* Effect.forEach(files, (url) =>\n\t\t\t\t\t\tfs\n\t\t\t\t\t\t\t.readFile(fileURLToPath(url))\n\t\t\t\t\t\t\t.pipe(\n\t\t\t\t\t\t\t\tEffect.map((bytes): readonly [string, FileVersion] => [\n\t\t\t\t\t\t\t\t\turl,\n\t\t\t\t\t\t\t\t\t{ generation: -1, content: digest(bytes) },\n\t\t\t\t\t\t\t\t]),\n\t\t\t\t\t\t\t),\n\t\t\t\t\t)\n\t\t\t\t\tconst baseline = HashMap.fromIterable(observed)\n\t\t\t\t\tconst snapshot = yield* observations.pipe(\n\t\t\t\t\t\tEffect.map((attempts) =>\n\t\t\t\t\t\t\tHashMap.union(\n\t\t\t\t\t\t\t\tbaseline,\n\t\t\t\t\t\t\t\thooks.files(\n\t\t\t\t\t\t\t\t\tArray.filter(\n\t\t\t\t\t\t\t\t\t\tattempts,\n\t\t\t\t\t\t\t\t\t\t(attempt) =>\n\t\t\t\t\t\t\t\t\t\t\tArray.contains(files, attempt.url) ||\n\t\t\t\t\t\t\t\t\t\t\t(attempt.request !== undefined &&\n\t\t\t\t\t\t\t\t\t\t\t\tArray.contains(files, attempt.request)),\n\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t),\n\t\t\t\t\t\tsemaphore.withPermits(1),\n\t\t\t\t\t)\n\t\t\t\t\treturn changes(\n\t\t\t\t\t\t(use) => use(snapshot),\n\t\t\t\t\t\tArray.map(Array.fromIterable(HashMap.keys(snapshot)), (url) =>\n\t\t\t\t\t\t\tfileURLToPath(url),\n\t\t\t\t\t\t),\n\t\t\t\t\t).pipe(Stream.as(undefined))\n\t\t\t\t}),\n\t\t\t)\n\n\t\tconst importerScoped: Hmr[\"importerScoped\"] = (specifier, options) =>\n\t\t\toptions === undefined\n\t\t\t\t? importWithLease(specifier)\n\t\t\t\t: importWithLease(specifier).pipe(\n\t\t\t\t\t\tScope.provide(options.observationScope),\n\t\t\t\t\t)\n\n\t\tconst importer = (specifier: string): Promise<unknown> =>\n\t\t\t// A closed FiberSet interrupts new work before checkOpen can execute.\n\t\t\tRef.getUnsafe(closed)\n\t\t\t\t? Promise.reject(closedError())\n\t\t\t\t: run(\n\t\t\t\t\t\timporterScoped(specifier).pipe(\n\t\t\t\t\t\t\tEffect.provideService(Scope.Scope, imports),\n\t\t\t\t\t\t),\n\t\t\t\t\t)\n\n\t\tconst unsupportedAttempts = (attempts: ReadonlyArray<Attempt>) =>\n\t\t\tArray.reduce(attempts, HashSet.empty<string>(), (all, attempt) =>\n\t\t\t\tHashSet.union(\n\t\t\t\t\tall,\n\t\t\t\t\thooks.unsupported(attempt.generation, [attempt.url]),\n\t\t\t\t),\n\t\t\t)\n\t\tconst unsupportedModules = Ref.get(owners).pipe(\n\t\t\tEffect.map((owned) =>\n\t\t\t\tunsupportedAttempts(\n\t\t\t\t\tArray.getSomes(\n\t\t\t\t\t\tArray.map(HashMap.toValues(owned), (owner) => owner.active),\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\t),\n\t\t)\n\n\t\tconst reloadChanged = Effect.fnUntraced(function* (\n\t\t\tdirty: HashSet.HashSet<string> | undefined,\n\t\t) {\n\t\t\tyield* checkOpen\n\t\t\tconst fullRetry = yield* Ref.get(retryAll)\n\t\t\tconst force = dirty === undefined || fullRetry\n\t\t\tconst pendingDirty = yield* Ref.get(retryDirty)\n\t\t\tconst changedFiles =\n\t\t\t\tdirty === undefined ? pendingDirty : HashSet.union(pendingDirty, dirty)\n\t\t\tyield* Ref.set(retryDirty, changedFiles)\n\t\t\tyield* Ref.set(retryAll, force)\n\t\t\tconst changed = yield* changedResolutions\n\t\t\tif (changed.length > 0)\n\t\t\t\treturn WatchResult.Skipped({\n\t\t\t\t\treason: \"restart-required\",\n\t\t\t\t\tmodules: changed,\n\t\t\t\t})\n\t\t\tconst { entries } = yield* Ref.get(state)\n\t\t\tconst unsupported = yield* unsupportedModules\n\t\t\tif (HashSet.size(unsupported) > 0)\n\t\t\t\treturn WatchResult.Skipped({\n\t\t\t\t\tmodules: Array.fromIterable(unsupported),\n\t\t\t\t\treason: \"restart-required\",\n\t\t\t\t})\n\t\t\tconst owned = yield* Ref.get(owners)\n\t\t\tconst attempts = Array.flatMap(HashMap.toValues(owned), (owner) =>\n\t\t\t\tArray.getSomes([owner.active, owner.pending]),\n\t\t\t)\n\t\t\tconst active = Array.getSomes(\n\t\t\t\tArray.map(HashMap.toValues(owned), (owner) => owner.active),\n\t\t\t)\n\t\t\tlet selected = entries\n\t\t\tlet invalid = HashSet.empty<string>()\n\t\t\tif (!force) {\n\t\t\t\tlet affected = changedFiles\n\t\t\t\t// Plugin identity groups and importer closure can expand each other.\n\t\t\t\t// Reach a fixed point before allocating any candidate instance.\n\t\t\t\twhile (true) {\n\t\t\t\t\tinvalid = hooks.invalidated(attempts, affected)\n\t\t\t\t\tconst plugins = HashSet.fromIterable(\n\t\t\t\t\t\tArray.filterMap(Array.fromIterable(entries), ([url, entry]) =>\n\t\t\t\t\t\t\tHashSet.has(affected, url) ||\n\t\t\t\t\t\t\tArray.some(Array.fromIterable(entry.leases), (token) =>\n\t\t\t\t\t\t\t\tOption.exists(HashMap.get(owned, token), (owner) =>\n\t\t\t\t\t\t\t\t\tArray.some(\n\t\t\t\t\t\t\t\t\t\tArray.getSomes([owner.active, owner.pending]),\n\t\t\t\t\t\t\t\t\t\t(attempt) => hooks.affected(attempt, invalid),\n\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t? Result.succeed(entry.plugin)\n\t\t\t\t\t\t\t\t: Result.fail(undefined),\n\t\t\t\t\t\t),\n\t\t\t\t\t)\n\t\t\t\t\tselected = HashMap.filter(entries, (entry) =>\n\t\t\t\t\t\tHashSet.has(plugins, entry.plugin),\n\t\t\t\t\t)\n\t\t\t\t\tconst expanded = HashSet.union(\n\t\t\t\t\t\taffected,\n\t\t\t\t\t\tHashSet.fromIterable(HashMap.keys(selected)),\n\t\t\t\t\t)\n\t\t\t\t\tif (HashSet.size(expanded) === HashSet.size(affected)) break\n\t\t\t\t\taffected = expanded\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Advance even without entries so retries bypass cached failed imports.\n\t\t\tconst candidate = force ? hooks.prepare() : hooks.prepare(active, invalid)\n\n\t\t\thooks.start(candidate, true)\n\t\t\treturn yield* Effect.gen(function* () {\n\t\t\t\tconst loaded = yield* Effect.forEach(selected, ([url, previous]) =>\n\t\t\t\t\tRef.update(\n\t\t\t\t\t\towners,\n\t\t\t\t\t\tHashMap.map((owner, token) =>\n\t\t\t\t\t\t\tHashSet.has(previous.leases, token)\n\t\t\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\t\t\t...owner,\n\t\t\t\t\t\t\t\t\t\tpending: Option.map(owner.active, (attempt) => ({\n\t\t\t\t\t\t\t\t\t\t\t...attempt,\n\t\t\t\t\t\t\t\t\t\t\turl,\n\t\t\t\t\t\t\t\t\t\t\tgeneration: candidate,\n\t\t\t\t\t\t\t\t\t\t})),\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t: owner,\n\t\t\t\t\t\t),\n\t\t\t\t\t).pipe(\n\t\t\t\t\t\tEffect.andThen(load(url)),\n\t\t\t\t\t\tEffect.map((entry) =>\n\t\t\t\t\t\t\tOption.some({\n\t\t\t\t\t\t\t\turl,\n\t\t\t\t\t\t\t\tprevious: previous.plugin,\n\t\t\t\t\t\t\t\tleases: previous.leases,\n\t\t\t\t\t\t\t\tplugin: entry.plugin,\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t),\n\t\t\t\t\t\tEffect.catchIf(\n\t\t\t\t\t\t\t(error) =>\n\t\t\t\t\t\t\t\terror._tag === \"HmrError\" &&\n\t\t\t\t\t\t\t\terror.stage === \"import\" &&\n\t\t\t\t\t\t\t\tisMissingEntry(url, error.cause),\n\t\t\t\t\t\t\t() => Effect.succeedNone,\n\t\t\t\t\t\t),\n\t\t\t\t\t),\n\t\t\t\t)\n\t\t\t\tconst candidates = Array.getSomes(loaded)\n\t\t\t\tconst alternatives = Array.reduce(\n\t\t\t\t\tcandidates,\n\t\t\t\t\tHashMap.empty<Plugin.Plugin, HashSet.HashSet<Plugin.Plugin>>(),\n\t\t\t\t\t(groups, { previous, plugin }) =>\n\t\t\t\t\t\tHashMap.set(\n\t\t\t\t\t\t\tgroups,\n\t\t\t\t\t\t\tprevious,\n\t\t\t\t\t\t\tHashSet.add(\n\t\t\t\t\t\t\t\tOption.getOrElse(\n\t\t\t\t\t\t\t\t\tHashMap.get(groups, previous),\n\t\t\t\t\t\t\t\t\tHashSet.empty<Plugin.Plugin>,\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\tplugin,\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t),\n\t\t\t\t)\n\t\t\t\tconst ambiguous = Array.filter(candidates, ({ previous }) =>\n\t\t\t\t\tOption.exists(\n\t\t\t\t\t\tHashMap.get(alternatives, previous),\n\t\t\t\t\t\t(plugins) => HashSet.size(plugins) > 1,\n\t\t\t\t\t),\n\t\t\t\t)\n\t\t\t\tif (ambiguous.length > 0)\n\t\t\t\t\treturn WatchResult.Skipped({\n\t\t\t\t\t\treason: \"ambiguous-exports\",\n\t\t\t\t\t\tmodules: Array.map(ambiguous, ({ url }) => url),\n\t\t\t\t\t})\n\t\t\t\tconst replacements = HashMap.fromIterable(\n\t\t\t\t\tArray.map(\n\t\t\t\t\t\tcandidates,\n\t\t\t\t\t\t({ url, plugin, leases }) => [url, { plugin, leases }] as const,\n\t\t\t\t\t),\n\t\t\t\t)\n\t\t\t\t// A missing entry still owns its running plugin until the last lease closes.\n\t\t\t\tconst next = HashMap.union(entries, replacements)\n\n\t\t\t\tconst pairs = Array.map(\n\t\t\t\t\tcandidates,\n\t\t\t\t\t({ previous, plugin }) => [previous, plugin] as const,\n\t\t\t\t)\n\t\t\t\tconst changed = yield* changedResolutions\n\t\t\t\tif (changed.length > 0)\n\t\t\t\t\treturn WatchResult.Skipped({\n\t\t\t\t\t\treason: \"restart-required\",\n\t\t\t\t\t\tmodules: changed,\n\t\t\t\t\t})\n\t\t\t\t// A reused instance can acquire a native loading capability while the\n\t\t\t\t// candidate imports. Observe it without throwing into concurrent old code.\n\t\t\t\tconst unsafe = unsupportedAttempts(\n\t\t\t\t\tArray.map(active, (attempt) =>\n\t\t\t\t\t\tHashMap.has(replacements, attempt.url)\n\t\t\t\t\t\t\t? { ...attempt, generation: candidate }\n\t\t\t\t\t\t\t: attempt,\n\t\t\t\t\t),\n\t\t\t\t)\n\t\t\t\tif (HashSet.size(unsafe) > 0)\n\t\t\t\t\treturn WatchResult.Skipped({\n\t\t\t\t\t\treason: \"restart-required\",\n\t\t\t\t\t\tmodules: Array.fromIterable(unsafe),\n\t\t\t\t\t})\n\n\t\t\t\tconst replacement = yield* Graft.replace(pairs).pipe(\n\t\t\t\t\tEffect.provideService(Graft.Graft, graft),\n\t\t\t\t\tEffect.result,\n\t\t\t\t)\n\t\t\t\tif (Result.isFailure(replacement))\n\t\t\t\t\treturn WatchResult.Skipped({\n\t\t\t\t\t\treason: \"identity-conflict\",\n\t\t\t\t\t\tmodules: Array.filterMap(candidates, ({ url }, index) =>\n\t\t\t\t\t\t\tArray.contains(replacement.failure.indices, index)\n\t\t\t\t\t\t\t\t? Result.succeed(url)\n\t\t\t\t\t\t\t\t: Result.fail(undefined),\n\t\t\t\t\t\t),\n\t\t\t\t\t})\n\t\t\t\tyield* Ref.update(owners, (owners) =>\n\t\t\t\t\tArray.reduce(candidates, owners, (owners, { url, leases }) =>\n\t\t\t\t\t\tHashMap.map(owners, (owner, token) =>\n\t\t\t\t\t\t\tHashSet.has(leases, token)\n\t\t\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\t\t\tactive: Option.map(owner.pending, (attempt) => ({\n\t\t\t\t\t\t\t\t\t\t\t...attempt,\n\t\t\t\t\t\t\t\t\t\t\turl,\n\t\t\t\t\t\t\t\t\t\t\tgeneration: candidate,\n\t\t\t\t\t\t\t\t\t\t})),\n\t\t\t\t\t\t\t\t\t\tpending: Option.none(),\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t: owner,\n\t\t\t\t\t\t),\n\t\t\t\t\t),\n\t\t\t\t)\n\t\t\t\tyield* Ref.set(state, { entries: next, generation: candidate })\n\t\t\t\tyield* Ref.update(cached, (cached) =>\n\t\t\t\t\tHashMap.union(\n\t\t\t\t\t\tHashMap.filter(cached, (_, url) => HashMap.has(next, url)),\n\t\t\t\t\t\tHashMap.map(replacements, (_, url) => ({\n\t\t\t\t\t\t\turl,\n\t\t\t\t\t\t\tgeneration: candidate,\n\t\t\t\t\t\t})),\n\t\t\t\t\t),\n\t\t\t\t)\n\t\t\t\tyield* Ref.set(retryDirty, HashSet.empty())\n\t\t\t\tyield* Ref.set(retryAll, false)\n\t\t\t\treturn WatchResult.Reloaded({\n\t\t\t\t\tentries: Array.map(candidates, (candidate) => candidate.url),\n\t\t\t\t})\n\t\t\t}).pipe(\n\t\t\t\tEffect.catchTag(\"RestartRequired\", (error) =>\n\t\t\t\t\tEffect.succeed(\n\t\t\t\t\t\tWatchResult.Skipped({\n\t\t\t\t\t\t\tmodules: Array.fromIterable(\n\t\t\t\t\t\t\t\tHashSet.add(hooks.unsupported(candidate), error.url),\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\treason: \"restart-required\",\n\t\t\t\t\t\t}),\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\t\tEffect.ensuring(Effect.sync(hooks.discard)),\n\t\t\t\tEffect.ensuring(collect),\n\t\t\t)\n\t\t}, serial)\n\t\treturn {\n\t\t\timporter,\n\t\t\timporterScoped,\n\t\t\timportModule,\n\t\t\tobservation,\n\t\t\timportModuleScoped,\n\t\t\tobserve,\n\t\t\treload: reloadChanged(undefined),\n\t\t\twatch: (paths, watchOptions) =>\n\t\t\t\tpaths.length === 0\n\t\t\t\t\t? Stream.empty\n\t\t\t\t\t: changes(\n\t\t\t\t\t\t\t(use) =>\n\t\t\t\t\t\t\t\tRef.get(owners).pipe(\n\t\t\t\t\t\t\t\t\tEffect.map((owners) =>\n\t\t\t\t\t\t\t\t\t\thooks.files([\n\t\t\t\t\t\t\t\t\t\t\t...Array.getSomes(\n\t\t\t\t\t\t\t\t\t\t\t\tArray.map(\n\t\t\t\t\t\t\t\t\t\t\t\t\tHashMap.toValues(owners),\n\t\t\t\t\t\t\t\t\t\t\t\t\t(owner) => owner.active,\n\t\t\t\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\t\t\t...Array.getSomes(\n\t\t\t\t\t\t\t\t\t\t\t\tArray.map(\n\t\t\t\t\t\t\t\t\t\t\t\t\tHashMap.toValues(owners),\n\t\t\t\t\t\t\t\t\t\t\t\t\t(owner) => owner.pending,\n\t\t\t\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\t\t]),\n\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\tEffect.flatMap(use),\n\t\t\t\t\t\t\t\t\t// Only snapshot and validation callbacks run under the lock.\n\t\t\t\t\t\t\t\t\t// File reads operate on the retained immutable snapshot outside it.\n\t\t\t\t\t\t\t\t\tsemaphore.withPermits(1),\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\tpaths,\n\t\t\t\t\t\t\twatchOptions,\n\t\t\t\t\t\t).pipe(\n\t\t\t\t\t\t\tStream.mapEffect((dirty) =>\n\t\t\t\t\t\t\t\tEffect.map(\n\t\t\t\t\t\t\t\t\tEffect.exit(reloadChanged(dirty)),\n\t\t\t\t\t\t\t\t\t(exit): WatchResult =>\n\t\t\t\t\t\t\t\t\t\tExit.isSuccess(exit)\n\t\t\t\t\t\t\t\t\t\t\t? exit.value\n\t\t\t\t\t\t\t\t\t\t\t: WatchResult.Failed({ cause: exit.cause }),\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t// Native caches may hide both dependency edges and the first save.\n\t\t\t\t\t\t\t// Report known restart requirements independently of filesystem events.\n\t\t\t\t\t\t\tStream.merge(\n\t\t\t\t\t\t\t\tStream.tick(\"1 second\").pipe(\n\t\t\t\t\t\t\t\t\tStream.mapEffect(() =>\n\t\t\t\t\t\t\t\t\t\tunsupportedModules.pipe(semaphore.withPermits(1)),\n\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\tStream.changes,\n\t\t\t\t\t\t\t\t\tStream.filter((modules) => HashSet.size(modules) > 0),\n\t\t\t\t\t\t\t\t\tStream.map((modules) =>\n\t\t\t\t\t\t\t\t\t\tWatchResult.Skipped({\n\t\t\t\t\t\t\t\t\t\t\treason: \"restart-required\",\n\t\t\t\t\t\t\t\t\t\t\tmodules: Array.fromIterable(modules),\n\t\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t),\n\t\t}\n\t},\n)\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"changes.js","names":[],"sources":["../../src/internal/changes.ts"],"sourcesContent":["// @effect-diagnostics-next-line nodeBuiltinImport:off -- watcher paths use host-platform syntax without adding a Path service requirement\nimport { dirname, resolve } from \"node:path\"\nimport type { FileVersion } from \"./modules\"\nimport type { WatchOptions } from \"../index\"\nimport { digest } from \"./digest\"\nimport { fileURLToPath, pathToFileURL } from \"node:url\"\nimport {\n\tArray,\n\tCause,\n\tExit,\n\tEffect,\n\tFiber,\n\tFileSystem,\n\tHashMap,\n\tHashSet,\n\tEqual,\n\tClock,\n\tRef,\n\tQueue,\n\tOption,\n\tStream,\n\tString,\n} from \"effect\"\n\nexport type WithFiles = <A, E, R>(\n\tuse: (files: HashMap.HashMap<string, FileVersion>) => Effect.Effect<A, E, R>,\n) => Effect.Effect<A, E, R>\n\n/** Observe the producer after its resource scope closes, before merge can discard its Exit. */\nconst observeSource = <A, E, R>(source: Stream.Stream<A, E, R>) =>\n\tStream.callback<A, E, R>(\n\t\t(queue) =>\n\t\t\tEffect.scoped(\n\t\t\t\tEffect.uninterruptibleMask((restore) =>\n\t\t\t\t\tEffect.gen(function* () {\n\t\t\t\t\t\tconst id = yield* Effect.withFiber((self) =>\n\t\t\t\t\t\t\tEffect.succeed(self.id),\n\t\t\t\t\t\t)\n\t\t\t\t\t\tconst producer = yield* Effect.forkScoped(\n\t\t\t\t\t\t\trestore(\n\t\t\t\t\t\t\t\tsource.pipe(\n\t\t\t\t\t\t\t\t\tStream.runForEachArray((values) =>\n\t\t\t\t\t\t\t\t\t\tQueue.offerAll(queue, values),\n\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\tEffect.scoped,\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t)\n\t\t\t\t\t\tconst waiting = yield* Effect.exit(restore(Fiber.await(producer)))\n\t\t\t\t\t\tif (Exit.isFailure(waiting)) yield* Fiber.interrupt(producer)\n\t\t\t\t\t\tconst exit = yield* Fiber.await(producer)\n\t\t\t\t\t\t// Only our own cancellation is expected; nested finalizers may contribute other interrupts.\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\tExit.isFailure(exit) &&\n\t\t\t\t\t\t\tCause.hasInterrupts(exit.cause) &&\n\t\t\t\t\t\t\t!(\n\t\t\t\t\t\t\t\tExit.isFailure(waiting) &&\n\t\t\t\t\t\t\t\tArray.every(\n\t\t\t\t\t\t\t\t\texit.cause.reasons,\n\t\t\t\t\t\t\t\t\t(reason) =>\n\t\t\t\t\t\t\t\t\t\treason._tag === \"Interrupt\" && reason.fiberId === id,\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t)\n\t\t\t\t\t\t\tyield* Effect.logError(\n\t\t\t\t\t\t\t\t\"Native watcher failed during cancellation\",\n\t\t\t\t\t\t\t\texit.cause,\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\tyield* exit\n\t\t\t\t\t\tyield* Queue.end(queue)\n\t\t\t\t\t}),\n\t\t\t\t),\n\t\t\t),\n\t\t{ bufferSize: 16 },\n\t)\n\n/** Compare immutable observation tokens again after filesystem I/O releases the lock. */\nconst sameVersion = (a: FileVersion, b: FileVersion) =>\n\ta.generation === b.generation &&\n\ta.content === b.content &&\n\ta.resolution === b.resolution\n\n/** Reconcile owned modules because native watchers can silently miss events. */\nexport const changes = (\n\twithFiles: WithFiles,\n\tpaths: ReadonlyArray<string>,\n\toptions?: WatchOptions,\n) =>\n\tStream.unwrap(\n\t\tEffect.gen(function* () {\n\t\t\tif (paths.length === 0) return Stream.empty\n\t\t\tconst fs = yield* FileSystem.FileSystem\n\t\t\tconst roots = yield* Effect.forEach(\n\t\t\t\tpaths,\n\t\t\t\tEffect.fnUntraced(function* (path: string) {\n\t\t\t\t\tconst canonical = yield* fs.realPath(path)\n\t\t\t\t\tconst info = yield* fs.stat(canonical)\n\t\t\t\t\treturn {\n\t\t\t\t\t\tpath: canonical,\n\t\t\t\t\t\turls: [\n\t\t\t\t\t\t\tpathToFileURL(canonical).href,\n\t\t\t\t\t\t\tpathToFileURL(resolve(path)).href,\n\t\t\t\t\t\t],\n\t\t\t\t\t\tdirectory: info.type === \"Directory\",\n\t\t\t\t\t}\n\t\t\t\t}),\n\t\t\t)\n\t\t\tconst accepted = (path: string) => options?.filter?.(path) ?? true\n\t\t\tconst watched = (url: string) =>\n\t\t\t\taccepted(fileURLToPath(url)) &&\n\t\t\t\tArray.some(roots, ({ urls, directory }) =>\n\t\t\t\t\tArray.some(urls, (root) => {\n\t\t\t\t\t\tconst prefix = String.endsWith(\"/\")(root) ? root : `${root}/`\n\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\tfileURLToPath(url) === fileURLToPath(root) ||\n\t\t\t\t\t\t\t(directory &&\n\t\t\t\t\t\t\t\t(options?.recursive === true\n\t\t\t\t\t\t\t\t\t? String.startsWith(prefix)(url)\n\t\t\t\t\t\t\t\t\t: new URL(\".\", url).href === prefix))\n\t\t\t\t\t\t)\n\t\t\t\t\t}),\n\t\t\t\t)\n\t\t\tconst files = withFiles((loaded) =>\n\t\t\t\tEffect.succeed(HashMap.filter(loaded, (_, url) => watched(url))),\n\t\t\t)\n\t\t\tconst missing = <\n\t\t\t\tA,\n\t\t\t\tE extends import(\"effect\").PlatformError.PlatformError,\n\t\t\t\tR,\n\t\t\t>(\n\t\t\t\teffect: Effect.Effect<A, E, R>,\n\t\t\t) =>\n\t\t\t\teffect.pipe(\n\t\t\t\t\tEffect.catchIf(\n\t\t\t\t\t\t(error) => error.reason._tag === \"NotFound\",\n\t\t\t\t\t\t() => Effect.undefined,\n\t\t\t\t\t),\n\t\t\t\t)\n\t\t\t// Watch only graph directories, never recursively traverse an application root.\n\t\t\t// Missing descendants use their nearest existing ancestor until they appear.\n\t\t\tconst existingDirectory: (\n\t\t\t\tpath: string,\n\t\t\t) => Effect.Effect<string, import(\"effect\").PlatformError.PlatformError> =\n\t\t\t\tEffect.fnUntraced(function* (path: string) {\n\t\t\t\t\tconst info = yield* missing(fs.stat(path))\n\t\t\t\t\treturn info?.type === \"Directory\" || dirname(path) === path\n\t\t\t\t\t\t? path\n\t\t\t\t\t\t: yield* existingDirectory(dirname(path))\n\t\t\t\t})\n\t\t\tconst directories = Effect.gen(function* () {\n\t\t\t\tconst loaded = yield* files\n\t\t\t\tconst requested = HashSet.fromIterable([\n\t\t\t\t\t...Array.map(roots, (root) =>\n\t\t\t\t\t\troot.directory ? root.path : dirname(root.path),\n\t\t\t\t\t),\n\t\t\t\t\t...Array.map(Array.fromIterable(HashMap.keys(loaded)), (url) =>\n\t\t\t\t\t\tdirname(fileURLToPath(url)),\n\t\t\t\t\t),\n\t\t\t\t])\n\t\t\t\tconst existing = yield* Effect.forEach(requested, existingDirectory, {\n\t\t\t\t\tconcurrency: 8,\n\t\t\t\t})\n\t\t\t\treturn HashSet.fromIterable(existing)\n\t\t\t})\n\t\t\tconst dirty = yield* Ref.make(HashSet.empty<string>())\n\t\t\tconst native = Stream.tick(\"1 second\").pipe(\n\t\t\t\tStream.mapEffect(() => directories),\n\t\t\t\tStream.changesWith((a, b) => Equal.equals(a, b)),\n\t\t\t\tStream.switchMap((directories) =>\n\t\t\t\t\tStream.mergeAll(\n\t\t\t\t\t\tArray.map(Array.fromIterable(directories), (directory) =>\n\t\t\t\t\t\t\tfs.watch(directory, { ...options, recursive: false }).pipe(\n\t\t\t\t\t\t\t\tobserveSource,\n\t\t\t\t\t\t\t\tStream.map((event) => resolve(directory, event.path || \".\")),\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t),\n\t\t\t\t\t\t{ concurrency: \"unbounded\" },\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\t\tStream.tap((path) => Ref.update(dirty, HashSet.add(path))),\n\t\t\t\tStream.debounce(options?.debounce ?? \"50 millis\"),\n\t\t\t\tStream.mapEffect(() => Ref.getAndSet(dirty, HashSet.empty<string>())),\n\t\t\t)\n\t\t\tinterface Observation {\n\t\t\t\treadonly baseline: FileVersion\n\t\t\t\treadonly content: string | undefined\n\t\t\t\treadonly resolution: string | undefined\n\t\t\t\treadonly stat: string\n\t\t\t\treadonly checked: number\n\t\t\t}\n\t\t\tconst observed = yield* Ref.make(HashMap.empty<string, Observation>())\n\t\t\tconst scan = Effect.fnUntraced(function* (\n\t\t\t\tevents: HashSet.HashSet<string> | undefined,\n\t\t\t) {\n\t\t\t\tconst loaded = yield* files\n\t\t\t\tconst before = yield* Ref.get(observed)\n\t\t\t\tconst now = yield* Clock.currentTimeMillis\n\t\t\t\tconst selected = Array.filter(\n\t\t\t\t\tArray.fromIterable(loaded),\n\t\t\t\t\t([url]) =>\n\t\t\t\t\t\tevents === undefined ||\n\t\t\t\t\t\tArray.some(Array.fromIterable(events), (path) => {\n\t\t\t\t\t\t\tconst file = fileURLToPath(url)\n\t\t\t\t\t\t\treturn file === path || String.startsWith(`${path}/`)(file)\n\t\t\t\t\t\t}),\n\t\t\t\t)\n\t\t\t\tconst checked = yield* Effect.forEach(\n\t\t\t\t\tselected,\n\t\t\t\t\tEffect.fnUntraced(function* ([\n\t\t\t\t\t\turl,\n\t\t\t\t\t\tbaseline,\n\t\t\t\t\t]: (typeof selected)[number]) {\n\t\t\t\t\t\tconst path = fileURLToPath(url)\n\t\t\t\t\t\tconst previous = Option.getOrUndefined(HashMap.get(before, url))\n\t\t\t\t\t\tconst info = yield* missing(fs.stat(path))\n\t\t\t\t\t\tconst stat =\n\t\t\t\t\t\t\tinfo === undefined\n\t\t\t\t\t\t\t\t? \"missing\"\n\t\t\t\t\t\t\t\t: `${info.size}:${Option.getOrUndefined(info.mtime)?.getTime()}:${Option.getOrUndefined(info.ino)}`\n\t\t\t\t\t\tconst resolution =\n\t\t\t\t\t\t\tbaseline.resolution === undefined\n\t\t\t\t\t\t\t\t? undefined\n\t\t\t\t\t\t\t\t: yield* missing(fs.realPath(path)).pipe(\n\t\t\t\t\t\t\t\t\t\tEffect.map((path) =>\n\t\t\t\t\t\t\t\t\t\t\tpath === undefined ? undefined : pathToFileURL(path).href,\n\t\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\tconst audit =\n\t\t\t\t\t\t\tevents !== undefined ||\n\t\t\t\t\t\t\tprevious === undefined ||\n\t\t\t\t\t\t\t!sameVersion(previous.baseline, baseline) ||\n\t\t\t\t\t\t\tprevious.stat !== stat ||\n\t\t\t\t\t\t\tnow - previous.checked >= 10000\n\t\t\t\t\t\tconst content = audit\n\t\t\t\t\t\t\t? yield* missing(fs.readFile(path)).pipe(\n\t\t\t\t\t\t\t\t\tEffect.map((bytes) =>\n\t\t\t\t\t\t\t\t\t\tbytes === undefined ? undefined : digest(bytes),\n\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t: previous.content\n\t\t\t\t\t\tconst expected =\n\t\t\t\t\t\t\tprevious === undefined\n\t\t\t\t\t\t\t\t? baseline\n\t\t\t\t\t\t\t\t: {\n\t\t\t\t\t\t\t\t\t\tcontent:\n\t\t\t\t\t\t\t\t\t\t\tbaseline.content === undefined ||\n\t\t\t\t\t\t\t\t\t\t\tsameVersion(previous.baseline, baseline)\n\t\t\t\t\t\t\t\t\t\t\t\t? previous.content\n\t\t\t\t\t\t\t\t\t\t\t\t: baseline.content,\n\t\t\t\t\t\t\t\t\t\tresolution: sameVersion(previous.baseline, baseline)\n\t\t\t\t\t\t\t\t\t\t\t? previous.resolution\n\t\t\t\t\t\t\t\t\t\t\t: baseline.resolution,\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\turl,\n\t\t\t\t\t\t\tobservation: {\n\t\t\t\t\t\t\t\tbaseline,\n\t\t\t\t\t\t\t\tcontent,\n\t\t\t\t\t\t\t\tresolution,\n\t\t\t\t\t\t\t\tstat,\n\t\t\t\t\t\t\t\tchecked: audit ? now : previous.checked,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tchanged:\n\t\t\t\t\t\t\t\texpected.content !== content ||\n\t\t\t\t\t\t\t\texpected.resolution !== resolution,\n\t\t\t\t\t\t}\n\t\t\t\t\t}),\n\t\t\t\t\t{ concurrency: 8 },\n\t\t\t\t)\n\t\t\t\t// The immutable snapshot keeps its bytes alive while owners can be released.\n\t\t\t\t// A stale result cannot acknowledge a newer import, even when bytes coincide.\n\t\t\t\treturn yield* withFiles((current) =>\n\t\t\t\t\tRef.modify(observed, (seen) => {\n\t\t\t\t\t\tlet next = HashMap.filter(seen, (_, url) =>\n\t\t\t\t\t\t\tHashMap.has(current, url),\n\t\t\t\t\t\t)\n\t\t\t\t\t\tlet changed = HashSet.empty<string>()\n\t\t\t\t\t\tfor (const { url, observation, changed: differs } of checked) {\n\t\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t\t!Option.exists(HashMap.get(current, url), (version) =>\n\t\t\t\t\t\t\t\t\tsameVersion(version, observation.baseline),\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\tcontinue\n\t\t\t\t\t\t\tnext = HashMap.set(next, url, observation)\n\t\t\t\t\t\t\tif (differs) changed = HashSet.add(changed, url)\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn [changed, next]\n\t\t\t\t\t}),\n\t\t\t\t)\n\t\t\t})\n\t\t\treturn Stream.merge(\n\t\t\t\tnative,\n\t\t\t\tStream.tick(\"1 second\").pipe(\n\t\t\t\t\tStream.drop(1),\n\t\t\t\t\tStream.map(() => undefined),\n\t\t\t\t),\n\t\t\t).pipe(\n\t\t\t\tStream.mapEffect(scan),\n\t\t\t\tStream.filter((changed) => HashSet.size(changed) > 0),\n\t\t\t)\n\t\t}),\n\t)\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"changes.js","names":[],"sources":["../../src/internal/changes.ts"],"sourcesContent":["// @effect-diagnostics-next-line nodeBuiltinImport:off -- watcher paths use host-platform syntax without adding a Path service requirement\nimport { dirname, resolve } from \"node:path\"\nimport { fileURLToPath, pathToFileURL } from \"node:url\"\n\nimport {\n\tArray,\n\tCause,\n\tClock,\n\tEffect,\n\tEqual,\n\tExit,\n\tFiber,\n\tFileSystem,\n\tHashMap,\n\tHashSet,\n\tOption,\n\tQueue,\n\tRef,\n\tStream,\n\tString,\n} from \"effect\"\n\nimport type { WatchOptions } from \"../index\"\nimport { digest } from \"./digest\"\nimport type { FileVersion } from \"./modules\"\n\nexport type WithFiles = <A, E, R>(\n\tuse: (files: HashMap.HashMap<string, FileVersion>) => Effect.Effect<A, E, R>,\n) => Effect.Effect<A, E, R>\n\n/** Observe the producer after its resource scope closes, before merge can discard its Exit. */\nconst observeSource = <A, E, R>(source: Stream.Stream<A, E, R>) =>\n\tStream.callback<A, E, R>(\n\t\t(queue) =>\n\t\t\tEffect.scoped(\n\t\t\t\tEffect.uninterruptibleMask((restore) =>\n\t\t\t\t\tEffect.gen(function* () {\n\t\t\t\t\t\tconst id = yield* Effect.withFiber((self) =>\n\t\t\t\t\t\t\tEffect.succeed(self.id),\n\t\t\t\t\t\t)\n\t\t\t\t\t\tconst producer = yield* Effect.forkScoped(\n\t\t\t\t\t\t\trestore(\n\t\t\t\t\t\t\t\tsource.pipe(\n\t\t\t\t\t\t\t\t\tStream.runForEachArray((values) =>\n\t\t\t\t\t\t\t\t\t\tQueue.offerAll(queue, values),\n\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\tEffect.scoped,\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t)\n\t\t\t\t\t\tconst waiting = yield* Effect.exit(restore(Fiber.await(producer)))\n\t\t\t\t\t\tif (Exit.isFailure(waiting)) yield* Fiber.interrupt(producer)\n\t\t\t\t\t\tconst exit = yield* Fiber.await(producer)\n\t\t\t\t\t\t// Only our own cancellation is expected; nested finalizers may contribute other interrupts.\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\tExit.isFailure(exit) &&\n\t\t\t\t\t\t\tCause.hasInterrupts(exit.cause) &&\n\t\t\t\t\t\t\t!(\n\t\t\t\t\t\t\t\tExit.isFailure(waiting) &&\n\t\t\t\t\t\t\t\tArray.every(\n\t\t\t\t\t\t\t\t\texit.cause.reasons,\n\t\t\t\t\t\t\t\t\t(reason) =>\n\t\t\t\t\t\t\t\t\t\treason._tag === \"Interrupt\" && reason.fiberId === id,\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t)\n\t\t\t\t\t\t\tyield* Effect.logError(\n\t\t\t\t\t\t\t\t\"Native watcher failed during cancellation\",\n\t\t\t\t\t\t\t\texit.cause,\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\tyield* exit\n\t\t\t\t\t\tyield* Queue.end(queue)\n\t\t\t\t\t}),\n\t\t\t\t),\n\t\t\t),\n\t\t{ bufferSize: 16 },\n\t)\n\n/** Compare immutable observation tokens again after filesystem I/O releases the lock. */\nconst sameVersion = (a: FileVersion, b: FileVersion) =>\n\ta.generation === b.generation &&\n\ta.content === b.content &&\n\ta.resolution === b.resolution\n\n/** Reconcile owned modules because native watchers can silently miss events. */\nexport const changes = (\n\twithFiles: WithFiles,\n\tpaths: ReadonlyArray<string>,\n\toptions?: WatchOptions,\n) =>\n\tStream.unwrap(\n\t\tEffect.gen(function* () {\n\t\t\tif (paths.length === 0) return Stream.empty\n\t\t\tconst fs = yield* FileSystem.FileSystem\n\t\t\tconst roots = yield* Effect.forEach(\n\t\t\t\tpaths,\n\t\t\t\tEffect.fnUntraced(function* (path: string) {\n\t\t\t\t\tconst canonical = yield* fs.realPath(path)\n\t\t\t\t\tconst info = yield* fs.stat(canonical)\n\t\t\t\t\treturn {\n\t\t\t\t\t\tpath: canonical,\n\t\t\t\t\t\turls: [\n\t\t\t\t\t\t\tpathToFileURL(canonical).href,\n\t\t\t\t\t\t\tpathToFileURL(resolve(path)).href,\n\t\t\t\t\t\t],\n\t\t\t\t\t\tdirectory: info.type === \"Directory\",\n\t\t\t\t\t}\n\t\t\t\t}),\n\t\t\t)\n\t\t\tconst accepted = (path: string) => options?.filter?.(path) ?? true\n\t\t\tconst watched = (url: string) =>\n\t\t\t\taccepted(fileURLToPath(url)) &&\n\t\t\t\tArray.some(roots, ({ urls, directory }) =>\n\t\t\t\t\tArray.some(urls, (root) => {\n\t\t\t\t\t\tconst prefix = String.endsWith(\"/\")(root) ? root : `${root}/`\n\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\tfileURLToPath(url) === fileURLToPath(root) ||\n\t\t\t\t\t\t\t(directory &&\n\t\t\t\t\t\t\t\t(options?.recursive === true\n\t\t\t\t\t\t\t\t\t? String.startsWith(prefix)(url)\n\t\t\t\t\t\t\t\t\t: new URL(\".\", url).href === prefix))\n\t\t\t\t\t\t)\n\t\t\t\t\t}),\n\t\t\t\t)\n\t\t\tconst files = withFiles((loaded) =>\n\t\t\t\tEffect.succeed(HashMap.filter(loaded, (_, url) => watched(url))),\n\t\t\t)\n\t\t\tconst missing = <\n\t\t\t\tA,\n\t\t\t\tE extends import(\"effect\").PlatformError.PlatformError,\n\t\t\t\tR,\n\t\t\t>(\n\t\t\t\teffect: Effect.Effect<A, E, R>,\n\t\t\t) =>\n\t\t\t\teffect.pipe(\n\t\t\t\t\tEffect.catchIf(\n\t\t\t\t\t\t(error) => error.reason._tag === \"NotFound\",\n\t\t\t\t\t\t() => Effect.undefined,\n\t\t\t\t\t),\n\t\t\t\t)\n\t\t\t// Watch only graph directories, never recursively traverse an application root.\n\t\t\t// Missing descendants use their nearest existing ancestor until they appear.\n\t\t\tconst existingDirectory: (\n\t\t\t\tpath: string,\n\t\t\t) => Effect.Effect<string, import(\"effect\").PlatformError.PlatformError> =\n\t\t\t\tEffect.fnUntraced(function* (path: string) {\n\t\t\t\t\tconst info = yield* missing(fs.stat(path))\n\t\t\t\t\treturn info?.type === \"Directory\" || dirname(path) === path\n\t\t\t\t\t\t? path\n\t\t\t\t\t\t: yield* existingDirectory(dirname(path))\n\t\t\t\t})\n\t\t\tconst directories = Effect.gen(function* () {\n\t\t\t\tconst loaded = yield* files\n\t\t\t\tconst requested = HashSet.fromIterable([\n\t\t\t\t\t...Array.map(roots, (root) =>\n\t\t\t\t\t\troot.directory ? root.path : dirname(root.path),\n\t\t\t\t\t),\n\t\t\t\t\t...Array.map(Array.fromIterable(HashMap.keys(loaded)), (url) =>\n\t\t\t\t\t\tdirname(fileURLToPath(url)),\n\t\t\t\t\t),\n\t\t\t\t])\n\t\t\t\tconst existing = yield* Effect.forEach(requested, existingDirectory, {\n\t\t\t\t\tconcurrency: 8,\n\t\t\t\t})\n\t\t\t\treturn HashSet.fromIterable(existing)\n\t\t\t})\n\t\t\tconst dirty = yield* Ref.make(HashSet.empty<string>())\n\t\t\tconst native = Stream.tick(\"1 second\").pipe(\n\t\t\t\tStream.mapEffect(() => directories),\n\t\t\t\tStream.changesWith((a, b) => Equal.equals(a, b)),\n\t\t\t\tStream.switchMap((directories) =>\n\t\t\t\t\tStream.mergeAll(\n\t\t\t\t\t\tArray.map(Array.fromIterable(directories), (directory) =>\n\t\t\t\t\t\t\tfs.watch(directory, { ...options, recursive: false }).pipe(\n\t\t\t\t\t\t\t\tobserveSource,\n\t\t\t\t\t\t\t\tStream.map((event) => resolve(directory, event.path || \".\")),\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t),\n\t\t\t\t\t\t{ concurrency: \"unbounded\" },\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\t\tStream.tap((path) => Ref.update(dirty, HashSet.add(path))),\n\t\t\t\tStream.debounce(options?.debounce ?? \"50 millis\"),\n\t\t\t\tStream.mapEffect(() => Ref.getAndSet(dirty, HashSet.empty<string>())),\n\t\t\t)\n\t\t\tinterface Observation {\n\t\t\t\treadonly baseline: FileVersion\n\t\t\t\treadonly content: string | undefined\n\t\t\t\treadonly resolution: string | undefined\n\t\t\t\treadonly stat: string\n\t\t\t\treadonly checked: number\n\t\t\t}\n\t\t\tconst observed = yield* Ref.make(HashMap.empty<string, Observation>())\n\t\t\tconst scan = Effect.fnUntraced(function* (\n\t\t\t\tevents: HashSet.HashSet<string> | undefined,\n\t\t\t) {\n\t\t\t\tconst loaded = yield* files\n\t\t\t\tconst before = yield* Ref.get(observed)\n\t\t\t\tconst now = yield* Clock.currentTimeMillis\n\t\t\t\tconst selected = Array.filter(\n\t\t\t\t\tArray.fromIterable(loaded),\n\t\t\t\t\t([url]) =>\n\t\t\t\t\t\tevents === undefined ||\n\t\t\t\t\t\tArray.some(Array.fromIterable(events), (path) => {\n\t\t\t\t\t\t\tconst file = fileURLToPath(url)\n\t\t\t\t\t\t\treturn file === path || String.startsWith(`${path}/`)(file)\n\t\t\t\t\t\t}),\n\t\t\t\t)\n\t\t\t\tconst checked = yield* Effect.forEach(\n\t\t\t\t\tselected,\n\t\t\t\t\tEffect.fnUntraced(function* ([\n\t\t\t\t\t\turl,\n\t\t\t\t\t\tbaseline,\n\t\t\t\t\t]: (typeof selected)[number]) {\n\t\t\t\t\t\tconst path = fileURLToPath(url)\n\t\t\t\t\t\tconst previous = Option.getOrUndefined(HashMap.get(before, url))\n\t\t\t\t\t\tconst info = yield* missing(fs.stat(path))\n\t\t\t\t\t\tconst stat =\n\t\t\t\t\t\t\tinfo === undefined\n\t\t\t\t\t\t\t\t? \"missing\"\n\t\t\t\t\t\t\t\t: `${info.size}:${Option.getOrUndefined(info.mtime)?.getTime()}:${Option.getOrUndefined(info.ino)}`\n\t\t\t\t\t\tconst resolution =\n\t\t\t\t\t\t\tbaseline.resolution === undefined\n\t\t\t\t\t\t\t\t? undefined\n\t\t\t\t\t\t\t\t: yield* missing(fs.realPath(path)).pipe(\n\t\t\t\t\t\t\t\t\t\tEffect.map((path) =>\n\t\t\t\t\t\t\t\t\t\t\tpath === undefined ? undefined : pathToFileURL(path).href,\n\t\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\tconst audit =\n\t\t\t\t\t\t\tevents !== undefined ||\n\t\t\t\t\t\t\tprevious === undefined ||\n\t\t\t\t\t\t\t!sameVersion(previous.baseline, baseline) ||\n\t\t\t\t\t\t\tprevious.stat !== stat ||\n\t\t\t\t\t\t\tnow - previous.checked >= 10000\n\t\t\t\t\t\tconst content = audit\n\t\t\t\t\t\t\t? yield* missing(fs.readFile(path)).pipe(\n\t\t\t\t\t\t\t\t\tEffect.map((bytes) =>\n\t\t\t\t\t\t\t\t\t\tbytes === undefined ? undefined : digest(bytes),\n\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t: previous.content\n\t\t\t\t\t\tconst expected =\n\t\t\t\t\t\t\tprevious === undefined\n\t\t\t\t\t\t\t\t? baseline\n\t\t\t\t\t\t\t\t: {\n\t\t\t\t\t\t\t\t\t\tcontent:\n\t\t\t\t\t\t\t\t\t\t\tbaseline.content === undefined ||\n\t\t\t\t\t\t\t\t\t\t\tsameVersion(previous.baseline, baseline)\n\t\t\t\t\t\t\t\t\t\t\t\t? previous.content\n\t\t\t\t\t\t\t\t\t\t\t\t: baseline.content,\n\t\t\t\t\t\t\t\t\t\tresolution: sameVersion(previous.baseline, baseline)\n\t\t\t\t\t\t\t\t\t\t\t? previous.resolution\n\t\t\t\t\t\t\t\t\t\t\t: baseline.resolution,\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\turl,\n\t\t\t\t\t\t\tobservation: {\n\t\t\t\t\t\t\t\tbaseline,\n\t\t\t\t\t\t\t\tcontent,\n\t\t\t\t\t\t\t\tresolution,\n\t\t\t\t\t\t\t\tstat,\n\t\t\t\t\t\t\t\tchecked: audit ? now : previous.checked,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tchanged:\n\t\t\t\t\t\t\t\texpected.content !== content ||\n\t\t\t\t\t\t\t\texpected.resolution !== resolution,\n\t\t\t\t\t\t}\n\t\t\t\t\t}),\n\t\t\t\t\t{ concurrency: 8 },\n\t\t\t\t)\n\t\t\t\t// The immutable snapshot keeps its bytes alive while owners can be released.\n\t\t\t\t// A stale result cannot acknowledge a newer import, even when bytes coincide.\n\t\t\t\treturn yield* withFiles((current) =>\n\t\t\t\t\tRef.modify(observed, (seen) => {\n\t\t\t\t\t\tlet next = HashMap.filter(seen, (_, url) =>\n\t\t\t\t\t\t\tHashMap.has(current, url),\n\t\t\t\t\t\t)\n\t\t\t\t\t\tlet changed = HashSet.empty<string>()\n\t\t\t\t\t\tfor (const { url, observation, changed: differs } of checked) {\n\t\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t\t!Option.exists(HashMap.get(current, url), (version) =>\n\t\t\t\t\t\t\t\t\tsameVersion(version, observation.baseline),\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\tcontinue\n\t\t\t\t\t\t\tnext = HashMap.set(next, url, observation)\n\t\t\t\t\t\t\tif (differs) changed = HashSet.add(changed, url)\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn [changed, next]\n\t\t\t\t\t}),\n\t\t\t\t)\n\t\t\t})\n\t\t\treturn Stream.merge(\n\t\t\t\tnative,\n\t\t\t\tStream.tick(\"1 second\").pipe(\n\t\t\t\t\tStream.drop(1),\n\t\t\t\t\tStream.map(() => undefined),\n\t\t\t\t),\n\t\t\t).pipe(\n\t\t\t\tStream.mapEffect(scan),\n\t\t\t\tStream.filter((changed) => HashSet.size(changed) > 0),\n\t\t\t)\n\t\t}),\n\t)\n"],"mappings":";;;;;;AA+BA,MAAM,iBAA0B,WAC/B,OAAO,UACL,UACA,OAAO,OACN,OAAO,qBAAqB,YAC3B,OAAO,IAAI,aAAa;CACvB,MAAM,KAAK,OAAO,OAAO,WAAW,SACnC,OAAO,QAAQ,KAAK,EAAE,CACvB;CACA,MAAM,WAAW,OAAO,OAAO,WAC9B,QACC,OAAO,KACN,OAAO,iBAAiB,WACvB,MAAM,SAAS,OAAO,MAAM,CAC7B,GACA,OAAO,MACR,CACD,CACD;CACA,MAAM,UAAU,OAAO,OAAO,KAAK,QAAQ,MAAM,MAAM,QAAQ,CAAC,CAAC;CACjE,IAAI,KAAK,UAAU,OAAO,GAAG,OAAO,MAAM,UAAU,QAAQ;CAC5D,MAAM,OAAO,OAAO,MAAM,MAAM,QAAQ;CAExC,IACC,KAAK,UAAU,IAAI,KACnB,MAAM,cAAc,KAAK,KAAK,KAC9B,EACC,KAAK,UAAU,OAAO,KACtB,MAAM,MACL,KAAK,MAAM,UACV,WACA,OAAO,SAAS,eAAe,OAAO,YAAY,EACpD,IAGD,OAAO,OAAO,SACb,6CACA,KAAK,KACN;CACD,OAAO;CACP,OAAO,MAAM,IAAI,KAAK;AACvB,CAAC,CACF,CACD,GACD,EAAE,YAAY,GAAG,CAClB;;AAGD,MAAM,eAAe,GAAgB,MACpC,EAAE,eAAe,EAAE,cACnB,EAAE,YAAY,EAAE,WAChB,EAAE,eAAe,EAAE;;AAGpB,MAAa,WACZ,WACA,OACA,YAEA,OAAO,OACN,OAAO,IAAI,aAAa;CACvB,IAAI,MAAM,WAAW,GAAG,OAAO,OAAO;CACtC,MAAM,KAAK,OAAO,WAAW;CAC7B,MAAM,QAAQ,OAAO,OAAO,QAC3B,OACA,OAAO,WAAW,WAAW,MAAc;EAC1C,MAAM,YAAY,OAAO,GAAG,SAAS,IAAI;EACzC,MAAM,OAAO,OAAO,GAAG,KAAK,SAAS;EACrC,OAAO;GACN,MAAM;GACN,MAAM,CACL,cAAc,SAAS,CAAC,CAAC,MACzB,cAAc,QAAQ,IAAI,CAAC,CAAC,CAAC,IAC9B;GACA,WAAW,KAAK,SAAS;EAC1B;CACD,CAAC,CACF;CACA,MAAM,YAAY,SAAiB,SAAS,SAAS,IAAI,KAAK;CAC9D,MAAM,WAAW,QAChB,SAAS,cAAc,GAAG,CAAC,KAC3B,MAAM,KAAK,QAAQ,EAAE,MAAM,gBAC1B,MAAM,KAAK,OAAO,SAAS;EAC1B,MAAM,SAAS,OAAO,SAAS,GAAG,CAAC,CAAC,IAAI,IAAI,OAAO,GAAG,KAAK;EAC3D,OACC,cAAc,GAAG,MAAM,cAAc,IAAI,KACxC,cACC,SAAS,cAAc,OACrB,OAAO,WAAW,MAAM,CAAC,CAAC,GAAG,IAC7B,IAAI,IAAI,KAAK,GAAG,CAAC,CAAC,SAAS;CAEjC,CAAC,CACF;CACD,MAAM,QAAQ,WAAW,WACxB,OAAO,QAAQ,QAAQ,OAAO,SAAS,GAAG,QAAQ,QAAQ,GAAG,CAAC,CAAC,CAChE;CACA,MAAM,WAKL,WAEA,OAAO,KACN,OAAO,SACL,UAAU,MAAM,OAAO,SAAS,kBAC3B,OAAO,SACd,CACD;CAGD,MAAM,oBAGL,OAAO,WAAW,WAAW,MAAc;EAE1C,QAAO,OADa,QAAQ,GAAG,KAAK,IAAI,CAAC,EAAA,EAC5B,SAAS,eAAe,QAAQ,IAAI,MAAM,OACpD,OACA,OAAO,kBAAkB,QAAQ,IAAI,CAAC;CAC1C,CAAC;CACF,MAAM,cAAc,OAAO,IAAI,aAAa;EAC3C,MAAM,SAAS,OAAO;EACtB,MAAM,YAAY,QAAQ,aAAa,CACtC,GAAG,MAAM,IAAI,QAAQ,SACpB,KAAK,YAAY,KAAK,OAAO,QAAQ,KAAK,IAAI,CAC/C,GACA,GAAG,MAAM,IAAI,MAAM,aAAa,QAAQ,KAAK,MAAM,CAAC,IAAI,QACvD,QAAQ,cAAc,GAAG,CAAC,CAC3B,CACD,CAAC;EACD,MAAM,WAAW,OAAO,OAAO,QAAQ,WAAW,mBAAmB,EACpE,aAAa,EACd,CAAC;EACD,OAAO,QAAQ,aAAa,QAAQ;CACrC,CAAC;CACD,MAAM,QAAQ,OAAO,IAAI,KAAK,QAAQ,MAAc,CAAC;CACrD,MAAM,SAAS,OAAO,KAAK,UAAU,CAAC,CAAC,KACtC,OAAO,gBAAgB,WAAW,GAClC,OAAO,aAAa,GAAG,MAAM,MAAM,OAAO,GAAG,CAAC,CAAC,GAC/C,OAAO,WAAW,gBACjB,OAAO,SACN,MAAM,IAAI,MAAM,aAAa,WAAW,IAAI,cAC3C,GAAG,MAAM,WAAW;EAAE,GAAG;EAAS,WAAW;CAAM,CAAC,CAAC,CAAC,KACrD,eACA,OAAO,KAAK,UAAU,QAAQ,WAAW,MAAM,QAAQ,GAAG,CAAC,CAC5D,CACD,GACA,EAAE,aAAa,YAAY,CAC5B,CACD,GACA,OAAO,KAAK,SAAS,IAAI,OAAO,OAAO,QAAQ,IAAI,IAAI,CAAC,CAAC,GACzD,OAAO,SAAS,SAAS,YAAY,WAAW,GAChD,OAAO,gBAAgB,IAAI,UAAU,OAAO,QAAQ,MAAc,CAAC,CAAC,CACrE;CAQA,MAAM,WAAW,OAAO,IAAI,KAAK,QAAQ,MAA2B,CAAC;CACrE,MAAM,OAAO,OAAO,WAAW,WAC9B,QACC;EACD,MAAM,SAAS,OAAO;EACtB,MAAM,SAAS,OAAO,IAAI,IAAI,QAAQ;EACtC,MAAM,MAAM,OAAO,MAAM;EACzB,MAAM,WAAW,MAAM,OACtB,MAAM,aAAa,MAAM,IACxB,CAAC,SACD,WAAW,KAAA,KACX,MAAM,KAAK,MAAM,aAAa,MAAM,IAAI,SAAS;GAChD,MAAM,OAAO,cAAc,GAAG;GAC9B,OAAO,SAAS,QAAQ,OAAO,WAAW,GAAG,KAAK,EAAE,CAAC,CAAC,IAAI;EAC3D,CAAC,CACH;EACA,MAAM,UAAU,OAAO,OAAO,QAC7B,UACA,OAAO,WAAW,WAAW,CAC5B,KACA,WAC6B;GAC7B,MAAM,OAAO,cAAc,GAAG;GAC9B,MAAM,WAAW,OAAO,eAAe,QAAQ,IAAI,QAAQ,GAAG,CAAC;GAC/D,MAAM,OAAO,OAAO,QAAQ,GAAG,KAAK,IAAI,CAAC;GACzC,MAAM,OACL,SAAS,KAAA,IACN,YACA,GAAG,KAAK,KAAK,GAAG,OAAO,eAAe,KAAK,KAAK,CAAC,EAAE,QAAQ,EAAE,GAAG,OAAO,eAAe,KAAK,GAAG;GAClG,MAAM,aACL,SAAS,eAAe,KAAA,IACrB,KAAA,IACA,OAAO,QAAQ,GAAG,SAAS,IAAI,CAAC,CAAC,CAAC,KAClC,OAAO,KAAK,SACX,SAAS,KAAA,IAAY,KAAA,IAAY,cAAc,IAAI,CAAC,CAAC,IACtD,CACD;GACH,MAAM,QACL,WAAW,KAAA,KACX,aAAa,KAAA,KACb,CAAC,YAAY,SAAS,UAAU,QAAQ,KACxC,SAAS,SAAS,QAClB,MAAM,SAAS,WAAW;GAC3B,MAAM,UAAU,QACb,OAAO,QAAQ,GAAG,SAAS,IAAI,CAAC,CAAC,CAAC,KAClC,OAAO,KAAK,UACX,UAAU,KAAA,IAAY,KAAA,IAAY,OAAO,KAAK,CAC/C,CACD,IACC,SAAS;GACZ,MAAM,WACL,aAAa,KAAA,IACV,WACA;IACA,SACC,SAAS,YAAY,KAAA,KACrB,YAAY,SAAS,UAAU,QAAQ,IACpC,SAAS,UACT,SAAS;IACb,YAAY,YAAY,SAAS,UAAU,QAAQ,IAChD,SAAS,aACT,SAAS;GACb;GACH,OAAO;IACN;IACA,aAAa;KACZ;KACA;KACA;KACA;KACA,SAAS,QAAQ,MAAM,SAAS;IACjC;IACA,SACC,SAAS,YAAY,WACrB,SAAS,eAAe;GAC1B;EACD,CAAC,GACD,EAAE,aAAa,EAAE,CAClB;EAGA,OAAO,OAAO,WAAW,YACxB,IAAI,OAAO,WAAW,SAAS;GAC9B,IAAI,OAAO,QAAQ,OAAO,OAAO,GAAG,QACnC,QAAQ,IAAI,SAAS,GAAG,CACzB;GACA,IAAI,UAAU,QAAQ,MAAc;GACpC,KAAK,MAAM,EAAE,KAAK,aAAa,SAAS,aAAa,SAAS;IAC7D,IACC,CAAC,OAAO,OAAO,QAAQ,IAAI,SAAS,GAAG,IAAI,YAC1C,YAAY,SAAS,YAAY,QAAQ,CAC1C,GAEA;IACD,OAAO,QAAQ,IAAI,MAAM,KAAK,WAAW;IACzC,IAAI,SAAS,UAAU,QAAQ,IAAI,SAAS,GAAG;GAChD;GACA,OAAO,CAAC,SAAS,IAAI;EACtB,CAAC,CACF;CACD,CAAC;CACD,OAAO,OAAO,MACb,QACA,OAAO,KAAK,UAAU,CAAC,CAAC,KACvB,OAAO,KAAK,CAAC,GACb,OAAO,UAAU,KAAA,CAAS,CAC3B,CACD,CAAC,CAAC,KACD,OAAO,UAAU,IAAI,GACrB,OAAO,QAAQ,YAAY,QAAQ,KAAK,OAAO,IAAI,CAAC,CACrD;AACD,CAAC,CACF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"modules.js","names":[],"sources":["../../src/internal/modules.ts"],"sourcesContent":["// Node's synchronous module hooks have no Effect equivalent.\nimport { digest } from \"./digest\"\nimport { registerHooks } from \"node:module\"\nimport { fileURLToPath, pathToFileURL } from \"node:url\"\nimport {\n\tArray,\n\tChunk,\n\tHashMap,\n\tHashSet,\n\tOption,\n\tPredicate,\n\tSchema,\n\tString,\n} from \"effect\"\n\nexport class RestartRequired extends Schema.TaggedError<\n\tRestartRequired,\n\t{ readonly brand: unique symbol }\n>()(\"RestartRequired\", { url: Schema.String }) {}\n\n// Only a missing entry is disposable; missing dependencies still fail the reload.\nexport const isMissingEntry = (url: string, cause: unknown): boolean =>\n\tString.startsWith(\"file:\")(url) &&\n\tPredicate.hasProperty(cause, \"code\") &&\n\t((cause.code === \"ERR_MODULE_NOT_FOUND\" &&\n\t\tPredicate.hasProperty(cause, \"url\") &&\n\t\tcause.url === url) ||\n\t\t(cause.code === \"ENOENT\" &&\n\t\t\tPredicate.hasProperty(cause, \"path\") &&\n\t\t\tcause.path === fileURLToPath(url)))\n\n// Allocated only when a session starts; importing this module performs no I/O.\nlet sessions = 0\n\n/** A resolution view that allocates fresh URLs for new or invalidated instances. */\nexport interface Generation {\n\treadonly id: number\n}\n\n/** Digest of the bytes actually loaded by a concrete module instance. */\nexport interface FileVersion {\n\treadonly generation: number\n\treadonly content: string | undefined\n\treadonly resolution?: string\n}\n\nexport interface Attempt {\n\treadonly generation: Generation\n\treadonly url: string\n\treadonly request?: string\n}\n\ninterface Dependency extends Attempt {\n\treadonly node: string\n}\n\n/** Resolve local requests lexically; Node's cached physical target is a separate fact. */\nconst fileRequest = (\n\tspecifier: string,\n\tparent: string,\n): Option.Option<string> => {\n\tif (\n\t\t!Array.some([\"file:\", \"./\", \"../\", \"/\"], (prefix) =>\n\t\t\tString.startsWith(prefix)(specifier),\n\t\t)\n\t)\n\t\treturn Option.none()\n\tconst url = new URL(specifier, parent)\n\treturn url.protocol === \"file:\" ? Option.some(url.href) : Option.none()\n}\n\n/** A scoped Node hook. Mutable bindings bridge synchronous hooks to Effect. */\nexport const modules = (base: string, include: (url: string) => boolean) => {\n\tconst key = `graft-hmr-${++sessions}`\n\tconst prefix = `${key}:`\n\tconst rawPrefix = `${key}:raw:`\n\t/** What `request` produces: the generation that imports a specifier. */\n\tconst decodeRequest = Schema.decodeUnknownOption(\n\t\tSchema.TemplateLiteralParser([\n\t\t\tprefix,\n\t\t\tSchema.String.check(Schema.isPattern(/^\\d+$/)),\n\t\t\t\":\",\n\t\t\tSchema.String,\n\t\t]),\n\t)\n\tlet revision = 0\n\tlet importing:\n\t\t{ readonly generation: Generation; readonly reload: boolean } | undefined\n\tlet resolved: string | undefined\n\t// Resolution views contain only routing identities. Old code can execute after\n\t// replacement (including teardown), so these persistent maps live until close.\n\t// Cached instances also retain their facts: Node does not replay static imports.\n\t// Leases restrict observation, not the lifetime of old routing targets.\n\tlet views = HashMap.empty<number, HashMap.HashMap<string, string>>()\n\tlet edges = HashMap.empty<string, HashMap.HashMap<string, Dependency>>()\n\tlet sources = HashMap.empty<string, string>()\n\tlet dependencies = HashSet.empty<string>()\n\tlet reachCache = HashMap.empty<string, HashSet.HashSet<string>>()\n\tlet retained = HashSet.empty<string>()\n\tlet instantiatedViews = HashSet.empty<number>()\n\tconst clean = (url: string): string => {\n\t\tconst value = new URL(url)\n\t\tvalue.searchParams.delete(key)\n\t\treturn value.href\n\t}\n\tconst version = (url: string | undefined): number | undefined => {\n\t\tif (url === undefined) return undefined\n\t\tconst value = new URL(url).searchParams.get(key)\n\t\treturn value === null ? undefined : Number(value)\n\t}\n\tconst tag = (url: string, id: number) => {\n\t\tconst value = new URL(url)\n\t\tvalue.searchParams.set(key, String.String(id))\n\t\treturn value.href\n\t}\n\tconst route = (url: string, id: number): string =>\n\t\tOption.getOrElse(\n\t\t\tHashMap.get(\n\t\t\t\tOption.getOrElse(HashMap.get(views, id), HashMap.empty<string, string>),\n\t\t\t\turl,\n\t\t\t),\n\t\t\t() => tag(url, id),\n\t\t)\n\n\tconst root = (attempt: Attempt) => route(attempt.url, attempt.generation.id)\n\tconst children = (node: string) =>\n\t\tOption.getOrElse(\n\t\t\tHashMap.get(edges, node),\n\t\t\tHashMap.empty<string, Dependency>,\n\t\t)\n\tconst reachable = (node: string) => {\n\t\tconst cached = HashMap.get(reachCache, node)\n\t\tif (Option.isSome(cached)) return cached.value\n\t\tlet seen = HashSet.empty<string>()\n\t\tlet pending: Chunk.Chunk<string> = Chunk.of(node)\n\t\twhile (Chunk.isNonEmpty(pending)) {\n\t\t\tconst current = Chunk.headNonEmpty(pending)\n\t\t\tpending = Chunk.drop(pending, 1)\n\t\t\tif (HashSet.has(seen, current)) continue\n\t\t\tseen = HashSet.add(seen, current)\n\t\t\tfor (const edge of HashMap.values(children(current)))\n\t\t\t\tpending = Chunk.prepend(pending, edge.node)\n\t\t}\n\t\treachCache = HashMap.set(reachCache, node, seen)\n\t\treturn seen\n\t}\n\tconst usedBy = (attempts: ReadonlyArray<Attempt>) => {\n\t\tconst roots = HashSet.fromIterable(Array.map(attempts, root))\n\t\tlet used = HashSet.empty<string>()\n\t\tfor (const node of roots) used = HashSet.union(used, reachable(node))\n\t\treturn used\n\t}\n\tconst link = (parent: string, node: string, request?: string) => {\n\t\tif (\n\t\t\timporting === undefined &&\n\t\t\t!HashSet.has(retained, parent) &&\n\t\t\t!HashSet.has(instantiatedViews, version(parent)!)\n\t\t)\n\t\t\treturn\n\t\tretained = HashSet.add(retained, node)\n\t\tconst url = clean(node)\n\t\tconst edge = {\n\t\t\tnode,\n\t\t\turl,\n\t\t\tgeneration: { id: version(node)! },\n\t\t\t...(request === undefined ? {} : { request }),\n\t\t}\n\t\tconst previous = HashMap.get(children(parent), request ?? url)\n\t\tif (\n\t\t\tOption.exists(\n\t\t\t\tprevious,\n\t\t\t\t(previous) => previous.node === node && previous.request === request,\n\t\t\t)\n\t\t)\n\t\t\treturn\n\t\tedges = HashMap.set(\n\t\t\tedges,\n\t\t\tparent,\n\t\t\tHashMap.set(children(parent), request ?? url, edge),\n\t\t)\n\t\treachCache = HashMap.empty()\n\t}\n\tconst resolutions = (\n\t\tattempts: ReadonlyArray<Attempt>,\n\t): ReadonlyArray<Attempt> => [\n\t\t...Array.filter(attempts, (attempt) => attempt.request !== undefined),\n\t\t...Array.flatMap(Array.fromIterable(usedBy(attempts)), (node) =>\n\t\t\tArray.filter(\n\t\t\t\tHashMap.toValues(children(node)),\n\t\t\t\t(edge) => edge.request !== undefined,\n\t\t\t),\n\t\t),\n\t]\n\tconst unsupported = (url: string, format: string | null | undefined) =>\n\t\tformat === \"commonjs\" ||\n\t\tformat === \"commonjs-typescript\" ||\n\t\tformat === \"addon\" ||\n\t\tString.endsWith(\".node\")(new URL(url).pathname)\n\tconst requireRestart = (node: string) => {\n\t\tif (importing !== undefined || HashSet.has(retained, node))\n\t\t\tdependencies = HashSet.add(dependencies, node)\n\t\tif (importing?.reload === true && importing.generation.id === version(node))\n\t\t\tthrow RestartRequired.make({ url: clean(node) })\n\t}\n\tconst record = (node: string, format: string | null | undefined) => {\n\t\tif (unsupported(clean(node), format)) requireRestart(node)\n\t}\n\t// One reverse traversal closes cycles and all importers of every dirty instance.\n\tconst invalidated = (\n\t\tattempts: ReadonlyArray<Attempt>,\n\t\tdirty: HashSet.HashSet<string>,\n\t) => {\n\t\tconst used = usedBy(attempts)\n\t\tlet parents = HashMap.empty<string, HashSet.HashSet<string>>()\n\t\tlet pending = Chunk.empty<string>()\n\t\tfor (const node of used) {\n\t\t\tif (HashSet.has(dirty, clean(node)))\n\t\t\t\tpending = Chunk.prepend(pending, node)\n\t\t\tfor (const edge of HashMap.values(children(node))) {\n\t\t\t\tparents = HashMap.set(\n\t\t\t\t\tparents,\n\t\t\t\t\tedge.node,\n\t\t\t\t\tHashSet.add(\n\t\t\t\t\t\tOption.getOrElse(\n\t\t\t\t\t\t\tHashMap.get(parents, edge.node),\n\t\t\t\t\t\t\tHashSet.empty<string>,\n\t\t\t\t\t\t),\n\t\t\t\t\t\tnode,\n\t\t\t\t\t),\n\t\t\t\t)\n\t\t\t\tif (edge.request !== undefined && HashSet.has(dirty, edge.request))\n\t\t\t\t\tpending = Chunk.prepend(pending, edge.node)\n\t\t\t}\n\t\t}\n\t\tfor (const attempt of attempts)\n\t\t\tif (attempt.request !== undefined && HashSet.has(dirty, attempt.request))\n\t\t\t\tpending = Chunk.prepend(pending, root(attempt))\n\t\tlet invalid = HashSet.empty<string>()\n\t\twhile (Chunk.isNonEmpty(pending)) {\n\t\t\tconst node = Chunk.headNonEmpty(pending)\n\t\t\tpending = Chunk.drop(pending, 1)\n\t\t\tif (HashSet.has(invalid, node)) continue\n\t\t\tinvalid = HashSet.add(invalid, node)\n\t\t\tfor (const parent of Option.getOrElse(\n\t\t\t\tHashMap.get(parents, node),\n\t\t\t\tHashSet.empty<string>,\n\t\t\t))\n\t\t\t\tpending = Chunk.prepend(pending, parent)\n\t\t}\n\t\treturn invalid\n\t}\n\tconst prepare = (\n\t\tattempts: ReadonlyArray<Attempt> = [],\n\t\tinvalid = HashSet.empty<string>(),\n\t): Generation => {\n\t\tconst id = ++revision\n\t\tconst seed = Array.reduce(attempts, 0, (id, attempt) =>\n\t\t\tMath.max(id, attempt.generation.id),\n\t\t)\n\t\tlet view = Option.getOrElse(\n\t\t\tHashMap.get(views, seed),\n\t\t\tHashMap.empty<string, string>,\n\t\t)\n\t\tconst used = usedBy(attempts)\n\t\t// Retain HAMT structure between views. Default routes need no stored entry;\n\t\t// only modules reused from older views need an explicit override.\n\t\tfor (const [url, node] of view)\n\t\t\tif (!HashSet.has(used, node) || HashSet.has(invalid, node))\n\t\t\t\tview = HashMap.remove(view, url)\n\t\tfor (const node of used) {\n\t\t\tif (HashSet.has(invalid, node)) continue\n\t\t\tconst url = clean(node)\n\t\t\tconst previous = HashMap.get(view, url)\n\t\t\tif (Option.isNone(previous) || version(previous.value)! < version(node)!)\n\t\t\t\tview = HashMap.set(view, url, node)\n\t\t}\n\n\t\tviews = HashMap.set(views, id, view)\n\t\treturn { id }\n\t}\n\tconst hooks = registerHooks({\n\t\tresolve(specifier, context, nextResolve) {\n\t\t\tif (String.startsWith(rawPrefix)(specifier))\n\t\t\t\treturn nextResolve(String.slice(rawPrefix.length)(specifier), {\n\t\t\t\t\t...context,\n\t\t\t\t\tparentURL: base,\n\t\t\t\t})\n\t\t\tconst parentNode = context.parentURL\n\t\t\tconst request = decodeRequest(specifier)\n\t\t\tconst entry = Option.isSome(request)\n\t\t\tconst id = Option.match(request, {\n\t\t\t\tonNone: () => version(context.parentURL),\n\t\t\t\tonSome: ([, id]) => Number(id),\n\t\t\t})\n\t\t\tif (id === undefined) return nextResolve(specifier, context)\n\t\t\tconst target = Option.match(request, {\n\t\t\t\tonNone: () => specifier,\n\t\t\t\tonSome: ([, , , target]) => target,\n\t\t\t})\n\t\t\tconst parent = entry ? base : clean(context.parentURL!)\n\t\t\tconst lexical = Option.getOrUndefined(fileRequest(target, parent))\n\t\t\tconst result = (() => {\n\t\t\t\ttry {\n\t\t\t\t\treturn nextResolve(target, { ...context, parentURL: parent })\n\t\t\t\t} catch (cause) {\n\t\t\t\t\tif (\n\t\t\t\t\t\tPredicate.hasProperty(cause, \"url\") &&\n\t\t\t\t\t\ttypeof cause.url === \"string\" &&\n\t\t\t\t\t\tString.startsWith(\"file:\")(cause.url)\n\t\t\t\t\t) {\n\t\t\t\t\t\tif (entry) resolved = cause.url\n\t\t\t\t\t\telse if (include(cause.url))\n\t\t\t\t\t\t\tlink(parentNode!, route(cause.url, id), lexical)\n\t\t\t\t\t}\n\t\t\t\t\tthrow cause\n\t\t\t\t}\n\t\t\t})()\n\t\t\tif (entry) resolved = result.url\n\t\t\tif (!entry && result.url === \"node:module\") {\n\t\t\t\tconst node = route(result.url, id)\n\t\t\t\tlink(parentNode!, node)\n\t\t\t\trequireRestart(node)\n\t\t\t}\n\t\t\tif (\n\t\t\t\t!String.startsWith(\"file:\")(result.url) ||\n\t\t\t\t(!entry && !include(result.url))\n\t\t\t)\n\t\t\t\treturn result\n\t\t\tconst node = route(result.url, id)\n\t\t\tif (!entry) link(parentNode!, node, lexical)\n\t\t\tconst required = Array.contains(context.conditions, \"require\")\n\t\t\tif (required) requireRestart(node)\n\t\t\telse record(node, result.format)\n\t\t\treturn required || unsupported(result.url, result.format)\n\t\t\t\t? result\n\t\t\t\t: { ...result, url: node }\n\t\t},\n\t\tload(url, context, nextLoad) {\n\t\t\tconst id = version(url)\n\t\t\tif (id === undefined) return nextLoad(url, context)\n\t\t\tinstantiatedViews = HashSet.add(instantiatedViews, id)\n\t\t\tconst original = clean(url)\n\t\t\trecord(url, context.format)\n\t\t\tconst result = nextLoad(original, context)\n\t\t\tconst source = result.source\n\t\t\tif (source !== undefined && source !== null) {\n\t\t\t\tconst bytes =\n\t\t\t\t\ttypeof source === \"string\"\n\t\t\t\t\t\t? source\n\t\t\t\t\t\t: ArrayBuffer.isView(source)\n\t\t\t\t\t\t\t? new Uint8Array(\n\t\t\t\t\t\t\t\t\tsource.buffer,\n\t\t\t\t\t\t\t\t\tsource.byteOffset,\n\t\t\t\t\t\t\t\t\tsource.byteLength,\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t: new Uint8Array(source)\n\t\t\t\tif (importing !== undefined || HashSet.has(retained, url))\n\t\t\t\t\tsources = HashMap.set(sources, url, digest(bytes))\n\t\t\t}\n\t\t\trecord(url, result.format)\n\t\t\treturn result\n\t\t},\n\t})\n\tconst files = (attempts: ReadonlyArray<Attempt>) => {\n\t\tlet files = HashMap.empty<string, FileVersion>()\n\t\tconst put = (url: string, node: string, resolution?: string) => {\n\t\t\tif (!String.startsWith(\"file:\")(url) || HashSet.has(dependencies, node))\n\t\t\t\treturn\n\t\t\tconst generation = version(node)!\n\t\t\tconst previous = HashMap.get(files, url)\n\t\t\tif (\n\t\t\t\tOption.exists(\n\t\t\t\t\tprevious,\n\t\t\t\t\t(previous) =>\n\t\t\t\t\t\tprevious.generation > generation ||\n\t\t\t\t\t\t(previous.generation === generation &&\n\t\t\t\t\t\t\tprevious.resolution !== undefined),\n\t\t\t\t)\n\t\t\t)\n\t\t\t\treturn\n\t\t\tfiles = HashMap.set(files, url, {\n\t\t\t\tgeneration,\n\t\t\t\tcontent: Option.getOrUndefined(HashMap.get(sources, node)),\n\t\t\t\t...(resolution === undefined ? {} : { resolution }),\n\t\t\t})\n\t\t}\n\t\tfor (const node of usedBy(attempts)) put(clean(node), node)\n\t\tfor (const attempt of resolutions(attempts))\n\t\t\tif (attempt.request !== undefined)\n\t\t\t\tput(\n\t\t\t\t\tattempt.request,\n\t\t\t\t\troot(attempt),\n\t\t\t\t\tpathToFileURL(fileURLToPath(attempt.url)).href,\n\t\t\t\t)\n\t\treturn files\n\t}\n\treturn {\n\t\tprepare,\n\t\tfiles,\n\t\tresolutions,\n\t\tinvalidated,\n\t\taffected: (attempt: Attempt, invalid: HashSet.HashSet<string>) =>\n\t\t\tHashSet.has(invalid, root(attempt)),\n\t\tfileRequest: (specifier: string) => fileRequest(specifier, base),\n\t\tunsupported: (generation: Generation, roots?: ReadonlyArray<string>) => {\n\t\t\tconst used =\n\t\t\t\troots === undefined\n\t\t\t\t\t? undefined\n\t\t\t\t\t: usedBy(Array.map(roots, (url) => ({ url, generation })))\n\t\t\treturn HashSet.fromIterable(\n\t\t\t\tArray.map(\n\t\t\t\t\tArray.filter(Array.fromIterable(dependencies), (node) =>\n\t\t\t\t\t\tused === undefined\n\t\t\t\t\t\t\t? version(node) === generation.id\n\t\t\t\t\t\t\t: HashSet.has(used, node),\n\t\t\t\t\t),\n\t\t\t\t\tclean,\n\t\t\t\t),\n\t\t\t)\n\t\t},\n\t\tcollect: (attempts: ReadonlyArray<Attempt>) => {\n\t\t\tconst used = usedBy(attempts)\n\t\t\tconst ownedViews = HashSet.fromIterable(\n\t\t\t\tArray.map(attempts, (attempt) => attempt.generation.id),\n\t\t\t)\n\t\t\tviews = HashMap.filter(\n\t\t\t\tviews,\n\t\t\t\t(_, id) =>\n\t\t\t\t\tid === revision ||\n\t\t\t\t\tHashSet.has(instantiatedViews, id) ||\n\t\t\t\t\tHashSet.has(ownedViews, id),\n\t\t\t)\n\t\t\t// Old code can reach any default route in its instantiated view, even\n\t\t\t// after every lease on that target closed. Preserve its complete graph,\n\t\t\t// source baseline and native capabilities until the session closes.\n\t\t\tconst keep = (node: string) =>\n\t\t\t\tHashSet.has(used, node) ||\n\t\t\t\tHashSet.has(instantiatedViews, version(node)!)\n\t\t\tretained = used\n\t\t\tsources = HashMap.filter(sources, (_, node) => keep(node))\n\t\t\tedges = HashMap.filter(edges, (_, node) => keep(node))\n\t\t\tdependencies = HashSet.filter(dependencies, keep)\n\t\t\treachCache = HashMap.filter(reachCache, (_, node) =>\n\t\t\t\tHashSet.has(used, node),\n\t\t\t)\n\t\t},\n\t\t// Internal counters support deterministic retention tests and external benchmarks.\n\t\tcounts: () => ({\n\t\t\tsources: HashMap.size(sources),\n\t\t\tedges: HashMap.size(edges),\n\t\t\tdependencies: HashSet.size(dependencies),\n\t\t\tviews: HashMap.size(views),\n\t\t}),\n\t\tstart: (generation: Generation, reload = false) => {\n\t\t\timporting = { generation, reload }\n\t\t},\n\t\tdiscard: () => {\n\t\t\timporting = undefined\n\t\t},\n\t\trequest: (specifier: string) => {\n\t\t\tresolved = undefined\n\t\t\treturn `${prefix}${importing!.generation.id}:${specifier}`\n\t\t},\n\t\trawRequest: (specifier: string) => `${rawPrefix}${specifier}`,\n\t\tresolved: () => Option.fromUndefinedOr(resolved),\n\t\tclose: () => {\n\t\t\thooks.deregister()\n\t\t\tviews = HashMap.empty()\n\t\t\tsources = HashMap.empty()\n\t\t\tedges = HashMap.empty()\n\t\t\tdependencies = HashSet.empty()\n\t\t\treachCache = HashMap.empty()\n\t\t\tretained = HashSet.empty()\n\t\t\tinstantiatedViews = HashSet.empty()\n\t\t},\n\t}\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"modules.js","names":[],"sources":["../../src/internal/modules.ts"],"sourcesContent":["// Node's synchronous module hooks have no Effect equivalent.\nimport { registerHooks } from \"node:module\"\nimport { fileURLToPath, pathToFileURL } from \"node:url\"\n\nimport {\n\tArray,\n\tChunk,\n\tHashMap,\n\tHashSet,\n\tOption,\n\tPredicate,\n\tSchema,\n\tString,\n} from \"effect\"\n\nimport { digest } from \"./digest\"\n\nexport class RestartRequired extends Schema.TaggedError<\n\tRestartRequired,\n\t{ readonly brand: unique symbol }\n>()(\"RestartRequired\", { url: Schema.String }) {}\n\n// Only a missing entry is disposable; missing dependencies still fail the reload.\nexport const isMissingEntry = (url: string, cause: unknown): boolean =>\n\tString.startsWith(\"file:\")(url) &&\n\tPredicate.hasProperty(cause, \"code\") &&\n\t((cause.code === \"ERR_MODULE_NOT_FOUND\" &&\n\t\tPredicate.hasProperty(cause, \"url\") &&\n\t\tcause.url === url) ||\n\t\t(cause.code === \"ENOENT\" &&\n\t\t\tPredicate.hasProperty(cause, \"path\") &&\n\t\t\tcause.path === fileURLToPath(url)))\n\n// Allocated only when a session starts; importing this module performs no I/O.\nlet sessions = 0\n\n/** A resolution view that allocates fresh URLs for new or invalidated instances. */\nexport interface Generation {\n\treadonly id: number\n}\n\n/** Digest of the bytes actually loaded by a concrete module instance. */\nexport interface FileVersion {\n\treadonly generation: number\n\treadonly content: string | undefined\n\treadonly resolution?: string\n}\n\nexport interface Attempt {\n\treadonly generation: Generation\n\treadonly url: string\n\treadonly request?: string\n}\n\ninterface Dependency extends Attempt {\n\treadonly node: string\n}\n\n/** Resolve local requests lexically; Node's cached physical target is a separate fact. */\nconst fileRequest = (\n\tspecifier: string,\n\tparent: string,\n): Option.Option<string> => {\n\tif (\n\t\t!Array.some([\"file:\", \"./\", \"../\", \"/\"], (prefix) =>\n\t\t\tString.startsWith(prefix)(specifier),\n\t\t)\n\t)\n\t\treturn Option.none()\n\tconst url = new URL(specifier, parent)\n\treturn url.protocol === \"file:\" ? Option.some(url.href) : Option.none()\n}\n\n/** A scoped Node hook. Mutable bindings bridge synchronous hooks to Effect. */\nexport const modules = (base: string, include: (url: string) => boolean) => {\n\tconst key = `graft-hmr-${++sessions}`\n\tconst prefix = `${key}:`\n\tconst rawPrefix = `${key}:raw:`\n\t/** What `request` produces: the generation that imports a specifier. */\n\tconst decodeRequest = Schema.decodeUnknownOption(\n\t\tSchema.TemplateLiteralParser([\n\t\t\tprefix,\n\t\t\tSchema.String.check(Schema.isPattern(/^\\d+$/)),\n\t\t\t\":\",\n\t\t\tSchema.String,\n\t\t]),\n\t)\n\tlet revision = 0\n\tlet importing:\n\t\t{ readonly generation: Generation; readonly reload: boolean } | undefined\n\tlet resolved: string | undefined\n\t// Resolution views contain only routing identities. Old code can execute after\n\t// replacement (including teardown), so these persistent maps live until close.\n\t// Cached instances also retain their facts: Node does not replay static imports.\n\t// Leases restrict observation, not the lifetime of old routing targets.\n\tlet views = HashMap.empty<number, HashMap.HashMap<string, string>>()\n\tlet edges = HashMap.empty<string, HashMap.HashMap<string, Dependency>>()\n\tlet sources = HashMap.empty<string, string>()\n\tlet dependencies = HashSet.empty<string>()\n\tlet reachCache = HashMap.empty<string, HashSet.HashSet<string>>()\n\tlet retained = HashSet.empty<string>()\n\tlet instantiatedViews = HashSet.empty<number>()\n\tconst clean = (url: string): string => {\n\t\tconst value = new URL(url)\n\t\tvalue.searchParams.delete(key)\n\t\treturn value.href\n\t}\n\tconst version = (url: string | undefined): number | undefined => {\n\t\tif (url === undefined) return undefined\n\t\tconst value = new URL(url).searchParams.get(key)\n\t\treturn value === null ? undefined : Number(value)\n\t}\n\tconst tag = (url: string, id: number) => {\n\t\tconst value = new URL(url)\n\t\tvalue.searchParams.set(key, String.String(id))\n\t\treturn value.href\n\t}\n\tconst route = (url: string, id: number): string =>\n\t\tOption.getOrElse(\n\t\t\tHashMap.get(\n\t\t\t\tOption.getOrElse(HashMap.get(views, id), HashMap.empty<string, string>),\n\t\t\t\turl,\n\t\t\t),\n\t\t\t() => tag(url, id),\n\t\t)\n\n\tconst root = (attempt: Attempt) => route(attempt.url, attempt.generation.id)\n\tconst children = (node: string) =>\n\t\tOption.getOrElse(\n\t\t\tHashMap.get(edges, node),\n\t\t\tHashMap.empty<string, Dependency>,\n\t\t)\n\tconst reachable = (node: string) => {\n\t\tconst cached = HashMap.get(reachCache, node)\n\t\tif (Option.isSome(cached)) return cached.value\n\t\tlet seen = HashSet.empty<string>()\n\t\tlet pending: Chunk.Chunk<string> = Chunk.of(node)\n\t\twhile (Chunk.isNonEmpty(pending)) {\n\t\t\tconst current = Chunk.headNonEmpty(pending)\n\t\t\tpending = Chunk.drop(pending, 1)\n\t\t\tif (HashSet.has(seen, current)) continue\n\t\t\tseen = HashSet.add(seen, current)\n\t\t\tfor (const edge of HashMap.values(children(current)))\n\t\t\t\tpending = Chunk.prepend(pending, edge.node)\n\t\t}\n\t\treachCache = HashMap.set(reachCache, node, seen)\n\t\treturn seen\n\t}\n\tconst usedBy = (attempts: ReadonlyArray<Attempt>) => {\n\t\tconst roots = HashSet.fromIterable(Array.map(attempts, root))\n\t\tlet used = HashSet.empty<string>()\n\t\tfor (const node of roots) used = HashSet.union(used, reachable(node))\n\t\treturn used\n\t}\n\tconst link = (parent: string, node: string, request?: string) => {\n\t\tif (\n\t\t\timporting === undefined &&\n\t\t\t!HashSet.has(retained, parent) &&\n\t\t\t!HashSet.has(instantiatedViews, version(parent)!)\n\t\t)\n\t\t\treturn\n\t\tretained = HashSet.add(retained, node)\n\t\tconst url = clean(node)\n\t\tconst edge = {\n\t\t\tnode,\n\t\t\turl,\n\t\t\tgeneration: { id: version(node)! },\n\t\t\t...(request === undefined ? {} : { request }),\n\t\t}\n\t\tconst previous = HashMap.get(children(parent), request ?? url)\n\t\tif (\n\t\t\tOption.exists(\n\t\t\t\tprevious,\n\t\t\t\t(previous) => previous.node === node && previous.request === request,\n\t\t\t)\n\t\t)\n\t\t\treturn\n\t\tedges = HashMap.set(\n\t\t\tedges,\n\t\t\tparent,\n\t\t\tHashMap.set(children(parent), request ?? url, edge),\n\t\t)\n\t\treachCache = HashMap.empty()\n\t}\n\tconst resolutions = (\n\t\tattempts: ReadonlyArray<Attempt>,\n\t): ReadonlyArray<Attempt> => [\n\t\t...Array.filter(attempts, (attempt) => attempt.request !== undefined),\n\t\t...Array.flatMap(Array.fromIterable(usedBy(attempts)), (node) =>\n\t\t\tArray.filter(\n\t\t\t\tHashMap.toValues(children(node)),\n\t\t\t\t(edge) => edge.request !== undefined,\n\t\t\t),\n\t\t),\n\t]\n\tconst unsupported = (url: string, format: string | null | undefined) =>\n\t\tformat === \"commonjs\" ||\n\t\tformat === \"commonjs-typescript\" ||\n\t\tformat === \"addon\" ||\n\t\tString.endsWith(\".node\")(new URL(url).pathname)\n\tconst requireRestart = (node: string) => {\n\t\tif (importing !== undefined || HashSet.has(retained, node))\n\t\t\tdependencies = HashSet.add(dependencies, node)\n\t\tif (importing?.reload === true && importing.generation.id === version(node))\n\t\t\tthrow RestartRequired.make({ url: clean(node) })\n\t}\n\tconst record = (node: string, format: string | null | undefined) => {\n\t\tif (unsupported(clean(node), format)) requireRestart(node)\n\t}\n\t// One reverse traversal closes cycles and all importers of every dirty instance.\n\tconst invalidated = (\n\t\tattempts: ReadonlyArray<Attempt>,\n\t\tdirty: HashSet.HashSet<string>,\n\t) => {\n\t\tconst used = usedBy(attempts)\n\t\tlet parents = HashMap.empty<string, HashSet.HashSet<string>>()\n\t\tlet pending = Chunk.empty<string>()\n\t\tfor (const node of used) {\n\t\t\tif (HashSet.has(dirty, clean(node)))\n\t\t\t\tpending = Chunk.prepend(pending, node)\n\t\t\tfor (const edge of HashMap.values(children(node))) {\n\t\t\t\tparents = HashMap.set(\n\t\t\t\t\tparents,\n\t\t\t\t\tedge.node,\n\t\t\t\t\tHashSet.add(\n\t\t\t\t\t\tOption.getOrElse(\n\t\t\t\t\t\t\tHashMap.get(parents, edge.node),\n\t\t\t\t\t\t\tHashSet.empty<string>,\n\t\t\t\t\t\t),\n\t\t\t\t\t\tnode,\n\t\t\t\t\t),\n\t\t\t\t)\n\t\t\t\tif (edge.request !== undefined && HashSet.has(dirty, edge.request))\n\t\t\t\t\tpending = Chunk.prepend(pending, edge.node)\n\t\t\t}\n\t\t}\n\t\tfor (const attempt of attempts)\n\t\t\tif (attempt.request !== undefined && HashSet.has(dirty, attempt.request))\n\t\t\t\tpending = Chunk.prepend(pending, root(attempt))\n\t\tlet invalid = HashSet.empty<string>()\n\t\twhile (Chunk.isNonEmpty(pending)) {\n\t\t\tconst node = Chunk.headNonEmpty(pending)\n\t\t\tpending = Chunk.drop(pending, 1)\n\t\t\tif (HashSet.has(invalid, node)) continue\n\t\t\tinvalid = HashSet.add(invalid, node)\n\t\t\tfor (const parent of Option.getOrElse(\n\t\t\t\tHashMap.get(parents, node),\n\t\t\t\tHashSet.empty<string>,\n\t\t\t))\n\t\t\t\tpending = Chunk.prepend(pending, parent)\n\t\t}\n\t\treturn invalid\n\t}\n\tconst prepare = (\n\t\tattempts: ReadonlyArray<Attempt> = [],\n\t\tinvalid = HashSet.empty<string>(),\n\t): Generation => {\n\t\tconst id = ++revision\n\t\tconst seed = Array.reduce(attempts, 0, (id, attempt) =>\n\t\t\tMath.max(id, attempt.generation.id),\n\t\t)\n\t\tlet view = Option.getOrElse(\n\t\t\tHashMap.get(views, seed),\n\t\t\tHashMap.empty<string, string>,\n\t\t)\n\t\tconst used = usedBy(attempts)\n\t\t// Retain HAMT structure between views. Default routes need no stored entry;\n\t\t// only modules reused from older views need an explicit override.\n\t\tfor (const [url, node] of view)\n\t\t\tif (!HashSet.has(used, node) || HashSet.has(invalid, node))\n\t\t\t\tview = HashMap.remove(view, url)\n\t\tfor (const node of used) {\n\t\t\tif (HashSet.has(invalid, node)) continue\n\t\t\tconst url = clean(node)\n\t\t\tconst previous = HashMap.get(view, url)\n\t\t\tif (Option.isNone(previous) || version(previous.value)! < version(node)!)\n\t\t\t\tview = HashMap.set(view, url, node)\n\t\t}\n\n\t\tviews = HashMap.set(views, id, view)\n\t\treturn { id }\n\t}\n\tconst hooks = registerHooks({\n\t\tresolve(specifier, context, nextResolve) {\n\t\t\tif (String.startsWith(rawPrefix)(specifier))\n\t\t\t\treturn nextResolve(String.slice(rawPrefix.length)(specifier), {\n\t\t\t\t\t...context,\n\t\t\t\t\tparentURL: base,\n\t\t\t\t})\n\t\t\tconst parentNode = context.parentURL\n\t\t\tconst request = decodeRequest(specifier)\n\t\t\tconst entry = Option.isSome(request)\n\t\t\tconst id = Option.match(request, {\n\t\t\t\tonNone: () => version(context.parentURL),\n\t\t\t\tonSome: ([, id]) => Number(id),\n\t\t\t})\n\t\t\tif (id === undefined) return nextResolve(specifier, context)\n\t\t\tconst target = Option.match(request, {\n\t\t\t\tonNone: () => specifier,\n\t\t\t\tonSome: ([, , , target]) => target,\n\t\t\t})\n\t\t\tconst parent = entry ? base : clean(context.parentURL!)\n\t\t\tconst lexical = Option.getOrUndefined(fileRequest(target, parent))\n\t\t\tconst result = (() => {\n\t\t\t\ttry {\n\t\t\t\t\treturn nextResolve(target, { ...context, parentURL: parent })\n\t\t\t\t} catch (cause) {\n\t\t\t\t\tif (\n\t\t\t\t\t\tPredicate.hasProperty(cause, \"url\") &&\n\t\t\t\t\t\ttypeof cause.url === \"string\" &&\n\t\t\t\t\t\tString.startsWith(\"file:\")(cause.url)\n\t\t\t\t\t) {\n\t\t\t\t\t\tif (entry) resolved = cause.url\n\t\t\t\t\t\telse if (include(cause.url))\n\t\t\t\t\t\t\tlink(parentNode!, route(cause.url, id), lexical)\n\t\t\t\t\t}\n\t\t\t\t\tthrow cause\n\t\t\t\t}\n\t\t\t})()\n\t\t\tif (entry) resolved = result.url\n\t\t\tif (!entry && result.url === \"node:module\") {\n\t\t\t\tconst node = route(result.url, id)\n\t\t\t\tlink(parentNode!, node)\n\t\t\t\trequireRestart(node)\n\t\t\t}\n\t\t\tif (\n\t\t\t\t!String.startsWith(\"file:\")(result.url) ||\n\t\t\t\t(!entry && !include(result.url))\n\t\t\t)\n\t\t\t\treturn result\n\t\t\tconst node = route(result.url, id)\n\t\t\tif (!entry) link(parentNode!, node, lexical)\n\t\t\tconst required = Array.contains(context.conditions, \"require\")\n\t\t\tif (required) requireRestart(node)\n\t\t\telse record(node, result.format)\n\t\t\treturn required || unsupported(result.url, result.format)\n\t\t\t\t? result\n\t\t\t\t: { ...result, url: node }\n\t\t},\n\t\tload(url, context, nextLoad) {\n\t\t\tconst id = version(url)\n\t\t\tif (id === undefined) return nextLoad(url, context)\n\t\t\tinstantiatedViews = HashSet.add(instantiatedViews, id)\n\t\t\tconst original = clean(url)\n\t\t\trecord(url, context.format)\n\t\t\tconst result = nextLoad(original, context)\n\t\t\tconst source = result.source\n\t\t\tif (source !== undefined && source !== null) {\n\t\t\t\tconst bytes =\n\t\t\t\t\ttypeof source === \"string\"\n\t\t\t\t\t\t? source\n\t\t\t\t\t\t: ArrayBuffer.isView(source)\n\t\t\t\t\t\t\t? new Uint8Array(\n\t\t\t\t\t\t\t\t\tsource.buffer,\n\t\t\t\t\t\t\t\t\tsource.byteOffset,\n\t\t\t\t\t\t\t\t\tsource.byteLength,\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t: new Uint8Array(source)\n\t\t\t\tif (importing !== undefined || HashSet.has(retained, url))\n\t\t\t\t\tsources = HashMap.set(sources, url, digest(bytes))\n\t\t\t}\n\t\t\trecord(url, result.format)\n\t\t\treturn result\n\t\t},\n\t})\n\tconst files = (attempts: ReadonlyArray<Attempt>) => {\n\t\tlet files = HashMap.empty<string, FileVersion>()\n\t\tconst put = (url: string, node: string, resolution?: string) => {\n\t\t\tif (!String.startsWith(\"file:\")(url) || HashSet.has(dependencies, node))\n\t\t\t\treturn\n\t\t\tconst generation = version(node)!\n\t\t\tconst previous = HashMap.get(files, url)\n\t\t\tif (\n\t\t\t\tOption.exists(\n\t\t\t\t\tprevious,\n\t\t\t\t\t(previous) =>\n\t\t\t\t\t\tprevious.generation > generation ||\n\t\t\t\t\t\t(previous.generation === generation &&\n\t\t\t\t\t\t\tprevious.resolution !== undefined),\n\t\t\t\t)\n\t\t\t)\n\t\t\t\treturn\n\t\t\tfiles = HashMap.set(files, url, {\n\t\t\t\tgeneration,\n\t\t\t\tcontent: Option.getOrUndefined(HashMap.get(sources, node)),\n\t\t\t\t...(resolution === undefined ? {} : { resolution }),\n\t\t\t})\n\t\t}\n\t\tfor (const node of usedBy(attempts)) put(clean(node), node)\n\t\tfor (const attempt of resolutions(attempts))\n\t\t\tif (attempt.request !== undefined)\n\t\t\t\tput(\n\t\t\t\t\tattempt.request,\n\t\t\t\t\troot(attempt),\n\t\t\t\t\tpathToFileURL(fileURLToPath(attempt.url)).href,\n\t\t\t\t)\n\t\treturn files\n\t}\n\treturn {\n\t\tprepare,\n\t\tfiles,\n\t\tresolutions,\n\t\tinvalidated,\n\t\taffected: (attempt: Attempt, invalid: HashSet.HashSet<string>) =>\n\t\t\tHashSet.has(invalid, root(attempt)),\n\t\tfileRequest: (specifier: string) => fileRequest(specifier, base),\n\t\tunsupported: (generation: Generation, roots?: ReadonlyArray<string>) => {\n\t\t\tconst used =\n\t\t\t\troots === undefined\n\t\t\t\t\t? undefined\n\t\t\t\t\t: usedBy(Array.map(roots, (url) => ({ url, generation })))\n\t\t\treturn HashSet.fromIterable(\n\t\t\t\tArray.map(\n\t\t\t\t\tArray.filter(Array.fromIterable(dependencies), (node) =>\n\t\t\t\t\t\tused === undefined\n\t\t\t\t\t\t\t? version(node) === generation.id\n\t\t\t\t\t\t\t: HashSet.has(used, node),\n\t\t\t\t\t),\n\t\t\t\t\tclean,\n\t\t\t\t),\n\t\t\t)\n\t\t},\n\t\tcollect: (attempts: ReadonlyArray<Attempt>) => {\n\t\t\tconst used = usedBy(attempts)\n\t\t\tconst ownedViews = HashSet.fromIterable(\n\t\t\t\tArray.map(attempts, (attempt) => attempt.generation.id),\n\t\t\t)\n\t\t\tviews = HashMap.filter(\n\t\t\t\tviews,\n\t\t\t\t(_, id) =>\n\t\t\t\t\tid === revision ||\n\t\t\t\t\tHashSet.has(instantiatedViews, id) ||\n\t\t\t\t\tHashSet.has(ownedViews, id),\n\t\t\t)\n\t\t\t// Old code can reach any default route in its instantiated view, even\n\t\t\t// after every lease on that target closed. Preserve its complete graph,\n\t\t\t// source baseline and native capabilities until the session closes.\n\t\t\tconst keep = (node: string) =>\n\t\t\t\tHashSet.has(used, node) ||\n\t\t\t\tHashSet.has(instantiatedViews, version(node)!)\n\t\t\tretained = used\n\t\t\tsources = HashMap.filter(sources, (_, node) => keep(node))\n\t\t\tedges = HashMap.filter(edges, (_, node) => keep(node))\n\t\t\tdependencies = HashSet.filter(dependencies, keep)\n\t\t\treachCache = HashMap.filter(reachCache, (_, node) =>\n\t\t\t\tHashSet.has(used, node),\n\t\t\t)\n\t\t},\n\t\t// Internal counters support deterministic retention tests and external benchmarks.\n\t\tcounts: () => ({\n\t\t\tsources: HashMap.size(sources),\n\t\t\tedges: HashMap.size(edges),\n\t\t\tdependencies: HashSet.size(dependencies),\n\t\t\tviews: HashMap.size(views),\n\t\t}),\n\t\tstart: (generation: Generation, reload = false) => {\n\t\t\timporting = { generation, reload }\n\t\t},\n\t\tdiscard: () => {\n\t\t\timporting = undefined\n\t\t},\n\t\trequest: (specifier: string) => {\n\t\t\tresolved = undefined\n\t\t\treturn `${prefix}${importing!.generation.id}:${specifier}`\n\t\t},\n\t\trawRequest: (specifier: string) => `${rawPrefix}${specifier}`,\n\t\tresolved: () => Option.fromUndefinedOr(resolved),\n\t\tclose: () => {\n\t\t\thooks.deregister()\n\t\t\tviews = HashMap.empty()\n\t\t\tsources = HashMap.empty()\n\t\t\tedges = HashMap.empty()\n\t\t\tdependencies = HashSet.empty()\n\t\t\treachCache = HashMap.empty()\n\t\t\tretained = HashSet.empty()\n\t\t\tinstantiatedViews = HashSet.empty()\n\t\t},\n\t}\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { changes } from "./changes.js";
|
|
2
|
+
import { digest } from "./digest.js";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
import { Array, Cause, Effect, FileSystem, HashMap, Option, Stream, SubscriptionRef } from "effect";
|
|
5
|
+
// src/internal/sourceObservation.ts
|
|
6
|
+
/** An entry keeps its last known snapshots across execution and watcher failures. */
|
|
7
|
+
const make = Effect.fnUntraced(function* () {
|
|
8
|
+
const scope = yield* Effect.scope;
|
|
9
|
+
const fs = yield* FileSystem.FileSystem;
|
|
10
|
+
const sources = yield* SubscriptionRef.make({
|
|
11
|
+
imports: HashMap.empty(),
|
|
12
|
+
explicit: HashMap.empty(),
|
|
13
|
+
activation: Option.none()
|
|
14
|
+
});
|
|
15
|
+
const snapshot = (value) => Array.reduce(HashMap.toValues(value.imports), value.explicit, (all, files) => HashMap.union(all, files));
|
|
16
|
+
const read = (url) => fs.readFile(fileURLToPath(url)).pipe(Effect.map((bytes) => [url, {
|
|
17
|
+
generation: -1,
|
|
18
|
+
content: digest(bytes)
|
|
19
|
+
}]), Effect.catchIf((error) => error.reason._tag === "NotFound", () => Effect.succeed([url, {
|
|
20
|
+
generation: -1,
|
|
21
|
+
content: void 0
|
|
22
|
+
}])));
|
|
23
|
+
const watch = (files, activation) => Effect.forEach(files, read).pipe(Effect.flatMap((entries) => SubscriptionRef.update(sources, (current) => {
|
|
24
|
+
const explicit = HashMap.union(Option.exists(current.activation, (owner) => owner === activation) ? current.explicit : HashMap.empty(), HashMap.fromIterable(entries));
|
|
25
|
+
return {
|
|
26
|
+
...current,
|
|
27
|
+
explicit,
|
|
28
|
+
activation: Option.some(activation),
|
|
29
|
+
imports: HashMap.filter(current.imports, (_, root) => HashMap.has(explicit, root))
|
|
30
|
+
};
|
|
31
|
+
})), Effect.onError(() => SubscriptionRef.update(sources, (current) => ({
|
|
32
|
+
...current,
|
|
33
|
+
explicit: HashMap.union(HashMap.fromIterable(Array.map(files, (url) => [url, {
|
|
34
|
+
generation: -1,
|
|
35
|
+
content: void 0
|
|
36
|
+
}])), current.explicit)
|
|
37
|
+
}))));
|
|
38
|
+
const imported = (root, files, success) => SubscriptionRef.update(sources, (current) => ({
|
|
39
|
+
...current,
|
|
40
|
+
imports: HashMap.set(current.imports, root, success ? files : HashMap.union(Option.getOrElse(HashMap.get(current.imports, root), HashMap.empty), files))
|
|
41
|
+
}));
|
|
42
|
+
const observe = SubscriptionRef.changes(sources).pipe(Stream.switchMap((current) => {
|
|
43
|
+
const files = snapshot(current);
|
|
44
|
+
if (HashMap.size(files) === 0) return Stream.never;
|
|
45
|
+
return changes((use) => use(files), Array.dedupe(Array.map(Array.fromIterable(HashMap.keys(files)), (url) => fileURLToPath(new URL(".", url)))), { recursive: true }).pipe(Stream.as(void 0));
|
|
46
|
+
}), Stream.provideService(FileSystem.FileSystem, fs));
|
|
47
|
+
const recover = Stream.suspend(() => observe.pipe(Stream.catchCause((cause) => Cause.hasInterruptsOnly(cause) ? Stream.failCause(Cause.fromReasons(Array.filter(cause.reasons, Cause.isInterruptReason))) : Stream.fromEffect(Effect.logError("Source observation failed; retrying", cause).pipe(Effect.andThen(Effect.sleep("1 second")))).pipe(Stream.drain, Stream.concat(recover)))));
|
|
48
|
+
return {
|
|
49
|
+
scope,
|
|
50
|
+
watch,
|
|
51
|
+
changes: recover,
|
|
52
|
+
imported
|
|
53
|
+
};
|
|
54
|
+
});
|
|
55
|
+
export { make };
|
|
56
|
+
|
|
57
|
+
//# sourceMappingURL=sourceObservation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sourceObservation.js","names":[],"sources":["../../src/internal/sourceObservation.ts"],"sourcesContent":["import { fileURLToPath } from \"node:url\"\n\nimport {\n\tArray,\n\tCause,\n\tEffect,\n\tFileSystem,\n\tHashMap,\n\tOption,\n\tScope,\n\tStream,\n\tSubscriptionRef,\n} from \"effect\"\n\nimport { changes } from \"./changes\"\nimport { digest } from \"./digest\"\nimport type { FileVersion } from \"./modules\"\n\ntype Files = HashMap.HashMap<string, FileVersion>\ninterface Sources {\n\treadonly imports: HashMap.HashMap<string, Files>\n\treadonly explicit: Files\n\t/** Explicit files belong to the latest activation that registered any. */\n\treadonly activation: Option.Option<Scope.Scope>\n}\n\n/** An entry keeps its last known snapshots across execution and watcher failures. */\nexport const make = Effect.fnUntraced(function* () {\n\tconst scope = yield* Effect.scope\n\tconst fs = yield* FileSystem.FileSystem\n\tconst sources = yield* SubscriptionRef.make({\n\t\timports: HashMap.empty<string, Files>(),\n\t\texplicit: HashMap.empty<string, FileVersion>(),\n\t\tactivation: Option.none<Scope.Scope>(),\n\t})\n\tconst snapshot = (value: Sources): Files =>\n\t\tArray.reduce(\n\t\t\tHashMap.toValues(value.imports),\n\t\t\tvalue.explicit,\n\t\t\t(all, files) => HashMap.union(all, files),\n\t\t)\n\tconst read = (url: string) =>\n\t\tfs.readFile(fileURLToPath(url)).pipe(\n\t\t\tEffect.map((bytes): readonly [string, FileVersion] => [\n\t\t\t\turl,\n\t\t\t\t{ generation: -1, content: digest(bytes) },\n\t\t\t]),\n\t\t\tEffect.catchIf(\n\t\t\t\t(error) => error.reason._tag === \"NotFound\",\n\t\t\t\t() =>\n\t\t\t\t\tEffect.succeed<readonly [string, FileVersion]>([\n\t\t\t\t\t\turl,\n\t\t\t\t\t\t{ generation: -1, content: undefined },\n\t\t\t\t\t]),\n\t\t\t),\n\t\t)\n\t// An activation may start several remote plugins, so its calls accumulate; a newer activation\n\t// replaces them, and files it no longer uses stop being observed.\n\tconst watch = (files: ReadonlyArray<string>, activation: Scope.Scope) =>\n\t\tEffect.forEach(files, read).pipe(\n\t\t\tEffect.flatMap((entries) =>\n\t\t\t\tSubscriptionRef.update(sources, (current) => {\n\t\t\t\t\tconst explicit = HashMap.union(\n\t\t\t\t\t\tOption.exists(current.activation, (owner) => owner === activation)\n\t\t\t\t\t\t\t? current.explicit\n\t\t\t\t\t\t\t: HashMap.empty<string, FileVersion>(),\n\t\t\t\t\t\tHashMap.fromIterable(entries),\n\t\t\t\t\t)\n\t\t\t\t\treturn {\n\t\t\t\t\t\t...current,\n\t\t\t\t\t\texplicit,\n\t\t\t\t\t\tactivation: Option.some(activation),\n\t\t\t\t\t\timports: HashMap.filter(current.imports, (_, root) =>\n\t\t\t\t\t\t\tHashMap.has(explicit, root),\n\t\t\t\t\t\t),\n\t\t\t\t\t}\n\t\t\t\t}),\n\t\t\t),\n\t\t\tEffect.onError(() =>\n\t\t\t\tSubscriptionRef.update(sources, (current) => ({\n\t\t\t\t\t...current,\n\t\t\t\t\texplicit: HashMap.union(\n\t\t\t\t\t\tHashMap.fromIterable(\n\t\t\t\t\t\t\tArray.map(files, (url): readonly [string, FileVersion] => [\n\t\t\t\t\t\t\t\turl,\n\t\t\t\t\t\t\t\t{ generation: -1, content: undefined },\n\t\t\t\t\t\t\t]),\n\t\t\t\t\t\t),\n\t\t\t\t\t\tcurrent.explicit,\n\t\t\t\t\t),\n\t\t\t\t})),\n\t\t\t),\n\t\t)\n\tconst imported = (root: string, files: Files, success: boolean) =>\n\t\tSubscriptionRef.update(sources, (current) => ({\n\t\t\t...current,\n\t\t\timports: HashMap.set(\n\t\t\t\tcurrent.imports,\n\t\t\t\troot,\n\t\t\t\tsuccess\n\t\t\t\t\t? files\n\t\t\t\t\t: HashMap.union(\n\t\t\t\t\t\t\tOption.getOrElse(\n\t\t\t\t\t\t\t\tHashMap.get(current.imports, root),\n\t\t\t\t\t\t\t\tHashMap.empty<string, FileVersion>,\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\tfiles,\n\t\t\t\t\t\t),\n\t\t\t),\n\t\t}))\n\tconst observe = SubscriptionRef.changes(sources).pipe(\n\t\tStream.switchMap((current) => {\n\t\t\tconst files = snapshot(current)\n\t\t\tif (HashMap.size(files) === 0) return Stream.never\n\t\t\t// Watch parent directories so deleting an entry does not prevent its recovery.\n\t\t\treturn changes(\n\t\t\t\t(use) => use(files),\n\t\t\t\tArray.dedupe(\n\t\t\t\t\tArray.map(Array.fromIterable(HashMap.keys(files)), (url) =>\n\t\t\t\t\t\tfileURLToPath(new URL(\".\", url)),\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\t\t{ recursive: true },\n\t\t\t).pipe(Stream.as(undefined))\n\t\t}),\n\t\tStream.provideService(FileSystem.FileSystem, fs),\n\t)\n\tconst recover: Stream.Stream<void> = Stream.suspend(() =>\n\t\tobserve.pipe(\n\t\t\tStream.catchCause((cause) =>\n\t\t\t\tCause.hasInterruptsOnly(cause)\n\t\t\t\t\t? Stream.failCause(\n\t\t\t\t\t\t\tCause.fromReasons(\n\t\t\t\t\t\t\t\tArray.filter(cause.reasons, Cause.isInterruptReason),\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t)\n\t\t\t\t\t: Stream.fromEffect(\n\t\t\t\t\t\t\tEffect.logError(\n\t\t\t\t\t\t\t\t\"Source observation failed; retrying\",\n\t\t\t\t\t\t\t\tcause,\n\t\t\t\t\t\t\t).pipe(Effect.andThen(Effect.sleep(\"1 second\"))),\n\t\t\t\t\t\t).pipe(Stream.drain, Stream.concat(recover)),\n\t\t\t),\n\t\t),\n\t)\n\treturn { scope, watch, changes: recover, imported }\n})\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@graftland/hmr",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"engines": {
|
|
6
6
|
"node": ">=22.19.0"
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"vitest": "5.1.0"
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"@graftland/graft": "0.
|
|
36
|
+
"@graftland/graft": "0.4.0"
|
|
37
37
|
},
|
|
38
38
|
"scripts": {
|
|
39
39
|
"build": "tsc -b && tsdown",
|
package/src/index.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
// @effect-diagnostics-next-line nodeBuiltinImport:off -- native import resolution must work without requiring a platform layer
|
|
5
5
|
import { realpath } from "node:fs/promises"
|
|
6
6
|
import { fileURLToPath, pathToFileURL } from "node:url"
|
|
7
|
-
|
|
7
|
+
|
|
8
8
|
import {
|
|
9
9
|
Array,
|
|
10
10
|
Cause,
|
|
@@ -19,20 +19,27 @@ import {
|
|
|
19
19
|
Option,
|
|
20
20
|
Ref,
|
|
21
21
|
Result,
|
|
22
|
-
String,
|
|
23
22
|
Schema,
|
|
23
|
+
Scope,
|
|
24
24
|
Semaphore,
|
|
25
25
|
Stream,
|
|
26
|
-
|
|
26
|
+
String,
|
|
27
|
+
type Duration,
|
|
28
|
+
type PlatformError,
|
|
27
29
|
} from "effect"
|
|
28
|
-
|
|
30
|
+
|
|
31
|
+
import { Graft, Plugin } from "@graftland/graft"
|
|
32
|
+
|
|
29
33
|
import { changes } from "./internal/changes"
|
|
34
|
+
import { digest } from "./internal/digest"
|
|
30
35
|
import {
|
|
31
36
|
isMissingEntry,
|
|
32
37
|
modules,
|
|
33
38
|
RestartRequired,
|
|
34
39
|
type Attempt,
|
|
40
|
+
type FileVersion,
|
|
35
41
|
} from "./internal/modules"
|
|
42
|
+
import * as SourceObservation from "./internal/sourceObservation"
|
|
36
43
|
|
|
37
44
|
export class HmrError extends Schema.TaggedError<
|
|
38
45
|
HmrError,
|
|
@@ -79,11 +86,37 @@ export interface ImportOptions {
|
|
|
79
86
|
readonly observationScope: Scope.Scope
|
|
80
87
|
}
|
|
81
88
|
|
|
89
|
+
/** An entry-owned observation collection; successful imports replace old dependencies, failures retain them. */
|
|
90
|
+
export interface Observation {
|
|
91
|
+
readonly scope: Scope.Scope
|
|
92
|
+
/** Files registered by one activation accumulate; the next activation's files replace them. */
|
|
93
|
+
readonly watch: (
|
|
94
|
+
files: ReadonlyArray<string>,
|
|
95
|
+
activation: Scope.Scope,
|
|
96
|
+
) => Effect.Effect<void, PlatformError.PlatformError>
|
|
97
|
+
readonly changes: Stream.Stream<void>
|
|
98
|
+
}
|
|
99
|
+
|
|
82
100
|
export interface Hmr {
|
|
101
|
+
/** Makes a collection independent of individual activation and retry scopes. */
|
|
102
|
+
readonly observation: Effect.Effect<
|
|
103
|
+
Observation,
|
|
104
|
+
never,
|
|
105
|
+
Scope.Scope | FileSystem.FileSystem
|
|
106
|
+
>
|
|
83
107
|
/** Keeps imported entries registered until this HMR session closes. */
|
|
84
108
|
readonly importer: (specifier: string) => Promise<unknown>
|
|
85
109
|
/** Uses the application context and Node cache, without watching or replacing the module. */
|
|
86
110
|
readonly importModule: (specifier: string) => Effect.Effect<unknown, HmrError>
|
|
111
|
+
/** Imports a fresh non-plugin graph in the caller's scope; failed observations survive in observationScope when supplied. */
|
|
112
|
+
readonly importModuleScoped: (
|
|
113
|
+
specifier: string,
|
|
114
|
+
options?: ImportOptions,
|
|
115
|
+
) => Effect.Effect<unknown, HmrError, Scope.Scope>
|
|
116
|
+
/** Observes file URLs and dependencies of leased modules without importing the other files. */
|
|
117
|
+
readonly observe: (
|
|
118
|
+
files: ReadonlyArray<string>,
|
|
119
|
+
) => Stream.Stream<void, PlatformError.PlatformError, FileSystem.FileSystem>
|
|
87
120
|
/** Registers an observation lease in observationScope, or the caller's scope when omitted. */
|
|
88
121
|
readonly importerScoped: (
|
|
89
122
|
specifier: string,
|
|
@@ -126,6 +159,21 @@ export const make: (
|
|
|
126
159
|
}
|
|
127
160
|
>(),
|
|
128
161
|
)
|
|
162
|
+
const sourceObservers = yield* Ref.make<
|
|
163
|
+
ReadonlyArray<Effect.Success<ReturnType<typeof SourceObservation.make>>>
|
|
164
|
+
>([])
|
|
165
|
+
const observation = Effect.gen(function* () {
|
|
166
|
+
const source = yield* SourceObservation.make()
|
|
167
|
+
yield* Effect.acquireRelease(
|
|
168
|
+
Ref.update(sourceObservers, Array.append(source)),
|
|
169
|
+
() =>
|
|
170
|
+
Ref.update(
|
|
171
|
+
sourceObservers,
|
|
172
|
+
Array.filter((current) => current !== source),
|
|
173
|
+
),
|
|
174
|
+
)
|
|
175
|
+
return source
|
|
176
|
+
})
|
|
129
177
|
const closed = yield* Ref.make(false)
|
|
130
178
|
const session = yield* Effect.scope
|
|
131
179
|
// Transfer the complete Exit before restoring interruption. Effect may replace
|
|
@@ -435,6 +483,125 @@ export const make: (
|
|
|
435
483
|
),
|
|
436
484
|
)
|
|
437
485
|
|
|
486
|
+
const importModuleScoped: Hmr["importModuleScoped"] = (
|
|
487
|
+
specifier,
|
|
488
|
+
options,
|
|
489
|
+
) =>
|
|
490
|
+
Effect.uninterruptibleMask((restore) =>
|
|
491
|
+
Effect.gen(function* () {
|
|
492
|
+
const caller = yield* Effect.scope
|
|
493
|
+
const { token, exit, managed } = yield* serial(
|
|
494
|
+
Effect.gen(function* () {
|
|
495
|
+
yield* checkOpen
|
|
496
|
+
const generation = hooks.prepare()
|
|
497
|
+
hooks.start(generation)
|
|
498
|
+
const token: symbol = Symbol()
|
|
499
|
+
const exit = yield* Effect.exit(
|
|
500
|
+
Effect.tryPromise({
|
|
501
|
+
try: () =>
|
|
502
|
+
import(/* @vite-ignore */ hooks.request(specifier)),
|
|
503
|
+
catch: (cause) =>
|
|
504
|
+
HmrError.make({ stage: "import", specifier, cause }),
|
|
505
|
+
}),
|
|
506
|
+
)
|
|
507
|
+
const root = Option.orElse(hooks.resolved(), () =>
|
|
508
|
+
String.startsWith("file:")(specifier)
|
|
509
|
+
? Option.some(specifier)
|
|
510
|
+
: Option.none(),
|
|
511
|
+
)
|
|
512
|
+
const attempt = Option.map(root, (url) => ({
|
|
513
|
+
url,
|
|
514
|
+
generation,
|
|
515
|
+
...Option.match(hooks.fileRequest(specifier), {
|
|
516
|
+
onNone: () => ({}),
|
|
517
|
+
onSome: (request) => ({ request }),
|
|
518
|
+
}),
|
|
519
|
+
}))
|
|
520
|
+
const observers = yield* Ref.get(sourceObservers)
|
|
521
|
+
const observer =
|
|
522
|
+
options === undefined
|
|
523
|
+
? Option.none()
|
|
524
|
+
: Array.findFirst(
|
|
525
|
+
observers,
|
|
526
|
+
(source) => source.scope === options.observationScope,
|
|
527
|
+
)
|
|
528
|
+
if (Option.isSome(observer)) {
|
|
529
|
+
yield* observer.value.imported(
|
|
530
|
+
Option.match(attempt, {
|
|
531
|
+
onNone: () => specifier,
|
|
532
|
+
onSome: (value) => value.request ?? value.url,
|
|
533
|
+
}),
|
|
534
|
+
hooks.files(Option.toArray(attempt)),
|
|
535
|
+
Exit.isSuccess(exit),
|
|
536
|
+
)
|
|
537
|
+
} else
|
|
538
|
+
yield* Ref.update(
|
|
539
|
+
owners,
|
|
540
|
+
HashMap.set(token, {
|
|
541
|
+
active: Exit.isSuccess(exit) ? attempt : Option.none(),
|
|
542
|
+
pending: Exit.isFailure(exit) ? attempt : Option.none(),
|
|
543
|
+
}),
|
|
544
|
+
)
|
|
545
|
+
return { token, exit, managed: Option.isSome(observer) }
|
|
546
|
+
}).pipe(Effect.ensuring(Effect.sync(hooks.discard))),
|
|
547
|
+
)
|
|
548
|
+
// Collections already copied the observed digests; they do not retain per-attempt leases.
|
|
549
|
+
// Without a collection, failed imports keep the caller's explicit observation lease.
|
|
550
|
+
yield* Scope.addFinalizer(
|
|
551
|
+
!managed && Exit.isFailure(exit)
|
|
552
|
+
? (options?.observationScope ?? caller)
|
|
553
|
+
: caller,
|
|
554
|
+
serial(
|
|
555
|
+
Ref.update(owners, HashMap.remove(token)).pipe(
|
|
556
|
+
Effect.ensuring(collect),
|
|
557
|
+
),
|
|
558
|
+
),
|
|
559
|
+
)
|
|
560
|
+
return yield* restore(exit)
|
|
561
|
+
}),
|
|
562
|
+
).pipe(preserveExit)
|
|
563
|
+
|
|
564
|
+
const observe: Hmr["observe"] = (files) =>
|
|
565
|
+
Stream.unwrap(
|
|
566
|
+
Effect.gen(function* () {
|
|
567
|
+
const fs = yield* FileSystem.FileSystem
|
|
568
|
+
const observed = yield* Effect.forEach(files, (url) =>
|
|
569
|
+
fs
|
|
570
|
+
.readFile(fileURLToPath(url))
|
|
571
|
+
.pipe(
|
|
572
|
+
Effect.map((bytes): readonly [string, FileVersion] => [
|
|
573
|
+
url,
|
|
574
|
+
{ generation: -1, content: digest(bytes) },
|
|
575
|
+
]),
|
|
576
|
+
),
|
|
577
|
+
)
|
|
578
|
+
const baseline = HashMap.fromIterable(observed)
|
|
579
|
+
const snapshot = yield* observations.pipe(
|
|
580
|
+
Effect.map((attempts) =>
|
|
581
|
+
HashMap.union(
|
|
582
|
+
baseline,
|
|
583
|
+
hooks.files(
|
|
584
|
+
Array.filter(
|
|
585
|
+
attempts,
|
|
586
|
+
(attempt) =>
|
|
587
|
+
Array.contains(files, attempt.url) ||
|
|
588
|
+
(attempt.request !== undefined &&
|
|
589
|
+
Array.contains(files, attempt.request)),
|
|
590
|
+
),
|
|
591
|
+
),
|
|
592
|
+
),
|
|
593
|
+
),
|
|
594
|
+
semaphore.withPermits(1),
|
|
595
|
+
)
|
|
596
|
+
return changes(
|
|
597
|
+
(use) => use(snapshot),
|
|
598
|
+
Array.map(Array.fromIterable(HashMap.keys(snapshot)), (url) =>
|
|
599
|
+
fileURLToPath(url),
|
|
600
|
+
),
|
|
601
|
+
).pipe(Stream.as(undefined))
|
|
602
|
+
}),
|
|
603
|
+
)
|
|
604
|
+
|
|
438
605
|
const importerScoped: Hmr["importerScoped"] = (specifier, options) =>
|
|
439
606
|
options === undefined
|
|
440
607
|
? importWithLease(specifier)
|
|
@@ -698,6 +865,9 @@ export const make: (
|
|
|
698
865
|
importer,
|
|
699
866
|
importerScoped,
|
|
700
867
|
importModule,
|
|
868
|
+
observation,
|
|
869
|
+
importModuleScoped,
|
|
870
|
+
observe,
|
|
701
871
|
reload: reloadChanged(undefined),
|
|
702
872
|
watch: (paths, watchOptions) =>
|
|
703
873
|
paths.length === 0
|
package/src/internal/changes.ts
CHANGED
|
@@ -1,27 +1,29 @@
|
|
|
1
1
|
// @effect-diagnostics-next-line nodeBuiltinImport:off -- watcher paths use host-platform syntax without adding a Path service requirement
|
|
2
2
|
import { dirname, resolve } from "node:path"
|
|
3
|
-
import type { FileVersion } from "./modules"
|
|
4
|
-
import type { WatchOptions } from "../index"
|
|
5
|
-
import { digest } from "./digest"
|
|
6
3
|
import { fileURLToPath, pathToFileURL } from "node:url"
|
|
4
|
+
|
|
7
5
|
import {
|
|
8
6
|
Array,
|
|
9
7
|
Cause,
|
|
10
|
-
|
|
8
|
+
Clock,
|
|
11
9
|
Effect,
|
|
10
|
+
Equal,
|
|
11
|
+
Exit,
|
|
12
12
|
Fiber,
|
|
13
13
|
FileSystem,
|
|
14
14
|
HashMap,
|
|
15
15
|
HashSet,
|
|
16
|
-
Equal,
|
|
17
|
-
Clock,
|
|
18
|
-
Ref,
|
|
19
|
-
Queue,
|
|
20
16
|
Option,
|
|
17
|
+
Queue,
|
|
18
|
+
Ref,
|
|
21
19
|
Stream,
|
|
22
20
|
String,
|
|
23
21
|
} from "effect"
|
|
24
22
|
|
|
23
|
+
import type { WatchOptions } from "../index"
|
|
24
|
+
import { digest } from "./digest"
|
|
25
|
+
import type { FileVersion } from "./modules"
|
|
26
|
+
|
|
25
27
|
export type WithFiles = <A, E, R>(
|
|
26
28
|
use: (files: HashMap.HashMap<string, FileVersion>) => Effect.Effect<A, E, R>,
|
|
27
29
|
) => Effect.Effect<A, E, R>
|
package/src/internal/modules.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// Node's synchronous module hooks have no Effect equivalent.
|
|
2
|
-
import { digest } from "./digest"
|
|
3
2
|
import { registerHooks } from "node:module"
|
|
4
3
|
import { fileURLToPath, pathToFileURL } from "node:url"
|
|
4
|
+
|
|
5
5
|
import {
|
|
6
6
|
Array,
|
|
7
7
|
Chunk,
|
|
@@ -13,6 +13,8 @@ import {
|
|
|
13
13
|
String,
|
|
14
14
|
} from "effect"
|
|
15
15
|
|
|
16
|
+
import { digest } from "./digest"
|
|
17
|
+
|
|
16
18
|
export class RestartRequired extends Schema.TaggedError<
|
|
17
19
|
RestartRequired,
|
|
18
20
|
{ readonly brand: unique symbol }
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import { fileURLToPath } from "node:url"
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
Array,
|
|
5
|
+
Cause,
|
|
6
|
+
Effect,
|
|
7
|
+
FileSystem,
|
|
8
|
+
HashMap,
|
|
9
|
+
Option,
|
|
10
|
+
Scope,
|
|
11
|
+
Stream,
|
|
12
|
+
SubscriptionRef,
|
|
13
|
+
} from "effect"
|
|
14
|
+
|
|
15
|
+
import { changes } from "./changes"
|
|
16
|
+
import { digest } from "./digest"
|
|
17
|
+
import type { FileVersion } from "./modules"
|
|
18
|
+
|
|
19
|
+
type Files = HashMap.HashMap<string, FileVersion>
|
|
20
|
+
interface Sources {
|
|
21
|
+
readonly imports: HashMap.HashMap<string, Files>
|
|
22
|
+
readonly explicit: Files
|
|
23
|
+
/** Explicit files belong to the latest activation that registered any. */
|
|
24
|
+
readonly activation: Option.Option<Scope.Scope>
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/** An entry keeps its last known snapshots across execution and watcher failures. */
|
|
28
|
+
export const make = Effect.fnUntraced(function* () {
|
|
29
|
+
const scope = yield* Effect.scope
|
|
30
|
+
const fs = yield* FileSystem.FileSystem
|
|
31
|
+
const sources = yield* SubscriptionRef.make({
|
|
32
|
+
imports: HashMap.empty<string, Files>(),
|
|
33
|
+
explicit: HashMap.empty<string, FileVersion>(),
|
|
34
|
+
activation: Option.none<Scope.Scope>(),
|
|
35
|
+
})
|
|
36
|
+
const snapshot = (value: Sources): Files =>
|
|
37
|
+
Array.reduce(
|
|
38
|
+
HashMap.toValues(value.imports),
|
|
39
|
+
value.explicit,
|
|
40
|
+
(all, files) => HashMap.union(all, files),
|
|
41
|
+
)
|
|
42
|
+
const read = (url: string) =>
|
|
43
|
+
fs.readFile(fileURLToPath(url)).pipe(
|
|
44
|
+
Effect.map((bytes): readonly [string, FileVersion] => [
|
|
45
|
+
url,
|
|
46
|
+
{ generation: -1, content: digest(bytes) },
|
|
47
|
+
]),
|
|
48
|
+
Effect.catchIf(
|
|
49
|
+
(error) => error.reason._tag === "NotFound",
|
|
50
|
+
() =>
|
|
51
|
+
Effect.succeed<readonly [string, FileVersion]>([
|
|
52
|
+
url,
|
|
53
|
+
{ generation: -1, content: undefined },
|
|
54
|
+
]),
|
|
55
|
+
),
|
|
56
|
+
)
|
|
57
|
+
// An activation may start several remote plugins, so its calls accumulate; a newer activation
|
|
58
|
+
// replaces them, and files it no longer uses stop being observed.
|
|
59
|
+
const watch = (files: ReadonlyArray<string>, activation: Scope.Scope) =>
|
|
60
|
+
Effect.forEach(files, read).pipe(
|
|
61
|
+
Effect.flatMap((entries) =>
|
|
62
|
+
SubscriptionRef.update(sources, (current) => {
|
|
63
|
+
const explicit = HashMap.union(
|
|
64
|
+
Option.exists(current.activation, (owner) => owner === activation)
|
|
65
|
+
? current.explicit
|
|
66
|
+
: HashMap.empty<string, FileVersion>(),
|
|
67
|
+
HashMap.fromIterable(entries),
|
|
68
|
+
)
|
|
69
|
+
return {
|
|
70
|
+
...current,
|
|
71
|
+
explicit,
|
|
72
|
+
activation: Option.some(activation),
|
|
73
|
+
imports: HashMap.filter(current.imports, (_, root) =>
|
|
74
|
+
HashMap.has(explicit, root),
|
|
75
|
+
),
|
|
76
|
+
}
|
|
77
|
+
}),
|
|
78
|
+
),
|
|
79
|
+
Effect.onError(() =>
|
|
80
|
+
SubscriptionRef.update(sources, (current) => ({
|
|
81
|
+
...current,
|
|
82
|
+
explicit: HashMap.union(
|
|
83
|
+
HashMap.fromIterable(
|
|
84
|
+
Array.map(files, (url): readonly [string, FileVersion] => [
|
|
85
|
+
url,
|
|
86
|
+
{ generation: -1, content: undefined },
|
|
87
|
+
]),
|
|
88
|
+
),
|
|
89
|
+
current.explicit,
|
|
90
|
+
),
|
|
91
|
+
})),
|
|
92
|
+
),
|
|
93
|
+
)
|
|
94
|
+
const imported = (root: string, files: Files, success: boolean) =>
|
|
95
|
+
SubscriptionRef.update(sources, (current) => ({
|
|
96
|
+
...current,
|
|
97
|
+
imports: HashMap.set(
|
|
98
|
+
current.imports,
|
|
99
|
+
root,
|
|
100
|
+
success
|
|
101
|
+
? files
|
|
102
|
+
: HashMap.union(
|
|
103
|
+
Option.getOrElse(
|
|
104
|
+
HashMap.get(current.imports, root),
|
|
105
|
+
HashMap.empty<string, FileVersion>,
|
|
106
|
+
),
|
|
107
|
+
files,
|
|
108
|
+
),
|
|
109
|
+
),
|
|
110
|
+
}))
|
|
111
|
+
const observe = SubscriptionRef.changes(sources).pipe(
|
|
112
|
+
Stream.switchMap((current) => {
|
|
113
|
+
const files = snapshot(current)
|
|
114
|
+
if (HashMap.size(files) === 0) return Stream.never
|
|
115
|
+
// Watch parent directories so deleting an entry does not prevent its recovery.
|
|
116
|
+
return changes(
|
|
117
|
+
(use) => use(files),
|
|
118
|
+
Array.dedupe(
|
|
119
|
+
Array.map(Array.fromIterable(HashMap.keys(files)), (url) =>
|
|
120
|
+
fileURLToPath(new URL(".", url)),
|
|
121
|
+
),
|
|
122
|
+
),
|
|
123
|
+
{ recursive: true },
|
|
124
|
+
).pipe(Stream.as(undefined))
|
|
125
|
+
}),
|
|
126
|
+
Stream.provideService(FileSystem.FileSystem, fs),
|
|
127
|
+
)
|
|
128
|
+
const recover: Stream.Stream<void> = Stream.suspend(() =>
|
|
129
|
+
observe.pipe(
|
|
130
|
+
Stream.catchCause((cause) =>
|
|
131
|
+
Cause.hasInterruptsOnly(cause)
|
|
132
|
+
? Stream.failCause(
|
|
133
|
+
Cause.fromReasons(
|
|
134
|
+
Array.filter(cause.reasons, Cause.isInterruptReason),
|
|
135
|
+
),
|
|
136
|
+
)
|
|
137
|
+
: Stream.fromEffect(
|
|
138
|
+
Effect.logError(
|
|
139
|
+
"Source observation failed; retrying",
|
|
140
|
+
cause,
|
|
141
|
+
).pipe(Effect.andThen(Effect.sleep("1 second"))),
|
|
142
|
+
).pipe(Stream.drain, Stream.concat(recover)),
|
|
143
|
+
),
|
|
144
|
+
),
|
|
145
|
+
)
|
|
146
|
+
return { scope, watch, changes: recover, imported }
|
|
147
|
+
})
|