@phis/ui 0.4.1 → 0.4.3

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 (246) hide show
  1. package/components/cms/phi-cms-layout-renderer.js +4 -3
  2. package/components/cms/phi-cms-page-render-scope.d.ts +4 -5
  3. package/components/cms/phi-cms-page-render-scope.js +43 -22
  4. package/components/cms/phi-cms-render-diagnostic-client.js +7 -3
  5. package/components/cms/phi-cms-render-error-boundary.js +2 -1
  6. package/components/controls/phi-bullet-list-control.js +31 -2
  7. package/components/controls/phi-ribbon-control.d.ts +29 -0
  8. package/components/controls/phi-ribbon-control.js +53 -0
  9. package/components/controls/phi-table-control.d.ts +3 -0
  10. package/components/controls/phi-table-control.js +13 -1
  11. package/components/controls/phi-tree-control.js +3 -3
  12. package/components/forms/shared-form-provider-registry.js +1 -4
  13. package/components/media/asset-collection-runtime.js +6 -16
  14. package/components/media/media-font-metrics.d.ts +3 -0
  15. package/components/media/media-font-metrics.js +43 -0
  16. package/components/media/phi-area-upload-widget.js +53 -97
  17. package/components/media/phi-image-preview-data.d.ts +13 -0
  18. package/components/media/phi-image-preview-data.js +184 -9
  19. package/components/media/phi-media-picker-binding.js +16 -13
  20. package/components/media/phi-media-upload.d.ts +15 -8
  21. package/components/media/phi-media-upload.js +18 -9
  22. package/components/media/phi-site-font-assets.js +7 -8
  23. package/components/overlays/phi-overlay-container-client.js +16 -1
  24. package/components/regions/presets/phi-settings-page-shell-tree.js +48 -1
  25. package/components/runtime/runtime-controller-materialization.js +12 -1
  26. package/components/state/scoped-state-store.js +20 -3
  27. package/components/tables/client/phi-table-binding.d.ts +2 -1
  28. package/components/tables/client/phi-table-binding.js +45 -21
  29. package/components/trees/client/phi-tree-binding.js +19 -11
  30. package/components/widgets/client/bullet-list-entries-editor.d.ts +26 -0
  31. package/components/widgets/client/bullet-list-entries-editor.js +103 -0
  32. package/components/widgets/config/choice-shared.js +12 -13
  33. package/components/widgets/config/command-buttons.d.ts +5 -1
  34. package/components/widgets/config/command-buttons.js +38 -81
  35. package/components/widgets/config/control-signal-config.d.ts +3 -1
  36. package/components/widgets/config/control-signal-config.js +19 -17
  37. package/components/widgets/config/image-source-parser.d.ts +1 -0
  38. package/components/widgets/config/image-source-parser.js +7 -8
  39. package/components/widgets/config/mask.d.ts +6 -1
  40. package/components/widgets/config/mask.js +24 -1
  41. package/components/widgets/config/parser-primitives.js +72 -0
  42. package/components/widgets/config/stack-tabs.d.ts +1 -1
  43. package/components/widgets/config/stack-tabs.js +2 -3
  44. package/components/widgets/config/strict-config-reader.d.ts +40 -0
  45. package/components/widgets/config/strict-config-reader.js +174 -0
  46. package/components/widgets/label-sets/effects.js +2 -0
  47. package/components/widgets/label-types/effects.d.ts +1 -0
  48. package/components/widgets/label-types/effects.js +1 -0
  49. package/components/widgets/navigation-descriptor-resolver.server.js +20 -8
  50. package/components/widgets/shared/bullet-list-vocabulary.d.ts +17 -1
  51. package/components/widgets/shared/bullet-list-vocabulary.js +19 -2
  52. package/components/widgets/shared/card-body-client.d.ts +16 -4
  53. package/components/widgets/shared/card-body-client.js +81 -24
  54. package/components/widgets/shared/card-vocabulary.d.ts +21 -4
  55. package/components/widgets/shared/card-vocabulary.js +28 -2
  56. package/components/widgets/shared/markdown-body-client.d.ts +2 -1
  57. package/components/widgets/shared/markdown-body-client.js +3 -1
  58. package/components/widgets/shared/markdown-render.js +8 -1
  59. package/components/widgets/signals/control-signal-capabilities.d.ts +0 -18
  60. package/components/widgets/signals/control-signal-capabilities.js +10 -22
  61. package/components/workspace/catalog-store.d.ts +4 -3
  62. package/components/workspace/catalog-store.js +6 -5
  63. package/gateway/dashboard-cards-route.js +1 -0
  64. package/gateway/internal-references.d.ts +6 -1
  65. package/gateway/internal-references.js +48 -23
  66. package/gateway/site-cms-write-validation.d.ts +9 -0
  67. package/gateway/site-cms-write-validation.js +78 -0
  68. package/gateway/site-proxy.js +19 -3
  69. package/helpers/renderable-block-serialization.js +1 -1
  70. package/next/config.d.mts +3 -0
  71. package/next/config.mjs +28 -1
  72. package/package.json +2 -2
  73. package/plugins/runtime/phi-slot-child-viewport-effects-observer.js +5 -1
  74. package/plugins/runtime-modules/accounting/presets.d.ts +9 -0
  75. package/plugins/runtime-modules/accounting/presets.js +37 -0
  76. package/plugins/runtime-modules/accounting/server.d.ts +1 -4
  77. package/plugins/runtime-modules/accounting/server.js +4 -7
  78. package/plugins/runtime-modules/app/presets.d.ts +18 -0
  79. package/plugins/runtime-modules/app/presets.js +67 -0
  80. package/plugins/runtime-modules/app/server.d.ts +1 -4
  81. package/plugins/runtime-modules/app/server.js +4 -7
  82. package/plugins/runtime-modules/asset/controller/runtime.js +2 -2
  83. package/plugins/runtime-modules/asset/services/collection.js +9 -1
  84. package/plugins/runtime-modules/asset/services/options.js +2 -2
  85. package/plugins/runtime-modules/builder/area-settings-answer.js +2 -1
  86. package/plugins/runtime-modules/builder/authoring-canvas.js +6 -6
  87. package/plugins/runtime-modules/builder/cards.js +3 -5
  88. package/plugins/runtime-modules/builder/clients/builder-region-overrides.js +3 -3
  89. package/plugins/runtime-modules/builder/clients/canvas-widget.js +15 -54
  90. package/plugins/runtime-modules/builder/clients/inspector-config-field.d.ts +4 -1
  91. package/plugins/runtime-modules/builder/clients/inspector-config-field.js +5 -34
  92. package/plugins/runtime-modules/builder/clients/inspector-link-target-field.js +1 -1
  93. package/plugins/runtime-modules/builder/clients/inspector-section-widget.js +8 -8
  94. package/plugins/runtime-modules/builder/clients/inspector-title.js +6 -6
  95. package/plugins/runtime-modules/builder/clients/layout-inspector.d.ts +1 -1
  96. package/plugins/runtime-modules/builder/clients/layout-inspector.js +11 -25
  97. package/plugins/runtime-modules/builder/clients/mode-switch.js +1 -1
  98. package/plugins/runtime-modules/builder/clients/pages-header.js +11 -11
  99. package/plugins/runtime-modules/builder/clients/pages-workspace.js +1 -1
  100. package/plugins/runtime-modules/builder/clients/region-visibility-fields.js +1 -1
  101. package/plugins/runtime-modules/builder/clients/runtime-module-authoring-boundary.js +1 -1
  102. package/plugins/runtime-modules/builder/clients/shells-workspace.js +15 -31
  103. package/plugins/runtime-modules/builder/clients/structure-canvas.js +1 -1
  104. package/plugins/runtime-modules/builder/clients/use-region-draft-hydration.d.ts +26 -0
  105. package/plugins/runtime-modules/builder/clients/use-region-draft-hydration.js +36 -0
  106. package/plugins/runtime-modules/builder/clients/widget-effects-editor.js +1 -1
  107. package/plugins/runtime-modules/builder/clients/widget-inspector.js +1 -0
  108. package/plugins/runtime-modules/builder/clients/workspace-scope-boundary.js +2 -2
  109. package/plugins/runtime-modules/builder/cms-instance-allocator.js +8 -28
  110. package/plugins/runtime-modules/builder/controller/client.d.ts +0 -15
  111. package/plugins/runtime-modules/builder/controller/definition.d.ts +0 -15
  112. package/plugins/runtime-modules/builder/controller/definition.js +0 -8
  113. package/plugins/runtime-modules/builder/controller/draft-command-controller.d.ts +1 -2
  114. package/plugins/runtime-modules/builder/controller/draft-command-controller.js +11 -30
  115. package/plugins/runtime-modules/builder/controller/draft-status-controller.js +15 -2
  116. package/plugins/runtime-modules/builder/controller/inspector-controller.d.ts +1 -2
  117. package/plugins/runtime-modules/builder/controller/inspector-controller.js +4 -7
  118. package/plugins/runtime-modules/builder/controller/page-controller.d.ts +1 -2
  119. package/plugins/runtime-modules/builder/controller/page-controller.js +16 -68
  120. package/plugins/runtime-modules/builder/controller/server-definition.d.ts +0 -15
  121. package/plugins/runtime-modules/builder/controller/signal-wiring-controller.d.ts +2 -5
  122. package/plugins/runtime-modules/builder/controller/signal-wiring-controller.js +6 -50
  123. package/plugins/runtime-modules/builder/controller/workspace-controller.d.ts +2 -3
  124. package/plugins/runtime-modules/builder/controller/workspace-controller.js +89 -153
  125. package/plugins/runtime-modules/builder/data-providers.d.ts +1 -0
  126. package/plugins/runtime-modules/builder/data-providers.js +1 -0
  127. package/plugins/runtime-modules/builder/definition.d.ts +1 -0
  128. package/plugins/runtime-modules/builder/developer-workspace-store.d.ts +64 -30
  129. package/plugins/runtime-modules/builder/developer-workspace-store.js +255 -61
  130. package/plugins/runtime-modules/builder/edit-scaffold-drawer.js +1 -1
  131. package/plugins/runtime-modules/builder/history.d.ts +3 -1
  132. package/plugins/runtime-modules/builder/options-providers.js +3 -2
  133. package/plugins/runtime-modules/builder/page-catalog-client.js +19 -7
  134. package/plugins/runtime-modules/builder/page-meta-form.js +1 -0
  135. package/plugins/runtime-modules/builder/page-references-provider.js +1 -1
  136. package/plugins/runtime-modules/builder/persistence.js +33 -69
  137. package/plugins/runtime-modules/builder/public-route-collisions.d.ts +2 -2
  138. package/plugins/runtime-modules/builder/public-route-collisions.js +6 -19
  139. package/plugins/runtime-modules/builder/render-root-node-preview.server.js +20 -3
  140. package/plugins/runtime-modules/builder/render-root-node-scaffold.js +3 -3
  141. package/plugins/runtime-modules/builder/runtime-module-selection.d.ts +2 -12
  142. package/plugins/runtime-modules/builder/runtime-module-selection.js +16 -42
  143. package/plugins/runtime-modules/builder/services/navigation-table.js +9 -15
  144. package/plugins/runtime-modules/builder/services/page-source-tree.js +8 -8
  145. package/plugins/runtime-modules/builder/services/runtime-modules-table.js +10 -10
  146. package/plugins/runtime-modules/builder/services/signal-routes-table.js +3 -3
  147. package/plugins/runtime-modules/builder/signal-route-selection.d.ts +1 -2
  148. package/plugins/runtime-modules/builder/signal-route-selection.js +2 -2
  149. package/plugins/runtime-modules/builder/signal-wiring-options.js +3 -2
  150. package/plugins/runtime-modules/builder/structure-dnd.js +8 -61
  151. package/plugins/runtime-modules/builder/trees/phi-default-builder-area-preset-tree.js +13 -10
  152. package/plugins/runtime-modules/builder/widgets/structure-region/built-in.js +12 -18
  153. package/plugins/runtime-modules/builder/workspace-catalog-actions.d.ts +55 -0
  154. package/plugins/runtime-modules/builder/workspace-catalog-actions.js +142 -0
  155. package/plugins/runtime-modules/client-manifests/common.js +1 -1
  156. package/plugins/runtime-modules/{runtime-calendar-adapters.js → core/calendar-adapters.js} +2 -2
  157. package/plugins/runtime-modules/{client-calendar-adapters/core.js → core/client-calendar-adapters.js} +1 -1
  158. package/plugins/runtime-modules/core/content-entries/table.js +1 -1
  159. package/plugins/runtime-modules/core/data-providers.d.ts +3 -0
  160. package/plugins/runtime-modules/core/data-providers.js +2 -1
  161. package/plugins/runtime-modules/core/definition.d.ts +3 -0
  162. package/plugins/runtime-modules/core/definition.js +1 -1
  163. package/plugins/runtime-modules/core/messaging/data-providers.d.ts +1 -0
  164. package/plugins/runtime-modules/core/messaging/data-providers.js +1 -0
  165. package/plugins/runtime-modules/core/messaging/thread-inbox-table.js +1 -1
  166. package/plugins/runtime-modules/core/server.js +1 -1
  167. package/plugins/runtime-modules/core/themes.d.ts +44 -0
  168. package/plugins/runtime-modules/core/themes.js +12 -0
  169. package/plugins/runtime-modules/core/widgets/card/collection-view-binding.js +25 -9
  170. package/plugins/runtime-modules/core/widgets/card/config.d.ts +296 -254
  171. package/plugins/runtime-modules/core/widgets/card/config.js +52 -3
  172. package/plugins/runtime-modules/core/widgets/card/editor.js +30 -3
  173. package/plugins/runtime-modules/core/widgets/card/server.d.ts +3 -0
  174. package/plugins/runtime-modules/core/widgets/card/server.js +31 -3
  175. package/plugins/runtime-modules/core/widgets/collection-view/asset-binding.js +7 -6
  176. package/plugins/runtime-modules/core/widgets/collection-view/config.js +9 -2
  177. package/plugins/runtime-modules/core/widgets/description/config.d.ts +1 -25
  178. package/plugins/runtime-modules/core/widgets/description/editor.js +4 -61
  179. package/plugins/runtime-modules/core/widgets/entry-list/config.d.ts +1 -25
  180. package/plugins/runtime-modules/core/widgets/gallery/config.d.ts +1 -25
  181. package/plugins/runtime-modules/core/widgets/image/config.js +2 -2
  182. package/plugins/runtime-modules/core/widgets/markdown/config.d.ts +3 -1
  183. package/plugins/runtime-modules/core/widgets/markdown/config.js +14 -0
  184. package/plugins/runtime-modules/core/widgets/markdown/editor.js +2 -3
  185. package/plugins/runtime-modules/core/widgets/result/config.d.ts +4 -25
  186. package/plugins/runtime-modules/core/widgets/result/config.js +2 -0
  187. package/plugins/runtime-modules/core/widgets/result/server.js +25 -19
  188. package/plugins/runtime-modules/core/widgets/simple-text/config.d.ts +1 -25
  189. package/plugins/runtime-modules/core/widgets/slot-upload/client.js +11 -2
  190. package/plugins/runtime-modules/core/widgets/table/client.js +8 -4
  191. package/plugins/runtime-modules/core/widgets/table/config.d.ts +3 -83
  192. package/plugins/runtime-modules/core/widgets/table/config.js +302 -452
  193. package/plugins/runtime-modules/core/widgets/tree/config.js +5 -2
  194. package/plugins/runtime-modules/dashboard/card-rows.d.ts +5 -0
  195. package/plugins/runtime-modules/dashboard/card-rows.js +59 -0
  196. package/plugins/runtime-modules/dashboard/clients/dashboard-card-view.js +4 -6
  197. package/plugins/runtime-modules/dashboard/services/collection.js +17 -7
  198. package/plugins/runtime-modules/groups/data-providers.d.ts +2 -0
  199. package/plugins/runtime-modules/groups/data-providers.js +3 -3
  200. package/plugins/runtime-modules/groups/definition.d.ts +2 -0
  201. package/plugins/runtime-modules/localization/data-providers.d.ts +3 -0
  202. package/plugins/runtime-modules/localization/data-providers.js +2 -0
  203. package/plugins/runtime-modules/localization/definition.d.ts +3 -0
  204. package/plugins/runtime-modules/localization/services/table.js +3 -7
  205. package/plugins/runtime-modules/observability/data-providers.d.ts +1 -0
  206. package/plugins/runtime-modules/observability/data-providers.js +1 -0
  207. package/plugins/runtime-modules/observability/definition.d.ts +1 -0
  208. package/plugins/runtime-modules/observability/module.d.ts +1 -0
  209. package/plugins/runtime-modules/observability/services/table.js +1 -1
  210. package/plugins/runtime-modules/phi-default-site-area-preset-tree.js +2 -105
  211. package/plugins/runtime-modules/public/presets.d.ts +115 -0
  212. package/plugins/runtime-modules/{area-base-presets.js → public/presets.js} +19 -119
  213. package/plugins/runtime-modules/public/server.d.ts +1 -4
  214. package/plugins/runtime-modules/public/server.js +4 -7
  215. package/plugins/runtime-modules/public/trees/phi-default-pub-error-page-tree.js +7 -8
  216. package/plugins/runtime-modules/public-base-page-references.d.ts +1 -1
  217. package/plugins/runtime-modules/public-base-page-references.js +1 -1
  218. package/plugins/runtime-modules/revisions/controller/client.js +11 -11
  219. package/plugins/runtime-modules/revisions/services/table.js +3 -3
  220. package/plugins/runtime-modules/theme/trees/phi-default-builder-theme-page-tree.js +22 -0
  221. package/plugins/runtime-modules/theme/widgets/brand-controls/client.d.ts +2 -1
  222. package/plugins/runtime-modules/theme/widgets/brand-controls/client.js +93 -58
  223. package/plugins/runtime-modules/theme/widgets/brand-controls/config.d.ts +2 -1
  224. package/plugins/runtime-modules/theme/widgets/brand-controls/config.js +23 -22
  225. package/plugins/runtime-modules/theme/widgets/brand-controls/plugin.js +1 -1
  226. package/plugins/runtime-modules/theme-descriptors.js +1 -1
  227. package/plugins/runtime-modules/user-management/data-providers.d.ts +2 -0
  228. package/plugins/runtime-modules/user-management/data-providers.js +1 -0
  229. package/plugins/runtime-modules/user-management/definition.d.ts +2 -0
  230. package/styles/control-shape.css +11 -11
  231. package/styles/controls.css +29 -3
  232. package/styles/layout.css +16 -7
  233. package/types/cms-config.js +142 -185
  234. package/types/cms-plugins.d.ts +4 -11
  235. package/types/core-widget-placements.d.ts +17 -3
  236. package/types/dashboard-cards.d.ts +9 -0
  237. package/types/media.d.ts +0 -3
  238. package/types/renderable-block.d.ts +6 -1
  239. package/types/table-widget.d.ts +9 -0
  240. package/types/table-widget.js +20 -0
  241. package/types.d.ts +1 -1
  242. package/widget-config.d.ts +2 -0
  243. package/widget-config.js +6 -0
  244. package/plugins/runtime-modules/area-base-presets.d.ts +0 -139
  245. /package/plugins/runtime-modules/{runtime-calendar-adapters.d.ts → core/calendar-adapters.d.ts} +0 -0
  246. /package/plugins/runtime-modules/{client-calendar-adapters/core.d.ts → core/client-calendar-adapters.d.ts} +0 -0
