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
@@ -0,0 +1,200 @@
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
+ /** roms' `ASSET_EXT`, verbatim. */
44
+ export const DEFAULT_ASSET_EXT = /\.(?:js|mjs|css|wasm|woff2?|ttf|png|jpe?g|webp|svg|ico|json)$/i;
45
+ /** Always an API prefix, whatever the config says. */
46
+ export const ALWAYS_API_PREFIX = '/api/';
47
+ const apiPrefixesOf = (config) => {
48
+ const extra = config.apiPrefixes ?? [];
49
+ return extra.includes(ALWAYS_API_PREFIX) ? extra : [ALWAYS_API_PREFIX, ...extra];
50
+ };
51
+ const startsWithAny = (pathname, prefixes) => prefixes.some((prefix) => pathname.startsWith(prefix));
52
+ /**
53
+ * Classify a request. Order matters and is roms' order: non-GET and cross-origin
54
+ * first, then the API (so an API path that happens to end in `.json` is still `api`),
55
+ * then the app's own passthrough prefixes, then navigation, then assets.
56
+ */
57
+ export function classifyRequest(facts, config = {}) {
58
+ if (facts.method !== 'GET')
59
+ return 'passthrough';
60
+ if (!facts.sameOrigin)
61
+ return 'passthrough';
62
+ if (startsWithAny(facts.pathname, apiPrefixesOf(config)))
63
+ return 'api';
64
+ if (startsWithAny(facts.pathname, config.passthroughPrefixes ?? []))
65
+ return 'passthrough';
66
+ if (facts.isNavigate)
67
+ return 'navigate';
68
+ if ((config.assetExtensions ?? DEFAULT_ASSET_EXT).test(facts.pathname))
69
+ return 'asset';
70
+ return 'passthrough';
71
+ }
72
+ /** Whether a response on this route may be written to the cache. Never `api`. */
73
+ export function shouldCache(route) {
74
+ return route === 'asset' || route === 'navigate';
75
+ }
76
+ /** May an offline miss on this navigation be answered with the shell? */
77
+ export function mayFallBackToShell(pathname, config = {}) {
78
+ return !(config.noShellFallback ?? []).includes(pathname);
79
+ }
80
+ /**
81
+ * Apply defaults and refuse the configs that would break a promise in the header.
82
+ * `installShellWorker` calls this; it is exported so an app's own test can prove its
83
+ * config is accepted without standing up a worker.
84
+ */
85
+ export function resolveShellWorkerConfig(config) {
86
+ if (config.cachePrefix.trim() === '') {
87
+ // An empty prefix makes EVERY cache on the origin "an old version of ours", and
88
+ // activate would delete the app's other caches with it.
89
+ throw new Error('shell worker: cachePrefix must not be empty — activate deletes every cache it prefixes');
90
+ }
91
+ if (config.version.trim() === '')
92
+ throw new Error('shell worker: version must not be empty');
93
+ const shellPath = config.shellPath ?? '/';
94
+ const apiPrefixes = apiPrefixesOf(config);
95
+ const precache = config.precache.includes(shellPath) ? [...config.precache] : [shellPath, ...config.precache];
96
+ for (const path of precache) {
97
+ if (!path.startsWith('/')) {
98
+ throw new Error(`shell worker: precache entry "${path}" must be a same-origin path starting with "/"`);
99
+ }
100
+ if (startsWithAny(path, apiPrefixes)) {
101
+ throw new Error(`shell worker: precache entry "${path}" is under an API prefix — the API is never cached`);
102
+ }
103
+ }
104
+ if (config.noShellFallback?.includes(shellPath)) {
105
+ throw new Error(`shell worker: the shell path "${shellPath}" cannot also be in noShellFallback`);
106
+ }
107
+ return {
108
+ cachePrefix: config.cachePrefix,
109
+ version: config.version,
110
+ cacheName: `${config.cachePrefix}${config.version}`,
111
+ precache,
112
+ apiPrefixes,
113
+ passthroughPrefixes: config.passthroughPrefixes ?? [],
114
+ noShellFallback: config.noShellFallback ?? [],
115
+ assetExtensions: config.assetExtensions ?? DEFAULT_ASSET_EXT,
116
+ shellPath,
117
+ };
118
+ }
119
+ /**
120
+ * Wire `install`, `activate` and `fetch` onto `scope` (the worker's `self`).
121
+ * Returns the resolved config, so an app can read `cacheName` for its own use.
122
+ */
123
+ export function installShellWorker(scope, config) {
124
+ const resolved = resolveShellWorkerConfig(config);
125
+ const { caches } = scope;
126
+ // Written after the response is handed back, like roms' `cache.put` — but kept
127
+ // alive with `waitUntil` so the worker is not stopped mid-write, and swallowed on
128
+ // failure: a full quota must not turn a good network response into an error.
129
+ const store = (event, route, response) => {
130
+ if (!shouldCache(route) || !response.ok)
131
+ return;
132
+ const copy = response.clone();
133
+ event.waitUntil(caches
134
+ .open(resolved.cacheName)
135
+ .then((cache) => cache.put(event.request, copy))
136
+ .catch(() => undefined));
137
+ };
138
+ const cacheFirst = async (event) => {
139
+ const cached = await caches.match(event.request);
140
+ if (cached)
141
+ return cached;
142
+ const response = await scope.fetch(event.request);
143
+ store(event, 'asset', response);
144
+ return response;
145
+ };
146
+ const networkFirst = async (event) => {
147
+ const { request } = event;
148
+ try {
149
+ const response = await scope.fetch(request);
150
+ store(event, 'navigate', response);
151
+ return response;
152
+ }
153
+ catch (error) {
154
+ // Offline. The exact URL first, then the same path ignoring the query — roms'
155
+ // frame is `/emulator-frame.html?system=nes`, and one cached copy answers for
156
+ // every console.
157
+ const cached = (await caches.match(request)) ?? (await caches.match(request, { ignoreSearch: true }));
158
+ if (cached)
159
+ return cached;
160
+ if (mayFallBackToShell(new URL(request.url).pathname, resolved)) {
161
+ const shell = await caches.match(resolved.shellPath);
162
+ if (shell)
163
+ return shell;
164
+ }
165
+ // Nothing honest to serve: reject, and the browser shows its own offline page
166
+ // rather than a document that is not the one asked for.
167
+ throw error;
168
+ }
169
+ };
170
+ scope.addEventListener('install', (event) => {
171
+ event.waitUntil(caches
172
+ .open(resolved.cacheName)
173
+ .then((cache) => cache.addAll([...resolved.precache]))
174
+ .then(() => scope.skipWaiting()));
175
+ });
176
+ scope.addEventListener('activate', (event) => {
177
+ event.waitUntil(caches
178
+ .keys()
179
+ .then((keys) => Promise.all(keys
180
+ .filter((key) => key.startsWith(resolved.cachePrefix) && key !== resolved.cacheName)
181
+ .map((key) => caches.delete(key))))
182
+ .then(() => scope.clients.claim()));
183
+ });
184
+ scope.addEventListener('fetch', (event) => {
185
+ const url = new URL(event.request.url);
186
+ const route = classifyRequest({
187
+ method: event.request.method,
188
+ sameOrigin: url.origin === scope.location.origin,
189
+ pathname: url.pathname,
190
+ isNavigate: event.request.mode === 'navigate',
191
+ }, resolved);
192
+ if (route === 'asset')
193
+ event.respondWith(cacheFirst(event));
194
+ else if (route === 'navigate')
195
+ event.respondWith(networkFirst(event));
196
+ // `api` and `passthrough`: no respondWith, so the browser goes to the network as
197
+ // if this worker did not exist. Never a cache read, never a cache write.
198
+ });
199
+ return resolved;
200
+ }
@@ -1,4 +1,4 @@
1
- import type { NavItem } from '../navigation';
1
+ import type { NavItem } from '../navigation/index.js';
2
2
  /**
3
3
  * The initials of a multi-word label (`'Query Builder'` → `'qb'`). Single-word labels
4
4
  * return `''` (their prefix already matches via the label itself). Powers initialism
@@ -1,3 +1,3 @@
1
- export { fuzzyRankItems, searchInitials, } from './fuzzyRank';
2
- export { formatHotkey, isApplePlatform, matchHotkey, type ParsedHotkey, parseHotkey, } from './hotkeys';
3
- export { type ShortcutEntry, ShortcutRegistry, shortcutRegistry, } from './ShortcutRegistry';
1
+ export { fuzzyRankItems, searchInitials, } from './fuzzyRank.js';
2
+ export { formatHotkey, isApplePlatform, matchHotkey, type ParsedHotkey, parseHotkey, } from './hotkeys.js';
3
+ export { type ShortcutEntry, ShortcutRegistry, shortcutRegistry, } from './ShortcutRegistry.js';
@@ -3,6 +3,6 @@
3
3
  // browser dependency beyond optional `navigator`/event reads — usable in a startup
4
4
  // module, a server test, or the React layer alike. The `CommandPalette` component +
5
5
  // its hooks live in `cursedbelt/react` and build on exactly this.
6
- export { fuzzyRankItems, searchInitials, } from './fuzzyRank';
7
- export { formatHotkey, isApplePlatform, matchHotkey, parseHotkey, } from './hotkeys';
8
- export { ShortcutRegistry, shortcutRegistry, } from './ShortcutRegistry';
6
+ export { fuzzyRankItems, searchInitials, } from './fuzzyRank.js';
7
+ export { formatHotkey, isApplePlatform, matchHotkey, parseHotkey, } from './hotkeys.js';
8
+ export { ShortcutRegistry, shortcutRegistry, } from './ShortcutRegistry.js';
@@ -1,5 +1,5 @@
1
1
  /** The fleet's sharing/access vocabulary — see `./model.ts` for the whole
2
2
  * contract. Storage lives in `cursedbelt-server/sharing`, the UI in
3
3
  * `cursedbelt/react/sharing`; both speak these words. */
