@jxsuite/studio 2.2.2 → 2.4.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 (188) hide show
  1. package/data/css-meta.json +1487 -0
  2. package/data/elements-meta.json +370 -0
  3. package/data/html-meta.json +366 -0
  4. package/data/stylebook-meta.json +200 -0
  5. package/data/webdata.json +1621 -0
  6. package/dist/chunks/{Overlay.dev-ymy3et3y.js → Overlay.dev-d2ajy6sj.js} +7 -7
  7. package/dist/chunks/{content-source-r2n7v682.js → content-source-jrvn5vwy.js} +13 -12
  8. package/dist/chunks/{convert-to-repeater-cnpyvj74.js → convert-to-repeater-109dwcj7.js} +12 -11
  9. package/dist/chunks/{extension-sections-vpcm4jvx.js → extension-sections-2zjyty05.js} +17 -16
  10. package/dist/chunks/{files-zeg88k2d.js → files-jdbtammm.js} +18 -19
  11. package/dist/chunks/{format-host-taymsw55.js → format-host-kq6963gs.js} +2 -2
  12. package/dist/chunks/{git-panel-qp4rrwr9.js → git-panel-2stf3ahg.js} +12 -11
  13. package/dist/chunks/{layers-panel-kj93w2zg.js → layers-panel-a8wjsdjj.js} +15 -14
  14. package/dist/chunks/{monaco-setup-xy3bs05d.js → monaco-setup-a5wkmbgh.js} +6 -3
  15. package/dist/chunks/{publish-panel-6qz6kp41.js → publish-panel-2we6smjv.js} +6 -6
  16. package/dist/chunks/{quick-search-9wwa09hh.js → quick-search-hmpwdgys.js} +19 -18
  17. package/dist/chunks/right-panel-hn3y3j0j.js +38 -0
  18. package/dist/chunks/{sp-overlay.dev-h6kdx076.js → sp-overlay.dev-s18hymn9.js} +8 -8
  19. package/dist/chunks/sp-progress-circle.dev-0zxcyz3r.js +15 -0
  20. package/dist/chunks/sp-tooltip.dev-5c6d1kjz.js +15 -0
  21. package/dist/chunks/{studio-753znj4c.js → studio-0evba9z5.js} +5 -5
  22. package/dist/chunks/{studio-qhh8r5fz.js → studio-102jzb8r.js} +4 -4
  23. package/dist/chunks/{studio-22xr4q8q.js → studio-1dgqagzz.js} +18 -29
  24. package/dist/chunks/{studio-6f0am8f2.js → studio-2w11grav.js} +2 -2
  25. package/dist/chunks/{studio-pv8m0h4a.js → studio-377bbhtz.js} +28 -23
  26. package/dist/chunks/{studio-6zzbyx17.js → studio-53dn6e6t.js} +2 -2
  27. package/dist/chunks/studio-53n8bp04.js +16 -0
  28. package/dist/chunks/{studio-tqemhphj.js → studio-6gcrk1bq.js} +4 -4
  29. package/dist/chunks/{studio-3z8jjm2p.js → studio-7ejemhej.js} +3 -3
  30. package/dist/chunks/{studio-nqq8jk8f.js → studio-8x4399kc.js} +14 -14
  31. package/dist/chunks/{studio-rgwcpast.js → studio-ay8wcr2b.js} +2 -2
  32. package/dist/chunks/{studio-xmvbhg31.js → studio-c31yb4t6.js} +2 -2
  33. package/dist/chunks/{studio-5kt960pk.js → studio-ddgrc5hs.js} +133 -147
  34. package/dist/chunks/{studio-zqv3w24n.js → studio-eqyybj2e.js} +5 -5
  35. package/dist/chunks/{studio-p471gg5n.js → studio-kvfx9z2c.js} +7 -3
  36. package/dist/chunks/{studio-8sdyjfd6.js → studio-kwavhmdr.js} +2 -2
  37. package/dist/chunks/{studio-300zsz1k.js → studio-ky68mp85.js} +6 -6
  38. package/dist/chunks/{studio-x0et2z9g.js → studio-ng5gbxkj.js} +15 -15
  39. package/dist/chunks/{studio-hekaagev.js → studio-q07vj7p9.js} +17 -17
  40. package/dist/chunks/{studio-fys6z73y.js → studio-qd4k0h80.js} +7 -7
  41. package/dist/chunks/{studio-yphy4z9m.js → studio-rdsvb808.js} +5 -5
  42. package/dist/chunks/{studio-g8t7g0gp.js → studio-tqr02xaa.js} +3 -3
  43. package/dist/chunks/{studio-ckwz4d3x.js → studio-twsafr1e.js} +2 -2
  44. package/dist/chunks/{studio-qrsfh1w7.js → studio-tzx3xmvx.js} +5 -5
  45. package/dist/chunks/{studio-6a0h7sne.js → studio-vhk5fmfv.js} +2 -2
  46. package/dist/chunks/{studio-hrajjyt2.js → studio-wdt9y92a.js} +2 -2
  47. package/dist/chunks/{studio-r8vx7bkz.js → studio-wxthr2x1.js} +14 -13
  48. package/dist/chunks/{studio-yz9s88s0.js → studio-yk7037sg.js} +40 -14
  49. package/dist/chunks/{studio-1kgfcv7s.js → studio-yz06mkfj.js} +12 -11
  50. package/dist/codicon.ttf +0 -0
  51. package/dist/iframe-entry.js +14 -3
  52. package/dist/manifest.json +82 -0
  53. package/dist/studio.js +247 -106
  54. package/index.html +0 -50
  55. package/package.json +16 -9
  56. package/src/canvas/canvas-live-render.ts +2 -4
  57. package/src/canvas/canvas-origin.ts +25 -0
  58. package/src/canvas/iframe-entry.ts +5 -0
  59. package/src/canvas/iframe-host.ts +45 -4
  60. package/src/content/entry-editor.ts +2 -1
  61. package/src/editor/context-menu.ts +13 -2
  62. package/src/editor/slash-menu.ts +26 -11
  63. package/src/files/files.ts +11 -23
  64. package/src/grid/grid-panel.ts +27 -6
  65. package/src/hosting/document.ts +109 -0
  66. package/src/hosting/layout.ts +211 -0
  67. package/src/hosting/stage.ts +166 -0
  68. package/src/hosting/tsconfig.json +18 -0
  69. package/src/panels/ai-chat/chat-view.ts +25 -14
  70. package/src/panels/git-panel.ts +17 -14
  71. package/src/panels/head-panel.ts +32 -14
  72. package/src/panels/imports-panel.ts +32 -13
  73. package/src/panels/layers-panel.ts +9 -1
  74. package/src/panels/panel-registry.ts +0 -1
  75. package/src/panels/properties-panel.ts +3 -3
  76. package/src/panels/settings-pane.ts +1 -1
  77. package/src/panels/style-panel.ts +3 -3
  78. package/src/panels/stylebook-panel.ts +10 -1
  79. package/src/panels/toolbar.ts +1 -1
  80. package/src/platforms/cloud.ts +9 -0
  81. package/src/services/ai-models.ts +14 -1
  82. package/src/services/bundle-base.ts +69 -0
  83. package/src/services/monaco-setup.ts +19 -13
  84. package/src/shell/tree.ts +155 -0
  85. package/src/shell.ts +0 -2
  86. package/src/studio.ts +22 -2
  87. package/src/types.ts +32 -0
  88. package/src/ui/ai-managed-connect.ts +18 -3
  89. package/src/ui/regions.ts +10 -45
  90. package/styles/overlays.css +35 -0
  91. package/styles/shell.css +7 -0
  92. package/dist/chunks/2020-xp8vnwma.js.map +0 -24
  93. package/dist/chunks/Overlay.dev-ymy3et3y.js.map +0 -9
  94. package/dist/chunks/adapter-jkcyhgtr.js.map +0 -9
  95. package/dist/chunks/cf-settings-g5fbf2zp.js.map +0 -9
  96. package/dist/chunks/components-z6cnkyy1.js.map +0 -9
  97. package/dist/chunks/content-source-r2n7v682.js.map +0 -9
  98. package/dist/chunks/convert-to-repeater-cnpyvj74.js.map +0 -10
  99. package/dist/chunks/editor-cptq5jp1.js.map +0 -9
  100. package/dist/chunks/extension-sections-vpcm4jvx.js.map +0 -11
  101. package/dist/chunks/files-zeg88k2d.js.map +0 -9
  102. package/dist/chunks/flow-qbfgrpeh.js.map +0 -12
  103. package/dist/chunks/focus-trap.esm-ggawf1hy.js.map +0 -11
  104. package/dist/chunks/focus-visible-6eg70z18.js.map +0 -10
  105. package/dist/chunks/format-host-taymsw55.js.map +0 -9
  106. package/dist/chunks/git-panel-qp4rrwr9.js.map +0 -9
  107. package/dist/chunks/index-nj44jpzj.js.map +0 -14
  108. package/dist/chunks/index-zqxmqxmh.js.map +0 -9
  109. package/dist/chunks/javascript-q8kpmfah.js.map +0 -11
  110. package/dist/chunks/jsonMode-dkr040ga.js.map +0 -18
  111. package/dist/chunks/jx-validate-jj9rnt4n.js.map +0 -9
  112. package/dist/chunks/layers-panel-kj93w2zg.js.map +0 -9
  113. package/dist/chunks/monaco-binding-rj6xpx9y.js.map +0 -10
  114. package/dist/chunks/monaco-setup-xy3bs05d.js.map +0 -15
  115. package/dist/chunks/publish-panel-6qz6kp41.js.map +0 -9
  116. package/dist/chunks/quick-search-9wwa09hh.js.map +0 -9
  117. package/dist/chunks/right-panel-faf816ch.js +0 -37
  118. package/dist/chunks/right-panel-faf816ch.js.map +0 -9
  119. package/dist/chunks/section-registry-sx1ykvkw.js.map +0 -9
  120. package/dist/chunks/sp-overlay.dev-h6kdx076.js.map +0 -9
  121. package/dist/chunks/sp-popover.dev-dj9x7e7a.js.map +0 -9
  122. package/dist/chunks/sp-progress-circle.dev-0fpvhm52.js +0 -15
  123. package/dist/chunks/sp-progress-circle.dev-0fpvhm52.js.map +0 -9
  124. package/dist/chunks/sp-tooltip.dev-rvepkw4r.js +0 -15
  125. package/dist/chunks/sp-tooltip.dev-rvepkw4r.js.map +0 -9
  126. package/dist/chunks/sp-tray.dev-64v4pxw8.js.map +0 -12
  127. package/dist/chunks/studio-0a5qrh01.js.map +0 -9
  128. package/dist/chunks/studio-0rqqhrdy.js.map +0 -12
  129. package/dist/chunks/studio-18j3bmcz.js.map +0 -10
  130. package/dist/chunks/studio-1kgfcv7s.js.map +0 -13
  131. package/dist/chunks/studio-22xr4q8q.js.map +0 -13
  132. package/dist/chunks/studio-300zsz1k.js.map +0 -39
  133. package/dist/chunks/studio-3fk1ac9z.js.map +0 -12
  134. package/dist/chunks/studio-3n4ndrzh.js.map +0 -41
  135. package/dist/chunks/studio-3z8jjm2p.js.map +0 -13
  136. package/dist/chunks/studio-4mqb9a0j.js.map +0 -14
  137. package/dist/chunks/studio-4q0wznzf.js.map +0 -73
  138. package/dist/chunks/studio-5ehhackm.js.map +0 -10
  139. package/dist/chunks/studio-5kt960pk.js.map +0 -38
  140. package/dist/chunks/studio-5x5774ak.js.map +0 -10
  141. package/dist/chunks/studio-685s0ytq.js.map +0 -76
  142. package/dist/chunks/studio-6a0h7sne.js.map +0 -15
  143. package/dist/chunks/studio-6f0am8f2.js.map +0 -10
  144. package/dist/chunks/studio-6kv3apa9.js.map +0 -10
  145. package/dist/chunks/studio-6zzbyx17.js.map +0 -12
  146. package/dist/chunks/studio-753znj4c.js.map +0 -16
  147. package/dist/chunks/studio-7afd21nw.js.map +0 -10
  148. package/dist/chunks/studio-8jpzqk5s.js.map +0 -10
  149. package/dist/chunks/studio-8q517dfr.js.map +0 -10
  150. package/dist/chunks/studio-8sdyjfd6.js.map +0 -10
  151. package/dist/chunks/studio-a0tswy0w.js.map +0 -9
  152. package/dist/chunks/studio-a7pzveq1.js.map +0 -11
  153. package/dist/chunks/studio-ahnzd9rg.js.map +0 -10
  154. package/dist/chunks/studio-b9b6t1dg.js.map +0 -651
  155. package/dist/chunks/studio-bw5dz6km.js.map +0 -21
  156. package/dist/chunks/studio-cjm7fdjf.js.map +0 -14
  157. package/dist/chunks/studio-ckwz4d3x.js.map +0 -12
  158. package/dist/chunks/studio-d1ks410h.js.map +0 -10
  159. package/dist/chunks/studio-dg7zyt5x.js.map +0 -10
  160. package/dist/chunks/studio-fys6z73y.js.map +0 -10
  161. package/dist/chunks/studio-g1wdche0.js.map +0 -56
  162. package/dist/chunks/studio-g8t7g0gp.js.map +0 -10
  163. package/dist/chunks/studio-h4rxscfc.js.map +0 -10
  164. package/dist/chunks/studio-hekaagev.js.map +0 -18
  165. package/dist/chunks/studio-hrajjyt2.js.map +0 -10
  166. package/dist/chunks/studio-nqq8jk8f.js.map +0 -14
  167. package/dist/chunks/studio-p471gg5n.js.map +0 -14
  168. package/dist/chunks/studio-pv8m0h4a.js.map +0 -98
  169. package/dist/chunks/studio-qhh8r5fz.js.map +0 -13
  170. package/dist/chunks/studio-qrsfh1w7.js.map +0 -41
  171. package/dist/chunks/studio-r8vx7bkz.js.map +0 -235
  172. package/dist/chunks/studio-rgwcpast.js.map +0 -12
  173. package/dist/chunks/studio-s519zc99.js.map +0 -10
  174. package/dist/chunks/studio-sas7mt3k.js.map +0 -10
  175. package/dist/chunks/studio-t5wqwzdh.js.map +0 -10
  176. package/dist/chunks/studio-tqemhphj.js.map +0 -11
  177. package/dist/chunks/studio-tr20m8g8.js.map +0 -9
  178. package/dist/chunks/studio-tvgyw9xw.js.map +0 -14
  179. package/dist/chunks/studio-x0et2z9g.js.map +0 -32
  180. package/dist/chunks/studio-xm3dbxvn.js.map +0 -19
  181. package/dist/chunks/studio-xmvbhg31.js.map +0 -10
  182. package/dist/chunks/studio-ynxwkrzd.js.map +0 -246
  183. package/dist/chunks/studio-yphy4z9m.js.map +0 -10
  184. package/dist/chunks/studio-yz9s88s0.js.map +0 -54
  185. package/dist/chunks/studio-z6nw2ek2.js.map +0 -10
  186. package/dist/chunks/studio-zqv3w24n.js.map +0 -11
  187. package/dist/chunks/tsMode-76kr53q0.js.map +0 -13
  188. package/dist/chunks/ws-client-6shc5rze.js.map +0 -12