@@ -13,8 +13,10 @@ import { resolvePhiCmsRegionType } from "../../../helpers/cms-region-keys";
13
13
  import { resolvePhiAuthUiProviderModuleId, resolvePhiDeclaredMediaSpaces, resolvePhiDeclaredSeeds, resolvePhiDeclaredThreadKinds, resolvePhiRuntimeModuleIdsForArea, } from "../../../plugins/runtime-modules/settings";
14
14
  import { isPhiRuntimeAreaBaseModuleId } from "../../../plugins/runtime-modules/area-definitions";
15
15
  import { createPhiBuilderDraftAllocationKey } from "./draft-allocation-key";
16
- import { builderWorkspaceStore, commitPhiDeveloperBuilderAreaConfig, readPhiBuilderEffectiveAreaRootRoute, readPhiBuilderEffectiveAreaMeta, } from "./developer-workspace-store";
16
+ import { clearPhiBuilderDraftAllocation, storePhiBuilderDraftAllocation, commitPhiDeveloperBuilderAreaConfig, readPhiBuilderEffectiveAreaRootRoute, readPhiBuilderEffectiveAreaMeta, } from "./developer-workspace-store";
17
17
  import { resolvePhiBuilderActivePageCatalog, resolvePhiBuilderPageDefaultFlags, resolvePhiBuilderPagePresetSource, } from "../../../helpers/cms-page-catalog";
