@dirwell/core 0.0.1-alpha → 0.0.1-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/index.mjs +8 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @dirwell/core
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Framework-neutral filesystem, listing and static-publication SDK. Install with `npm install @dirwell/core@alpha` and a theme of your choice.
|
|
4
4
|
|
|
5
5
|
Core owns filesystem selection, safe navigation, public listing projection and static publication. It requires an explicit theme and does not load a default theme, image renderer, frontend framework, config loader or watcher. The only runtime npm dependency is picomatch.
|
|
6
6
|
|
package/dist/index.mjs
CHANGED
|
@@ -761,7 +761,14 @@ async function createDirectoryService(options) {
|
|
|
761
761
|
const physical = await realpath(entry.absolutePath);
|
|
762
762
|
if (!isInsideRoot(root, physical)) throw new DirectoryAccessError("Unavailable directory");
|
|
763
763
|
const names = (await readdir(physical)).filter((name) => logicalPath !== "" || name !== "__dirwell");
|
|
764
|
-
const entries = await Promise.all(names.filter((name) => selection === null || selection.has(path.posix.join(logicalPath, name))).map((name) =>
|
|
764
|
+
const entries = (await Promise.all(names.filter((name) => selection === null || selection.has(path.posix.join(logicalPath, name))).map(async (name) => {
|
|
765
|
+
try {
|
|
766
|
+
return await describe(path.posix.join(logicalPath, name), selection);
|
|
767
|
+
} catch (error) {
|
|
768
|
+
if (error instanceof Error && "code" in error && error.code === "ENOENT") return null;
|
|
769
|
+
throw error;
|
|
770
|
+
}
|
|
771
|
+
}))).filter((entry) => entry !== null);
|
|
765
772
|
entries.sort((left, right) => compareEntries(left, right, options.sort) || (left.relativePath < right.relativePath ? -1 : left.relativePath > right.relativePath ? 1 : 0));
|
|
766
773
|
return {
|
|
767
774
|
root: await describe("", selection),
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":[],"sources":["../src/filesystem.ts","../src/listing.ts","../src/filters.ts","../src/generator.ts","../src/html.ts","../src/file-identity.ts","../src/service.ts"],"sourcesContent":["import { lstat, readlink, realpath, stat } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport type { Stats } from \"node:fs\";\nimport type { EntryKind, FileMetadata, FileSystemEntry, SymlinkMetadata } from \"./model.ts\";\nfunction entryKind(stats: Stats): EntryKind {\n if (stats.isDirectory()) return \"directory\";\n if (stats.isFile()) return \"file\";\n if (stats.isSymbolicLink()) return \"symlink\";\n return \"other\";\n}\n\nfunction metadata(stats: Stats): FileMetadata {\n return {\n device: stats.dev,\n groupId: stats.gid,\n hardLinkCount: stats.nlink,\n inode: stats.ino,\n mode: stats.mode,\n ownerId: stats.uid,\n size: stats.size,\n times: {\n accessedAt: stats.atime.toISOString(),\n changedAt: stats.ctime.toISOString(),\n createdAt: stats.birthtime.toISOString(),\n modifiedAt: stats.mtime.toISOString(),\n },\n };\n}\n\nexport function isInsideRoot(rootPath: string, candidatePath: string): boolean {\n const relative = path.relative(rootPath, candidatePath);\n return (\n relative === \"\" ||\n (relative !== \"..\" && !relative.startsWith(`..${path.sep}`) && !path.isAbsolute(relative))\n );\n}\n\nexport async function describeEntry({\n absolutePath,\n relativePath,\n rootRealPath,\n ancestors,\n followSymlinks,\n selectedPaths,\n}: {\n absolutePath: string;\n relativePath: string;\n rootRealPath: string;\n ancestors: ReadonlySet<string>;\n followSymlinks: boolean;\n selectedPaths: ReadonlySet<string> | null;\n}): Promise<FileSystemEntry> {\n const linkStats = await lstat(absolutePath);\n const kind = entryKind(linkStats);\n let symlink: SymlinkMetadata | null = null;\n\n if (kind === \"symlink\") {\n const target = await readlink(absolutePath);\n let resolvedPath: string | null = null;\n let targetKind: Exclude<EntryKind, \"symlink\"> | null = null;\n let targetSize: number | null = null;\n try {\n resolvedPath = await realpath(absolutePath);\n const targetStats = await stat(absolutePath);\n targetKind = entryKind(targetStats) as Exclude<EntryKind, \"symlink\">;\n targetSize = targetStats.size;\n } catch {\n // Broken and inaccessible links are represented as data.\n }\n const isOutsideRoot = resolvedPath === null || !isInsideRoot(rootRealPath, resolvedPath);\n const isCycle = resolvedPath !== null && ancestors.has(resolvedPath);\n const targetRelativePath =\n resolvedPath !== null && !isOutsideRoot\n ? path.relative(rootRealPath, resolvedPath).split(path.sep).join(\"/\")\n : null;\n const isTargetExcluded =\n targetRelativePath !== null &&\n selectedPaths !== null &&\n !selectedPaths.has(targetRelativePath);\n symlink = {\n target,\n resolvedPath,\n targetRelativePath,\n targetKind,\n targetSize:\n isOutsideRoot || isTargetExcluded || targetKind === \"directory\" ? null : targetSize,\n isBroken: resolvedPath === null,\n isCycle,\n isOutsideRoot,\n isTargetExcluded,\n wasFollowed:\n followSymlinks &&\n targetKind === \"directory\" &&\n !isCycle &&\n !isOutsideRoot &&\n !isTargetExcluded,\n };\n }\n\n return {\n name: path.basename(absolutePath),\n absolutePath,\n relativePath,\n kind,\n metadata: metadata(linkStats),\n symlink,\n };\n}\n","import type { JsonObject } from \"./json.ts\";\nimport { createHash } from \"node:crypto\";\nimport type { EntryKind, FileSystemEntry, ThemeContext, SortOptions } from \"./model.ts\";\n\n/** Public transport fields only. Internal filesystem metadata must never be spread here. */\nexport interface ListingEntry {\n readonly presentation?: JsonObject;\n readonly id: string;\n readonly name: string;\n readonly kind: EntryKind;\n readonly href: string | null;\n readonly exitsExplorer: boolean;\n readonly size: number;\n readonly modifiedAt: string;\n readonly link: null | {\n readonly target: string;\n readonly targetKind: Exclude<EntryKind, \"symlink\"> | null;\n readonly targetSize: number | null;\n readonly unavailable: boolean;\n readonly cycle: boolean;\n };\n}\nexport interface ListingPlan {\n readonly html:\n | { readonly strategy: \"all\" }\n | { readonly strategy: \"paged\"; readonly pageSize: number };\n readonly data:\n | { readonly strategy: \"all\" }\n | { readonly strategy: \"blocks\"; readonly blockSize: number };\n}\nexport interface ListingPolicyContext {\n readonly operation?: \"build\" | \"server\";\n readonly directoryPath: string;\n readonly visibleCount: number;\n readonly dataBytes: number;\n readonly mode: \"ssg\" | \"mpa\";\n readonly supportsPagination: boolean;\n}\nexport type ListingPolicy = ListingPlan | ((context: ListingPolicyContext) => ListingPlan);\nexport interface ListingPage {\n readonly number: number;\n readonly count: number;\n readonly offset: number;\n readonly total: number;\n readonly href: string;\n readonly previousHref: string | null;\n readonly nextHref: string | null;\n}\nexport interface ListingContext {\n readonly revision: string;\n readonly manifestHref: string;\n readonly page: ListingPage;\n}\nexport interface ListingBlock {\n readonly version: 1;\n readonly revision: string;\n readonly offset: number;\n readonly total: number;\n readonly entries: readonly ListingEntry[];\n}\nexport interface ListingManifest {\n readonly version: 1;\n readonly revision: string;\n readonly directory: string;\n /** Resolve entry hrefs against this URL, resolved relative to the manifest URL. */\n readonly hrefBase: string;\n readonly total: number;\n readonly sort: Required<SortOptions>;\n /** Block hrefs are relative to the manifest URL. */\n readonly blocks: readonly {\n readonly href: string;\n readonly offset: number;\n readonly count: number;\n }[];\n}\n\nexport function projectListingEntry(\n entry: FileSystemEntry,\n context: Pick<ThemeContext, \"hrefFor\" | \"exitsExplorerFor\">,\n): ListingEntry {\n const link = entry.symlink;\n return {\n id: entry.relativePath,\n name: entry.name,\n kind: entry.kind,\n href: context.hrefFor(entry),\n exitsExplorer: context.exitsExplorerFor(entry),\n size: entry.metadata.size,\n modifiedAt: entry.metadata.times.modifiedAt,\n link:\n link === null\n ? null\n : {\n target: link.target,\n targetKind: link.targetKind,\n targetSize: link.targetSize ?? null,\n unavailable: link.isBroken || link.isOutsideRoot || Boolean(link.isTargetExcluded),\n cycle: link.isCycle,\n },\n };\n}\nfunction record(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\nfunction positiveInteger(value: unknown, key: string): void {\n if (typeof value !== \"number\" || !Number.isSafeInteger(value) || value < 1)\n throw new TypeError(`${key} must be a positive safe integer`);\n}\nexport function validateListingPlan(value: unknown): asserts value is ListingPlan {\n if (!record(value) || !record(value.html) || !record(value.data))\n throw new TypeError(\"listing must contain html and data plans\");\n if (value.html.strategy === \"paged\")\n positiveInteger(value.html.pageSize, \"listing.html.pageSize\");\n else if (value.html.strategy !== \"all\")\n throw new TypeError('listing.html.strategy must be \"all\" or \"paged\"');\n if (value.data.strategy === \"blocks\")\n positiveInteger(value.data.blockSize, \"listing.data.blockSize\");\n else if (value.data.strategy !== \"all\")\n throw new TypeError('listing.data.strategy must be \"all\" or \"blocks\"');\n}\nexport function listingRevision(\n entries: readonly ListingEntry[],\n sort: Required<SortOptions>,\n hrefBase: string,\n blockSize: number,\n): string {\n return createHash(\"sha256\")\n .update(JSON.stringify({ version: 1, entries, sort, hrefBase, blockSize }))\n .digest(\"hex\");\n}\n","import { readdir, readlink } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport picomatch from \"picomatch\";\n\nexport function normalizePathPatterns(value: unknown, name: string): readonly string[] {\n if (value === undefined) return [];\n const patterns = typeof value === \"string\" ? [value] : value;\n if (\n !Array.isArray(patterns) ||\n patterns.some(\n (pattern) =>\n typeof pattern !== \"string\" ||\n pattern.length === 0 ||\n pattern.startsWith(\"/\") ||\n /^[A-Za-z]:/.test(pattern) ||\n pattern.startsWith(\"!\") ||\n pattern.includes(\"\\\\\") ||\n pattern.split(\"/\").some((segment) => segment === \".\" || segment === \"..\"),\n )\n ) {\n throw new TypeError(`${name} must contain root-relative glob patterns using forward slashes`);\n }\n return patterns as readonly string[];\n}\n\nfunction isWithin(parent: string, candidate: string): boolean {\n const relative = path.relative(parent, candidate);\n return (\n relative === \"\" ||\n (relative !== \"..\" && !relative.startsWith(`..${path.sep}`) && !path.isAbsolute(relative))\n );\n}\n\nexport interface SourceSelection {\n readonly selected: ReadonlySet<string>;\n readonly symlinks: ReadonlySet<string>;\n readonly mirroredSymlinks: ReadonlySet<string>;\n}\n\n/** Select physical source paths; parent directories remain when a descendant matches. */\nexport async function selectSourcePaths(\n sourceDir: string,\n outputDir: string,\n include: unknown,\n exclude: unknown,\n ignoredPaths: readonly string[] = [],\n): Promise<SourceSelection> {\n const ignored = ignoredPaths.map((value) => path.resolve(value));\n const included = normalizePathPatterns(include, \"include\").map((pattern) =>\n picomatch(pattern, { dot: true, nonegate: true }),\n );\n const excluded = normalizePathPatterns(exclude, \"exclude\").map((pattern) =>\n picomatch(pattern, { dot: true, nonegate: true }),\n );\n const selected = new Set<string>([\"\"]);\n const symlinks = new Map<string, string>();\n\n async function visit(\n directory: string,\n relativeDir: string,\n inheritedInclude: boolean,\n ): Promise<boolean> {\n let hasSelected = false;\n for (const entry of await readdir(directory, { withFileTypes: true })) {\n const absolutePath = path.join(directory, entry.name);\n if (\n isWithin(outputDir, absolutePath) ||\n ignored.some((value) => isWithin(value, absolutePath))\n )\n continue;\n const relativePath = path.posix.join(relativeDir, entry.name);\n const directoryLike = entry.isDirectory();\n const matches = (matcher: (value: string) => boolean) =>\n matcher(relativePath) || (directoryLike && matcher(`${relativePath}/`));\n if (excluded.some(matches)) continue;\n const includedHere = inheritedInclude || included.some(matches);\n if (directoryLike) {\n const hasSelectedChild = await visit(absolutePath, relativePath, includedHere);\n if (included.length === 0 || includedHere || hasSelectedChild) {\n selected.add(relativePath);\n hasSelected = true;\n }\n } else if (included.length === 0 || includedHere) {\n selected.add(relativePath);\n hasSelected = true;\n if (entry.isSymbolicLink()) symlinks.set(relativePath, await readlink(absolutePath));\n }\n }\n return hasSelected;\n }\n\n await visit(sourceDir, \"\", false);\n // Absolute, escaping, and filtered targets cannot remain valid inside the copied tree.\n const mirroredSymlinks = new Set<string>();\n for (const [relativePath, target] of symlinks) {\n if (path.isAbsolute(target)) continue;\n const targetPath = path.resolve(sourceDir, path.dirname(relativePath), target);\n if (!isWithin(sourceDir, targetPath)) continue;\n const targetRelativePath = path.relative(sourceDir, targetPath).split(path.sep).join(\"/\");\n if (selected.has(targetRelativePath)) mirroredSymlinks.add(relativePath);\n }\n return { selected, symlinks: new Set(symlinks.keys()), mirroredSymlinks };\n}\n","import { copyJsonObject } from \"./json.ts\";\nimport { describeEntry, isInsideRoot } from \"./filesystem.ts\";\nimport {\n listingRevision,\n projectListingEntry,\n validateListingPlan,\n type ListingManifest,\n} from \"./listing.ts\";\nimport {\n cp,\n lstat,\n mkdtemp,\n mkdir,\n readFile,\n readdir,\n realpath,\n rename,\n rm,\n writeFile,\n} from \"node:fs/promises\";\nimport { createHash } from \"node:crypto\";\nimport path from \"node:path\";\nimport type {\n DirectoryData,\n EntryKind,\n ExplorerTheme,\n FileSystemEntry,\n GenerateOptions,\n NameSortMode,\n OutputNameResolver,\n SortOptions,\n ThemeContext,\n} from \"./model.ts\";\nimport { selectSourcePaths } from \"./filters.ts\";\n\nconst indexPattern = /^index\\.html?$/i;\n\nconst defaultSort = {\n direction: \"asc\",\n directoriesFirst: true,\n field: \"name\",\n nameMode: \"natural\",\n} as const satisfies Required<SortOptions>;\n\nexport const defaultOutputName: OutputNameResolver = ({ entries }) =>\n entries.some((entry) => entry.kind === \"file\" && indexPattern.test(entry.name))\n ? entries.some((entry) => entry.name.toLowerCase() === \"_dirwell.html\")\n ? null\n : \"_dirwell.html\"\n : \"index.html\";\n\nfunction assertSafeOutputName(name: string): void {\n if (name.length === 0 || path.basename(name) !== name || name === \".\" || name === \"..\") {\n throw new Error(`Output name must be a single safe filename: ${name}`);\n }\n}\n\nfunction normalizeBase(value: string): string {\n if (value.includes(\"?\") || value.includes(\"#\")) {\n throw new TypeError(\"base must not contain a query string or fragment\");\n }\n if (/^https?:\\/\\//i.test(value)) {\n const url = new URL(value);\n url.pathname = `${url.pathname.replace(/\\/+$/, \"\")}/`;\n return url.href;\n }\n if (!value.startsWith(\"/\")) {\n throw new TypeError('base must start with \"/\" or be an absolute HTTP(S) URL');\n }\n return `${value.replace(/\\/+$/, \"\")}/`;\n}\n\nfunction encodeLogicalPath(value: string): string {\n return value\n .split(\"/\")\n .filter((segment) => segment.length > 0)\n .map((segment) => encodeURIComponent(segment))\n .join(\"/\");\n}\n\nfunction isDirectoryLike(entry: FileSystemEntry): boolean {\n return entry.kind === \"directory\" || entry.symlink?.targetKind === \"directory\";\n}\n\nfunction isUnavailableSymlink(entry: FileSystemEntry): boolean {\n return Boolean(\n entry.symlink?.isBroken || entry.symlink?.isOutsideRoot || entry.symlink?.isTargetExcluded,\n );\n}\n\nfunction compareUnicode(left: string, right: string): number {\n const leftPoints = [...left];\n const rightPoints = [...right];\n const length = Math.min(leftPoints.length, rightPoints.length);\n for (let index = 0; index < length; index += 1) {\n const difference =\n (leftPoints[index]?.codePointAt(0) ?? 0) - (rightPoints[index]?.codePointAt(0) ?? 0);\n if (difference !== 0) return difference;\n }\n return leftPoints.length - rightPoints.length;\n}\n\nfunction compareNames(left: string, right: string, mode: NameSortMode): number {\n if (mode === \"unicode\") return compareUnicode(left, right);\n return left.localeCompare(right, undefined, {\n numeric: mode === \"natural\",\n sensitivity: \"base\",\n });\n}\n\nexport function compareEntries(\n left: FileSystemEntry,\n right: FileSystemEntry,\n options: SortOptions = {},\n): number {\n const resolved = { ...defaultSort, ...options };\n if (resolved.directoriesFirst && isDirectoryLike(left) !== isDirectoryLike(right)) {\n return isDirectoryLike(left) ? -1 : 1;\n }\n let result: number;\n if (resolved.field === \"modified\") {\n result = left.metadata.times.modifiedAt.localeCompare(right.metadata.times.modifiedAt);\n } else if (resolved.field === \"size\") {\n result =\n (left.kind === \"directory\" ? 0 : left.metadata.size) -\n (right.kind === \"directory\" ? 0 : right.metadata.size);\n } else {\n result = compareNames(left.name, right.name, resolved.nameMode);\n }\n if (result === 0) result = compareNames(left.name, right.name, resolved.nameMode);\n return resolved.direction === \"asc\" ? result : -result;\n}\n\nfunction rawLinkFilename(entry: FileSystemEntry): string {\n return `${createHash(\"sha256\")\n .update(entry.relativePath)\n .update(\"\\0\")\n .update(entry.symlink?.target ?? \"\")\n .digest(\"hex\")\n .slice(0, 16)}.txt`;\n}\n\nexport async function generateExplorer(options: GenerateOptions): Promise<void> {\n return generateExplorerSkippingPaths(options, []);\n}\n\n/** Internal entry point for hosts that stage previews outside their published output. */\nexport async function generateExplorerSkippingPaths(\n options: GenerateOptions,\n ignoredPaths: readonly string[],\n): Promise<void> {\n const sourceDir = path.resolve(options.sourceDir);\n const outputDir = path.resolve(options.outputDir);\n const ignoredSourcePaths = ignoredPaths.map((value) => path.resolve(value));\n const rootRealPath = await realpath(sourceDir);\n const outputName = options.outputName ?? defaultOutputName;\n const resolveOutputName: OutputNameResolver =\n typeof outputName === \"string\" ? () => outputName : outputName;\n const theme: ExplorerTheme = options.theme;\n if (theme === undefined) throw new TypeError(\"Core requires an explicit theme\");\n const mode = options.mode ?? \"ssg\";\n const urlStrategy = options.urlStrategy ?? \"relative\";\n const base = normalizeBase(options.base ?? \"/\");\n const followSymlinks = options.symlinks?.follow ?? false;\n const boundary = options.symlinks?.boundary ?? \"root\";\n const onCycle = options.symlinks?.onCycle ?? \"skip\";\n const filtersActive =\n options.include !== undefined || options.exclude !== undefined || ignoredSourcePaths.length > 0;\n const plans: Array<{\n readonly directory: DirectoryData;\n readonly logicalDir: string;\n readonly outputName: string | null;\n }> = [];\n if (isInsideRoot(outputDir, sourceDir)) {\n throw new Error(\"outputDir must not contain the sourceDir\");\n }\n try {\n await lstat(path.join(sourceDir, \"__dirwell\"));\n throw new Error('Dirwell reserves the source-root path \"__dirwell\"');\n } catch (error) {\n if (error instanceof Error && \"code\" in error && error.code === \"ENOENT\") {\n // The reserved asset path is available.\n } else {\n throw error;\n }\n }\n const outputIsWithinSource = isInsideRoot(sourceDir, outputDir);\n const selection = await selectSourcePaths(\n sourceDir,\n outputDir,\n options.include,\n options.exclude,\n ignoredSourcePaths,\n );\n const stageParent = outputIsWithinSource ? path.dirname(sourceDir) : path.dirname(outputDir);\n await mkdir(stageParent, { recursive: true });\n const stagedOutputDir = await mkdtemp(\n path.join(stageParent, `.${path.basename(outputDir)}-dirwell-`),\n );\n const buildOutputDir = stagedOutputDir;\n\n try {\n if (options.mirror ?? true) {\n await rm(buildOutputDir, { recursive: true, force: true });\n await mkdir(buildOutputDir, { recursive: true });\n await cp(sourceDir, buildOutputDir, {\n recursive: true,\n dereference: false,\n preserveTimestamps: true,\n filter: (sourcePath) => {\n const relativePath = path.relative(sourceDir, sourcePath).split(path.sep).join(\"/\");\n return (\n selection.selected.has(relativePath) &&\n (!selection.symlinks.has(relativePath) || selection.mirroredSymlinks.has(relativePath))\n );\n },\n });\n }\n } catch (error) {\n await rm(stagedOutputDir, { recursive: true, force: true });\n throw error;\n }\n\n async function visit(\n logicalDir: string,\n physicalDir: string,\n ancestors: ReadonlySet<string>,\n ): Promise<void> {\n const physicalRealPath = await realpath(physicalDir);\n if (ancestors.has(physicalRealPath)) {\n if (onCycle === \"error\") throw new Error(`Symlink cycle at ${logicalDir}`);\n return;\n }\n\n const nextAncestors = new Set(ancestors).add(physicalRealPath);\n const names = (await readdir(physicalDir)).filter((name) => {\n if (outputIsWithinSource && isInsideRoot(outputDir, path.join(physicalDir, name)))\n return false;\n if (ignoredSourcePaths.some((value) => isInsideRoot(value, path.join(physicalDir, name))))\n return false;\n if (!filtersActive) return true;\n const relativePath = path.relative(rootRealPath, path.join(physicalRealPath, name));\n return selection.selected.has(relativePath.split(path.sep).join(\"/\"));\n });\n const entries = await Promise.all(\n names.map((name) =>\n describeEntry({\n absolutePath: path.join(physicalDir, name),\n relativePath: path.posix.join(logicalDir, name),\n rootRealPath,\n ancestors: nextAncestors,\n followSymlinks,\n selectedPaths: filtersActive ? selection.selected : null,\n }),\n ),\n );\n entries.sort(\n (left, right) =>\n compareEntries(left, right, options.sort) ||\n (options.listing === undefined ? 0 : compareUnicode(left.relativePath, right.relativePath)),\n );\n\n const describedCurrent = await describeEntry({\n absolutePath: physicalDir,\n relativePath: logicalDir,\n rootRealPath,\n ancestors,\n followSymlinks,\n selectedPaths: filtersActive ? selection.selected : null,\n });\n if (describedCurrent.kind !== \"directory\") {\n throw new Error(`${physicalDir} is not a directory`);\n }\n const current: DirectoryData[\"current\"] = {\n ...describedCurrent,\n kind: \"directory\",\n };\n\n const root = await describeEntry({\n absolutePath: sourceDir,\n relativePath: \"\",\n rootRealPath,\n ancestors: new Set(),\n followSymlinks,\n selectedPaths: filtersActive ? selection.selected : null,\n });\n const parent =\n logicalDir === \"\"\n ? null\n : await describeEntry({\n absolutePath: path.dirname(physicalDir),\n relativePath:\n path.posix.dirname(logicalDir) === \".\" ? \"\" : path.posix.dirname(logicalDir),\n rootRealPath,\n ancestors,\n followSymlinks,\n selectedPaths: filtersActive ? selection.selected : null,\n });\n const directory: DirectoryData = {\n root,\n current,\n parent,\n depth: logicalDir === \"\" ? 0 : logicalDir.split(\"/\").length,\n entries,\n };\n\n const name = await resolveOutputName(directory);\n if (name !== null) assertSafeOutputName(name);\n plans.push({ directory, logicalDir, outputName: name });\n\n for (const entry of entries) {\n if (entry.kind === \"directory\") {\n await visit(path.posix.join(logicalDir, entry.name), entry.absolutePath, nextAncestors);\n continue;\n }\n if (!followSymlinks || entry.symlink?.targetKind !== \"directory\") continue;\n const physicalLinkPath = path\n .relative(rootRealPath, path.join(physicalRealPath, entry.name))\n .split(path.sep)\n .join(\"/\");\n if ((options.mirror ?? true) && !selection.mirroredSymlinks.has(physicalLinkPath)) continue;\n if (entry.symlink.isCycle) {\n if (onCycle === \"error\") throw new Error(`Symlink cycle at ${entry.relativePath}`);\n continue;\n }\n if (entry.symlink.resolvedPath === null) continue;\n if (boundary === \"root\" && entry.symlink.isOutsideRoot) continue;\n if (\n filtersActive &&\n (entry.symlink.targetRelativePath === null ||\n !selection.selected.has(entry.symlink.targetRelativePath))\n )\n continue;\n // Mirrored internal aliases already resolve to the target's generated page.\n // Writing an alias page through the copied symlink would overwrite that page.\n if (\n (options.mirror ?? true) &&\n entry.symlink.targetRelativePath !== null &&\n !entry.symlink.isOutsideRoot\n )\n continue;\n await visit(\n path.posix.join(logicalDir, entry.name),\n entry.symlink.resolvedPath,\n nextAncestors,\n );\n }\n }\n\n try {\n await visit(\"\", sourceDir, new Set());\n\n const generatedPages = new Map(\n plans\n .filter(\n (plan): plan is typeof plan & { readonly outputName: string } => plan.outputName !== null,\n )\n .map((plan) => [plan.logicalDir, plan.outputName]),\n );\n const generatedDirectories = new Set(generatedPages.keys());\n const pagePathForDirectory = (logicalPath: string): string => {\n const pageName = generatedPages.get(logicalPath);\n return pageName === undefined || pageName === \"index.html\"\n ? logicalPath\n : path.posix.join(logicalPath, pageName);\n };\n const sourceKinds = new Map<string, string>();\n for (const { directory } of plans)\n for (const entry of directory.entries) {\n const sourcePath = path.relative(sourceDir, entry.absolutePath).split(path.sep).join(\"/\");\n if (selection.selected.has(sourcePath)) sourceKinds.set(sourcePath, entry.kind);\n }\n const metadataResolver = await options.metadata?.({ sourceDir, sourceKinds });\n const sharedAssets = new Map<string, string | Uint8Array>();\n const rawLinkFiles = new Map<string, string>();\n const searchEntries = new Map<\n string,\n {\n href: string | null;\n exitsExplorer: boolean;\n isLink: boolean;\n kind: EntryKind;\n modifiedAt: string;\n name: string;\n path: string;\n size: number;\n target: string | null;\n targetKind: Exclude<EntryKind, \"symlink\"> | null;\n targetSize: number | null;\n isTargetUnavailable: boolean;\n isCycle: boolean;\n }\n >();\n\n for (const { directory, logicalDir } of theme.searchIndex === false ? [] : plans) {\n for (const entry of directory.entries) {\n if (searchEntries.has(entry.relativePath)) continue;\n const targetLogicalPath = isUnavailableSymlink(entry)\n ? null\n : entry.symlink?.targetRelativePath !== null && entry.symlink !== null\n ? entry.symlink.targetRelativePath\n : path.posix.join(logicalDir, entry.name);\n const directoryLike = isDirectoryLike(entry);\n const linkedPath =\n directoryLike && targetLogicalPath !== null\n ? pagePathForDirectory(targetLogicalPath)\n : targetLogicalPath;\n let href: string | null = null;\n if (entry.symlink !== null && isUnavailableSymlink(entry)) {\n const filename = rawLinkFilename(entry);\n rawLinkFiles.set(filename, entry.symlink.target);\n href = `raw-links/${filename}`;\n } else if (linkedPath !== null) {\n href =\n linkedPath === \"\"\n ? \"../\"\n : `../${encodeLogicalPath(linkedPath)}${directoryLike && linkedPath === targetLogicalPath ? \"/\" : \"\"}`;\n }\n searchEntries.set(entry.relativePath, {\n exitsExplorer:\n isUnavailableSymlink(entry) ||\n (targetLogicalPath !== null &&\n (!directoryLike || !generatedDirectories.has(targetLogicalPath))),\n href,\n isLink: entry.kind === \"symlink\",\n kind: entry.kind,\n modifiedAt: entry.metadata.times.modifiedAt,\n name: entry.name,\n path: entry.relativePath,\n size: entry.metadata.size,\n target: entry.symlink?.target ?? null,\n targetKind: entry.symlink?.targetKind ?? null,\n targetSize: entry.symlink?.targetSize ?? null,\n isTargetUnavailable: isUnavailableSymlink(entry),\n isCycle: entry.symlink?.isCycle ?? false,\n });\n }\n }\n\n for (const plan of plans) {\n const { directory, logicalDir, outputName: name } = plan;\n const sourceEntryNames = new Set(directory.entries.map((entry) => entry.name.toLowerCase()));\n if (name === null) continue;\n\n const targetLogicalPathFor = (entry: FileSystemEntry): string | null => {\n if (isUnavailableSymlink(entry)) return null;\n if (entry.symlink?.targetRelativePath !== null && entry.symlink !== null) {\n return entry.symlink.targetRelativePath;\n }\n return path.posix.join(logicalDir, entry.name);\n };\n const hrefForLogicalPath = (targetPath: string, directoryLike: boolean): string => {\n const linkedPath = directoryLike ? pagePathForDirectory(targetPath) : targetPath;\n const linkToDirectory = directoryLike && linkedPath === targetPath;\n if (urlStrategy === \"relative\") {\n const relativeTarget = path.posix.relative(\n logicalDir === \"\" ? \".\" : logicalDir,\n linkedPath === \"\" ? \".\" : linkedPath,\n );\n const encodedTarget = relativeTarget\n .split(\"/\")\n .map((segment) =>\n segment === \".\" || segment === \"..\" ? segment : encodeURIComponent(segment),\n )\n .join(\"/\");\n return `${encodedTarget || \".\"}${linkToDirectory ? \"/\" : \"\"}`;\n }\n const encodedTarget = encodeLogicalPath(linkedPath);\n if (encodedTarget === \"\") {\n return urlStrategy === \"base\" ? base : \"./\";\n }\n const suffix = `${encodedTarget}${linkToDirectory ? \"/\" : \"\"}`;\n return urlStrategy === \"base\" ? `${base}${suffix}` : suffix;\n };\n const hrefFor = (entry: FileSystemEntry): string | null => {\n if (entry.symlink !== null && isUnavailableSymlink(entry)) {\n const filename = rawLinkFilename(entry);\n rawLinkFiles.set(filename, entry.symlink.target);\n return hrefForLogicalPath(path.posix.join(\"__dirwell\", \"raw-links\", filename), false);\n }\n const targetLogicalPath = targetLogicalPathFor(entry);\n if (targetLogicalPath === null) return null;\n const directoryLike =\n entry.kind === \"directory\" || entry.symlink?.targetKind === \"directory\";\n return hrefForLogicalPath(targetLogicalPath, directoryLike);\n };\n const baseContext: ThemeContext = {\n operation: \"build\",\n directory,\n documentBaseHref: urlStrategy === \"html-base\" ? base : null,\n outputName: name,\n mode,\n searchIndexHref: hrefForLogicalPath(\n path.posix.join(\"__dirwell\", \"search-index.json\"),\n false,\n ),\n sort: { ...defaultSort, ...options.sort },\n assetHref: (assetName) => {\n assertSafeOutputName(assetName);\n return hrefForLogicalPath(\n mode === \"ssg\"\n ? path.posix.join(logicalDir, assetName)\n : path.posix.join(\"__dirwell\", assetName),\n false,\n );\n },\n hrefFor,\n hrefForDirectory: (relativePath) => hrefForLogicalPath(relativePath, true),\n hasPageForDirectory: (relativePath) => generatedDirectories.has(relativePath),\n exitsExplorerFor: (entry) => {\n if (isUnavailableSymlink(entry)) return true;\n const targetLogicalPath = targetLogicalPathFor(entry);\n const directoryLike =\n entry.kind === \"directory\" || entry.symlink?.targetKind === \"directory\";\n return (\n targetLogicalPath !== null &&\n (!directoryLike || !generatedDirectories.has(targetLogicalPath))\n );\n },\n };\n const targetDir = path.join(buildOutputDir, logicalDir);\n await mkdir(targetDir, { recursive: true });\n const sort = baseContext.sort;\n let revision = \"\";\n let manifestHref = \"\";\n let pageSize = Math.max(1, directory.entries.length);\n if (options.listing !== undefined) {\n const records = directory.entries.map((entry) => {\n const projected = projectListingEntry(entry, baseContext);\n return theme.entryData === undefined\n ? projected\n : {\n ...projected,\n presentation: copyJsonObject(\n theme.entryData(projected, {\n mode: baseContext.mode,\n outputName: baseContext.outputName,\n assetHref: baseContext.assetHref,\n hrefForDirectory: baseContext.hrefForDirectory,\n documentBaseHref: baseContext.documentBaseHref,\n directoryPath: logicalDir,\n }),\n ),\n };\n });\n const candidate =\n typeof options.listing === \"function\"\n ? options.listing({\n directoryPath: logicalDir,\n visibleCount: records.length,\n dataBytes: Buffer.byteLength(JSON.stringify(records)),\n mode,\n operation: \"build\",\n supportsPagination: theme.listing?.pagination === true,\n })\n : options.listing;\n validateListingPlan(candidate);\n if (candidate.html.strategy === \"paged\") {\n if (theme.listing?.pagination !== true)\n throw new Error(`Theme ${theme.name} does not support listing pagination`);\n pageSize = candidate.html.pageSize;\n }\n const directoryId = createHash(\"sha256\").update(logicalDir).digest(\"hex\");\n const manifestDirectory = path.posix.join(\"__dirwell\", \"listing\", directoryId);\n // Relative records belong to the document directory, not to the JSON asset directory.\n const hrefBase =\n urlStrategy === \"relative\"\n ? `../../../${encodeLogicalPath(logicalDir)}${logicalDir ? \"/\" : \"\"}`\n : base;\n const manifestPath = path.posix.join(manifestDirectory, \"manifest.json\");\n manifestHref = hrefForLogicalPath(manifestPath, false);\n const blocks: Array<ListingManifest[\"blocks\"][number]> = [];\n const blockSize =\n candidate.data.strategy === \"blocks\"\n ? candidate.data.blockSize\n : Math.max(1, records.length);\n revision = listingRevision(records, sort, hrefBase, blockSize);\n const outputListingDir = path.join(buildOutputDir, manifestDirectory);\n await mkdir(outputListingDir, { recursive: true });\n for (let offset = 0; offset < records.length || offset === 0; offset += blockSize) {\n const entries = records.slice(offset, offset + blockSize);\n const filename = `${revision}-${blocks.length}.json`;\n blocks.push({ href: filename, offset, count: entries.length });\n await writeFile(\n path.join(outputListingDir, filename),\n JSON.stringify({ version: 1, revision, offset, total: records.length, entries }),\n );\n }\n const manifest: ListingManifest = {\n version: 1,\n revision,\n directory: logicalDir,\n hrefBase,\n total: records.length,\n sort,\n blocks,\n };\n await writeFile(path.join(outputListingDir, \"manifest.json\"), JSON.stringify(manifest));\n }\n const pageCount = Math.max(1, Math.ceil(directory.entries.length / pageSize));\n const pagePrefix = `__dirwell-page-${createHash(\"sha256\").update(name).digest(\"hex\").slice(0, 16)}`;\n const pageNames = Array.from({ length: pageCount }, (_, index) =>\n index === 0 ? name : `${pagePrefix}-${index + 1}.html`,\n );\n for (const pageName of pageNames.slice(1)) {\n if (directory.entries.some((entry) => entry.name.toLowerCase() === pageName.toLowerCase()))\n throw new Error(\n `Listing page conflicts with source entry: ${path.posix.join(logicalDir, pageName)}`,\n );\n }\n const pagedAssets = new Map<string, Buffer>();\n for (const [index, pageName] of pageNames.entries()) {\n const pagePath = path.posix.join(logicalDir, pageName);\n const metadata = await metadataResolver?.resolve(\n directory,\n (outputPath) => hrefForLogicalPath(outputPath, false),\n pageName === \"index.html\" ? (logicalDir ? `${logicalDir}/` : \"\") : pagePath,\n );\n const pageHref = (number: number): string =>\n hrefForLogicalPath(path.posix.join(logicalDir, pageNames[number] ?? name), false);\n const page = await theme.render({\n ...baseContext,\n ...(metadata === undefined ? {} : { metadata }),\n outputName: pageName,\n directory:\n options.listing === undefined\n ? directory\n : {\n ...directory,\n entries: directory.entries.slice(index * pageSize, (index + 1) * pageSize),\n },\n ...(options.listing === undefined\n ? {}\n : {\n listing: {\n revision,\n manifestHref,\n page: {\n number: index + 1,\n count: pageCount,\n offset: index * pageSize,\n total: directory.entries.length,\n href: pageHref(index),\n previousHref: index === 0 ? null : pageHref(index - 1),\n nextHref: index + 1 === pageCount ? null : pageHref(index + 1),\n },\n },\n }),\n });\n await writeFile(path.join(targetDir, pageName), page.html);\n for (const [assetName, contents] of Object.entries(page.assets ?? {})) {\n assertSafeOutputName(assetName);\n if (\n (options.listing !== undefined || theme.listing?.pagination === true) &&\n mode === \"ssg\" &&\n sourceEntryNames.has(assetName.toLowerCase())\n )\n throw new Error(`Theme asset conflicts with source entry: ${assetName}`);\n if (\n options.listing !== undefined &&\n pageNames.some((pageName) => pageName.toLowerCase() === assetName.toLowerCase())\n )\n throw new Error(`Theme asset conflicts with listing page: ${assetName}`);\n if (options.listing !== undefined && pageCount > 1) {\n const bytes = Buffer.from(contents);\n const existing = pagedAssets.get(assetName);\n if (existing !== undefined && !existing.equals(bytes))\n throw new Error(`Theme emitted conflicting paginated asset: ${assetName}`);\n pagedAssets.set(assetName, bytes);\n }\n if (mode === \"ssg\") {\n await writeFile(path.join(targetDir, assetName), contents);\n } else {\n const bytes = Buffer.from(contents);\n const existing = sharedAssets.get(assetName);\n if (existing !== undefined && !Buffer.from(existing).equals(bytes)) {\n throw new Error(`Theme emitted conflicting shared asset: ${assetName}`);\n }\n sharedAssets.set(assetName, bytes);\n }\n }\n }\n }\n\n if (mode === \"mpa\" && sharedAssets.size > 0) {\n const assetDirectory = path.join(buildOutputDir, \"__dirwell\");\n await mkdir(assetDirectory, { recursive: true });\n for (const [assetName, contents] of sharedAssets) {\n await writeFile(path.join(assetDirectory, assetName), contents);\n }\n }\n\n for (const [filename, bytes] of metadataResolver?.assets ?? []) {\n const parts = filename.split(\"/\");\n for (let index = 1; index <= parts.length; index++) {\n const prefix = parts.slice(0, index).join(\"/\");\n if (selection.selected.has(prefix))\n throw new Error(`Metadata image conflicts with source entry: ${filename}`);\n const candidate = path.join(buildOutputDir, prefix);\n try {\n const info = await lstat(candidate);\n if (info.isSymbolicLink() || index === parts.length || !info.isDirectory())\n throw new Error(`Metadata image conflicts with generated output: ${filename}`);\n } catch (error) {\n if (!(error instanceof Error && \"code\" in error && error.code === \"ENOENT\")) throw error;\n }\n }\n const destination = path.join(buildOutputDir, filename);\n await mkdir(path.dirname(destination), { recursive: true });\n await writeFile(destination, bytes);\n }\n\n if (rawLinkFiles.size > 0) {\n const rawLinkDirectory = path.join(buildOutputDir, \"__dirwell\", \"raw-links\");\n await mkdir(rawLinkDirectory, { recursive: true });\n for (const [filename, target] of rawLinkFiles) {\n await writeFile(path.join(rawLinkDirectory, filename), target);\n }\n }\n if (theme.searchIndex !== false) {\n const generatedAssetDirectory = path.join(buildOutputDir, \"__dirwell\");\n await mkdir(generatedAssetDirectory, { recursive: true });\n const indexedEntries = [...searchEntries.values()];\n const shards: string[] = [];\n for (let offset = 0; offset < indexedEntries.length; offset += 512) {\n const filename = `search-${String(shards.length).padStart(5, \"0\")}.json`;\n shards.push(filename);\n await writeFile(\n path.join(generatedAssetDirectory, filename),\n JSON.stringify({ entries: indexedEntries.slice(offset, offset + 512) }),\n );\n }\n await writeFile(\n path.join(generatedAssetDirectory, \"search-index.json\"),\n JSON.stringify({ count: indexedEntries.length, shards, version: 3 }),\n );\n }\n\n await rm(outputDir, { recursive: true, force: true });\n await mkdir(path.dirname(outputDir), { recursive: true });\n await rename(stagedOutputDir, outputDir);\n } finally {\n await rm(stagedOutputDir, { recursive: true, force: true });\n }\n}\n\nexport async function readGeneratedPage(filePath: string): Promise<string> {\n return readFile(filePath, \"utf8\");\n}\n","/** Escape untrusted text for HTML/XML text nodes and double-quoted attributes. */\nexport function escapeHtml(value: string): string {\n return value\n .replaceAll(\"&\", \"&\")\n .replaceAll(\"<\", \"<\")\n .replaceAll(\">\", \">\")\n .replaceAll('\"', \""\");\n}\n","/** Some Windows Node/libuv versions omit the path-stat device ID but retain the file ID. */\nexport function fileIdentityMatches(\n before: { readonly device: number; readonly inode: number },\n descriptor: { readonly dev: number; readonly ino: number },\n platform = process.platform,\n): boolean {\n if (before.inode !== descriptor.ino) return false;\n if (before.device === descriptor.dev) return true;\n return platform === \"win32\" && before.device === 0 && before.inode !== 0;\n}\n","import { readdir, realpath, open, type FileHandle } from \"node:fs/promises\";\nimport { constants } from \"node:fs\";\nimport { fileIdentityMatches } from \"./file-identity.ts\";\nimport path from \"node:path\";\nimport { describeEntry, isInsideRoot } from \"./filesystem.ts\";\nimport { selectSourcePaths } from \"./filters.ts\";\nimport { compareEntries } from \"./generator.ts\";\nimport type { DirectoryData, FileSystemEntry, SortOptions } from \"./model.ts\";\n\nexport interface DirectoryServiceOptions {\n readonly root: string;\n readonly include?: string | readonly string[];\n readonly exclude?: string | readonly string[];\n readonly sort?: SortOptions;\n}\nexport interface DirectoryService {\n readonly resolvePath: (logicalPath: string) => Promise<string>;\n readonly openFile: (logicalPath: string) => Promise<{\n readonly entry: FileSystemEntry;\n readonly handle: FileHandle;\n readonly canonicalPath: string;\n }>;\n readonly getEntry: (logicalPath: string) => Promise<FileSystemEntry>;\n readonly listDirectory: (logicalPath: string) => Promise<DirectoryData>;\n}\nexport class DirectoryAccessError extends Error {\n override readonly name = \"DirectoryAccessError\";\n}\nfunction assertLogicalPath(value: string): void {\n if (\n value.startsWith(\"/\") ||\n value.includes(\"\\\\\") ||\n value.includes(\"\\0\") ||\n value\n .split(\"/\")\n .some((segment) => segment === \".\" || segment === \"..\" || (segment === \"\" && value !== \"\")) ||\n /^[a-z]:/i.test(value) ||\n value === \"__dirwell\" ||\n value.startsWith(\"__dirwell/\")\n )\n throw new DirectoryAccessError(\"Unavailable path\");\n}\n/** Live reads; no watcher, recursive stat snapshot, output tree or implicit cache. */\nexport async function createDirectoryService(\n options: DirectoryServiceOptions,\n): Promise<DirectoryService> {\n const root = await realpath(options.root);\n const selected = async () =>\n options.include === undefined && options.exclude === undefined\n ? null\n : (\n await selectSourcePaths(\n root,\n path.join(root, \"__dirwell\"),\n options.include,\n options.exclude,\n )\n ).selected;\n async function describe(\n logicalPath: string,\n selection: ReadonlySet<string> | null,\n ): Promise<FileSystemEntry> {\n assertLogicalPath(logicalPath);\n if (selection !== null && !selection.has(logicalPath))\n throw new DirectoryAccessError(\"Unavailable path\");\n const absolutePath = path.join(root, logicalPath);\n const parent = logicalPath === \"\" ? root : await realpath(path.dirname(absolutePath));\n if (!isInsideRoot(root, parent)) throw new DirectoryAccessError(\"Unavailable path\");\n const ancestors = new Set<string>([root]);\n if (logicalPath !== \"\") {\n const segments = logicalPath.split(\"/\").slice(0, -1);\n for (let length = 1; length <= segments.length; length++)\n ancestors.add(await realpath(path.join(root, ...segments.slice(0, length))));\n }\n return describeEntry({\n absolutePath,\n relativePath: logicalPath,\n rootRealPath: root,\n ancestors,\n followSymlinks: false,\n selectedPaths: selection,\n });\n }\n return {\n async resolvePath(logicalPath) {\n const selection = await selected();\n const entry = await describe(logicalPath, selection);\n if (\n entry.symlink &&\n (entry.symlink.isBroken || entry.symlink.isOutsideRoot || entry.symlink.isTargetExcluded)\n )\n throw new DirectoryAccessError(\"Unavailable target\");\n const resolved = await realpath(entry.absolutePath);\n if (!isInsideRoot(root, resolved)) throw new DirectoryAccessError(\"Unavailable target\");\n const canonical = path.relative(root, resolved).split(path.sep).join(\"/\");\n if (selection !== null && !selection.has(canonical))\n throw new DirectoryAccessError(\"Unavailable target\");\n return canonical;\n },\n async openFile(logicalPath) {\n assertLogicalPath(logicalPath);\n const selection = await selected();\n let entry = await describe(logicalPath, selection);\n if (entry.symlink !== null) {\n if (\n entry.symlink.isBroken ||\n entry.symlink.isOutsideRoot ||\n entry.symlink.isTargetExcluded ||\n entry.symlink.targetRelativePath === null\n )\n throw new DirectoryAccessError(\"Unavailable file\");\n entry = await describe(entry.symlink.targetRelativePath, selection);\n }\n if (entry.kind !== \"file\") throw new DirectoryAccessError(\"Unavailable file\");\n const handle = await open(\n entry.absolutePath,\n constants.O_RDONLY | (constants.O_NOFOLLOW ?? 0),\n );\n try {\n const stats = await handle.stat();\n const resolved = await realpath(entry.absolutePath);\n if (\n !stats.isFile() ||\n !isInsideRoot(root, resolved) ||\n !fileIdentityMatches(entry.metadata, stats)\n )\n throw new DirectoryAccessError(\"File changed before opening\");\n return {\n entry,\n handle,\n canonicalPath: path.relative(root, resolved).split(path.sep).join(\"/\"),\n };\n } catch (error) {\n await handle.close();\n throw error;\n }\n },\n async getEntry(logicalPath) {\n assertLogicalPath(logicalPath);\n return describe(logicalPath, await selected());\n },\n async listDirectory(logicalPath) {\n assertLogicalPath(logicalPath);\n const selection = await selected();\n const entry = await describe(logicalPath, selection);\n if (entry.kind !== \"directory\") throw new DirectoryAccessError(\"Unavailable directory\");\n const physical = await realpath(entry.absolutePath);\n if (!isInsideRoot(root, physical)) throw new DirectoryAccessError(\"Unavailable directory\");\n const names = (await readdir(physical)).filter(\n (name) => logicalPath !== \"\" || name !== \"__dirwell\",\n );\n const entries = await Promise.all(\n names\n .filter((name) => selection === null || selection.has(path.posix.join(logicalPath, name)))\n .map((name) => describe(path.posix.join(logicalPath, name), selection)),\n );\n entries.sort(\n (left, right) =>\n compareEntries(left, right, options.sort) ||\n (left.relativePath < right.relativePath\n ? -1\n : left.relativePath > right.relativePath\n ? 1\n : 0),\n );\n return {\n root: await describe(\"\", selection),\n current: { ...entry, kind: \"directory\" },\n parent:\n logicalPath === \"\"\n ? null\n : await describe(\n path.posix.dirname(logicalPath) === \".\" ? \"\" : path.posix.dirname(logicalPath),\n selection,\n ),\n depth: logicalPath === \"\" ? 0 : logicalPath.split(\"/\").length,\n entries,\n };\n },\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../src/filesystem.ts","../src/listing.ts","../src/filters.ts","../src/generator.ts","../src/html.ts","../src/file-identity.ts","../src/service.ts"],"sourcesContent":["import { lstat, readlink, realpath, stat } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport type { Stats } from \"node:fs\";\nimport type { EntryKind, FileMetadata, FileSystemEntry, SymlinkMetadata } from \"./model.ts\";\nfunction entryKind(stats: Stats): EntryKind {\n if (stats.isDirectory()) return \"directory\";\n if (stats.isFile()) return \"file\";\n if (stats.isSymbolicLink()) return \"symlink\";\n return \"other\";\n}\n\nfunction metadata(stats: Stats): FileMetadata {\n return {\n device: stats.dev,\n groupId: stats.gid,\n hardLinkCount: stats.nlink,\n inode: stats.ino,\n mode: stats.mode,\n ownerId: stats.uid,\n size: stats.size,\n times: {\n accessedAt: stats.atime.toISOString(),\n changedAt: stats.ctime.toISOString(),\n createdAt: stats.birthtime.toISOString(),\n modifiedAt: stats.mtime.toISOString(),\n },\n };\n}\n\nexport function isInsideRoot(rootPath: string, candidatePath: string): boolean {\n const relative = path.relative(rootPath, candidatePath);\n return (\n relative === \"\" ||\n (relative !== \"..\" && !relative.startsWith(`..${path.sep}`) && !path.isAbsolute(relative))\n );\n}\n\nexport async function describeEntry({\n absolutePath,\n relativePath,\n rootRealPath,\n ancestors,\n followSymlinks,\n selectedPaths,\n}: {\n absolutePath: string;\n relativePath: string;\n rootRealPath: string;\n ancestors: ReadonlySet<string>;\n followSymlinks: boolean;\n selectedPaths: ReadonlySet<string> | null;\n}): Promise<FileSystemEntry> {\n const linkStats = await lstat(absolutePath);\n const kind = entryKind(linkStats);\n let symlink: SymlinkMetadata | null = null;\n\n if (kind === \"symlink\") {\n const target = await readlink(absolutePath);\n let resolvedPath: string | null = null;\n let targetKind: Exclude<EntryKind, \"symlink\"> | null = null;\n let targetSize: number | null = null;\n try {\n resolvedPath = await realpath(absolutePath);\n const targetStats = await stat(absolutePath);\n targetKind = entryKind(targetStats) as Exclude<EntryKind, \"symlink\">;\n targetSize = targetStats.size;\n } catch {\n // Broken and inaccessible links are represented as data.\n }\n const isOutsideRoot = resolvedPath === null || !isInsideRoot(rootRealPath, resolvedPath);\n const isCycle = resolvedPath !== null && ancestors.has(resolvedPath);\n const targetRelativePath =\n resolvedPath !== null && !isOutsideRoot\n ? path.relative(rootRealPath, resolvedPath).split(path.sep).join(\"/\")\n : null;\n const isTargetExcluded =\n targetRelativePath !== null &&\n selectedPaths !== null &&\n !selectedPaths.has(targetRelativePath);\n symlink = {\n target,\n resolvedPath,\n targetRelativePath,\n targetKind,\n targetSize:\n isOutsideRoot || isTargetExcluded || targetKind === \"directory\" ? null : targetSize,\n isBroken: resolvedPath === null,\n isCycle,\n isOutsideRoot,\n isTargetExcluded,\n wasFollowed:\n followSymlinks &&\n targetKind === \"directory\" &&\n !isCycle &&\n !isOutsideRoot &&\n !isTargetExcluded,\n };\n }\n\n return {\n name: path.basename(absolutePath),\n absolutePath,\n relativePath,\n kind,\n metadata: metadata(linkStats),\n symlink,\n };\n}\n","import type { JsonObject } from \"./json.ts\";\nimport { createHash } from \"node:crypto\";\nimport type { EntryKind, FileSystemEntry, ThemeContext, SortOptions } from \"./model.ts\";\n\n/** Public transport fields only. Internal filesystem metadata must never be spread here. */\nexport interface ListingEntry {\n readonly presentation?: JsonObject;\n readonly id: string;\n readonly name: string;\n readonly kind: EntryKind;\n readonly href: string | null;\n readonly exitsExplorer: boolean;\n readonly size: number;\n readonly modifiedAt: string;\n readonly link: null | {\n readonly target: string;\n readonly targetKind: Exclude<EntryKind, \"symlink\"> | null;\n readonly targetSize: number | null;\n readonly unavailable: boolean;\n readonly cycle: boolean;\n };\n}\nexport interface ListingPlan {\n readonly html:\n | { readonly strategy: \"all\" }\n | { readonly strategy: \"paged\"; readonly pageSize: number };\n readonly data:\n | { readonly strategy: \"all\" }\n | { readonly strategy: \"blocks\"; readonly blockSize: number };\n}\nexport interface ListingPolicyContext {\n readonly operation?: \"build\" | \"server\";\n readonly directoryPath: string;\n readonly visibleCount: number;\n readonly dataBytes: number;\n readonly mode: \"ssg\" | \"mpa\";\n readonly supportsPagination: boolean;\n}\nexport type ListingPolicy = ListingPlan | ((context: ListingPolicyContext) => ListingPlan);\nexport interface ListingPage {\n readonly number: number;\n readonly count: number;\n readonly offset: number;\n readonly total: number;\n readonly href: string;\n readonly previousHref: string | null;\n readonly nextHref: string | null;\n}\nexport interface ListingContext {\n readonly revision: string;\n readonly manifestHref: string;\n readonly page: ListingPage;\n}\nexport interface ListingBlock {\n readonly version: 1;\n readonly revision: string;\n readonly offset: number;\n readonly total: number;\n readonly entries: readonly ListingEntry[];\n}\nexport interface ListingManifest {\n readonly version: 1;\n readonly revision: string;\n readonly directory: string;\n /** Resolve entry hrefs against this URL, resolved relative to the manifest URL. */\n readonly hrefBase: string;\n readonly total: number;\n readonly sort: Required<SortOptions>;\n /** Block hrefs are relative to the manifest URL. */\n readonly blocks: readonly {\n readonly href: string;\n readonly offset: number;\n readonly count: number;\n }[];\n}\n\nexport function projectListingEntry(\n entry: FileSystemEntry,\n context: Pick<ThemeContext, \"hrefFor\" | \"exitsExplorerFor\">,\n): ListingEntry {\n const link = entry.symlink;\n return {\n id: entry.relativePath,\n name: entry.name,\n kind: entry.kind,\n href: context.hrefFor(entry),\n exitsExplorer: context.exitsExplorerFor(entry),\n size: entry.metadata.size,\n modifiedAt: entry.metadata.times.modifiedAt,\n link:\n link === null\n ? null\n : {\n target: link.target,\n targetKind: link.targetKind,\n targetSize: link.targetSize ?? null,\n unavailable: link.isBroken || link.isOutsideRoot || Boolean(link.isTargetExcluded),\n cycle: link.isCycle,\n },\n };\n}\nfunction record(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\nfunction positiveInteger(value: unknown, key: string): void {\n if (typeof value !== \"number\" || !Number.isSafeInteger(value) || value < 1)\n throw new TypeError(`${key} must be a positive safe integer`);\n}\nexport function validateListingPlan(value: unknown): asserts value is ListingPlan {\n if (!record(value) || !record(value.html) || !record(value.data))\n throw new TypeError(\"listing must contain html and data plans\");\n if (value.html.strategy === \"paged\")\n positiveInteger(value.html.pageSize, \"listing.html.pageSize\");\n else if (value.html.strategy !== \"all\")\n throw new TypeError('listing.html.strategy must be \"all\" or \"paged\"');\n if (value.data.strategy === \"blocks\")\n positiveInteger(value.data.blockSize, \"listing.data.blockSize\");\n else if (value.data.strategy !== \"all\")\n throw new TypeError('listing.data.strategy must be \"all\" or \"blocks\"');\n}\nexport function listingRevision(\n entries: readonly ListingEntry[],\n sort: Required<SortOptions>,\n hrefBase: string,\n blockSize: number,\n): string {\n return createHash(\"sha256\")\n .update(JSON.stringify({ version: 1, entries, sort, hrefBase, blockSize }))\n .digest(\"hex\");\n}\n","import { readdir, readlink } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport picomatch from \"picomatch\";\n\nexport function normalizePathPatterns(value: unknown, name: string): readonly string[] {\n if (value === undefined) return [];\n const patterns = typeof value === \"string\" ? [value] : value;\n if (\n !Array.isArray(patterns) ||\n patterns.some(\n (pattern) =>\n typeof pattern !== \"string\" ||\n pattern.length === 0 ||\n pattern.startsWith(\"/\") ||\n /^[A-Za-z]:/.test(pattern) ||\n pattern.startsWith(\"!\") ||\n pattern.includes(\"\\\\\") ||\n pattern.split(\"/\").some((segment) => segment === \".\" || segment === \"..\"),\n )\n ) {\n throw new TypeError(`${name} must contain root-relative glob patterns using forward slashes`);\n }\n return patterns as readonly string[];\n}\n\nfunction isWithin(parent: string, candidate: string): boolean {\n const relative = path.relative(parent, candidate);\n return (\n relative === \"\" ||\n (relative !== \"..\" && !relative.startsWith(`..${path.sep}`) && !path.isAbsolute(relative))\n );\n}\n\nexport interface SourceSelection {\n readonly selected: ReadonlySet<string>;\n readonly symlinks: ReadonlySet<string>;\n readonly mirroredSymlinks: ReadonlySet<string>;\n}\n\n/** Select physical source paths; parent directories remain when a descendant matches. */\nexport async function selectSourcePaths(\n sourceDir: string,\n outputDir: string,\n include: unknown,\n exclude: unknown,\n ignoredPaths: readonly string[] = [],\n): Promise<SourceSelection> {\n const ignored = ignoredPaths.map((value) => path.resolve(value));\n const included = normalizePathPatterns(include, \"include\").map((pattern) =>\n picomatch(pattern, { dot: true, nonegate: true }),\n );\n const excluded = normalizePathPatterns(exclude, \"exclude\").map((pattern) =>\n picomatch(pattern, { dot: true, nonegate: true }),\n );\n const selected = new Set<string>([\"\"]);\n const symlinks = new Map<string, string>();\n\n async function visit(\n directory: string,\n relativeDir: string,\n inheritedInclude: boolean,\n ): Promise<boolean> {\n let hasSelected = false;\n for (const entry of await readdir(directory, { withFileTypes: true })) {\n const absolutePath = path.join(directory, entry.name);\n if (\n isWithin(outputDir, absolutePath) ||\n ignored.some((value) => isWithin(value, absolutePath))\n )\n continue;\n const relativePath = path.posix.join(relativeDir, entry.name);\n const directoryLike = entry.isDirectory();\n const matches = (matcher: (value: string) => boolean) =>\n matcher(relativePath) || (directoryLike && matcher(`${relativePath}/`));\n if (excluded.some(matches)) continue;\n const includedHere = inheritedInclude || included.some(matches);\n if (directoryLike) {\n const hasSelectedChild = await visit(absolutePath, relativePath, includedHere);\n if (included.length === 0 || includedHere || hasSelectedChild) {\n selected.add(relativePath);\n hasSelected = true;\n }\n } else if (included.length === 0 || includedHere) {\n selected.add(relativePath);\n hasSelected = true;\n if (entry.isSymbolicLink()) symlinks.set(relativePath, await readlink(absolutePath));\n }\n }\n return hasSelected;\n }\n\n await visit(sourceDir, \"\", false);\n // Absolute, escaping, and filtered targets cannot remain valid inside the copied tree.\n const mirroredSymlinks = new Set<string>();\n for (const [relativePath, target] of symlinks) {\n if (path.isAbsolute(target)) continue;\n const targetPath = path.resolve(sourceDir, path.dirname(relativePath), target);\n if (!isWithin(sourceDir, targetPath)) continue;\n const targetRelativePath = path.relative(sourceDir, targetPath).split(path.sep).join(\"/\");\n if (selected.has(targetRelativePath)) mirroredSymlinks.add(relativePath);\n }\n return { selected, symlinks: new Set(symlinks.keys()), mirroredSymlinks };\n}\n","import { copyJsonObject } from \"./json.ts\";\nimport { describeEntry, isInsideRoot } from \"./filesystem.ts\";\nimport {\n listingRevision,\n projectListingEntry,\n validateListingPlan,\n type ListingManifest,\n} from \"./listing.ts\";\nimport {\n cp,\n lstat,\n mkdtemp,\n mkdir,\n readFile,\n readdir,\n realpath,\n rename,\n rm,\n writeFile,\n} from \"node:fs/promises\";\nimport { createHash } from \"node:crypto\";\nimport path from \"node:path\";\nimport type {\n DirectoryData,\n EntryKind,\n ExplorerTheme,\n FileSystemEntry,\n GenerateOptions,\n NameSortMode,\n OutputNameResolver,\n SortOptions,\n ThemeContext,\n} from \"./model.ts\";\nimport { selectSourcePaths } from \"./filters.ts\";\n\nconst indexPattern = /^index\\.html?$/i;\n\nconst defaultSort = {\n direction: \"asc\",\n directoriesFirst: true,\n field: \"name\",\n nameMode: \"natural\",\n} as const satisfies Required<SortOptions>;\n\nexport const defaultOutputName: OutputNameResolver = ({ entries }) =>\n entries.some((entry) => entry.kind === \"file\" && indexPattern.test(entry.name))\n ? entries.some((entry) => entry.name.toLowerCase() === \"_dirwell.html\")\n ? null\n : \"_dirwell.html\"\n : \"index.html\";\n\nfunction assertSafeOutputName(name: string): void {\n if (name.length === 0 || path.basename(name) !== name || name === \".\" || name === \"..\") {\n throw new Error(`Output name must be a single safe filename: ${name}`);\n }\n}\n\nfunction normalizeBase(value: string): string {\n if (value.includes(\"?\") || value.includes(\"#\")) {\n throw new TypeError(\"base must not contain a query string or fragment\");\n }\n if (/^https?:\\/\\//i.test(value)) {\n const url = new URL(value);\n url.pathname = `${url.pathname.replace(/\\/+$/, \"\")}/`;\n return url.href;\n }\n if (!value.startsWith(\"/\")) {\n throw new TypeError('base must start with \"/\" or be an absolute HTTP(S) URL');\n }\n return `${value.replace(/\\/+$/, \"\")}/`;\n}\n\nfunction encodeLogicalPath(value: string): string {\n return value\n .split(\"/\")\n .filter((segment) => segment.length > 0)\n .map((segment) => encodeURIComponent(segment))\n .join(\"/\");\n}\n\nfunction isDirectoryLike(entry: FileSystemEntry): boolean {\n return entry.kind === \"directory\" || entry.symlink?.targetKind === \"directory\";\n}\n\nfunction isUnavailableSymlink(entry: FileSystemEntry): boolean {\n return Boolean(\n entry.symlink?.isBroken || entry.symlink?.isOutsideRoot || entry.symlink?.isTargetExcluded,\n );\n}\n\nfunction compareUnicode(left: string, right: string): number {\n const leftPoints = [...left];\n const rightPoints = [...right];\n const length = Math.min(leftPoints.length, rightPoints.length);\n for (let index = 0; index < length; index += 1) {\n const difference =\n (leftPoints[index]?.codePointAt(0) ?? 0) - (rightPoints[index]?.codePointAt(0) ?? 0);\n if (difference !== 0) return difference;\n }\n return leftPoints.length - rightPoints.length;\n}\n\nfunction compareNames(left: string, right: string, mode: NameSortMode): number {\n if (mode === \"unicode\") return compareUnicode(left, right);\n return left.localeCompare(right, undefined, {\n numeric: mode === \"natural\",\n sensitivity: \"base\",\n });\n}\n\nexport function compareEntries(\n left: FileSystemEntry,\n right: FileSystemEntry,\n options: SortOptions = {},\n): number {\n const resolved = { ...defaultSort, ...options };\n if (resolved.directoriesFirst && isDirectoryLike(left) !== isDirectoryLike(right)) {\n return isDirectoryLike(left) ? -1 : 1;\n }\n let result: number;\n if (resolved.field === \"modified\") {\n result = left.metadata.times.modifiedAt.localeCompare(right.metadata.times.modifiedAt);\n } else if (resolved.field === \"size\") {\n result =\n (left.kind === \"directory\" ? 0 : left.metadata.size) -\n (right.kind === \"directory\" ? 0 : right.metadata.size);\n } else {\n result = compareNames(left.name, right.name, resolved.nameMode);\n }\n if (result === 0) result = compareNames(left.name, right.name, resolved.nameMode);\n return resolved.direction === \"asc\" ? result : -result;\n}\n\nfunction rawLinkFilename(entry: FileSystemEntry): string {\n return `${createHash(\"sha256\")\n .update(entry.relativePath)\n .update(\"\\0\")\n .update(entry.symlink?.target ?? \"\")\n .digest(\"hex\")\n .slice(0, 16)}.txt`;\n}\n\nexport async function generateExplorer(options: GenerateOptions): Promise<void> {\n return generateExplorerSkippingPaths(options, []);\n}\n\n/** Internal entry point for hosts that stage previews outside their published output. */\nexport async function generateExplorerSkippingPaths(\n options: GenerateOptions,\n ignoredPaths: readonly string[],\n): Promise<void> {\n const sourceDir = path.resolve(options.sourceDir);\n const outputDir = path.resolve(options.outputDir);\n const ignoredSourcePaths = ignoredPaths.map((value) => path.resolve(value));\n const rootRealPath = await realpath(sourceDir);\n const outputName = options.outputName ?? defaultOutputName;\n const resolveOutputName: OutputNameResolver =\n typeof outputName === \"string\" ? () => outputName : outputName;\n const theme: ExplorerTheme = options.theme;\n if (theme === undefined) throw new TypeError(\"Core requires an explicit theme\");\n const mode = options.mode ?? \"ssg\";\n const urlStrategy = options.urlStrategy ?? \"relative\";\n const base = normalizeBase(options.base ?? \"/\");\n const followSymlinks = options.symlinks?.follow ?? false;\n const boundary = options.symlinks?.boundary ?? \"root\";\n const onCycle = options.symlinks?.onCycle ?? \"skip\";\n const filtersActive =\n options.include !== undefined || options.exclude !== undefined || ignoredSourcePaths.length > 0;\n const plans: Array<{\n readonly directory: DirectoryData;\n readonly logicalDir: string;\n readonly outputName: string | null;\n }> = [];\n if (isInsideRoot(outputDir, sourceDir)) {\n throw new Error(\"outputDir must not contain the sourceDir\");\n }\n try {\n await lstat(path.join(sourceDir, \"__dirwell\"));\n throw new Error('Dirwell reserves the source-root path \"__dirwell\"');\n } catch (error) {\n if (error instanceof Error && \"code\" in error && error.code === \"ENOENT\") {\n // The reserved asset path is available.\n } else {\n throw error;\n }\n }\n const outputIsWithinSource = isInsideRoot(sourceDir, outputDir);\n const selection = await selectSourcePaths(\n sourceDir,\n outputDir,\n options.include,\n options.exclude,\n ignoredSourcePaths,\n );\n const stageParent = outputIsWithinSource ? path.dirname(sourceDir) : path.dirname(outputDir);\n await mkdir(stageParent, { recursive: true });\n const stagedOutputDir = await mkdtemp(\n path.join(stageParent, `.${path.basename(outputDir)}-dirwell-`),\n );\n const buildOutputDir = stagedOutputDir;\n\n try {\n if (options.mirror ?? true) {\n await rm(buildOutputDir, { recursive: true, force: true });\n await mkdir(buildOutputDir, { recursive: true });\n await cp(sourceDir, buildOutputDir, {\n recursive: true,\n dereference: false,\n preserveTimestamps: true,\n filter: (sourcePath) => {\n const relativePath = path.relative(sourceDir, sourcePath).split(path.sep).join(\"/\");\n return (\n selection.selected.has(relativePath) &&\n (!selection.symlinks.has(relativePath) || selection.mirroredSymlinks.has(relativePath))\n );\n },\n });\n }\n } catch (error) {\n await rm(stagedOutputDir, { recursive: true, force: true });\n throw error;\n }\n\n async function visit(\n logicalDir: string,\n physicalDir: string,\n ancestors: ReadonlySet<string>,\n ): Promise<void> {\n const physicalRealPath = await realpath(physicalDir);\n if (ancestors.has(physicalRealPath)) {\n if (onCycle === \"error\") throw new Error(`Symlink cycle at ${logicalDir}`);\n return;\n }\n\n const nextAncestors = new Set(ancestors).add(physicalRealPath);\n const names = (await readdir(physicalDir)).filter((name) => {\n if (outputIsWithinSource && isInsideRoot(outputDir, path.join(physicalDir, name)))\n return false;\n if (ignoredSourcePaths.some((value) => isInsideRoot(value, path.join(physicalDir, name))))\n return false;\n if (!filtersActive) return true;\n const relativePath = path.relative(rootRealPath, path.join(physicalRealPath, name));\n return selection.selected.has(relativePath.split(path.sep).join(\"/\"));\n });\n const entries = await Promise.all(\n names.map((name) =>\n describeEntry({\n absolutePath: path.join(physicalDir, name),\n relativePath: path.posix.join(logicalDir, name),\n rootRealPath,\n ancestors: nextAncestors,\n followSymlinks,\n selectedPaths: filtersActive ? selection.selected : null,\n }),\n ),\n );\n entries.sort(\n (left, right) =>\n compareEntries(left, right, options.sort) ||\n (options.listing === undefined ? 0 : compareUnicode(left.relativePath, right.relativePath)),\n );\n\n const describedCurrent = await describeEntry({\n absolutePath: physicalDir,\n relativePath: logicalDir,\n rootRealPath,\n ancestors,\n followSymlinks,\n selectedPaths: filtersActive ? selection.selected : null,\n });\n if (describedCurrent.kind !== \"directory\") {\n throw new Error(`${physicalDir} is not a directory`);\n }\n const current: DirectoryData[\"current\"] = {\n ...describedCurrent,\n kind: \"directory\",\n };\n\n const root = await describeEntry({\n absolutePath: sourceDir,\n relativePath: \"\",\n rootRealPath,\n ancestors: new Set(),\n followSymlinks,\n selectedPaths: filtersActive ? selection.selected : null,\n });\n const parent =\n logicalDir === \"\"\n ? null\n : await describeEntry({\n absolutePath: path.dirname(physicalDir),\n relativePath:\n path.posix.dirname(logicalDir) === \".\" ? \"\" : path.posix.dirname(logicalDir),\n rootRealPath,\n ancestors,\n followSymlinks,\n selectedPaths: filtersActive ? selection.selected : null,\n });\n const directory: DirectoryData = {\n root,\n current,\n parent,\n depth: logicalDir === \"\" ? 0 : logicalDir.split(\"/\").length,\n entries,\n };\n\n const name = await resolveOutputName(directory);\n if (name !== null) assertSafeOutputName(name);\n plans.push({ directory, logicalDir, outputName: name });\n\n for (const entry of entries) {\n if (entry.kind === \"directory\") {\n await visit(path.posix.join(logicalDir, entry.name), entry.absolutePath, nextAncestors);\n continue;\n }\n if (!followSymlinks || entry.symlink?.targetKind !== \"directory\") continue;\n const physicalLinkPath = path\n .relative(rootRealPath, path.join(physicalRealPath, entry.name))\n .split(path.sep)\n .join(\"/\");\n if ((options.mirror ?? true) && !selection.mirroredSymlinks.has(physicalLinkPath)) continue;\n if (entry.symlink.isCycle) {\n if (onCycle === \"error\") throw new Error(`Symlink cycle at ${entry.relativePath}`);\n continue;\n }\n if (entry.symlink.resolvedPath === null) continue;\n if (boundary === \"root\" && entry.symlink.isOutsideRoot) continue;\n if (\n filtersActive &&\n (entry.symlink.targetRelativePath === null ||\n !selection.selected.has(entry.symlink.targetRelativePath))\n )\n continue;\n // Mirrored internal aliases already resolve to the target's generated page.\n // Writing an alias page through the copied symlink would overwrite that page.\n if (\n (options.mirror ?? true) &&\n entry.symlink.targetRelativePath !== null &&\n !entry.symlink.isOutsideRoot\n )\n continue;\n await visit(\n path.posix.join(logicalDir, entry.name),\n entry.symlink.resolvedPath,\n nextAncestors,\n );\n }\n }\n\n try {\n await visit(\"\", sourceDir, new Set());\n\n const generatedPages = new Map(\n plans\n .filter(\n (plan): plan is typeof plan & { readonly outputName: string } => plan.outputName !== null,\n )\n .map((plan) => [plan.logicalDir, plan.outputName]),\n );\n const generatedDirectories = new Set(generatedPages.keys());\n const pagePathForDirectory = (logicalPath: string): string => {\n const pageName = generatedPages.get(logicalPath);\n return pageName === undefined || pageName === \"index.html\"\n ? logicalPath\n : path.posix.join(logicalPath, pageName);\n };\n const sourceKinds = new Map<string, string>();\n for (const { directory } of plans)\n for (const entry of directory.entries) {\n const sourcePath = path.relative(sourceDir, entry.absolutePath).split(path.sep).join(\"/\");\n if (selection.selected.has(sourcePath)) sourceKinds.set(sourcePath, entry.kind);\n }\n const metadataResolver = await options.metadata?.({ sourceDir, sourceKinds });\n const sharedAssets = new Map<string, string | Uint8Array>();\n const rawLinkFiles = new Map<string, string>();\n const searchEntries = new Map<\n string,\n {\n href: string | null;\n exitsExplorer: boolean;\n isLink: boolean;\n kind: EntryKind;\n modifiedAt: string;\n name: string;\n path: string;\n size: number;\n target: string | null;\n targetKind: Exclude<EntryKind, \"symlink\"> | null;\n targetSize: number | null;\n isTargetUnavailable: boolean;\n isCycle: boolean;\n }\n >();\n\n for (const { directory, logicalDir } of theme.searchIndex === false ? [] : plans) {\n for (const entry of directory.entries) {\n if (searchEntries.has(entry.relativePath)) continue;\n const targetLogicalPath = isUnavailableSymlink(entry)\n ? null\n : entry.symlink?.targetRelativePath !== null && entry.symlink !== null\n ? entry.symlink.targetRelativePath\n : path.posix.join(logicalDir, entry.name);\n const directoryLike = isDirectoryLike(entry);\n const linkedPath =\n directoryLike && targetLogicalPath !== null\n ? pagePathForDirectory(targetLogicalPath)\n : targetLogicalPath;\n let href: string | null = null;\n if (entry.symlink !== null && isUnavailableSymlink(entry)) {\n const filename = rawLinkFilename(entry);\n rawLinkFiles.set(filename, entry.symlink.target);\n href = `raw-links/${filename}`;\n } else if (linkedPath !== null) {\n href =\n linkedPath === \"\"\n ? \"../\"\n : `../${encodeLogicalPath(linkedPath)}${directoryLike && linkedPath === targetLogicalPath ? \"/\" : \"\"}`;\n }\n searchEntries.set(entry.relativePath, {\n exitsExplorer:\n isUnavailableSymlink(entry) ||\n (targetLogicalPath !== null &&\n (!directoryLike || !generatedDirectories.has(targetLogicalPath))),\n href,\n isLink: entry.kind === \"symlink\",\n kind: entry.kind,\n modifiedAt: entry.metadata.times.modifiedAt,\n name: entry.name,\n path: entry.relativePath,\n size: entry.metadata.size,\n target: entry.symlink?.target ?? null,\n targetKind: entry.symlink?.targetKind ?? null,\n targetSize: entry.symlink?.targetSize ?? null,\n isTargetUnavailable: isUnavailableSymlink(entry),\n isCycle: entry.symlink?.isCycle ?? false,\n });\n }\n }\n\n for (const plan of plans) {\n const { directory, logicalDir, outputName: name } = plan;\n const sourceEntryNames = new Set(directory.entries.map((entry) => entry.name.toLowerCase()));\n if (name === null) continue;\n\n const targetLogicalPathFor = (entry: FileSystemEntry): string | null => {\n if (isUnavailableSymlink(entry)) return null;\n if (entry.symlink?.targetRelativePath !== null && entry.symlink !== null) {\n return entry.symlink.targetRelativePath;\n }\n return path.posix.join(logicalDir, entry.name);\n };\n const hrefForLogicalPath = (targetPath: string, directoryLike: boolean): string => {\n const linkedPath = directoryLike ? pagePathForDirectory(targetPath) : targetPath;\n const linkToDirectory = directoryLike && linkedPath === targetPath;\n if (urlStrategy === \"relative\") {\n const relativeTarget = path.posix.relative(\n logicalDir === \"\" ? \".\" : logicalDir,\n linkedPath === \"\" ? \".\" : linkedPath,\n );\n const encodedTarget = relativeTarget\n .split(\"/\")\n .map((segment) =>\n segment === \".\" || segment === \"..\" ? segment : encodeURIComponent(segment),\n )\n .join(\"/\");\n return `${encodedTarget || \".\"}${linkToDirectory ? \"/\" : \"\"}`;\n }\n const encodedTarget = encodeLogicalPath(linkedPath);\n if (encodedTarget === \"\") {\n return urlStrategy === \"base\" ? base : \"./\";\n }\n const suffix = `${encodedTarget}${linkToDirectory ? \"/\" : \"\"}`;\n return urlStrategy === \"base\" ? `${base}${suffix}` : suffix;\n };\n const hrefFor = (entry: FileSystemEntry): string | null => {\n if (entry.symlink !== null && isUnavailableSymlink(entry)) {\n const filename = rawLinkFilename(entry);\n rawLinkFiles.set(filename, entry.symlink.target);\n return hrefForLogicalPath(path.posix.join(\"__dirwell\", \"raw-links\", filename), false);\n }\n const targetLogicalPath = targetLogicalPathFor(entry);\n if (targetLogicalPath === null) return null;\n const directoryLike =\n entry.kind === \"directory\" || entry.symlink?.targetKind === \"directory\";\n return hrefForLogicalPath(targetLogicalPath, directoryLike);\n };\n const baseContext: ThemeContext = {\n operation: \"build\",\n directory,\n documentBaseHref: urlStrategy === \"html-base\" ? base : null,\n outputName: name,\n mode,\n searchIndexHref: hrefForLogicalPath(\n path.posix.join(\"__dirwell\", \"search-index.json\"),\n false,\n ),\n sort: { ...defaultSort, ...options.sort },\n assetHref: (assetName) => {\n assertSafeOutputName(assetName);\n return hrefForLogicalPath(\n mode === \"ssg\"\n ? path.posix.join(logicalDir, assetName)\n : path.posix.join(\"__dirwell\", assetName),\n false,\n );\n },\n hrefFor,\n hrefForDirectory: (relativePath) => hrefForLogicalPath(relativePath, true),\n hasPageForDirectory: (relativePath) => generatedDirectories.has(relativePath),\n exitsExplorerFor: (entry) => {\n if (isUnavailableSymlink(entry)) return true;\n const targetLogicalPath = targetLogicalPathFor(entry);\n const directoryLike =\n entry.kind === \"directory\" || entry.symlink?.targetKind === \"directory\";\n return (\n targetLogicalPath !== null &&\n (!directoryLike || !generatedDirectories.has(targetLogicalPath))\n );\n },\n };\n const targetDir = path.join(buildOutputDir, logicalDir);\n await mkdir(targetDir, { recursive: true });\n const sort = baseContext.sort;\n let revision = \"\";\n let manifestHref = \"\";\n let pageSize = Math.max(1, directory.entries.length);\n if (options.listing !== undefined) {\n const records = directory.entries.map((entry) => {\n const projected = projectListingEntry(entry, baseContext);\n return theme.entryData === undefined\n ? projected\n : {\n ...projected,\n presentation: copyJsonObject(\n theme.entryData(projected, {\n mode: baseContext.mode,\n outputName: baseContext.outputName,\n assetHref: baseContext.assetHref,\n hrefForDirectory: baseContext.hrefForDirectory,\n documentBaseHref: baseContext.documentBaseHref,\n directoryPath: logicalDir,\n }),\n ),\n };\n });\n const candidate =\n typeof options.listing === \"function\"\n ? options.listing({\n directoryPath: logicalDir,\n visibleCount: records.length,\n dataBytes: Buffer.byteLength(JSON.stringify(records)),\n mode,\n operation: \"build\",\n supportsPagination: theme.listing?.pagination === true,\n })\n : options.listing;\n validateListingPlan(candidate);\n if (candidate.html.strategy === \"paged\") {\n if (theme.listing?.pagination !== true)\n throw new Error(`Theme ${theme.name} does not support listing pagination`);\n pageSize = candidate.html.pageSize;\n }\n const directoryId = createHash(\"sha256\").update(logicalDir).digest(\"hex\");\n const manifestDirectory = path.posix.join(\"__dirwell\", \"listing\", directoryId);\n // Relative records belong to the document directory, not to the JSON asset directory.\n const hrefBase =\n urlStrategy === \"relative\"\n ? `../../../${encodeLogicalPath(logicalDir)}${logicalDir ? \"/\" : \"\"}`\n : base;\n const manifestPath = path.posix.join(manifestDirectory, \"manifest.json\");\n manifestHref = hrefForLogicalPath(manifestPath, false);\n const blocks: Array<ListingManifest[\"blocks\"][number]> = [];\n const blockSize =\n candidate.data.strategy === \"blocks\"\n ? candidate.data.blockSize\n : Math.max(1, records.length);\n revision = listingRevision(records, sort, hrefBase, blockSize);\n const outputListingDir = path.join(buildOutputDir, manifestDirectory);\n await mkdir(outputListingDir, { recursive: true });\n for (let offset = 0; offset < records.length || offset === 0; offset += blockSize) {\n const entries = records.slice(offset, offset + blockSize);\n const filename = `${revision}-${blocks.length}.json`;\n blocks.push({ href: filename, offset, count: entries.length });\n await writeFile(\n path.join(outputListingDir, filename),\n JSON.stringify({ version: 1, revision, offset, total: records.length, entries }),\n );\n }\n const manifest: ListingManifest = {\n version: 1,\n revision,\n directory: logicalDir,\n hrefBase,\n total: records.length,\n sort,\n blocks,\n };\n await writeFile(path.join(outputListingDir, \"manifest.json\"), JSON.stringify(manifest));\n }\n const pageCount = Math.max(1, Math.ceil(directory.entries.length / pageSize));\n const pagePrefix = `__dirwell-page-${createHash(\"sha256\").update(name).digest(\"hex\").slice(0, 16)}`;\n const pageNames = Array.from({ length: pageCount }, (_, index) =>\n index === 0 ? name : `${pagePrefix}-${index + 1}.html`,\n );\n for (const pageName of pageNames.slice(1)) {\n if (directory.entries.some((entry) => entry.name.toLowerCase() === pageName.toLowerCase()))\n throw new Error(\n `Listing page conflicts with source entry: ${path.posix.join(logicalDir, pageName)}`,\n );\n }\n const pagedAssets = new Map<string, Buffer>();\n for (const [index, pageName] of pageNames.entries()) {\n const pagePath = path.posix.join(logicalDir, pageName);\n const metadata = await metadataResolver?.resolve(\n directory,\n (outputPath) => hrefForLogicalPath(outputPath, false),\n pageName === \"index.html\" ? (logicalDir ? `${logicalDir}/` : \"\") : pagePath,\n );\n const pageHref = (number: number): string =>\n hrefForLogicalPath(path.posix.join(logicalDir, pageNames[number] ?? name), false);\n const page = await theme.render({\n ...baseContext,\n ...(metadata === undefined ? {} : { metadata }),\n outputName: pageName,\n directory:\n options.listing === undefined\n ? directory\n : {\n ...directory,\n entries: directory.entries.slice(index * pageSize, (index + 1) * pageSize),\n },\n ...(options.listing === undefined\n ? {}\n : {\n listing: {\n revision,\n manifestHref,\n page: {\n number: index + 1,\n count: pageCount,\n offset: index * pageSize,\n total: directory.entries.length,\n href: pageHref(index),\n previousHref: index === 0 ? null : pageHref(index - 1),\n nextHref: index + 1 === pageCount ? null : pageHref(index + 1),\n },\n },\n }),\n });\n await writeFile(path.join(targetDir, pageName), page.html);\n for (const [assetName, contents] of Object.entries(page.assets ?? {})) {\n assertSafeOutputName(assetName);\n if (\n (options.listing !== undefined || theme.listing?.pagination === true) &&\n mode === \"ssg\" &&\n sourceEntryNames.has(assetName.toLowerCase())\n )\n throw new Error(`Theme asset conflicts with source entry: ${assetName}`);\n if (\n options.listing !== undefined &&\n pageNames.some((pageName) => pageName.toLowerCase() === assetName.toLowerCase())\n )\n throw new Error(`Theme asset conflicts with listing page: ${assetName}`);\n if (options.listing !== undefined && pageCount > 1) {\n const bytes = Buffer.from(contents);\n const existing = pagedAssets.get(assetName);\n if (existing !== undefined && !existing.equals(bytes))\n throw new Error(`Theme emitted conflicting paginated asset: ${assetName}`);\n pagedAssets.set(assetName, bytes);\n }\n if (mode === \"ssg\") {\n await writeFile(path.join(targetDir, assetName), contents);\n } else {\n const bytes = Buffer.from(contents);\n const existing = sharedAssets.get(assetName);\n if (existing !== undefined && !Buffer.from(existing).equals(bytes)) {\n throw new Error(`Theme emitted conflicting shared asset: ${assetName}`);\n }\n sharedAssets.set(assetName, bytes);\n }\n }\n }\n }\n\n if (mode === \"mpa\" && sharedAssets.size > 0) {\n const assetDirectory = path.join(buildOutputDir, \"__dirwell\");\n await mkdir(assetDirectory, { recursive: true });\n for (const [assetName, contents] of sharedAssets) {\n await writeFile(path.join(assetDirectory, assetName), contents);\n }\n }\n\n for (const [filename, bytes] of metadataResolver?.assets ?? []) {\n const parts = filename.split(\"/\");\n for (let index = 1; index <= parts.length; index++) {\n const prefix = parts.slice(0, index).join(\"/\");\n if (selection.selected.has(prefix))\n throw new Error(`Metadata image conflicts with source entry: ${filename}`);\n const candidate = path.join(buildOutputDir, prefix);\n try {\n const info = await lstat(candidate);\n if (info.isSymbolicLink() || index === parts.length || !info.isDirectory())\n throw new Error(`Metadata image conflicts with generated output: ${filename}`);\n } catch (error) {\n if (!(error instanceof Error && \"code\" in error && error.code === \"ENOENT\")) throw error;\n }\n }\n const destination = path.join(buildOutputDir, filename);\n await mkdir(path.dirname(destination), { recursive: true });\n await writeFile(destination, bytes);\n }\n\n if (rawLinkFiles.size > 0) {\n const rawLinkDirectory = path.join(buildOutputDir, \"__dirwell\", \"raw-links\");\n await mkdir(rawLinkDirectory, { recursive: true });\n for (const [filename, target] of rawLinkFiles) {\n await writeFile(path.join(rawLinkDirectory, filename), target);\n }\n }\n if (theme.searchIndex !== false) {\n const generatedAssetDirectory = path.join(buildOutputDir, \"__dirwell\");\n await mkdir(generatedAssetDirectory, { recursive: true });\n const indexedEntries = [...searchEntries.values()];\n const shards: string[] = [];\n for (let offset = 0; offset < indexedEntries.length; offset += 512) {\n const filename = `search-${String(shards.length).padStart(5, \"0\")}.json`;\n shards.push(filename);\n await writeFile(\n path.join(generatedAssetDirectory, filename),\n JSON.stringify({ entries: indexedEntries.slice(offset, offset + 512) }),\n );\n }\n await writeFile(\n path.join(generatedAssetDirectory, \"search-index.json\"),\n JSON.stringify({ count: indexedEntries.length, shards, version: 3 }),\n );\n }\n\n await rm(outputDir, { recursive: true, force: true });\n await mkdir(path.dirname(outputDir), { recursive: true });\n await rename(stagedOutputDir, outputDir);\n } finally {\n await rm(stagedOutputDir, { recursive: true, force: true });\n }\n}\n\nexport async function readGeneratedPage(filePath: string): Promise<string> {\n return readFile(filePath, \"utf8\");\n}\n","/** Escape untrusted text for HTML/XML text nodes and double-quoted attributes. */\nexport function escapeHtml(value: string): string {\n return value\n .replaceAll(\"&\", \"&\")\n .replaceAll(\"<\", \"<\")\n .replaceAll(\">\", \">\")\n .replaceAll('\"', \""\");\n}\n","/** Some Windows Node/libuv versions omit the path-stat device ID but retain the file ID. */\nexport function fileIdentityMatches(\n before: { readonly device: number; readonly inode: number },\n descriptor: { readonly dev: number; readonly ino: number },\n platform = process.platform,\n): boolean {\n if (before.inode !== descriptor.ino) return false;\n if (before.device === descriptor.dev) return true;\n return platform === \"win32\" && before.device === 0 && before.inode !== 0;\n}\n","import { readdir, realpath, open, type FileHandle } from \"node:fs/promises\";\nimport { constants } from \"node:fs\";\nimport { fileIdentityMatches } from \"./file-identity.ts\";\nimport path from \"node:path\";\nimport { describeEntry, isInsideRoot } from \"./filesystem.ts\";\nimport { selectSourcePaths } from \"./filters.ts\";\nimport { compareEntries } from \"./generator.ts\";\nimport type { DirectoryData, FileSystemEntry, SortOptions } from \"./model.ts\";\n\nexport interface DirectoryServiceOptions {\n readonly root: string;\n readonly include?: string | readonly string[];\n readonly exclude?: string | readonly string[];\n readonly sort?: SortOptions;\n}\nexport interface DirectoryService {\n readonly resolvePath: (logicalPath: string) => Promise<string>;\n readonly openFile: (logicalPath: string) => Promise<{\n readonly entry: FileSystemEntry;\n readonly handle: FileHandle;\n readonly canonicalPath: string;\n }>;\n readonly getEntry: (logicalPath: string) => Promise<FileSystemEntry>;\n readonly listDirectory: (logicalPath: string) => Promise<DirectoryData>;\n}\nexport class DirectoryAccessError extends Error {\n override readonly name = \"DirectoryAccessError\";\n}\nfunction assertLogicalPath(value: string): void {\n if (\n value.startsWith(\"/\") ||\n value.includes(\"\\\\\") ||\n value.includes(\"\\0\") ||\n value\n .split(\"/\")\n .some((segment) => segment === \".\" || segment === \"..\" || (segment === \"\" && value !== \"\")) ||\n /^[a-z]:/i.test(value) ||\n value === \"__dirwell\" ||\n value.startsWith(\"__dirwell/\")\n )\n throw new DirectoryAccessError(\"Unavailable path\");\n}\n/** Live reads; no watcher, recursive stat snapshot, output tree or implicit cache. */\nexport async function createDirectoryService(\n options: DirectoryServiceOptions,\n): Promise<DirectoryService> {\n const root = await realpath(options.root);\n const selected = async () =>\n options.include === undefined && options.exclude === undefined\n ? null\n : (\n await selectSourcePaths(\n root,\n path.join(root, \"__dirwell\"),\n options.include,\n options.exclude,\n )\n ).selected;\n async function describe(\n logicalPath: string,\n selection: ReadonlySet<string> | null,\n ): Promise<FileSystemEntry> {\n assertLogicalPath(logicalPath);\n if (selection !== null && !selection.has(logicalPath))\n throw new DirectoryAccessError(\"Unavailable path\");\n const absolutePath = path.join(root, logicalPath);\n const parent = logicalPath === \"\" ? root : await realpath(path.dirname(absolutePath));\n if (!isInsideRoot(root, parent)) throw new DirectoryAccessError(\"Unavailable path\");\n const ancestors = new Set<string>([root]);\n if (logicalPath !== \"\") {\n const segments = logicalPath.split(\"/\").slice(0, -1);\n for (let length = 1; length <= segments.length; length++)\n ancestors.add(await realpath(path.join(root, ...segments.slice(0, length))));\n }\n return describeEntry({\n absolutePath,\n relativePath: logicalPath,\n rootRealPath: root,\n ancestors,\n followSymlinks: false,\n selectedPaths: selection,\n });\n }\n return {\n async resolvePath(logicalPath) {\n const selection = await selected();\n const entry = await describe(logicalPath, selection);\n if (\n entry.symlink &&\n (entry.symlink.isBroken || entry.symlink.isOutsideRoot || entry.symlink.isTargetExcluded)\n )\n throw new DirectoryAccessError(\"Unavailable target\");\n const resolved = await realpath(entry.absolutePath);\n if (!isInsideRoot(root, resolved)) throw new DirectoryAccessError(\"Unavailable target\");\n const canonical = path.relative(root, resolved).split(path.sep).join(\"/\");\n if (selection !== null && !selection.has(canonical))\n throw new DirectoryAccessError(\"Unavailable target\");\n return canonical;\n },\n async openFile(logicalPath) {\n assertLogicalPath(logicalPath);\n const selection = await selected();\n let entry = await describe(logicalPath, selection);\n if (entry.symlink !== null) {\n if (\n entry.symlink.isBroken ||\n entry.symlink.isOutsideRoot ||\n entry.symlink.isTargetExcluded ||\n entry.symlink.targetRelativePath === null\n )\n throw new DirectoryAccessError(\"Unavailable file\");\n entry = await describe(entry.symlink.targetRelativePath, selection);\n }\n if (entry.kind !== \"file\") throw new DirectoryAccessError(\"Unavailable file\");\n const handle = await open(\n entry.absolutePath,\n constants.O_RDONLY | (constants.O_NOFOLLOW ?? 0),\n );\n try {\n const stats = await handle.stat();\n const resolved = await realpath(entry.absolutePath);\n if (\n !stats.isFile() ||\n !isInsideRoot(root, resolved) ||\n !fileIdentityMatches(entry.metadata, stats)\n )\n throw new DirectoryAccessError(\"File changed before opening\");\n return {\n entry,\n handle,\n canonicalPath: path.relative(root, resolved).split(path.sep).join(\"/\"),\n };\n } catch (error) {\n await handle.close();\n throw error;\n }\n },\n async getEntry(logicalPath) {\n assertLogicalPath(logicalPath);\n return describe(logicalPath, await selected());\n },\n async listDirectory(logicalPath) {\n assertLogicalPath(logicalPath);\n const selection = await selected();\n const entry = await describe(logicalPath, selection);\n if (entry.kind !== \"directory\") throw new DirectoryAccessError(\"Unavailable directory\");\n const physical = await realpath(entry.absolutePath);\n if (!isInsideRoot(root, physical)) throw new DirectoryAccessError(\"Unavailable directory\");\n const names = (await readdir(physical)).filter(\n (name) => logicalPath !== \"\" || name !== \"__dirwell\",\n );\n const described = await Promise.all(\n names\n .filter((name) => selection === null || selection.has(path.posix.join(logicalPath, name)))\n .map(async (name) => {\n try {\n return await describe(path.posix.join(logicalPath, name), selection);\n } catch (error) {\n // An enumerated child may disappear before stat; the directory is still available.\n if (error instanceof Error && \"code\" in error && error.code === \"ENOENT\") return null;\n throw error;\n }\n }),\n );\n const entries = described.filter((entry): entry is FileSystemEntry => entry !== null);\n entries.sort(\n (left, right) =>\n compareEntries(left, right, options.sort) ||\n (left.relativePath < right.relativePath\n ? -1\n : left.relativePath > right.relativePath\n ? 1\n : 0),\n );\n return {\n root: await describe(\"\", selection),\n current: { ...entry, kind: \"directory\" },\n parent:\n logicalPath === \"\"\n ? null\n : await describe(\n path.posix.dirname(logicalPath) === \".\" ? \"\" : path.posix.dirname(logicalPath),\n selection,\n ),\n depth: logicalPath === \"\" ? 0 : logicalPath.split(\"/\").length,\n entries,\n };\n },\n };\n}\n"],"mappings":"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"}
|