cursedbelt-core 2.1.0 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (158) hide show
  1. package/dist/core/activity/index.d.ts +2 -2
  2. package/dist/core/activity/index.js +1 -1
  3. package/dist/core/activity/model.d.ts +2 -2
  4. package/dist/core/analytics/index.d.ts +2 -2
  5. package/dist/core/analytics/index.js +2 -2
  6. package/dist/core/category/index.d.ts +3 -3
  7. package/dist/core/category/index.js +2 -2
  8. package/dist/core/category/memoryStore.d.ts +1 -1
  9. package/dist/core/category/memoryStore.js +1 -1
  10. package/dist/core/category/tree.d.ts +1 -1
  11. package/dist/core/colorScheme/index.d.ts +1 -1
  12. package/dist/core/colorScheme/index.js +1 -1
  13. package/dist/core/folder-tree/actions.d.ts +1 -1
  14. package/dist/core/folder-tree/actions.js +1 -1
  15. package/dist/core/folder-tree/index.d.ts +3 -3
  16. package/dist/core/folder-tree/index.js +3 -3
  17. package/dist/core/folder-tree/tree.js +1 -1
  18. package/dist/core/master-lock/index.d.ts +4 -4
  19. package/dist/core/master-lock/index.js +4 -4
  20. package/dist/core/master-lock/wire.d.ts +1 -1
  21. package/dist/core/media/ffmpeg.d.ts +1 -1
  22. package/dist/core/media/format.d.ts +1 -1
  23. package/dist/core/media/index.d.ts +12 -12
  24. package/dist/core/media/index.js +11 -11
  25. package/dist/core/media/mediaItem.d.ts +1 -1
  26. package/dist/core/media/renderPlan.d.ts +1 -1
  27. package/dist/core/media/renderPlan.js +1 -1
  28. package/dist/core/media/validate.d.ts +1 -1
  29. package/dist/core/media/validate.js +1 -1
  30. package/dist/core/navigation/coverageTest.d.ts +1 -1
  31. package/dist/core/navigation/coverageTest.js +1 -1
  32. package/dist/core/navigation/index.d.ts +6 -6
  33. package/dist/core/navigation/index.js +6 -6
  34. package/dist/core/navigation/migrateNavPreferences.d.ts +1 -1
  35. package/dist/core/navigation/navigationSelectors.d.ts +1 -1
  36. package/dist/core/navigation/navigationSelectors.js +1 -1
  37. package/dist/core/navigation/searchCatalogue.d.ts +1 -1
  38. package/dist/core/offline/shellWorker.d.ts +185 -0
  39. package/dist/core/offline/shellWorker.js +200 -0
  40. package/dist/core/palette/fuzzyRank.d.ts +1 -1
  41. package/dist/core/palette/index.d.ts +3 -3
  42. package/dist/core/palette/index.js +3 -3
  43. package/dist/core/sharing/index.d.ts +2 -2
  44. package/dist/core/sharing/index.js +1 -1
  45. package/dist/core/tokens/registry.d.ts +2 -2
  46. package/dist/core/tokens/registry.js +1 -1
  47. package/dist/core/uiScale/index.d.ts +2 -2
  48. package/dist/core/uiScale/index.js +2 -2
  49. package/dist/core/uiScale/uiScaleStore.js +1 -1
  50. package/dist/core/wire/__fixtures__/rowsMarshalWorker.js +1 -1
  51. package/dist/core/wire/index.d.ts +4 -4
  52. package/dist/core/wire/index.js +4 -4
  53. package/dist/core/wire/ingress.d.ts +1 -1
  54. package/dist/core/wire/ingress.js +3 -3
  55. package/dist/core/wire/marshalWorker.d.ts +1 -1
  56. package/dist/core/wire/marshalWorker.js +2 -2
  57. package/dist/core/wire/marshalling.js +1 -1
  58. package/dist/ctgr/chunkAccumulator.d.ts +1 -1
  59. package/dist/ctgr/chunkAccumulator.js +2 -2
  60. package/dist/ctgr/chunkStore.d.ts +1 -1
  61. package/dist/ctgr/chunkStore.js +2 -2
  62. package/dist/ctgr/codec.d.ts +1 -1
  63. package/dist/ctgr/codec.js +5 -5
  64. package/dist/ctgr/index.d.ts +9 -9
  65. package/dist/ctgr/index.js +9 -9
  66. package/dist/ctgr/v0compat.d.ts +1 -1
  67. package/dist/ctgr/v0compat.js +2 -2
  68. package/dist/index.d.ts +2 -2
  69. package/dist/index.js +2 -2
  70. package/dist/testing/index.d.ts +3 -3
  71. package/dist/testing/index.js +3 -3
  72. package/package.json +8 -2
  73. package/src/config/appConfig.spec.ts +1 -1
  74. package/src/core/activity/index.ts +2 -2
  75. package/src/core/activity/model.ts +2 -2
  76. package/src/core/analytics/index.ts +2 -2
  77. package/src/core/analytics/range.spec.ts +1 -1
  78. package/src/core/analytics/schedule.spec.ts +1 -1
  79. package/src/core/category/category.spec.ts +1 -1
  80. package/src/core/category/index.ts +3 -3
  81. package/src/core/category/memoryStore.ts +2 -2
  82. package/src/core/category/tree.ts +1 -1
  83. package/src/core/color.spec.ts +1 -1
  84. package/src/core/colorScheme/colorScheme.spec.ts +1 -1
  85. package/src/core/colorScheme/index.ts +1 -1
  86. package/src/core/download.spec.ts +1 -1
  87. package/src/core/duplicates/index.spec.ts +1 -1
  88. package/src/core/events/ccEventBus.spec.ts +1 -1
  89. package/src/core/file-tree/fileTreeModel.spec.ts +1 -1
  90. package/src/core/folder-tree/actions.spec.ts +2 -2
  91. package/src/core/folder-tree/actions.ts +2 -2
  92. package/src/core/folder-tree/index.ts +3 -3
  93. package/src/core/folder-tree/path.spec.ts +1 -1
  94. package/src/core/folder-tree/tree.spec.ts +1 -1
  95. package/src/core/folder-tree/tree.ts +1 -1
  96. package/src/core/master-lock/index.ts +4 -4
  97. package/src/core/master-lock/kdf.spec.ts +2 -2
  98. package/src/core/master-lock/presence.spec.ts +1 -1
  99. package/src/core/master-lock/wire.spec.ts +1 -1
  100. package/src/core/master-lock/wire.ts +1 -1
  101. package/src/core/media/bgRemoval.spec.ts +1 -1
  102. package/src/core/media/ffmpeg.spec.ts +2 -2
  103. package/src/core/media/ffmpeg.ts +1 -1
  104. package/src/core/media/format.spec.ts +1 -1
  105. package/src/core/media/format.ts +1 -1
  106. package/src/core/media/index.ts +12 -12
  107. package/src/core/media/mediaItem.spec.ts +2 -2
  108. package/src/core/media/mediaItem.ts +1 -1
  109. package/src/core/media/renderPlan.spec.ts +1 -1
  110. package/src/core/media/renderPlan.ts +2 -2
  111. package/src/core/media/segment.spec.ts +1 -1
  112. package/src/core/media/size.spec.ts +1 -1
  113. package/src/core/media/trim.spec.ts +1 -1
  114. package/src/core/media/validate.spec.ts +2 -2
  115. package/src/core/media/validate.ts +2 -2
  116. package/src/core/media/videoCuts.spec.ts +1 -1
  117. package/src/core/navigation/coverageTest.ts +2 -2
  118. package/src/core/navigation/index.ts +6 -6
  119. package/src/core/navigation/migrateNavPreferences.ts +1 -1
  120. package/src/core/navigation/navigation.spec.ts +1 -1
  121. package/src/core/navigation/navigationSelectors.ts +1 -1
  122. package/src/core/navigation/searchCatalogue.ts +1 -1
  123. package/src/core/net/reconnectSchedule.spec.ts +1 -1
  124. package/src/core/offline/shellWorker.spec.ts +392 -0
  125. package/src/core/offline/shellWorker.ts +346 -0
  126. package/src/core/offline/shellWorker.webworker.spec.ts +80 -0
  127. package/src/core/palette/fuzzyRank.ts +1 -1
  128. package/src/core/palette/index.ts +3 -3
  129. package/src/core/palette/palette.spec.ts +4 -4
  130. package/src/core/schema/projection.spec.ts +1 -1
  131. package/src/core/sharing/index.ts +2 -2
  132. package/src/core/sharing/model.spec.ts +1 -1
  133. package/src/core/tokens/registry.spec.ts +1 -1
  134. package/src/core/tokens/registry.ts +2 -2
  135. package/src/core/uiScale/index.ts +2 -2
  136. package/src/core/uiScale/uiScale.spec.ts +1 -1
  137. package/src/core/uiScale/uiScaleStore.ts +1 -1
  138. package/src/core/wire/__fixtures__/rowsMarshalWorker.ts +1 -1
  139. package/src/core/wire/index.ts +4 -4
  140. package/src/core/wire/ingress.spec.ts +2 -2
  141. package/src/core/wire/ingress.ts +3 -3
  142. package/src/core/wire/marshalWorker.spec.ts +2 -2
  143. package/src/core/wire/marshalWorker.ts +2 -2
  144. package/src/core/wire/marshalling.spec.ts +1 -1
  145. package/src/core/wire/marshalling.ts +1 -1
  146. package/src/core/wire/wireHub.spec.ts +1 -1
  147. package/src/ctgr/chunkAccumulator.ts +3 -3
  148. package/src/ctgr/chunkStore.spec.ts +2 -2
  149. package/src/ctgr/chunkStore.ts +3 -3
  150. package/src/ctgr/codec.spec.ts +4 -4
  151. package/src/ctgr/codec.ts +5 -5
  152. package/src/ctgr/index.ts +9 -9
  153. package/src/ctgr/v0compat.spec.ts +2 -2
  154. package/src/ctgr/v0compat.ts +3 -3
  155. package/src/index.ts +2 -2
  156. package/src/leafSubpathsImportNothing.spec.ts +5 -0
  157. package/src/testTmpRoot.spec.ts +1 -1
  158. package/src/testing/index.ts +3 -3