18
+ import { isPhiRuntimeModuleId } from "../../../constants/module-identity";
19
+ import { createPhiResponseReader, requirePhiField } from "../../../components/widgets/config/strict-config-reader";
18
20
  import { PHI_AREA_CONFIG_MODULES_NAMESPACE, PHI_AREA_CONFIG_SHELL_NAMESPACE, PHI_AREA_PUBLIC_ROUTE_PATHS_KEY, PHI_AREA_ROOT_ROUTE_KEY, PHI_AREA_META_KEY, normalizePhiAreaPublicRoutePaths, } from "../../../helpers/cms-area-config";
19
21
  /**
20
22
  * A save that was refused because there is nothing to patch yet -- an Area with no stored revision at
@@ -194,22 +196,33 @@ async function postCmsDraft(path, payload) {
194
196
  const addressRefused = body?.error === "path_collision" || body?.error === "path_nested";
195
197
  throw response.status === 409 && !addressRefused ? new CmsDraftConflictError(message) : new Error(message);
196
198
  }
197
- if (!Number.isSafeInteger(body?.revisionId) ||
198
- body?.revisionId < 1 ||
199
- !Number.isSafeInteger(body?.version) ||
200
- body?.version < 1 ||
201
- !Number.isSafeInteger(body?.nextNodeSequence) ||
202
- body?.nextNodeSequence < 1) {
203
- throw new Error("CMS draft save returned invalid Draft allocation metadata.");
204
- }
205
- if (!Object.prototype.hasOwnProperty.call(body, "sourcePreset")) {
206
- throw new Error("CMS draft save returned no preset source metadata.");
207
- }
199
+ return readPhiDraftAllocation(body, "The CMS draft save");
200
+ }
201
+ /**
202
+ * What a Draft save or read answers about the Draft it now stands on: its revision, version and node
203
+ * sequence, all positive, and the preset it came from -- stated as `null` when it came from none, never
204
+ * left out. Read field by field; each was checked before and then cast, and the preset source was not
205
+ * checked at all.
206
+ */
207
+ function readPhiDraftAllocation(body, source) {
208
+ const reader = createPhiResponseReader(body, source);
209
+ const positive = (key) => {
210
+ const value = requirePhiField(reader, key, "a positive whole number", reader.integer);
211
+ return value >= 1 ? value : reader.fail(key, "a positive whole number");
212
+ };
213
+ if (!Object.prototype.hasOwnProperty.call(reader.record, "sourcePreset")) {
214
+ reader.fail("sourcePreset", "a preset source or null");
215
+ }
216
+ const sourcePreset = reader.object("sourcePreset", (preset) => ({
217
+ ownerModuleId: requirePhiField(preset, "ownerModuleId", "a Module id", (key) => preset.value(key, "a Module id", (value) => (isPhiRuntimeModuleId(value) ? value : undefined))),
218
+ presetKey: requirePhiField(preset, "presetKey", "a text", preset.string),
219
+ sourcePresetVersion: requirePhiField(preset, "sourcePresetVersion", "a whole number", preset.integer),
220
+ })) ?? null;
208
221
  return {
209
- revisionId: body.revisionId,
210
- version: body.version,
211
- nextNodeSequence: body.nextNodeSequence,
212
- sourcePreset: body.sourcePreset ?? null,
222
+ revisionId: positive("revisionId"),
223
+ version: positive("version"),
224
+ nextNodeSequence: positive("nextNodeSequence"),
225
+ sourcePreset,
213
226
  };
214
227
  }