@@ -1,12 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../node_modules/lit-html/development/directives/private-async-helpers.js", "../../../node_modules/lit-html/development/directives/until.js", "../../../node_modules/lit-html/development/directives/when.js"],
4
- "sourcesContent": [
5
- "/**\n * @license\n * Copyright 2021 Google LLC\n * SPDX-License-Identifier: BSD-3-Clause\n */\n// Note, this module is not included in package exports so that it's private to\n// our first-party directives. If it ends up being useful, we can open it up and\n// export it.\n/**\n * Helper to iterate an AsyncIterable in its own closure.\n * @param iterable The iterable to iterate\n * @param callback The callback to call for each value. If the callback returns\n * `false`, the loop will be broken.\n */\nexport const forAwaitOf = async (iterable, callback) => {\n for await (const v of iterable) {\n if ((await callback(v)) === false) {\n return;\n }\n }\n};\n/**\n * Holds a reference to an instance that can be disconnected and reconnected,\n * so that a closure over the ref (e.g. in a then function to a promise) does\n * not strongly hold a ref to the instance. Approximates a WeakRef but must\n * be manually connected & disconnected to the backing instance.\n */\nexport class PseudoWeakRef {\n constructor(ref) {\n this._ref = ref;\n }\n /**\n * Disassociates the ref with the backing instance.\n */\n disconnect() {\n this._ref = undefined;\n }\n /**\n * Reassociates the ref with the backing instance.\n */\n reconnect(ref) {\n this._ref = ref;\n }\n /**\n * Retrieves the backing instance (will be undefined when disconnected)\n */\n deref() {\n return this._ref;\n }\n}\n/**\n * A helper to pause and resume waiting on a condition in an async function\n */\nexport class Pauser {\n constructor() {\n this._promise = undefined;\n this._resolve = undefined;\n }\n /**\n * When paused, returns a promise to be awaited; when unpaused, returns\n * undefined. Note that in the microtask between the pauser being resumed\n * an await of this promise resolving, the pauser could be paused again,\n * hence callers should check the promise in a loop when awaiting.\n * @returns A promise to be awaited when paused or undefined\n */\n get() {\n return this._promise;\n }\n /**\n * Creates a promise to be awaited\n */\n pause() {\n this._promise ??= new Promise((resolve) => (this._resolve = resolve));\n }\n /**\n * Resolves the promise which may be awaited\n */\n resume() {\n this._resolve?.();\n this._promise = this._resolve = undefined;\n }\n}\n//# sourceMappingURL=private-async-helpers.js.map",
6
- "/**\n * @license\n * Copyright 2017 Google LLC\n * SPDX-License-Identifier: BSD-3-Clause\n */\nimport { noChange } from '../lit-html.js';\nimport { isPrimitive } from '../directive-helpers.js';\nimport { directive, AsyncDirective, } from '../async-directive.js';\nimport { Pauser, PseudoWeakRef } from './private-async-helpers.js';\nconst isPromise = (x) => {\n return !isPrimitive(x) && typeof x.then === 'function';\n};\n// Effectively infinity, but a SMI.\nconst _infinity = 0x3fffffff;\nexport class UntilDirective extends AsyncDirective {\n constructor() {\n super(...arguments);\n this.__lastRenderedIndex = _infinity;\n this.__values = [];\n this.__weakThis = new PseudoWeakRef(this);\n this.__pauser = new Pauser();\n }\n render(...args) {\n return (args.find((x) => !isPromise(x)) ?? noChange);\n }\n update(_part, args) {\n const previousValues = this.__values;\n let previousLength = previousValues.length;\n this.__values = args;\n const weakThis = this.__weakThis;\n const pauser = this.__pauser;\n // If our initial render occurs while disconnected, ensure that the pauser\n // and weakThis are in the disconnected state\n if (!this.isConnected) {\n this.disconnected();\n }\n for (let i = 0; i < args.length; i++) {\n // If we've rendered a higher-priority value already, stop.\n if (i > this.__lastRenderedIndex) {\n break;\n }\n const value = args[i];\n // Render non-Promise values immediately\n if (!isPromise(value)) {\n this.__lastRenderedIndex = i;\n // Since a lower-priority value will never overwrite a higher-priority\n // synchronous value, we can stop processing now.\n return value;\n }\n // If this is a Promise we've already handled, skip it.\n if (i < previousLength && value === previousValues[i]) {\n continue;\n }\n // We have a Promise that we haven't seen before, so priorities may have\n // changed. Forget what we rendered before.\n this.__lastRenderedIndex = _infinity;\n previousLength = 0;\n // Note, the callback avoids closing over `this` so that the directive\n // can be gc'ed before the promise resolves; instead `this` is retrieved\n // from `weakThis`, which can break the hard reference in the closure when\n // the directive disconnects\n Promise.resolve(value).then(async (result) => {\n // If we're disconnected, wait until we're (maybe) reconnected\n // The while loop here handles the case that the connection state\n // thrashes, causing the pauser to resume and then get re-paused\n while (pauser.get()) {\n await pauser.get();\n }\n // If the callback gets here and there is no `this`, it means that the\n // directive has been disconnected and garbage collected and we don't\n // need to do anything else\n const _this = weakThis.deref();\n if (_this !== undefined) {\n const index = _this.__values.indexOf(value);\n // If state.values doesn't contain the value, we've re-rendered without\n // the value, so don't render it. Then, only render if the value is\n // higher-priority than what's already been rendered.\n if (index > -1 && index < _this.__lastRenderedIndex) {\n _this.__lastRenderedIndex = index;\n _this.setValue(result);\n }\n }\n });\n }\n return noChange;\n }\n disconnected() {\n this.__weakThis.disconnect();\n this.__pauser.pause();\n }\n reconnected() {\n this.__weakThis.reconnect(this);\n this.__pauser.resume();\n }\n}\n/**\n * Renders one of a series of values, including Promises, to a Part.\n *\n * Values are rendered in priority order, with the first argument having the\n * highest priority and the last argument having the lowest priority. If a\n * value is a Promise, low-priority values will be rendered until it resolves.\n *\n * The priority of values can be used to create placeholder content for async\n * data. For example, a Promise with pending content can be the first,\n * highest-priority, argument, and a non_promise loading indicator template can\n * be used as the second, lower-priority, argument. The loading indicator will\n * render immediately, and the primary content will render when the Promise\n * resolves.\n *\n * Example:\n *\n * ```js\n * const content = fetch('./content.txt').then(r => r.text());\n * html`${until(content, html`<span>Loading...</span>`)}`\n * ```\n */\nexport const until = directive(UntilDirective);\n/**\n * The type of the class that powers this directive. Necessary for naming the\n * directive's return type.\n */\n// export type {UntilDirective};\n//# sourceMappingURL=until.js.map",
7
- "/**\n * @license\n * Copyright 2021 Google LLC\n * SPDX-License-Identifier: BSD-3-Clause\n */\nexport function when(condition, trueCase, falseCase) {\n return condition ? trueCase(condition) : falseCase?.(condition);\n}\n//# sourceMappingURL=when.js.map"
8
- ],
9
- "mappings": "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",
10
- "debugId": "6810A26C9093588464756E2164756E21",
11
- "names": []
12
- }
@@ -1,10 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../src/files/components.ts"],
4
- "sourcesContent": [
5
- "/** Component registry — cached list of project components discovered via the platform. */\n\nimport { getPlatform } from \"../platform\";\nimport { projectState } from \"../store\";\nimport type { ComponentMeta } from \"../types\";\nimport type { JxMutableNode } from \"@jxsuite/schema/types\";\n\n/** A discovered component: project components carry a file path; package components may not. */\nexport interface ComponentEntry extends Omit<ComponentMeta, \"path\"> {\n path?: string;\n source?: string;\n package?: string;\n modulePath?: string;\n}\n\nexport let componentRegistry: ComponentEntry[] = [];\nexport let _componentRegistryLoaded = false;\n\nexport async function loadComponentRegistry() {\n try {\n const platform = getPlatform();\n componentRegistry = await platform.discoverComponents(projectState?.projectRoot || undefined);\n _componentRegistryLoaded = true;\n } catch {\n _componentRegistryLoaded = true;\n }\n}\n\n/**\n * Build a fresh instance definition for a component: $props from prop defaults, plus the\n * component's slot fallback children cloned in as starting content so editors can edit from the\n * defaults. Children destined for a named slot carry a `slot` attribute (required for runtime\n * distribution); fallback for the default slot is inserted as-is. When the component has no slot\n * fallback, no `children` key is emitted so slotless instances stay atomic in the layers tree.\n *\n * @param {ComponentEntry} comp\n * @returns {JxMutableNode}\n */\nexport function buildComponentInstance(comp: ComponentEntry): JxMutableNode {\n const $props = Object.fromEntries(\n (comp.props ?? []).map((p) => [p.name, p.default !== undefined ? p.default : \"\"]),\n );\n const children: (JxMutableNode | string)[] = [];\n for (const slot of comp.slots ?? []) {\n for (const child of structuredClone(slot.fallback ?? [])) {\n if (!slot.name) {\n children.push(child);\n } else if (typeof child === \"object\" && child !== null && typeof child.tagName === \"string\") {\n // Preserve an author-set slot attribute (slot forwarding inside fallback).\n child.attributes = { slot: slot.name, ...child.attributes };\n children.push(child);\n } else {\n // Text and non-element nodes can't carry a slot attribute — wrap them.\n children.push({ attributes: { slot: slot.name }, children: [child], tagName: \"span\" });\n }\n }\n }\n return {\n $props,\n tagName: comp.tagName,\n ...(children.length > 0 ? { children } : {}),\n };\n}\n\n/**\n * @param {string | null} fromDocPath\n * @param {string} toCompPath\n */\nexport function computeRelativePath(fromDocPath: string | null, toCompPath: string) {\n if (!fromDocPath) {\n return `./${toCompPath}`;\n }\n const from = fromDocPath.replaceAll(\"\\\\\", \"/\");\n const to = toCompPath.replaceAll(\"\\\\\", \"/\");\n const fromDir = from.includes(\"/\") ? from.slice(0, from.lastIndexOf(\"/\")) : \"\";\n const fromParts = fromDir.split(\"/\").filter(Boolean);\n const toParts = to.split(\"/\").filter(Boolean);\n let common = 0;\n while (\n common < fromParts.length &&\n common < toParts.length &&\n fromParts[common] === toParts[common]\n ) {\n common += 1;\n }\n const ups = fromParts.length - common;\n const remaining = toParts.slice(common);\n return (ups > 0 ? \"../\".repeat(ups) : \"./\") + remaining.join(\"/\");\n}\n"
6
- ],
7
- "mappings": ";;;;;;;;AAeO,IAAI,oBAAsC,CAAC;AAC3C,IAAI,2BAA2B;AAEtC,eAAsB,qBAAqB,GAAG;AAAA,EAC5C,IAAI;AAAA,IACF,MAAM,WAAW,YAAY;AAAA,IAC7B,oBAAoB,MAAM,SAAS,mBAAmB,cAAc,eAAe,SAAS;AAAA,IAC5F,2BAA2B;AAAA,IAC3B,MAAM;AAAA,IACN,2BAA2B;AAAA;AAAA;AAcxB,SAAS,sBAAsB,CAAC,MAAqC;AAAA,EAC1E,MAAM,SAAS,OAAO,aACnB,KAAK,SAAS,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,YAAY,YAAY,EAAE,UAAU,EAAE,CAAC,CAClF;AAAA,EACA,MAAM,WAAuC,CAAC;AAAA,EAC9C,WAAW,QAAQ,KAAK,SAAS,CAAC,GAAG;AAAA,IACnC,WAAW,SAAS,gBAAgB,KAAK,YAAY,CAAC,CAAC,GAAG;AAAA,MACxD,IAAI,CAAC,KAAK,MAAM;AAAA,QACd,SAAS,KAAK,KAAK;AAAA,MACrB,EAAO,SAAI,OAAO,UAAU,YAAY,UAAU,QAAQ,OAAO,MAAM,YAAY,UAAU;AAAA,QAE3F,MAAM,aAAa,EAAE,MAAM,KAAK,SAAS,MAAM,WAAW;AAAA,QAC1D,SAAS,KAAK,KAAK;AAAA,MACrB,EAAO;AAAA,QAEL,SAAS,KAAK,EAAE,YAAY,EAAE,MAAM,KAAK,KAAK,GAAG,UAAU,CAAC,KAAK,GAAG,SAAS,OAAO,CAAC;AAAA;AAAA,IAEzF;AAAA,EACF;AAAA,EACA,OAAO;AAAA,IACL;AAAA,IACA,SAAS,KAAK;AAAA,OACV,SAAS,SAAS,IAAI,EAAE,SAAS,IAAI,CAAC;AAAA,EAC5C;AAAA;AAOK,SAAS,mBAAmB,CAAC,aAA4B,YAAoB;AAAA,EAClF,IAAI,CAAC,aAAa;AAAA,IAChB,OAAO,KAAK;AAAA,EACd;AAAA,EACA,MAAM,OAAO,YAAY,WAAW,MAAM,GAAG;AAAA,EAC7C,MAAM,KAAK,WAAW,WAAW,MAAM,GAAG;AAAA,EAC1C,MAAM,UAAU,KAAK,SAAS,GAAG,IAAI,KAAK,MAAM,GAAG,KAAK,YAAY,GAAG,CAAC,IAAI;AAAA,EAC5E,MAAM,YAAY,QAAQ,MAAM,GAAG,EAAE,OAAO,OAAO;AAAA,EACnD,MAAM,UAAU,GAAG,MAAM,GAAG,EAAE,OAAO,OAAO;AAAA,EAC5C,IAAI,SAAS;AAAA,EACb,OACE,SAAS,UAAU,UACnB,SAAS,QAAQ,UACjB,UAAU,YAAY,QAAQ,SAC9B;AAAA,IACA,UAAU;AAAA,EACZ;AAAA,EACA,MAAM,MAAM,UAAU,SAAS;AAAA,EAC/B,MAAM,YAAY,QAAQ,MAAM,MAAM;AAAA,EACtC,QAAQ,MAAM,IAAI,MAAM,OAAO,GAAG,IAAI,QAAQ,UAAU,KAAK,GAAG;AAAA;",
8
- "debugId": "37666BFABEF9083664756E2164756E21",
9
- "names": []
10
- }
@@ -1,10 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../src/platform.ts"],
4
- "sourcesContent": [
5
- "/// <reference lib=\"dom\" />\n/**\n * Platform.js — Platform Abstraction Layer (PAL)\n *\n * Studio is backend-agnostic. Each deployment target (desktop, dev server, cloud) registers a\n * platform adapter at startup. All file I/O, project loading, and component discovery goes through\n * this interface.\n *\n * Uses window.__jxPlatform so the platform can be registered from a separate script bundle (e.g.\n * init.js) before studio.js loads.\n *\n * See spec/desktop.md §3 for the full StudioPlatform interface.\n *\n * **Every call is counted.** `getPlatform()` hands out a counting proxy, not the raw adapter, so\n * \"is Studio waiting on I/O?\" is one number rather than thirty hand-instrumented methods\n * (`probe.idle()` condition 4, spec §13.5). Wrapping at the READ point rather than at\n * `registerPlatform` is deliberate: desktop pre-registers its adapter on `window.__jxPlatform`\n * without ever calling the registrar, and this is the seam both paths share.\n */\n\nimport type { StudioPlatform } from \"./types\";\n\nconst g = globalThis as unknown as { __jxPlatform?: StudioPlatform };\n\n/** @param {StudioPlatform} platform */\nexport function registerPlatform(platform: StudioPlatform) {\n g.__jxPlatform = platform;\n}\n\n// ─── In-flight accounting ─────────────────────────────────────────────────────\n\n/** Method name → how many of its calls have not settled. Entries are deleted at zero. */\nconst inFlight = new Map<string, number>();\n\n/**\n * One entry per platform call whose promise has not settled, named by its method.\n *\n * Repeats are meaningful: two concurrent `gitStatus` reads are two reasons the shell is not\n * settled, and the rejection message that names them is the whole point of §13.4 — 115 sleeps were\n * 115 places that could not fail.\n */\nexport function platformInFlight(): string[] {\n const names: string[] = [];\n for (const [method, count] of inFlight) {\n for (let i = 0; i < count; i++) {\n names.push(method);\n }\n }\n return names;\n}\n\nfunction enter(method: string): void {\n inFlight.set(method, (inFlight.get(method) ?? 0) + 1);\n}\n\nfunction leave(method: string): void {\n const count = (inFlight.get(method) ?? 1) - 1;\n if (count > 0) {\n inFlight.set(method, count);\n } else {\n inFlight.delete(method);\n }\n}\n\n/**\n * Wrap an adapter so every promise-returning member is counted while it is outstanding.\n *\n * Synchronous members are passed through untouched — they cannot be outstanding. Wrappers are\n * memoised per property so `platform.readFile === platform.readFile`, which matters because call\n * sites cache and compare these (`live-context.ts` tests `typeof platform[key] === \"function\"` to\n * derive `capability.*`, and a fresh closure per read would allocate on every predicate).\n */\nfunction countingPlatform(platform: StudioPlatform): StudioPlatform {\n const wrappers = new Map<PropertyKey, { raw: unknown; wrapper: unknown }>();\n return new Proxy(platform, {\n get(target, property) {\n // `this` stays the raw adapter: a proxy receiver would re-enter this trap for every internal\n // Property read the method makes, counting nothing and costing everything.\n const value = Reflect.get(target, property) as unknown;\n if (typeof value !== \"function\" || typeof property !== \"string\") {\n return value;\n }\n // Keyed by the FUNCTION, not just the name: an adapter whose method is replaced later (a\n // Lazily-installed capability, a test swapping one out) must not keep answering through a\n // Wrapper closed over the old implementation.\n const cached = wrappers.get(property);\n if (cached && cached.raw === value) {\n return cached.wrapper;\n }\n const method = property;\n const wrapper = (...args: unknown[]): unknown => {\n const result = (value as (...a: unknown[]) => unknown).apply(target, args);\n if (typeof (result as PromiseLike<unknown> | null)?.then !== \"function\") {\n return result;\n }\n enter(method);\n const settle = () => {\n leave(method);\n };\n // Both arms: a rejected platform call is a call that FINISHED. Leaving it counted would\n // Wedge every later `idle()` behind an error the caller already handled.\n (result as PromiseLike<unknown>).then(settle, settle);\n return result;\n };\n wrappers.set(property, { raw: value, wrapper });\n return wrapper;\n },\n });\n}\n\n/** The adapter the counting proxy currently wraps, so re-registration re-wraps and nothing else. */\nlet counted: { raw: StudioPlatform; wrapped: StudioPlatform } | null = null;\n\n/** @returns {StudioPlatform} */\nexport function getPlatform() {\n const raw = g.__jxPlatform;\n if (!raw) {\n throw new Error(\"No platform registered. Call registerPlatform() before starting Studio.\");\n }\n if (counted?.raw !== raw) {\n counted = { raw, wrapped: countingPlatform(raw) };\n }\n return counted.wrapped;\n}\n\n/** @returns {boolean} */\nexport function hasPlatform() {\n return g.__jxPlatform != null;\n}\n"
6
- ],
7
- "mappings": ";AAsBA,IAAM,IAAI;AAGH,SAAS,gBAAgB,CAAC,UAA0B;AAAA,EACzD,EAAE,eAAe;AAAA;AAMnB,IAAM,WAAW,IAAI;AASd,SAAS,gBAAgB,GAAa;AAAA,EAC3C,MAAM,QAAkB,CAAC;AAAA,EACzB,YAAY,QAAQ,UAAU,UAAU;AAAA,IACtC,SAAS,IAAI,EAAG,IAAI,OAAO,KAAK;AAAA,MAC9B,MAAM,KAAK,MAAM;AAAA,IACnB;AAAA,EACF;AAAA,EACA,OAAO;AAAA;AAGT,SAAS,KAAK,CAAC,QAAsB;AAAA,EACnC,SAAS,IAAI,SAAS,SAAS,IAAI,MAAM,KAAK,KAAK,CAAC;AAAA;AAGtD,SAAS,KAAK,CAAC,QAAsB;AAAA,EACnC,MAAM,SAAS,SAAS,IAAI,MAAM,KAAK,KAAK;AAAA,EAC5C,IAAI,QAAQ,GAAG;AAAA,IACb,SAAS,IAAI,QAAQ,KAAK;AAAA,EAC5B,EAAO;AAAA,IACL,SAAS,OAAO,MAAM;AAAA;AAAA;AAY1B,SAAS,gBAAgB,CAAC,UAA0C;AAAA,EAClE,MAAM,WAAW,IAAI;AAAA,EACrB,OAAO,IAAI,MAAM,UAAU;AAAA,IACzB,GAAG,CAAC,QAAQ,UAAU;AAAA,MAGpB,MAAM,QAAQ,QAAQ,IAAI,QAAQ,QAAQ;AAAA,MAC1C,IAAI,OAAO,UAAU,cAAc,OAAO,aAAa,UAAU;AAAA,QAC/D,OAAO;AAAA,MACT;AAAA,MAIA,MAAM,SAAS,SAAS,IAAI,QAAQ;AAAA,MACpC,IAAI,UAAU,OAAO,QAAQ,OAAO;AAAA,QAClC,OAAO,OAAO;AAAA,MAChB;AAAA,MACA,MAAM,SAAS;AAAA,MACf,MAAM,UAAU,IAAI,SAA6B;AAAA,QAC/C,MAAM,SAAU,MAAuC,MAAM,QAAQ,IAAI;AAAA,QACzE,IAAI,OAAQ,QAAwC,SAAS,YAAY;AAAA,UACvE,OAAO;AAAA,QACT;AAAA,QACA,MAAM,MAAM;AAAA,QACZ,MAAM,SAAS,MAAM;AAAA,UACnB,MAAM,MAAM;AAAA;AAAA,QAIb,OAAgC,KAAK,QAAQ,MAAM;AAAA,QACpD,OAAO;AAAA;AAAA,MAET,SAAS,IAAI,UAAU,EAAE,KAAK,OAAO,QAAQ,CAAC;AAAA,MAC9C,OAAO;AAAA;AAAA,EAEX,CAAC;AAAA;AAIH,IAAI,UAAmE;AAGhE,SAAS,WAAW,GAAG;AAAA,EAC5B,MAAM,MAAM,EAAE;AAAA,EACd,IAAI,CAAC,KAAK;AAAA,IACR,MAAM,IAAI,MAAM,yEAAyE;AAAA,EAC3F;AAAA,EACA,IAAI,SAAS,QAAQ,KAAK;AAAA,IACxB,UAAU,EAAE,KAAK,SAAS,iBAAiB,GAAG,EAAE;AAAA,EAClD;AAAA,EACA,OAAO,QAAQ;AAAA;AAIV,SAAS,WAAW,GAAG;AAAA,EAC5B,OAAO,EAAE,gBAAgB;AAAA;",
8
- "debugId": "02671227FE10A79C64756E2164756E21",
9
- "names": []
10
- }
@@ -1,10 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../schema/defs/field-schema.schema.ts"],
4
- "sourcesContent": [
5
- "/**\n * Field-schema vocabulary (specs/extensions.md §5.3, specs/relationships.md).\n *\n * JxFieldSchema is the JSON-Schema-subset shape for a single field inside a section entry schema\n * (content frontmatter fields, table columns). Recursive positions (`items`, nested `properties`)\n * reference the well-known **fields resource URI** — a schema resource the generated per-project\n * entry document re-embeds under the same `$id` with the effective union (core shape +\n * RelationshipRef + extension extras), shadowing the shipped default by standard compound-document\n * `$id` resolution. Extension fragments reference the same URI at their field positions.\n *\n * (An earlier design used `$dynamicRef`/`$dynamicAnchor` here; ajv restricts `$dynamicAnchor` to\n * schema-resource roots, which cannot express a non-root recursion unit, so the model uses plain\n * `$id` indirection instead — verified against ajv 8.20 / 2020-12.)\n */\n\n/** The well-known $id of the project field-schema union resource. */\nexport const PROJECT_FIELDS_SCHEMA_ID = \"https://jxsuite.com/schema/project/fields/v2\";\n\n/** The well-known $id of the document $paths-value union resource. */\nexport const DOCUMENT_PATHS_SCHEMA_ID = \"https://jxsuite.com/schema/document/paths/v2\";\n\nexport const jxFieldSchemaDef = {\n description:\n \"A single field definition inside a section entry schema — a small, recursive subset of \" +\n \"JSON Schema. Recursive positions reference the effective field union via the well-known \" +\n \"fields resource $id.\",\n properties: {\n default: {},\n description: { type: \"string\" },\n enum: { type: \"array\" },\n format: { type: \"string\" },\n items: { $ref: PROJECT_FIELDS_SCHEMA_ID },\n properties: {\n additionalProperties: { $ref: PROJECT_FIELDS_SCHEMA_ID },\n type: \"object\",\n },\n required: { items: { type: \"string\" }, type: \"array\" },\n type: {\n enum: [\"string\", \"number\", \"integer\", \"boolean\", \"array\", \"object\"],\n type: \"string\",\n },\n },\n required: [\"type\"],\n type: \"object\",\n} as const;\n\nexport const relationshipRefSchema = {\n description:\n \"Relationship reference field: points at a named entry of a referenceable section via \" +\n '\"#/<sectionKey>/<name>\" (specs/relationships.md). A bare reference is to-one; wrap in an ' +\n \"array field's items for to-many.\",\n properties: {\n $ref: { pattern: \"^#/[A-Za-z][A-Za-z0-9_-]*/[A-Za-z0-9._-]+$\", type: \"string\" },\n description: { type: \"string\" },\n },\n required: [\"$ref\"],\n type: \"object\",\n} as const;\n\n/**\n * The CORE `$paths` source shapes — the members the shipped default paths union carries, and the\n * ones every per-project entry document unions extension shapes on top of.\n *\n * These mirror `resolvePathEntries` in the compiler's pages-discovery exactly (specs/\n * site-architecture.md §4.3): an explicit value list, a JSON data-file reference, and the legacy\n * bare array of parameter objects. Anything else is dispatched by discriminator key to an\n * extension's `resolvePaths` capability, so extension shapes reach the union through the entry\n * document rather than from here.\n *\n * Each shape is CLOSED (`additionalProperties: false`). `$paths` is a build-time instruction with a\n * fully specified grammar and no forward-compatible extension points of its own — a stray or\n * misspelled key means the route silently expands to nothing, which is exactly the failure worth\n * catching in the editor.\n */\nexport const documentPathsCoreMembers = [\n {\n additionalProperties: false,\n description:\n 'Explicit value list: generates one page per value, bound to `param` (default \"value\").',\n properties: {\n param: { description: 'Route parameter to fill (default \"value\").', type: \"string\" },\n values: { description: \"The values to expand.\", type: \"array\" },\n },\n required: [\"values\"],\n type: \"object\",\n },\n {\n additionalProperties: false,\n description:\n \"JSON data-file source: loads a project-relative file that must contain an array, and \" +\n \"generates one page per item.\",\n properties: {\n $ref: {\n description: \"Project-relative path to a .json file containing an array.\",\n type: \"string\",\n },\n field: {\n description: 'Item field providing the parameter value (default \"id\").',\n type: \"string\",\n },\n param: { description: 'Route parameter to fill (default \"id\").', type: \"string\" },\n },\n required: [\"$ref\"],\n type: \"object\",\n },\n {\n description:\n \"Legacy explicit form: an array of ready-made parameter objects, used as-is with no \" +\n \"expansion. Prefer one of the source shapes above.\",\n items: { additionalProperties: { type: \"string\" }, type: \"object\" },\n type: \"array\",\n },\n] as const;\n\n/**\n * The extra member the SHIPPED DEFAULT union carries and a per-project entry document does not.\n *\n * A default cannot know which extensions a project enables, so without this any extension source\n * shape — `{ contentType: \"blog\" }` with the parser on — would be a FALSE ERROR wherever the\n * default is what is in play: the studio's offline fallback before per-project schemas arrive, and\n * clients that fetch the canonical URL. Spec §5.4 promises that path degrades to\n * _under-suggestion_, never false errors, so the default accepts any non-empty object and the entry\n * document — which does know the enabled extensions, and is what `jx validate` and every editor\n * actually resolve — is the strict one.\n */\nexport const documentPathsUnknownSourceMember = {\n description:\n \"A source shape contributed by an extension this schema cannot see. The project's generated \" +\n \"document.schema.json validates these exactly; enable the owning extension and regenerate \" +\n \"with `jx schema` to get precise checking here.\",\n minProperties: 1,\n type: \"object\",\n} as const;\n"
6
- ],
7
- "mappings": ";AAgBO,IAAM,2BAA2B;AAKjC,IAAM,mBAAmB;AAAA,EAC9B,aACE,4FACA,6FACA;AAAA,EACF,YAAY;AAAA,IACV,SAAS,CAAC;AAAA,IACV,aAAa,EAAE,MAAM,SAAS;AAAA,IAC9B,MAAM,EAAE,MAAM,QAAQ;AAAA,IACtB,QAAQ,EAAE,MAAM,SAAS;AAAA,IACzB,OAAO,EAAE,MAAM,yBAAyB;AAAA,IACxC,YAAY;AAAA,MACV,sBAAsB,EAAE,MAAM,yBAAyB;AAAA,MACvD,MAAM;AAAA,IACR;AAAA,IACA,UAAU,EAAE,OAAO,EAAE,MAAM,SAAS,GAAG,MAAM,QAAQ;AAAA,IACrD,MAAM;AAAA,MACJ,MAAM,CAAC,UAAU,UAAU,WAAW,WAAW,SAAS,QAAQ;AAAA,MAClE,MAAM;AAAA,IACR;AAAA,EACF;AAAA,EACA,UAAU,CAAC,MAAM;AAAA,EACjB,MAAM;AACR;AAEO,IAAM,wBAAwB;AAAA,EACnC,aACE,0FACA,8FACA;AAAA,EACF,YAAY;AAAA,IACV,MAAM,EAAE,SAAS,8CAA8C,MAAM,SAAS;AAAA,IAC9E,aAAa,EAAE,MAAM,SAAS;AAAA,EAChC;AAAA,EACA,UAAU,CAAC,MAAM;AAAA,EACjB,MAAM;AACR;AAiBO,IAAM,2BAA2B;AAAA,EACtC;AAAA,IACE,sBAAsB;AAAA,IACtB,aACE;AAAA,IACF,YAAY;AAAA,MACV,OAAO,EAAE,aAAa,8CAA8C,MAAM,SAAS;AAAA,MACnF,QAAQ,EAAE,aAAa,yBAAyB,MAAM,QAAQ;AAAA,IAChE;AAAA,IACA,UAAU,CAAC,QAAQ;AAAA,IACnB,MAAM;AAAA,EACR;AAAA,EACA;AAAA,IACE,sBAAsB;AAAA,IACtB,aACE,0FACA;AAAA,IACF,YAAY;AAAA,MACV,MAAM;AAAA,QACJ,aAAa;AAAA,QACb,MAAM;AAAA,MACR;AAAA,MACA,OAAO;AAAA,QACL,aAAa;AAAA,QACb,MAAM;AAAA,MACR;AAAA,MACA,OAAO,EAAE,aAAa,2CAA2C,MAAM,SAAS;AAAA,IAClF;AAAA,IACA,UAAU,CAAC,MAAM;AAAA,IACjB,MAAM;AAAA,EACR;AAAA,EACA;AAAA,IACE,aACE,wFACA;AAAA,IACF,OAAO,EAAE,sBAAsB,EAAE,MAAM,SAAS,GAAG,MAAM,SAAS;AAAA,IAClE,MAAM;AAAA,EACR;AACF;AAaO,IAAM,mCAAmC;AAAA,EAC9C,aACE,gGACA,8FACA;AAAA,EACF,eAAe;AAAA,EACf,MAAM;AACR;",
8
- "debugId": "48AAE1140CF35C2C64756E2164756E21",
9
- "names": []
10
- }
@@ -1,11 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../src/services/monaco-lazy.ts", "../src/format/format-host.ts"],
4
- "sourcesContent": [
5
- "/**\n * Lazy Monaco.\n *\n * Monaco is 12.6 MB of the studio bundle — two thirds of it — and most sessions never open a code\n * view. It used to be pulled in by a static `import * as monaco` in three modules plus a\n * side-effect `import \"./services/monaco-setup.js\"` from `studio.ts`, so every cold start\n * downloaded, parsed and evaluated the editor, its TypeScript/JSON/JavaScript language\n * contributions, and a `flattenSchema` pass over a 497 KB schema before first paint.\n *\n * Loading is deferred to the first code surface that actually needs it: source mode, the function\n * editor, the formula workspace. `loadMonaco()` is memoized, so concurrent callers share one import\n * and the language contributions register exactly once.\n *\n * Two accessors, deliberately:\n *\n * - {@link loadMonaco} for code that MOUNTS an editor. Those call sites are lit `ref()` DOM-attach\n * callbacks or already-async paths, so awaiting is free.\n * - {@link loadedMonaco} for code that can only run once an editor exists (setting markers on a\n * model, comparing a live editor's model URI). Returning the already-resolved namespace\n * synchronously keeps those paths sync — no async ripple through the render tree for a module\n * that is provably present.\n */\n\n/* `monaco-editor/editor`, not the package root. In 0.56 the root is an everything-barrel that also\n exports the `css` / `html` / `json` / `typescript` / `lsp` language namespaces, none of which is\n on the object {@link loadMonaco} resolves to — typing this as the root would make five namespaces\n look available that are not. `./editor` is exactly the editor API surface that import returns. */\nimport type * as monacoNs from \"monaco-editor/editor\";\n\nexport type Monaco = typeof monacoNs;\n\nlet _monaco: Monaco | null = null;\nlet _loading: Promise<Monaco> | null = null;\n\n/**\n * The active project's generated entry schemas, held until Monaco exists to receive them.\n *\n * These arrive at project activation — long before anyone opens a code view — and applying them\n * used to mean `import(\"./monaco-setup\")` right then. A dynamic import that EXECUTES at startup\n * defers evaluation by a tick but still fetches: Monaco went over the wire on every cold load,\n * which is precisely what the lazy path exists to avoid. So the schemas wait here instead, and the\n * loader applies whatever is pending once an editor actually needs one.\n */\nlet _pendingSchemas: { project?: unknown; document?: unknown } | null = null;\nlet _pendingSchemasDirty = false;\n\n/**\n * Record the active project's schemas for Monaco's JSON diagnostics.\n *\n * Applied immediately when Monaco is already loaded, otherwise on the next {@link loadMonaco}. Only\n * the LATEST set matters — reactivation and `project.json` writes both call this — so it overwrites\n * rather than queues.\n *\n * @returns Settles once the schemas are in force. Fire-and-forget is a valid use — say so with\n * `void` at the call site rather than having this hide it.\n */\nexport function setProjectSchemasForMonaco(\n schemas: { project?: unknown; document?: unknown } | null,\n): Promise<void> {\n _pendingSchemas = schemas;\n _pendingSchemasDirty = true;\n /* Resolves when the schemas have REACHED Monaco, not when they were queued. With Monaco already\n loaded that is a dynamic import away, and discarding the promise here left no caller — the\n app's or a test's — able to tell \"applied\" from \"about to be\": the only way to observe it was\n to guess a number of microtasks. `loadMonaco()` already awaits the same call on its own path,\n so this makes the two doors symmetric rather than adding a new contract. */\n return _monaco ? applyPendingSchemas() : Promise.resolve();\n}\n\n/** Push any pending schemas into Monaco's JSON diagnostics. No-op when nothing changed. */\nasync function applyPendingSchemas(): Promise<void> {\n if (!_pendingSchemasDirty) {\n return;\n }\n _pendingSchemasDirty = false;\n try {\n const { applyProjectSchemas } = await import(\"./monaco-setup.js\");\n applyProjectSchemas(_pendingSchemas);\n } catch {\n // Editor degradation: the bundled core schemas stay in force.\n }\n}\n\n/**\n * Load Monaco and its Jx configuration (workers, JSON schemas, TS/JS contributions). Memoized.\n *\n * The `monaco-setup` import is what registers the language contributions and the worker factory, so\n * it must resolve before an editor is created — hence both imports awaited here rather than left to\n * whichever module happens to be evaluated first.\n */\nexport function loadMonaco(): Promise<Monaco> {\n if (_monaco) {\n return Promise.resolve(_monaco);\n }\n // Not `async`: an async function wraps the memo in a fresh promise per call, so concurrent callers\n // Could not observe that they share one in-flight load. Returning `_loading` itself makes the\n // Load-once guarantee visible (and testable) rather than merely true.\n _loading ??= (async () => {\n const [monaco] = await Promise.all([\n import(\"monaco-editor/editor\"),\n import(\"./monaco-setup.js\"),\n ]);\n _monaco = monaco as unknown as Monaco;\n // The project's schemas may have arrived long before now; register them before the first editor\n // Mounts so its very first validation pass uses the right rules.\n await applyPendingSchemas();\n return _monaco;\n })();\n return _loading;\n}\n\n/**\n * The loaded Monaco namespace, or null when no code surface has opened yet.\n *\n * For call sites reachable ONLY with a live editor in hand — they cannot observe null in practice,\n * but they must not force the module to load either.\n */\nexport function loadedMonaco(): Monaco | null {\n return _monaco;\n}\n\n/**\n * Whether the mount started before {@link loadMonaco} is still the one the app wants.\n *\n * **The question you owe on the far side of the load, which is why it lives beside the load.** A\n * cold `loadMonaco()` is a 12.6 MB dynamic import; the user has hundreds of milliseconds inside it\n * to close the surface, retarget it, or leave the mode — and a second render has the same window to\n * start a mount of its own. Both surfaces need it and each had its own spelling of it, so the\n * source view simply did without: `renderCanvasImpl` assigns `surface.prevCanvasMode` BEFORE it\n * reaches the mount, so a second synchronous `renderCanvas()` during the load sees `modeChanged ===\n * false` and a null `view.monacoEditor`, skips the fast path and mounts again. The second mount\n * then calls `createModel` with a URI the first already registered, which real Monaco throws on\n * (\"ERR: Another model with the same URI\"), and `store.ts`'s `render()`/`renderOnly()` coalesce\n * nothing.\n *\n * Returning false means creating NOTHING — no model, no editor, no `automaticLayout` observer. That\n * is strictly better than creating and disposing: there is no window in which a doomed editor is\n * attached to anything, and no URI briefly claimed by a model nobody holds.\n *\n * @param {Element | null | undefined} container Where the editor was going to be created.\n * @param {unknown} existing The surface's editor handle (`view.monacoEditor` /\n * `view.functionEditor`). Non-null means another mount already won this race.\n * @param {() => boolean} stillTargeted Whether the app still wants exactly THIS mount — the same\n * tab, the same mode, the same editing target. Lazy: the two cheap clauses above answer first.\n * @returns {boolean}\n */\nexport function mountStillWanted(\n container: Element | null | undefined,\n existing: unknown,\n stillTargeted: () => boolean,\n): boolean {\n if (!container?.isConnected || existing) {\n return false;\n }\n return stillTargeted();\n}\n\n/** Whether Monaco has been loaded (tests, and the odd diagnostic). */\nexport function isMonacoLoaded(): boolean {\n return _monaco !== null;\n}\n\n/** Reset the memo (tests only). */\nexport function resetMonacoLazy(): void {\n _monaco = null;\n _loading = null;\n _pendingSchemas = null;\n _pendingSchemasDirty = false;\n}\n",
6
- "/**\n * Format-host — the studio's view of the project's format registry.\n *\n * Format classes are auto-discovered server-side from the project imports map\n * (specs/extensions.md); the studio introspects them via the PAL (`listFormats`) and invokes\n * parse/serialize capabilities via `formatAction` (POST /__studio/format in the dev server, RPC on\n * desktop). The studio itself holds zero format knowledge — `.json` is the single native built-in.\n */\n\nimport { setProjectSchemasForMonaco } from \"../services/monaco-lazy\";\nimport { getPlatform } from \"../platform\";\nimport type { ExtensionsInfo } from \"../types\";\nimport type { JxMutableNode } from \"@jxsuite/schema/types\";\n\nexport interface StudioFormatHints {\n icon?: string;\n modes?: string[];\n documentMode?: {\n default?: \"content\" | \"component\";\n componentWhen?: { frontmatterKey?: string; matches?: string };\n };\n newFileTemplate?: string;\n elements?: {\n block?: string[];\n inline?: string[];\n void?: string[];\n textOnly?: string[];\n nesting?: Record<\n string,\n {\n block?: boolean;\n inline?: boolean;\n directive?: boolean;\n only?: string[];\n }\n >;\n };\n [key: string]: unknown;\n}\n\nexport interface StudioFormat {\n name: string;\n extensions: string[];\n mediaType: string | null;\n documentKinds: string[];\n exportTarget: boolean;\n remote: boolean;\n studio: StudioFormatHints | null;\n capabilities: Record<string, { identifier: string; timing: string[] }>;\n}\n\nlet _formats: StudioFormat[] = [];\nlet _loaded: Promise<StudioFormat[]> | null = null;\n\n/** Load (and cache) the project's format registry from the platform. */\nexport function loadFormats(): Promise<StudioFormat[]> {\n if (!_loaded) {\n _loaded = (async () => {\n try {\n const platform = getPlatform() as {\n listFormats?: () => Promise<StudioFormat[]>;\n };\n _formats = (await platform.listFormats?.()) ?? [];\n } catch {\n _formats = [];\n }\n return _formats;\n })();\n }\n return _loaded;\n}\n\n/** Invalidate the cached registry and extensions payload (call on project switch). */\nexport function refreshFormats() {\n _loaded = null;\n _formats = [];\n _extensionsLoaded = null;\n _extensions = [];\n}\n\n/** Seed the registry directly (tests and hosts that preload format metadata). */\nexport function setFormats(formats: StudioFormat[]) {\n _formats = formats;\n _loaded = Promise.resolve(formats);\n}\n\n// ─── Extensions payload (specs/extensions.md §9/§9.1) ────────────────────────\n\nlet _extensions: ExtensionsInfo[] = [];\nlet _extensionsLoaded: Promise<ExtensionsInfo[]> | null = null;\n\n/**\n * Load (and cache) the project's enabled extensions with their project-section contributions.\n * Backed by the platform's optional `listExtensions` member; platforms without it (or failures)\n * degrade to an empty list, hiding descriptor-contributed settings sections.\n */\nexport function loadExtensions(): Promise<ExtensionsInfo[]> {\n if (!_extensionsLoaded) {\n _extensionsLoaded = (async () => {\n try {\n const platform = getPlatform() as {\n listExtensions?: () => Promise<ExtensionsInfo[]>;\n };\n _extensions = (await platform.listExtensions?.()) ?? [];\n } catch {\n _extensions = [];\n }\n return _extensions;\n })();\n }\n return _extensionsLoaded;\n}\n\n/** The last-loaded extensions payload (synchronous access for render paths). */\nexport function getExtensions(): ExtensionsInfo[] {\n return _extensions;\n}\n\n/** Seed the extensions payload directly (tests and hosts that preload it). */\nexport function setExtensions(extensions: ExtensionsInfo[]) {\n _extensions = extensions;\n _extensionsLoaded = Promise.resolve(extensions);\n}\n\n/**\n * Fetch the active project's entry documents ONCE and hand the same payload to every consumer.\n *\n * The backends regenerate entry documents that are missing or older than `project.json` and write\n * them to disk (extensions.md §5.2), so a second concurrent fetch is not a harmless duplicate — it\n * races the first on the same two files. One fetch also guarantees Monaco's diagnostics and the AI\n * assistant's gate judge a document by the SAME schema; when they disagree the model ships work its\n * own tool call called clean and the editor immediately paints red.\n *\n * @param {object} platform - The studio platform (only `fetchProjectSchemas` is consulted)\n * @returns {Promise<void>} Resolves once both consumers have been updated\n */\nasync function shareProjectSchemas(platform: {\n fetchProjectSchemas?: () => Promise<{ project?: unknown; document?: unknown }>;\n}): Promise<void> {\n let schemas: { project?: unknown; document?: unknown } | null = null;\n try {\n schemas = (await platform.fetchProjectSchemas?.()) ?? null;\n } catch {\n // Editor degradation: both consumers keep the bundled core schemas.\n }\n // Monaco's copy is HELD, not applied: this runs at project activation, and importing monaco-setup\n // Here would fetch the whole editor on every cold load for a code view most sessions never open.\n // `services/monaco-lazy` registers them when an editor is actually created.\n // Fire-and-forget: activation must not wait on Monaco, and a failure degrades to core schemas.\n void setProjectSchemasForMonaco(schemas);\n await import(\"../services/jx-validate\")\n .then(({ applyProjectSchemas }) => applyProjectSchemas(schemas))\n .catch(() => false);\n}\n\n/**\n * Fire-and-forget refresh of the extension-facing editor surface after project (re)activation, a\n * `project.json` write, or an `extensions` change: the per-project schemas behind Monaco's\n * diagnostics and the AI assistant's validation gate, plus the descriptor-contributed settings\n * sections. Every module loads lazily — monaco is heavy and the settings registry pulls DOM\n * templates — and all of them degrade silently (core schemas, built-in sections only).\n *\n * @param {object} platform - The studio platform (only `fetchProjectSchemas` is consulted here)\n */\nexport function refreshExtensionUi(platform: {\n fetchProjectSchemas?: () => Promise<{ project?: unknown; document?: unknown }>;\n}): void {\n void shareProjectSchemas(platform);\n void import(\"../settings/extension-sections\")\n .then(({ syncExtensionSettingsSections }) => syncExtensionSettingsSections())\n .catch(() => {\n // Contributed sections also refresh on the next settings-modal open.\n });\n}\n\n/** The last-loaded registry (synchronous access for render paths). */\nexport function getFormats(): StudioFormat[] {\n return _formats;\n}\n\n/** Look up the format claiming a file extension (\".md\" or \"md\"), optionally by capability. */\nexport function formatByExtension(ext: string, capability?: string): StudioFormat | undefined {\n const norm = ext.startsWith(\".\") ? ext.toLowerCase() : `.${ext.toLowerCase()}`;\n return _formats.find(\n (f) => f.extensions.includes(norm) && (!capability || f.capabilities[capability]),\n );\n}\n\n/** Look up a format by its import name. */\nexport function formatByName(name: string | null | undefined): StudioFormat | undefined {\n if (!name) {\n return undefined;\n }\n return _formats.find((f) => f.name === name);\n}\n\n/** Error for opening a non-JSON file when no imported format class claims its extension. */\nexport function noFormatError(path: string): Error {\n return new Error(\n `No format class imported for \"${path}\" — add one to project.json imports ` +\n `(e.g. \"Markdown\": \"@jxsuite/parser/Markdown.class.json\") and make sure the ` +\n `project's dependencies are installed`,\n );\n}\n\n/** The format claiming a file path's extension, if any. */\nexport function formatForPath(path: string | null | undefined): StudioFormat | undefined {\n if (!path) {\n return undefined;\n }\n const dot = path.lastIndexOf(\".\");\n if (dot === -1) {\n return undefined;\n }\n return formatByExtension(path.slice(dot));\n}\n\n/** Registered extensions, optionally filtered by document kind. Never includes \".json\". */\nexport function documentExtensions(kind?: string): string[] {\n const exts = new Set<string>();\n for (const f of _formats) {\n if (kind && !f.documentKinds.includes(kind)) {\n continue;\n }\n for (const e of f.extensions) {\n exts.add(e);\n }\n }\n exts.delete(\".json\");\n return [...exts];\n}\n\n/** The default format for new content documents (first content-kind serializer). */\nexport function defaultContentFormat(): StudioFormat | undefined {\n return _formats.find((f) => f.capabilities.serialize && f.documentKinds.includes(\"content\"));\n}\n\nasync function formatAction(payload: Record<string, unknown>): Promise<unknown> {\n const platform = getPlatform() as {\n formatAction?: (payload: Record<string, unknown>) => Promise<unknown>;\n };\n if (!platform.formatAction) {\n throw new Error(\"Platform does not support format actions\");\n }\n return platform.formatAction(payload);\n}\n\n/** Parse source text into a Jx document via the named format's parse capability. */\nexport async function formatParse(\n name: string,\n source: string,\n options?: Record<string, unknown>,\n): Promise<JxMutableNode> {\n return (await formatAction({\n action: \"parse\",\n format: name,\n options,\n source,\n })) as JxMutableNode;\n}\n\n/** Serialize a Jx document to source text via the named format's serialize capability. */\nexport async function formatSerialize(\n name: string,\n doc: Record<string, unknown>,\n options?: Record<string, unknown>,\n): Promise<string> {\n return (await formatAction({\n action: \"serialize\",\n doc,\n format: name,\n options,\n })) as string;\n}\n\n/**\n * Split a parsed format document into { document, frontmatter, mode } per the format's\n * `$studio.documentMode` hints. Component documents (e.g. a frontmatter `tagName` with a hyphen)\n * keep their full shape; content documents separate frontmatter metadata from the body children.\n */\nexport function splitFormatDocument(format: StudioFormat | undefined, doc: JxMutableNode) {\n const hints = format?.studio?.documentMode;\n const componentWhen = hints?.componentWhen;\n if (componentWhen?.frontmatterKey) {\n const value = doc[componentWhen.frontmatterKey];\n const pattern = componentWhen.matches ? new RegExp(componentWhen.matches) : /./;\n if (typeof value === \"string\" && pattern.test(value)) {\n return {\n document: doc,\n frontmatter: {} as Record<string, unknown>,\n mode: \"component\",\n };\n }\n }\n if (hints?.default === \"component\") {\n return {\n document: doc,\n frontmatter: {} as Record<string, unknown>,\n mode: \"component\",\n };\n }\n\n // Content document — children form the root-level body; other keys are frontmatter\n const children = (doc.children as unknown[]) ?? [];\n if (children.length === 0) {\n children.push({ children: [], tagName: \"p\" });\n }\n\n const documentKeys = new Set([\"state\", \"imports\"]);\n const contentDoc: Record<string, unknown> = { children };\n const frontmatter: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(doc)) {\n if (key === \"children\") {\n continue;\n }\n if (documentKeys.has(key)) {\n contentDoc[key] = value;\n } else {\n frontmatter[key] = value;\n }\n }\n\n return {\n document: contentDoc as JxMutableNode,\n frontmatter,\n mode: \"content\",\n };\n}\n"
7
- ],
8
- "mappings": "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",
9
- "debugId": "7A0A51B7AA10806664756E2164756E21",
10
- "names": []
11
- }
@@ -1,9 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": [],
4
- "sourcesContent": [
5
- ],
6
- "mappings": "",
7
- "debugId": "54E7850A0697E18F64756E2164756E21",
8
- "names": []
9
- }
@@ -1,14 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../collab/src/schema.ts", "../../collab/src/op-bridge.ts", "../../collab/src/diff.ts", "../../collab/src/source-lock.ts", "../../collab/src/awareness-types.ts"],
4
- "sourcesContent": [
5
- "/**\n * The shared Y.Doc schema for a Jx document, and the JSON ↔ Y mapping.\n *\n * Layout (all top-level types, created on demand): - `meta: Y.Map` — schemaVersion,\n * structureSeeded, canonical (\"structure\" | \"source\"), canonicalRev (representation-flip counter —\n * distinct from the provider's wire docEpoch), sourceFormat. - `frontmatter: Y.Map` — per-field\n * plain-JSON values (LWW per field). - `structure: Y.Map` — the root JxMutableNode. - `source:\n * Y.Text` — the serialized source. THE authoritative file content: providers persist\n * `getText(\"source\").toString()` and never parse or serialize Jx documents themselves; the\n * structure tree is a Studio-side projection kept in sync by the bridge.\n *\n * **CRDT granularity is deliberately FINER than Studio's op-log granularity.** Every node is a\n * Y.Map; within it, \"children\" is a Y.Array, {@link TEXT_KEYS} are `Y.Text`,\n * {@link GRANULAR_OBJECT_KEYS} are nested Y.Maps, and everything else is a whole-JSON LWW value.\n *\n * The two granularities used to match, on the reasoning that mutators emit whole-value set-keys so\n * deeper Y types would add merge surface nothing targets. That reasoning was wrong: it conflated\n * what an EDIT addresses with what a MERGE must resolve. Two authors typing in one paragraph, or\n * setting `color` and `padding` on one element, produce whole-value ops that a whole-value CRDT can\n * only resolve by discarding one of them. The bridge therefore diffs a whole-value op down onto the\n * granular representation ({@link applyTextEdit}, {@link mergeYObject}) and {@link yValueToJson}\n * reassembles whole values on the way out — so `JxDocOp`, the canvas patcher and the history ring\n * are unchanged, while concurrent edits actually merge.\n *\n * Seeding contract: providers seed only `source` (from file bytes). Clients derive `structure` on\n * first sync via {@link seedStructure}, which is convergence-safe under concurrent seeders because\n * it only performs whole-key Y.Map sets (per-key LWW picks one seeder's subtrees wholesale) — never\n * array inserts, which would duplicate.\n */\n\nimport * as Y from \"yjs\";\nimport type { JxMutableNode, JxPath } from \"@jxsuite/schema/types\";\n\nexport const META_KEY = \"meta\";\nexport const FRONTMATTER_KEY = \"frontmatter\";\nexport const STRUCTURE_KEY = \"structure\";\nexport const SOURCE_KEY = \"source\";\n\n/**\n * Bumped to 2 when prose moved to `Y.Text` and style/attributes/$props to nested `Y.Map`s.\n *\n * Written into `meta` at seed time and not currently validated on load. A room persisted under 1\n * still READS correctly ({@link yValueToJson} passes plain values through) and self-heals on the\n * first edit to a given key, since the bridge replaces a non-granular container. Two clients\n * running DIFFERENT versions in one room would disagree about merge granularity — see §5 of\n * specs/collab.md on version skew, which this does not attempt to solve.\n */\nexport const COLLAB_SCHEMA_VERSION = 2;\n\nexport function metaMap(doc: Y.Doc): Y.Map<unknown> {\n return doc.getMap(META_KEY);\n}\n\nexport function frontmatterMap(doc: Y.Doc): Y.Map<unknown> {\n return doc.getMap(FRONTMATTER_KEY);\n}\n\nexport function structureMap(doc: Y.Doc): Y.Map<unknown> {\n return doc.getMap(STRUCTURE_KEY);\n}\n\nexport function sourceText(doc: Y.Doc): Y.Text {\n return doc.getText(SOURCE_KEY);\n}\n\n/** JSON round-trip clone (normalizes away proxies/undefined; matches the ops applier). */\nfunction cloneJson<T>(value: T): T {\n // oxlint-disable-next-line unicorn/prefer-structured-clone -- JSON normalization is the point\n return JSON.parse(JSON.stringify(value)) as T;\n}\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\n/**\n * Node keys whose STRING value is stored as a `Y.Text` rather than an opaque string.\n *\n * This is the character-level-collaboration decision. Whole-paragraph last-writer-wins was never a\n * Yjs limitation — it was this schema storing prose as a plain LWW value, so two people typing in\n * one paragraph clobbered each other and only `source` (which the canvas does not edit) merged per\n * character.\n *\n * `innerHTML` is deliberately absent: it is an opaque markup blob, never caret-edited.\n */\nexport const TEXT_KEYS: ReadonlySet<string> = new Set([\"textContent\"]);\n\n/**\n * Node keys stored as a nested `Y.Map` so concurrent edits to DIFFERENT properties both survive.\n *\n * `mutateUpdateStyle` and friends record a whole-object `set-key`, so writing the object as one LWW\n * value meant A's `color` and B's `padding` raced and one lost. Per-property merge fixes that\n * without touching the op vocabulary: {@link yValueToJson} reassembles the whole object on the way\n * out, so `JxDocOp`, the canvas patcher and the history ring keep seeing whole values.\n *\n * Declaration VALUES stay plain (a CSS value is never partially edited); only the key space is\n * granular. Nesting recurses, which covers `style`'s media (`@--sm`) and pseudo (`&:hover`)\n * blocks.\n */\nexport const GRANULAR_OBJECT_KEYS: ReadonlySet<string> = new Set([\"style\", \"attributes\", \"$props\"]);\n\n/**\n * Rewrite a `Y.Text` to `next` with a minimal edit (common prefix/suffix trimmed).\n *\n * Minimal rather than replace-all for two reasons: the wire carries only the delta, and — the\n * load-bearing one — the surviving characters keep their identity, so a concurrent remote insert\n * inside the untouched region merges instead of being clobbered. Returns false when already equal.\n */\nexport function applyTextEdit(text: Y.Text, next: string): boolean {\n const current = text.toString();\n if (current === next) {\n return false;\n }\n let start = 0;\n const minLen = Math.min(current.length, next.length);\n while (start < minLen && current[start] === next[start]) {\n start += 1;\n }\n let endCurrent = current.length;\n let endNext = next.length;\n while (endCurrent > start && endNext > start && current[endCurrent - 1] === next[endNext - 1]) {\n endCurrent -= 1;\n endNext -= 1;\n }\n if (endCurrent > start) {\n text.delete(start, endCurrent - start);\n }\n if (endNext > start) {\n text.insert(start, next.slice(start, endNext));\n }\n return true;\n}\n\n/** A plain object becomes a Y.Map, recursing into nested objects; other values stay plain JSON. */\nexport function toYObject(value: Record<string, unknown>): Y.Map<unknown> {\n const map = new Y.Map<unknown>();\n for (const [key, entry] of Object.entries(value)) {\n if (entry === undefined) {\n continue;\n }\n map.set(key, isPlainObject(entry) ? toYObject(entry) : cloneJson(entry));\n }\n return map;\n}\n\n/**\n * Merge a plain object into an existing Y.Map per key: set changed keys, delete removed ones,\n * recurse into nested maps. Whole-value replacement would mint a new Y.Map and discard a peer's\n * concurrent edit to an untouched sibling property — the very thing granularity exists to prevent.\n */\nexport function mergeYObject(map: Y.Map<unknown>, value: Record<string, unknown>): void {\n // Detached key list: deleting from a Y.Map while iterating its live keys is unsafe.\n // oxlint-disable-next-line unicorn/no-useless-spread -- the copy is the point (mutation during iteration)\n for (const key of [...map.keys()]) {\n if (!(key in value) || value[key] === undefined) {\n map.delete(key);\n }\n }\n for (const [key, entry] of Object.entries(value)) {\n if (entry === undefined) {\n continue;\n }\n const existing = map.get(key);\n if (isPlainObject(entry)) {\n if (existing instanceof Y.Map) {\n mergeYObject(existing, entry);\n } else {\n map.set(key, toYObject(entry));\n }\n } else if (!deepEqualJson(existing, entry)) {\n map.set(key, cloneJson(entry));\n }\n }\n}\n\n/** Structural equality over plain JSON, used to skip no-op key writes. */\nfunction deepEqualJson(a: unknown, b: unknown): boolean {\n if (a === b) {\n return true;\n }\n if (a instanceof Y.Map || a instanceof Y.Array || a instanceof Y.Text) {\n return false;\n }\n return JSON.stringify(a ?? null) === JSON.stringify(b ?? null);\n}\n\n/** A child value: a bare string becomes a Y.Text (per-character merge), a node becomes a Y.Map. */\nexport function toYChild(child: unknown): unknown {\n return typeof child === \"string\" ? new Y.Text(child) : toYNode(child);\n}\n\n/** A children array becomes a Y.Array of node Y.Maps and Y.Texts. */\nexport function toYChildren(children: readonly unknown[]): Y.Array<unknown> {\n const arr = new Y.Array<unknown>();\n arr.insert(\n 0,\n children.map((child) => toYChild(child)),\n );\n return arr;\n}\n\n/**\n * A node object becomes a Y.Map. Nesting is no longer limited to `children`: text keys become\n * `Y.Text` and {@link GRANULAR_OBJECT_KEYS} become nested `Y.Map`s, so the CRDT merges at the\n * granularity edits actually happen at. Everything else stays a whole-JSON LWW value.\n */\nexport function toYNode(node: unknown): Y.Map<unknown> {\n if (!isPlainObject(node)) {\n throw new TypeError(\"collab-schema: a document node must be a plain object\");\n }\n const map = new Y.Map<unknown>();\n for (const [key, value] of Object.entries(node)) {\n if (value === undefined) {\n continue;\n }\n if (key === \"children\" && Array.isArray(value)) {\n map.set(key, toYChildren(value));\n } else if (TEXT_KEYS.has(key) && typeof value === \"string\") {\n map.set(key, new Y.Text(value));\n } else if (GRANULAR_OBJECT_KEYS.has(key) && isPlainObject(value)) {\n map.set(key, toYObject(value));\n } else {\n map.set(key, cloneJson(value));\n }\n }\n return map;\n}\n\n/** Convert any structure value (Y.Map, Y.Array, Y.Text, or plain leaf) back to JSON. */\nexport function yValueToJson(value: unknown): unknown {\n if (value instanceof Y.Map) {\n const out: Record<string, unknown> = {};\n for (const [key, entry] of value.entries()) {\n out[key] = yValueToJson(entry);\n }\n return out;\n }\n if (value instanceof Y.Array) {\n return value.toArray().map((entry) => yValueToJson(entry));\n }\n if (value instanceof Y.Text) {\n return value.toString();\n }\n return value;\n}\n\n/** The whole structure tree as a plain document (deep, detached copy). */\nexport function yDocToJson(doc: Y.Doc): JxMutableNode {\n return yValueToJson(structureMap(doc)) as JxMutableNode;\n}\n\n/**\n * Resolve a JxPath against the structure tree. Returns the Y value at the path (a node Y.Map, a\n * children Y.Array, a string child, or a plain leaf) or undefined when any segment is missing.\n */\nexport function resolveYPath(doc: Y.Doc, path: JxPath): unknown {\n let current: unknown = structureMap(doc);\n for (const segment of path) {\n if (current instanceof Y.Map) {\n current = current.get(String(segment));\n } else if (current instanceof Y.Array) {\n const index = typeof segment === \"number\" ? segment : Number(segment);\n if (!Number.isInteger(index) || index < 0 || index >= current.length) {\n return undefined;\n }\n current = current.get(index);\n } else {\n return undefined;\n }\n }\n return current;\n}\n\n/**\n * Update the source Y.Text to `next` with a minimal edit (common prefix/suffix trimmed), so mirror\n * refreshes don't ship the whole document over the wire. Returns false when already identical.\n */\nexport function updateSourceText(doc: Y.Doc, next: string, origin?: unknown): boolean {\n const text = sourceText(doc);\n if (text.toString() === next) {\n return false;\n }\n doc.transact(() => {\n applyTextEdit(text, next);\n }, origin);\n return true;\n}\n\n/**\n * Populate the structure tree (and frontmatter/meta) from a parsed document — the client-side\n * first-sync step. Safe under concurrent seeders: every write is a whole-key Y.Map set, so two\n * racing seeds converge to one seeder's subtrees via per-key LWW with no duplication. No-op when\n * another seeder already won.\n */\nexport function seedStructure(\n doc: Y.Doc,\n document: JxMutableNode,\n opts: {\n frontmatter?: Record<string, unknown>;\n sourceFormat?: string | null;\n origin?: unknown;\n } = {},\n): boolean {\n const meta = metaMap(doc);\n if (meta.get(\"structureSeeded\") === true) {\n return false;\n }\n doc.transact(() => {\n const structure = structureMap(doc);\n for (const [key, value] of Object.entries(document)) {\n if (value === undefined) {\n continue;\n }\n if (key === \"children\" && Array.isArray(value)) {\n structure.set(key, toYChildren(value));\n } else {\n structure.set(key, cloneJson(value));\n }\n }\n const frontmatter = frontmatterMap(doc);\n for (const [key, value] of Object.entries(opts.frontmatter ?? {})) {\n if (value !== undefined) {\n frontmatter.set(key, cloneJson(value));\n }\n }\n meta.set(\"schemaVersion\", COLLAB_SCHEMA_VERSION);\n meta.set(\"canonical\", \"structure\");\n meta.set(\"canonicalRev\", 0);\n meta.set(\"sourceFormat\", opts.sourceFormat ?? null);\n meta.set(\"structureSeeded\", true);\n }, opts.origin);\n return true;\n}\n",
6
- "/**\n * The two-way bridge between Studio's JxDocOp op-log and the shared Y.Doc structure tree.\n *\n * Outbound ({@link applyDocOpsToY}): forward ops recorded by a local transaction replay onto the Y\n * tree inside one Y transaction tagged with the caller's origin, so observers can tell local\n * mirroring from remote edits.\n *\n * Inbound ({@link yEventsToDocOps}): a remote transaction's Y events convert back into JxDocOps for\n * `applyExternalDocOps`. Only provably safe event shapes take this fast path (it keeps canvas\n * patches surgical); anything gnarlier returns null and the caller reconciles by diffing — the\n * correctness anchor.\n */\n\nimport * as Y from \"yjs\";\nimport type { JxPath } from \"@jxsuite/schema/types\";\nimport type { JxDocOp } from \"./ops.ts\";\nimport {\n applyTextEdit,\n GRANULAR_OBJECT_KEYS,\n mergeYObject,\n resolveYPath,\n TEXT_KEYS,\n toYChild,\n toYChildren,\n toYObject,\n yValueToJson,\n} from \"./schema.ts\";\n\n/** Origin of Y transactions produced by mirroring the local tab's ops. */\nexport const LOCAL_ORIGIN = \"jx-local\";\n/** Origin of derived-representation writes (the elected reconciler's structure↔source mirrors). */\nexport const MIRROR_ORIGIN = \"jx-mirror\";\n/** Origin of seeding/bootstrap writes. */\nexport const SEED_ORIGIN = \"jx-seed\";\n\n/** Thrown when an op's path does not resolve in the Y tree; callers fall back to diffing. */\nexport class CollabPathError extends Error {\n constructor(path: JxPath) {\n super(`collab-path-unresolved:${path.join(\"/\")}`);\n this.name = \"CollabPathError\";\n }\n}\n\nfunction requireNode(doc: Y.Doc, path: JxPath): Y.Map<unknown> {\n const target = resolveYPath(doc, path);\n if (!(target instanceof Y.Map)) {\n throw new CollabPathError(path);\n }\n return target;\n}\n\nfunction childrenOf(doc: Y.Doc, parentPath: JxPath, create: boolean): Y.Array<unknown> {\n const parent = requireNode(doc, parentPath);\n const children = parent.get(\"children\");\n if (children instanceof Y.Array) {\n return children;\n }\n if (create && children === undefined) {\n const fresh = new Y.Array<unknown>();\n parent.set(\"children\", fresh);\n return fresh;\n }\n throw new CollabPathError([...parentPath, \"children\"]);\n}\n\n/** JSON round-trip clone (matches the ops applier's normalization). */\nfunction cloneJson<T>(value: T): T {\n // oxlint-disable-next-line unicorn/prefer-structured-clone -- JSON normalization is the point\n return JSON.parse(JSON.stringify(value)) as T;\n}\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\n/**\n * Write a node key, preserving CRDT identity wherever the schema stores it granularly.\n *\n * Studio's mutators record whole-value `set-key` ops — `mutateUpdateStyle` replaces the entire\n * style object, an inline-edit commit replaces the entire `textContent`. Writing those straight\n * through with `Y.Map.set` mints a fresh Y type each time and throws away whatever a peer\n * concurrently did to the old one, which is exactly how \"two people typing in one paragraph\" became\n * last-writer-wins.\n *\n * So a whole-value op is diffed down onto the existing structure: text through {@link applyTextEdit}\n * (character-level), granular objects through {@link mergeYObject} (per-property). Only a TYPE\n * change — string text becoming a `$ref`, an object becoming a scalar — falls back to replacement,\n * because then there is no shared structure left to preserve.\n */\nfunction setNodeKey(node: Y.Map<unknown>, key: string, value: unknown): void {\n const existing = node.get(key);\n if (key === \"children\" && Array.isArray(value)) {\n node.set(key, toYChildren(value));\n return;\n }\n if (TEXT_KEYS.has(key) && typeof value === \"string\") {\n if (existing instanceof Y.Text) {\n applyTextEdit(existing, value);\n } else {\n node.set(key, new Y.Text(value));\n }\n return;\n }\n if (GRANULAR_OBJECT_KEYS.has(key) && isPlainObject(value)) {\n if (existing instanceof Y.Map) {\n mergeYObject(existing, value);\n } else {\n node.set(key, toYObject(value));\n }\n return;\n }\n node.set(key, cloneJson(value));\n}\n\nfunction applyOneOp(doc: Y.Doc, op: JxDocOp): void {\n switch (op.op) {\n case \"set-key\": {\n const node = requireNode(doc, op.path);\n if (op.value === undefined) {\n node.delete(op.key);\n } else {\n setNodeKey(node, op.key, op.value);\n }\n return;\n }\n case \"insert-child\": {\n const children = childrenOf(doc, op.parentPath, true);\n if (op.index < 0 || op.index > children.length) {\n throw new CollabPathError([...op.parentPath, \"children\", op.index]);\n }\n children.insert(op.index, [toYChild(op.node)]);\n return;\n }\n case \"remove-child\": {\n const children = childrenOf(doc, op.parentPath, false);\n if (op.index < 0 || op.index >= children.length) {\n throw new CollabPathError([...op.parentPath, \"children\", op.index]);\n }\n children.delete(op.index, 1);\n return;\n }\n case \"set-child\": {\n const children = childrenOf(doc, op.parentPath, false);\n if (op.index < 0 || op.index >= children.length) {\n throw new CollabPathError([...op.parentPath, \"children\", op.index]);\n }\n // Text child → text child: edit the existing Y.Text in place. A delete+insert would replace the\n // Whole element and discard a peer's concurrent characters, which is the same clobber\n // `setNodeKey` avoids for `textContent` — bare-string children are the other half of prose.\n const existing = children.get(op.index);\n if (existing instanceof Y.Text && typeof op.node === \"string\") {\n applyTextEdit(existing, op.node);\n return;\n }\n children.delete(op.index, 1);\n children.insert(op.index, [toYChild(op.node)]);\n return;\n }\n case \"move-child\": {\n // Y.Array has no native move: re-insert the node's current JSON at the target. A remote\n // Edit landing inside the moved subtree during the same round-trip is lost (documented v1\n // Limitation); convergence itself is unaffected. Both parent paths resolve BEFORE the\n // Removal splice — matching the plain applier's semantics — while toIndex is expressed in\n // Post-removal coordinates (the mutators pre-adjust same-parent moves).\n const from = childrenOf(doc, op.fromParentPath, false);\n const to = childrenOf(doc, op.toParentPath, true);\n if (op.fromIndex < 0 || op.fromIndex >= from.length) {\n throw new CollabPathError([...op.fromParentPath, \"children\", op.fromIndex]);\n }\n const json = yValueToJson(from.get(op.fromIndex));\n from.delete(op.fromIndex, 1);\n if (op.toIndex < 0 || op.toIndex > to.length) {\n throw new CollabPathError([...op.toParentPath, \"children\", op.toIndex]);\n }\n to.insert(op.toIndex, [toYChild(json)]);\n return;\n }\n default: {\n throw new Error(`unknown-doc-op:${(op as JxDocOp).op}`);\n }\n }\n}\n\n/**\n * Replay forward ops onto the Y structure tree in one transaction. Throws {@link CollabPathError}\n * when any op's path does not resolve — the transaction still commits the ops applied before the\n * failure, so callers catching it must reconcile by diff (which corrects any partial state).\n */\nexport function applyDocOpsToY(doc: Y.Doc, ops: readonly JxDocOp[], origin: unknown): void {\n doc.transact(() => {\n for (const op of ops) {\n applyOneOp(doc, op);\n }\n }, origin);\n}\n\n/**\n * When `path` addresses a granular container (or something nested inside one), the node that owns\n * it and the key it sits under; otherwise null.\n *\n * The event path is relative to the structure map, so the first segment matching a granular key\n * marks the boundary: everything before it is the node path, and anything after it is interior\n * detail the op log does not model.\n *\n * `children`/index segments need no special handling: they are not granular keys, so the scan\n * passes over them and the returned node path keeps the full prefix — `[\"children\", 0, \"style\"]`\n * resolves to the style of the node at `children/0`, not of the root.\n */\nfunction granularOwner(path: JxPath): { nodePath: JxPath; key: string } | null {\n for (let i = 0; i < path.length; i++) {\n const segment = path[i];\n if (typeof segment !== \"string\") {\n continue;\n }\n if (GRANULAR_OBJECT_KEYS.has(segment)) {\n return { key: segment, nodePath: path.slice(0, i) };\n }\n if (TEXT_KEYS.has(segment)) {\n return { key: segment, nodePath: path.slice(0, i) };\n }\n }\n return null;\n}\n\nfunction isStructurePath(segments: readonly (string | number)[]): segments is JxPath {\n return segments.every((seg) => typeof seg === \"string\" || typeof seg === \"number\");\n}\n\n/**\n * Convert a remote transaction's deep events on the structure tree into JxDocOps (positions valid\n * at sequential apply time). Returns null when the shape is not provably safe to convert — multiple\n * overlapping events, more than one array event, or non-contiguous delete runs — and the caller\n * must reconcile by diffing instead.\n */\nexport function yEventsToDocOps(events: readonly Y.YEvent<never>[]): JxDocOp[] | null {\n if (events.length === 0) {\n return [];\n }\n const paths = events.map((event) => event.path);\n if (!paths.every((p) => isStructurePath(p))) {\n return null;\n }\n // Overlap guard: one event's target must not sit inside another's subtree — later paths would\n // Describe positions the earlier splice already shifted.\n for (let i = 0; i < paths.length; i++) {\n for (let j = 0; j < paths.length; j++) {\n if (i === j) {\n continue;\n }\n const a = paths[i]!;\n const b = paths[j]!;\n if (a.length <= b.length && a.every((seg, k) => seg === b[k])) {\n return null;\n }\n }\n }\n const arrayEvents = events.filter((event) => event instanceof Y.YArrayEvent).length;\n if (arrayEvents > 1) {\n return null;\n }\n\n const ops: JxDocOp[] = [];\n for (const event of events) {\n const path = event.path as JxPath;\n /*\n * A remote edit inside a granular container (a `Y.Text` for prose, a nested `Y.Map` for\n * style/attributes/$props) reports its event at the CONTAINER's path, not the node's. Studio's op\n * vocabulary addresses nodes, so those collapse back to one whole-value op for the owning key —\n * the same shape a local mutator would have produced. Granularity buys merge; it deliberately does\n * not leak into the op log, the canvas patcher, or the history ring.\n */\n const granular = granularOwner(path);\n if (granular) {\n const { doc } = event.target as { doc?: Y.Doc | null };\n if (!doc) {\n return null;\n }\n const container = resolveYPath(doc, [...granular.nodePath, granular.key]);\n if (container === undefined) {\n return null;\n }\n ops.push({\n key: granular.key,\n op: \"set-key\",\n path: granular.nodePath,\n value: yValueToJson(container),\n });\n continue;\n }\n if (event instanceof Y.YTextEvent) {\n // A bare-string child: the text IS the child, so it round-trips as a child replacement.\n const index = path.at(-1);\n if (path.at(-2) === \"children\" && typeof index === \"number\") {\n ops.push({\n index,\n node: (event.target as Y.Text).toString(),\n op: \"set-child\",\n parentPath: path.slice(0, -2),\n });\n continue;\n }\n return null;\n }\n if (event instanceof Y.YMapEvent) {\n const target = event.target as Y.Map<unknown>;\n for (const [key, change] of event.changes.keys) {\n if (change.action === \"delete\") {\n ops.push({ key, op: \"set-key\", path });\n } else {\n ops.push({ key, op: \"set-key\", path, value: yValueToJson(target.get(key)) });\n }\n }\n } else if (event instanceof Y.YArrayEvent) {\n // The array event's path points at the children array; ops address its parent node.\n if (path.at(-1) !== \"children\") {\n return null;\n }\n const parentPath = path.slice(0, -1);\n let index = 0;\n for (const delta of event.changes.delta) {\n if (delta.retain !== undefined) {\n index += delta.retain;\n } else if (delta.delete !== undefined) {\n for (let i = 0; i < delta.delete; i++) {\n ops.push({ index, op: \"remove-child\", parentPath });\n }\n } else if (delta.insert !== undefined) {\n const items = Array.isArray(delta.insert) ? delta.insert : [delta.insert];\n for (const item of items) {\n ops.push({ index, node: yValueToJson(item), op: \"insert-child\", parentPath });\n index += 1;\n }\n }\n }\n } else {\n return null;\n }\n }\n return ops;\n}\n",
7
- "/**\n * Structural differ: `diffDocs(a, b)` produces JxDocOps that transform document `a` into `b` when\n * replayed sequentially (property invariant: `apply(clone(a), diffDocs(a, b)) ≡ b`). The collab\n * bridge uses it wherever no op-log exists — whole-document bypass writes (Monaco parse-flush,\n * navigation, reload), un-instrumented transactions, and inbound Y transactions too gnarly for the\n * fast event path.\n *\n * Children alignment: an LCS over strong keys (full-content hashes) pins unchanged nodes as\n * anchors; the gaps between anchors align by a second LCS over weak signatures (tagName +\n * id/$props.key) whose pairs diff recursively. Unmatched items become splices. Reorders of\n * identical siblings therefore degrade to remove+insert — exactly what the Y move mapping does, so\n * no fidelity is lost relative to the wire.\n */\n\nimport type { JxMutableNode, JxPath } from \"@jxsuite/schema/types\";\nimport type { JxDocOp } from \"./ops.ts\";\nimport { metaMap, structureMap, toYChildren } from \"./schema.ts\";\nimport type * as Y from \"yjs\";\n\nexport interface DiffOptions {\n /** Abort (return null) when the diff would exceed this many ops; caller hard-replaces instead. */\n maxOps?: number;\n}\n\nconst DEFAULT_MAX_OPS = 500;\n\nclass MaxOpsExceededError extends Error {\n override name = \"MaxOpsExceededError\";\n}\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\n/** Order-insensitive for object keys, order-sensitive for arrays. */\nexport function deepEqual(a: unknown, b: unknown): boolean {\n if (a === b) {\n return true;\n }\n if (Array.isArray(a) && Array.isArray(b)) {\n return a.length === b.length && a.every((item, i) => deepEqual(item, b[i]));\n }\n if (isPlainObject(a) && isPlainObject(b)) {\n const keysA = Object.keys(a);\n const keysB = Object.keys(b);\n return (\n keysA.length === keysB.length && keysA.every((key) => key in b && deepEqual(a[key], b[key]))\n );\n }\n return false;\n}\n\nfunction contentHash(text: string): string {\n let hash = 5381;\n for (let i = 0; i < text.length; i++) {\n hash = Math.imul(hash, 33) + (text.codePointAt(i) ?? 0);\n }\n return hash.toString(36);\n}\n\n/** Full-content identity: equal strong keys mean \"treat as the same unchanged child\". */\nfunction strongKey(item: unknown): string {\n return typeof item === \"string\" ? `s:${item}` : `n:${contentHash(JSON.stringify(item))}`;\n}\n\n/** Alignment identity: equal weak keys mean \"same logical child, diff its contents\". */\nfunction weakKey(item: unknown): string {\n if (typeof item === \"string\") {\n return \"s\";\n }\n const node = item as Record<string, unknown>;\n const attrs = node[\"attributes\"];\n const props = node[\"$props\"];\n const id =\n (isPlainObject(attrs) ? attrs[\"id\"] : undefined) ??\n (isPlainObject(props) ? props[\"key\"] : undefined) ??\n \"\";\n return `w:${String(node[\"tagName\"] ?? \"\")}:${String(id)}`;\n}\n\n/** Longest common subsequence over key arrays; returns strictly-increasing index pairs. */\nfunction lcsPairs(aKeys: readonly string[], bKeys: readonly string[]): [number, number][] {\n const n = aKeys.length;\n const m = bKeys.length;\n if (n === 0 || m === 0) {\n return [];\n }\n // Classic DP table; children arrays are small (bounded by document size, typically < 200).\n const table: number[][] = Array.from({ length: n + 1 }, () =>\n Array.from({ length: m + 1 }, () => 0),\n );\n for (let i = n - 1; i >= 0; i--) {\n for (let j = m - 1; j >= 0; j--) {\n table[i]![j] =\n aKeys[i] === bKeys[j]\n ? table[i + 1]![j + 1]! + 1\n : Math.max(table[i + 1]![j]!, table[i]![j + 1]!);\n }\n }\n const pairs: [number, number][] = [];\n let i = 0;\n let j = 0;\n while (i < n && j < m) {\n if (aKeys[i] === bKeys[j]) {\n pairs.push([i, j]);\n i += 1;\n j += 1;\n } else if (table[i + 1]![j]! >= table[i]![j + 1]!) {\n i += 1;\n } else {\n j += 1;\n }\n }\n return pairs;\n}\n\ninterface ChildMatch {\n aIndex: number;\n bIndex: number;\n /** Strong matches are byte-identical — no recursion needed. */\n identical: boolean;\n}\n\n/** Anchor by strong LCS, then align each gap by weak LCS. Matches never cross. */\nfunction matchChildren(a: readonly unknown[], b: readonly unknown[]): ChildMatch[] {\n const anchors = lcsPairs(\n a.map((item) => strongKey(item)),\n b.map((item) => strongKey(item)),\n );\n const matches: ChildMatch[] = [];\n let prevA = -1;\n let prevB = -1;\n const gaps: [number, number, number, number][] = [];\n for (const [ai, bi] of anchors) {\n gaps.push([prevA + 1, ai, prevB + 1, bi]);\n matches.push({ aIndex: ai, bIndex: bi, identical: true });\n prevA = ai;\n prevB = bi;\n }\n gaps.push([prevA + 1, a.length, prevB + 1, b.length]);\n for (const [aStart, aEnd, bStart, bEnd] of gaps) {\n const aGap = a.slice(aStart, aEnd);\n const bGap = b.slice(bStart, bEnd);\n for (const [gi, gj] of lcsPairs(\n aGap.map((item) => weakKey(item)),\n bGap.map((item) => weakKey(item)),\n )) {\n matches.push({ aIndex: aStart + gi, bIndex: bStart + gj, identical: false });\n }\n }\n return matches.toSorted((x, y) => x.aIndex - y.aIndex);\n}\n\nclass Differ {\n private readonly ops: JxDocOp[] = [];\n private readonly maxOps: number;\n\n constructor(maxOps: number) {\n this.maxOps = maxOps;\n }\n\n result(): JxDocOp[] {\n return this.ops;\n }\n\n private push(op: JxDocOp): void {\n if (this.ops.length >= this.maxOps) {\n throw new MaxOpsExceededError();\n }\n this.ops.push(op);\n }\n\n diffNode(path: JxPath, a: Record<string, unknown>, b: Record<string, unknown>): void {\n for (const key of new Set([...Object.keys(a), ...Object.keys(b)])) {\n if (key === \"children\") {\n continue;\n }\n if (!(key in b)) {\n this.push({ key, op: \"set-key\", path });\n } else if (!deepEqual(a[key], b[key])) {\n this.push({ key, op: \"set-key\", path, value: b[key] });\n }\n }\n const ca = a[\"children\"];\n const cb = b[\"children\"];\n if (Array.isArray(ca) && Array.isArray(cb)) {\n this.diffChildren(path, ca, cb);\n } else if (!deepEqual(ca, cb)) {\n // Mapped-array children (or one side missing entirely) replace whole, like the mutators do.\n this.push({ key: \"children\", op: \"set-key\", path, value: cb });\n }\n }\n\n private diffChildren(path: JxPath, a: readonly unknown[], b: readonly unknown[]): void {\n const matches = matchChildren(a, b);\n const matchedA = new Set(matches.map((match) => match.aIndex));\n const byB = new Map(matches.map((match) => [match.bIndex, match]));\n\n // Removals first, in descending original index — each splice leaves lower indices intact.\n for (let i = a.length - 1; i >= 0; i--) {\n if (!matchedA.has(i)) {\n this.push({ index: i, op: \"remove-child\", parentPath: path });\n }\n }\n // Then walk b ascending: inserts land at their final index; matched pairs already sit there\n // (matches never cross), so recursion paths are valid as emitted.\n for (let i = 0; i < b.length; i++) {\n const match = byB.get(i);\n if (!match) {\n this.push({ index: i, node: b[i], op: \"insert-child\", parentPath: path });\n continue;\n }\n if (match.identical) {\n continue;\n }\n const aItem = a[match.aIndex];\n const bItem = b[i];\n if (isPlainObject(aItem) && isPlainObject(bItem)) {\n this.diffNode([...path, \"children\", i], aItem, bItem);\n } else if (!deepEqual(aItem, bItem)) {\n this.push({ index: i, node: bItem, op: \"set-child\", parentPath: path });\n }\n }\n }\n}\n\n/**\n * Ops that transform `a` into `b` when replayed sequentially, or null when the change is too large\n * to express surgically (caller should hard-replace and reset).\n */\nexport function diffDocs(\n a: JxMutableNode,\n b: JxMutableNode,\n opts: DiffOptions = {},\n): JxDocOp[] | null {\n const differ = new Differ(opts.maxOps ?? DEFAULT_MAX_OPS);\n try {\n differ.diffNode([], a as Record<string, unknown>, b as Record<string, unknown>);\n } catch (error) {\n if (error instanceof MaxOpsExceededError) {\n return null;\n }\n throw error;\n }\n return differ.result();\n}\n\n/**\n * Hard-replace the structure tree with `document` (the diff-overflow escape hatch) and bump the\n * in-doc canonicalRev so stale mirror writes computed against the old tree are discarded.\n */\nexport function replaceYStructure(doc: Y.Doc, document: JxMutableNode, origin: unknown): void {\n doc.transact(() => {\n const structure = structureMap(doc);\n const next = document as Record<string, unknown>;\n // Detached copy: keys are deleted while iterating.\n const existingKeys = [...structure.keys()];\n for (const key of existingKeys) {\n if (!(key in next) || next[key] === undefined) {\n structure.delete(key);\n }\n }\n for (const [key, value] of Object.entries(next)) {\n if (value === undefined) {\n continue;\n }\n if (key === \"children\" && Array.isArray(value)) {\n structure.set(key, toYChildren(value));\n } else {\n // oxlint-disable-next-line unicorn/prefer-structured-clone -- JSON normalization is the point\n structure.set(key, JSON.parse(JSON.stringify(value)));\n }\n }\n const meta = metaMap(doc);\n meta.set(\"canonicalRev\", Number(meta.get(\"canonicalRev\") ?? 0) + 1);\n }, origin);\n}\n",
8
- "/**\n * The canonical-representation lock for source-mode co-editing (the Phase-B dual-representation\n * design). `meta.canonical` says which representation is authoritative: \"structure\" (the default —\n * canvas/inspector edits flow through the op bridge and the elected reconciler mirrors them into\n * source text) or \"source\" (Monaco co-edits the Y.Text character-level; structural surfaces\n * soft-freeze and the source reconciler mirrors parses back into the structure tree for live\n * previews).\n *\n * Every flip bumps `meta.canonicalRev`; derived-representation writers stamp the rev they computed\n * against and observers discard stale mirrors. Flips are LWW-idempotent under concurrency: both\n * flippers serialize the same structure, so the merged text converges.\n */\n\nimport type { Doc } from \"yjs\";\nimport type { Awareness } from \"y-protocols/awareness\";\nimport { metaMap, updateSourceText } from \"./schema.ts\";\nimport type { CollabAwarenessState } from \"./awareness-types.ts\";\n\nexport type CanonicalRepresentation = \"structure\" | \"source\";\n\nexport function canonicalOf(doc: Doc): CanonicalRepresentation {\n return metaMap(doc).get(\"canonical\") === \"source\" ? \"source\" : \"structure\";\n}\n\nexport function canonicalRevOf(doc: Doc): number {\n return Number(metaMap(doc).get(\"canonicalRev\") ?? 0);\n}\n\n/**\n * Flip canonical to \"source\", seeding the text from `serialized` (the flipper's serialization of\n * the current structure). No-op (false) when source already holds the lock.\n */\nexport function acquireSourceCanonical(doc: Doc, serialized: string, origin: unknown): boolean {\n if (canonicalOf(doc) === \"source\") {\n return false;\n }\n doc.transact(() => {\n updateSourceText(doc, serialized, origin);\n const meta = metaMap(doc);\n meta.set(\"canonical\", \"source\");\n meta.set(\"canonicalRev\", canonicalRevOf(doc) + 1);\n }, origin);\n return true;\n}\n\n/** Flip canonical back to \"structure\" (the mirror is the caller's responsibility beforehand). */\nexport function releaseSourceCanonical(doc: Doc, origin: unknown): boolean {\n if (canonicalOf(doc) !== \"source\") {\n return false;\n }\n doc.transact(() => {\n const meta = metaMap(doc);\n meta.set(\"canonical\", \"structure\");\n meta.set(\"canonicalRev\", canonicalRevOf(doc) + 1);\n }, origin);\n return true;\n}\n\n/** Peers (excluding `selfClientId`) currently source-editing this doc, per awareness. */\nexport function otherSourceEditors(\n awareness: Awareness,\n path: string,\n selfClientId: number,\n): number[] {\n const editors: number[] = [];\n for (const [clientId, raw] of awareness.getStates()) {\n const state = raw as Partial<CollabAwarenessState>;\n if (clientId !== selfClientId && state.mode === \"source\" && state.focusedPath === path) {\n editors.push(clientId);\n }\n }\n return editors;\n}\n\n/**\n * The source reconciler — the lowest write-capable clientID among this doc's source editors\n * (including self when in source mode) — owns parsing Y.Text back into the structure tree.\n */\nexport function isSourceReconciler(awareness: Awareness, path: string): boolean {\n const self = awareness.clientID;\n const selfState = awareness.getStates().get(self) as Partial<CollabAwarenessState> | undefined;\n if (selfState?.mode !== \"source\" || selfState.focusedPath !== path) {\n return false;\n }\n let lowest = self;\n for (const [clientId, raw] of awareness.getStates()) {\n const state = raw as Partial<CollabAwarenessState>;\n if (\n state.mode === \"source\" &&\n state.focusedPath === path &&\n state.canWrite !== false &&\n clientId < lowest\n ) {\n lowest = clientId;\n }\n }\n return lowest === self;\n}\n",
9
- "/**\n * The project-level awareness contract. One y-protocols Awareness instance rides each provider\n * connection (not one per document): every client publishes a single state describing who they are\n * and where they're working, which gives file-tree presence for free; per-document cursor overlays\n * filter the same states by focusedPath.\n */\n\nimport type { JxPath } from \"@jxsuite/schema/types\";\n\nexport interface CollabUser {\n login: string;\n name?: string;\n avatarUrl?: string;\n /** Presence color, assigned deterministically by the server (hello) or colorForKey. */\n color: string;\n}\n\nexport interface CollabAwarenessState {\n user: CollabUser;\n /** Project-relative path of the document the client is focused on, or null. */\n focusedPath: string | null;\n /** Which representation the client is editing (drives the Phase-B canonical lock). */\n mode?: \"structure\" | \"source\";\n /**\n * The client's structural (canvas) selection in the focused document — the whole SET.\n *\n * A list because `session.selection` is one (studio §6.5): a peer who has selected six cards\n * publishes six paths, and the remote canvas draws a presence box for each. A peer with one node\n * selected publishes a one-entry list, which draws exactly the one box it always did.\n */\n structuralSelection?: JxPath[] | null;\n /**\n * RESERVED for the code view: the in-buffer text cursor as {anchor, head} Y.RelativePosition\n * JSON. `studio/src/collab/monaco-binding.ts`'s bindMonacoToYText owns this field via\n * setLocalStateField(\"selection\", …) while a code view is bound, and sets it back to null when it\n * unbinds; nothing else may write it. The shape is y-monaco's, deliberately — a peer on an older\n * Studio publishes and reads exactly this.\n */\n selection?: { anchor: unknown; head: unknown } | null;\n /**\n * Whether this client may write (from the server hello). Drives reconciler election — the lowest\n * write-capable clientID mirrors derived representations. Advisory only: the server drops updates\n * from read-only sockets regardless.\n */\n canWrite?: boolean;\n}\n\n/** Eight distinguishable presence hues (dark-theme friendly). */\nexport const PRESENCE_PALETTE = [\n \"#4f9cf9\",\n \"#e5484d\",\n \"#30a46c\",\n \"#f5a524\",\n \"#8e4ec6\",\n \"#00a2c7\",\n \"#e93d82\",\n \"#a8845c\",\n] as const;\n\n/** Deterministic palette pick — the same key always maps to the same color. */\nexport function colorForKey(key: string): string {\n let hash = 5381;\n for (let i = 0; i < key.length; i++) {\n hash = Math.imul(hash, 33) + (key.codePointAt(i) ?? 0);\n }\n const index = Math.abs(hash) % PRESENCE_PALETTE.length;\n return PRESENCE_PALETTE[index]!;\n}\n"
10
- ],
11
- "mappings": "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",
12
- "debugId": "B8ADE0E78745B17964756E2164756E21",
13
- "names": []
14
- }