@@ -30,7 +30,7 @@
30
30
  * - **`id` is source-qualified** (`log:41`, `share:12`), because the stream is a
31
31
  * UNION over more than one table and two tables' autoincrements collide at 1.
32
32
  */
33
- import type { ShareEvent } from "../sharing/model";
33
+ import type { ShareEvent } from "../sharing/model.js";
34
34
 
35
35
  /** How it went. `denied` is its own outcome rather than an `error`: a refused
36
36
  * action is the single most interesting row in an audit trail, and one that
@@ -44,7 +44,7 @@ export const isActivityOutcome = (value: unknown): value is ActivityOutcome =>
44
44
 
45
45
  /**
46
46
  * What was acted on: `(app, kind, id)` — deliberately identical to
47
- * {@link import("../sharing/model").ShareResource}, so a resource can be handed
47
+ * {@link import("../sharing/model.js").ShareResource}, so a resource can be handed
48
48
  * from one primitive to the other without a translation layer.
49
49
  */
50
50
  export interface ActivityResource {
@@ -14,5 +14,5 @@
14
14
  *
15
15
  * The React furniture that renders it lives in `cursedbelt/react/analytics`.
16
16
  */
17
- export * from './range';
18
- export * from './schedule';
17
+ export * from './range.js';
18
+ export * from './schedule.js';
@@ -16,7 +16,7 @@ import {
16
16
  startOfDay,
17
17
  startOfHour,
18
18
  unitForSpan,
19
- } from './range';
19
+ } from './range.js';
20
20
 