215
228
  async function postCmsAction(path, payload) {
@@ -247,23 +260,7 @@ async function getCmsDraft(path, payload) {
247
260
  const detail = body?.details?.length ? ` ${body.details.join(" ")}` : "";
248
261
  throw new Error(`${body?.error ?? "CMS draft read failed."}${detail}`);
249
262
  }
250
- if (!Number.isSafeInteger(body?.revisionId) ||
251
- body?.revisionId < 1 ||
252
- !Number.isSafeInteger(body?.version) ||
253
- body?.version < 1 ||
254
- !Number.isSafeInteger(body?.nextNodeSequence) ||
255
- body?.nextNodeSequence < 1) {
256
- throw new Error("CMS draft read returned invalid Draft allocation metadata.");
257
- }
258
- if (!Object.prototype.hasOwnProperty.call(body, "sourcePreset")) {
259
- throw new Error("CMS draft read returned no preset source metadata.");
260
- }
261
- return {
262
- revisionId: body.revisionId,
263
- version: body.version,
264
- nextNodeSequence: body.nextNodeSequence,
265
- sourcePreset: body.sourcePreset ?? null,
266
- };
263
+ return readPhiDraftAllocation(body, "The CMS draft read");
267
264
  }
268
265
  /**
269
266
  * The href a preview opens, with no locale in it.
@@ -294,37 +291,11 @@ export function buildPhiBuilderLiveHref(area, pageKey, pages, workspaceKind) {
294
291
  return `${url.pathname}${url.search}${url.hash}`;
295
292
  }
296
293
  function storePhiDeveloperBuilderDraftAllocation(allocationKey, saved) {
297
- builderWorkspaceStore.patch("public", (current) => {
298
- const currentAllocation = current.draftAllocations[allocationKey];
299
- const nextNodeSequence = currentAllocation?.revisionId === saved.revisionId
300
- ? Math.max(currentAllocation.nextNodeSequence, saved.nextNodeSequence)
301
- : saved.nextNodeSequence;
302
- return {
303
- ...current,
304
- draftAllocations: {
305
- ...current.draftAllocations,
306
- [allocationKey]: {
307
- revisionId: saved.revisionId,
308
- version: currentAllocation?.revisionId === saved.revisionId
309
- ? Math.max(currentAllocation.version, saved.version)
310
- : saved.version,
311
- nextNodeSequence,
312
- sourcePreset: saved.sourcePreset,
313
- },
314
- },
315
- };
316
- });
294
+ storePhiBuilderDraftAllocation(allocationKey, saved);
317
295
  }
318
296
  export function clearPhiDeveloperBuilderDraftAllocation(input) {
319
297
  const allocationKey = createPhiBuilderDraftAllocationKey(input.area, input.pageKey, input.workspaceKind === "pages" ? "page" : "area");
320
- builderWorkspaceStore.patch("public", (current) => {
321
- if (!current.draftAllocations[allocationKey]) {
322
- return current;
323
- }
324
- const draftAllocations = { ...current.draftAllocations };
325
- delete draftAllocations[allocationKey];
326
- return { ...current, draftAllocations };
327
- });
298
+ clearPhiBuilderDraftAllocation(allocationKey);
328
299
  }
329
300
  export async function getPhiDeveloperBuilderDraftAllocation(input) {
330
301
  const cmsArea = resolvePhiBuilderAreaAsCmsArea(input.area);
@@ -368,14 +339,7 @@ export async function getPhiDeveloperBuilderModulesDraftAllocation(input) {
368
339
  }
369
340
  function clearPhiDeveloperBuilderModulesDraftAllocation(area) {
370
341
  const allocationKey = createPhiBuilderDraftAllocationKey(area, area, "modules");
371
- builderWorkspaceStore.patch("public", (current) => {
372
- if (!current.draftAllocations[allocationKey]) {
373
- return current;
374
- }
375
- const draftAllocations = { ...current.draftAllocations };
376
- delete draftAllocations[allocationKey];
377
- return { ...current, draftAllocations };
378
- });
342
+ clearPhiBuilderDraftAllocation(allocationKey);
379
343
  }
380
344
  /**
381
345
  * What a tree tells its Controllers, as it arrived with the workspace. The Builder edits none of it but
@@ -1,5 +1,5 @@
1
1
  import type { PhiRuntimeModuleId } from "../../../types";
2
- import type { PhiBuilderPublicRouteCollisionAnswer, PhiBuilderPublicRouteCollisionRequest, PhiDeveloperBuilderArea, PhiDeveloperBuilderWorkspaceState } from "./developer-workspace-types";
2
+ import type { PhiBuilderPublicRouteCollisionAnswer, PhiBuilderPublicRouteCollisionRequest, PhiDeveloperBuilderWorkspaceState } from "./developer-workspace-types";
3
3
  /**
4
4
  * The question to put to the Builder before a Module may be enabled for Public.
5
5
  *
@@ -22,4 +22,4 @@ export declare function findPhiBuilderPublicRouteAnswerProblem(state: Pick<PhiDe
22
22
  * alone, including those of Modules that are switched off -- an assignment outlives its Module being
23
23
  * disabled, which is why nobody is asked the same question twice.
24
24
  */
25
- export declare function applyPhiBuilderPublicRouteAssignments(scopeKey: PhiDeveloperBuilderArea, request: Pick<PhiBuilderPublicRouteCollisionRequest, "moduleId" | "answers">): void;
25
+ export declare function applyPhiBuilderPublicRouteAssignments(request: Pick<PhiBuilderPublicRouteCollisionRequest, "moduleId" | "answers">): void;
@@ -1,8 +1,8 @@
1
1
  import { buildPhiRuntimeModulePackageRoutePrefix } from "../../../helpers/runtime-module-route-path";
2
2
  import { buildPhiPublicRouteAddressMap, findPhiPublicRoutePathCollisions, } from "../../../helpers/public-route-claims";
3
- import { isPhiAssignablePublicRoutePath, normalizePhiAreaPublicRoutePaths, } from "../../../helpers/cms-area-config";
4
- import { phiWorkspaceCatalogStore } from "../../../components/workspace/catalog-store";
5
- import { markPhiBuilderModuleAreasDirty } from "./runtime-module-selection";
3
+ import { isPhiAssignablePublicRoutePath, } from "../../../helpers/cms-area-config";
4
+ import { assignPhiWorkspacePublicRoutePaths } from "./workspace-catalog-actions";
5
+ import { markPhiBuilderModuleAreasDirty } from "./developer-workspace-store";
6
6
  /**
7
7
  * Which Public addresses a Site Page already occupies.
8
8
  *
@@ -121,21 +121,8 @@ export function findPhiBuilderPublicRouteAnswerProblem(state, request) {
121
121
  * alone, including those of Modules that are switched off -- an assignment outlives its Module being
122
122
  * disabled, which is why nobody is asked the same question twice.
123
123
  */
