cursedbelt-core 1.0.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 (307) hide show
  1. package/LICENSE +15 -0
  2. package/dist/client/wsWire.d.ts +49 -0
  3. package/dist/client/wsWire.js +57 -0
  4. package/dist/config/appConfig.d.ts +361 -0
  5. package/dist/config/appConfig.js +308 -0
  6. package/dist/core/activity/index.d.ts +8 -0
  7. package/dist/core/activity/index.js +7 -0
  8. package/dist/core/activity/model.d.ts +115 -0
  9. package/dist/core/activity/model.js +63 -0
  10. package/dist/core/analytics/index.d.ts +18 -0
  11. package/dist/core/analytics/index.js +18 -0
  12. package/dist/core/analytics/range.d.ts +186 -0
  13. package/dist/core/analytics/range.js +271 -0
  14. package/dist/core/analytics/schedule.d.ts +301 -0
  15. package/dist/core/analytics/schedule.js +372 -0
  16. package/dist/core/category/index.d.ts +3 -0
  17. package/dist/core/category/index.js +6 -0
  18. package/dist/core/category/memoryStore.d.ts +21 -0
  19. package/dist/core/category/memoryStore.js +97 -0
  20. package/dist/core/category/tree.d.ts +26 -0
  21. package/dist/core/category/tree.js +113 -0
  22. package/dist/core/category/types.d.ts +48 -0
  23. package/dist/core/category/types.js +8 -0
  24. package/dist/core/color.d.ts +14 -0
  25. package/dist/core/color.js +32 -0
  26. package/dist/core/colorScheme/colorSchemeStore.d.ts +70 -0
  27. package/dist/core/colorScheme/colorSchemeStore.js +123 -0
  28. package/dist/core/colorScheme/index.d.ts +7 -0
  29. package/dist/core/colorScheme/index.js +7 -0
  30. package/dist/core/domainOwners.d.ts +19 -0
  31. package/dist/core/domainOwners.js +15 -0
  32. package/dist/core/download.d.ts +14 -0
  33. package/dist/core/download.js +37 -0
  34. package/dist/core/events/ccEventBus.d.ts +44 -0
  35. package/dist/core/events/ccEventBus.js +70 -0
  36. package/dist/core/file-tree/fileTreeModel.d.ts +276 -0
  37. package/dist/core/file-tree/fileTreeModel.js +312 -0
  38. package/dist/core/folder-tree/actions.d.ts +84 -0
  39. package/dist/core/folder-tree/actions.js +119 -0
  40. package/dist/core/folder-tree/index.d.ts +3 -0
  41. package/dist/core/folder-tree/index.js +20 -0
  42. package/dist/core/folder-tree/path.d.ts +76 -0
  43. package/dist/core/folder-tree/path.js +146 -0
  44. package/dist/core/folder-tree/tree.d.ts +86 -0
  45. package/dist/core/folder-tree/tree.js +184 -0
  46. package/dist/core/layout/index.d.ts +1 -0
  47. package/dist/core/layout/index.js +7 -0
  48. package/dist/core/master-lock/index.d.ts +14 -0
  49. package/dist/core/master-lock/index.js +14 -0
  50. package/dist/core/master-lock/kdf.d.ts +63 -0
  51. package/dist/core/master-lock/kdf.js +117 -0
  52. package/dist/core/master-lock/policy.d.ts +32 -0
  53. package/dist/core/master-lock/policy.js +52 -0
  54. package/dist/core/master-lock/presence.d.ts +52 -0
  55. package/dist/core/master-lock/presence.js +61 -0
  56. package/dist/core/master-lock/wire.d.ts +139 -0
  57. package/dist/core/master-lock/wire.js +81 -0
  58. package/dist/core/media/bgRemoval.d.ts +27 -0
  59. package/dist/core/media/bgRemoval.js +101 -0
  60. package/dist/core/media/ffmpeg.d.ts +57 -0
  61. package/dist/core/media/ffmpeg.js +126 -0
  62. package/dist/core/media/format.d.ts +20 -0
  63. package/dist/core/media/format.js +54 -0
  64. package/dist/core/media/index.d.ts +12 -0
  65. package/dist/core/media/index.js +18 -0
  66. package/dist/core/media/mediaItem.d.ts +15 -0
  67. package/dist/core/media/mediaItem.js +34 -0
  68. package/dist/core/media/renderPlan.d.ts +63 -0
  69. package/dist/core/media/renderPlan.js +232 -0
  70. package/dist/core/media/segment.d.ts +79 -0
  71. package/dist/core/media/segment.js +247 -0
  72. package/dist/core/media/size.d.ts +1 -0
  73. package/dist/core/media/size.js +3 -0
  74. package/dist/core/media/trim.d.ts +21 -0
  75. package/dist/core/media/trim.js +40 -0
  76. package/dist/core/media/types.d.ts +148 -0
  77. package/dist/core/media/types.js +11 -0
  78. package/dist/core/media/uploadLimits.d.ts +7 -0
  79. package/dist/core/media/uploadLimits.js +16 -0
  80. package/dist/core/media/validate.d.ts +9 -0
  81. package/dist/core/media/validate.js +121 -0
  82. package/dist/core/media/videoCuts.d.ts +152 -0
  83. package/dist/core/media/videoCuts.js +284 -0
  84. package/dist/core/navigation/breadcrumbCompat.d.ts +24 -0
  85. package/dist/core/navigation/breadcrumbCompat.js +21 -0
  86. package/dist/core/navigation/coverageTest.d.ts +24 -0
  87. package/dist/core/navigation/coverageTest.js +48 -0
  88. package/dist/core/navigation/index.d.ts +6 -0
  89. package/dist/core/navigation/index.js +10 -0
  90. package/dist/core/navigation/migrateNavPreferences.d.ts +55 -0
  91. package/dist/core/navigation/migrateNavPreferences.js +63 -0
  92. package/dist/core/navigation/navigationModel.d.ts +165 -0
  93. package/dist/core/navigation/navigationModel.js +14 -0
  94. package/dist/core/navigation/navigationSelectors.d.ts +63 -0
  95. package/dist/core/navigation/navigationSelectors.js +167 -0
  96. package/dist/core/navigation/searchCatalogue.d.ts +23 -0
  97. package/dist/core/navigation/searchCatalogue.js +76 -0
  98. package/dist/core/net/reconnectSchedule.d.ts +46 -0
  99. package/dist/core/net/reconnectSchedule.js +38 -0
  100. package/dist/core/palette/ShortcutRegistry.d.ts +33 -0
  101. package/dist/core/palette/ShortcutRegistry.js +52 -0
  102. package/dist/core/palette/fuzzyRank.d.ts +18 -0
  103. package/dist/core/palette/fuzzyRank.js +73 -0
  104. package/dist/core/palette/hotkeys.d.ts +28 -0
  105. package/dist/core/palette/hotkeys.js +118 -0
  106. package/dist/core/palette/index.d.ts +3 -0
  107. package/dist/core/palette/index.js +8 -0
  108. package/dist/core/schema/projection.d.ts +84 -0
  109. package/dist/core/schema/projection.js +184 -0
  110. package/dist/core/session/claims.d.ts +145 -0
  111. package/dist/core/session/claims.js +157 -0
  112. package/dist/core/sharing/index.d.ts +5 -0
  113. package/dist/core/sharing/index.js +4 -0
  114. package/dist/core/sharing/model.d.ts +195 -0
  115. package/dist/core/sharing/model.js +150 -0
  116. package/dist/core/site/siteCopy.d.ts +92 -0
  117. package/dist/core/site/siteCopy.js +91 -0
  118. package/dist/core/slots.d.ts +22 -0
  119. package/dist/core/slots.js +31 -0
  120. package/dist/core/styles/constructableSheet.d.ts +51 -0
  121. package/dist/core/styles/constructableSheet.js +80 -0
  122. package/dist/core/tokens/registry.d.ts +119 -0
  123. package/dist/core/tokens/registry.js +447 -0
  124. package/dist/core/uiScale/index.d.ts +8 -0
  125. package/dist/core/uiScale/index.js +8 -0
  126. package/dist/core/uiScale/scale.d.ts +36 -0
  127. package/dist/core/uiScale/scale.js +47 -0
  128. package/dist/core/uiScale/uiScaleStore.d.ts +47 -0
  129. package/dist/core/uiScale/uiScaleStore.js +63 -0
  130. package/dist/core/wire/__fixtures__/rowsMarshalWorker.d.ts +1 -0
  131. package/dist/core/wire/__fixtures__/rowsMarshalWorker.js +23 -0
  132. package/dist/core/wire/index.d.ts +17 -0
  133. package/dist/core/wire/index.js +17 -0
  134. package/dist/core/wire/ingress.d.ts +44 -0
  135. package/dist/core/wire/ingress.js +134 -0
  136. package/dist/core/wire/marshalWorker.d.ts +70 -0
  137. package/dist/core/wire/marshalWorker.js +273 -0
  138. package/dist/core/wire/marshalling.d.ts +122 -0
  139. package/dist/core/wire/marshalling.js +126 -0
  140. package/dist/core/wire/wireHub.d.ts +80 -0
  141. package/dist/core/wire/wireHub.js +116 -0
  142. package/dist/ctgr/base64url.d.ts +8 -0
  143. package/dist/ctgr/base64url.js +39 -0
  144. package/dist/ctgr/chunkAccumulator.d.ts +214 -0
  145. package/dist/ctgr/chunkAccumulator.js +307 -0
  146. package/dist/ctgr/chunkStore.d.ts +24 -0
  147. package/dist/ctgr/chunkStore.js +125 -0
  148. package/dist/ctgr/codec.d.ts +44 -0
  149. package/dist/ctgr/codec.js +153 -0
  150. package/dist/ctgr/compress.d.ts +2 -0
  151. package/dist/ctgr/compress.js +20 -0
  152. package/dist/ctgr/crc32.d.ts +2 -0
  153. package/dist/ctgr/crc32.js +23 -0
  154. package/dist/ctgr/digest.d.ts +1 -0
  155. package/dist/ctgr/digest.js +15 -0
  156. package/dist/ctgr/index.d.ts +9 -0
  157. package/dist/ctgr/index.js +17 -0
  158. package/dist/ctgr/types.d.ts +64 -0
  159. package/dist/ctgr/types.js +21 -0
  160. package/dist/ctgr/v0compat.d.ts +27 -0
  161. package/dist/ctgr/v0compat.js +128 -0
  162. package/dist/index.d.ts +15 -0
  163. package/dist/index.js +17 -0
  164. package/dist/shared/errors.d.ts +101 -0
  165. package/dist/shared/errors.js +99 -0
  166. package/dist/testing/bytes.d.ts +32 -0
  167. package/dist/testing/bytes.js +33 -0
  168. package/dist/testing/domInspect.d.ts +59 -0
  169. package/dist/testing/domInspect.js +115 -0
  170. package/dist/testing/fakeFetch.d.ts +23 -0
  171. package/dist/testing/fakeFetch.js +21 -0
  172. package/dist/testing/index.d.ts +3 -0
  173. package/dist/testing/index.js +11 -0
  174. package/package.json +373 -0
  175. package/src/client/wsWire.ts +83 -0
  176. package/src/config/appConfig.spec.ts +158 -0
  177. package/src/config/appConfig.ts +372 -0
  178. package/src/core/activity/index.ts +21 -0
  179. package/src/core/activity/model.ts +160 -0
  180. package/src/core/analytics/index.ts +18 -0
  181. package/src/core/analytics/range.spec.ts +280 -0
  182. package/src/core/analytics/range.ts +383 -0
  183. package/src/core/analytics/schedule.spec.ts +311 -0
  184. package/src/core/analytics/schedule.ts +624 -0
  185. package/src/core/category/category.spec.ts +144 -0
  186. package/src/core/category/index.ts +19 -0
  187. package/src/core/category/memoryStore.ts +104 -0
  188. package/src/core/category/tree.ts +118 -0
  189. package/src/core/category/types.ts +59 -0
  190. package/src/core/color.spec.ts +35 -0
  191. package/src/core/color.ts +35 -0
  192. package/src/core/colorScheme/colorScheme.spec.ts +127 -0
  193. package/src/core/colorScheme/colorSchemeStore.ts +184 -0
  194. package/src/core/colorScheme/index.ts +23 -0
  195. package/src/core/domainOwners.ts +32 -0
  196. package/src/core/download.spec.ts +38 -0
  197. package/src/core/download.ts +35 -0
  198. package/src/core/events/ccEventBus.spec.ts +90 -0
  199. package/src/core/events/ccEventBus.ts +120 -0
  200. package/src/core/file-tree/fileTreeModel.spec.ts +462 -0
  201. package/src/core/file-tree/fileTreeModel.ts +511 -0
  202. package/src/core/folder-tree/actions.spec.ts +103 -0
  203. package/src/core/folder-tree/actions.ts +153 -0
  204. package/src/core/folder-tree/index.ts +46 -0
  205. package/src/core/folder-tree/path.spec.ts +113 -0
  206. package/src/core/folder-tree/path.ts +148 -0
  207. package/src/core/folder-tree/tree.spec.ts +157 -0
  208. package/src/core/folder-tree/tree.ts +244 -0
  209. package/src/core/layout/index.ts +7 -0
  210. package/src/core/master-lock/index.ts +50 -0
  211. package/src/core/master-lock/kdf.spec.ts +95 -0
  212. package/src/core/master-lock/kdf.ts +145 -0
  213. package/src/core/master-lock/policy.ts +55 -0
  214. package/src/core/master-lock/presence.spec.ts +73 -0
  215. package/src/core/master-lock/presence.ts +71 -0
  216. package/src/core/master-lock/wire.ts +155 -0
  217. package/src/core/media/bgRemoval.spec.ts +120 -0
  218. package/src/core/media/bgRemoval.ts +123 -0
  219. package/src/core/media/ffmpeg.spec.ts +135 -0
  220. package/src/core/media/ffmpeg.ts +162 -0
  221. package/src/core/media/format.spec.ts +41 -0
  222. package/src/core/media/format.ts +58 -0
  223. package/src/core/media/index.ts +105 -0
  224. package/src/core/media/mediaItem.spec.ts +46 -0
  225. package/src/core/media/mediaItem.ts +40 -0
  226. package/src/core/media/renderPlan.spec.ts +140 -0
  227. package/src/core/media/renderPlan.ts +318 -0
  228. package/src/core/media/segment.spec.ts +159 -0
  229. package/src/core/media/segment.ts +352 -0
  230. package/src/core/media/size.spec.ts +19 -0
  231. package/src/core/media/size.ts +3 -0
  232. package/src/core/media/trim.spec.ts +75 -0
  233. package/src/core/media/trim.ts +60 -0
  234. package/src/core/media/types.ts +147 -0
  235. package/src/core/media/uploadLimits.ts +18 -0
  236. package/src/core/media/validate.spec.ts +106 -0
  237. package/src/core/media/validate.ts +131 -0
  238. package/src/core/media/videoCuts.spec.ts +327 -0
  239. package/src/core/media/videoCuts.ts +355 -0
  240. package/src/core/navigation/breadcrumbCompat.ts +44 -0
  241. package/src/core/navigation/coverageTest.ts +54 -0
  242. package/src/core/navigation/index.ts +50 -0
  243. package/src/core/navigation/migrateNavPreferences.ts +119 -0
  244. package/src/core/navigation/navigation.spec.ts +388 -0
  245. package/src/core/navigation/navigationModel.ts +185 -0
  246. package/src/core/navigation/navigationSelectors.ts +206 -0
  247. package/src/core/navigation/searchCatalogue.ts +89 -0
  248. package/src/core/net/reconnectSchedule.spec.ts +49 -0
  249. package/src/core/net/reconnectSchedule.ts +78 -0
  250. package/src/core/palette/ShortcutRegistry.ts +69 -0
  251. package/src/core/palette/fuzzyRank.ts +78 -0
  252. package/src/core/palette/hotkeys.ts +132 -0
  253. package/src/core/palette/index.ts +22 -0
  254. package/src/core/palette/palette.spec.ts +160 -0
  255. package/src/core/schema/projection.spec.ts +122 -0
  256. package/src/core/schema/projection.ts +225 -0
  257. package/src/core/session/claims.ts +181 -0
  258. package/src/core/sharing/index.ts +33 -0
  259. package/src/core/sharing/model.spec.ts +104 -0
  260. package/src/core/sharing/model.ts +296 -0
  261. package/src/core/site/siteCopy.ts +115 -0
  262. package/src/core/slots.ts +38 -0
  263. package/src/core/styles/constructableSheet.ts +86 -0
  264. package/src/core/tokens/registry.spec.ts +160 -0
  265. package/src/core/tokens/registry.ts +536 -0
  266. package/src/core/uiScale/index.ts +32 -0
  267. package/src/core/uiScale/scale.ts +63 -0
  268. package/src/core/uiScale/uiScale.spec.ts +77 -0
  269. package/src/core/uiScale/uiScaleStore.ts +100 -0
  270. package/src/core/wire/__fixtures__/rowsMarshalWorker.ts +24 -0
  271. package/src/core/wire/index.ts +56 -0
  272. package/src/core/wire/ingress.spec.ts +276 -0
  273. package/src/core/wire/ingress.ts +182 -0
  274. package/src/core/wire/marshalWorker.spec.ts +196 -0
  275. package/src/core/wire/marshalWorker.ts +361 -0
  276. package/src/core/wire/marshalling.spec.ts +139 -0
  277. package/src/core/wire/marshalling.ts +238 -0
  278. package/src/core/wire/wireHub.spec.ts +137 -0
  279. package/src/core/wire/wireHub.ts +213 -0
  280. package/src/ctgr/base64url.ts +44 -0
  281. package/src/ctgr/chunkAccumulator.ts +403 -0
  282. package/src/ctgr/chunkStore.spec.ts +101 -0
  283. package/src/ctgr/chunkStore.ts +168 -0
  284. package/src/ctgr/codec.spec.ts +208 -0
  285. package/src/ctgr/codec.ts +202 -0
  286. package/src/ctgr/compress.ts +21 -0
  287. package/src/ctgr/crc32.ts +23 -0
  288. package/src/ctgr/digest.ts +14 -0
  289. package/src/ctgr/index.ts +39 -0
  290. package/src/ctgr/types.ts +80 -0
  291. package/src/ctgr/v0compat.spec.ts +73 -0
  292. package/src/ctgr/v0compat.ts +156 -0
  293. package/src/declaredDepsAreImported.spec.ts +87 -0
  294. package/src/index.ts +25 -0
  295. package/src/leafSubpathsImportNothing.spec.ts +287 -0
  296. package/src/lockfileIsTracked.spec.ts +50 -0
  297. package/src/namedSubpathsResolve.spec.ts +122 -0
  298. package/src/noPathDeps.spec.ts +24 -0
  299. package/src/publishShape.spec.ts +89 -0
  300. package/src/shared/errors.ts +153 -0
  301. package/src/skippedTestsAreAnswered.spec.ts +221 -0
  302. package/src/testTmpRoot.spec.ts +102 -0
  303. package/src/testing/bytes.ts +38 -0
  304. package/src/testing/domInspect.spec.ts +79 -0
  305. package/src/testing/domInspect.ts +127 -0
  306. package/src/testing/fakeFetch.ts +26 -0
  307. package/src/testing/index.ts +11 -0