21
21
  /** 2026-08-13 14:30 LOCAL — the tests are about local calendar behaviour. */
22
22
  const NOW = new Date(2026, 7, 13, 14, 30, 0).getTime();
@@ -10,7 +10,7 @@ import {
10
10
  simulateSchedule,
11
11
  stretchAt,
12
12
  sweepFleetSizes,
13
- } from './schedule';
13
+ } from './schedule.js';
14
14
 
15
15
  const MIN = 60_000;
16
16
  const item = (id: string, minutes: number, rest: Partial<ScheduleItem> = {}): ScheduleItem => ({
@@ -7,7 +7,7 @@ import {
7
7
  flattenCategoryForest,
8
8
  wouldCreateCycle,
9
9
  type Category,
10
- } from './index';
10
+ } from './index.js';
11
11
 
12
12
  const cat = (id: string, parentId: string | null, label: string, order = 0): Category => ({
13
13
  id,
@@ -8,12 +8,12 @@ export type {
8
8
  CategoryCreateInput,
9
9
  CategoryNode,
10
10
  CategoryStore,
11
- } from './types';
11
+ } from './types.js';
12
12
  export {
13
13
  buildCategoryForest,
14
14
  categoryPath,
15
15
  descendantCategoryIds,
16
16
  flattenCategoryForest,
17
17
  wouldCreateCycle,
18
- } from './tree';
19
- export { createMemoryCategoryStore } from './memoryStore';
18
+ } from './tree.js';
19
+ export { createMemoryCategoryStore } from './memoryStore.js';
@@ -1,5 +1,5 @@
1
- import type { Category, CategoryCreateInput, CategoryStore } from './types';
2
- import { wouldCreateCycle } from './tree';
1
+ import type { Category, CategoryCreateInput, CategoryStore } from './types.js';
2
+ import { wouldCreateCycle } from './tree.js';
3
3
 
4
4
  /**
5
5
  * Zero-config in-memory {@link CategoryStore}: a per-boot `Map` per tenant, so a
@@ -1,4 +1,4 @@
1
- import type { Category, CategoryNode } from './types';
1
+ import type { Category, CategoryNode } from './types.js';
2
2
 
3
3
  /** Sort siblings by explicit `order`, then label (locale-aware, stable). */
4
4
  function compareSiblings(a: Category, b: Category): number {
@@ -1,5 +1,5 @@
1
1
  import { describe, expect, it } from 'bun:test';
2
- import { contrastText } from './color';
2
+ import { contrastText } from './color.js';
3
3
 
4
4
  describe('contrastText', () => {
5
5
  it('returns white on dark backgrounds', () => {
@@ -4,7 +4,7 @@ import {
4
4
  type ColorSchemeStorage,
5
5
  createColorSchemeStore,
6
6
  type ResolvedColorScheme,
7
- } from './index';
7
+ } from './index.js';
8
8
 
9
9
  const makeStorage = (): ColorSchemeStorage & { map: Map<string, string> } => {
10
10
  const map = new Map<string, string>();
@@ -20,4 +20,4 @@ export {
20
20
  setColorSchemeMode,
21
21
  subscribeColorScheme,
22
22
  toggleColorScheme,
23
- } from './colorSchemeStore';
23
+ } from './colorSchemeStore.js';
@@ -1,5 +1,5 @@
1
1
  import { describe, expect, test } from 'bun:test';
2
- import { base64ToBytes, downloadBlob } from './download';
2
+ import { base64ToBytes, downloadBlob } from './download.js';
3
3
 
4
4
  describe('base64ToBytes', () => {
5
5
  test('decodes base64 to the original bytes', () => {
@@ -13,7 +13,7 @@ import {
13
13
  normalizeName,
14
14
  SIZE_TOLERANCE,
15
15
  sizesClose,
16
- } from "./index";
16
+ } from "./index.js";
17
17
 
18
18
  describe("normalizeName", () => {
19
19
  it("reduces the marks a copy picks up to the same stem", () => {
@@ -1,5 +1,5 @@
1
1
  import { describe, expect, it } from 'bun:test';
2
- import { createCcEventBus, MAX_EVENT_DEPTH } from './ccEventBus';
2
+ import { createCcEventBus, MAX_EVENT_DEPTH } from './ccEventBus.js';
3
3
 
4
4
  describe('CCEventBus', () => {
5
5
  it('delivers to every subscriber of a type and to nobody else', async () => {
@@ -13,7 +13,7 @@ import {
13
13
  resolveDrop,
14
14
  resolveKeyboardMove,
15
15
  describeDrop,
16
- } from './fileTreeModel';
16
+ } from './fileTreeModel.js';
17
17
 
18
18
  /**
19
19
  * The shape collections actually feeds this: albums at the top level, each one a folder,
@@ -9,8 +9,8 @@
9
9
  * both are pinned here side by side rather than each in isolation.
10
10
  */
11
11
  import { describe, expect, test } from "bun:test";
12
- import { folderMoveTargets, planFolderMergeInto } from "./actions";
13
- import { buildFolderTree, planFolderMove } from "./tree";
12
+ import { folderMoveTargets, planFolderMergeInto } from "./actions.js";
13
+ import { buildFolderTree, planFolderMove } from "./tree.js";
14
14
 
15
15
  const PATHS = [
16
16
  "rock",
@@ -34,8 +34,8 @@ import {
34
34
  isFolderPathUnder,
35
35
  parseFolderPath,
36
36
  serializeFolderPath,
37
- } from "./path";
38
- import type { FolderNode, FolderRemap } from "./tree";
37
+ } from "./path.js";
38
+ import type { FolderNode, FolderRemap } from "./tree.js";
39
39
 
40
40
  /**
41
41
  * Move everything at or under `source` INTO `destination`, and stop `source` existing.
@@ -26,7 +26,7 @@ export {
26
26
  normalizeFolderName,
27
27
  parseFolderPath,
28
28
  serializeFolderPath,
29
- } from "./path";
29
+ } from "./path.js";
30
30
  export {
31
31
  buildFolderIndex,
32
32
  buildFolderTree,
@@ -37,10 +37,10 @@ export {
37
37
  planFolderDelete,
38
38
  planFolderMove,
39
39
  planFolderRename,
40
- } from "./tree";
40
+ } from "./tree.js";
41
41
  export {
42
42
  type FolderDeleteMode,
43
43
  type FolderTarget,
44
44
  folderMoveTargets,
45
45
  planFolderMergeInto,
46
- } from "./actions";
46
+ } from "./actions.js";
@@ -7,7 +7,7 @@ import {
7
7
  isValidFolderName,
8
8
  parseFolderPath,
9
9
  serializeFolderPath,
10
- } from "./path";
10
+ } from "./path.js";
11
11
 
12
12
  describe("folder path serialization", () => {
13
13
  test("round-trips a simple nested path", () => {
@@ -7,7 +7,7 @@ import {
7
7
  planFolderDelete,
8
8
  planFolderMove,
9
9
  planFolderRename,
10
- } from "./tree";
10
+ } from "./tree.js";
11
11
 
12
12
  /** A compact "name(child,child)" view of a subtree, for readable assertions. */
13
13
  function shape(nodes: readonly FolderNode[]): string {
@@ -17,7 +17,7 @@ import {
17
17
  normalizeFolderName,
18
18
  parseFolderPath,
19
19
  serializeFolderPath,
20
- } from "./path";
20
+ } from "./path.js";
21
21
 
22
22
  /** A node in the derived tree. `path` is the full segment array from the root; a
23
23
  * `child` node's path is its parent's plus one segment. */
@@ -16,7 +16,7 @@ export {
16
16
  isMasterLockKdfParams,
17
17
  newMasterLockKdfParams,
18
18
  unb64u,
19
- } from "./kdf";
19
+ } from "./kdf.js";
20
20
  export {
21
21
  BASE_DELAY_MS,
22
22
  DEFAULT_IDLE_MS,
@@ -27,7 +27,7 @@ export {
27
27
  clampIdleMs,
28
28
  delayAfter,
29
29
  windowRemaining,
30
- } from "./policy";
30
+ } from "./policy.js";
31
31
  export {
32
32
  MASTER_LOCK_COOKIE,
33
33
  masterLockCookieName,
@@ -46,10 +46,10 @@ export {
46
46
  type MasterLockSettingsRequest,
47
47
  type MasterLockStatus,
48
48
  type MasterLockUnlockRequest,
49
- } from "./wire";
49
+ } from "./wire.js";
50
50
  export {
51
51
  PRESENCE_ATTRIBUTE,
52
52
  type PresenceMedia,
53
53
  isPresenceMedia,
54
54
  isSomebodyWatching,
55
- } from "./presence";
55
+ } from "./presence.js";
@@ -17,8 +17,8 @@ import {
17
17
  deriveMasterLockVerifier,
18
18
  isMasterLockKdfParams,
19
19
  newMasterLockKdfParams,
20
- } from ".";
21
- import { b64u, unb64u } from "./kdf";
20
+ } from "./index.js";
21
+ import { b64u, unb64u } from "./kdf.js";
22
22
 
23
23
  // The exact fixture `apps/vault/src/crypto/kdf.test.ts` derives against.
24
24
  const FIXED: MasterLockKdfParams = {
@@ -10,7 +10,7 @@
10
10
  * hole it was asked to close.
11
11
  */
12
12
  import { describe, expect, test } from "bun:test";
13
- import { PRESENCE_ATTRIBUTE, type PresenceMedia, isPresenceMedia, isSomebodyWatching } from "./presence";
13
+ import { PRESENCE_ATTRIBUTE, type PresenceMedia, isPresenceMedia, isSomebodyWatching } from "./presence.js";
14
14
 
15
15
  const media = (over: Partial<PresenceMedia> & { presence?: string } = {}): PresenceMedia => ({
16
16
  paused: false,
@@ -9,7 +9,7 @@
9
9
  * it was told to mount and the browser would fetch what it was told to fetch.
10
10
  */
11
11
  import { describe, expect, it } from "bun:test";
12
- import { MASTER_LOCK_PATHS, MASTER_LOCK_PREFIX } from "./wire";
12
+ import { MASTER_LOCK_PATHS, MASTER_LOCK_PREFIX } from "./wire.js";
13
13
 
14
14
  describe("MASTER_LOCK_PATHS", () => {
15
15
  it("keeps every surface under the one prefix the guard reserves", () => {
@@ -4,7 +4,7 @@
4
4
  * One module both halves import, so a rename cannot make the browser talk to a route that
5
5
  * no longer exists.
6
6
  */
7
- import type { MasterLockKdfParams } from "./kdf";
7
+ import type { MasterLockKdfParams } from "./kdf.js";
8
8
 
9
9
  /**
10
10
  * The mount prefix. Everything under it is reachable while LOCKED (it is how you unlock);
@@ -1,5 +1,5 @@
1
1
  import { describe, expect, test } from 'bun:test';
2
- import { floodFillBGS } from './bgRemoval';
2
+ import { floodFillBGS } from './bgRemoval.js';
3
3
 
4
4
  /** Build a `w×h` RGB buffer from a `pick(x,y) → [r,g,b]` function. */
5
5
  function rgb(
@@ -7,8 +7,8 @@ import {
7
7
  parseFfmpegProgress,
8
8
  parseFfprobe,
9
9
  videoCodecPlan,
10
- } from './ffmpeg';
11
- import type { VideoTrimSpec } from './types';
10
+ } from './ffmpeg.js';
11
+ import type { VideoTrimSpec } from './types.js';
12
12
 
13
13
  const trim = (over: Partial<VideoTrimSpec> = {}): VideoTrimSpec => ({
14
14
  inputPath: '/in.mp4',
@@ -3,7 +3,7 @@
3
3
  // (`server/media-bun/video.ts` spawns these against native ffmpeg) and the browser editor
4
4
  // (`react/media` executes the same argv against ffmpeg.wasm). Unit tested without ffmpeg.
5
5
 
6
- import type { VideoFormat, VideoProgressEvent, VideoQuality, VideoTrimSpec } from './types';
6
+ import type { VideoFormat, VideoProgressEvent, VideoQuality, VideoTrimSpec } from './types.js';
7
7
 
8
8
  /** Codec + rate-control plan for an output container at a quality preset. */
9
9
  export interface VideoCodecPlan {
@@ -5,7 +5,7 @@ import {
5
5
  imageFormatToMime,
6
6
  mimeToImageFormat,
7
7
  pickThumbnailFormat,
8
- } from './format';
8
+ } from './format.js';
9
9
 
10
10
  describe('format helpers', () => {
11
11
  test('mime + extension lookup', () => {
@@ -1,7 +1,7 @@
1
1
  // Pure format helpers — MIME/extension lookup, quality clamping, thumbnail-format
2
2
  // selection. No npm deps; shared by the server adapter, the React layer, and tests.
3
3
 
4
- import type { ImageOutputFormat } from './types';
4
+ import type { ImageOutputFormat } from './types.js';
5
5
 
6
6
  export const IMAGE_OUTPUT_FORMATS: readonly ImageOutputFormat[] = ['jpeg', 'png', 'webp', 'avif'];
7
7
 
@@ -3,7 +3,7 @@
3
3
  // (`cursedbelt/react/media`), and any consuming app/test. No React, no Bun, no npm
4
4
  // dep — the same module loads identically everywhere.
5
5
 
6
- export { type FloodFillBGOptions, floodFillBGS } from './bgRemoval';
6
+ export { type FloodFillBGOptions, floodFillBGS } from './bgRemoval.js';
7
7
  export {
8
8
  buildProbeArgs,
9
9
  buildThumbnailArgs,
@@ -14,7 +14,7 @@ export {
14
14
  parseFfprobe,
15
15
  type VideoCodecPlan,
16
16
  videoCodecPlan,
17
- } from './ffmpeg';
17
+ } from './ffmpeg.js';
18
18
  export {
19
19
  clampQuality,
20
20
  IMAGE_OUTPUT_FORMATS,
@@ -22,14 +22,14 @@ export {
22
22
  imageFormatToMime,
23
23
  mimeToImageFormat,
24
24
  pickThumbnailFormat,
25
- } from './format';
25
+ } from './format.js';
26
26
  export {
27
27
  isAudioItem,
28
28
  isImageItem,
29
29
  isVideoItem,
30
30
  mediaItemAspect,
31
31
  mediaItemDimensions,
32
- } from './mediaItem';
32
+ } from './mediaItem.js';
33
33
  export {
34
34
  buildAtempoChain,
35
35
  buildTimelineRenderPlan,
@@ -40,7 +40,7 @@ export {
40
40
  speedFilters,
41
41
  type TimelineRenderOptions,
42
42
  type TimelineRenderPlan,
43
- } from './renderPlan';
43
+ } from './renderPlan.js';
44
44
  export {
45
45
  closeMask,
46
46
  createRegionSegmenter,
@@ -56,15 +56,15 @@ export {
56
56
  type SegmentSource,
57
57
  sensitivityToTolerance,
58
58
  upscaleMask,
59
- } from './segment';
60
- export { formatBytes } from './size';
59
+ } from './segment.js';
60
+ export { formatBytes } from './size.js';
61
61
  export {
62
62
  type ClampTrimOptions,
63
63
  clampTrimRange,
64
64
  formatTimecode,
65
65
  type TrimRange,
66
66
  trimDurationSeconds,
67
- } from './trim';
67
+ } from './trim.js';
68
68
  export type {
69
69
  GalleryMedia,
70
70
  GalleryPhoto,
@@ -80,15 +80,15 @@ export type {
80
80
  VideoProgressEvent,
81
81
  VideoQuality,
82
82
  VideoTrimSpec,
83
- } from './types';
84
- export { DEFAULT_UPLOAD_CHUNK_SIZE, MAX_SINGLE_UPLOAD_BYTES } from './uploadLimits';
83
+ } from './types.js';
84
+ export { DEFAULT_UPLOAD_CHUNK_SIZE, MAX_SINGLE_UPLOAD_BYTES } from './uploadLimits.js';
85
85
  export {
86
86
  assertValidImagePipelineSpec,
87
87
  assertValidVideoTrimSpec,
88
88
  type ValidationResult,
89
89
  validateImagePipelineSpec,
90
90
  validateVideoTrimSpec,
91
- } from './validate';
91
+ } from './validate.js';
92
92
 
93
93
  // Marking sections of a video to CUT OUT. Framework-free on purpose: the dialog
94
94
  // (`react/media/VideoCutEditor`), the app route that refuses an unexecutable list and the
@@ -102,4 +102,4 @@ export {
102
102
  MIN_CUT_SECONDS,
103
103
  normalizeCuts,
104
104
  type VideoCut,
105
- } from './videoCuts';
105
+ } from './videoCuts.js';
@@ -5,8 +5,8 @@ import {
5
5
  isVideoItem,
6
6
  mediaItemAspect,
7
7
  mediaItemDimensions,
8
- } from './mediaItem';
9
- import type { MediaItem } from './types';
8
+ } from './mediaItem.js';
9
+ import type { MediaItem } from './types.js';
10
10
 
11
11
  const item = (over: Partial<MediaItem> = {}): MediaItem => ({
12
12
  id: '1',
@@ -2,7 +2,7 @@
2
2
  // catalogue maps items to layout photos through these, so the "what size is this
3
3
  // thumbnail" logic is tested here, not buried in a component.
4
4
 
5
- import type { MediaItem } from './types';
5
+ import type { MediaItem } from './types.js';
6
6
 
7
7
  export const isImageItem = (item: MediaItem): boolean => item.type === 'image';
8
8
  export const isVideoItem = (item: MediaItem): boolean => item.type === 'video';
@@ -5,7 +5,7 @@ import {
5
5
  buildTimelineRenderPlan,
6
6
  DEFAULT_NORMALIZE,
7
7
  speedFilters,
8
- } from './renderPlan';
8
+ } from './renderPlan.js';
9
9
 
10
10
  const clip = (partial: Partial<TimelineClip> & { id: string }): TimelineClip => ({
11
11
  name: partial.id,
@@ -16,8 +16,8 @@
16
16
  // where the gaps were. Audio clip offsets are their absolute `timelineStart`.
17
17
 
18
18
  import { clipDuration, roundSeconds, type TimelineClip, type TimelineTrack } from 'cwip/timeline';
19
- import { videoCodecPlan } from './ffmpeg';
20
- import type { VideoFormat, VideoQuality } from './types';
19
+ import { videoCodecPlan } from './ffmpeg.js';
20
+ import type { VideoFormat, VideoQuality } from './types.js';
21
21
 
22
22
  /** An auxiliary text file the executor writes before running the commands. */
23
23
  export interface RenderPlanFile {
@@ -9,7 +9,7 @@ import {
9
9
  type SegmentSource,
10
10
  sensitivityToTolerance,
11
11
  upscaleMask,
12
- } from './segment';
12
+ } from './segment.js';
13
13
 
14
14
  /** Build an RGBA source from a per-pixel color function. */
15
15
  const makeSource = (
@@ -1,5 +1,5 @@
1
1
  import { describe, expect, test } from 'bun:test';
2
- import { formatBytes } from './size';
2
+ import { formatBytes } from './size.js';
3
3
 
4
4
  describe('formatBytes', () => {
5
5
  test('formats across unit boundaries, dropping the decimal at ≥ 100 / in bytes', () => {
@@ -1,5 +1,5 @@
1
1
  import { describe, expect, test } from 'bun:test';
2
- import { clampTrimRange, formatTimecode, trimDurationSeconds } from './trim';
2
+ import { clampTrimRange, formatTimecode, trimDurationSeconds } from './trim.js';
3
3
 
4
4
  describe('clampTrimRange', () => {
5
5
  test('passes a valid range through', () => {
@@ -1,11 +1,11 @@
1
1
  import { describe, expect, test } from 'bun:test';
2
- import type { ImagePipelineSpec, VideoTrimSpec } from './types';
2
+ import type { ImagePipelineSpec, VideoTrimSpec } from './types.js';
3
3
  import {
4
4
  assertValidImagePipelineSpec,
5
5
  assertValidVideoTrimSpec,
6
6
  validateImagePipelineSpec,
7
7
  validateVideoTrimSpec,
8
- } from './validate';
8
+ } from './validate.js';
9
9
 
10
10
  const baseImage = (over: Partial<ImagePipelineSpec> = {}): ImagePipelineSpec => ({
11
11
  input: '/tmp/in.jpg',
@@ -2,8 +2,8 @@
2
2
  // sharp or ffmpeg (where the failure mode is an opaque native error). No deps;
3
3
  // `validate*` returns a collected error list, `assert*` throws on the first problem.
4
4
 
5
- import { IMAGE_OUTPUT_FORMATS } from './format';
6
- import type { ImageOperation, ImagePipelineSpec, VideoTrimSpec } from './types';
5
+ import { IMAGE_OUTPUT_FORMATS } from './format.js';
6
+ import type { ImageOperation, ImagePipelineSpec, VideoTrimSpec } from './types.js';
7
7
 
8
8
  export interface ValidationResult {
9
9
  valid: boolean;
@@ -19,7 +19,7 @@ import {
19
19
  removeSplit,
20
20
  toggleSegment,
21
21
  type VideoCut,
22
- } from './videoCuts';
22
+ } from './videoCuts.js';
23
23
 
24
24
  const cut = (start: number, end: number): VideoCut => ({ start, end });
25
25
  const shape = (cuts: readonly VideoCut[]): string =>
@@ -6,8 +6,8 @@
6
6
  // can never silently bury. Framework-agnostic (throws a plain Error; works under
7
7
  // bun:test, vitest, jest) so the same factory drops into any app's spec file.
8
8
 
9
- import type { NavigationModel } from './navigationModel';
10
- import { deriveAllPaths, normalizeNavPath } from './navigationSelectors';
9
+ import type { NavigationModel } from './navigationModel.js';
10
+ import { deriveAllPaths, normalizeNavPath } from './navigationSelectors.js';
11
11
 
12
12
  /**
13
13
  * Build the coverage assertion for `model` against `allRoutePaths` (the app's full
@@ -7,11 +7,11 @@ export {
7
7
  type BreadcrumbItem,
8
8
  type BreadcrumbNode,
9
9
  buildBreadcrumbTrail,
10
- } from './breadcrumbCompat';
10
+ } from './breadcrumbCompat.js';
11
11
  export {
12
12
  createCoverageTest,
13
13
  findCoverageGaps,
14
- } from './coverageTest';
14
+ } from './coverageTest.js';
15
15
  export {
16
16
  CURRENT_NAV_PREFS_VERSION,
17
17
  type LegacyNavPrefs,
@@ -19,7 +19,7 @@ export {
19
19
  migrateNavPreferences,
20
20
  type NavPreferences,
21
21
  type NavTilePrefs,
22
- } from './migrateNavPreferences';
22
+ } from './migrateNavPreferences.js';
23
23
  export {
24
24
  allowAllGate,
25
25
  type GateFn,
@@ -29,7 +29,7 @@ export {
29
29
  type NavHostLimit,
30
30
  type NavItem,
31
31
  type NavigationModel,
32
- } from './navigationModel';
32
+ } from './navigationModel.js';
33
33
  export {
34
34
  deriveAllPaths,
35
35
  deriveBreadcrumbTrail,
@@ -41,10 +41,10 @@ export {
41
41
  type NavCrumb,
42
42
  normalizeNavPath,
43
43
  type SearchCatalogueEntry,
44
- } from './navigationSelectors';
44
+ } from './navigationSelectors.js';
45
45
  export {
46
46
  type CatalogueHit,
47
47
  type CatalogueResultGroup,
48
48
  groupCatalogueHits,
49
49
  rankCatalogue,
50
- } from './searchCatalogue';
50
+ } from './searchCatalogue.js';
@@ -6,7 +6,7 @@
6
6
  // cold load but no-ops once `version` is current, so colors/hidden the user set
7
7
  // AFTER migrating are never clobbered.
8
8
 
9
- import type { NavigationModel } from './navigationModel';
9
+ import type { NavigationModel } from './navigationModel.js';
10
10
 
11
11
  /** Bump when the migration logic or the prefs shape changes. */
12
12
  export const CURRENT_NAV_PREFS_VERSION = 1;
@@ -17,7 +17,7 @@ import {
17
17
  type NavigationModel,
18
18
  normalizeNavPath,
19
19
  rankCatalogue,
20
- } from './index';
20
+ } from './index.js';
21
21
 
22
22
  // A representative slice of the ca IA: 6 domains + an Admin domain + ungrouped, with
23
23
  // deepLinkOnly + gated + tab-target items — enough to exercise every selector.
@@ -11,7 +11,7 @@ import {
11
11
  type NavGroup,
12
12
  type NavItem,
13
13
  type NavigationModel,
14
- } from './navigationModel';
14
+ } from './navigationModel.js';
15
15
 
16
16
  /**
17
17
  * Normalize a path for route *matching* — drop the query string, the hash (the