124
- export function applyPhiBuilderPublicRouteAssignments(scopeKey, request) {
124
+ export function applyPhiBuilderPublicRouteAssignments(request) {
125
125
  const answered = new Map(request.answers.map((answer) => [answer.presetKey, answer.path.trim()]));
126
- phiWorkspaceCatalogStore.patch(scopeKey, (catalog) => {
127
- const kept = (catalog.publicRoutePaths ?? []).filter((assignment) => assignment.ownerModuleId !== request.moduleId || !answered.has(assignment.presetKey));
128
- return {
129
- ...catalog,
130
- publicRoutePaths: normalizePhiAreaPublicRoutePaths([
131
- ...kept,
132
- ...[...answered.entries()].map(([presetKey, path]) => ({
133
- ownerModuleId: request.moduleId,
134
- presetKey,
135
- path,
136
- })),
137
- ]),
138
- };
139
- });
140
- markPhiBuilderModuleAreasDirty(["public"], scopeKey);
126
+ assignPhiWorkspacePublicRoutePaths(request.moduleId, answered);
127
+ markPhiBuilderModuleAreasDirty(["public"]);
141
128
  }
@@ -46,12 +46,29 @@ function mergePreviewTreeNodes(tree, extraPreviewNodes) {
46
46
  function resolveRootNodeFromPreviewDraft(draft) {
47
47
  return draft?.rootNode ? readPhiBuilderRootNodeDraft(draft.rootNode) : null;
48
48
  }
49
+ /*
50
+ * The nodes of every Region in one preview snapshot, built once per snapshot.
51
+ *
52
+ * Each of the ten Region previews needs all of them -- a signal route may name a node in another Region
53
+ * -- and each used to build every Region's tree again: about a hundred tree builds for one preview
54
+ * request. A snapshot is one parsed object per request and nothing here writes the result, so it is kept
55
+ * by that object and dropped with it.
56
+ */
57
+ const previewSnapshotNodes = new WeakMap();
49
58
  function buildPreviewSnapshotNodes(snapshot) {
50
- const layoutNodes = [];
51
- const contentWidgets = [];
52
59
  if (!snapshot) {
53
- return { layoutNodes, contentWidgets };
60
+ return { layoutNodes: [], contentWidgets: [] };
61
+ }
62
+ let nodes = previewSnapshotNodes.get(snapshot);
63
+ if (!nodes) {
64
+ nodes = collectPreviewSnapshotNodes(snapshot);
65
+ previewSnapshotNodes.set(snapshot, nodes);
54
66
  }
67
+ return nodes;
68
+ }
69
+ function collectPreviewSnapshotNodes(snapshot) {
70
+ const layoutNodes = [];
71
+ const contentWidgets = [];
55
72
  for (const [draftKey, draft] of Object.entries(snapshot.regionDrafts)) {
56
73
  const regionKey = draftKey.split(":").at(-1);
57
74
  const rootNode = resolveRootNodeFromPreviewDraft(draft);
@@ -265,7 +265,7 @@ function findPhiWidgetAuthoringTextTarget(container, clientX, clientY) {
265
265
  }
266
266
  function PhiWidgetEffectsPreviewFrame({ kind, slotSizePolicy, surfacePolicy, blockId, regionKey, config: committedConfig, title, scaffoldLabel, editorInteraction = "inert", onSelect, dropTarget, tools, style, children, }) {
267
267
  const { token } = usePhiConfig();
268
- const selected = usePhiDeveloperBuilderStateValue("public", (state) => blockId != null &&
268
+ const selected = usePhiDeveloperBuilderStateValue((state) => blockId != null &&
269
269
  regionKey != null &&
270
270
  state.selectedRootRegionKey === regionKey &&
271
271
  state.nodeKind === "widget" &&
@@ -278,7 +278,7 @@ function PhiWidgetEffectsPreviewFrame({ kind, slotSizePolicy, surfacePolicy, blo
278
278
  * still under the finger; the draft learns it when Save is pressed. Overlaying the whole `effects`
279
279
  * rather than one property keeps this the editor's picture and not a second opinion about it.
280
280
  */
281
- const effectsPreview = usePhiDeveloperBuilderStateValue("public", (state) => readPhiDeveloperBuilderEffectsPreview(state, "widget", blockId ?? null));
281
+ const effectsPreview = usePhiDeveloperBuilderStateValue((state) => readPhiDeveloperBuilderEffectsPreview(state, "widget", blockId ?? null));
282
282
  const config = effectsPreview
283
283
  ? { ...committedConfig, effects: effectsPreview }
284
284
  : committedConfig;
@@ -493,7 +493,7 @@ function PhiWidgetEffectsPreviewFrame({ kind, slotSizePolicy, surfacePolicy, blo
493
493
  }
494
494
  function PhiLayoutEffectsPreviewFrame({ kind, slotSizePolicy, blockId, config: committedConfig, explicitInlineSize, explicitBlockSize, children, }) {
495
495
  // The same live picture the Widget frame draws, for the Layout whose own toolbar opened the editor.
496
- const effectsPreview = usePhiDeveloperBuilderStateValue("public", (state) => readPhiDeveloperBuilderEffectsPreview(state, "layout", blockId ?? null));
496
+ const effectsPreview = usePhiDeveloperBuilderStateValue((state) => readPhiDeveloperBuilderEffectsPreview(state, "layout", blockId ?? null));
497
497
  const config = effectsPreview
498
498
  ? { ...committedConfig, effects: effectsPreview }
499
499
  : committedConfig;
@@ -1,6 +1,4 @@
1
- import type { PhiRuntimeModuleId } from "../../../types";
2
1
  import type { PhiDeveloperBuilderArea } from "./developer-workspace-types";
3
- export declare function areRuntimeModuleIdsEqual(left: readonly PhiRuntimeModuleId[] | null | undefined, right: readonly PhiRuntimeModuleId[] | null | undefined): boolean;
4
2
  /**
5
3
  * Applies a new Module selection to one or more Areas: validates each Area's list, patches the
6
4
  * catalog, and records the whole gesture as ONE history entry -- the one place all of this happens,
@@ -15,13 +13,5 @@ export declare function areRuntimeModuleIdsEqual(left: readonly PhiRuntimeModule
15
13
  export declare function applyPhiBuilderRuntimeModuleSelectionChanges(changes: ReadonlyArray<{
16
14
  area: PhiDeveloperBuilderArea;
17
15
  selectedIds: readonly string[];
18
- }>, defaultArea: PhiDeveloperBuilderArea): void;
19
- export declare function applyPhiBuilderRuntimeModuleSelectionChange(area: PhiDeveloperBuilderArea, selectedIds: readonly string[], defaultArea: PhiDeveloperBuilderArea): `${string}/${string}`[];
20
- /**
21
- * The Areas whose Module selection has unsaved edits, kept as Builder tool state so the Modules
22
- * workspace commands know which Areas a site-wide save or publish has to reach. Undo does not clear
23
- * an Area from here -- a save of an unchanged selection is a no-op draft, while a missed Area would
24
- * silently publish stale state.
25
- */
26
- export declare function markPhiBuilderModuleAreasDirty(areas: readonly PhiDeveloperBuilderArea[], defaultArea: PhiDeveloperBuilderArea): void;
27
- export declare function clearPhiBuilderModuleAreasDirty(defaultArea: PhiDeveloperBuilderArea): void;
16
+ }>): void;
17
+ export declare function applyPhiBuilderRuntimeModuleSelectionChange(area: PhiDeveloperBuilderArea, selectedIds: readonly string[]): `${string}/${string}`[];
@@ -1,13 +1,13 @@
1
1
  import { resolvePhiBuilderAreaAsCmsArea } from "../../../constants/cms-areas";
2
2
  import { isPhiRuntimeAreaBaseModuleId, resolvePhiRuntimeAreaDefinition, } from "../area-definitions";
3
3
  import { assertPhiRuntimeModuleIdsAllowedForArea } from "../settings";
4
- import { phiWorkspaceCatalogStore } from "../../../components/workspace/catalog-store";
5
- import { builderWorkspaceStore, getPhiDeveloperBuilderStateSnapshot } from "./developer-workspace-store";
4
+ import { getPhiDeveloperBuilderStateSnapshot, markPhiBuilderModuleAreasDirty } from "./developer-workspace-store";
5
+ import { setPhiWorkspaceModuleSelection } from "./workspace-catalog-actions";
6
6
  import { capturePhiBuilderModulesHistoryState, createPhiBuilderHistoryContext, phiBuilderHistory, } from "./history";
7
7
  function serializeRuntimeModuleIds(moduleIds) {
8
8
  return JSON.stringify(moduleIds ?? []);
9
9
  }
10
- export function areRuntimeModuleIdsEqual(left, right) {
10
+ function areRuntimeModuleIdsEqual(left, right) {
11
11
  return serializeRuntimeModuleIds(left) === serializeRuntimeModuleIds(right);
12
12
  }
13
13
  /**
@@ -52,8 +52,8 @@ function normalizeRuntimeModuleSelection(selectedIds, area, definitions) {
52
52
  * switched on in one Area and off in another is named once; the step's sentence says that the
53
53
  * selection of these changed, not which way.
54
54
  */
55
- function describeModuleSelectionChange(effective, before, defaultArea) {
56
- const definitions = getPhiDeveloperBuilderStateSnapshot(defaultArea).runtimeModuleDefinitions;
55
+ function describeModuleSelectionChange(effective, before) {
56
+ const definitions = getPhiDeveloperBuilderStateSnapshot().runtimeModuleDefinitions;
57
57
  const titleById = new Map(definitions.map((definition) => [definition.moduleId, definition.title]));
58
58
  const changed = new Set();
59
59
  for (const { area, moduleIds } of effective) {
@@ -79,8 +79,8 @@ function describeModuleSelectionChange(effective, before, defaultArea) {
79
79
  * the switch exists to avoid. Areas whose normalized list already matches what is live are dropped;
80
80
  * if nothing remains, nothing is recorded.
81
81
  */
82
- export function applyPhiBuilderRuntimeModuleSelectionChanges(changes, defaultArea) {
83
- const current = getPhiDeveloperBuilderStateSnapshot(defaultArea);
82
+ export function applyPhiBuilderRuntimeModuleSelectionChanges(changes) {
83
+ const current = getPhiDeveloperBuilderStateSnapshot();
84
84
  const effective = [];
85
85
  for (const change of changes) {
86
86
  const currentModuleIds = current.runtimeModuleIdsByArea?.[change.area] ?? [];
@@ -93,42 +93,16 @@ export function applyPhiBuilderRuntimeModuleSelectionChanges(changes, defaultAre
93
93
  return;
94
94
  }
95
95
  const changedAreas = effective.map(({ area }) => area);
96
- const historyBefore = capturePhiBuilderModulesHistoryState(getPhiDeveloperBuilderStateSnapshot(defaultArea), changedAreas);
97
- phiWorkspaceCatalogStore.patch(defaultArea, (catalog) => ({
98
- ...catalog,
99
- runtimeModuleIdsByArea: {
100
- ...(catalog.runtimeModuleIdsByArea ?? {}),
101
- ...Object.fromEntries(effective.map(({ area, moduleIds }) => [area, moduleIds])),
102
- },
103
- }));
104
- markPhiBuilderModuleAreasDirty(changedAreas, defaultArea);
105
- phiBuilderHistory.record(createPhiBuilderHistoryContext({ workspace: "modules", area: defaultArea }), {
106
- action: { key: "changeModules", subject: describeModuleSelectionChange(effective, historyBefore, defaultArea) },
96
+ const historyBefore = capturePhiBuilderModulesHistoryState(getPhiDeveloperBuilderStateSnapshot(), changedAreas);
97
+ setPhiWorkspaceModuleSelection(Object.fromEntries(effective.map(({ area, moduleIds }) => [area, moduleIds])));
98
+ markPhiBuilderModuleAreasDirty(changedAreas);
99
+ phiBuilderHistory.record(createPhiBuilderHistoryContext({ workspace: "modules" }), {
100
+ action: { key: "changeModules", subject: describeModuleSelectionChange(effective, historyBefore) },
107
101
  before: historyBefore,
108
- after: capturePhiBuilderModulesHistoryState(getPhiDeveloperBuilderStateSnapshot(defaultArea), changedAreas),
102
+ after: capturePhiBuilderModulesHistoryState(getPhiDeveloperBuilderStateSnapshot(), changedAreas),
109
103
  });
110
104
  }
111
- export function applyPhiBuilderRuntimeModuleSelectionChange(area, selectedIds, defaultArea) {
112
- applyPhiBuilderRuntimeModuleSelectionChanges([{ area, selectedIds }], defaultArea);
113
- return getPhiDeveloperBuilderStateSnapshot(defaultArea).runtimeModuleIdsByArea?.[area] ?? [];
114
- }
115
- /**
116
- * The Areas whose Module selection has unsaved edits, kept as Builder tool state so the Modules
117
- * workspace commands know which Areas a site-wide save or publish has to reach. Undo does not clear
118
- * an Area from here -- a save of an unchanged selection is a no-op draft, while a missed Area would
119
- * silently publish stale state.
120
- */
121
- export function markPhiBuilderModuleAreasDirty(areas, defaultArea) {
122
- builderWorkspaceStore.patch(defaultArea, (tool) => {
123
- const next = new Set(tool.modulesDirtyAreas ?? []);
124
- for (const area of areas) {
125
- next.add(area);
126
- }
127
- return next.size === (tool.modulesDirtyAreas ?? []).length
128
- ? tool
129
- : { ...tool, modulesDirtyAreas: [...next] };
130
- });
131
- }
132
- export function clearPhiBuilderModuleAreasDirty(defaultArea) {
133
- builderWorkspaceStore.patch(defaultArea, (tool) => (tool.modulesDirtyAreas?.length ?? 0) === 0 ? tool : { ...tool, modulesDirtyAreas: [] });
105
+ export function applyPhiBuilderRuntimeModuleSelectionChange(area, selectedIds) {
106
+ applyPhiBuilderRuntimeModuleSelectionChanges([{ area, selectedIds }]);
107
+ return getPhiDeveloperBuilderStateSnapshot().runtimeModuleIdsByArea?.[area] ?? [];
134
108
  }
@@ -23,7 +23,7 @@ import { PHI_BUILDER_RUNTIME_DATA_PROVIDER_DESCRIPTORS } from "../../../../plugi
23
23
  import { isPhiExternalHref } from "../../../../helpers/external-href";
24
24
  import { createPhiPageUri, readPhiInternalReference } from "../../../../types/references";
25
25
  import { buildPhiBuilderNavigationContainerFromCatalogFolder, findPhiBuilderCatalogNode, } from "../navigation-folder-drop";
26
- import { phiWorkspaceCatalogStore } from "../../../../components/workspace/catalog-store";
26
+ import { addPhiWorkspaceNavigationSurface } from "../workspace-catalog-actions";
27
27
  /**
28
28
  * The "404" choice of the Path cell. On a container it is how a folder address is cleared, and what a
29
29
  * choice that is no longer a direct child reads as; on a page link it is what a deleted target reads as,
@@ -196,11 +196,11 @@ export function PhiBuilderNavigationTableProviderClient({ children }) {
196
196
  * Inspector and every slider step -- each one a reload of the navigation. The functions below read the
197
197
  * state snapshot when they run; these subscriptions only say when a change is worth a new registration.
198
198
  */
199
- const area = usePhiDeveloperBuilderStateValue("public", (state) => state.area);
200
- const customPages = usePhiDeveloperBuilderStateValue("public", (state) => state.customPages);
201
- const modulePresetPagesByArea = usePhiDeveloperBuilderStateValue("public", (state) => state.modulePresetPagesByArea);
202
- const persistedPageCatalogByArea = usePhiDeveloperBuilderStateValue("public", (state) => state.persistedPageCatalogByArea);
203
- const navigationSurfacesByArea = usePhiDeveloperBuilderStateValue("public", (state) => state.navigationSurfacesByArea);
199
+ const area = usePhiDeveloperBuilderStateValue((state) => state.area);
200
+ const customPages = usePhiDeveloperBuilderStateValue((state) => state.customPages);
201
+ const modulePresetPagesByArea = usePhiDeveloperBuilderStateValue((state) => state.modulePresetPagesByArea);
202
+ const persistedPageCatalogByArea = usePhiDeveloperBuilderStateValue((state) => state.persistedPageCatalogByArea);
203
+ const navigationSurfacesByArea = usePhiDeveloperBuilderStateValue((state) => state.navigationSurfacesByArea);
204
204
  const activeNavigationKey = resolvePhiBuilderNavigationWidgetNavKey(undefined, navigationSearchValue, area);
205
205
  const activeNavigationDraft = usePhiBuilderNavigationDraft(activeNavigationKey);
206
206
  const loaded = useRef(new Map());
@@ -209,7 +209,7 @@ export function PhiBuilderNavigationTableProviderClient({ children }) {
209
209
  const initializedHistoryScopes = useRef(new Set());
210
210
  const registration = useMemo(() => {
211
211
  const resolveScope = (params) => {
212
- const state = getPhiDeveloperBuilderStateSnapshot("public");
212
+ const state = getPhiDeveloperBuilderStateSnapshot();
213
213
  const requestedNavKey = typeof params?.navKey === "string" ? params.navKey : navigationSearchValue;
214
214
  const navKey = resolvePhiBuilderNavigationWidgetNavKey(undefined, requestedNavKey ?? null, state.area);
215
215
  const surfaces = state.navigationSurfacesByArea[state.area];
@@ -345,7 +345,7 @@ export function PhiBuilderNavigationTableProviderClient({ children }) {
345
345
  if (!localKey) {
346
346
  return { status: "rejected", invalidation: "none", errorCode: "invalid-navigation-key", message: "Navigation key is invalid." };
347
347
  }
348
- const state = getPhiDeveloperBuilderStateSnapshot("public");
348
+ const state = getPhiDeveloperBuilderStateSnapshot();
349
349
  const cmsArea = resolvePhiBuilderAreaAsCmsArea(state.area);
350
350
  const navKey = formatPhiBuilderNavigationScopeKey(cmsArea, localKey);
351
351
  const surfaces = state.navigationSurfacesByArea[state.area] ?? [];
@@ -353,13 +353,7 @@ export function PhiBuilderNavigationTableProviderClient({ children }) {
353
353
  return { status: "rejected", invalidation: "none", errorCode: "navigation-exists", message: "Navigation already exists." };
354
354
  }
355
355
  const surface = createPhiBuilderCustomNavigationSurface(navKey, localKey);
356
- phiWorkspaceCatalogStore.patch("public", (current) => ({
357
- ...current,
358
- navigationSurfacesByArea: {
359
- ...current.navigationSurfacesByArea,
360
- [state.area]: [...(current.navigationSurfacesByArea[state.area] ?? []), surface],
361
- },
362
- }));
356
+ addPhiWorkspaceNavigationSurface(state.area, surface);
363
357
  const navigation = (await loadPhiBuilderNavigationScope(navKey, surface)).navigation;
364
358
  const saved = await savePhiBuilderNavigationDraft(navigation);
365
359
  setPhiBuilderNavigationDraft(navKey, {
@@ -47,13 +47,13 @@ export function PhiBuilderPageSourceTreeProviderClient({ children }) {
47
47
  * The slices the offered catalog is built from; the query reads the state when it runs. Subscribed
48
48
  * to the whole state, every selection renewed the registration and reloaded the tree.
49
49
  */
50
- const area = usePhiDeveloperBuilderStateValue("public", (state) => state.area);
51
- const customPages = usePhiDeveloperBuilderStateValue("public", (state) => state.customPages);
52
- const modulePresetPagesByArea = usePhiDeveloperBuilderStateValue("public", (state) => state.modulePresetPagesByArea);
53
- const navigationSurfacesByArea = usePhiDeveloperBuilderStateValue("public", (state) => state.navigationSurfacesByArea);
54
- const persistedPageCatalogByArea = usePhiDeveloperBuilderStateValue("public", (state) => state.persistedPageCatalogByArea);
55
- const runtimeModuleIdsByArea = usePhiDeveloperBuilderStateValue("public", (state) => state.runtimeModuleIdsByArea);
56
- const areaRootRoutes = usePhiDeveloperBuilderStateValue("public", (state) => state.areaRootRoutes);
50
+ const area = usePhiDeveloperBuilderStateValue((state) => state.area);
51
+ const customPages = usePhiDeveloperBuilderStateValue((state) => state.customPages);
52
+ const modulePresetPagesByArea = usePhiDeveloperBuilderStateValue((state) => state.modulePresetPagesByArea);
53
+ const navigationSurfacesByArea = usePhiDeveloperBuilderStateValue((state) => state.navigationSurfacesByArea);
54
+ const persistedPageCatalogByArea = usePhiDeveloperBuilderStateValue((state) => state.persistedPageCatalogByArea);
55
+ const runtimeModuleIdsByArea = usePhiDeveloperBuilderStateValue((state) => state.runtimeModuleIdsByArea);
56
+ const areaRootRoutes = usePhiDeveloperBuilderStateValue((state) => state.areaRootRoutes);
57
57
  const registration = useMemo(() => {
58
58
  const descriptor = PHI_BUILDER_RUNTIME_DATA_PROVIDER_DESCRIPTORS.find((candidate) => candidate.key === PHI_BUILDER_RUNTIME_DATA_PROVIDER_KEYS.pageSourceTree);
59
59
  return {
@@ -65,7 +65,7 @@ export function PhiBuilderPageSourceTreeProviderClient({ children }) {
65
65
  : field),
66
66
  })) : [],
67
67
  query: async (request) => {
68
- const state = getPhiDeveloperBuilderStateSnapshot("public");
68
+ const state = getPhiDeveloperBuilderStateSnapshot();
69
69
  const requestedArea = isBuilderArea(request.params?.area) ? request.params.area : state.area;
70
70
  /*
71
71
  * What the Area answers with, not what is installed in it. The active catalog mirrors the route
@@ -293,10 +293,10 @@ export function PhiBuilderRuntimeModulesTableProviderClient({ children }) {
293
293
  * they run -- which is also what a mutation has to do, since the answer it writes back is to the
294
294
  * selection as it stands then, not as it stood when the provider registered.
295
295
  */
296
- const runtimeModuleDefinitions = usePhiDeveloperBuilderStateValue("public", (state) => state.runtimeModuleDefinitions);
297
- const runtimeModuleIdsByArea = usePhiDeveloperBuilderStateValue("public", (state) => state.runtimeModuleIdsByArea);
298
- const unresolvedModuleIdsByArea = usePhiDeveloperBuilderStateValue("public", (state) => state.unresolvedModuleIdsByArea);
299
- const serverUnavailableModules = usePhiDeveloperBuilderStateValue("public", (state) => state.serverUnavailableModules);
296
+ const runtimeModuleDefinitions = usePhiDeveloperBuilderStateValue((state) => state.runtimeModuleDefinitions);
297
+ const runtimeModuleIdsByArea = usePhiDeveloperBuilderStateValue((state) => state.runtimeModuleIdsByArea);
298
+ const unresolvedModuleIdsByArea = usePhiDeveloperBuilderStateValue((state) => state.unresolvedModuleIdsByArea);
299
+ const serverUnavailableModules = usePhiDeveloperBuilderStateValue((state) => state.serverUnavailableModules);
300
300
  const registration = useMemo(() => {
301
301
  const descriptor = PHI_BUILDER_RUNTIME_DATA_PROVIDER_DESCRIPTORS.find((candidate) => candidate.key === PHI_BUILDER_RUNTIME_DATA_PROVIDER_KEYS.runtimeModulesTable);
302
302
  const resources = descriptor?.kind === "table" ? descriptor.resources : [];
@@ -309,7 +309,7 @@ export function PhiBuilderRuntimeModulesTableProviderClient({ children }) {
309
309
  throw new Error("Runtime Modules Table provider descriptor has no resource.");
310
310
  }
311
311
  const query = async (request) => {
312
- const builderState = getPhiDeveloperBuilderStateSnapshot("public");
312
+ const builderState = getPhiDeveloperBuilderStateSnapshot();
313
313
  if (request.resourceKey === DETAIL_RESOURCE_KEY) {
314
314
  const moduleId = typeof request.params?.moduleId === "string" ? request.params.moduleId : "";
315
315
  const areaLabels = readAreaLabels(request.params);
@@ -360,7 +360,7 @@ export function PhiBuilderRuntimeModulesTableProviderClient({ children }) {
360
360
  }, { ...request, query: filteredQuery });
361
361
  };
362
362
  const mutate = async (request) => {
363
- const builderState = getPhiDeveloperBuilderStateSnapshot("public");
363
+ const builderState = getPhiDeveloperBuilderStateSnapshot();
364
364
  if (request.resourceKey === MODULE_USAGE_RESOURCE_KEY) {
365
365
  return { status: "rejected", invalidation: "none", errorCode: "unsupported-mutation" };
366
366
  }
@@ -369,7 +369,7 @@ export function PhiBuilderRuntimeModulesTableProviderClient({ children }) {
369
369
  return { status: "rejected", invalidation: "none", errorCode: "unsupported-mutation" };
370
370
  }
371
371
  const path = typeof request.proposedValue === "string" ? request.proposedValue.trim() : "";
372
- answerPhiBuilderPublicRouteCollision("public", String(request.rowIdentity), path);
372
+ answerPhiBuilderPublicRouteCollision(String(request.rowIdentity), path);
373
373
  return { status: "accepted", invalidation: "none", rowPatch: { path } };
374
374
  }
375
375
  if (request.resourceKey !== RESOURCE_KEY) {
@@ -409,7 +409,7 @@ export function PhiBuilderRuntimeModulesTableProviderClient({ children }) {
409
409
  if (answers.length === 0) {
410
410
  return false;
411
411
  }
412
- openPhiBuilderPublicRouteCollisionRequest("public", {
412
+ openPhiBuilderPublicRouteCollisionRequest({
413
413
  moduleId: definition.moduleId,
414
414
  moduleTitle: definition.title,
415
415
  areas: cmsAreas.filter((areaKey) => isPhiBuilderAreaKey(areaKey)),
@@ -456,7 +456,7 @@ export function PhiBuilderRuntimeModulesTableProviderClient({ children }) {
456
456
  if (usage.length === 0) {
457
457
  return false;
458
458
  }
459
- openPhiBuilderModuleDeactivationRequest("public", {
459
+ openPhiBuilderModuleDeactivationRequest({
460
460
  moduleId: definition.moduleId,
461
461
  moduleTitle: definition.title,
462
462
  areas,
@@ -476,7 +476,7 @@ export function PhiBuilderRuntimeModulesTableProviderClient({ children }) {
476
476
  : currentModuleIds.filter((candidateId) => candidateId !== definition.moduleId),
477
477
  };
478
478
  });
479
- applyPhiBuilderRuntimeModuleSelectionChanges(changes, "public");
479
+ applyPhiBuilderRuntimeModuleSelectionChanges(changes);
480
480
  };
481
481
  // The row's switch: the Module as a whole, i.e. every eligible Area in one gesture.
482
482
  if (request.fieldKey === "active") {
@@ -50,8 +50,8 @@ export function PhiBuilderSignalRoutesTableProviderClient({ children }) {
50
50
  }
51
51
  const sessionKey = readSessionKey(request);
52
52
  const currentRoutes = sessionKey
53
- ? routeTableSessions.current.get(sessionKey) ?? getPhiDeveloperSelectedSignalRoutes("public")
54
- : getPhiDeveloperSelectedSignalRoutes("public");
53
+ ? routeTableSessions.current.get(sessionKey) ?? getPhiDeveloperSelectedSignalRoutes()
54
+ : getPhiDeveloperSelectedSignalRoutes();
55
55
  if (sessionKey && !routeTableSessions.current.has(sessionKey)) {
56
56
  routeTableSessions.current.set(sessionKey, currentRoutes ?? {});
57
57
  }
@@ -72,7 +72,7 @@ export function PhiBuilderSignalRoutesTableProviderClient({ children }) {
72
72
  throw new Error("Invalid Signal Routes Table mutation.");
73
73
  }
74
74
  const current = routeTableSessions.current.get(sessionKey) ??
75
- getPhiDeveloperSelectedSignalRoutes("public") ?? {};
75
+ getPhiDeveloperSelectedSignalRoutes() ?? {};
76
76
  if (request.actionKey === "cancel") {
77
77
  routeTableSessions.current.delete(sessionKey);
78
78
  }
@@ -1,3 +1,2 @@
1
1
  import { type PhiSignalRouteSet } from "../../../types/signals";
2
- import type { PhiDeveloperBuilderArea } from "./developer-workspace-types";
3
- export declare function getPhiDeveloperSelectedSignalRoutes(defaultArea: PhiDeveloperBuilderArea): PhiSignalRouteSet | null;
2
+ export declare function getPhiDeveloperSelectedSignalRoutes(): PhiSignalRouteSet | null;
@@ -25,7 +25,7 @@ function resolveSelectedSignalRouteConfig(state, drafts = getPhiDeveloperRegionD
25
25
  }
26
26
  return null;
27
27
  }
28
- export function getPhiDeveloperSelectedSignalRoutes(defaultArea) {
29
- const state = getPhiDeveloperBuilderStateSnapshot(defaultArea);
28
+ export function getPhiDeveloperSelectedSignalRoutes() {
29
+ const state = getPhiDeveloperBuilderStateSnapshot();
30
30
  return readPhiSignalRouteSet(resolveSelectedSignalRouteConfig(state)?.signalRoutes);
31
31
  }
@@ -1,4 +1,5 @@
1
1
  "use client";
2
+ import { PHI_WORKSPACE_CATALOG_SCOPE } from "../../../components/workspace/catalog-store";
2
3
  import { PHI_BUILDER_RUNTIME_DATA_PROVIDER_KEYS } from "./ids";
3
4
  import { createPhiControlOptionsProviderClient, } from "../../../components/controls/phi-options-provider";
4
5
  import { readPhiBuilderBoundCollectionResource } from "./selected-collection-source";
@@ -193,8 +194,8 @@ function resolveReceiverCapabilityOptions(context) {
193
194
  };
194
195
  }
195
196
  const wiringProviderStore = {
196
- subscribe: (listener) => builderWorkspaceStore.subscribe("public", listener),
197
- getSnapshot: () => getPhiDeveloperBuilderStateSnapshot("public"),
197
+ subscribe: (listener) => builderWorkspaceStore.subscribe(PHI_WORKSPACE_CATALOG_SCOPE, listener),
198
+ getSnapshot: () => getPhiDeveloperBuilderStateSnapshot(),
198
199
  };
199
200
  export const PhiBuilderSignalSendersOptionsProviderClient = createPhiControlOptionsProviderClient({
200
201
  key: PHI_BUILDER_RUNTIME_DATA_PROVIDER_KEYS.signalSenders,