4
- export { accessMeets, describeAccess, describeShareEvent, isShareAccess, isShareLevel, isShareSubjectType, levelsMeeting, normalizeSubject, normalizeSubjectId, resolveAccess, resourceKey, sameResource, sameSubject, SHARE_ACTIONS, strongerAccess, } from "./model";
5
- export type { ShareAccess, ShareAction, ShareEvent, ShareGrant, ShareGroup, ShareGroupMember, ShareLevel, ShareResource, ShareSubject, ShareSubjectType, ShareViewer, } from "./model";
4
+ export { accessMeets, describeAccess, describeShareEvent, isShareAccess, isShareLevel, isShareSubjectType, levelsMeeting, normalizeSubject, normalizeSubjectId, resolveAccess, resourceKey, sameResource, sameSubject, SHARE_ACTIONS, strongerAccess, } from "./model.js";
5
+ export type { ShareAccess, ShareAction, ShareEvent, ShareGrant, ShareGroup, ShareGroupMember, ShareLevel, ShareResource, ShareSubject, ShareSubjectType, ShareViewer, } from "./model.js";
@@ -1,4 +1,4 @@
1
1
  /** The fleet's sharing/access vocabulary — see `./model.ts` for the whole
2
2
  * contract. Storage lives in `cursedbelt-server/sharing`, the UI in
3
3
  * `cursedbelt/react/sharing`; both speak these words. */
