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.
- package/dist/core/activity/index.d.ts +2 -2
- package/dist/core/activity/index.js +1 -1
- package/dist/core/activity/model.d.ts +2 -2
- package/dist/core/analytics/index.d.ts +2 -2
- package/dist/core/analytics/index.js +2 -2
- package/dist/core/category/index.d.ts +3 -3
- package/dist/core/category/index.js +2 -2
- package/dist/core/category/memoryStore.d.ts +1 -1
- package/dist/core/category/memoryStore.js +1 -1
- package/dist/core/category/tree.d.ts +1 -1
- package/dist/core/colorScheme/index.d.ts +1 -1
- package/dist/core/colorScheme/index.js +1 -1
- package/dist/core/folder-tree/actions.d.ts +1 -1
- package/dist/core/folder-tree/actions.js +1 -1
- package/dist/core/folder-tree/index.d.ts +3 -3
- package/dist/core/folder-tree/index.js +3 -3
- package/dist/core/folder-tree/tree.js +1 -1
- package/dist/core/master-lock/index.d.ts +4 -4
- package/dist/core/master-lock/index.js +4 -4
- package/dist/core/master-lock/wire.d.ts +1 -1
- package/dist/core/media/ffmpeg.d.ts +1 -1
- package/dist/core/media/format.d.ts +1 -1
- package/dist/core/media/index.d.ts +12 -12
- package/dist/core/media/index.js +11 -11
- package/dist/core/media/mediaItem.d.ts +1 -1
- package/dist/core/media/renderPlan.d.ts +1 -1
- package/dist/core/media/renderPlan.js +1 -1
- package/dist/core/media/validate.d.ts +1 -1
- package/dist/core/media/validate.js +1 -1
- package/dist/core/navigation/coverageTest.d.ts +1 -1
- package/dist/core/navigation/coverageTest.js +1 -1
- package/dist/core/navigation/index.d.ts +6 -6
- package/dist/core/navigation/index.js +6 -6
- package/dist/core/navigation/migrateNavPreferences.d.ts +1 -1
- package/dist/core/navigation/navigationSelectors.d.ts +1 -1
- package/dist/core/navigation/navigationSelectors.js +1 -1
- package/dist/core/navigation/searchCatalogue.d.ts +1 -1
- package/dist/core/offline/shellWorker.d.ts +185 -0
- package/dist/core/offline/shellWorker.js +200 -0
- package/dist/core/palette/fuzzyRank.d.ts +1 -1
- package/dist/core/palette/index.d.ts +3 -3
- package/dist/core/palette/index.js +3 -3
- package/dist/core/sharing/index.d.ts +2 -2
- package/dist/core/sharing/index.js +1 -1
- package/dist/core/tokens/registry.d.ts +2 -2
- package/dist/core/tokens/registry.js +1 -1
- package/dist/core/uiScale/index.d.ts +2 -2
- package/dist/core/uiScale/index.js +2 -2
- package/dist/core/uiScale/uiScaleStore.js +1 -1
- package/dist/core/wire/__fixtures__/rowsMarshalWorker.js +1 -1
- package/dist/core/wire/index.d.ts +4 -4
- package/dist/core/wire/index.js +4 -4
- package/dist/core/wire/ingress.d.ts +1 -1
- package/dist/core/wire/ingress.js +3 -3
- package/dist/core/wire/marshalWorker.d.ts +1 -1
- package/dist/core/wire/marshalWorker.js +2 -2
- package/dist/core/wire/marshalling.js +1 -1
- package/dist/ctgr/chunkAccumulator.d.ts +1 -1
- package/dist/ctgr/chunkAccumulator.js +2 -2
- package/dist/ctgr/chunkStore.d.ts +1 -1
- package/dist/ctgr/chunkStore.js +2 -2
- package/dist/ctgr/codec.d.ts +1 -1
- package/dist/ctgr/codec.js +5 -5
- package/dist/ctgr/index.d.ts +9 -9
- package/dist/ctgr/index.js +9 -9
- package/dist/ctgr/v0compat.d.ts +1 -1
- package/dist/ctgr/v0compat.js +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/dist/testing/index.d.ts +3 -3
- package/dist/testing/index.js +3 -3
- package/package.json +8 -2
- package/src/config/appConfig.spec.ts +1 -1
- package/src/core/activity/index.ts +2 -2
- package/src/core/activity/model.ts +2 -2
- package/src/core/analytics/index.ts +2 -2
- package/src/core/analytics/range.spec.ts +1 -1
- package/src/core/analytics/schedule.spec.ts +1 -1
- package/src/core/category/category.spec.ts +1 -1
- package/src/core/category/index.ts +3 -3
- package/src/core/category/memoryStore.ts +2 -2
- package/src/core/category/tree.ts +1 -1
- package/src/core/color.spec.ts +1 -1
- package/src/core/colorScheme/colorScheme.spec.ts +1 -1
- package/src/core/colorScheme/index.ts +1 -1
- package/src/core/download.spec.ts +1 -1
- package/src/core/duplicates/index.spec.ts +1 -1
- package/src/core/events/ccEventBus.spec.ts +1 -1
- package/src/core/file-tree/fileTreeModel.spec.ts +1 -1
- package/src/core/folder-tree/actions.spec.ts +2 -2
- package/src/core/folder-tree/actions.ts +2 -2
- package/src/core/folder-tree/index.ts +3 -3
- package/src/core/folder-tree/path.spec.ts +1 -1
- package/src/core/folder-tree/tree.spec.ts +1 -1
- package/src/core/folder-tree/tree.ts +1 -1
- package/src/core/master-lock/index.ts +4 -4
- package/src/core/master-lock/kdf.spec.ts +2 -2
- package/src/core/master-lock/presence.spec.ts +1 -1
- package/src/core/master-lock/wire.spec.ts +1 -1
- package/src/core/master-lock/wire.ts +1 -1
- package/src/core/media/bgRemoval.spec.ts +1 -1
- package/src/core/media/ffmpeg.spec.ts +2 -2
- package/src/core/media/ffmpeg.ts +1 -1
- package/src/core/media/format.spec.ts +1 -1
- package/src/core/media/format.ts +1 -1
- package/src/core/media/index.ts +12 -12
- package/src/core/media/mediaItem.spec.ts +2 -2
- package/src/core/media/mediaItem.ts +1 -1
- package/src/core/media/renderPlan.spec.ts +1 -1
- package/src/core/media/renderPlan.ts +2 -2
- package/src/core/media/segment.spec.ts +1 -1
- package/src/core/media/size.spec.ts +1 -1
- package/src/core/media/trim.spec.ts +1 -1
- package/src/core/media/validate.spec.ts +2 -2
- package/src/core/media/validate.ts +2 -2
- package/src/core/media/videoCuts.spec.ts +1 -1
- package/src/core/navigation/coverageTest.ts +2 -2
- package/src/core/navigation/index.ts +6 -6
- package/src/core/navigation/migrateNavPreferences.ts +1 -1
- package/src/core/navigation/navigation.spec.ts +1 -1
- package/src/core/navigation/navigationSelectors.ts +1 -1
- package/src/core/navigation/searchCatalogue.ts +1 -1
- package/src/core/net/reconnectSchedule.spec.ts +1 -1
- package/src/core/offline/shellWorker.spec.ts +392 -0
- package/src/core/offline/shellWorker.ts +346 -0
- package/src/core/offline/shellWorker.webworker.spec.ts +80 -0
- package/src/core/palette/fuzzyRank.ts +1 -1
- package/src/core/palette/index.ts +3 -3
- package/src/core/palette/palette.spec.ts +4 -4
- package/src/core/schema/projection.spec.ts +1 -1
- package/src/core/sharing/index.ts +2 -2
- package/src/core/sharing/model.spec.ts +1 -1
- package/src/core/tokens/registry.spec.ts +1 -1
- package/src/core/tokens/registry.ts +2 -2
- package/src/core/uiScale/index.ts +2 -2
- package/src/core/uiScale/uiScale.spec.ts +1 -1
- package/src/core/uiScale/uiScaleStore.ts +1 -1
- package/src/core/wire/__fixtures__/rowsMarshalWorker.ts +1 -1
- package/src/core/wire/index.ts +4 -4
- package/src/core/wire/ingress.spec.ts +2 -2
- package/src/core/wire/ingress.ts +3 -3
- package/src/core/wire/marshalWorker.spec.ts +2 -2
- package/src/core/wire/marshalWorker.ts +2 -2
- package/src/core/wire/marshalling.spec.ts +1 -1
- package/src/core/wire/marshalling.ts +1 -1
- package/src/core/wire/wireHub.spec.ts +1 -1
- package/src/ctgr/chunkAccumulator.ts +3 -3
- package/src/ctgr/chunkStore.spec.ts +2 -2
- package/src/ctgr/chunkStore.ts +3 -3
- package/src/ctgr/codec.spec.ts +4 -4
- package/src/ctgr/codec.ts +5 -5
- package/src/ctgr/index.ts +9 -9
- package/src/ctgr/v0compat.spec.ts +2 -2
- package/src/ctgr/v0compat.ts +3 -3
- package/src/index.ts +2 -2
- package/src/leafSubpathsImportNothing.spec.ts +5 -0
- package/src/testTmpRoot.spec.ts +1 -1
- package/src/testing/index.ts +3 -3
|
@@ -4,5 +4,5 @@
|
|
|
4
4
|
* The storage + query half is `cursedbelt-server/activity`; this entry is what a
|
|
5
5
|
* browser, a spec or a wire type can import without pulling `bun:sqlite` in.
|
|
6
6
|
*/
|
|
7
|
-
export { ACTIVITY_OUTCOMES, activityFromShareEvent, activitySubject, describeActivityEvent, describeActivityResource, isActivityAction, isActivityOutcome, } from "./model";
|
|
8
|
-
export type { ActivityEvent, ActivityEventInput, ActivityOutcome, ActivityResource, } from "./model";
|
|
7
|
+
export { ACTIVITY_OUTCOMES, activityFromShareEvent, activitySubject, describeActivityEvent, describeActivityResource, isActivityAction, isActivityOutcome, } from "./model.js";
|
|
8
|
+
export type { ActivityEvent, ActivityEventInput, ActivityOutcome, ActivityResource, } from "./model.js";
|
|
@@ -4,4 +4,4 @@
|
|
|
4
4
|
* The storage + query half is `cursedbelt-server/activity`; this entry is what a
|
|
5
5
|
* browser, a spec or a wire type can import without pulling `bun:sqlite` in.
|
|
6
6
|
*/
|
|
7
|
-
export { ACTIVITY_OUTCOMES, activityFromShareEvent, activitySubject, describeActivityEvent, describeActivityResource, isActivityAction, isActivityOutcome, } from "./model";
|
|
7
|
+
export { ACTIVITY_OUTCOMES, activityFromShareEvent, activitySubject, describeActivityEvent, describeActivityResource, isActivityAction, isActivityOutcome, } from "./model.js";
|
|
@@ -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
|
/** How it went. `denied` is its own outcome rather than an `error`: a refused
|
|
35
35
|
* action is the single most interesting row in an audit trail, and one that
|
|
36
36
|
* reads as a crash gets triaged as one. */
|
|
@@ -39,7 +39,7 @@ export declare const ACTIVITY_OUTCOMES: readonly ActivityOutcome[];
|
|
|
39
39
|
export declare const isActivityOutcome: (value: unknown) => value is ActivityOutcome;
|
|
40
40
|
/**
|
|
41
41
|
* What was acted on: `(app, kind, id)` — deliberately identical to
|
|
42
|
-
* {@link import("../sharing/model").ShareResource}, so a resource can be handed
|
|
42
|
+
* {@link import("../sharing/model.js").ShareResource}, so a resource can be handed
|
|
43
43
|
* from one primitive to the other without a translation layer.
|
|
44
44
|
*/
|
|
45
45
|
export interface ActivityResource {
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export type { Category, CategoryCreateInput, CategoryNode, CategoryStore, } from './types';
|
|
2
|
-
export { buildCategoryForest, categoryPath, descendantCategoryIds, flattenCategoryForest, wouldCreateCycle, } from './tree';
|
|
3
|
-
export { createMemoryCategoryStore } from './memoryStore';
|
|
1
|
+
export type { Category, CategoryCreateInput, CategoryNode, CategoryStore, } from './types.js';
|
|
2
|
+
export { buildCategoryForest, categoryPath, descendantCategoryIds, flattenCategoryForest, wouldCreateCycle, } from './tree.js';
|
|
3
|
+
export { createMemoryCategoryStore } from './memoryStore.js';
|
|
@@ -2,5 +2,5 @@
|
|
|
2
2
|
// through `cursedbelt/react`'s categoryTree. Pure and
|
|
3
3
|
// React-free (the `TreeView` adapter lives in `cursedbelt/react`), so servers
|
|
4
4
|
// can import the contract + store without pulling any UI runtime.
|
|
5
|
-
export { buildCategoryForest, categoryPath, descendantCategoryIds, flattenCategoryForest, wouldCreateCycle, } from './tree';
|
|
6
|
-
export { createMemoryCategoryStore } from './memoryStore';
|
|
5
|
+
export { buildCategoryForest, categoryPath, descendantCategoryIds, flattenCategoryForest, wouldCreateCycle, } from './tree.js';
|
|
6
|
+
export { createMemoryCategoryStore } from './memoryStore.js';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Category, CategoryCreateInput } from './types';
|
|
1
|
+
import type { Category, CategoryCreateInput } from './types.js';
|
|
2
2
|
/**
|
|
3
3
|
* Zero-config in-memory {@link CategoryStore}: a per-boot `Map` per tenant, so a
|
|
4
4
|
* host that wires nothing up still gets a working (non-persistent) category
|
|
@@ -4,4 +4,4 @@
|
|
|
4
4
|
* on app boot (before React mounts → no flash); the React control + hook live in
|
|
5
5
|
* `cursedbelt/react` (`ThemeToggle`, `useColorScheme`).
|
|
6
6
|
*/
|
|
7
|
-
export { applyColorSchemeToDocument, COLOR_SCHEME_STORAGE_KEY, type ColorSchemeMode, type ColorSchemeStorage, type ColorSchemeStore, type ColorSchemeStoreOptions, colorSchemeStore, createColorSchemeStore, getColorSchemeMode, getResolvedColorScheme, initColorScheme, type ResolvedColorScheme, setColorSchemeMode, subscribeColorScheme, toggleColorScheme, } from './colorSchemeStore';
|
|
7
|
+
export { applyColorSchemeToDocument, COLOR_SCHEME_STORAGE_KEY, type ColorSchemeMode, type ColorSchemeStorage, type ColorSchemeStore, type ColorSchemeStoreOptions, colorSchemeStore, createColorSchemeStore, getColorSchemeMode, getResolvedColorScheme, initColorScheme, type ResolvedColorScheme, setColorSchemeMode, subscribeColorScheme, toggleColorScheme, } from './colorSchemeStore.js';
|
|
@@ -4,4 +4,4 @@
|
|
|
4
4
|
* on app boot (before React mounts → no flash); the React control + hook live in
|
|
5
5
|
* `cursedbelt/react` (`ThemeToggle`, `useColorScheme`).
|
|
6
6
|
*/
|
|
7
|
-
export { applyColorSchemeToDocument, COLOR_SCHEME_STORAGE_KEY, colorSchemeStore, createColorSchemeStore, getColorSchemeMode, getResolvedColorScheme, initColorScheme, setColorSchemeMode, subscribeColorScheme, toggleColorScheme, } from './colorSchemeStore';
|
|
7
|
+
export { applyColorSchemeToDocument, COLOR_SCHEME_STORAGE_KEY, colorSchemeStore, createColorSchemeStore, getColorSchemeMode, getResolvedColorScheme, initColorScheme, setColorSchemeMode, subscribeColorScheme, toggleColorScheme, } from './colorSchemeStore.js';
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
* place that can count what is about to be lost or refuse the operation. Modelling it here
|
|
29
29
|
* would mean inventing an item, and an item this model cannot see is one it cannot protect.
|
|
30
30
|
*/
|
|
31
|
-
import type { FolderNode, FolderRemap } from "./tree";
|
|
31
|
+
import type { FolderNode, FolderRemap } from "./tree.js";
|
|
32
32
|
/**
|
|
33
33
|
* Move everything at or under `source` INTO `destination`, and stop `source` existing.
|
|
34
34
|
*
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
* place that can count what is about to be lost or refuse the operation. Modelling it here
|
|
29
29
|
* would mean inventing an item, and an item this model cannot see is one it cannot protect.
|
|
30
30
|
*/
|
|
31
|
-
import { folderPathKey, isFolderPathUnder, parseFolderPath, serializeFolderPath, } from "./path";
|
|
31
|
+
import { folderPathKey, isFolderPathUnder, parseFolderPath, serializeFolderPath, } from "./path.js";
|
|
32
32
|
/**
|
|
33
33
|
* Move everything at or under `source` INTO `destination`, and stop `source` existing.
|
|
34
34
|
*
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { FOLDER_PATH_DELIMITER, FOLDER_PATH_ESCAPE, folderDescendantPrefix, folderPathKey, formatFolderPath, isFolderPathUnder, isValidFolderName, normalizeFolderName, parseFolderPath, serializeFolderPath, } from "./path";
|
|
2
|
-
export { buildFolderIndex, buildFolderTree, flattenFolderTree, type FolderIndex, type FolderNode, type FolderRemap, planFolderDelete, planFolderMove, planFolderRename, } from "./tree";
|
|
3
|
-
export { type FolderDeleteMode, type FolderTarget, folderMoveTargets, planFolderMergeInto, } from "./actions";
|
|
1
|
+
export { FOLDER_PATH_DELIMITER, FOLDER_PATH_ESCAPE, folderDescendantPrefix, folderPathKey, formatFolderPath, isFolderPathUnder, isValidFolderName, normalizeFolderName, parseFolderPath, serializeFolderPath, } from "./path.js";
|
|
2
|
+
export { buildFolderIndex, buildFolderTree, flattenFolderTree, type FolderIndex, type FolderNode, type FolderRemap, planFolderDelete, planFolderMove, planFolderRename, } from "./tree.js";
|
|
3
|
+
export { type FolderDeleteMode, type FolderTarget, folderMoveTargets, planFolderMergeInto, } from "./actions.js";
|
|
@@ -15,6 +15,6 @@
|
|
|
15
15
|
// and bulk-moved by SQL. Importing the React barrel into a Bun server to reach
|
|
16
16
|
// `isFolderPathUnder` would drag `Button`/`Input` and the whole component graph into a
|
|
17
17
|
// process that renders nothing. Same law as `cursedbelt-core/sharing` vs `cursedbelt/react/sharing`.
|
|
18
|
-
export { FOLDER_PATH_DELIMITER, FOLDER_PATH_ESCAPE, folderDescendantPrefix, folderPathKey, formatFolderPath, isFolderPathUnder, isValidFolderName, normalizeFolderName, parseFolderPath, serializeFolderPath, } from "./path";
|
|
19
|
-
export { buildFolderIndex, buildFolderTree, flattenFolderTree, planFolderDelete, planFolderMove, planFolderRename, } from "./tree";
|
|
20
|
-
export { folderMoveTargets, planFolderMergeInto, } from "./actions";
|
|
18
|
+
export { FOLDER_PATH_DELIMITER, FOLDER_PATH_ESCAPE, folderDescendantPrefix, folderPathKey, formatFolderPath, isFolderPathUnder, isValidFolderName, normalizeFolderName, parseFolderPath, serializeFolderPath, } from "./path.js";
|
|
19
|
+
export { buildFolderIndex, buildFolderTree, flattenFolderTree, planFolderDelete, planFolderMove, planFolderRename, } from "./tree.js";
|
|
20
|
+
export { folderMoveTargets, planFolderMergeInto, } from "./actions.js";
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* entries and for notes' groups) and keeps the dangerous part — rewriting stored
|
|
11
11
|
* items — a small, testable list of string swaps.
|
|
12
12
|
*/
|
|
13
|
-
import { folderPathKey, isFolderPathUnder, normalizeFolderName, parseFolderPath, serializeFolderPath, } from "./path";
|
|
13
|
+
import { folderPathKey, isFolderPathUnder, normalizeFolderName, parseFolderPath, serializeFolderPath, } from "./path.js";
|
|
14
14
|
/**
|
|
15
15
|
* Build the nested tree from a flat collection of serialized folder-path strings
|
|
16
16
|
* (one per item, duplicates fine). EVERY prefix becomes a node, so a tree with only
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* What the whole feature is, and what it is NOT, is written once in the engine's module
|
|
9
9
|
* note — read that before changing anything here.
|
|
10
10
|
*/
|
|
11
|
-
export { MASTER_LOCK_KDF, type MasterLockKdfParams, b64u, deriveMasterLockVerifier, isMasterLockKdfParams, newMasterLockKdfParams, unb64u, } from "./kdf";
|
|
12
|
-
export { BASE_DELAY_MS, DEFAULT_IDLE_MS, FREE_ATTEMPTS, MAX_DELAY_MS, MAX_IDLE_MS, MIN_IDLE_MS, clampIdleMs, delayAfter, windowRemaining, } from "./policy";
|
|
13
|
-
export { MASTER_LOCK_COOKIE, masterLockCookieName, MASTER_LOCK_HEADER, MASTER_LOCK_PATHS, MASTER_LOCK_PREFIX, MASTER_LOCK_STATE_HEADER, type MasterLockAccountSummary, type MasterLockAccountsResponse, type MasterLockAddAccountRequest, type MasterLockChangeRequest, type MasterLockEditAccountRequest, type MasterLockEnrollRequest, type MasterLockHintsResponse, type MasterLockRefusal, type MasterLockSettingsRequest, type MasterLockStatus, type MasterLockUnlockRequest, } from "./wire";
|
|
14
|
-
export { PRESENCE_ATTRIBUTE, type PresenceMedia, isPresenceMedia, isSomebodyWatching, } from "./presence";
|
|
11
|
+
export { MASTER_LOCK_KDF, type MasterLockKdfParams, b64u, deriveMasterLockVerifier, isMasterLockKdfParams, newMasterLockKdfParams, unb64u, } from "./kdf.js";
|
|
12
|
+
export { BASE_DELAY_MS, DEFAULT_IDLE_MS, FREE_ATTEMPTS, MAX_DELAY_MS, MAX_IDLE_MS, MIN_IDLE_MS, clampIdleMs, delayAfter, windowRemaining, } from "./policy.js";
|
|
13
|
+
export { MASTER_LOCK_COOKIE, masterLockCookieName, MASTER_LOCK_HEADER, MASTER_LOCK_PATHS, MASTER_LOCK_PREFIX, MASTER_LOCK_STATE_HEADER, type MasterLockAccountSummary, type MasterLockAccountsResponse, type MasterLockAddAccountRequest, type MasterLockChangeRequest, type MasterLockEditAccountRequest, type MasterLockEnrollRequest, type MasterLockHintsResponse, type MasterLockRefusal, type MasterLockSettingsRequest, type MasterLockStatus, type MasterLockUnlockRequest, } from "./wire.js";
|
|
14
|
+
export { PRESENCE_ATTRIBUTE, type PresenceMedia, isPresenceMedia, isSomebodyWatching, } from "./presence.js";
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* What the whole feature is, and what it is NOT, is written once in the engine's module
|
|
9
9
|
* note — read that before changing anything here.
|
|
10
10
|
*/
|
|
11
|
-
export { MASTER_LOCK_KDF, b64u, deriveMasterLockVerifier, isMasterLockKdfParams, newMasterLockKdfParams, unb64u, } from "./kdf";
|
|
12
|
-
export { BASE_DELAY_MS, DEFAULT_IDLE_MS, FREE_ATTEMPTS, MAX_DELAY_MS, MAX_IDLE_MS, MIN_IDLE_MS, clampIdleMs, delayAfter, windowRemaining, } from "./policy";
|
|
13
|
-
export { MASTER_LOCK_COOKIE, masterLockCookieName, MASTER_LOCK_HEADER, MASTER_LOCK_PATHS, MASTER_LOCK_PREFIX, MASTER_LOCK_STATE_HEADER, } from "./wire";
|
|
14
|
-
export { PRESENCE_ATTRIBUTE, isPresenceMedia, isSomebodyWatching, } from "./presence";
|
|
11
|
+
export { MASTER_LOCK_KDF, b64u, deriveMasterLockVerifier, isMasterLockKdfParams, newMasterLockKdfParams, unb64u, } from "./kdf.js";
|
|
12
|
+
export { BASE_DELAY_MS, DEFAULT_IDLE_MS, FREE_ATTEMPTS, MAX_DELAY_MS, MAX_IDLE_MS, MIN_IDLE_MS, clampIdleMs, delayAfter, windowRemaining, } from "./policy.js";
|
|
13
|
+
export { MASTER_LOCK_COOKIE, masterLockCookieName, MASTER_LOCK_HEADER, MASTER_LOCK_PATHS, MASTER_LOCK_PREFIX, MASTER_LOCK_STATE_HEADER, } from "./wire.js";
|
|
14
|
+
export { PRESENCE_ATTRIBUTE, isPresenceMedia, isSomebodyWatching, } from "./presence.js";
|
|
@@ -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
|
* The mount prefix. Everything under it is reachable while LOCKED (it is how you unlock);
|
|
10
10
|
* everything else on the origin is not.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { VideoFormat, VideoProgressEvent, VideoQuality, VideoTrimSpec } from './types';
|
|
1
|
+
import type { VideoFormat, VideoProgressEvent, VideoQuality, VideoTrimSpec } from './types.js';
|
|
2
2
|
/** Codec + rate-control plan for an output container at a quality preset. */
|
|
3
3
|
export interface VideoCodecPlan {
|
|
4
4
|
videoCodec: string;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ImageOutputFormat } from './types';
|
|
1
|
+
import type { ImageOutputFormat } from './types.js';
|
|
2
2
|
export declare const IMAGE_OUTPUT_FORMATS: readonly ImageOutputFormat[];
|
|
3
3
|
export declare function imageFormatToMime(format: ImageOutputFormat): string;
|
|
4
4
|
export declare function imageFormatToExtension(format: ImageOutputFormat): string;
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
export { type FloodFillBGOptions, floodFillBGS } from './bgRemoval';
|
|
2
|
-
export { buildProbeArgs, buildThumbnailArgs, buildTrimArgs, ffmpegTimeToSeconds, type ProbeResult, parseFfmpegProgress, parseFfprobe, type VideoCodecPlan, videoCodecPlan, } from './ffmpeg';
|
|
3
|
-
export { clampQuality, IMAGE_OUTPUT_FORMATS, imageFormatToExtension, imageFormatToMime, mimeToImageFormat, pickThumbnailFormat, } from './format';
|
|
4
|
-
export { isAudioItem, isImageItem, isVideoItem, mediaItemAspect, mediaItemDimensions, } from './mediaItem';
|
|
5
|
-
export { buildAtempoChain, buildTimelineRenderPlan, DEFAULT_NORMALIZE, type FfmpegCommand, type NormalizeSpec, type RenderPlanFile, speedFilters, type TimelineRenderOptions, type TimelineRenderPlan, } from './renderPlan';
|
|
6
|
-
export { closeMask, createRegionSegmenter, DEFAULT_CLOSE_RADIUS, DEFAULT_TOLERANCE, dilateMask, downscaleRgba, erodeMask, fitWorkingSize, type ImageSegmenter, type SegmentOptions, type SegmentPrompt, type SegmentSource, sensitivityToTolerance, upscaleMask, } from './segment';
|
|
7
|
-
export { formatBytes } from './size';
|
|
8
|
-
export { type ClampTrimOptions, clampTrimRange, formatTimecode, type TrimRange, trimDurationSeconds, } from './trim';
|
|
9
|
-
export type { GalleryMedia, GalleryPhoto, ImageOperation, ImageOutputFormat, ImagePipelineSpec, MediaItem, MediaKind, MediaKindFilter, PlayableVideo, ProcessingStatus, VideoFormat, VideoProgressEvent, VideoQuality, VideoTrimSpec, } from './types';
|
|
10
|
-
export { DEFAULT_UPLOAD_CHUNK_SIZE, MAX_SINGLE_UPLOAD_BYTES } from './uploadLimits';
|
|
11
|
-
export { assertValidImagePipelineSpec, assertValidVideoTrimSpec, type ValidationResult, validateImagePipelineSpec, validateVideoTrimSpec, } from './validate';
|
|
12
|
-
export { cutListProblem, cutSeconds, cutTimecode, keptSeconds, keptSegments, MIN_CUT_SECONDS, normalizeCuts, type VideoCut, } from './videoCuts';
|
|
1
|
+
export { type FloodFillBGOptions, floodFillBGS } from './bgRemoval.js';
|
|
2
|
+
export { buildProbeArgs, buildThumbnailArgs, buildTrimArgs, ffmpegTimeToSeconds, type ProbeResult, parseFfmpegProgress, parseFfprobe, type VideoCodecPlan, videoCodecPlan, } from './ffmpeg.js';
|
|
3
|
+
export { clampQuality, IMAGE_OUTPUT_FORMATS, imageFormatToExtension, imageFormatToMime, mimeToImageFormat, pickThumbnailFormat, } from './format.js';
|
|
4
|
+
export { isAudioItem, isImageItem, isVideoItem, mediaItemAspect, mediaItemDimensions, } from './mediaItem.js';
|
|
5
|
+
export { buildAtempoChain, buildTimelineRenderPlan, DEFAULT_NORMALIZE, type FfmpegCommand, type NormalizeSpec, type RenderPlanFile, speedFilters, type TimelineRenderOptions, type TimelineRenderPlan, } from './renderPlan.js';
|
|
6
|
+
export { closeMask, createRegionSegmenter, DEFAULT_CLOSE_RADIUS, DEFAULT_TOLERANCE, dilateMask, downscaleRgba, erodeMask, fitWorkingSize, type ImageSegmenter, type SegmentOptions, type SegmentPrompt, type SegmentSource, sensitivityToTolerance, upscaleMask, } from './segment.js';
|
|
7
|
+
export { formatBytes } from './size.js';
|
|
8
|
+
export { type ClampTrimOptions, clampTrimRange, formatTimecode, type TrimRange, trimDurationSeconds, } from './trim.js';
|
|
9
|
+
export type { GalleryMedia, GalleryPhoto, ImageOperation, ImageOutputFormat, ImagePipelineSpec, MediaItem, MediaKind, MediaKindFilter, PlayableVideo, ProcessingStatus, VideoFormat, VideoProgressEvent, VideoQuality, VideoTrimSpec, } from './types.js';
|
|
10
|
+
export { DEFAULT_UPLOAD_CHUNK_SIZE, MAX_SINGLE_UPLOAD_BYTES } from './uploadLimits.js';
|
|
11
|
+
export { assertValidImagePipelineSpec, assertValidVideoTrimSpec, type ValidationResult, validateImagePipelineSpec, validateVideoTrimSpec, } from './validate.js';
|
|
12
|
+
export { cutListProblem, cutSeconds, cutTimecode, keptSeconds, keptSegments, MIN_CUT_SECONDS, normalizeCuts, type VideoCut, } from './videoCuts.js';
|
package/dist/core/media/index.js
CHANGED
|
@@ -2,17 +2,17 @@
|
|
|
2
2
|
// the Bun server adapter (`src/server/media-bun`), the React components
|
|
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
|
-
export { floodFillBGS } from './bgRemoval';
|
|
6
|
-
export { buildProbeArgs, buildThumbnailArgs, buildTrimArgs, ffmpegTimeToSeconds, parseFfmpegProgress, parseFfprobe, videoCodecPlan, } from './ffmpeg';
|
|
7
|
-
export { clampQuality, IMAGE_OUTPUT_FORMATS, imageFormatToExtension, imageFormatToMime, mimeToImageFormat, pickThumbnailFormat, } from './format';
|
|
8
|
-
export { isAudioItem, isImageItem, isVideoItem, mediaItemAspect, mediaItemDimensions, } from './mediaItem';
|
|
9
|
-
export { buildAtempoChain, buildTimelineRenderPlan, DEFAULT_NORMALIZE, speedFilters, } from './renderPlan';
|
|
10
|
-
export { closeMask, createRegionSegmenter, DEFAULT_CLOSE_RADIUS, DEFAULT_TOLERANCE, dilateMask, downscaleRgba, erodeMask, fitWorkingSize, sensitivityToTolerance, upscaleMask, } from './segment';
|
|
11
|
-
export { formatBytes } from './size';
|
|
12
|
-
export { clampTrimRange, formatTimecode, trimDurationSeconds, } from './trim';
|
|
13
|
-
export { DEFAULT_UPLOAD_CHUNK_SIZE, MAX_SINGLE_UPLOAD_BYTES } from './uploadLimits';
|
|
14
|
-
export { assertValidImagePipelineSpec, assertValidVideoTrimSpec, validateImagePipelineSpec, validateVideoTrimSpec, } from './validate';
|
|
5
|
+
export { floodFillBGS } from './bgRemoval.js';
|
|
6
|
+
export { buildProbeArgs, buildThumbnailArgs, buildTrimArgs, ffmpegTimeToSeconds, parseFfmpegProgress, parseFfprobe, videoCodecPlan, } from './ffmpeg.js';
|
|
7
|
+
export { clampQuality, IMAGE_OUTPUT_FORMATS, imageFormatToExtension, imageFormatToMime, mimeToImageFormat, pickThumbnailFormat, } from './format.js';
|
|
8
|
+
export { isAudioItem, isImageItem, isVideoItem, mediaItemAspect, mediaItemDimensions, } from './mediaItem.js';
|
|
9
|
+
export { buildAtempoChain, buildTimelineRenderPlan, DEFAULT_NORMALIZE, speedFilters, } from './renderPlan.js';
|
|
10
|
+
export { closeMask, createRegionSegmenter, DEFAULT_CLOSE_RADIUS, DEFAULT_TOLERANCE, dilateMask, downscaleRgba, erodeMask, fitWorkingSize, sensitivityToTolerance, upscaleMask, } from './segment.js';
|
|
11
|
+
export { formatBytes } from './size.js';
|
|
12
|
+
export { clampTrimRange, formatTimecode, trimDurationSeconds, } from './trim.js';
|
|
13
|
+
export { DEFAULT_UPLOAD_CHUNK_SIZE, MAX_SINGLE_UPLOAD_BYTES } from './uploadLimits.js';
|
|
14
|
+
export { assertValidImagePipelineSpec, assertValidVideoTrimSpec, validateImagePipelineSpec, validateVideoTrimSpec, } from './validate.js';
|
|
15
15
|
// Marking sections of a video to CUT OUT. Framework-free on purpose: the dialog
|
|
16
16
|
// (`react/media/VideoCutEditor`), the app route that refuses an unexecutable list and the
|
|
17
17
|
// binary-server job that runs it all read the same rules from here.
|
|
18
|
-
export { cutListProblem, cutSeconds, cutTimecode, keptSeconds, keptSegments, MIN_CUT_SECONDS, normalizeCuts, } from './videoCuts';
|
|
18
|
+
export { cutListProblem, cutSeconds, cutTimecode, keptSeconds, keptSegments, MIN_CUT_SECONDS, normalizeCuts, } from './videoCuts.js';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { MediaItem } from './types';
|
|
1
|
+
import type { MediaItem } from './types.js';
|
|
2
2
|
export declare const isImageItem: (item: MediaItem) => boolean;
|
|
3
3
|
export declare const isVideoItem: (item: MediaItem) => boolean;
|
|
4
4
|
export declare const isAudioItem: (item: MediaItem) => boolean;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type TimelineTrack } from 'cwip/timeline';
|
|
2
|
-
import type { VideoFormat, VideoQuality } from './types';
|
|
2
|
+
import type { VideoFormat, VideoQuality } from './types.js';
|
|
3
3
|
/** An auxiliary text file the executor writes before running the commands. */
|
|
4
4
|
export interface RenderPlanFile {
|
|
5
5
|
name: string;
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
// end-to-end in timeline order, so close gaps before exporting if you want cuts
|
|
16
16
|
// where the gaps were. Audio clip offsets are their absolute `timelineStart`.
|
|
17
17
|
import { clipDuration, roundSeconds } from 'cwip/timeline';
|
|
18
|
-
import { videoCodecPlan } from './ffmpeg';
|
|
18
|
+
import { videoCodecPlan } from './ffmpeg.js';
|
|
19
19
|
/** 720p30 keeps in-browser (wasm) export times tolerable; hosts can raise it. */
|
|
20
20
|
export const DEFAULT_NORMALIZE = {
|
|
21
21
|
width: 1280,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// Pure spec validation — catches a malformed pipeline/trim spec BEFORE it reaches
|
|
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
|
-
import { IMAGE_OUTPUT_FORMATS } from './format';
|
|
4
|
+
import { IMAGE_OUTPUT_FORMATS } from './format.js';
|
|
5
5
|
function ok(errors) {
|
|
6
6
|
return { valid: errors.length === 0, errors };
|
|
7
7
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { NavigationModel } from './navigationModel';
|
|
1
|
+
import type { NavigationModel } from './navigationModel.js';
|
|
2
2
|
/**
|
|
3
3
|
* Build the coverage assertion for `model` against `allRoutePaths` (the app's full
|
|
4
4
|
* route list, e.g. derived from `routes.tsx`). The returned `() => void` throws —
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
// model, a registered route is automatically discoverable — and an unregistered one
|
|
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
|
-
import { deriveAllPaths, normalizeNavPath } from './navigationSelectors';
|
|
8
|
+
import { deriveAllPaths, normalizeNavPath } from './navigationSelectors.js';
|
|
9
9
|
/**
|
|
10
10
|
* Build the coverage assertion for `model` against `allRoutePaths` (the app's full
|
|
11
11
|
* route list, e.g. derived from `routes.tsx`). The returned `() => void` throws —
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
export { type BreadcrumbItem, type BreadcrumbNode, buildBreadcrumbTrail, } from './breadcrumbCompat';
|
|
2
|
-
export { createCoverageTest, findCoverageGaps, } from './coverageTest';
|
|
3
|
-
export { CURRENT_NAV_PREFS_VERSION, type LegacyNavPrefs, type MigrateNavPrefsOptions, migrateNavPreferences, type NavPreferences, type NavTilePrefs, } from './migrateNavPreferences';
|
|
4
|
-
export { allowAllGate, type GateFn, type NavDomain, type NavGate, type NavGroup, type NavHostLimit, type NavItem, type NavigationModel, } from './navigationModel';
|
|
5
|
-
export { deriveAllPaths, deriveBreadcrumbTrail, deriveDomain, deriveDomainGroups, deriveDomainItems, deriveSearchCatalogue, deriveSideNavDomains, type NavCrumb, normalizeNavPath, type SearchCatalogueEntry, } from './navigationSelectors';
|
|
6
|
-
export { type CatalogueHit, type CatalogueResultGroup, groupCatalogueHits, rankCatalogue, } from './searchCatalogue';
|
|
1
|
+
export { type BreadcrumbItem, type BreadcrumbNode, buildBreadcrumbTrail, } from './breadcrumbCompat.js';
|
|
2
|
+
export { createCoverageTest, findCoverageGaps, } from './coverageTest.js';
|
|
3
|
+
export { CURRENT_NAV_PREFS_VERSION, type LegacyNavPrefs, type MigrateNavPrefsOptions, migrateNavPreferences, type NavPreferences, type NavTilePrefs, } from './migrateNavPreferences.js';
|
|
4
|
+
export { allowAllGate, type GateFn, type NavDomain, type NavGate, type NavGroup, type NavHostLimit, type NavItem, type NavigationModel, } from './navigationModel.js';
|
|
5
|
+
export { deriveAllPaths, deriveBreadcrumbTrail, deriveDomain, deriveDomainGroups, deriveDomainItems, deriveSearchCatalogue, deriveSideNavDomains, type NavCrumb, normalizeNavPath, type SearchCatalogueEntry, } from './navigationSelectors.js';
|
|
6
|
+
export { type CatalogueHit, type CatalogueResultGroup, groupCatalogueHits, rankCatalogue, } from './searchCatalogue.js';
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
// routing-free: the single source of truth (the IA tree) plus every derivation off
|
|
3
3
|
// it (side nav, hub tiles, breadcrumbs, search catalogue, coverage test, prefs
|
|
4
4
|
// migration). The React components in `cursedbelt/react` consume exactly this.
|
|
5
|
-
export { buildBreadcrumbTrail, } from './breadcrumbCompat';
|
|
6
|
-
export { createCoverageTest, findCoverageGaps, } from './coverageTest';
|
|
7
|
-
export { CURRENT_NAV_PREFS_VERSION, migrateNavPreferences, } from './migrateNavPreferences';
|
|
8
|
-
export { allowAllGate, } from './navigationModel';
|
|
9
|
-
export { deriveAllPaths, deriveBreadcrumbTrail, deriveDomain, deriveDomainGroups, deriveDomainItems, deriveSearchCatalogue, deriveSideNavDomains, normalizeNavPath, } from './navigationSelectors';
|
|
10
|
-
export { groupCatalogueHits, rankCatalogue, } from './searchCatalogue';
|
|
5
|
+
export { buildBreadcrumbTrail, } from './breadcrumbCompat.js';
|
|
6
|
+
export { createCoverageTest, findCoverageGaps, } from './coverageTest.js';
|
|
7
|
+
export { CURRENT_NAV_PREFS_VERSION, migrateNavPreferences, } from './migrateNavPreferences.js';
|
|
8
|
+
export { allowAllGate, } from './navigationModel.js';
|
|
9
|
+
export { deriveAllPaths, deriveBreadcrumbTrail, deriveDomain, deriveDomainGroups, deriveDomainItems, deriveSearchCatalogue, deriveSideNavDomains, normalizeNavPath, } from './navigationSelectors.js';
|
|
10
|
+
export { groupCatalogueHits, rankCatalogue, } from './searchCatalogue.js';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { NavigationModel } from './navigationModel';
|
|
1
|
+
import type { NavigationModel } from './navigationModel.js';
|
|
2
2
|
/** Bump when the migration logic or the prefs shape changes. */
|
|
3
3
|
export declare const CURRENT_NAV_PREFS_VERSION = 1;
|
|
4
4
|
/** Per-hub tile customization (keyed by item path/id within a domain). */
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type GateFn, type NavDomain, type NavGroup, type NavItem, type NavigationModel } from './navigationModel';
|
|
1
|
+
import { type GateFn, type NavDomain, type NavGroup, type NavItem, type NavigationModel } from './navigationModel.js';
|
|
2
2
|
/**
|
|
3
3
|
* Normalize a path for route *matching* — drop the query string, the hash (the
|
|
4
4
|
* `#tab=…` in-page target), and a trailing slash. `'/'` stays `'/'`. Used so a tab
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// model exclusively through these — there is no second list to keep in sync. They
|
|
4
4
|
// import nothing from React, so they run identically in the client, in a server
|
|
5
5
|
// test, and in the CI coverage check.
|
|
6
|
-
import { allowAllGate, } from './navigationModel';
|
|
6
|
+
import { allowAllGate, } from './navigationModel.js';
|
|
7
7
|
/**
|
|
8
8
|
* Normalize a path for route *matching* — drop the query string, the hash (the
|
|
9
9
|
* `#tab=…` in-page target), and a trailing slash. `'/'` stays `'/'`. Used so a tab
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { SearchCatalogueEntry } from './navigationSelectors';
|
|
1
|
+
import type { SearchCatalogueEntry } from './navigationSelectors.js';
|
|
2
2
|
/** A query hit with its computed relevance score (higher = better). */
|
|
3
3
|
export interface CatalogueHit extends SearchCatalogueEntry {
|
|
4
4
|
score: number;
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The app-shell service worker, once, for every app that serves its shell offline
|
|
3
|
+
* (task 2073, 2026-09-22).
|
|
4
|
+
*
|
|
5
|
+
* `apps/roms` wrote this by hand as plain JS in `public/sw.js`, with a TypeScript
|
|
6
|
+
* twin in `src/offline/swRouting.ts` held in step by a comment saying "keep the two
|
|
7
|
+
* in step". `apps/music` needed the same worker, and a third hand copy is how a fix
|
|
8
|
+
* lands in one app and not the others. This module is the one body; an app's
|
|
9
|
+
* `src/sw.ts` passes a config and adds whatever is genuinely its own (background
|
|
10
|
+
* sync, an outbox, a digest-keyed media cache) as further listeners beside it.
|
|
11
|
+
*
|
|
12
|
+
* What it does, and it is deliberately all it does:
|
|
13
|
+
* - `install` — precache the shell and the config's `precache` list, then `skipWaiting`.
|
|
14
|
+
* - `activate` — delete every cache named `<cachePrefix>*` that is not this version's,
|
|
15
|
+
* then `clients.claim()`.
|
|
16
|
+
* - `fetch` — same-origin static ASSETS cache-first; document NAVIGATIONS
|
|
17
|
+
* network-first, falling back offline to the exact URL, then the same
|
|
18
|
+
* path ignoring the query, then the shell. Everything else is left on
|
|
19
|
+
* the network: `respondWith` is never called for it.
|
|
20
|
+
*
|
|
21
|
+
* 🔴 `/api/` is NEVER cached and NEVER served from a cache. It is auth-gated, and a
|
|
22
|
+
* browser whose session has since been revoked must not read yesterday's copy of a
|
|
23
|
+
* private response out of its own cache. That is not a default a config can switch
|
|
24
|
+
* off: `apiPrefixes` ADDS prefixes to `/api/`, it cannot remove it, a precache entry
|
|
25
|
+
* under an API prefix is refused when the worker is installed, and `shouldCache`
|
|
26
|
+
* refuses to store an `api` route even if a caller asks.
|
|
27
|
+
*
|
|
28
|
+
* 🔴 `noShellFallback` exists because of the 2026-08-12 frame incident in roms. A game
|
|
29
|
+
* boots by loading `/emulator-frame.html` into a sandboxed iframe — a NAVIGATION, so it
|
|
30
|
+
* went network-first, and offline with nothing cached under that path the fallback
|
|
31
|
+
* handed it the APP SHELL. The iframe rendered a second copy of the library where the
|
|
32
|
+
* game should be: no canvas, no error, no clue. Any document that is not the shell (an
|
|
33
|
+
* iframe, a popup, a print view) must be listed there, and must be in `precache` if it
|
|
34
|
+
* is meant to work offline at all — an offline miss on it then REJECTS, which is the
|
|
35
|
+
* honest answer, rather than resolving the wrong document.
|
|
36
|
+
*
|
|
37
|
+
* Imports nothing at runtime (`leafSubpathsImportNothing.spec.ts` holds it to that):
|
|
38
|
+
* it is bundled into a service worker, where every byte ships on every install.
|
|
39
|
+
* `scope` is typed structurally so this compiles without the WebWorker lib, is testable
|
|
40
|
+
* with a fake, and still accepts the real `self` — `shellWorker.webworker.spec.ts`
|
|
41
|
+
* typechecks exactly that against `lib.webworker.d.ts`.
|
|
42
|
+
*/
|
|
43
|
+
/** Where a request goes. */
|
|
44
|
+
export type ShellRoute =
|
|
45
|
+
/** A document navigation — network-first, cached-document fallback offline. */
|
|
46
|
+
'navigate'
|
|
47
|
+
/** A same-origin static asset (JS/CSS/WASM/font/image/JSON) — cache-first. */
|
|
48
|
+
| 'asset'
|
|
49
|
+
/** An auth-gated API call — never cached, never answered from a cache. */
|
|
50
|
+
| 'api'
|
|
51
|
+
/** Everything else (non-GET, cross-origin, `passthroughPrefixes`) — untouched. */
|
|
52
|
+
| 'passthrough';
|
|
53
|
+
/** The facts about a request that classification reads — nothing else. */
|
|
54
|
+
export interface RequestFacts {
|
|
55
|
+
method: string;
|
|
56
|
+
/** Same origin as the worker (`new URL(request.url).origin === location.origin`). */
|
|
57
|
+
sameOrigin: boolean;
|
|
58
|
+
/** URL pathname, no query. */
|
|
59
|
+
pathname: string;
|
|
60
|
+
/** `request.mode === 'navigate'`. */
|
|
61
|
+
isNavigate: boolean;
|
|
62
|
+
}
|
|
63
|
+
export interface ShellWorkerConfig {
|
|
64
|
+
/**
|
|
65
|
+
* Every cache this worker owns is named `<cachePrefix><version>`, and `activate`
|
|
66
|
+
* deletes every OTHER cache starting with `cachePrefix`. So the prefix must be one
|
|
67
|
+
* nothing else in the app shares — `roms-shell-`, not `roms-`, or the app's own
|
|
68
|
+
* digest-keyed caches go with it.
|
|
69
|
+
*/
|
|
70
|
+
cachePrefix: string;
|
|
71
|
+
/** Bump to evict the previous shell on the next activate. */
|
|
72
|
+
version: string;
|
|
73
|
+
/**
|
|
74
|
+
* Same-origin paths fetched into the cache at install. `shellPath` is always
|
|
75
|
+
* precached whether listed or not — a shell fallback with no shell is no fallback.
|
|
76
|
+
*/
|
|
77
|
+
precache: readonly string[];
|
|
78
|
+
/**
|
|
79
|
+
* Extra API prefixes. `/api/` is ALWAYS one of them and cannot be removed — see the
|
|
80
|
+
* header. Default: `['/api/']`.
|
|
81
|
+
*/
|
|
82
|
+
apiPrefixes?: readonly string[];
|
|
83
|
+
/**
|
|
84
|
+
* Same-origin prefixes the worker must leave alone even for GET assets — e.g. roms'
|
|
85
|
+
* `/_nes-roms/`, whose bytes the app caches itself under a content digest.
|
|
86
|
+
*/
|
|
87
|
+
passthroughPrefixes?: readonly string[];
|
|
88
|
+
/**
|
|
89
|
+
* Exact pathnames that must NEVER be answered with the shell offline (roms'
|
|
90
|
+
* `/emulator-frame.html`). An offline miss on one rejects instead. See the header.
|
|
91
|
+
*/
|
|
92
|
+
noShellFallback?: readonly string[];
|
|
93
|
+
/** Which same-origin pathnames count as static assets. Default: `DEFAULT_ASSET_EXT`. */
|
|
94
|
+
assetExtensions?: RegExp;
|
|
95
|
+
/** The app shell's path, the navigation fallback. Default: `'/'`. */
|
|
96
|
+
shellPath?: string;
|
|
97
|
+
}
|
|
98
|
+
/** A config with every default applied and every refusal already checked. */
|
|
99
|
+
export interface ResolvedShellWorkerConfig {
|
|
100
|
+
cachePrefix: string;
|
|
101
|
+
version: string;
|
|
102
|
+
cacheName: string;
|
|
103
|
+
precache: readonly string[];
|
|
104
|
+
apiPrefixes: readonly string[];
|
|
105
|
+
passthroughPrefixes: readonly string[];
|
|
106
|
+
noShellFallback: readonly string[];
|
|
107
|
+
assetExtensions: RegExp;
|
|
108
|
+
shellPath: string;
|
|
109
|
+
}
|
|
110
|
+
/** roms' `ASSET_EXT`, verbatim. */
|
|
111
|
+
export declare const DEFAULT_ASSET_EXT: RegExp;
|
|
112
|
+
/** Always an API prefix, whatever the config says. */
|
|
113
|
+
export declare const ALWAYS_API_PREFIX = "/api/";
|
|
114
|
+
/**
|
|
115
|
+
* Classify a request. Order matters and is roms' order: non-GET and cross-origin
|
|
116
|
+
* first, then the API (so an API path that happens to end in `.json` is still `api`),
|
|
117
|
+
* then the app's own passthrough prefixes, then navigation, then assets.
|
|
118
|
+
*/
|
|
119
|
+
export declare function classifyRequest(facts: RequestFacts, config?: Pick<ShellWorkerConfig, 'apiPrefixes' | 'passthroughPrefixes' | 'assetExtensions'>): ShellRoute;
|
|
120
|
+
/** Whether a response on this route may be written to the cache. Never `api`. */
|
|
121
|
+
export declare function shouldCache(route: ShellRoute): boolean;
|
|
122
|
+
/** May an offline miss on this navigation be answered with the shell? */
|
|
123
|
+
export declare function mayFallBackToShell(pathname: string, config?: Pick<ShellWorkerConfig, 'noShellFallback'>): boolean;
|
|
124
|
+
/**
|
|
125
|
+
* Apply defaults and refuse the configs that would break a promise in the header.
|
|
126
|
+
* `installShellWorker` calls this; it is exported so an app's own test can prove its
|
|
127
|
+
* config is accepted without standing up a worker.
|
|
128
|
+
*/
|
|
129
|
+
export declare function resolveShellWorkerConfig(config: ShellWorkerConfig): ResolvedShellWorkerConfig;
|
|
130
|
+
export interface ShellWorkerRequest {
|
|
131
|
+
readonly url: string;
|
|
132
|
+
readonly method: string;
|
|
133
|
+
readonly mode: string;
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* The structural mirror of `RequestInfo | URL` — a request, a string, or a URL-like —
|
|
137
|
+
* which is what the real `fetch`, `Cache` and `CacheStorage` accept. It has to be the
|
|
138
|
+
* whole union: with `ShellWorkerRequest` alone the real `self` is refused, because a
|
|
139
|
+
* `URL` is not a request in either direction (measured by the webworker spec).
|
|
140
|
+
*/
|
|
141
|
+
export type ShellWorkerRequestInfo = ShellWorkerRequest | string | {
|
|
142
|
+
readonly href: string;
|
|
143
|
+
};
|
|
144
|
+
export interface ShellWorkerResponse {
|
|
145
|
+
readonly ok: boolean;
|
|
146
|
+
clone(): ShellWorkerResponse;
|
|
147
|
+
}
|
|
148
|
+
export interface ShellWorkerCache {
|
|
149
|
+
addAll(requests: string[]): Promise<void>;
|
|
150
|
+
put(request: ShellWorkerRequestInfo, response: ShellWorkerResponse): Promise<void>;
|
|
151
|
+
}
|
|
152
|
+
export interface ShellWorkerCacheStorage {
|
|
153
|
+
open(cacheName: string): Promise<ShellWorkerCache>;
|
|
154
|
+
keys(): Promise<string[]>;
|
|
155
|
+
delete(cacheName: string): Promise<boolean>;
|
|
156
|
+
match(request: ShellWorkerRequestInfo, options?: {
|
|
157
|
+
ignoreSearch?: boolean;
|
|
158
|
+
}): Promise<ShellWorkerResponse | undefined>;
|
|
159
|
+
}
|
|
160
|
+
export interface ShellExtendableEvent {
|
|
161
|
+
waitUntil(promise: Promise<unknown>): void;
|
|
162
|
+
}
|
|
163
|
+
export interface ShellFetchEvent extends ShellExtendableEvent {
|
|
164
|
+
readonly request: ShellWorkerRequest;
|
|
165
|
+
respondWith(response: Promise<ShellWorkerResponse>): void;
|
|
166
|
+
}
|
|
167
|
+
export interface ShellWorkerScope {
|
|
168
|
+
addEventListener(type: 'install', listener: (event: ShellExtendableEvent) => void): void;
|
|
169
|
+
addEventListener(type: 'activate', listener: (event: ShellExtendableEvent) => void): void;
|
|
170
|
+
addEventListener(type: 'fetch', listener: (event: ShellFetchEvent) => void): void;
|
|
171
|
+
readonly caches: ShellWorkerCacheStorage;
|
|
172
|
+
readonly clients: {
|
|
173
|
+
claim(): Promise<void>;
|
|
174
|
+
};
|
|
175
|
+
readonly location: {
|
|
176
|
+
readonly origin: string;
|
|
177
|
+
};
|
|
178
|
+
fetch(request: ShellWorkerRequestInfo): Promise<ShellWorkerResponse>;
|
|
179
|
+
skipWaiting(): Promise<void>;
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Wire `install`, `activate` and `fetch` onto `scope` (the worker's `self`).
|
|
183
|
+
* Returns the resolved config, so an app can read `cacheName` for its own use.
|
|
184
|
+
*/
|
|
185
|
+
export declare function installShellWorker(scope: ShellWorkerScope, config: ShellWorkerConfig): ResolvedShellWorkerConfig;
|