@topik/core 0.1.0-alpha.6 → 0.1.0-alpha.7

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.
@@ -1,6 +1,6 @@
1
- import { a as resolveDeclaredSourcePage, i as resolveDeclaredPublicRoute, n as hasDeclaredFolder, o as resolveNavigationPath, r as isFolderHref } from "./folder-links-DI4xfipU.mjs";
1
+ import { a as resolveDeclaredSourcePage, i as resolveDeclaredPublicRoute, n as hasDeclaredFolder, o as resolveNavigationPath, r as isFolderHref } from "./folder-links-jLZaG6xi.mjs";
2
2
  import { parseTopikResourceReference } from "@topik/content";
3
- //#region src/assets/constants.ts
3
+ // src/assets/constants.ts
4
4
  const ASSET_API_VERSION = "v1";
5
5
  const ASSET_TYPE = "Asset";
6
6
  const ASSET_SCHEMA_ID = "https://topik.dev/schemas/asset/v1.json";
@@ -30,8 +30,7 @@ const TOPIK_ASSET_LIMITS = {
30
30
  maxComponents: 64,
31
31
  maxRepositoryPathUtf8Bytes: 768
32
32
  };
33
- //#endregion
34
- //#region src/assets/nfkc-casefold-v17.ts
33
+ // src/assets/nfkc-casefold-v17.ts
35
34
  /** Unicode 17.0.0 NFKC_CF data from DerivedNormalizationProps.txt.
36
35
  * Source SHA-256: 71fd6a206a2c0cdd41feb6b7f656aa31091db45e9cedc926985d718397f9e488
37
36
  */
@@ -112,8 +111,7 @@ const NFKC_CASEFOLD_V17_DATA = [
112
111
  "13e;2f986=5ab5;2f987=267a7;2f988=267b5;2f989=23393;2f98a=2339c;2f98b=8201;2f98c=8204;2f98d=8f9e;2f98e=446b;2f98f=8291;2f990=828b;2f991=829d;2f992=52b3;2f993=82b1;2f994=82b3;2f995=82bd;2f996=82e6;2f997=26b3c;2f998=82e5;2f999=831d;2f99a=8363;2f99b=83ad;2f99c=8323;2f99d=83bd;2f99e=83e7;2f99f=8457;2f9a0=8353;2f9a1=83ca;2f9a2=83cc;2f9a3=83dc;2f9a4=26c36;2f9a5=26d6b;2f9a6=26cd5;2f9a7=452b;2f9a8=84f1;2f9a9=84f3;2f9aa=8516;2f9ab=273ca;2f9ac=8564;2f9ad=26f2c;2f9ae=455d;2f9af=4561;2f9b0=26fb1;2f9b1=270d2;2f9b2=456b;2f9b3=8650;2f9b4=865c;2f9b5=8667;2f9b6=8669;2f9b7=86a9;2f9b8=8688;2f9b9=870e;2f9ba=86e2;2f9bb=8779;2f9bc=8728;2f9bd=876b;2f9be=8786;2f9bf=45d7;2f9c0=87e1;2f9c1=8801;2f9c2=45f9;2f9c3=8860;2f9c4=8863;2f9c5=27667;2f9c6=88d7;2f9c7=88de;2f9c8=4635;2f9c9=88fa;2f9ca=34bb;2f9cb=278ae;2f9cc=27966;2f9cd=46be;2f9ce=46c7;2f9cf=8aa0;2f9d0=8aed;2f9d1=8b8a;2f9d2=8c55;2f9d3=27ca8;2f9d4=8cab;2f9d5=8cc1;2f9d6=8d1b;2f9d7=8d77;2f9d8=27f2f;2f9d9=20804;2f9da=8dcb;2f9db=8dbc;2f9dc=8df0;2f9dd=208de;2f9de=8ed",
113
112
  "4;2f9df=8f38;2f9e0=285d2;2f9e1=285ed;2f9e2=9094;2f9e3=90f1;2f9e4=9111;2f9e5=2872e;2f9e6=911b;2f9e7=9238;2f9e8=92d7;2f9e9=92d8;2f9ea=927c;2f9eb=93f9;2f9ec=9415;2f9ed=28bfa;2f9ee=958b;2f9ef=4995;2f9f0=95b7;2f9f1=28d77;2f9f2=49e6;2f9f3=96c3;2f9f4=5db2;2f9f5=9723;2f9f6=29145;2f9f7=2921a;2f9f8=4a6e;2f9f9=4a76;2f9fa=97e0;2f9fb=2940a;2f9fc=4ab2;2f9fd=29496;2f9fe..2f9ff=980b;2fa00=9829;2fa01=295b6;2fa02=98e2;2fa03=4b33;2fa04=9929;2fa05=99a7;2fa06=99c2;2fa07=99fe;2fa08=4bce;2fa09=29b30;2fa0a=9b12;2fa0b=9c40;2fa0c=9cfd;2fa0d=4cce;2fa0e=4ced;2fa0f=9d67;2fa10=2a0ce;2fa11=4cf8;2fa12=2a105;2fa13=2a20e;2fa14=2a291;2fa15=9ebb;2fa16=4d56;2fa17=9ef9;2fa18=9efe;2fa19=9f05;2fa1a=9f0f;2fa1b=9f16;2fa1c=9f3b;2fa1d=2a600;e0000=;e0001=;e0002..e001f=;e0020..e007f=;e0080..e00ff=;e0100..e01ef=;e01f0..e0fff="
114
113
  ].join("");
115
- //#endregion
116
- //#region src/assets/path-unicode-v17.ts
114
+ // src/assets/path-unicode-v17.ts
117
115
  /**
118
116
  * Unicode 17 path-forbidden code points, encoded as inclusive hexadecimal ranges.
119
117
  *
@@ -175,8 +173,7 @@ function isCodePointInRanges(codePoint, ranges) {
175
173
  }
176
174
  return false;
177
175
  }
178
- //#endregion
179
- //#region src/assets/diagnostics.ts
176
+ // src/assets/diagnostics.ts
180
177
  const TOPIK_ASSET_DIAGNOSTIC_IDS = [
181
178
  "TOPIK_ASSET_UNSUPPORTED_VERSION",
182
179
  "TOPIK_ASSET_DUPLICATE_MEMBER",
@@ -289,8 +286,7 @@ function containsUnsafeDiagnosticUnicode(value) {
289
286
  }
290
287
  return false;
291
288
  }
292
- //#endregion
293
- //#region src/assets/path.ts
289
+ // src/assets/path.ts
294
290
  const encoder = new TextEncoder();
295
291
  const decoder = new TextDecoder("utf-8", { fatal: true });
296
292
  const FORBIDDEN_ASCII = /[\\%<>:"|?*]/u;
@@ -436,8 +432,7 @@ function parseNfkcCasefoldData(source) {
436
432
  }
437
433
  return mapping;
438
434
  }
439
- //#endregion
440
- //#region src/course-navigation.ts
435
+ // src/course-navigation.ts
441
436
  const INTERNAL_COURSE_ORIGIN = "https://topik.invalid";
442
437
  const RESOURCE_NAME = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
443
438
  function isName(value) {
@@ -554,5 +549,4 @@ function resolveCourseContentHref(href, currentPageName, resolved) {
554
549
  search: url.search
555
550
  } : null;
556
551
  }
557
- //#endregion
558
552
  export { TOPIK_JSON_VERSION as C, TOPIK_PATH_VERSION as E, TOPIK_BLOB_OUTPUT_PREFIX as S, TOPIK_PATH_V1_DESCRIPTOR as T, ASSET_SCHEMA_ID as _, computeTopikPathCollisionKey as a, TOPIK_ASSET_NAME_VERSION as b, validateTopikPathSet as c, TOPIK_ASSET_DIAGNOSTIC_IDS as d, correlateTopikAssetResult as f, ASSET_API_VERSION as g, isTopikPathNormalizationSensitiveV17 as h, validateCoursePageSources as i, TOPIK_ASSET_CORRELATION_ID_PATTERN as l, isTopikPathCodePointForbiddenV17 as m, resolveCourseContentReference as n, toNfkcCasefold as o, topikAssetDiagnostic as p, resolveCourseNavigation as r, validateTopikPath as s, resolveCourseContentHref as t, TOPIK_ASSET_DEFAULT_CORRELATION_ID as u, ASSET_TYPE as v, TOPIK_MATERIALIZATION_VERSION as w, TOPIK_ASSET_REFERENCE_VERSION as x, TOPIK_ASSET_LIMITS as y };
@@ -1,4 +1,3 @@
1
- //#region src/course-navigation.d.ts
2
1
  /** @internal Logical page sources become Markdown files and must agree on directory spelling. */
3
2
  export declare function validateCoursePageSources(paths: readonly string[]): boolean;
4
3
  /** Portable reference context for one Course, independent of filesystem access. */