package/LICENSE ADDED
@@ -0,0 +1,15 @@
1
+ ISC License
2
+
3
+ Copyright (c) 2026
4
+
5
+ Permission to use, copy, modify, and/or distribute this software for any
6
+ purpose with or without fee is hereby granted, provided that the above
7
+ copyright notice and this permission notice appear in all copies.
8
+
9
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12
+ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
@@ -0,0 +1,49 @@
1
+ /**
2
+ * The WS hub's WIRE, with no socket attached.
3
+ *
4
+ * ── Why this is a module of its own ─────────────────────────────────────────
5
+ * `./ws` imports `partysocket/ws` at the top of the file to build the
6
+ * auto-reconnecting socket. `partysocket` is an OPTIONAL peer of cursedbelt, so
7
+ * a consumer that brings its own socket — because it already has a reconnect
8
+ * strategy, or because its entry chunk is measured to the byte and it will not
9
+ * spend it on a reconnect library — could not touch the URL builder or the
10
+ * envelope helpers without pulling the library in. They are twenty lines of pure
11
+ * string handling and they were only ever in that file because they were written
12
+ * on the same afternoon.
13
+ *
14
+ * So: the WIRE lives here and is free of dependencies, and `./ws` re-exports it
15
+ * beside the socket factory. Nothing moved for the callers that already had it —
16
+ * `cursedbelt-cc/client` still exports all of it from one place — and the split is
17
+ * what makes `cursedbelt-core/ws-wire` a thing an app can import.
18
+ *
19
+ * 🔴 The contract is that the envelope has ONE definition. An app that hand-rolls
20
+ * `JSON.stringify({ event, data })` is an app whose frames drift from the hub's
21
+ * the day the envelope gains a field, and the drift presents as a message the
22
+ * server silently ignores — `createWsHub` returns from `message` rather than
23
+ * throwing, on purpose. Take the helpers.
24
+ *
25
+ * `apps/family` (cursed-satellites) is the first consumer of this subpath.
26
+ */
27
+ /** The minimal shape of `window.location` {@link buildChannelSocketUrl} needs. Injectable
28
+ * so the URL builder is pure + testable (no `window` at module scope). */
29
+ export interface WsLocation {
30
+ protocol: string;
31
+ host: string;
32
+ }
33
+ /** The hub's wire envelope, mirroring `cursedbelt-server`'s `WsMessage`. Re-declared here
34
+ * (not imported) because the server module is Bun-typed and must not leak into the browser
35
+ * surface. */
36
+ export interface WsMessage<T = unknown> {
37
+ event: string;
38
+ data: T;
39
+ }
40
+ /** Build the `ws(s)://host/ws/<channel>[?room=<roomId>]` URL the hub upgrades. `wss` is
41
+ * chosen iff the page is `https`. Pure — pass `loc` in tests. */
42
+ export declare function buildChannelSocketUrl(channel: string, roomId: string | undefined, loc: WsLocation): string;
43
+ /** Send a `{ event, data }` frame the hub understands. */
44
+ export declare function sendWsMessage(socket: {
45
+ send(data: string): void;
46
+ }, event: string, data: unknown): void;
47
+ /** Parse an inbound frame into a `{ event, data }` envelope, or `null` if it isn't valid
48
+ * JSON of that shape (so a stray non-envelope frame can't throw in a message handler). */
49
+ export declare function parseWsMessage<T = unknown>(raw: unknown): WsMessage<T> | null;
@@ -0,0 +1,57 @@
1
+ /**
2
+ * The WS hub's WIRE, with no socket attached.
3
+ *
4
+ * ── Why this is a module of its own ─────────────────────────────────────────
5
+ * `./ws` imports `partysocket/ws` at the top of the file to build the
6
+ * auto-reconnecting socket. `partysocket` is an OPTIONAL peer of cursedbelt, so
7
+ * a consumer that brings its own socket — because it already has a reconnect
8
+ * strategy, or because its entry chunk is measured to the byte and it will not
9
+ * spend it on a reconnect library — could not touch the URL builder or the
10
+ * envelope helpers without pulling the library in. They are twenty lines of pure
11
+ * string handling and they were only ever in that file because they were written
12
+ * on the same afternoon.
13
+ *
14
+ * So: the WIRE lives here and is free of dependencies, and `./ws` re-exports it
15
+ * beside the socket factory. Nothing moved for the callers that already had it —
16
+ * `cursedbelt-cc/client` still exports all of it from one place — and the split is
17
+ * what makes `cursedbelt-core/ws-wire` a thing an app can import.
18
+ *
19
+ * 🔴 The contract is that the envelope has ONE definition. An app that hand-rolls
20
+ * `JSON.stringify({ event, data })` is an app whose frames drift from the hub's
21
+ * the day the envelope gains a field, and the drift presents as a message the
22
+ * server silently ignores — `createWsHub` returns from `message` rather than
23
+ * throwing, on purpose. Take the helpers.
24
+ *
25
+ * `apps/family` (cursed-satellites) is the first consumer of this subpath.
26
+ */
27
+ /** Build the `ws(s)://host/ws/<channel>[?room=<roomId>]` URL the hub upgrades. `wss` is
28
+ * chosen iff the page is `https`. Pure — pass `loc` in tests. */
29
+ export function buildChannelSocketUrl(channel, roomId, loc) {
30
+ const scheme = loc.protocol === 'https:' ? 'wss' : 'ws';
31
+ const base = `${scheme}://${loc.host}/ws/${encodeURIComponent(channel)}`;
32
+ return roomId ? `${base}?room=${encodeURIComponent(roomId)}` : base;
33
+ }
34
+ /** Send a `{ event, data }` frame the hub understands. */
35
+ export function sendWsMessage(socket, event, data) {
36
+ socket.send(JSON.stringify({ event, data }));
37
+ }
38
+ /** Parse an inbound frame into a `{ event, data }` envelope, or `null` if it isn't valid
39
+ * JSON of that shape (so a stray non-envelope frame can't throw in a message handler). */
40
+ export function parseWsMessage(raw) {
41
+ if (typeof raw !== 'string')
42
+ return null;
43
+ let parsed;
44
+ try {
45
+ parsed = JSON.parse(raw);
46
+ }
47
+ catch {
48
+ return null;
49
+ }
50
+ if (parsed &&
51
+ typeof parsed === 'object' &&
52
+ 'event' in parsed &&
53
+ typeof parsed.event === 'string') {
54
+ return parsed;
55
+ }
56
+ return null;
57
+ }
@@ -0,0 +1,361 @@
1
+ /**
2
+ * `app-config.json` — the single schema the compiler AND the runtime import
3
+ * (02-MASTER-ENGINES §2). Nothing else may re-declare this shape: a second copy
4
+ * is how `privateMedia` without `guard` parsed as valid for a year (J2-1).
5
+ *
6
+ * Two laws are encoded here rather than in prose:
7
+ *
8
+ * 1. `.strict()` end to end. An unknown key — including inside a per-engine
9
+ * `features` block — is a parse ERROR (`unknown-config-key`), never silently
10
+ * stripped. A typo'd flag that gets dropped reads as "the feature is off" at
11
+ * runtime, which is indistinguishable from a bug in the feature.
12
+ * 2. `.superRefine()` cross-engine dependencies. `privateMedia` needs `guard`,
13
+ * `oralHistory` needs `asset`, `auth.enabled` needs `guard`, and the saas
14
+ * profile needs `guard` + `rbac:true`. These are structural: the config
15
+ * references something that will not exist at runtime, so it dies at V0 —
16
+ * fail-closed on structure (04 §0).
17
+ *
18
+ * Zod v4 notes: `z.record` requires an explicit key schema, and `addIssue` takes
19
+ * the literal `'custom'` code (the `ZodIssueCode` enum is gone).
20
+ */
21
+ import { z } from 'zod';
22
+ export declare const ENGINE_IDS: readonly ["asset", "knowledge", "dev", "guard", "system"];
23
+ export declare const EngineIdSchema: z.ZodEnum<{
24
+ asset: "asset";
25
+ knowledge: "knowledge";
26
+ dev: "dev";
27
+ guard: "guard";
28
+ system: "system";
29
+ }>;
30
+ export type EngineId = (typeof ENGINE_IDS)[number];
31
+ export declare const AssetFeatures: z.ZodObject<{
32
+ gallery: z.ZodDefault<z.ZodBoolean>;
33
+ galleryLayouts: z.ZodDefault<z.ZodArray<z.ZodEnum<{
34
+ masonry: "masonry";
35
+ rows: "rows";
36
+ columns: "columns";
37
+ dense: "dense";
38
+ }>>>;
39
+ video: z.ZodDefault<z.ZodBoolean>;
40
+ hls: z.ZodDefault<z.ZodBoolean>;
41
+ editor: z.ZodDefault<z.ZodBoolean>;
42
+ fileBrowser: z.ZodDefault<z.ZodBoolean>;
43
+ taggedFiles: z.ZodDefault<z.ZodBoolean>;
44
+ privateMedia: z.ZodDefault<z.ZodBoolean>;
45
+ vaultSource: z.ZodDefault<z.ZodBoolean>;
46
+ ocr: z.ZodDefault<z.ZodBoolean>;
47
+ imageStudio: z.ZodDefault<z.ZodBoolean>;
48
+ }, z.core.$strict>;
49
+ export declare const KnowledgeFeatures: z.ZodObject<{
50
+ notes: z.ZodDefault<z.ZodBoolean>;
51
+ todos: z.ZodDefault<z.ZodBoolean>;
52
+ airtableStyleLists: z.ZodDefault<z.ZodBoolean>;
53
+ kanban: z.ZodDefault<z.ZodBoolean>;
54
+ contacts: z.ZodDefault<z.ZodBoolean>;
55
+ oralHistory: z.ZodDefault<z.ZodBoolean>;
56
+ textCompare: z.ZodDefault<z.ZodBoolean>;
57
+ ragChat: z.ZodDefault<z.ZodBoolean>;
58
+ ragDiskIndexing: z.ZodDefault<z.ZodBoolean>;
59
+ aiOrganizer: z.ZodDefault<z.ZodBoolean>;
60
+ bookmarks: z.ZodDefault<z.ZodBoolean>;
61
+ worklog: z.ZodDefault<z.ZodBoolean>;
62
+ family: z.ZodDefault<z.ZodBoolean>;
63
+ habits: z.ZodDefault<z.ZodBoolean>;
64
+ articles: z.ZodDefault<z.ZodBoolean>;
65
+ }, z.core.$strict>;
66
+ export declare const DevFeatures: z.ZodObject<{
67
+ appRegistry: z.ZodDefault<z.ZodBoolean>;
68
+ configEditor: z.ZodDefault<z.ZodBoolean>;
69
+ deploy: z.ZodDefault<z.ZodBoolean>;
70
+ fleet: z.ZodDefault<z.ZodBoolean>;
71
+ pipelines: z.ZodDefault<z.ZodBoolean>;
72
+ docs: z.ZodDefault<z.ZodBoolean>;
73
+ screenshots: z.ZodDefault<z.ZodBoolean>;
74
+ diskUsage: z.ZodDefault<z.ZodBoolean>;
75
+ dbAdmin: z.ZodDefault<z.ZodBoolean>;
76
+ orchestration: z.ZodDefault<z.ZodBoolean>;
77
+ }, z.core.$strict>;
78
+ /**
79
+ * Who may create an account (D33 — the commercial-launch gate). Ordered from
80
+ * most open to most closed; `effectiveSignupMode` picks the STRICTEST configured
81
+ * value, so two guard instances can never disagree in the open direction.
82
+ *
83
+ * - `open` — anyone signs up (saas: minting their own tenant as OWNER).
84
+ * - `invite` — a valid invitation token is required; token-less signup is a
85
+ * 403. This is the "coming soon" launch posture: the operator invites
86
+ * trusted testers while the public sees a closed door.
87
+ * - `closed` — no signups at all, invitation or not.
88
+ */
89
+ export declare const SIGNUP_MODES: readonly ["open", "invite", "closed"];
90
+ export type SignupMode = (typeof SIGNUP_MODES)[number];
91
+ export declare const GuardFeatures: z.ZodObject<{
92
+ privateMode: z.ZodDefault<z.ZodBoolean>;
93
+ secretsPanel: z.ZodDefault<z.ZodBoolean>;
94
+ accounts: z.ZodDefault<z.ZodBoolean>;
95
+ rbac: z.ZodDefault<z.ZodBoolean>;
96
+ sessionTtlMinutes: z.ZodDefault<z.ZodNumber>;
97
+ signupMode: z.ZodDefault<z.ZodEnum<{
98
+ open: "open";
99
+ invite: "invite";
100
+ closed: "closed";
101
+ }>>;
102
+ siteCopy: z.ZodDefault<z.ZodBoolean>;
103
+ }, z.core.$strict>;
104
+ export declare const SystemFeatures: z.ZodObject<{
105
+ dashboard: z.ZodDefault<z.ZodBoolean>;
106
+ calendar: z.ZodDefault<z.ZodBoolean>;
107
+ notifications: z.ZodDefault<z.ZodBoolean>;
108
+ stopwatch: z.ZodDefault<z.ZodBoolean>;
109
+ timeOff: z.ZodDefault<z.ZodBoolean>;
110
+ formatLab: z.ZodDefault<z.ZodBoolean>;
111
+ lineFilter: z.ZodDefault<z.ZodBoolean>;
112
+ httpClient: z.ZodDefault<z.ZodBoolean>;
113
+ budgets: z.ZodDefault<z.ZodBoolean>;
114
+ subscriptions: z.ZodDefault<z.ZodBoolean>;
115
+ }, z.core.$strict>;
116
+ export declare const FeaturesByEngine: {
117
+ readonly asset: z.ZodObject<{
118
+ gallery: z.ZodDefault<z.ZodBoolean>;
119
+ galleryLayouts: z.ZodDefault<z.ZodArray<z.ZodEnum<{
120
+ masonry: "masonry";
121
+ rows: "rows";
122
+ columns: "columns";
123
+ dense: "dense";
124
+ }>>>;
125
+ video: z.ZodDefault<z.ZodBoolean>;
126
+ hls: z.ZodDefault<z.ZodBoolean>;
127
+ editor: z.ZodDefault<z.ZodBoolean>;
128
+ fileBrowser: z.ZodDefault<z.ZodBoolean>;
129
+ taggedFiles: z.ZodDefault<z.ZodBoolean>;
130
+ privateMedia: z.ZodDefault<z.ZodBoolean>;
131
+ vaultSource: z.ZodDefault<z.ZodBoolean>;
132
+ ocr: z.ZodDefault<z.ZodBoolean>;
133
+ imageStudio: z.ZodDefault<z.ZodBoolean>;
134
+ }, z.core.$strict>;
135
+ readonly knowledge: z.ZodObject<{
136
+ notes: z.ZodDefault<z.ZodBoolean>;
137
+ todos: z.ZodDefault<z.ZodBoolean>;
138
+ airtableStyleLists: z.ZodDefault<z.ZodBoolean>;
139
+ kanban: z.ZodDefault<z.ZodBoolean>;
140
+ contacts: z.ZodDefault<z.ZodBoolean>;
141
+ oralHistory: z.ZodDefault<z.ZodBoolean>;
142
+ textCompare: z.ZodDefault<z.ZodBoolean>;
143
+ ragChat: z.ZodDefault<z.ZodBoolean>;
144
+ ragDiskIndexing: z.ZodDefault<z.ZodBoolean>;
145
+ aiOrganizer: z.ZodDefault<z.ZodBoolean>;
146
+ bookmarks: z.ZodDefault<z.ZodBoolean>;
147
+ worklog: z.ZodDefault<z.ZodBoolean>;
148
+ family: z.ZodDefault<z.ZodBoolean>;
149
+ habits: z.ZodDefault<z.ZodBoolean>;
150
+ articles: z.ZodDefault<z.ZodBoolean>;
151
+ }, z.core.$strict>;
152
+ readonly dev: z.ZodObject<{
153
+ appRegistry: z.ZodDefault<z.ZodBoolean>;
154
+ configEditor: z.ZodDefault<z.ZodBoolean>;
155
+ deploy: z.ZodDefault<z.ZodBoolean>;
156
+ fleet: z.ZodDefault<z.ZodBoolean>;
157
+ pipelines: z.ZodDefault<z.ZodBoolean>;
158
+ docs: z.ZodDefault<z.ZodBoolean>;
159
+ screenshots: z.ZodDefault<z.ZodBoolean>;
160
+ diskUsage: z.ZodDefault<z.ZodBoolean>;
161
+ dbAdmin: z.ZodDefault<z.ZodBoolean>;
162
+ orchestration: z.ZodDefault<z.ZodBoolean>;
163
+ }, z.core.$strict>;
164
+ readonly guard: z.ZodObject<{
165
+ privateMode: z.ZodDefault<z.ZodBoolean>;
166
+ secretsPanel: z.ZodDefault<z.ZodBoolean>;
167
+ accounts: z.ZodDefault<z.ZodBoolean>;
168
+ rbac: z.ZodDefault<z.ZodBoolean>;
169
+ sessionTtlMinutes: z.ZodDefault<z.ZodNumber>;
170
+ signupMode: z.ZodDefault<z.ZodEnum<{
171
+ open: "open";
172
+ invite: "invite";
173
+ closed: "closed";
174
+ }>>;
175
+ siteCopy: z.ZodDefault<z.ZodBoolean>;
176
+ }, z.core.$strict>;
177
+ readonly system: z.ZodObject<{
178
+ dashboard: z.ZodDefault<z.ZodBoolean>;
179
+ calendar: z.ZodDefault<z.ZodBoolean>;
180
+ notifications: z.ZodDefault<z.ZodBoolean>;
181
+ stopwatch: z.ZodDefault<z.ZodBoolean>;
182
+ timeOff: z.ZodDefault<z.ZodBoolean>;
183
+ formatLab: z.ZodDefault<z.ZodBoolean>;
184
+ lineFilter: z.ZodDefault<z.ZodBoolean>;
185
+ httpClient: z.ZodDefault<z.ZodBoolean>;
186
+ budgets: z.ZodDefault<z.ZodBoolean>;
187
+ subscriptions: z.ZodDefault<z.ZodBoolean>;
188
+ }, z.core.$strict>;
189
+ };
190
+ export type FeaturesFor<E extends EngineId> = z.infer<(typeof FeaturesByEngine)[E]>;
191
+ /**
192
+ * A fully-resolved feature block: every key of the engine's schema present, no
193
+ * `undefined`. Numeric feature values (`sessionTtlMinutes`) and string values
194
+ * (`signupMode`) are part of the record, so consumers narrow with `=== true`
195
+ * rather than truthiness.
196
+ */
197
+ export type EffectiveFeatures = Readonly<Record<string, boolean | number | string | readonly string[]>>;
198
+ /**
199
+ * The signup gate a whole app enforces (D33). The STRICTEST configured value
200
+ * wins across guard instances — with two instances, `open` beside `invite`
201
+ * must mean invite-only, or adding a second guard instance would silently
202
+ * reopen a closed door. Apps with no guard instance have no signup surface at
203
+ * all, so the returned default is never enforced anywhere.
204
+ */
205
+ export declare const effectiveSignupMode: (instances: ReadonlyArray<{
206
+ readonly engine: string;
207
+ readonly effective: EffectiveFeatures;
208
+ }>) => SignupMode;
209
+ /**
210
+ * Client SPA path (03 §3): kebab-case literal segments, camelCase `:params`.
211
+ * `/chat/:conversationId` is the canonical example, so param names must admit
212
+ * capitals while literal segments stay lowercase — a `/Chat` vs `/chat` pair is
213
+ * two routes on a case-sensitive router and one route on a case-insensitive one.
214
+ */
215
+ export declare const ROUTE_PATH_RE: RegExp;
216
+ export declare const RouteDeclSchema: z.ZodObject<{
217
+ path: z.ZodString;
218
+ view: z.ZodString;
219
+ aliases: z.ZodDefault<z.ZodArray<z.ZodString>>;
220
+ deepLinkEntity: z.ZodOptional<z.ZodString>;
221
+ }, z.core.$strict>;
222
+ export type RouteDecl = z.infer<typeof RouteDeclSchema>;
223
+ export declare const FillDeclSchema: z.ZodObject<{
224
+ slot: z.ZodString;
225
+ component: z.ZodString;
226
+ order: z.ZodDefault<z.ZodNumber>;
227
+ requiredFeatures: z.ZodDefault<z.ZodArray<z.ZodString>>;
228
+ }, z.core.$strict>;
229
+ export type FillDecl = z.infer<typeof FillDeclSchema>;
230
+ export declare const InstanceSchema: z.ZodObject<{
231
+ engine: z.ZodEnum<{
232
+ asset: "asset";
233
+ knowledge: "knowledge";
234
+ dev: "dev";
235
+ guard: "guard";
236
+ system: "system";
237
+ }>;
238
+ id: z.ZodString;
239
+ title: z.ZodOptional<z.ZodString>;
240
+ features: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
241
+ options: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
242
+ routes: z.ZodDefault<z.ZodArray<z.ZodObject<{
243
+ path: z.ZodString;
244
+ view: z.ZodString;
245
+ aliases: z.ZodDefault<z.ZodArray<z.ZodString>>;
246
+ deepLinkEntity: z.ZodOptional<z.ZodString>;
247
+ }, z.core.$strict>>>;
248
+ fills: z.ZodDefault<z.ZodArray<z.ZodObject<{
249
+ slot: z.ZodString;
250
+ component: z.ZodString;
251
+ order: z.ZodDefault<z.ZodNumber>;
252
+ requiredFeatures: z.ZodDefault<z.ZodArray<z.ZodString>>;
253
+ }, z.core.$strict>>>;
254
+ cssIsolation: z.ZodDefault<z.ZodEnum<{
255
+ none: "none";
256
+ scope: "scope";
257
+ shadow: "shadow";
258
+ }>>;
259
+ }, z.core.$strict>;
260
+ export type ConfigInstance = z.infer<typeof InstanceSchema>;
261
+ /** '<instanceId>:<portId>' or 'data:<sourceId>'. */
262
+ export declare const ENDPOINT_RE: RegExp;
263
+ export declare const ConnectionSchema: z.ZodObject<{
264
+ from: z.ZodString;
265
+ to: z.ZodString;
266
+ cyclic: z.ZodDefault<z.ZodBoolean>;
267
+ }, z.core.$strict>;
268
+ export type Connection = z.infer<typeof ConnectionSchema>;
269
+ export declare const AppConfigSchema: z.ZodObject<{
270
+ configVersion: z.ZodLiteral<1>;
271
+ app: z.ZodObject<{
272
+ id: z.ZodString;
273
+ title: z.ZodString;
274
+ port: z.ZodOptional<z.ZodNumber>;
275
+ kind: z.ZodDefault<z.ZodEnum<{
276
+ app: "app";
277
+ test: "test";
278
+ demo: "demo";
279
+ }>>;
280
+ }, z.core.$strict>;
281
+ profile: z.ZodDefault<z.ZodEnum<{
282
+ local: "local";
283
+ saas: "saas";
284
+ }>>;
285
+ deployTarget: z.ZodDefault<z.ZodObject<{
286
+ capabilities: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodBoolean>>;
287
+ }, z.core.$strict>>;
288
+ engines: z.ZodArray<z.ZodEnum<{
289
+ asset: "asset";
290
+ knowledge: "knowledge";
291
+ dev: "dev";
292
+ guard: "guard";
293
+ system: "system";
294
+ }>>;
295
+ instances: z.ZodArray<z.ZodObject<{
296
+ engine: z.ZodEnum<{
297
+ asset: "asset";
298
+ knowledge: "knowledge";
299
+ dev: "dev";
300
+ guard: "guard";
301
+ system: "system";
302
+ }>;
303
+ id: z.ZodString;
304
+ title: z.ZodOptional<z.ZodString>;
305
+ features: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
306
+ options: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
307
+ routes: z.ZodDefault<z.ZodArray<z.ZodObject<{
308
+ path: z.ZodString;
309
+ view: z.ZodString;
310
+ aliases: z.ZodDefault<z.ZodArray<z.ZodString>>;
311
+ deepLinkEntity: z.ZodOptional<z.ZodString>;
312
+ }, z.core.$strict>>>;
313
+ fills: z.ZodDefault<z.ZodArray<z.ZodObject<{
314
+ slot: z.ZodString;
315
+ component: z.ZodString;
316
+ order: z.ZodDefault<z.ZodNumber>;
317
+ requiredFeatures: z.ZodDefault<z.ZodArray<z.ZodString>>;
318
+ }, z.core.$strict>>>;
319
+ cssIsolation: z.ZodDefault<z.ZodEnum<{
320
+ none: "none";
321
+ scope: "scope";
322
+ shadow: "shadow";
323
+ }>>;
324
+ }, z.core.$strict>>;
325
+ connections: z.ZodDefault<z.ZodArray<z.ZodObject<{
326
+ from: z.ZodString;
327
+ to: z.ZodString;
328
+ cyclic: z.ZodDefault<z.ZodBoolean>;
329
+ }, z.core.$strict>>>;
330
+ auth: z.ZodDefault<z.ZodObject<{
331
+ enabled: z.ZodDefault<z.ZodBoolean>;
332
+ authUI: z.ZodDefault<z.ZodObject<{
333
+ showLogout: z.ZodDefault<z.ZodBoolean>;
334
+ placement: z.ZodDefault<z.ZodEnum<{
335
+ "header-right": "header-right";
336
+ "header-left": "header-left";
337
+ "sidebar-footer": "sidebar-footer";
338
+ }>>;
339
+ icon: z.ZodDefault<z.ZodString>;
340
+ variant: z.ZodDefault<z.ZodEnum<{
341
+ default: "default";
342
+ ghost: "ghost";
343
+ outline: "outline";
344
+ }>>;
345
+ }, z.core.$strict>>;
346
+ }, z.core.$strict>>;
347
+ theme: z.ZodDefault<z.ZodObject<{
348
+ preset: z.ZodDefault<z.ZodString>;
349
+ overrides: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodString>>;
350
+ }, z.core.$strict>>;
351
+ ignoreExistingData: z.ZodDefault<z.ZodBoolean>;
352
+ }, z.core.$strict>;
353
+ export type AppConfig = z.infer<typeof AppConfigSchema>;
354
+ /**
355
+ * Resolve one instance's declared features through the FULL (non-partial) engine
356
+ * schema — the "full-resolution preview" of V0.3. Defaults land here, so a
357
+ * missing required option surfaces at design time instead of at first boot.
358
+ */
359
+ export declare function resolveInstanceFeatures(engine: EngineId, declared: Record<string, unknown>): EffectiveFeatures;
360
+ /** The declared feature key set of an engine — used by V1 `unknown-required-feature`. */
361
+ export declare function featureKeysOf(engine: EngineId): readonly string[];