4
- export { accessMeets, describeAccess, describeShareEvent, isShareAccess, isShareLevel, isShareSubjectType, levelsMeeting, normalizeSubject, normalizeSubjectId, resolveAccess, resourceKey, sameResource, sameSubject, SHARE_ACTIONS, strongerAccess, } from "./model";
4
+ export { accessMeets, describeAccess, describeShareEvent, isShareAccess, isShareLevel, isShareSubjectType, levelsMeeting, normalizeSubject, normalizeSubjectId, resolveAccess, resourceKey, sameResource, sameSubject, SHARE_ACTIONS, strongerAccess, } from "./model.js";
@@ -50,8 +50,8 @@ export interface TokenDef<S extends z.ZodType = z.ZodType> {
50
50
  * They used to be a second, divergent declaration of the same names — see the
51
51
  * unification note on `CCWireMarshaller` (05 §B1).
52
52
  */
53
- import type { CCWireMarshaller } from '../wire/marshalling';
54
- export { type CCWireMarshaller, MARSHALLER_WORKER_OFFLOAD_BYTES, requiresWorkerOffload, } from '../wire/marshalling';
53
+ import type { CCWireMarshaller } from '../wire/marshalling.js';
54
+ export { type CCWireMarshaller, MARSHALLER_WORKER_OFFLOAD_BYTES, requiresWorkerOffload, } from '../wire/marshalling.js';
55
55
  export type TokenRegistryIssueCode = 'token-collision' | 'token-namespace-violation' | 'subtype-inversion' | 'token-supertype-missing' | 'token-subtype-cycle' | 'token-sample-invalid';
56
56
  export interface TokenRegistryIssue {
57
57
  code: TokenRegistryIssueCode;
@@ -19,7 +19,7 @@
19
19
  * (the core would stop compiling the moment the plugin is deleted).
20
20
  */
21
21
  import { z } from 'zod';
22
- export { MARSHALLER_WORKER_OFFLOAD_BYTES, requiresWorkerOffload, } from '../wire/marshalling';
22
+ export { MARSHALLER_WORKER_OFFLOAD_BYTES, requiresWorkerOffload, } from '../wire/marshalling.js';
23
23
  const TOKEN_ID_RE = /^[a-z][a-z0-9-]*:[a-z0-9-]+$/;
24
24
  const EXTENSION_ID_RE = /^x-[a-z0-9-]+:[a-z0-9-]+$/;
25
25
  export const isExtensionTokenId = (id) => id.startsWith('x-');
@@ -4,5 +4,5 @@
4
4
  * the saved size on app boot (before React mounts → no flash); the React control +
5
5
  * hook live in `cursedbelt/react`.
6
6
  */
7
- export { clampUiScale, DEFAULT_UI_SCALE, MAX_UI_SCALE, MIN_UI_SCALE, nearestUiScaleLevel, stepUiScale, UI_SCALE_LEVELS, UI_SCALE_STEP, type UiScaleLevel, type UiScaleLevelId, uiScaleToFontSize, } from './scale';
8
- export { applyUiScaleToDocument, createUiScaleStore, getUiScale, initUiScale, setUiScale, subscribeUiScale, UI_SCALE_STORAGE_KEY, type UiScaleStorage, type UiScaleStore, type UiScaleStoreOptions, uiScaleStore, } from './uiScaleStore';
7
+ export { clampUiScale, DEFAULT_UI_SCALE, MAX_UI_SCALE, MIN_UI_SCALE, nearestUiScaleLevel, stepUiScale, UI_SCALE_LEVELS, UI_SCALE_STEP, type UiScaleLevel, type UiScaleLevelId, uiScaleToFontSize, } from './scale.js';
8
+ export { applyUiScaleToDocument, createUiScaleStore, getUiScale, initUiScale, setUiScale, subscribeUiScale, UI_SCALE_STORAGE_KEY, type UiScaleStorage, type UiScaleStore, type UiScaleStoreOptions, uiScaleStore, } from './uiScaleStore.js';
@@ -4,5 +4,5 @@
4
4
  * the saved size on app boot (before React mounts → no flash); the React control +
5
5
  * hook live in `cursedbelt/react`.
6
6
  */
7
- export { clampUiScale, DEFAULT_UI_SCALE, MAX_UI_SCALE, MIN_UI_SCALE, nearestUiScaleLevel, stepUiScale, UI_SCALE_LEVELS, UI_SCALE_STEP, uiScaleToFontSize, } from './scale';
8
- export { applyUiScaleToDocument, createUiScaleStore, getUiScale, initUiScale, setUiScale, subscribeUiScale, UI_SCALE_STORAGE_KEY, uiScaleStore, } from './uiScaleStore';
7
+ export { clampUiScale, DEFAULT_UI_SCALE, MAX_UI_SCALE, MIN_UI_SCALE, nearestUiScaleLevel, stepUiScale, UI_SCALE_LEVELS, UI_SCALE_STEP, uiScaleToFontSize, } from './scale.js';
8
+ export { applyUiScaleToDocument, createUiScaleStore, getUiScale, initUiScale, setUiScale, subscribeUiScale, UI_SCALE_STORAGE_KEY, uiScaleStore, } from './uiScaleStore.js';
@@ -8,7 +8,7 @@
8
8
  * real store with fakes; the exported default singleton binds them to
9
9
  * `localStorage` + the `<html>` element.
10
10
  */
11
- import { clampUiScale, DEFAULT_UI_SCALE, stepUiScale, uiScaleToFontSize } from './scale';
11
+ import { clampUiScale, DEFAULT_UI_SCALE, stepUiScale, uiScaleToFontSize } from './scale.js';
12
12
  export const UI_SCALE_STORAGE_KEY = 'cwip.uiScale';
13
13
  export function createUiScaleStore(options = {}) {
14
14
  const { storage = null, apply, key = UI_SCALE_STORAGE_KEY } = options;
@@ -8,7 +8,7 @@
8
8
  * and the worker imports it.
9
9
  */
10
10
  import { z } from 'zod';
11
- import { serveMarshalWorker } from '../marshalWorker';
11
+ import { serveMarshalWorker } from '../marshalWorker.js';
12
12
  const schema = z.object({ rows: z.array(z.object({ id: z.string() })) });
13
13
  await serveMarshalWorker({
14
14
  id: 'rows',
@@ -11,7 +11,7 @@
11
11
  * `wireHub` is re-exported from `cursedbelt-cc/client` as well; that entry is where
12
12
  * a shell host looks, this one is where the wire tier lives.
13
13
  */
14
- export { type CCWireMarshaller, createMarshallerRegistry, MARSHALLER_PAYLOAD_TOO_LARGE, MARSHALLER_SCHEMA_VIOLATION, MARSHALLER_VALIDATION_FAILED, MARSHALLER_WORKER_OFFLOAD_BYTES, type MarshallerRegistry, type MarshalOptions, type MarshalWorker, marshalInbound, payloadBytes, requiresWorkerOffload, } from './marshalling';
15
- export { createMarshalWorkerClient, MARSHAL_WORKER_DEFAULT_TIMEOUT_MS, MARSHALLER_WORKER_FAILED, MARSHALLER_WORKER_TIMEOUT, type MarshalWorkerClient, type MarshalWorkerClientOptions, type MarshalWorkerRequest, type MarshalWorkerResponse, serveMarshalWorker, } from './marshalWorker';
16
- export { createMarshalledIngress, INGRESS_TOKEN_UNKNOWN, type MarshalledIngress, type MarshalledIngressOptions, } from './ingress';
17
- export { createInstanceRuntime, createWireHub, type InstanceRuntime, type InstanceRuntimeOptions, type WireEnvelope, type WireHub, type WireHubOptions, } from './wireHub';
14
+ export { type CCWireMarshaller, createMarshallerRegistry, MARSHALLER_PAYLOAD_TOO_LARGE, MARSHALLER_SCHEMA_VIOLATION, MARSHALLER_VALIDATION_FAILED, MARSHALLER_WORKER_OFFLOAD_BYTES, type MarshallerRegistry, type MarshalOptions, type MarshalWorker, marshalInbound, payloadBytes, requiresWorkerOffload, } from './marshalling.js';
15
+ export { createMarshalWorkerClient, MARSHAL_WORKER_DEFAULT_TIMEOUT_MS, MARSHALLER_WORKER_FAILED, MARSHALLER_WORKER_TIMEOUT, type MarshalWorkerClient, type MarshalWorkerClientOptions, type MarshalWorkerRequest, type MarshalWorkerResponse, serveMarshalWorker, } from './marshalWorker.js';
16
+ export { createMarshalledIngress, INGRESS_TOKEN_UNKNOWN, type MarshalledIngress, type MarshalledIngressOptions, } from './ingress.js';
17
+ export { createInstanceRuntime, createWireHub, type InstanceRuntime, type InstanceRuntimeOptions, type WireEnvelope, type WireHub, type WireHubOptions, } from './wireHub.js';
@@ -11,7 +11,7 @@
11
11
  * `wireHub` is re-exported from `cursedbelt-cc/client` as well; that entry is where
12
12
  * a shell host looks, this one is where the wire tier lives.
13
13
  */
14
- export { createMarshallerRegistry, MARSHALLER_PAYLOAD_TOO_LARGE, MARSHALLER_SCHEMA_VIOLATION, MARSHALLER_VALIDATION_FAILED, MARSHALLER_WORKER_OFFLOAD_BYTES, marshalInbound, payloadBytes, requiresWorkerOffload, } from './marshalling';
15
- export { createMarshalWorkerClient, MARSHAL_WORKER_DEFAULT_TIMEOUT_MS, MARSHALLER_WORKER_FAILED, MARSHALLER_WORKER_TIMEOUT, serveMarshalWorker, } from './marshalWorker';
16
- export { createMarshalledIngress, INGRESS_TOKEN_UNKNOWN, } from './ingress';
17
- export { createInstanceRuntime, createWireHub, } from './wireHub';
14
+ export { createMarshallerRegistry, MARSHALLER_PAYLOAD_TOO_LARGE, MARSHALLER_SCHEMA_VIOLATION, MARSHALLER_VALIDATION_FAILED, MARSHALLER_WORKER_OFFLOAD_BYTES, marshalInbound, payloadBytes, requiresWorkerOffload, } from './marshalling.js';
15
+ export { createMarshalWorkerClient, MARSHAL_WORKER_DEFAULT_TIMEOUT_MS, MARSHALLER_WORKER_FAILED, MARSHALLER_WORKER_TIMEOUT, serveMarshalWorker, } from './marshalWorker.js';
16
+ export { createMarshalledIngress, INGRESS_TOKEN_UNKNOWN, } from './ingress.js';
17
+ export { createInstanceRuntime, createWireHub, } from './wireHub.js';
@@ -1,4 +1,4 @@
1
- import { type MarshallerRegistry } from './marshalling';
1
+ import { type MarshallerRegistry } from './marshalling.js';
2
2
  /** No marshaller is registered for the token an ingress was asked to feed. */
3
3
  export declare const INGRESS_TOKEN_UNKNOWN = "INGRESS_TOKEN_UNKNOWN";
4
4
  export interface MarshalledIngressOptions {
@@ -50,9 +50,9 @@
50
50
  * A CSV import is the same three lines with a different marshaller and a
51
51
  * different service call. Neither needs to know that a worker exists.
52
52
  */
53
- import { AppError } from '../../shared/errors';
54
- import { createMarshalWorkerClient } from './marshalWorker';
55
- import { marshalInbound, } from './marshalling';
53
+ import { AppError } from '../../shared/errors.js';
54
+ import { createMarshalWorkerClient } from './marshalWorker.js';
55
+ import { marshalInbound, } from './marshalling.js';
56
56
  /** No marshaller is registered for the token an ingress was asked to feed. */
57
57
  export const INGRESS_TOKEN_UNKNOWN = 'INGRESS_TOKEN_UNKNOWN';
58
58
  /**
@@ -1,4 +1,4 @@
1
- import { type CCWireMarshaller, MARSHALLER_SCHEMA_VIOLATION, MARSHALLER_VALIDATION_FAILED, type MarshalWorker } from './marshalling';
1
+ import { type CCWireMarshaller, MARSHALLER_SCHEMA_VIOLATION, MARSHALLER_VALIDATION_FAILED, type MarshalWorker } from './marshalling.js';
2
2
  export declare const MARSHALLER_WORKER_FAILED = "MARSHALLER_WORKER_FAILED";
3
3
  export declare const MARSHALLER_WORKER_TIMEOUT = "MARSHALLER_WORKER_TIMEOUT";
4
4
  /** How long one payload may occupy the worker before the host gives up. */
@@ -33,8 +33,8 @@
33
33
  * inside the server branch — a static import would put a Node builtin in the
34
34
  * module graph of every client bundle that touches wire code.
35
35
  */
36
- import { AppError } from '../../shared/errors';
37
- import { MARSHALLER_SCHEMA_VIOLATION, MARSHALLER_VALIDATION_FAILED, } from './marshalling';
36
+ import { AppError } from '../../shared/errors.js';
37
+ import { MARSHALLER_SCHEMA_VIOLATION, MARSHALLER_VALIDATION_FAILED, } from './marshalling.js';
38
38
  export const MARSHALLER_WORKER_FAILED = 'MARSHALLER_WORKER_FAILED';
39
39
  export const MARSHALLER_WORKER_TIMEOUT = 'MARSHALLER_WORKER_TIMEOUT';
40
40
  /** How long one payload may occupy the worker before the host gives up. */
@@ -1,4 +1,4 @@
1
- import { AppError } from '../../shared/errors';
1
+ import { AppError } from '../../shared/errors.js';
2
2
  /** Above this, `validate` + `transform` are offloaded to a Worker (02 §7.1). */
3
3
  export const MARSHALLER_WORKER_OFFLOAD_BYTES = 512 * 1024;
4
4
  /**
@@ -61,7 +61,7 @@
61
61
  * - Inconsistency errors (e.g., second chunk claims different total count) delete the entry immediately; recovery requires retransmitting all chunks from the client
62
62
  * - The service itself is a singleton; do NOT create multiple instances per server or request thread
63
63
  */
64
- import type { CtgrDecoded } from './types';
64
+ import type { CtgrDecoded } from './types.js';
65
65
  /**
66
66
  * Configuration for ChunkAccumulator resource limits and timing behavior.
67
67
  *
@@ -61,8 +61,8 @@
61
61
  * - Inconsistency errors (e.g., second chunk claims different total count) delete the entry immediately; recovery requires retransmitting all chunks from the client
62
62
  * - The service itself is a singleton; do NOT create multiple instances per server or request thread
63
63
  */
64
- import { decodePayload, parseChunk } from './codec';
65
- import { sha256Hex } from './digest';
64
+ import { decodePayload, parseChunk } from './codec.js';
65
+ import { sha256Hex } from './digest.js';
66
66
  /**
67
67
  * ChunkAccumulator — The hardened service for multi-chunk payload assembly.
68
68
  *
@@ -1,4 +1,4 @@
1
- import type { CtgrDecoded } from './types';
1
+ import type { CtgrDecoded } from './types.js';
2
2
  export interface ChunkStoreOpts {
3
3
  /** Max concurrent in-flight (incomplete) payloads. Default 200. */
4
4
  maxInFlight?: number;
@@ -9,8 +9,8 @@
9
9
  * It NEVER throws: a malformed/corrupt/oversized payload returns an `Error` the
10
10
  * middleware maps to a 400; an intermediate chunk returns `false` (→ 202).
11
11
  */
12
- import { decodePayload, parseChunk } from './codec';
13
- import { sha256Hex } from './digest';
12
+ import { decodePayload, parseChunk } from './codec.js';
13
+ import { sha256Hex } from './digest.js';
14
14
  export class ChunkStore {
15
15
  entries = new Map();
16
16
  maxInFlight;
@@ -1,4 +1,4 @@
1
- import { type CtgrDecoded, type CtgrMethod, type EncodedRequest, type EncodeOpts, type UploadedFile } from './types';
1
+ import { type CtgrDecoded, type CtgrMethod, type EncodedRequest, type EncodeOpts, type UploadedFile } from './types.js';
2
2
  /**
3
3
  * Encode a mutating request into one or more `/ctgr<XX>` GET-twin chunks. Small
4
4
  * bodies become a single chunk; large bodies gzip (when over the threshold) and split
@@ -11,11 +11,11 @@
11
11
  * double-base64'd and whose swap/reverse was trivially-reversible obfuscation, not
12
12
  * protection — the real protection (getOnly JWT claim + CSRF guard) is unchanged.
13
13
  */
14
- import { fromBase64, fromBase64url, toBase64url } from './base64url';
15
- import { gunzip, gzip } from './compress';
16
- import { crc32 } from './crc32';
17
- import { sha256Hex } from './digest';
18
- import { ABBREV_TO_METHOD, CTGR_WIRE_VERSION, METHOD_TO_ABBREV, } from './types';
14
+ import { fromBase64, fromBase64url, toBase64url } from './base64url.js';
15
+ import { gunzip, gzip } from './compress.js';
16
+ import { crc32 } from './crc32.js';
17
+ import { sha256Hex } from './digest.js';
18
+ import { ABBREV_TO_METHOD, CTGR_WIRE_VERSION, METHOD_TO_ABBREV, } from './types.js';
19
19
  const DEFAULT_CHUNK_SIZE = 1800;
20
20
  const DEFAULT_GZIP_THRESHOLD = 1024;
21
21
  const textEncoder = new TextEncoder();
@@ -1,9 +1,9 @@
1
- export { fromBase64, fromBase64url, toBase64, toBase64url } from './base64url';
2
- export { ChunkAccumulator, type ChunkAccumulatorConfig, } from './chunkAccumulator';
3
- export { ChunkStore, type ChunkStoreOpts } from './chunkStore';
4
- export { decodePayload, decodeRequest, encodeRequest, extractFiles, type ParsedChunk, parseChunk, } from './codec';
5
- export { gunzip, gzip } from './compress';
6
- export { crc32 } from './crc32';
7
- export { sha256Hex } from './digest';
8
- export { ABBREV_TO_METHOD, CTGR_WIRE_VERSION, type CtgrAbbrev, type CtgrDecoded, type CtgrMethod, type EncodedChunk, type EncodedRequest, type EncodeOpts, METHOD_TO_ABBREV, type SerializedFile, type UploadedFile, } from './types';
9
- export { decodeV0Payload, V0ChunkStore, type V0ChunkStoreOpts } from './v0compat';
1
+ export { fromBase64, fromBase64url, toBase64, toBase64url } from './base64url.js';
2
+ export { ChunkAccumulator, type ChunkAccumulatorConfig, } from './chunkAccumulator.js';
3
+ export { ChunkStore, type ChunkStoreOpts } from './chunkStore.js';
4
+ export { decodePayload, decodeRequest, encodeRequest, extractFiles, type ParsedChunk, parseChunk, } from './codec.js';
5
+ export { gunzip, gzip } from './compress.js';
6
+ export { crc32 } from './crc32.js';
7
+ export { sha256Hex } from './digest.js';
8
+ export { ABBREV_TO_METHOD, CTGR_WIRE_VERSION, type CtgrAbbrev, type CtgrDecoded, type CtgrMethod, type EncodedChunk, type EncodedRequest, type EncodeOpts, METHOD_TO_ABBREV, type SerializedFile, type UploadedFile, } from './types.js';
9
+ export { decodeV0Payload, V0ChunkStore, type V0ChunkStoreOpts } from './v0compat.js';
@@ -6,12 +6,12 @@
6
6
  * The ChunkAccumulator is the primary abstraction for multi-chunk payload assembly;
7
7
  * ChunkStore is kept for backward compatibility (they are identical implementations).
8
8
  */
9
- export { fromBase64, fromBase64url, toBase64, toBase64url } from './base64url';
10
- export { ChunkAccumulator, } from './chunkAccumulator';
11
- export { ChunkStore } from './chunkStore';
12
- export { decodePayload, decodeRequest, encodeRequest, extractFiles, parseChunk, } from './codec';
13
- export { gunzip, gzip } from './compress';
14
- export { crc32 } from './crc32';
15
- export { sha256Hex } from './digest';
16
- export { ABBREV_TO_METHOD, CTGR_WIRE_VERSION, METHOD_TO_ABBREV, } from './types';
17
- export { decodeV0Payload, V0ChunkStore } from './v0compat';
9
+ export { fromBase64, fromBase64url, toBase64, toBase64url } from './base64url.js';
10
+ export { ChunkAccumulator, } from './chunkAccumulator.js';
11
+ export { ChunkStore } from './chunkStore.js';
12
+ export { decodePayload, decodeRequest, encodeRequest, extractFiles, parseChunk, } from './codec.js';
13
+ export { gunzip, gzip } from './compress.js';
14
+ export { crc32 } from './crc32.js';
15
+ export { sha256Hex } from './digest.js';
16
+ export { ABBREV_TO_METHOD, CTGR_WIRE_VERSION, METHOD_TO_ABBREV, } from './types.js';
17
+ export { decodeV0Payload, V0ChunkStore } from './v0compat.js';
@@ -1,4 +1,4 @@
1
- import type { CtgrDecoded, CtgrMethod } from './types';
1
+ import type { CtgrDecoded, CtgrMethod } from './types.js';
2
2
  /** Reverse the v0 client pipeline (`encode→reverse→swap→encode→swap`) and parse JSON. */
3
3
  export declare function decodeV0Payload(encoded: string): unknown;
4
4
  export interface V0ChunkStoreOpts {
@@ -9,8 +9,8 @@
9
9
  * heuristic, since v1 always sets `_cv=1`. v0 carried the method only in the path
10
10
  * (`/ctgr<XX>`), so the middleware passes the path-derived method in.
11
11
  */
12
- import { fromBase64 } from './base64url';
13
- import { extractFiles } from './codec';
12
+ import { fromBase64 } from './base64url.js';
13
+ import { extractFiles } from './codec.js';
14
14
  const decodeBase64Utf8 = (str) => new TextDecoder().decode(fromBase64(str));
15
15
  const reverseString = (str) => str.split('').reverse().join('');
16
16
  const swapEnds = (str) => {
package/dist/index.d.ts CHANGED
@@ -11,5 +11,5 @@
11
11
  * drag 47 dependencies into every consumer.
12
12
  */
13
13
  export declare const VERSION = "1.0.0";
14
- export { contrastText } from './core/color';
15
- export { isSiteCopyKey, SITE_COPY_BAKED_ONLY, SITE_COPY_DEFAULTS, SITE_COPY_KEYS, SITE_COPY_MAX_VALUE_LENGTH, type SiteCopyKey, } from './core/site/siteCopy';
14
+ export { contrastText } from './core/color.js';
15
+ export { isSiteCopyKey, SITE_COPY_BAKED_ONLY, SITE_COPY_DEFAULTS, SITE_COPY_KEYS, SITE_COPY_MAX_VALUE_LENGTH, type SiteCopyKey, } from './core/site/siteCopy.js';
package/dist/index.js CHANGED
@@ -13,5 +13,5 @@
13
13
  export const VERSION = '1.0.0';
14
14
  // The two root-level conveniences the pre-split "." barrel actually served:
15
15
  // the WCAG readable-foreground picker and the baked marketing-copy contract.
16
- export { contrastText } from './core/color';
17
- export { isSiteCopyKey, SITE_COPY_BAKED_ONLY, SITE_COPY_DEFAULTS, SITE_COPY_KEYS, SITE_COPY_MAX_VALUE_LENGTH, } from './core/site/siteCopy';
16
+ export { contrastText } from './core/color.js';
17
+ export { isSiteCopyKey, SITE_COPY_BAKED_ONLY, SITE_COPY_DEFAULTS, SITE_COPY_KEYS, SITE_COPY_MAX_VALUE_LENGTH, } from './core/site/siteCopy.js';
@@ -1,3 +1,3 @@
1
- export { installCheapDomInspect } from "./domInspect";
2
- export { asBody, bytesResponse, bytesStream } from "./bytes";
3
- export { type FetchImpl, fakeFetch } from "./fakeFetch";
1
+ export { installCheapDomInspect } from "./domInspect.js";
2
+ export { asBody, bytesResponse, bytesStream } from "./bytes.js";
3
+ export { type FetchImpl, fakeFetch } from "./fakeFetch.js";
@@ -6,6 +6,6 @@
6
6
  // can `import { installCheapDomInspect } from "cursedbelt-core/testing"` instead of
7
7
  // keeping a ~60-line hand-port of domInspect.ts — the file already lived here,
8
8
  // it just had no export.
9
- export { installCheapDomInspect } from "./domInspect";
10
- export { asBody, bytesResponse, bytesStream } from "./bytes";
11
- export { fakeFetch } from "./fakeFetch";
9
+ export { installCheapDomInspect } from "./domInspect.js";
10
+ export { asBody, bytesResponse, bytesStream } from "./bytes.js";
11
+ export { fakeFetch } from "./fakeFetch.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cursedbelt-core",
3
- "version": "2.1.0",
3
+ "version": "2.2.0",
4
4
  "license": "ISC",
5
5
  "type": "module",
6
6
  "description": "Framework-agnostic core of the cursedbelt split — isomorphic domain logic. cwip below it, cursedbelt-server and cursedbelt (react) above it.",
@@ -251,6 +251,12 @@
251
251
  "source": "./src/core/net/reconnectSchedule.ts",
252
252
  "import": "./dist/core/net/reconnectSchedule.js"
253
253
  },
254
+ "./offline/shell-worker": {
255
+ "types": "./dist/core/offline/shellWorker.d.ts",
256
+ "bun": "./src/core/offline/shellWorker.ts",
257
+ "source": "./src/core/offline/shellWorker.ts",
258
+ "import": "./dist/core/offline/shellWorker.js"
259
+ },
254
260
  "./palette": {
255
261
  "types": "./dist/core/palette/index.d.ts",
256
262
  "bun": "./src/core/palette/index.ts",
@@ -362,7 +368,7 @@
362
368
  },
363
369
  "dependencies": {
364
370
  "@leeoniya/ufuzzy": "^1.0.19",
365
- "cwip": "^4.1.0"
371
+ "cwip": "^4.6.0"
366
372
  },
367
373
  "peerDependencies": {
368
374
  "zod": "^4.4.0"
@@ -1,5 +1,5 @@
1
1
  import { describe, expect, it } from 'bun:test';
2
- import { AppConfigSchema, effectiveSignupMode, featureKeysOf, resolveInstanceFeatures, ROUTE_PATH_RE } from './appConfig';
2
+ import { AppConfigSchema, effectiveSignupMode, featureKeysOf, resolveInstanceFeatures, ROUTE_PATH_RE } from './appConfig.js';
3
3
 
4
4
  const base = (over: Record<string, unknown> = {}) => ({
5
5
  configVersion: 1,
@@ -12,10 +12,10 @@ export {
12
12
  describeActivityResource,
13
13
  isActivityAction,
14
14
  isActivityOutcome,
15
- } from "./model";
15
+ } from "./model.js";
16
16
  export type {
17
17
  ActivityEvent,
18
18
  ActivityEventInput,
19
19
  ActivityOutcome,
20
20
  ActivityResource,
21
- } from "./model";
21
+ } from "./model.js";