@@ -48,5 +47,4 @@ export type ResolvedCourseContentReference = {
48
47
  export declare function resolveCourseNavigation(context: CourseReferenceContext): ResolvedCourseNavigation;
49
48
  export declare function resolveCourseContentReference(href: string, currentPageName: string, resolved: ResolvedCourseNavigation): ResolvedCourseContentReference;
50
49
  /** Resolve relative source references or root-relative public routes without guessing files. */
51
- export declare function resolveCourseContentHref(href: string, currentPageName: string, resolved: ResolvedCourseNavigation): ResolvedCourseContentLink | null;
52
- //#endregion
50
+ export declare function resolveCourseContentHref(href: string, currentPageName: string, resolved: ResolvedCourseNavigation): ResolvedCourseContentLink | null;
@@ -1 +1 @@
1
- export { t as resolveCourseContentHref, n as resolveCourseContentReference, r as resolveCourseNavigation, i as validateCoursePageSources } from "./course-navigation-CWlVc0a0.mjs";
1
+ export { t as resolveCourseContentHref, n as resolveCourseContentReference, r as resolveCourseNavigation, i as validateCoursePageSources } from "./course-navigation-h54ccuqO.mjs";
@@ -1,4 +1,4 @@
1
- //#region src/folder-links.ts
1
+ // src/folder-links.ts
2
2
  /** Resolve decoded source paths consistently without URL root-clamping or Node-only APIs. */
3
3
  function resolveNavigationPath(href, sourcePath, directory = "") {
4
4
  if (/^[a-z][a-z0-9+.-]*:/i.test(href) || href.startsWith("//")) return void 0;
@@ -45,13 +45,13 @@ function resolveDeclaredSourcePage(path, pages, folder = false) {
45
45
  const candidates = folderLandingCandidates(path, pages);
46
46
  return candidates.length === 1 ? candidates[0] : void 0;
47
47
  }
48
- /** Wiki's index aliases are public routes in every consumer, including compilation. */
48
+ /** Exact public routes take precedence over Wiki's fallback index aliases. */
49
49
  function resolveDeclaredPublicRoute(href, pages, wiki = false) {
50
50
  if (!href.startsWith("/") || isFolderHref(href)) return void 0;
51
51
  const path = resolveNavigationPath(href, "");
52
52
  if (path === void 0 || /\.(?:mdx?|markdown)$/i.test(path)) return void 0;
53
+ if (pages.has(path)) return pages.get(path);
53
54
  const route = wiki ? path === "index" ? "" : path.replace(/\/index$/, "") : path;
54
55
  return pages.get(route);
55
56
  }
56
- //#endregion
57
57
  export { resolveDeclaredSourcePage as a, resolveDeclaredPublicRoute as i, hasDeclaredFolder as n, resolveNavigationPath as o, isFolderHref as r, folderLandingCandidates as t };
package/dist/index.d.mts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { CourseReferenceContext, ResolvedCourseContentLink, ResolvedCourseContentReference, ResolvedCourseNavigation, ResolvedCoursePage, resolveCourseContentHref, resolveCourseContentReference, resolveCourseNavigation } from "./course-navigation.mjs";
2
- import { $ as TopikAssetPathDiagnosticReason, A as AssetBlobUri, B as parseGeneratedAssetName, C as TopikMaterializationResourceV1, D as digestTopikAssetSemanticRecord, E as createTopikMaterializationRecord, F as generateAutomaticAssetName, G as validateProjectNamespace, H as topikAssetNameDescriptor, I as isAssetBlobUri, J as TOPIK_ASSET_DIAGNOSTIC_IDS, K as TOPIK_ASSET_CORRELATION_ID_PATTERN, L as isGeneratedAssetName, M as GenerateAutomaticAssetNameOptions, N as GeneratedAssetName, O as digestTopikMaterializationRecord, P as ParsedAsset, Q as TopikAssetDiagnosticLocation, R as parseAsset, S as TopikMaterializationResourceInput, T as createTopikAssetSemanticRecord, U as validateAssetBlobUri, V as serializeAsset, W as validateAssetValue, X as TopikAssetDiagnostic, Y as TopikAssetCorrelationId, Z as TopikAssetDiagnosticId, _ as TopikAssetReferenceMappingV1, a as PreviewState, at as ASSET_TYPE, b as TopikMaterializationPayloadV1, c as AssetCompilationOptions, ct as TOPIK_ASSET_REFERENCE_VERSION, d as AssetNameInput, dt as TOPIK_MATERIALIZATION_VERSION, et as TopikAssetRecoveryCategory, f as AssetPayload, ft as TOPIK_PATH_V1_DESCRIPTOR, g as compileAssetResources, gt as SourceResource, h as ContentBearingResource, ht as ResourceType, i as PreviewPayloadDescriptor, it as ASSET_SCHEMA_ID, j as CompiledAsset, k as validateTopikMaterializationRecord, l as AssetCompilationResult, lt as TOPIK_BLOB_OUTPUT_PREFIX, m as CompiledResource, mt as Resource, n as CourseNavigationModule, nt as correlateTopikAssetResult, o as TOPIK_PREVIEW_PROTOCOL, ot as TOPIK_ASSET_LIMITS, p as CompileAssetResourcesInput, pt as TOPIK_PATH_VERSION, q as TOPIK_ASSET_DEFAULT_CORRELATION_ID, r as PreviewDiagnostic, rt as ASSET_API_VERSION, s as AssetCompilationError, st as TOPIK_ASSET_NAME_VERSION, t as CourseNavigationIndex, tt as TopikAssetResult, u as AssetNameGenerator, ut as TOPIK_JSON_VERSION, v as TopikAssetSemanticRecordV1, w as compareTopikAssetIdentities, x as TopikMaterializationRecordV1, y as TopikMaterializationPayloadInput, z as parseAssetBlobUri } from "./preview-C_3OnNUi.mjs";
2
+ import { $ as TopikAssetPathDiagnosticReason, A as AssetBlobUri, B as parseGeneratedAssetName, C as TopikMaterializationResourceV1, D as digestTopikAssetSemanticRecord, E as createTopikMaterializationRecord, F as generateAutomaticAssetName, G as validateProjectNamespace, H as topikAssetNameDescriptor, I as isAssetBlobUri, J as TOPIK_ASSET_DIAGNOSTIC_IDS, K as TOPIK_ASSET_CORRELATION_ID_PATTERN, L as isGeneratedAssetName, M as GenerateAutomaticAssetNameOptions, N as GeneratedAssetName, O as digestTopikMaterializationRecord, P as ParsedAsset, Q as TopikAssetDiagnosticLocation, R as parseAsset, S as TopikMaterializationResourceInput, T as createTopikAssetSemanticRecord, U as validateAssetBlobUri, V as serializeAsset, W as validateAssetValue, X as TopikAssetDiagnostic, Y as TopikAssetCorrelationId, Z as TopikAssetDiagnosticId, _ as TopikAssetReferenceMappingV1, a as PreviewState, at as ASSET_TYPE, b as TopikMaterializationPayloadV1, c as AssetCompilationOptions, ct as TOPIK_ASSET_REFERENCE_VERSION, d as AssetNameInput, dt as TOPIK_MATERIALIZATION_VERSION, et as TopikAssetRecoveryCategory, f as AssetPayload, ft as TOPIK_PATH_V1_DESCRIPTOR, g as compileAssetResources, gt as SourceResource, h as ContentBearingResource, ht as ResourceType, i as PreviewPayloadDescriptor, it as ASSET_SCHEMA_ID, j as CompiledAsset, k as validateTopikMaterializationRecord, l as AssetCompilationResult, lt as TOPIK_BLOB_OUTPUT_PREFIX, m as CompiledResource, mt as Resource, n as CourseNavigationModule, nt as correlateTopikAssetResult, o as TOPIK_PREVIEW_PROTOCOL, ot as TOPIK_ASSET_LIMITS, p as CompileAssetResourcesInput, pt as TOPIK_PATH_VERSION, q as TOPIK_ASSET_DEFAULT_CORRELATION_ID, r as PreviewDiagnostic, rt as ASSET_API_VERSION, s as AssetCompilationError, st as TOPIK_ASSET_NAME_VERSION, t as CourseNavigationIndex, tt as TopikAssetResult, u as AssetNameGenerator, ut as TOPIK_JSON_VERSION, v as TopikAssetSemanticRecordV1, w as compareTopikAssetIdentities, x as TopikMaterializationRecordV1, y as TopikMaterializationPayloadInput, z as parseAssetBlobUri } from "./preview-DfACgOEg.mjs";
3
3
  import { ExternalWikiDropdown, ExternalWikiTab, InternalWikiDropdown, InternalWikiTab, ResolvedWikiContentLink, ResolvedWikiContentReference, ResolvedWikiNavigation, ResolvedWikiPage, WikiSwitcherNode, findFirstWikiPage, findWikiPageAncestors, hasWikiNavChildren, isExternalWikiDropdown, isExternalWikiTab, isInternalWikiDropdown, isInternalWikiTab, joinWikiPath, resolveWikiContentHref, resolveWikiContentReference, resolveWikiNavigation } from "./wiki-navigation.mjs";
4
4
  import { z } from "zod";
5
5
  import { TopikContentDiagnostic, TopikNavigationReference, TopikResourceReference } from "@topik/content";
@@ -9,11 +9,8 @@ import { CoursePage } from "@topik/schema/course-page/v1";
9
9
  import { Guide } from "@topik/schema/guide/v1";
10
10
  import { Wiki, WikiNavNode } from "@topik/schema/wiki/v1";
11
11
  import { WikiPage } from "@topik/schema/wiki-page/v1";
12
- //#region src/config/source-version.d.ts
13
12
  /** The public resource validator owns Person fields, including future schema additions. */
14
13
  declare function parseSourcePersons(value: unknown): Person[];
15
- //#endregion
16
- //#region src/config/collection.d.ts
17
14
  declare const collectionConfigSchema: z.ZodObject<{
18
15
  id: z.ZodString;
19
16
  title: z.ZodString;
@@ -28,8 +25,6 @@ type CollectionConfig = Omit<z.infer<typeof collectionConfigSchema>, "persons">
28
25
  persons?: ReturnType<typeof parseSourcePersons>;
29
26
  };
30
27
  export declare function parseCollectionConfig(raw: unknown): CollectionConfig;
31
- //#endregion
32
- //#region src/config/wiki.d.ts
33
28
  type WikiPageNavNode$1 = {
34
29
  type: "page";
35
30
  slug: string;
@@ -98,8 +93,6 @@ type WikiConfig = Omit<z.infer<typeof wikiConfigSchema>, "labels"> & {
98
93
  labels?: Record<string, string>;
99
94
  };
100
95
  export declare function parseWikiConfig(raw: unknown): WikiConfig;
101
- //#endregion
102
- //#region src/config/course.d.ts
103
96
  declare const moduleSchema: z.ZodObject<{
104
97
  id: z.ZodString;
105
98
  title: z.ZodString;
@@ -136,8 +129,6 @@ type CourseConfig = Omit<z.infer<typeof courseConfigSchema>, "persons"> & {
136
129
  };
137
130
  type CourseModuleConfig = z.infer<typeof moduleSchema>;
138
131
  export declare function parseCourseConfig(raw: unknown): CourseConfig;
139
- //#endregion
140
- //#region src/config/manifest.d.ts
141
132
  export declare const TOPIK_MANIFEST_FILENAME = ".topik.yaml";
142
133
  export declare const TOPIK_MANIFEST_LIMITS: {
143
134
  readonly maxBytes: 1048576;
@@ -167,16 +158,12 @@ export declare const topikManifestSchema: z.ZodObject<{
167
158
  type TopikManifest = z.infer<typeof topikManifestSchema>;
168
159
  type TopikManifestSource = z.infer<typeof topikManifestSourceSchema>;
169
160
  export declare function parseTopikManifest(raw: unknown): TopikManifest;
170
- //#endregion
171
- //#region src/config/assets.d.ts
172
161
  export declare const DEFAULT_ASSET_DIRECTORY = "_assets";
173
162
  /** Source-local destination for new synced media; not an input scan or compiler output path. */
174
163
  export declare const sourceAssetsConfigSchema: z.ZodObject<{
175
164
  directory: z.ZodDefault<z.ZodString>;
176
165
  }, z.core.$strict>;
177
166
  type SourceAssetsConfig = z.infer<typeof sourceAssetsConfigSchema>;
178
- //#endregion
179
- //#region src/compile/public-errors.d.ts
180
167
  declare const PUBLIC_COMPILE_ERROR_MESSAGES: {
181
168
  readonly "manifest-required": 'Project compilation requires .topik.yaml in the selected directory. Add a manifest such as: {"version":1,"namespace":"owner/project","sources":[{"kind":"wiki","config":"wiki.yaml"}]}';
182
169
  readonly "manifest-invalid": "Root manifest is invalid.";
@@ -207,8 +194,6 @@ export declare class PublicCompileError extends Error {
207
194
  readonly location?: string;
208
195
  constructor(id: PublicCompileErrorId, location?: string);
209
196
  }
210
- //#endregion
211
- //#region src/compile/manifest.d.ts
212
197
  interface ManifestSourceDescriptor extends TopikManifestSource {
213
198
  /** Zero-based declaration index, used only for provenance and diagnostics. */
214
199
  sourceIndex: number;
@@ -236,8 +221,6 @@ export declare function loadTopikManifest(dir: string): Promise<TopikManifest>;
236
221
  export declare function discoverManifestSources(options: CompileOptions): Promise<ManifestSourceDescriptor[]>;
237
222
  /** Compile only declared sources, sharing the existing local compiler and Asset pipeline. */
238
223
  export declare function compileManifest(options: CompileOptions): Promise<ManifestCompileResult>;
239
- //#endregion
240
- //#region src/compile/shared.d.ts
241
224
  interface CompileResult {
242
225
  courseNavigation: CourseNavigationIndex;
243
226
  /** Present for manifest compilation, in declaration order. */
@@ -260,8 +243,6 @@ export declare class CompileError extends Error {
260
243
  constructor(diagnostics: TopikContentDiagnostic[]);
261
244
  }
262
245
  export declare function isErrorDiagnostic(diagnostic: TopikContentDiagnostic): boolean;
263
- //#endregion
264
- //#region src/compile/links.d.ts
265
246
  /** Optional application-provided catalogue; Topik never fetches targets. */
266
247
  interface CompileResourceReferenceTarget {
267
248
  type: TopikResourceReference["type"];
@@ -295,8 +276,6 @@ export declare function compileResourceLinks(input: CompileResourceLinksInput):
295
276
  diagnostics: TopikContentDiagnostic[];
296
277
  references: CompiledResourceReference[];
297
278
  }>;
298
- //#endregion
299
- //#region src/compile/guide.d.ts
300
279
  interface CompileGuidesOptions {
301
280
  dir: string;
302
281
  /** Exact config path relative to dir; content is relative to the config directory. */
@@ -316,8 +295,6 @@ interface CompileResourceDiscovery {
316
295
  consumedSourcePaths: string[];
317
296
  }
318
297
  export declare function compileGuides(options: CompileGuidesOptions): Promise<CompileResult>;
319
- //#endregion
320
- //#region src/compile/discovery.d.ts
321
298
  interface DiscoverResourceOptions {
322
299
  dir: string;
323
300
  /** Exact config path relative to dir; content is relative to its directory. */
@@ -330,8 +307,6 @@ export declare function discoverGuideResources(options: DiscoverResourceOptions)
330
307
  export declare function discoverWikiResources(options: DiscoverResourceOptions): Promise<SourceResourceDiscovery>;
331
308
  /** Read Course membership, metadata and paths without compiling links or Assets. */
332
309
  export declare function discoverCourseResources(options: DiscoverResourceOptions): Promise<SourceResourceDiscovery>;
333
- //#endregion
334
- //#region src/compile/wiki.d.ts
335
310
  interface CompileWikiOptions {
336
311
  dir: string;
337
312
  /** Exact config path relative to dir; content is relative to the config directory. */
@@ -342,8 +317,6 @@ interface CompileWikiOptions {
342
317
  }
343
318
  export declare function compileWiki(options: CompileWikiOptions): Promise<CompileResult>;
344
319
  export declare function pagePathToName(wikiId: string, pagePath: string): string;
345
- //#endregion
346
- //#region src/compile/course.d.ts
347
320
  interface CompileCourseOptions {
348
321
  dir: string;
349
322
  /** Exact configuration path relative to dir; page sources are relative to its directory. */
@@ -353,8 +326,6 @@ interface CompileCourseOptions {
353
326
  referenceTargets?: readonly CompileResourceReferenceTarget[];
354
327
  }
355
328
  export declare function compileCourse(options: CompileCourseOptions): Promise<CompileResult>;
356
- //#endregion
357
- //#region src/compile/asset-names.d.ts
358
329
  interface ProjectAssetNameOptions {
359
330
  /** Directory containing the manifest, or an explicitly chosen root for standalone use. */
360
331
  projectRoot: string;
@@ -362,8 +333,6 @@ interface ProjectAssetNameOptions {
362
333
  }
363
334
  /** Create the project's naming policy without reading or requiring a manifest. */
364
335
  export declare function createProjectAssetNameGenerator(options: ProjectAssetNameOptions): AssetNameGenerator;
365
- //#endregion
366
- //#region src/compile/index.d.ts
367
336
  interface CompileOptions {
368
337
  dir: string;
369
338
  validation?: CompileValidationOptions;
@@ -376,8 +345,6 @@ interface LintResult {
376
345
  diagnostics: CompileResult["diagnostics"];
377
346
  }
378
347
  export declare function lint(options: CompileOptions): Promise<LintResult>;
379
- //#endregion
380
- //#region src/validate.d.ts
381
348
  interface ValidationError {
382
349
  id?: "resource-invalid" | "resource-unsupported-type" | "resource-unsupported-version" | TopikAssetDiagnosticId;
383
350
  resource: string;
@@ -390,8 +357,6 @@ interface ValidationResult {
390
357
  }
391
358
  /** Validate the resources produced by `compile` and the CLI export. */
392
359
  export declare function validateResources(resources: readonly unknown[]): ValidationResult;
393
- //#endregion
394
- //#region src/watch.d.ts
395
360
  interface WatchOptions {
396
361
  dir: string;
397
362
  signal?: AbortSignal;
@@ -414,8 +379,6 @@ interface Watcher {
414
379
  close(): Promise<void>;
415
380
  }
416
381
  export declare function watch(options: WatchOptions): Promise<Watcher>;
417
- //#endregion
418
- //#region src/assets/path.d.ts
419
382
  interface ValidateTopikPathOptions {
420
383
  bindingRoot?: string;
421
384
  capabilities?: {
@@ -434,8 +397,6 @@ export declare function computeTopikPathCollisionKey(path: string, options?: Val
434
397
  export declare function validateTopikPathSet(paths: readonly string[], options?: ValidateTopikPathOptions): TopikAssetResult<Map<string, string>>;
435
398
  /** Unicode 17 NFKC casefold for topik-path-v1-admitted input. */
436
399
  export declare function toNfkcCasefold(value: string): string;
437
- //#endregion
438
- //#region src/assets/json.d.ts
439
400
  export declare class TopikJsonSyntaxError extends SyntaxError {
440
401
  readonly offset: number;
441
402
  readonly duplicatePointer?: string | undefined;
@@ -447,8 +408,6 @@ export declare function serializeTopikJson(value: unknown): string;
447
408
  export declare function topikJsonDescriptor(): {
448
409
  id: typeof TOPIK_JSON_VERSION;
449
410
  };
450
- //#endregion
451
- //#region src/assets/files.d.ts
452
411
  type PortableAssetFileType = "regular" | "symlink" | "hardlink" | "gitlink" | "device" | "fifo" | "socket" | "special" | "sparse" | "archive-link";
453
412
  interface PortableAssetFileDescriptor {
454
413
  path: string;
@@ -473,15 +432,11 @@ interface ReadPortableAssetFileOptions {
473
432
  /** Filesystem reader using no-follow traversal and stable same-handle identity checks. */
474
433
  export declare function readPortableAssetFile(options: ReadPortableAssetFileOptions): Promise<TopikAssetResult<PortableAssetFileDescriptor>>;
475
434
  export declare function looksLikeGitLfsPointer(bytes: Uint8Array): boolean;
476
- //#endregion
477
- //#region src/assets/media.d.ts
478
435
  export declare const TOPIK_UNRESOLVED_ACTIVE_CONTENT_TYPE: "application/x-topik-active-content";
479
436
  /** Sniff exact bytes conservatively. Unknown safe bytes remain opaque downloads. */
480
437
  export declare function sniffPortableMediaType(bytes: Uint8Array): string;
481
438
  export declare function isTopikActiveMediaType(mediaType: string): boolean;
482
439
  export declare function isInlineMediaCompatible(mediaType: string, role: string): boolean;
483
- //#endregion
484
- //#region src/source/syntax.d.ts
485
440
  interface SourceByteRange {
486
441
  start: number;
487
442
  end: number;
@@ -497,8 +452,6 @@ interface SourceByteEdit extends SourceByteRange {
497
452
  oldSha256: string;
498
453
  replacement: Uint8Array;
499
454
  }
500
- //#endregion
501
- //#region src/source/project.d.ts
502
455
  export declare const SOURCE_WRITER_VERSION: "topik-source-writer-v1";
503
456
  export declare const SOURCE_PROJECT_LIMITS: {
504
457
  readonly maxFiles: 10000;
@@ -590,11 +543,7 @@ export declare function digestSourceResourceGraph(resources: readonly Resource[]
590
543
  export declare function readSourceProject(input: {
591
544
  tree: readonly SourceTreeFile[];
592
545
  }): Promise<SourceProject>;
593
- //#endregion
594
- //#region src/source/asset-context.d.ts
595
546
  type SourceAssetReferenceContexts = Readonly<Record<string, Readonly<Record<string, string>>>>;
596
- //#endregion
597
- //#region src/source/initialize.d.ts
598
547
  interface SourceInitializationIntent {
599
548
  namespace: string;
600
549
  source: TopikManifestSource & {
@@ -645,8 +594,6 @@ interface AddSourceToProjectInput {
645
594
  }
646
595
  /** Adding a declaration preserves the existing namespace, order and every original source. */
647
596
  export declare function addSourceToProject(input: AddSourceToProjectInput): Promise<SourcePlanResult>;
648
- //#endregion
649
- //#region src/source/diagnostics.d.ts
650
597
  interface SourcePlanDiagnostic {
651
598
  code: string;
652
599
  message: string;
@@ -658,8 +605,6 @@ interface SourcePlanDiagnostic {
658
605
  kind?: "wiki" | "collection" | "course";
659
606
  config?: string;
660
607
  }
661
- //#endregion
662
- //#region src/source/plan.d.ts
663
608
  type SourceResourceOperation = {
664
609
  kind: "update" | "delete";
665
610
  resource: string;
@@ -754,5 +699,4 @@ interface PlanSourceUpdatesInput {
754
699
  }
755
700
  /** The complete candidate is compiled before any applicable file changes are returned. */
756
701
  export declare function planSourceUpdates(input: PlanSourceUpdatesInput): Promise<SourcePlanResult>;
757
- //#endregion
758
702
  export { ASSET_API_VERSION, ASSET_SCHEMA_ID, ASSET_TYPE, type AddSourceToProjectInput, type AssetBlobUri, AssetCompilationError, type AssetCompilationOptions, type AssetCompilationResult, type AssetNameGenerator, type AssetNameInput, type AssetPayload, type CollectionConfig, type CompileAssetResourcesInput, type CompileCourseOptions, type CompileGuidesOptions, type CompileOptions, type CompileResourceLinksInput, type CompileResourceReferenceTarget, type CompileResult, type CompileValidationOptions, type CompileWikiOptions, type CompiledAsset, type CompiledResource, type CompiledResourceReference, type ContentBearingResource, type CourseConfig, type CourseModuleConfig, CourseNavigationIndex, CourseNavigationModule, type CourseReferenceContext, type DiscoverResourceOptions, type ExternalWikiDropdown, type ExternalWikiTab, type GenerateAutomaticAssetNameOptions, type GeneratedAssetName, type InitializeSourceProjectInput, type InternalWikiDropdown, type InternalWikiTab, type LinkValidationPolicy, type LintResult, type ManifestCompileResult, type ManifestSourceDescriptor, type ManifestSourceProvenance, type ParsedAsset, type PlanSourceUpdatesInput, type PortableAssetFileDescriptor, type PortableAssetFileType, PreviewDiagnostic, PreviewPayloadDescriptor, PreviewState, type ProjectAssetNameOptions, type PublicCompileErrorId, type ReadPortableAssetFileOptions, type ResolvedCourseContentLink, type ResolvedCourseContentReference, type ResolvedCourseNavigation, type ResolvedCoursePage, type ResolvedWikiContentLink, type ResolvedWikiContentReference, type ResolvedWikiNavigation, type ResolvedWikiPage, type Resource, type ResourceType, type SourceAssetsConfig, type SourceByteEdit, type SourceByteRange, type SourceConfigurationProvenance, type SourceDocumentProvenance, type SourceExclusiveAuthority, type SourceFieldEvidence, type SourceFieldOrigin, type SourceFileChange, type SourceInitializationIntent, type SourceMediaSelection, type SourcePlanDiagnostic, type SourcePlanResult, type SourceProject, type SourceResource, type SourceResourceDiscovery, type SourceResourceOperation, type SourceSharedAuthority, type SourceTreeFile, type SourceUpdatePlan, type SourceWriteAuthority, TOPIK_ASSET_CORRELATION_ID_PATTERN, TOPIK_ASSET_DEFAULT_CORRELATION_ID, TOPIK_ASSET_DIAGNOSTIC_IDS, TOPIK_ASSET_LIMITS, TOPIK_ASSET_NAME_VERSION, TOPIK_ASSET_REFERENCE_VERSION, TOPIK_BLOB_OUTPUT_PREFIX, TOPIK_JSON_VERSION, TOPIK_MATERIALIZATION_VERSION, TOPIK_PATH_V1_DESCRIPTOR, TOPIK_PATH_VERSION, TOPIK_PREVIEW_PROTOCOL, type TopikAssetCorrelationId, type TopikAssetDiagnostic, type TopikAssetDiagnosticId, type TopikAssetDiagnosticLocation, type TopikAssetPathDiagnosticReason, type TopikAssetRecoveryCategory, type TopikAssetReferenceMappingV1, type TopikAssetResult, type TopikAssetSemanticRecordV1, type TopikManifest, type TopikManifestSource, type TopikMaterializationPayloadInput, type TopikMaterializationPayloadV1, type TopikMaterializationRecordV1, type TopikMaterializationResourceInput, type TopikMaterializationResourceV1, type ValidTopikPath, type ValidateTopikPathOptions, type ValidationError, type ValidationResult, type WatchOptions, type Watcher, type WikiConfig, type WikiSwitcherNode, compareTopikAssetIdentities, compileAssetResources, correlateTopikAssetResult, createTopikAssetSemanticRecord, createTopikMaterializationRecord, digestTopikAssetSemanticRecord, digestTopikMaterializationRecord, findFirstWikiPage, findWikiPageAncestors, generateAutomaticAssetName, hasWikiNavChildren, isAssetBlobUri, isExternalWikiDropdown, isExternalWikiTab, isGeneratedAssetName, isInternalWikiDropdown, isInternalWikiTab, joinWikiPath, parseAsset, parseAssetBlobUri, parseGeneratedAssetName, resolveCourseContentHref, resolveCourseContentReference, resolveCourseNavigation, resolveWikiContentHref, resolveWikiContentReference, resolveWikiNavigation, serializeAsset, topikAssetNameDescriptor, validateAssetBlobUri, validateAssetValue, validateProjectNamespace, validateTopikMaterializationRecord };
package/dist/index.mjs CHANGED
@@ -1,5 +1,5 @@
1
- import { C as TOPIK_JSON_VERSION, E as TOPIK_PATH_VERSION, S as TOPIK_BLOB_OUTPUT_PREFIX, T as TOPIK_PATH_V1_DESCRIPTOR, _ as ASSET_SCHEMA_ID, a as computeTopikPathCollisionKey, b as TOPIK_ASSET_NAME_VERSION, c as validateTopikPathSet, d as TOPIK_ASSET_DIAGNOSTIC_IDS, f as correlateTopikAssetResult, g as ASSET_API_VERSION, h as isTopikPathNormalizationSensitiveV17, i as validateCoursePageSources, l as TOPIK_ASSET_CORRELATION_ID_PATTERN, m as isTopikPathCodePointForbiddenV17, n as resolveCourseContentReference, o as toNfkcCasefold, p as topikAssetDiagnostic, r as resolveCourseNavigation, s as validateTopikPath, t as resolveCourseContentHref, u as TOPIK_ASSET_DEFAULT_CORRELATION_ID, v as ASSET_TYPE, w as TOPIK_MATERIALIZATION_VERSION, x as TOPIK_ASSET_REFERENCE_VERSION, y as TOPIK_ASSET_LIMITS } from "./course-navigation-CWlVc0a0.mjs";
2
- import { i as resolveDeclaredPublicRoute, o as resolveNavigationPath, r as isFolderHref, t as folderLandingCandidates } from "./folder-links-DI4xfipU.mjs";
1
+ import { C as TOPIK_JSON_VERSION, E as TOPIK_PATH_VERSION, S as TOPIK_BLOB_OUTPUT_PREFIX, T as TOPIK_PATH_V1_DESCRIPTOR, _ as ASSET_SCHEMA_ID, a as computeTopikPathCollisionKey, b as TOPIK_ASSET_NAME_VERSION, c as validateTopikPathSet, d as TOPIK_ASSET_DIAGNOSTIC_IDS, f as correlateTopikAssetResult, g as ASSET_API_VERSION, h as isTopikPathNormalizationSensitiveV17, i as validateCoursePageSources, l as TOPIK_ASSET_CORRELATION_ID_PATTERN, m as isTopikPathCodePointForbiddenV17, n as resolveCourseContentReference, o as toNfkcCasefold, p as topikAssetDiagnostic, r as resolveCourseNavigation, s as validateTopikPath, t as resolveCourseContentHref, u as TOPIK_ASSET_DEFAULT_CORRELATION_ID, v as ASSET_TYPE, w as TOPIK_MATERIALIZATION_VERSION, x as TOPIK_ASSET_REFERENCE_VERSION, y as TOPIK_ASSET_LIMITS } from "./course-navigation-h54ccuqO.mjs";
2
+ import { i as resolveDeclaredPublicRoute, o as resolveNavigationPath, r as isFolderHref, t as folderLandingCandidates } from "./folder-links-jLZaG6xi.mjs";
3
3
  import { findFirstWikiPage, findWikiPageAncestors, hasWikiNavChildren, isExternalWikiDropdown, isExternalWikiTab, isInternalWikiDropdown, isInternalWikiTab, joinWikiPath, resolveWikiContentHref, resolveWikiContentReference, resolveWikiNavigation } from "./wiki-navigation.mjs";
4
4
  import { TOPIK_PREVIEW_PROTOCOL } from "./preview.mjs";
5
5
  import { z } from "zod";
@@ -24,12 +24,11 @@ import { isAlias, isMap, isNode, isScalar, isSeq, parse as parse$1, parseDocumen
24
24
  import { EventEmitter } from "node:events";
25
25
  import { watch as watch$1 } from "chokidar";
26
26
  import { tmpdir } from "node:os";
27
- //#region src/config/assets.ts
27
+ // src/config/assets.ts
28
28
  const DEFAULT_ASSET_DIRECTORY = "_assets";
29
29
  /** Source-local destination for new synced media; not an input scan or compiler output path. */
30
30
  const sourceAssetsConfigSchema = z.strictObject({ directory: z.string().refine((directory) => validateTopikPath(directory).ok, "Expected a portable relative directory").default(DEFAULT_ASSET_DIRECTORY) });
31
- //#endregion
32
- //#region src/assets/json.ts
31
+ // src/assets/json.ts
33
32
  var TopikJsonSyntaxError = class extends SyntaxError {
34
33
  offset;
35
34
  duplicatePointer;
@@ -253,8 +252,7 @@ function escapePointer(value) {
253
252
  function isJsonWhitespace(code) {
254
253
  return code === 9 || code === 10 || code === 13 || code === 32;
255
254
  }
256
- //#endregion
257
- //#region src/assets/asset.ts
255
+ // src/assets/asset.ts
258
256
  const encoder = new TextEncoder();
259
257
  const decoder = new TextDecoder("utf-8", { fatal: true });
260
258
  const ASSET_BLOB_URI_VALIDATOR = /^blobs\/[0-9a-f]{64}$/u;
@@ -472,8 +470,7 @@ function base32(bytes) {
472
470
  if (bits > 0) result += alphabet[accumulator << 5 - bits & 31];
473
471
  return result;
474
472
  }
475
- //#endregion
476
- //#region src/validate.ts
473
+ // src/validate.ts
477
474
  const ajv = new Ajv2020({
478
475
  strict: true,
479
476
  discriminator: true,
@@ -571,8 +568,7 @@ function validateResources(resources) {
571
568
  errors
572
569
  };
573
570
  }
574
- //#endregion
575
- //#region src/config/source-version.ts
571
+ // src/config/source-version.ts
576
572
  const sourceVersionSchema = z.literal(1).optional();
577
573
  const sourceLabelsSchema = z.record(z.string(), z.string());
578
574
  const name$1 = z.string().min(1).max(63).regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/);
@@ -616,8 +612,7 @@ function parseSourcePersons(value) {
616
612
  if (new Set(persons.map((person) => person.name)).size !== persons.length || !validateResources(persons).valid) throw new TypeError("Invalid or duplicate Person resource");
617
613
  return persons;
618
614
  }
619
- //#endregion
620
- //#region src/config/collection.ts
615
+ // src/config/collection.ts
621
616
  const collectionConfigSchema = z.object({
622
617
  id: z.string().min(1).max(63).regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/),
623
618
  title: z.string().min(1).max(256),
@@ -633,8 +628,7 @@ function parseCollectionConfig(raw) {
633
628
  ...config.sourceVersion === 1 && persons !== void 0 ? { persons: parseSourcePersons(persons) } : {}
634
629
  };
635
630
  }
636
- //#endregion
637
- //#region src/config/wiki.ts
631
+ // src/config/wiki.ts
638
632
  const wikiNavIconPattern = new RegExp(wikiV1Schema.$defs.groupNode.properties.icon.pattern);
639
633
  const wikiExternalHrefPattern = new RegExp(wikiV1Schema.$defs.externalTabNode.properties.href.pattern);
640
634
  const pathSegment = z.string().min(1).max(256).regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/, "Slugs must be lowercase DNS-style segments");
@@ -812,8 +806,7 @@ function parseWikiConfig(raw) {
812
806
  ...config.sourceVersion === 1 && labels !== void 0 ? { labels: sourceLabelsSchema.parse(labels) } : {}
813
807
  };
814
808
  }
815
- //#endregion
816
- //#region src/config/course.ts
809
+ // src/config/course.ts
817
810
  const name = z.string().min(1).max(63).regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/);
818
811
  const slug = z.string().min(1).max(256).regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/);
819
812
  const title = z.string().min(1).max(256);
@@ -865,8 +858,7 @@ function parseCourseConfig(raw) {
865
858
  function parseCoursePageMetadata(raw) {
866
859
  return coursePageMetadataSchema.parse(raw);
867
860
  }
868
- //#endregion
869
- //#region src/config/manifest.ts
861
+ // src/config/manifest.ts
870
862
  const TOPIK_MANIFEST_FILENAME = ".topik.yaml";
871
863
  const TOPIK_MANIFEST_LIMITS = {
872
864
  maxBytes: 1048576,
@@ -933,8 +925,7 @@ function findConfigurationPathConflict(paths) {
933
925
  }
934
926
  }
935
927
  }
936
- //#endregion
937
- //#region src/assets/files.ts
928
+ // src/assets/files.ts
938
929
  const execFileAsync = promisify(execFile);
939
930
  function validatePortableAssetFile(file) {
940
931
  const diagnostics = [];
@@ -1124,7 +1115,7 @@ async function readPortableAssetFileAnchored(options, afterDirectoryOpened, afte
1124
1115
  const bytes = buffer.subarray(0, length);
1125
1116
  await afterFileRead?.();
1126
1117
  const after = await fileHandle.stat({ bigint: true });
1127
- if (before.dev !== after.dev || before.ino !== after.ino || before.mode !== after.mode || before.nlink !== after.nlink || before.size !== after.size || before.ctimeNs !== after.ctimeNs || before.mtimeNs !== after.mtimeNs) return {
1118
+ if (!hasStableFileIdentity(before, after)) return {
1128
1119
  ok: false,
1129
1120
  diagnostics: [unsupportedPath(options.path, "File identity changed while hashing")]
1130
1121
  };
@@ -1248,7 +1239,7 @@ async function anchoredGitBoundaryFingerprint(directory) {
1248
1239
  failure: "Git boundary is not a regular file or directory"
1249
1240
  };
1250
1241
  const after = await handle.stat({ bigint: true });
1251
- if (before.dev !== after.dev || before.ino !== after.ino || before.mode !== after.mode || before.nlink !== after.nlink || before.size !== after.size || before.ctimeNs !== after.ctimeNs || before.mtimeNs !== after.mtimeNs) return {
1242
+ if (!hasStableFileIdentity(before, after)) return {
1252
1243
  ok: false,
1253
1244
  failure: "Git boundary identity changed while it was inspected"
1254
1245
  };
@@ -1374,8 +1365,7 @@ async function applyGitAttributes(directory, relativePath, state) {
1374
1365
  const before = await handle.stat({ bigint: true });
1375
1366
  if (!before.isFile() || before.nlink !== 1n) return "Git attribute evidence is not a stable regular file";
1376
1367
  const bytes = await handle.readFile();
1377
- const after = await handle.stat({ bigint: true });
1378
- if (before.dev !== after.dev || before.ino !== after.ino || before.mode !== after.mode || before.nlink !== after.nlink || before.size !== after.size || before.ctimeNs !== after.ctimeNs || before.mtimeNs !== after.mtimeNs) return "Git attribute evidence changed while it was evaluated";
1368
+ if (!hasStableFileIdentity(before, await handle.stat({ bigint: true }))) return "Git attribute evidence changed while it was evaluated";
1379
1369
  let source;
1380
1370
  try {
1381
1371
  source = new TextDecoder("utf-8", { fatal: true }).decode(bytes);
@@ -1456,8 +1446,11 @@ function unsupportedPath(path, message) {
1456
1446
  recovery: "preserve-read-only"
1457
1447
  });
1458
1448
  }
1459
- //#endregion
1460
- //#region src/assets/identity.ts
1449
+ /** Keep the mutation evidence identical for bytes, Git boundaries, and Git attributes. */
1450
+ function hasStableFileIdentity(before, after) {
1451
+ return before.dev === after.dev && before.ino === after.ino && before.mode === after.mode && before.nlink === after.nlink && before.size === after.size && before.ctimeNs === after.ctimeNs && before.mtimeNs === after.mtimeNs;
1452
+ }
1453
+ // src/assets/identity.ts
1461
1454
  function createTopikAssetSemanticRecord(assets, references) {
1462
1455
  return {
1463
1456
  descriptor: "topik-asset-semantic-v1",
@@ -1669,8 +1662,7 @@ function sha256$1(bytes) {
1669
1662
  function compareUtf8$1(left, right) {
1670
1663
  return Buffer.compare(Buffer.from(left), Buffer.from(right));
1671
1664
  }
1672
- //#endregion
1673
- //#region src/assets/media.ts
1665
+ // src/assets/media.ts
1674
1666
  const MARKUP_INSPECTION_LIMIT = 65536;
1675
1667
  const TOPIK_UNRESOLVED_ACTIVE_CONTENT_TYPE = "application/x-topik-active-content";
1676
1668
  /** Sniff exact bytes conservatively. Unknown safe bytes remain opaque downloads. */
@@ -1774,8 +1766,7 @@ function skipMarkupWhitespace(value, start) {
1774
1766
  function ascii(bytes, start, length) {
1775
1767
  return String.fromCharCode(...bytes.slice(start, start + length));
1776
1768
  }
1777
- //#endregion
1778
- //#region src/compile/assets.ts
1769
+ // src/compile/assets.ts
1779
1770
  var AssetCompilationError = class extends Error {
1780
1771
  diagnostics;
1781
1772
  constructor(message, diagnostics = []) {
@@ -2128,8 +2119,7 @@ function compareResources(left, right) {
2128
2119
  function compareUtf8(left, right) {
2129
2120
  return Buffer.compare(Buffer.from(left), Buffer.from(right));
2130
2121
  }
2131
- //#endregion
2132
- //#region src/compile/asset-names.ts
2122
+ // src/compile/asset-names.ts
2133
2123
  /** Create the project's naming policy without reading or requiring a manifest. */
2134
2124
  function createProjectAssetNameGenerator(options) {
2135
2125
  const root = resolve(options.projectRoot);
@@ -2146,8 +2136,7 @@ function createProjectAssetNameGenerator(options) {
2146
2136
  return generated.value;
2147
2137
  };
2148
2138
  }
2149
- //#endregion
2150
- //#region src/compile/public-errors.ts
2139
+ // src/compile/public-errors.ts
2151
2140
  const PUBLIC_COMPILE_ERROR_MESSAGES = {
2152
2141
  "manifest-required": "Project compilation requires .topik.yaml in the selected directory. Add a manifest such as: {\"version\":1,\"namespace\":\"owner/project\",\"sources\":[{\"kind\":\"wiki\",\"config\":\"wiki.yaml\"}]}",
2153
2142
  "manifest-invalid": "Root manifest is invalid.",
@@ -2196,8 +2185,7 @@ function containsForbiddenCodePoint(value) {
2196
2185
  for (const character of value) if (isTopikPathCodePointForbiddenV17(character.codePointAt(0) ?? 0)) return true;
2197
2186
  return false;
2198
2187
  }
2199
- //#endregion
2200
- //#region src/compile/files.ts
2188
+ // src/compile/files.ts
2201
2189
  const LINUX_O_PATH = 2097152;
2202
2190
  const SAFE_READ_FLAGS = constants.O_RDONLY | (typeof constants.O_NOFOLLOW === "number" ? constants.O_NOFOLLOW : 0) | (typeof constants.O_NONBLOCK === "number" ? constants.O_NONBLOCK : 0);
2203
2191
  var FileOutsideCompilationRootError = class extends PublicCompileError {
@@ -2287,8 +2275,7 @@ function safeRelativePath(filePath, rootDir) {
2287
2275
  const location = relative(resolve(rootDir), resolve(filePath)).split(sep).join("/");
2288
2276
  return location.length > 0 && !location.startsWith("../") && location !== ".." ? location : void 0;
2289
2277
  }
2290
- //#endregion
2291
- //#region src/compile/config.ts
2278
+ // src/compile/config.ts
2292
2279
  async function readOptionalConfigFileWithPath(dir, candidates) {
2293
2280
  for (const name of candidates) {
2294
2281
  const filePath = join(dir, name);
@@ -2382,8 +2369,7 @@ function parseSafeConfigurationYaml(raw) {
2382
2369
  }
2383
2370
  return document.toJS({ maxAliasCount: 0 });
2384
2371
  }
2385
- //#endregion
2386
- //#region src/compile/frontmatter.ts
2372
+ // src/compile/frontmatter.ts
2387
2373
  /** Find the same Markdown header boundary for compilation and source byte inspection. */
2388
2374
  function markdownFrontmatter(raw) {
2389
2375
  const match = raw.match(/^\uFEFF?---[ \t]*\r?\n(?:---[ \t]*(?:\r?\n|$)|([\s\S]*?)\r?\n---[ \t]*(?:\r?\n|$))/);
@@ -2398,8 +2384,7 @@ function markdownFrontmatter(raw) {
2398
2384
  bodyStart: match[0].length
2399
2385
  };
2400
2386
  }
2401
- //#endregion
2402
- //#region src/compile/shared.ts
2387
+ // src/compile/shared.ts
2403
2388
  var CompileError = class extends Error {
2404
2389
  diagnostics;
2405
2390
  constructor(diagnostics) {
@@ -2463,8 +2448,7 @@ function parseReferenceList(value, _fieldName, filePath) {
2463
2448
  });
2464
2449
  return references.length > 0 ? references : void 0;
2465
2450
  }
2466
- //#endregion
2467
- //#region src/reference-paths.ts
2451
+ // src/reference-paths.ts
2468
2452
  /** Physical source paths also satisfy the portable filesystem contract. */
2469
2453
  function resolveSourceReferencePath(href, sourcePath, directory) {
2470
2454
  const path = resolveNavigationPath(href, sourcePath, directory);
@@ -2505,8 +2489,7 @@ function sourceNonMarkdownLinkPath(reference, sourcePath, directory) {
2505
2489
  const path = resolveSourceReferencePath(reference.href, sourcePath, directory);
2506
2490
  return path !== void 0 && !/\.(?:mdx?|markdown)$/i.test(path) ? path : void 0;
2507
2491
  }
2508
- //#endregion
2509
- //#region src/compile/links.ts
2492
+ // src/compile/links.ts
2510
2493
  /** Resolve document identity after all declared sources have been discovered, before Assets. */
2511
2494
  async function compileResourceLinks(input) {
2512
2495
  const policy = linkValidationPolicy(input.validation);
@@ -2652,10 +2635,10 @@ async function compileResourceLinks(input) {
2652
2635
  const candidates = path === void 0 || link.href.startsWith("/") && !markdown ? void 0 : markdown ? targetsByPath.get(path) : extensionless ? targetsByExtensionlessPath.get(path) : void 0;
2653
2636
  let target = routeTarget ? localTargets.get(`${resource.type}/${routeTarget.page}`) : folder ? landingPages[0] : candidates?.length === 1 ? candidates[0] : void 0;
2654
2637
  const rootRoute = link.href.split(/[?#]/, 1)[0] === "/";
2655
- if (!target && (extensionless || rootRoute) && resource.type === "WikiPage") {
2638
+ if (!target && (rootRoute || path !== void 0 && !markdown) && resource.type === "WikiPage") {
2656
2639
  const resolved = navigation.get(resource.spec.wiki);
2657
2640
  const wikiTarget = resolved && resolveWikiContentHref(link.href, resource.name, resolved);
2658
- if (wikiTarget) target = localTargets.get(`WikiPage/${wikiTarget.page.page}`);
2641
+ if (wikiTarget && (rootRoute || extensionless || link.kind === "card" || path !== void 0 && !await hasNonPageFile(path))) target = localTargets.get(`WikiPage/${wikiTarget.page.page}`);
2659
2642
  }
2660
2643
  if (!target && path !== void 0 && !markdown && resource.type === "CoursePage") {
2661
2644
  const resolved = courseNavigationByPage.get(resource.name);
@@ -2773,8 +2756,7 @@ function linkDiagnostic(id, level, link) {
2773
2756
  ...link.file ? { file: link.file } : {}
2774
2757
  };
2775
2758
  }
2776
- //#endregion
2777
- //#region src/compile/guide.ts
2759
+ // src/compile/guide.ts
2778
2760
  async function compileGuides(options) {
2779
2761
  const result = await inspectGuides(options);
2780
2762
  throwOnCompileErrors(result.diagnostics);
@@ -2922,8 +2904,7 @@ function mergeTags(collectionTags, frontmatterTags) {
2922
2904
  }
2923
2905
  return [...tags];
2924
2906
  }
2925
- //#endregion
2926
- //#region src/compile/wiki.ts
2907
+ // src/compile/wiki.ts
2927
2908
  async function compileWiki(options) {
2928
2909
  const result = await inspectWiki(options);
2929
2910
  throwOnCompileErrors(result.diagnostics);
@@ -3160,8 +3141,7 @@ function normalizePagePath(pagePath) {
3160
3141
  function pagePathToTitleFallback(pagePath) {
3161
3142
  return normalizePagePath(pagePath).replaceAll("/", "-");
3162
3143
  }
3163
- //#endregion
3164
- //#region src/compile/course.ts
3144
+ // src/compile/course.ts
3165
3145
  async function compileCourse(options) {
3166
3146
  const result = await inspectCourse(options);
3167
3147
  throwOnCompileErrors(result.diagnostics);
@@ -3351,8 +3331,7 @@ function validateCourseAuthors(resources, paths) {
3351
3331
  const persons = new Set(resources.filter((resource) => resource.type === "Person").map((resource) => resource.name));
3352
3332
  for (const resource of resources) if ((resource.type === "Course" || resource.type === "CoursePage") && resource.spec.authors?.some((author) => !persons.has(author))) throw new PublicCompileError("author-not-found", paths[`${resource.type}/${resource.name}`]);
3353
3333
  }
3354
- //#endregion
3355
- //#region src/compile/manifest.ts
3334
+ // src/compile/manifest.ts
3356
3335
  var ManifestSourceError = class extends PublicCompileError {
3357
3336
  sourceIndex;
3358
3337
  kind;
@@ -3489,8 +3468,7 @@ async function compileManifest(options) {
3489
3468
  ...compiled
3490
3469
  };
3491
3470
  }
3492
- //#endregion
3493
- //#region src/compile/discovery.ts
3471
+ // src/compile/discovery.ts
3494
3472
  /** Read authoring metadata and paths before combining a caller-owned source inventory. */
3495
3473
  async function discoverGuideResources(options) {
3496
3474
  return discoverGuides(options);
@@ -3503,8 +3481,7 @@ async function discoverWikiResources(options) {
3503
3481
  async function discoverCourseResources(options) {
3504
3482
  return discoverCourse(options);
3505
3483
  }
3506
- //#endregion
3507
- //#region src/compile/index.ts
3484
+ // src/compile/index.ts
3508
3485
  /** Compile exactly the project declared by .topik.yaml in dir. */
3509
3486
  async function compile(options) {
3510
3487
  return compileManifest(options);
@@ -3517,8 +3494,7 @@ async function lint(options) {
3517
3494
  throw error;
3518
3495
  }
3519
3496
  }
3520
- //#endregion
3521
- //#region src/watch.ts
3497
+ // src/watch.ts
3522
3498
  function freeze(value) {
3523
3499
  if (value && typeof value === "object") {
3524
3500
  for (const child of Object.values(value)) freeze(child);
@@ -3545,6 +3521,7 @@ async function watch(options) {
3545
3521
  let materializationDigest;
3546
3522
  let requested = 0;
3547
3523
  let closed = false;
3524
+ let watchFailed = false;
3548
3525
  let running;
3549
3526
  let debounceTimer;
3550
3527
  function publish(patch) {
@@ -3564,7 +3541,7 @@ async function watch(options) {
3564
3541
  });
3565
3542
  try {
3566
3543
  const result = await compile({ dir });
3567
- if (closed) return;
3544
+ if (closed || watchFailed) return;
3568
3545
  if (revision !== requested) continue;
3569
3546
  const nextDigest = digestTopikMaterializationRecord(result.materialization);
3570
3547
  const updates = result.resources.filter((resource) => {
@@ -3586,7 +3563,7 @@ async function watch(options) {
3586
3563
  });
3587
3564
  for (const resource of updates) emitter.emit("update", `${resource.type}/${resource.name}`, resource);
3588
3565
  } catch (error) {
3589
- if (closed) return;
3566
+ if (closed || watchFailed) return;
3590
3567
  if (revision !== requested) continue;
3591
3568
  const id = error instanceof PublicCompileError ? error.id : "compilation-failed";
3592
3569
  publish({
@@ -3599,17 +3576,17 @@ async function watch(options) {
3599
3576
  if (emitter.listenerCount("error") > 0) emitter.emit("error", error instanceof Error ? error : /* @__PURE__ */ new Error("Compilation failed"));
3600
3577
  }
3601
3578
  if (revision === requested) return;
3602
- } while (!closed);
3579
+ } while (!closed && !watchFailed);
3603
3580
  }
3604
3581
  function startCompile() {
3605
- if (closed) return Promise.resolve();
3582
+ if (closed || watchFailed) return Promise.resolve();
3606
3583
  running ??= drain().finally(() => {
3607
3584
  running = void 0;
3608
3585
  });
3609
3586
  return running;
3610
3587
  }
3611
3588
  function scheduleRecompile() {
3612
- if (closed) return;
3589
+ if (closed || watchFailed) return;
3613
3590
  requested++;
3614
3591
  if (debounceTimer) clearTimeout(debounceTimer);
3615
3592
  if (running) return;
@@ -3631,15 +3608,50 @@ async function watch(options) {
3631
3608
  closed = true;
3632
3609
  if (debounceTimer) clearTimeout(debounceTimer);
3633
3610
  options.signal?.removeEventListener("abort", onAbort);
3634
- await Promise.all([fsWatcher.close(), running]);
3611
+ const closing = fsWatcher.close();
3612
+ if (fsWatcher.listenerCount("error") === 0) fsWatcher.on("error", () => {});
3613
+ await Promise.all([closing, running]);
3635
3614
  };
3636
3615
  const onAbort = () => {
3637
3616
  close();
3638
3617
  };
3639
- await new Promise((resolveReady, rejectReady) => {
3640
- fsWatcher.once("ready", resolveReady);
3641
- fsWatcher.once("error", rejectReady);
3618
+ fsWatcher.on("error", (error) => {
3619
+ if (closed) return;
3620
+ watchFailed = true;
3621
+ if (debounceTimer) clearTimeout(debounceTimer);
3622
+ publish({
3623
+ status: "error",
3624
+ diagnostics: [{
3625
+ id: "watch-failed",
3626
+ message: "Source watching failed. Restart the preview to resume updates."
3627
+ }]
3628
+ });
3629
+ if (emitter.listenerCount("error") > 0) emitter.emit("error", error instanceof Error ? error : /* @__PURE__ */ new Error("Source watching failed"));
3642
3630
  });
3631
+ try {
3632
+ await new Promise((resolveReady, rejectReady) => {
3633
+ const cleanup = () => {
3634
+ fsWatcher.off("ready", ready);
3635
+ fsWatcher.off("error", failed);
3636
+ options.signal?.removeEventListener("abort", ready);
3637
+ };
3638
+ const ready = () => {
3639
+ cleanup();
3640
+ resolveReady();
3641
+ };
3642
+ const failed = (error) => {
3643
+ cleanup();
3644
+ rejectReady(error);
3645
+ };
3646
+ fsWatcher.once("ready", ready);
3647
+ fsWatcher.once("error", failed);
3648
+ options.signal?.addEventListener("abort", ready, { once: true });
3649
+ if (options.signal?.aborted) ready();
3650
+ });
3651
+ } catch (error) {
3652
+ await close();
3653
+ throw error;
3654
+ }
3643
3655
  options.signal?.addEventListener("abort", onAbort, { once: true });
3644
3656
  if (options.signal?.aborted) await close();
3645
3657
  else await startCompile();
@@ -3661,8 +3673,7 @@ async function watch(options) {
3661
3673
  };
3662
3674
  return watcher;
3663
3675
  }
3664
- //#endregion
3665
- //#region src/source/diagnostics.ts
3676
+ // src/source/diagnostics.ts
3666
3677
  var SourcePlanningError = class extends Error {
3667
3678
  diagnostic;
3668
3679
  constructor(diagnostic) {
@@ -3698,8 +3709,7 @@ function sourcePlanDiagnostics(error, fallback) {
3698
3709
  }
3699
3710
  return [fallback];
3700
3711
  }
3701
- //#endregion
3702
- //#region src/source/metadata.ts
3712
+ // src/source/metadata.ts
3703
3713
  /** Existing mapping leaves change individually so sibling metadata keeps its original syntax. */
3704
3714
  function collectMetadataEdits(updates, selector, previous, desired) {
3705
3715
  if (serializeTopikJson(previous ?? null) === serializeTopikJson(desired ?? null) && previous === void 0 === (desired === void 0)) return;
@@ -3709,8 +3719,7 @@ function collectMetadataEdits(updates, selector, previous, desired) {
3709
3719
  for (const key of /* @__PURE__ */ new Set([...Object.keys(before), ...Object.keys(after)])) collectMetadataEdits(updates, `${selector}/${encodeURIComponent(key)}`, before[key], after[key]);
3710
3720
  } else updates[selector] = desired;
3711
3721
  }
3712
- //#endregion
3713
- //#region src/source/syntax.ts
3722
+ // src/source/syntax.ts
3714
3723
  /** Commas in comments and nested values are never collection delimiters. */
3715
3724
  function flowDelimiters(collection) {
3716
3725
  const token = collection.srcToken;
@@ -4109,8 +4118,7 @@ function patchSourceFields(raw, updates, json = false, eol = raw.includes("\r\n"
4109
4118
  edits
4110
4119
  };
4111
4120
  }
4112
- //#endregion
4113
- //#region src/source/course.ts
4121
+ // src/source/course.ts
4114
4122
  function fail(code, message, resource) {
4115
4123
  throw new SourcePlanningError({
4116
4124
  code,
@@ -4259,11 +4267,9 @@ function planCourseConfiguration(input) {
4259
4267
  membershipResources
4260
4268
  };
4261
4269
  }
4262
- //#endregion
4263
- //#region package.json
4264
- var version = "0.1.0-alpha.6";
4265
- //#endregion
4266
- //#region src/source/project.ts
4270
+ // package.json
4271
+ var version = "0.1.0-alpha.7";
4272
+ // src/source/project.ts
4267
4273
  const SOURCE_WRITER_VERSION = "topik-source-writer-v1";
4268
4274
  const SOURCE_PROJECT_LIMITS = {
4269
4275
  maxFiles: 1e4,
@@ -4607,8 +4613,7 @@ function sourceReferences(source, name, resource, compilation, assetPositions, s
4607
4613
  }).ok) throw new TypeError("Source reference provenance cannot be inspected");
4608
4614
  return references;
4609
4615
  }
4610
- //#endregion
4611
- //#region src/source/reference-context.ts
4616
+ // src/source/reference-context.ts
4612
4617
  /** Every saved body must have a source position in its own immutable Wiki snapshot. */
4613
4618
  function resolveSourceReferenceContext(context, wikiName, pageName) {
4614
4619
  if (context.type !== "Wiki" || context.name !== wikiName) return {
@@ -4625,8 +4630,7 @@ function resolveSourceReferenceContext(context, wikiName, pageName) {
4625
4630
  navigation
4626
4631
  };
4627
4632
  }
4628
- //#endregion
4629
- //#region src/source/resource-references.ts
4633
+ // src/source/resource-references.ts
4630
4634
  function courseName(resource, resources) {
4631
4635
  if (resource.type !== "CoursePage") return void 0;
4632
4636
  const module = resources.get(`CourseModule/${resource.spec.module}`);
@@ -4807,8 +4811,7 @@ function restoreSourceResourceReferences(resource, document, path, paths, origin
4807
4811
  repairs
4808
4812
  };
4809
4813
  }
4810
- //#endregion
4811
- //#region src/source/asset-context.ts
4814
+ // src/source/asset-context.ts
4812
4815
  /** Retained saved Asset names resolve only through independently pinned identity mappings. */
4813
4816
  function applySourceAssetReferenceContexts(resources, contexts, scope) {
4814
4817
  for (const [key, mappings] of Object.entries(contexts ?? {})) {
@@ -4827,8 +4830,7 @@ function applySourceAssetReferenceContexts(resources, contexts, scope) {
4827
4830
  resource.spec.content.value = rewritten.content;
4828
4831
  }
4829
4832
  }
4830
- //#endregion
4831
- //#region src/source/plan.ts
4833
+ // src/source/plan.ts
4832
4834
  function block(code, message, resource, path) {
4833
4835
  throw new SourcePlanningError({
4834
4836
  code,
@@ -5596,8 +5598,7 @@ async function planSourceUpdates(input) {
5596
5598
  };
5597
5599
  }
5598
5600
  }
5599
- //#endregion
5600
- //#region src/source/initialize.ts
5601
+ // src/source/initialize.ts
5601
5602
  /** Initialization is distinct from adding a source to a valid existing manifest. */
5602
5603
  async function initializeSourceProject(input) {
5603
5604
  return buildSource(input);
@@ -6012,5 +6013,4 @@ async function buildSource(input, existing) {
6012
6013
  };
6013
6014
  }
6014
6015
  }
6015
- //#endregion
6016
6016
  export { ASSET_API_VERSION, ASSET_SCHEMA_ID, ASSET_TYPE, AssetCompilationError, CompileError, DEFAULT_ASSET_DIRECTORY, ManifestSourceError, PublicCompileError, SOURCE_PROJECT_LIMITS, SOURCE_WRITER_DESCRIPTOR, SOURCE_WRITER_VERSION, TOPIK_ASSET_CORRELATION_ID_PATTERN, TOPIK_ASSET_DEFAULT_CORRELATION_ID, TOPIK_ASSET_DIAGNOSTIC_IDS, TOPIK_ASSET_LIMITS, TOPIK_ASSET_NAME_VERSION, TOPIK_ASSET_REFERENCE_VERSION, TOPIK_BLOB_OUTPUT_PREFIX, TOPIK_JSON_VERSION, TOPIK_MANIFEST_FILENAME, TOPIK_MANIFEST_LIMITS, TOPIK_MATERIALIZATION_VERSION, TOPIK_PATH_V1_DESCRIPTOR, TOPIK_PATH_VERSION, TOPIK_PREVIEW_PROTOCOL, TOPIK_UNRESOLVED_ACTIVE_CONTENT_TYPE, TopikJsonSyntaxError, addSourceToProject, compareTopikAssetIdentities, compile, compileAssetResources, compileCourse, compileGuides, compileManifest, compileResourceLinks, compileWiki, computeTopikPathCollisionKey, correlateTopikAssetResult, createProjectAssetNameGenerator, createTopikAssetSemanticRecord, createTopikMaterializationRecord, digestSourceResourceGraph, digestSourceTree, digestTopikAssetSemanticRecord, digestTopikMaterializationRecord, discoverCourseResources, discoverGuideResources, discoverManifestSources, discoverWikiResources, findFirstWikiPage, findWikiPageAncestors, generateAutomaticAssetName, hasWikiNavChildren, initializeSourceProject, isAssetBlobUri, isErrorDiagnostic, isExternalWikiDropdown, isExternalWikiTab, isGeneratedAssetName, isInlineMediaCompatible, isInternalWikiDropdown, isInternalWikiTab, isTopikActiveMediaType, joinWikiPath, lint, loadTopikManifest, looksLikeGitLfsPointer, pagePathToName, parseAsset, parseAssetBlobUri, parseCollectionConfig, parseCourseConfig, parseGeneratedAssetName, parseStrictTopikJson, parseTopikManifest, parseWikiConfig, planSourceUpdates, publicCompileErrorMessage, readPortableAssetFile, readSourceProject, resolveCourseContentHref, resolveCourseContentReference, resolveCourseNavigation, resolveWikiContentHref, resolveWikiContentReference, resolveWikiNavigation, serializeAsset, serializeTopikJson, sniffPortableMediaType, sourceAssetsConfigSchema, toNfkcCasefold, topikAssetNameDescriptor, topikJsonDescriptor, topikManifestSchema, topikManifestSourceSchema, validateAssetBlobUri, validateAssetValue, validatePortableAssetFile, validatePortableAssetTree, validateProjectNamespace, validateResources, validateTopikMaterializationRecord, validateTopikPath, validateTopikPathSet, watch };
@@ -7,13 +7,10 @@ import { CoursePage } from "@topik/schema/course-page/v1";
7
7
  import { Guide } from "@topik/schema/guide/v1";
8
8
  import { Wiki } from "@topik/schema/wiki/v1";
9
9
  import { WikiPage } from "@topik/schema/wiki-page/v1";
10
- //#region src/resource.d.ts
11
10
  type Resource = Asset | Course | CourseModule | CoursePage | Guide | Person | Wiki | WikiPage;
12
11
  /** Resources accepted as compiler input. `Asset` exists only in compiler output. */
13
12
  type SourceResource = Exclude<Resource, Asset>;
14
13
  type ResourceType = Resource["type"];
15
- //#endregion
16
- //#region src/assets/constants.d.ts
17
14
  declare const ASSET_API_VERSION: "v1";
18
15
  declare const ASSET_TYPE: "Asset";
19
16
  declare const ASSET_SCHEMA_ID: "https://topik.dev/schemas/asset/v1.json";
@@ -43,8 +40,6 @@ declare const TOPIK_ASSET_LIMITS: {
43
40
  readonly maxComponents: 64;
44
41
  readonly maxRepositoryPathUtf8Bytes: 768;
45
42
  };
46
- //#endregion
47
- //#region src/assets/diagnostics.d.ts
48
43
  declare const TOPIK_ASSET_DIAGNOSTIC_IDS: readonly ["TOPIK_ASSET_UNSUPPORTED_VERSION", "TOPIK_ASSET_DUPLICATE_MEMBER", "TOPIK_ASSET_SCHEMA_INVALID", "TOPIK_ASSET_NON_CANONICAL", "TOPIK_ASSET_NAME_INVALID", "TOPIK_ASSET_NAME_COLLISION", "TOPIK_ASSET_NAME_GENERATOR_REQUIRED", "TOPIK_ASSET_PROJECT_NAMESPACE_INVALID", "TOPIK_ASSET_PATH_INVALID", "TOPIK_ASSET_PATH_COLLISION", "TOPIK_ASSET_REFERENCE_AMBIGUOUS", "TOPIK_ASSET_REFERENCE_MALFORMED", "TOPIK_ASSET_REFERENCE_MISSING", "TOPIK_ASSET_FILE_MISSING", "TOPIK_ASSET_DIGEST_MISMATCH", "TOPIK_ASSET_SIZE_MISMATCH", "TOPIK_ASSET_MEDIA_TYPE_MISMATCH", "TOPIK_ASSET_FILE_TYPE_UNSUPPORTED", "TOPIK_ASSET_ACTIVE_CONTENT_UNSUPPORTED", "TOPIK_ASSET_REFERENCE_ACCESSIBILITY_INVALID", "TOPIK_EXTERNAL_REFERENCE_UNSAFE", "TOPIK_ASSET_INVENTORY_INCOMPLETE", "TOPIK_ASSET_VERSION_INCOMPARABLE"];
49
44
  declare const TOPIK_ASSET_DEFAULT_CORRELATION_ID: "cor_00000000000000000000000000";
50
45
  declare const TOPIK_ASSET_CORRELATION_ID_PATTERN: RegExp;
@@ -85,8 +80,6 @@ type TopikAssetResult<T> = {
85
80
  source?: Uint8Array;
86
81
  };
87
82
  declare function correlateTopikAssetResult<T>(result: TopikAssetResult<T>, correlationId: TopikAssetCorrelationId): TopikAssetResult<T>;
88
- //#endregion
89
- //#region src/assets/asset.d.ts
90
83
  interface ParsedAsset {
91
84
  asset: Asset;
92
85
  canonicalBytes: Uint8Array;
@@ -129,8 +122,6 @@ declare function generateAutomaticAssetName(options: GenerateAutomaticAssetNameO
129
122
  declare function topikAssetNameDescriptor(): {
130
123
  id: typeof TOPIK_ASSET_NAME_VERSION;
131
124
  };
132
- //#endregion
133
- //#region src/assets/identity.d.ts
134
125
  interface TopikAssetReferenceMappingV1 {
135
126
  resource: string;
136
127
  position: string;
@@ -186,8 +177,6 @@ declare function compareTopikAssetIdentities(left: {
186
177
  semanticEqual: boolean;
187
178
  exactEqual: boolean;
188
179
  }>;
189
- //#endregion
190
- //#region src/compile/assets.d.ts
191
180
  type ContentBearingResource = CoursePage | Guide | WikiPage;
192
181
  interface AssetNameInput {
193
182
  /** Absolute native path after resolving the authored reference within its allowed root.
@@ -232,8 +221,6 @@ declare class AssetCompilationError extends Error {
232
221
  }
233
222
  /** Discover and resolve one compilation-wide Asset set and deduplicated payload inventory. */
234
223
  declare function compileAssetResources(input: CompileAssetResourcesInput): Promise<AssetCompilationResult>;
235
- //#endregion
236
- //#region src/preview.d.ts
237
224
  /** Browser-safe capability and wire types. No filesystem imports at runtime. */
238
225
  declare const TOPIK_PREVIEW_PROTOCOL: "topik-preview/1";
239
226
  interface CourseNavigationModule {
@@ -264,5 +251,4 @@ interface PreviewState {
264
251
  payloads: PreviewPayloadDescriptor[];
265
252
  courseNavigation: CourseNavigationIndex;
266
253
  }
267
- //#endregion
268
254
  export { TopikAssetPathDiagnosticReason as $, AssetBlobUri as A, parseGeneratedAssetName as B, TopikMaterializationResourceV1 as C, digestTopikAssetSemanticRecord as D, createTopikMaterializationRecord as E, generateAutomaticAssetName as F, validateProjectNamespace as G, topikAssetNameDescriptor as H, isAssetBlobUri as I, TOPIK_ASSET_DIAGNOSTIC_IDS as J, TOPIK_ASSET_CORRELATION_ID_PATTERN as K, isGeneratedAssetName as L, GenerateAutomaticAssetNameOptions as M, GeneratedAssetName as N, digestTopikMaterializationRecord as O, ParsedAsset as P, TopikAssetDiagnosticLocation as Q, parseAsset as R, TopikMaterializationResourceInput as S, createTopikAssetSemanticRecord as T, validateAssetBlobUri as U, serializeAsset as V, validateAssetValue as W, TopikAssetDiagnostic as X, TopikAssetCorrelationId as Y, TopikAssetDiagnosticId as Z, TopikAssetReferenceMappingV1 as _, PreviewState as a, ASSET_TYPE as at, TopikMaterializationPayloadV1 as b, AssetCompilationOptions as c, TOPIK_ASSET_REFERENCE_VERSION as ct, AssetNameInput as d, TOPIK_MATERIALIZATION_VERSION as dt, TopikAssetRecoveryCategory as et, AssetPayload as f, TOPIK_PATH_V1_DESCRIPTOR as ft, compileAssetResources as g, SourceResource as gt, ContentBearingResource as h, ResourceType as ht, PreviewPayloadDescriptor as i, ASSET_SCHEMA_ID as it, CompiledAsset as j, validateTopikMaterializationRecord as k, AssetCompilationResult as l, TOPIK_BLOB_OUTPUT_PREFIX as lt, CompiledResource as m, Resource as mt, CourseNavigationModule as n, correlateTopikAssetResult as nt, TOPIK_PREVIEW_PROTOCOL as o, TOPIK_ASSET_LIMITS as ot, CompileAssetResourcesInput as p, TOPIK_PATH_VERSION as pt, TOPIK_ASSET_DEFAULT_CORRELATION_ID as q, PreviewDiagnostic as r, ASSET_API_VERSION as rt, AssetCompilationError as s, TOPIK_ASSET_NAME_VERSION as st, CourseNavigationIndex as t, TopikAssetResult as tt, AssetNameGenerator as u, TOPIK_JSON_VERSION as ut, TopikAssetSemanticRecordV1 as v, compareTopikAssetIdentities as w, TopikMaterializationRecordV1 as x, TopikMaterializationPayloadInput as y, parseAssetBlobUri as z };
@@ -1,2 +1,2 @@
1
- import { a as PreviewState, i as PreviewPayloadDescriptor, n as CourseNavigationModule, o as TOPIK_PREVIEW_PROTOCOL, r as PreviewDiagnostic, t as CourseNavigationIndex } from "./preview-C_3OnNUi.mjs";
1
+ import { a as PreviewState, i as PreviewPayloadDescriptor, n as CourseNavigationModule, o as TOPIK_PREVIEW_PROTOCOL, r as PreviewDiagnostic, t as CourseNavigationIndex } from "./preview-DfACgOEg.mjs";
2
2
  export { CourseNavigationIndex, CourseNavigationModule, PreviewDiagnostic, PreviewPayloadDescriptor, PreviewState, TOPIK_PREVIEW_PROTOCOL };
package/dist/preview.mjs CHANGED
@@ -1,5 +1,4 @@
1
- //#region src/preview.ts
1
+ // src/preview.ts
2
2
  /** Browser-safe capability and wire types. No filesystem imports at runtime. */
3
3
  const TOPIK_PREVIEW_PROTOCOL = "topik-preview/1";
4
- //#endregion
5
4
  export { TOPIK_PREVIEW_PROTOCOL };
@@ -1,5 +1,4 @@
1
1
  import { WikiDropdownNavNode, WikiExternalDropdownNavNode, WikiExternalTabNavNode, WikiInternalDropdownNavNode, WikiInternalTabNavNode, WikiNavContainerNode, WikiNavNode, WikiNavigation, WikiPageNavNode, WikiTabNavNode } from "@topik/schema/wiki/v1";
2
- //#region src/wiki-navigation.d.ts
3
2
  export type ResolvedWikiPage = {
4
3
  /** The compiled WikiPage resource name. */
5
4
  page: string;
@@ -61,5 +60,4 @@ export type InternalWikiTab = WikiInternalTabNavNode;
61
60
  export type ExternalWikiTab = WikiExternalTabNavNode;
62
61
  export type InternalWikiDropdown = WikiInternalDropdownNavNode;
63
62
  export type ExternalWikiDropdown = WikiExternalDropdownNavNode;
64
- export type WikiSwitcherNode = WikiTabNavNode | WikiDropdownNavNode;
65
- //#endregion
63
+ export type WikiSwitcherNode = WikiTabNavNode | WikiDropdownNavNode;
@@ -1,6 +1,6 @@
1
- import { a as resolveDeclaredSourcePage, i as resolveDeclaredPublicRoute, n as hasDeclaredFolder, o as resolveNavigationPath, r as isFolderHref } from "./folder-links-DI4xfipU.mjs";
1
+ import { a as resolveDeclaredSourcePage, i as resolveDeclaredPublicRoute, n as hasDeclaredFolder, o as resolveNavigationPath, r as isFolderHref } from "./folder-links-jLZaG6xi.mjs";
2
2
  import { parseTopikResourceReference } from "@topik/content";
3
- //#region src/wiki-navigation.ts
3
+ // src/wiki-navigation.ts
4
4
  const INTERNAL_WIKI_ORIGIN = "https://topik.invalid";
5
5
  /** Classify an already-admitted compiled href without treating missing page context as external.
6
6
  * Local files/downloads must first be compiled to Asset references using their source inventory;
@@ -129,5 +129,4 @@ function joinWikiPath(prefix, slug) {
129
129
  if (!slug) return prefix;
130
130
  return prefix ? `${prefix}/${slug}` : slug;
131
131
  }
132
- //#endregion
133
132
  export { findFirstWikiPage, findWikiPageAncestors, hasWikiNavChildren, isExternalWikiDropdown, isExternalWikiTab, isInternalWikiDropdown, isInternalWikiTab, joinWikiPath, resolveWikiContentHref, resolveWikiContentReference, resolveWikiNavigation };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@topik/core",
3
- "version": "0.1.0-alpha.6",
3
+ "version": "0.1.0-alpha.7",
4
4
  "description": "Topik core library",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -23,19 +23,19 @@
23
23
  "access": "public"
24
24
  },
25
25
  "dependencies": {
26
+ "@topik/content": "0.1.0-alpha.7",
27
+ "@topik/schema": "0.1.0-alpha.7",
26
28
  "ajv": "^8.20.0",
27
29
  "ajv-formats": "^3.0.1",
28
30
  "chokidar": "^5.0.0",
29
31
  "yaml": "^2.9.1",
30
- "zod": "^4.6.7",
31
- "@topik/content": "0.1.0-alpha.6",
32
- "@topik/schema": "0.1.0-alpha.6"
32
+ "zod": "^4.6.7"
33
33
  },
34
34
  "devDependencies": {
35
- "@types/node": "22.20.4",
35
+ "@types/node": "22.20.5",
36
36
  "typescript": "^7.0.2",
37
- "vite": "npm:@voidzero-dev/vite-plus-core@1.2.0",
38
- "vite-plus": "1.2.0"
37
+ "vite": "npm:@voidzero-dev/vite-plus-core@1.4.0",
38
+ "vite-plus": "1.4.0"
39
39
  },
40
40
  "scripts": {
41
41
  "build": "vp pack",