@aglyn/aglyn 1.0.0-beta.172 → 1.0.0-beta.174

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 (39) hide show
  1. package/package.json +10 -10
  2. package/src/lib/app-utils/campaign-membership.d.ts +10 -8
  3. package/src/lib/app-utils/campaign-membership.js +11 -9
  4. package/src/lib/app-utils/campaign-membership.js.map +1 -1
  5. package/src/lib/app-utils/compose-layout-props.d.ts +6 -2
  6. package/src/lib/app-utils/compose-layout-props.js +8 -3
  7. package/src/lib/app-utils/compose-layout-props.js.map +1 -1
  8. package/src/lib/app-utils/compose-reusable-components.d.ts +85 -1
  9. package/src/lib/app-utils/compose-reusable-components.js +137 -11
  10. package/src/lib/app-utils/compose-reusable-components.js.map +1 -1
  11. package/src/lib/app-utils/crm.d.ts +3 -3
  12. package/src/lib/app-utils/crm.js.map +1 -1
  13. package/src/lib/app-utils/docs-help.generated.d.ts +1 -1
  14. package/src/lib/app-utils/docs-help.generated.js +1 -0
  15. package/src/lib/app-utils/docs-help.generated.js.map +1 -1
  16. package/src/lib/app-utils/docs-index.generated.js +11 -4
  17. package/src/lib/app-utils/docs-index.generated.js.map +1 -1
  18. package/src/lib/app-utils/element-color-scheme.d.ts +43 -0
  19. package/src/lib/app-utils/element-color-scheme.js +41 -0
  20. package/src/lib/app-utils/element-color-scheme.js.map +1 -0
  21. package/src/lib/app-utils/layout-style-overrides.d.ts +106 -0
  22. package/src/lib/app-utils/layout-style-overrides.js +158 -0
  23. package/src/lib/app-utils/layout-style-overrides.js.map +1 -0
  24. package/src/lib/app-utils/server.d.ts +2 -0
  25. package/src/lib/app-utils/server.js +4 -0
  26. package/src/lib/app-utils/server.js.map +1 -1
  27. package/src/lib/canvas-manager/canvas-manager.d.ts +5 -0
  28. package/src/lib/canvas-manager/canvas-manager.js +7 -0
  29. package/src/lib/canvas-manager/canvas-manager.js.map +1 -1
  30. package/src/lib/foundation/definitions/platform.types.d.ts +9 -0
  31. package/src/lib/foundation/definitions/platform.types.js.map +1 -1
  32. package/src/lib/plugin-manager/first-party-plugins.generated.d.ts +6 -1
  33. package/src/lib/plugin-manager/first-party-plugins.generated.js +17 -11
  34. package/src/lib/plugin-manager/first-party-plugins.generated.js.map +1 -1
  35. package/src/lib/plugin-manager/plugin-host-collections.d.ts +52 -1
  36. package/src/lib/plugin-manager/plugin-host-collections.js +23 -6
  37. package/src/lib/plugin-manager/plugin-host-collections.js.map +1 -1
  38. package/src/lib/types/nodes.d.ts +12 -0
  39. package/src/lib/types/nodes.js.map +1 -1
@@ -0,0 +1,43 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Aglyn LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+ /**
18
+ * An element's pinned color scheme (AGL-3284).
19
+ *
20
+ * A layout element — Section, Container, Stack, Box, Grid — may say "Always
21
+ * light" or "Always dark", and everything inside it then renders with the
22
+ * site's theme for that scheme, whatever the visitor picked: palette tokens
23
+ * (`background.default`, `text.primary`, `divider`, …) and every node's
24
+ * `@scheme dark` sx slice resolve for the pinned scheme. The renderer's leaf
25
+ * consumes the prop; it never reaches the DOM or the MUI component.
26
+ *
27
+ * Stored as a real value for all three choices. "Match the site" is the
28
+ * {@link ELEMENT_COLOR_SCHEME_SITE} sentinel rather than `''`, because an empty
29
+ * option value cannot survive the attributes form's save (AGL-1453) — and it
30
+ * resolves exactly like a missing prop, so an element that never had the
31
+ * attribute and one switched back to "Match the site" render identically.
32
+ */
33
+ /** The node prop carrying the pinned scheme. */
34
+ export declare const NODE_COLOR_SCHEME_PROP = "colorScheme";
35
+ /** "Match the site": follow the visitor's scheme, as if the prop were unset. */
36
+ export declare const ELEMENT_COLOR_SCHEME_SITE = "site";
37
+ export type ElementColorScheme = 'light' | 'dark';
38
+ /**
39
+ * The scheme an element is pinned to, or `undefined` when it follows the site.
40
+ * Anything other than `light`/`dark` — the sentinel, a cleared `null`, a
41
+ * stray paste — follows the site.
42
+ */
43
+ export declare function resolveElementColorScheme(value: unknown): ElementColorScheme | undefined;
@@ -0,0 +1,41 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Aglyn LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */ /**
17
+ * An element's pinned color scheme (AGL-3284).
18
+ *
19
+ * A layout element — Section, Container, Stack, Box, Grid — may say "Always
20
+ * light" or "Always dark", and everything inside it then renders with the
21
+ * site's theme for that scheme, whatever the visitor picked: palette tokens
22
+ * (`background.default`, `text.primary`, `divider`, …) and every node's
23
+ * `@scheme dark` sx slice resolve for the pinned scheme. The renderer's leaf
24
+ * consumes the prop; it never reaches the DOM or the MUI component.
25
+ *
26
+ * Stored as a real value for all three choices. "Match the site" is the
27
+ * {@link ELEMENT_COLOR_SCHEME_SITE} sentinel rather than `''`, because an empty
28
+ * option value cannot survive the attributes form's save (AGL-1453) — and it
29
+ * resolves exactly like a missing prop, so an element that never had the
30
+ * attribute and one switched back to "Match the site" render identically.
31
+ */ /** The node prop carrying the pinned scheme. */ export const NODE_COLOR_SCHEME_PROP = 'colorScheme';
32
+ /** "Match the site": follow the visitor's scheme, as if the prop were unset. */ export const ELEMENT_COLOR_SCHEME_SITE = 'site';
33
+ /**
34
+ * The scheme an element is pinned to, or `undefined` when it follows the site.
35
+ * Anything other than `light`/`dark` — the sentinel, a cleared `null`, a
36
+ * stray paste — follows the site.
37
+ */ export function resolveElementColorScheme(value) {
38
+ return value === 'light' || value === 'dark' ? value : undefined;
39
+ }
40
+
41
+ //# sourceMappingURL=element-color-scheme.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../libs/aglyn/src/lib/app-utils/element-color-scheme.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * An element's pinned color scheme (AGL-3284).\n *\n * A layout element — Section, Container, Stack, Box, Grid — may say \"Always\n * light\" or \"Always dark\", and everything inside it then renders with the\n * site's theme for that scheme, whatever the visitor picked: palette tokens\n * (`background.default`, `text.primary`, `divider`, …) and every node's\n * `@scheme dark` sx slice resolve for the pinned scheme. The renderer's leaf\n * consumes the prop; it never reaches the DOM or the MUI component.\n *\n * Stored as a real value for all three choices. \"Match the site\" is the\n * {@link ELEMENT_COLOR_SCHEME_SITE} sentinel rather than `''`, because an empty\n * option value cannot survive the attributes form's save (AGL-1453) — and it\n * resolves exactly like a missing prop, so an element that never had the\n * attribute and one switched back to \"Match the site\" render identically.\n */\n\n/** The node prop carrying the pinned scheme. */\nexport const NODE_COLOR_SCHEME_PROP = 'colorScheme'\n\n/** \"Match the site\": follow the visitor's scheme, as if the prop were unset. */\nexport const ELEMENT_COLOR_SCHEME_SITE = 'site'\n\nexport type ElementColorScheme = 'light' | 'dark'\n\n/**\n * The scheme an element is pinned to, or `undefined` when it follows the site.\n * Anything other than `light`/`dark` — the sentinel, a cleared `null`, a\n * stray paste — follows the site.\n */\nexport function resolveElementColorScheme(\n value: unknown,\n): ElementColorScheme | undefined {\n return value === 'light' || value === 'dark' ? value : undefined\n}\n"],"names":["NODE_COLOR_SCHEME_PROP","ELEMENT_COLOR_SCHEME_SITE","resolveElementColorScheme","value","undefined"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAED;;;;;;;;;;;;;;;CAeC,GAED,8CAA8C,GAC9C,OAAO,MAAMA,yBAAyB,cAAa;AAEnD,8EAA8E,GAC9E,OAAO,MAAMC,4BAA4B,OAAM;AAI/C;;;;CAIC,GACD,OAAO,SAASC,0BACdC,KAAc;IAEd,OAAOA,UAAU,WAAWA,UAAU,SAASA,QAAQC;AACzD"}
@@ -0,0 +1,106 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Aglyn LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+ import type { AglynNodeSchema, NodeId } from '../foundation';
18
+ /**
19
+ * Per-page styling of a shared layout's elements (AGL-3286).
20
+ *
21
+ * A screen framed by a layout may restyle any element of that layout for
22
+ * itself alone — a transparent nav over this page's hero, a different footer
23
+ * background — without touching the layout's content or the other screens
24
+ * that render inside it. It is the layout analogue of a component instance's
25
+ * `styleOverrides` (AGL-1306): an sx-shaped record per element, merged over
26
+ * that element's own sx with `mergeNodeSx`.
27
+ *
28
+ * Shape: layout id → layout node id → sx record. Keyed by layout, as
29
+ * `layoutPropValues` is (AGL-2893), so a screen can restyle an element of any
30
+ * layout in its chain and binding a different layout never hands these
31
+ * records to a node that merely shares an id there.
32
+ *
33
+ * Keyed by the layout's OWN node ids — the ids stored in the layout version,
34
+ * never the `layout__`/`layout2__` ids composition prefixes them with, which
35
+ * depend on where the layout sits in a chain.
36
+ */
37
+ export type LayoutStyleOverrides = Record<string, Record<NodeId, Record<string, unknown>>>;
38
+ /**
39
+ * Screen-version key holding the overrides, beside `layoutPropValues`.
40
+ * Persisted in screen version documents — never rename.
41
+ */
42
+ export declare const SCREEN_LAYOUT_STYLE_OVERRIDES_KEY = "layoutStyleOverrides";
43
+ type NormalizedNodes<N extends AglynNodeSchema> = Record<NodeId, N>;
44
+ /**
45
+ * The overrides with every empty or malformed entry dropped, or `undefined`
46
+ * when nothing is left — so "no overrides" has exactly one spelling, and a
47
+ * stored `{}` never reads as a change.
48
+ */
49
+ export declare function normalizeLayoutStyleOverrides(value: unknown): LayoutStyleOverrides | undefined;
50
+ /**
51
+ * A screen's overrides for one layout of its chain, or `undefined` where it
52
+ * set none. Anything that is not a map of sx records is read as none.
53
+ */
54
+ export declare function layoutStyleOverridesFor(overrides: unknown, layoutId: string | null | undefined): Record<NodeId, Record<string, unknown>> | undefined;
55
+ /**
56
+ * A layout's nodes with one screen's style overrides merged in.
57
+ *
58
+ * - A plain element takes the override over its own `sx` (`mergeNodeSx`, so
59
+ * breakpoint objects cascade and the `@scheme dark` slice merges key by
60
+ * key).
61
+ * - A reusable-component INSTANCE placed by the layout (the site nav, most
62
+ * often) takes it over its root override slice instead
63
+ * (`styleOverrides.root`), because that is the record the component graft
64
+ * merges onto the element it renders — an instance's own `sx` is not.
65
+ * - A key naming a node the layout no longer has is ignored: a layout edited
66
+ * after the page was styled degrades to its own styling.
67
+ *
68
+ * Inputs are never mutated; with nothing to apply the nodes come back by
69
+ * identity.
70
+ */
71
+ export declare function applyLayoutStyleOverrides<N extends AglynNodeSchema = AglynNodeSchema>(nodes: NormalizedNodes<N> | null | undefined, overrides: Record<NodeId, Record<string, unknown>> | null | undefined): NormalizedNodes<N> | undefined;
72
+ /**
73
+ * The screen's node map with its layout style overrides parked on the ROOT
74
+ * node, for the editor.
75
+ *
76
+ * In the besigner the overrides ride on the canvas root rather than in React
77
+ * state beside it, so they are part of the one document the editor already
78
+ * tracks: an edit is an undo step, marks the screen dirty, is carried by the
79
+ * working draft and the co-editing mirror, and is written by the same save —
80
+ * none of which a second store would get for free. `extractLayoutStyleOverrides`
81
+ * lifts them back out before anything is stored, so a saved `nodes` map never
82
+ * carries them.
83
+ */
84
+ export declare function injectLayoutStyleOverrides<T extends Record<string, any>>(nodes: T | null | undefined, overrides: unknown): T | null | undefined;
85
+ /**
86
+ * The inverse of {@link injectLayoutStyleOverrides}: the node map with the
87
+ * root's `layoutStyleOverrides` removed, and the overrides it held
88
+ * (`undefined` when none). The node map comes back by identity when the root
89
+ * carries none.
90
+ */
91
+ export declare function extractLayoutStyleOverrides<T extends Record<string, any>>(nodes: T): {
92
+ nodes: T;
93
+ layoutStyleOverrides: LayoutStyleOverrides | undefined;
94
+ };
95
+ /**
96
+ * The write that turns a stored map into `next` under a MERGING set.
97
+ *
98
+ * A Firestore `set(…, { merge: true })` merges nested maps key by key, so
99
+ * writing `next` as-is could only ever ADD: an override cleared in the editor
100
+ * would survive in the document. This names every key `previous` has and
101
+ * `next` does not with `remove()` (the caller's `deleteField()`), recursing
102
+ * through records both sides hold, so the merged result is exactly `next`.
103
+ * `undefined` for `next` removes the whole field.
104
+ */
105
+ export declare function replaceUnderMerge(previous: unknown, next: unknown, remove: () => unknown): unknown;
106
+ export {};
@@ -0,0 +1,158 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Aglyn LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */ import { _ as _extends } from "@swc/helpers/_/_extends";
17
+ import { _ as _object_without_properties_loose } from "@swc/helpers/_/_object_without_properties_loose";
18
+ import { NODE_ROOT_ID } from "../canvas-manager/canvas-manager.js";
19
+ import { mergeNodeSx } from "./merge-node-sx.js";
20
+ import { REUSABLE_INSTANCE_COMPONENT_ID, STYLE_OVERRIDES_ROOT_KEY } from "./reusable-component-keys.js";
21
+ /**
22
+ * Screen-version key holding the overrides, beside `layoutPropValues`.
23
+ * Persisted in screen version documents — never rename.
24
+ */ export const SCREEN_LAYOUT_STYLE_OVERRIDES_KEY = 'layoutStyleOverrides';
25
+ const isPlainRecord = (value)=>typeof value === 'object' && value !== null && !Array.isArray(value);
26
+ /**
27
+ * The overrides with every empty or malformed entry dropped, or `undefined`
28
+ * when nothing is left — so "no overrides" has exactly one spelling, and a
29
+ * stored `{}` never reads as a change.
30
+ */ export function normalizeLayoutStyleOverrides(value) {
31
+ if (!isPlainRecord(value)) return undefined;
32
+ const result = {};
33
+ for (const [layoutId, perNode] of Object.entries(value)){
34
+ if (!layoutId || !isPlainRecord(perNode)) continue;
35
+ const nodes = {};
36
+ for (const [nodeId, sx] of Object.entries(perNode)){
37
+ if (!nodeId || !isPlainRecord(sx) || !Object.keys(sx).length) continue;
38
+ nodes[nodeId] = sx;
39
+ }
40
+ if (Object.keys(nodes).length) result[layoutId] = nodes;
41
+ }
42
+ return Object.keys(result).length ? result : undefined;
43
+ }
44
+ /**
45
+ * A screen's overrides for one layout of its chain, or `undefined` where it
46
+ * set none. Anything that is not a map of sx records is read as none.
47
+ */ export function layoutStyleOverridesFor(overrides, layoutId) {
48
+ var _normalizeLayoutStyleOverrides;
49
+ if (!layoutId || !isPlainRecord(overrides)) return undefined;
50
+ return (_normalizeLayoutStyleOverrides = normalizeLayoutStyleOverrides({
51
+ [layoutId]: overrides[layoutId]
52
+ })) == null ? void 0 : _normalizeLayoutStyleOverrides[layoutId];
53
+ }
54
+ /**
55
+ * A layout's nodes with one screen's style overrides merged in.
56
+ *
57
+ * - A plain element takes the override over its own `sx` (`mergeNodeSx`, so
58
+ * breakpoint objects cascade and the `@scheme dark` slice merges key by
59
+ * key).
60
+ * - A reusable-component INSTANCE placed by the layout (the site nav, most
61
+ * often) takes it over its root override slice instead
62
+ * (`styleOverrides.root`), because that is the record the component graft
63
+ * merges onto the element it renders — an instance's own `sx` is not.
64
+ * - A key naming a node the layout no longer has is ignored: a layout edited
65
+ * after the page was styled degrades to its own styling.
66
+ *
67
+ * Inputs are never mutated; with nothing to apply the nodes come back by
68
+ * identity.
69
+ */ export function applyLayoutStyleOverrides(nodes, overrides) {
70
+ if (!nodes) return undefined;
71
+ if (!overrides) return nodes;
72
+ let result;
73
+ for (const [nodeId, sx] of Object.entries(overrides)){
74
+ const node = nodes[nodeId];
75
+ if (!node || !isPlainRecord(sx) || !Object.keys(sx).length) continue;
76
+ result != null ? result : result = _extends({}, nodes);
77
+ if (node.componentId === REUSABLE_INSTANCE_COMPONENT_ID) {
78
+ var _node_styleOverrides;
79
+ const slices = _extends({}, (_node_styleOverrides = node.styleOverrides) != null ? _node_styleOverrides : {});
80
+ slices[STYLE_OVERRIDES_ROOT_KEY] = mergeNodeSx(slices[STYLE_OVERRIDES_ROOT_KEY], sx);
81
+ result[nodeId] = _extends({}, node, {
82
+ styleOverrides: slices
83
+ });
84
+ } else {
85
+ result[nodeId] = _extends({}, node, {
86
+ sx: mergeNodeSx(node.sx, sx)
87
+ });
88
+ }
89
+ }
90
+ return result != null ? result : nodes;
91
+ }
92
+ /**
93
+ * The screen's node map with its layout style overrides parked on the ROOT
94
+ * node, for the editor.
95
+ *
96
+ * In the besigner the overrides ride on the canvas root rather than in React
97
+ * state beside it, so they are part of the one document the editor already
98
+ * tracks: an edit is an undo step, marks the screen dirty, is carried by the
99
+ * working draft and the co-editing mirror, and is written by the same save —
100
+ * none of which a second store would get for free. `extractLayoutStyleOverrides`
101
+ * lifts them back out before anything is stored, so a saved `nodes` map never
102
+ * carries them.
103
+ */ export function injectLayoutStyleOverrides(nodes, overrides) {
104
+ const normalized = normalizeLayoutStyleOverrides(overrides);
105
+ const root = nodes == null ? void 0 : nodes[NODE_ROOT_ID];
106
+ if (!nodes || !root || !normalized) return nodes;
107
+ return _extends({}, nodes, {
108
+ [NODE_ROOT_ID]: _extends({}, root, {
109
+ layoutStyleOverrides: normalized
110
+ })
111
+ });
112
+ }
113
+ /**
114
+ * The inverse of {@link injectLayoutStyleOverrides}: the node map with the
115
+ * root's `layoutStyleOverrides` removed, and the overrides it held
116
+ * (`undefined` when none). The node map comes back by identity when the root
117
+ * carries none.
118
+ */ export function extractLayoutStyleOverrides(nodes) {
119
+ const root = nodes == null ? void 0 : nodes[NODE_ROOT_ID];
120
+ if (!root || !('layoutStyleOverrides' in root)) {
121
+ return {
122
+ nodes,
123
+ layoutStyleOverrides: undefined
124
+ };
125
+ }
126
+ const { layoutStyleOverrides } = root, rest = _object_without_properties_loose(root, [
127
+ "layoutStyleOverrides"
128
+ ]);
129
+ return {
130
+ nodes: _extends({}, nodes, {
131
+ [NODE_ROOT_ID]: rest
132
+ }),
133
+ layoutStyleOverrides: normalizeLayoutStyleOverrides(layoutStyleOverrides)
134
+ };
135
+ }
136
+ /**
137
+ * The write that turns a stored map into `next` under a MERGING set.
138
+ *
139
+ * A Firestore `set(…, { merge: true })` merges nested maps key by key, so
140
+ * writing `next` as-is could only ever ADD: an override cleared in the editor
141
+ * would survive in the document. This names every key `previous` has and
142
+ * `next` does not with `remove()` (the caller's `deleteField()`), recursing
143
+ * through records both sides hold, so the merged result is exactly `next`.
144
+ * `undefined` for `next` removes the whole field.
145
+ */ export function replaceUnderMerge(previous, next, remove) {
146
+ if (next === undefined) return previous === undefined ? undefined : remove();
147
+ if (!isPlainRecord(previous) || !isPlainRecord(next)) return next;
148
+ const write = {};
149
+ for (const key of Object.keys(previous)){
150
+ if (!(key in next)) write[key] = remove();
151
+ }
152
+ for (const [key, value] of Object.entries(next)){
153
+ write[key] = replaceUnderMerge(previous[key], value, remove);
154
+ }
155
+ return write;
156
+ }
157
+
158
+ //# sourceMappingURL=layout-style-overrides.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../libs/aglyn/src/lib/app-utils/layout-style-overrides.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { AglynNodeSchema, NodeId } from '../foundation'\nimport { NODE_ROOT_ID } from '../canvas-manager/canvas-manager'\nimport { mergeNodeSx } from './merge-node-sx'\nimport {\n REUSABLE_INSTANCE_COMPONENT_ID,\n STYLE_OVERRIDES_ROOT_KEY,\n} from './reusable-component-keys'\n\n/**\n * Per-page styling of a shared layout's elements (AGL-3286).\n *\n * A screen framed by a layout may restyle any element of that layout for\n * itself alone — a transparent nav over this page's hero, a different footer\n * background — without touching the layout's content or the other screens\n * that render inside it. It is the layout analogue of a component instance's\n * `styleOverrides` (AGL-1306): an sx-shaped record per element, merged over\n * that element's own sx with `mergeNodeSx`.\n *\n * Shape: layout id → layout node id → sx record. Keyed by layout, as\n * `layoutPropValues` is (AGL-2893), so a screen can restyle an element of any\n * layout in its chain and binding a different layout never hands these\n * records to a node that merely shares an id there.\n *\n * Keyed by the layout's OWN node ids — the ids stored in the layout version,\n * never the `layout__`/`layout2__` ids composition prefixes them with, which\n * depend on where the layout sits in a chain.\n */\nexport type LayoutStyleOverrides = Record<\n string,\n Record<NodeId, Record<string, unknown>>\n>\n\n/**\n * Screen-version key holding the overrides, beside `layoutPropValues`.\n * Persisted in screen version documents — never rename.\n */\nexport const SCREEN_LAYOUT_STYLE_OVERRIDES_KEY = 'layoutStyleOverrides'\n\ntype NormalizedNodes<N extends AglynNodeSchema> = Record<NodeId, N>\n\nconst isPlainRecord = (value: unknown): value is Record<string, unknown> =>\n typeof value === 'object' && value !== null && !Array.isArray(value)\n\n/**\n * The overrides with every empty or malformed entry dropped, or `undefined`\n * when nothing is left — so \"no overrides\" has exactly one spelling, and a\n * stored `{}` never reads as a change.\n */\nexport function normalizeLayoutStyleOverrides(\n value: unknown,\n): LayoutStyleOverrides | undefined {\n if (!isPlainRecord(value)) return undefined\n const result: LayoutStyleOverrides = {}\n for (const [layoutId, perNode] of Object.entries(value)) {\n if (!layoutId || !isPlainRecord(perNode)) continue\n const nodes: Record<NodeId, Record<string, unknown>> = {}\n for (const [nodeId, sx] of Object.entries(perNode)) {\n if (!nodeId || !isPlainRecord(sx) || !Object.keys(sx).length) continue\n nodes[nodeId] = sx\n }\n if (Object.keys(nodes).length) result[layoutId] = nodes\n }\n return Object.keys(result).length ? result : undefined\n}\n\n/**\n * A screen's overrides for one layout of its chain, or `undefined` where it\n * set none. Anything that is not a map of sx records is read as none.\n */\nexport function layoutStyleOverridesFor(\n overrides: unknown,\n layoutId: string | null | undefined,\n): Record<NodeId, Record<string, unknown>> | undefined {\n if (!layoutId || !isPlainRecord(overrides)) return undefined\n return normalizeLayoutStyleOverrides({ [layoutId]: overrides[layoutId] })?.[\n layoutId\n ]\n}\n\n/**\n * A layout's nodes with one screen's style overrides merged in.\n *\n * - A plain element takes the override over its own `sx` (`mergeNodeSx`, so\n * breakpoint objects cascade and the `@scheme dark` slice merges key by\n * key).\n * - A reusable-component INSTANCE placed by the layout (the site nav, most\n * often) takes it over its root override slice instead\n * (`styleOverrides.root`), because that is the record the component graft\n * merges onto the element it renders — an instance's own `sx` is not.\n * - A key naming a node the layout no longer has is ignored: a layout edited\n * after the page was styled degrades to its own styling.\n *\n * Inputs are never mutated; with nothing to apply the nodes come back by\n * identity.\n */\nexport function applyLayoutStyleOverrides<\n N extends AglynNodeSchema = AglynNodeSchema,\n>(\n nodes: NormalizedNodes<N> | null | undefined,\n overrides: Record<NodeId, Record<string, unknown>> | null | undefined,\n): NormalizedNodes<N> | undefined {\n if (!nodes) return undefined\n if (!overrides) return nodes\n let result: NormalizedNodes<N> | undefined\n for (const [nodeId, sx] of Object.entries(overrides)) {\n const node = nodes[nodeId]\n if (!node || !isPlainRecord(sx) || !Object.keys(sx).length) continue\n result ??= { ...nodes }\n if (node.componentId === REUSABLE_INSTANCE_COMPONENT_ID) {\n const slices = {\n ...((node as { styleOverrides?: Record<string, unknown> })\n .styleOverrides ?? {}),\n }\n slices[STYLE_OVERRIDES_ROOT_KEY] = mergeNodeSx(\n slices[STYLE_OVERRIDES_ROOT_KEY],\n sx,\n )\n result[nodeId] = { ...node, styleOverrides: slices }\n } else {\n result[nodeId] = { ...node, sx: mergeNodeSx(node.sx, sx) as N['sx'] }\n }\n }\n return result ?? nodes\n}\n\n/**\n * The screen's node map with its layout style overrides parked on the ROOT\n * node, for the editor.\n *\n * In the besigner the overrides ride on the canvas root rather than in React\n * state beside it, so they are part of the one document the editor already\n * tracks: an edit is an undo step, marks the screen dirty, is carried by the\n * working draft and the co-editing mirror, and is written by the same save —\n * none of which a second store would get for free. `extractLayoutStyleOverrides`\n * lifts them back out before anything is stored, so a saved `nodes` map never\n * carries them.\n */\nexport function injectLayoutStyleOverrides<T extends Record<string, any>>(\n nodes: T | null | undefined,\n overrides: unknown,\n): T | null | undefined {\n const normalized = normalizeLayoutStyleOverrides(overrides)\n const root = nodes?.[NODE_ROOT_ID]\n if (!nodes || !root || !normalized) return nodes\n return {\n ...nodes,\n [NODE_ROOT_ID]: { ...root, layoutStyleOverrides: normalized },\n }\n}\n\n/**\n * The inverse of {@link injectLayoutStyleOverrides}: the node map with the\n * root's `layoutStyleOverrides` removed, and the overrides it held\n * (`undefined` when none). The node map comes back by identity when the root\n * carries none.\n */\nexport function extractLayoutStyleOverrides<T extends Record<string, any>>(\n nodes: T,\n): { nodes: T; layoutStyleOverrides: LayoutStyleOverrides | undefined } {\n const root = nodes?.[NODE_ROOT_ID]\n if (!root || !('layoutStyleOverrides' in root)) {\n return { nodes, layoutStyleOverrides: undefined }\n }\n const { layoutStyleOverrides, ...rest } = root\n return {\n nodes: { ...nodes, [NODE_ROOT_ID]: rest },\n layoutStyleOverrides: normalizeLayoutStyleOverrides(layoutStyleOverrides),\n }\n}\n\n/**\n * The write that turns a stored map into `next` under a MERGING set.\n *\n * A Firestore `set(…, { merge: true })` merges nested maps key by key, so\n * writing `next` as-is could only ever ADD: an override cleared in the editor\n * would survive in the document. This names every key `previous` has and\n * `next` does not with `remove()` (the caller's `deleteField()`), recursing\n * through records both sides hold, so the merged result is exactly `next`.\n * `undefined` for `next` removes the whole field.\n */\nexport function replaceUnderMerge(\n previous: unknown,\n next: unknown,\n remove: () => unknown,\n): unknown {\n if (next === undefined) return previous === undefined ? undefined : remove()\n if (!isPlainRecord(previous) || !isPlainRecord(next)) return next\n const write: Record<string, unknown> = {}\n for (const key of Object.keys(previous)) {\n if (!(key in next)) write[key] = remove()\n }\n for (const [key, value] of Object.entries(next)) {\n write[key] = replaceUnderMerge(previous[key], value, remove)\n }\n return write\n}\n"],"names":["NODE_ROOT_ID","mergeNodeSx","REUSABLE_INSTANCE_COMPONENT_ID","STYLE_OVERRIDES_ROOT_KEY","SCREEN_LAYOUT_STYLE_OVERRIDES_KEY","isPlainRecord","value","Array","isArray","normalizeLayoutStyleOverrides","undefined","result","layoutId","perNode","Object","entries","nodes","nodeId","sx","keys","length","layoutStyleOverridesFor","overrides","applyLayoutStyleOverrides","node","componentId","slices","styleOverrides","injectLayoutStyleOverrides","normalized","root","layoutStyleOverrides","extractLayoutStyleOverrides","rest","replaceUnderMerge","previous","next","remove","write","key"],"mappings":"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"}
@@ -69,6 +69,7 @@ export * from './dynamic-list-rule';
69
69
  export * from './email-topics';
70
70
  export * from './compose-layout-nodes';
71
71
  export * from './compose-layout-props';
72
+ export * from './layout-style-overrides';
72
73
  export * from './document-landmark';
73
74
  export * from './functions';
74
75
  export * from './compose-reusable-components';
@@ -76,6 +77,7 @@ export * from './compress';
76
77
  export * from './merge-node-sx';
77
78
  export * from './palette-sx';
78
79
  export * from './scheme-sx';
80
+ export * from './element-color-scheme';
79
81
  export * from './create-resource-uid';
80
82
  export * from './decompress';
81
83
  export * from './stored-nodes';
@@ -156,6 +156,8 @@ export * from "./email-topics.js";
156
156
  export * from "./compose-layout-nodes.js";
157
157
  // Layout properties applied through the chain (AGL-2893).
158
158
  export * from "./compose-layout-props.js";
159
+ // A screen's per-page restyling of its layout's elements (AGL-3286).
160
+ export * from "./layout-style-overrides.js";
159
161
  export * from "./document-landmark.js";
160
162
  export * from "./functions.js";
161
163
  export * from "./compose-reusable-components.js";
@@ -163,6 +165,8 @@ export * from "./compress.js";
163
165
  export * from "./merge-node-sx.js";
164
166
  export * from "./palette-sx.js";
165
167
  export * from "./scheme-sx.js";
168
+ // An element pinned to one color scheme (AGL-3284).
169
+ export * from "./element-color-scheme.js";
166
170
  export * from "./create-resource-uid.js";
167
171
  export * from "./decompress.js";
168
172
  export * from "./stored-nodes.js";
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../libs/aglyn/src/lib/app-utils/server.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2022 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Server-safe app-utils: every app-util EXCEPT the client-only React\n * contexts (see ./contexts). Nothing here calls `createContext` at module\n * scope, so this barrel — re-exported by `@aglyn/aglyn/server` — is safe to\n * import from tenant Server Components (AGL-405). The full `./index` barrel\n * re-adds the contexts for client consumers.\n */\nexport * from './binding-token-catalog'\nexport * from './binding-tokens'\nexport * from './breadcrumb-json-ld'\n// What a search listing holds and how long each field may be (AGL-2910):\n// the SEO editors and anything that proposes a value read one catalog.\nexport * from './seo-listing-fields'\n// `VideoObject` for the Video elements a page actually ships (AGL-2747).\n// Beside the other structured-data builders, and server-only like them: only\n// the route emits JSON-LD, and a crawler-facing block has no client caller.\nexport * from './video-object'\nexport * from './collection-delete'\nexport * from './collection-entries'\nexport * from './collection-kind'\nexport * from './collection-slug'\nexport * from './content-authors'\nexport * from './content-schema-type'\nexport * from './content-author-profile'\nexport * from './url-slug'\nexport * from './child-contract'\nexport * from './child-contract-compose'\n// The one reading of `restrictChildren`/`restrictParent`, shared by the\n// besigner's drop check and the AI plugin's node-tree validator (AGL-2905).\nexport * from './lineal-order'\n// What a node tree must satisfy before it lands on a canvas that did not\n// author it (AGL-2939): the marketplace's install sanitizer and the AI\n// plugin's node-tree validator both pass through it.\nexport * from './node-definition-sanitizer'\nexport * from './console-routes'\nexport * from './console-record-links'\n// What a stored screen-link value means, with no React attached — the\n// where-used scan reads these on the server (AGL-703).\nexport * from './screen-link-value'\n// Which entries a page's links name (AGL-3118). The tenant render reads\n// exactly those entry documents, so the walk runs on the server.\nexport * from './link-references'\nexport * from './analytics-path-key'\nexport * from './contacts'\n// A lead's or a contact's email state (AGL-3245): the last verdict on its\n// address, in words a person can act on, mirrored from the senders' lists.\nexport * from './email-state'\n// The records that sit beside a contact — companies, pipelines, deals, tasks,\n// activities, field definitions (AGL-2595). Pure like `contacts`, and beside\n// it because `ContactFacet` names its lifecycle stage and custom-value types;\n// the scope stamp every CRM creator writes lives here too.\nexport * from './crm'\n// Email templates, snippets and the merge-field resolver (AGL-2658): the\n// letter a rep keeps under a name, and the one grammar the send route and\n// the dialog fill it in by. Pure like `crm`, and beside it because a\n// template is scoped the way a task is.\nexport * from './crm-email-templates'\n// The booking door's shared vocabulary (AGL-2660): the query keys a booking\n// link carries, the record reference inside it, and the wording and due\n// date of what a booking files back on the record.\nexport * from './crm-booking'\n// Two contact documents folded into one (AGL-2625): the plan the console\n// previews and the server writes, reading the facet shape from `contacts`\n// and the company mirror from `crm`.\nexport * from './contact-merge'\n// A person's privacy erasure from one workspace (AGL-2623): the request's\n// shape and id, the marker a record carries while it waits, and the lists\n// the dialog and the docs share. Pure like `crm`; the sweep is server-side.\nexport * from './person-erasure'\n// What the CRM's reports compute from what they read — periods, weekly\n// buckets, the lifecycle funnel, pipeline totals (AGL-2604). Pure like `crm`,\n// and beside it because it reads the stage list and the deal weighting from\n// there rather than restating either.\nexport * from './crm-reports'\n// Every CRM CSV, written once (AGL-2662): the column lists and the cells\n// each section's Export button writes, and the server's whole-collection\n// export streams — one implementation, because the console app may not\n// import the plugin whose sections used to hold it.\nexport * from './crm-csv'\n// Which holder a cross-site reader sees one contact through (AGL-2630),\n// beside the files that write it: the org-level list and the server's\n// export both flatten a contact this way.\nexport * from './contact-holder'\n// What one member is owed this morning — the day's window in a named zone,\n// the task and lead bucketing, and the words the notification and the mail\n// say (AGL-2619). Pure like `crm-reports`, read by the scheduled route.\nexport * from './crm-digest'\n// A task's reminder at its own time (AGL-2659): which reminder a save\n// leaves, whether one is owed, and the words the notification and the mail\n// say. Pure like `crm-digest`, read by the hourly route and by every\n// writer of the field.\nexport * from './crm-task-reminders'\n// Email capture (AGL-2657): the address's shape and token, which of a\n// message's addresses is the correspondent, the excerpt, and the row a\n// captured message becomes. Pure like `crm-digest`; the webhook route and\n// the address route are the readers with Firestore.\nexport * from './crm-inbound'\n// A member's own addresses in a workspace (AGL-2975): the ones they have\n// confirmed count as theirs wherever the roster is asked who wrote a\n// message. Pure; the store and the confirmation link are server-side.\nexport * from './member-email-aliases'\n// The next activity a record carries (AGL-2661): what `nextTaskAtMs` IS given\n// a record's open tasks, the view clause a list filters on, the report figure.\n// Pure like `crm`; the admin library's `recomputeCrmNextTaskAt` is the writer.\nexport * from './crm-next-activity'\n// The CSV cell grammar the exports write with (AGL-2621), and the target a\n// mapped column names for a custom field — named rather than starred, because\n// an importer built on this file exports the shared ceilings under its own\n// names.\nexport {\n csvCell,\n csvDocument,\n customImportTarget,\n customImportTargetKey,\n} from './csv-import'\nexport type {\n ImportChunkResult,\n ImportDroppedValue,\n ImportSkippedRow,\n} from './csv-import'\n// What a VALUE under a custom contact field may be, and the coercion every\n// door applies to one (AGL-2601): a mapped form field, an API `custom` body,\n// and the carry-over that keeps a mapping across a publish. Pure like `crm`.\nexport * from './contact-custom-fields'\n// The consent JOIN (`docs/specs/email-overhaul.md` §3f). Pure, and it composes\n// `contacts` for the normalizer, so it sits directly beside it. No Node\n// builtin, which is what keeps it out of the `/server`-only group `person-key`\n// belongs to.\nexport * from './consent-groups'\nexport * from './marketing-consent'\n// The ENROLLMENT-time half of the same question, beside its reader for the\n// same reason: `marketing-consent` decides whether a recorded basis lets us\n// mail somebody, and this decides what basis putting them on a list may\n// record. Two enrollment surfaces import it — the Inbox assignment route and\n// the Emails console's audience card — and neither could import the other.\nexport * from './list-assignment-policy'\n// Reading the FILE a merchant arrives with (`docs/specs/email-competitive-gaps.md`\n// G5/P4), directly after the policy it hands its addresses to: parsing and\n// mechanical screening only, so that an import asks the enrollment question\n// through the same module the one-address add path asks it through rather\n// than answering it a second way.\nexport * from './list-import'\n// The dynamic-list rule (§3b/§3c), beside it for the same reasons: pure, and\n// it composes `contacts` for the segment vocabulary rather than restating it.\nexport * from './dynamic-list-rule'\n// The subscribable streams a recipient can leave one at a time\n// (`docs/specs/email-competitive-gaps.md` §1f). Pure, and read from all three\n// sides of the feature: the composer picks one, the send path signs it into\n// the unsubscribe link, and the unauthenticated preference page renders the\n// catalog. No Node builtin, so it stays out of the `/server`-only group.\nexport * from './email-topics'\nexport * from './compose-layout-nodes'\n// Layout properties applied through the chain (AGL-2893).\nexport * from './compose-layout-props'\nexport * from './document-landmark'\nexport * from './functions'\nexport * from './compose-reusable-components'\nexport * from './compress'\nexport * from './merge-node-sx'\nexport * from './palette-sx'\nexport * from './scheme-sx'\nexport * from './create-resource-uid'\nexport * from './decompress'\nexport * from './stored-nodes'\nexport * from './strip-undefined'\nexport * from './organizations'\nexport * from './org-permissions'\n// The AI verdict on either membership axis (AGL-2927). After both modules it\n// composes: the org catalog for org-wide members, the host role for site\n// collaborators.\nexport * from './host-permissions'\nexport * from './password-policy'\nexport * from './idp-profile'\nexport * from './onboarding-deep-link'\n// Where an account came from (AGL-1731). Beside the plan intent because\n// they are the same hop — the marketing CTA's query string — and both are\n// remembered on `users/{uid}` across the verification wall.\nexport * from './campaign-attribution'\n// The edge between a campaign and the forms, screens and contacts a push is\n// coordinated across. Beside the attribution above because the two answer\n// opposite questions about the same word: attribution records where somebody\n// CAME from, this records what a merchant DECLARED belongs together.\nexport * from './campaign-membership'\nexport * from './deployment-shape'\n// Which browser origins may complete a signed direct-to-GCS upload (AGL-1452).\n// GCS matches the origin list EXACTLY, so every serving console name needs its\n// own entry — the rule nobody could be expected to remember at attach time.\nexport * from './upload-cors'\n// The docs-help subset the first-party plugin consoles read (AGL-2213) — the\n// console's own registry lives in apps/console/constants and a lib cannot\n// import an app.\nexport * from './docs-help'\nexport * from './platform-brand'\nexport * from './plan-entitlements'\n// The free plan's bandwidth hard cap (AGL-1967/2070/2155). After\n// `plan-entitlements`, which owns the predicate it keys off.\nexport * from './bandwidth-cap'\nexport * from './form-abuse-ceiling'\nexport * from './forms'\n// What a form's DESIGN must still satisfy for its submissions to arrive.\n// After `forms`, whose field walk it reads the drawn fields with.\nexport * from './form-contract'\nexport * from './visitor-record-ceiling'\nexport * from './health-report'\n// Did a webhook delivery actually DO anything (AGL-1954)? After\n// `health-report`, whose billing verdict consumes the counts this produces.\nexport * from './webhook-delivery'\nexport * from './support-tiers'\nexport * from './release-flags'\n// Who runs THIS deployment, and where its notices go (AGL-2016). Ordered\n// before the four surfaces that print it, all of which used to declare their\n// own `support@aglyn.com` literal.\nexport * from './operator-identity'\nexport * from './lockdown'\nexport * from './media-quarantine'\nexport * from './media-takedown-reach'\nexport * from './upload-inspection'\nexport * from './abuse-report'\n// The other three quarters of §512 (AGL-1983): the put-back procedure that\n// answers a notice, and the strike ledger that conditions the safe harbour.\nexport * from './dmca-counter-notice'\nexport * from './repeat-infringer'\n// `addBusinessDays` briefly existed TWICE — once here in './support-tiers'\n// and once in './dmca-counter-notice' — and two `export *` made the name\n// ambiguous, TS2308'ing this barrel and every tsconfig that reads it. The\n// interleave was fixed twice in parallel: once by naming a winner here, and\n// once by deleting the second definition so './dmca-counter-notice' imports\n// this one. Only the deletion survives, so the disambiguating re-export that\n// stood on this line is gone with it — `export *` is unambiguous again.\n//\n// The concern that argued for keeping two copies is worth answering rather\n// than dropping: a later tweak to the SUPPORT SLA window must never silently\n// move the §512(g)(2)(C) put-back deadline. It cannot. This function embeds\n// no window — it is \"add N business days\", and N is the argument. The two\n// windows live in their own constants (`SUPPORT_*` there,\n// `COUNTER_NOTICE_*_BUSINESS_DAYS` in the DMCA module) and never meet. What\n// SHOULD stay shared is the day arithmetic itself: two copies of a weekend\n// rule are two chances to disagree about which day a deadline falls on.\nexport * from './org-override-reason'\nexport * from './host-tokens'\nexport * from './variables'\nexport * from './workflows'\nexport * from './datasets'\nexport * from './expand-repeatables'\nexport * from './org-roles'\nexport * from './markdown-lite'\nexport * from './notifications'\nexport * from './definition-canvas-tree'\nexport * from './ensure-canvas-root'\nexport * from './repair-canvas-nodes'\nexport * from './detect-template-placeholders'\nexport * from './guarded-version-save'\nexport * from './local-storage-budget'\nexport * from './measure-node-map'\nexport * from './resolve-named-tokens'\nexport * from './screen-route'\nexport * from './host-naming'\nexport * from './name-search'\nexport * from './name-match'\nexport * from './api-plugins'\nexport * from './plugin-api-rate-limit'\n// The same-origin gate on visitor-facing plugin writes (AGL-1880). After\n// `plugin-api-rate-limit`, whose `isMachinePluginApiPath` it reuses so the\n// two gates exempt exactly the same machine surfaces.\nexport * from './plugin-api-cross-origin'\nexport * from './actions'\nexport * from './element-animation'\nexport * from './attribution-guard'\nexport * from './node-interactions'\nexport * from './element-ui'\nexport * from './image-upload-types'\nexport * from './sanitize-svg'\nexport * from './media-folders'\nexport * from './media-metadata'\nexport * from './media-ref'\n// After `media-ref`, whose reference grammar it reads stored URLs with.\nexport * from './paid-media-source'\nexport * from './author-css'\n// The isomorphic HTML rule (AGL-1901), after the CSS one it depends on.\nexport * from './author-html'\nexport * from './dataset-models'\nexport * from './dataset-csv'\nexport * from './marketplace-provenance'\nexport * from './marketplace-update-state'\nexport * from './dataset-query'\nexport * from './plugin-manifest'\n// After `plugin-manifest`, whose revocation predicates it asks the kill\n// question with, and after `media-ref`, whose grammar decides what counts as a\n// first-party image.\nexport * from './email-starter-policy'\nexport * from './safe-json-ld'\n// Agent readiness (AGL-2716): content negotiation, the Markdown rendering of a\n// page, `/llms.txt` and the per-site OpenAPI document. All pure, all server-safe.\nexport * from './accept-negotiation'\nexport * from './agent-api-catalog'\nexport * from './agent-openapi'\nexport * from './author-html-markdown'\nexport * from './llms-txt'\nexport * from './page-markdown'\nexport * from './request-geo'\nexport * from './request-ip'\nexport * from './search-indexing'\nexport * from './seo-title'\nexport * from './sitemap'\nexport * from './visitor-consent'\nexport * from './social-image'\nexport * from './scope-tokens'\nexport * from './org-billing-doc'\nexport * from './stripe-deployment-mode'\nexport * from './deferred-image'\n"],"names":["csvCell","csvDocument","customImportTarget","customImportTargetKey"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../../../libs/aglyn/src/lib/app-utils/server.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2022 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Server-safe app-utils: every app-util EXCEPT the client-only React\n * contexts (see ./contexts). Nothing here calls `createContext` at module\n * scope, so this barrel — re-exported by `@aglyn/aglyn/server` — is safe to\n * import from tenant Server Components (AGL-405). The full `./index` barrel\n * re-adds the contexts for client consumers.\n */\nexport * from './binding-token-catalog'\nexport * from './binding-tokens'\nexport * from './breadcrumb-json-ld'\n// What a search listing holds and how long each field may be (AGL-2910):\n// the SEO editors and anything that proposes a value read one catalog.\nexport * from './seo-listing-fields'\n// `VideoObject` for the Video elements a page actually ships (AGL-2747).\n// Beside the other structured-data builders, and server-only like them: only\n// the route emits JSON-LD, and a crawler-facing block has no client caller.\nexport * from './video-object'\nexport * from './collection-delete'\nexport * from './collection-entries'\nexport * from './collection-kind'\nexport * from './collection-slug'\nexport * from './content-authors'\nexport * from './content-schema-type'\nexport * from './content-author-profile'\nexport * from './url-slug'\nexport * from './child-contract'\nexport * from './child-contract-compose'\n// The one reading of `restrictChildren`/`restrictParent`, shared by the\n// besigner's drop check and the AI plugin's node-tree validator (AGL-2905).\nexport * from './lineal-order'\n// What a node tree must satisfy before it lands on a canvas that did not\n// author it (AGL-2939): the marketplace's install sanitizer and the AI\n// plugin's node-tree validator both pass through it.\nexport * from './node-definition-sanitizer'\nexport * from './console-routes'\nexport * from './console-record-links'\n// What a stored screen-link value means, with no React attached — the\n// where-used scan reads these on the server (AGL-703).\nexport * from './screen-link-value'\n// Which entries a page's links name (AGL-3118). The tenant render reads\n// exactly those entry documents, so the walk runs on the server.\nexport * from './link-references'\nexport * from './analytics-path-key'\nexport * from './contacts'\n// A lead's or a contact's email state (AGL-3245): the last verdict on its\n// address, in words a person can act on, mirrored from the senders' lists.\nexport * from './email-state'\n// The records that sit beside a contact — companies, pipelines, deals, tasks,\n// activities, field definitions (AGL-2595). Pure like `contacts`, and beside\n// it because `ContactFacet` names its lifecycle stage and custom-value types;\n// the scope stamp every CRM creator writes lives here too.\nexport * from './crm'\n// Email templates, snippets and the merge-field resolver (AGL-2658): the\n// letter a rep keeps under a name, and the one grammar the send route and\n// the dialog fill it in by. Pure like `crm`, and beside it because a\n// template is scoped the way a task is.\nexport * from './crm-email-templates'\n// The booking door's shared vocabulary (AGL-2660): the query keys a booking\n// link carries, the record reference inside it, and the wording and due\n// date of what a booking files back on the record.\nexport * from './crm-booking'\n// Two contact documents folded into one (AGL-2625): the plan the console\n// previews and the server writes, reading the facet shape from `contacts`\n// and the company mirror from `crm`.\nexport * from './contact-merge'\n// A person's privacy erasure from one workspace (AGL-2623): the request's\n// shape and id, the marker a record carries while it waits, and the lists\n// the dialog and the docs share. Pure like `crm`; the sweep is server-side.\nexport * from './person-erasure'\n// What the CRM's reports compute from what they read — periods, weekly\n// buckets, the lifecycle funnel, pipeline totals (AGL-2604). Pure like `crm`,\n// and beside it because it reads the stage list and the deal weighting from\n// there rather than restating either.\nexport * from './crm-reports'\n// Every CRM CSV, written once (AGL-2662): the column lists and the cells\n// each section's Export button writes, and the server's whole-collection\n// export streams — one implementation, because the console app may not\n// import the plugin whose sections used to hold it.\nexport * from './crm-csv'\n// Which holder a cross-site reader sees one contact through (AGL-2630),\n// beside the files that write it: the org-level list and the server's\n// export both flatten a contact this way.\nexport * from './contact-holder'\n// What one member is owed this morning — the day's window in a named zone,\n// the task and lead bucketing, and the words the notification and the mail\n// say (AGL-2619). Pure like `crm-reports`, read by the scheduled route.\nexport * from './crm-digest'\n// A task's reminder at its own time (AGL-2659): which reminder a save\n// leaves, whether one is owed, and the words the notification and the mail\n// say. Pure like `crm-digest`, read by the hourly route and by every\n// writer of the field.\nexport * from './crm-task-reminders'\n// Email capture (AGL-2657): the address's shape and token, which of a\n// message's addresses is the correspondent, the excerpt, and the row a\n// captured message becomes. Pure like `crm-digest`; the webhook route and\n// the address route are the readers with Firestore.\nexport * from './crm-inbound'\n// A member's own addresses in a workspace (AGL-2975): the ones they have\n// confirmed count as theirs wherever the roster is asked who wrote a\n// message. Pure; the store and the confirmation link are server-side.\nexport * from './member-email-aliases'\n// The next activity a record carries (AGL-2661): what `nextTaskAtMs` IS given\n// a record's open tasks, the view clause a list filters on, the report figure.\n// Pure like `crm`; the admin library's `recomputeCrmNextTaskAt` is the writer.\nexport * from './crm-next-activity'\n// The CSV cell grammar the exports write with (AGL-2621), and the target a\n// mapped column names for a custom field — named rather than starred, because\n// an importer built on this file exports the shared ceilings under its own\n// names.\nexport {\n csvCell,\n csvDocument,\n customImportTarget,\n customImportTargetKey,\n} from './csv-import'\nexport type {\n ImportChunkResult,\n ImportDroppedValue,\n ImportSkippedRow,\n} from './csv-import'\n// What a VALUE under a custom contact field may be, and the coercion every\n// door applies to one (AGL-2601): a mapped form field, an API `custom` body,\n// and the carry-over that keeps a mapping across a publish. Pure like `crm`.\nexport * from './contact-custom-fields'\n// The consent JOIN (`docs/specs/email-overhaul.md` §3f). Pure, and it composes\n// `contacts` for the normalizer, so it sits directly beside it. No Node\n// builtin, which is what keeps it out of the `/server`-only group `person-key`\n// belongs to.\nexport * from './consent-groups'\nexport * from './marketing-consent'\n// The ENROLLMENT-time half of the same question, beside its reader for the\n// same reason: `marketing-consent` decides whether a recorded basis lets us\n// mail somebody, and this decides what basis putting them on a list may\n// record. Two enrollment surfaces import it — the Inbox assignment route and\n// the Emails console's audience card — and neither could import the other.\nexport * from './list-assignment-policy'\n// Reading the FILE a merchant arrives with (`docs/specs/email-competitive-gaps.md`\n// G5/P4), directly after the policy it hands its addresses to: parsing and\n// mechanical screening only, so that an import asks the enrollment question\n// through the same module the one-address add path asks it through rather\n// than answering it a second way.\nexport * from './list-import'\n// The dynamic-list rule (§3b/§3c), beside it for the same reasons: pure, and\n// it composes `contacts` for the segment vocabulary rather than restating it.\nexport * from './dynamic-list-rule'\n// The subscribable streams a recipient can leave one at a time\n// (`docs/specs/email-competitive-gaps.md` §1f). Pure, and read from all three\n// sides of the feature: the composer picks one, the send path signs it into\n// the unsubscribe link, and the unauthenticated preference page renders the\n// catalog. No Node builtin, so it stays out of the `/server`-only group.\nexport * from './email-topics'\nexport * from './compose-layout-nodes'\n// Layout properties applied through the chain (AGL-2893).\nexport * from './compose-layout-props'\n// A screen's per-page restyling of its layout's elements (AGL-3286).\nexport * from './layout-style-overrides'\nexport * from './document-landmark'\nexport * from './functions'\nexport * from './compose-reusable-components'\nexport * from './compress'\nexport * from './merge-node-sx'\nexport * from './palette-sx'\nexport * from './scheme-sx'\n// An element pinned to one color scheme (AGL-3284).\nexport * from './element-color-scheme'\nexport * from './create-resource-uid'\nexport * from './decompress'\nexport * from './stored-nodes'\nexport * from './strip-undefined'\nexport * from './organizations'\nexport * from './org-permissions'\n// The AI verdict on either membership axis (AGL-2927). After both modules it\n// composes: the org catalog for org-wide members, the host role for site\n// collaborators.\nexport * from './host-permissions'\nexport * from './password-policy'\nexport * from './idp-profile'\nexport * from './onboarding-deep-link'\n// Where an account came from (AGL-1731). Beside the plan intent because\n// they are the same hop — the marketing CTA's query string — and both are\n// remembered on `users/{uid}` across the verification wall.\nexport * from './campaign-attribution'\n// The edge between a campaign and the forms, screens and contacts a push is\n// coordinated across. Beside the attribution above because the two answer\n// opposite questions about the same word: attribution records where somebody\n// CAME from, this records what a merchant DECLARED belongs together.\nexport * from './campaign-membership'\nexport * from './deployment-shape'\n// Which browser origins may complete a signed direct-to-GCS upload (AGL-1452).\n// GCS matches the origin list EXACTLY, so every serving console name needs its\n// own entry — the rule nobody could be expected to remember at attach time.\nexport * from './upload-cors'\n// The docs-help subset the first-party plugin consoles read (AGL-2213) — the\n// console's own registry lives in apps/console/constants and a lib cannot\n// import an app.\nexport * from './docs-help'\nexport * from './platform-brand'\nexport * from './plan-entitlements'\n// The free plan's bandwidth hard cap (AGL-1967/2070/2155). After\n// `plan-entitlements`, which owns the predicate it keys off.\nexport * from './bandwidth-cap'\nexport * from './form-abuse-ceiling'\nexport * from './forms'\n// What a form's DESIGN must still satisfy for its submissions to arrive.\n// After `forms`, whose field walk it reads the drawn fields with.\nexport * from './form-contract'\nexport * from './visitor-record-ceiling'\nexport * from './health-report'\n// Did a webhook delivery actually DO anything (AGL-1954)? After\n// `health-report`, whose billing verdict consumes the counts this produces.\nexport * from './webhook-delivery'\nexport * from './support-tiers'\nexport * from './release-flags'\n// Who runs THIS deployment, and where its notices go (AGL-2016). Ordered\n// before the four surfaces that print it, all of which used to declare their\n// own `support@aglyn.com` literal.\nexport * from './operator-identity'\nexport * from './lockdown'\nexport * from './media-quarantine'\nexport * from './media-takedown-reach'\nexport * from './upload-inspection'\nexport * from './abuse-report'\n// The other three quarters of §512 (AGL-1983): the put-back procedure that\n// answers a notice, and the strike ledger that conditions the safe harbour.\nexport * from './dmca-counter-notice'\nexport * from './repeat-infringer'\n// `addBusinessDays` briefly existed TWICE — once here in './support-tiers'\n// and once in './dmca-counter-notice' — and two `export *` made the name\n// ambiguous, TS2308'ing this barrel and every tsconfig that reads it. The\n// interleave was fixed twice in parallel: once by naming a winner here, and\n// once by deleting the second definition so './dmca-counter-notice' imports\n// this one. Only the deletion survives, so the disambiguating re-export that\n// stood on this line is gone with it — `export *` is unambiguous again.\n//\n// The concern that argued for keeping two copies is worth answering rather\n// than dropping: a later tweak to the SUPPORT SLA window must never silently\n// move the §512(g)(2)(C) put-back deadline. It cannot. This function embeds\n// no window — it is \"add N business days\", and N is the argument. The two\n// windows live in their own constants (`SUPPORT_*` there,\n// `COUNTER_NOTICE_*_BUSINESS_DAYS` in the DMCA module) and never meet. What\n// SHOULD stay shared is the day arithmetic itself: two copies of a weekend\n// rule are two chances to disagree about which day a deadline falls on.\nexport * from './org-override-reason'\nexport * from './host-tokens'\nexport * from './variables'\nexport * from './workflows'\nexport * from './datasets'\nexport * from './expand-repeatables'\nexport * from './org-roles'\nexport * from './markdown-lite'\nexport * from './notifications'\nexport * from './definition-canvas-tree'\nexport * from './ensure-canvas-root'\nexport * from './repair-canvas-nodes'\nexport * from './detect-template-placeholders'\nexport * from './guarded-version-save'\nexport * from './local-storage-budget'\nexport * from './measure-node-map'\nexport * from './resolve-named-tokens'\nexport * from './screen-route'\nexport * from './host-naming'\nexport * from './name-search'\nexport * from './name-match'\nexport * from './api-plugins'\nexport * from './plugin-api-rate-limit'\n// The same-origin gate on visitor-facing plugin writes (AGL-1880). After\n// `plugin-api-rate-limit`, whose `isMachinePluginApiPath` it reuses so the\n// two gates exempt exactly the same machine surfaces.\nexport * from './plugin-api-cross-origin'\nexport * from './actions'\nexport * from './element-animation'\nexport * from './attribution-guard'\nexport * from './node-interactions'\nexport * from './element-ui'\nexport * from './image-upload-types'\nexport * from './sanitize-svg'\nexport * from './media-folders'\nexport * from './media-metadata'\nexport * from './media-ref'\n// After `media-ref`, whose reference grammar it reads stored URLs with.\nexport * from './paid-media-source'\nexport * from './author-css'\n// The isomorphic HTML rule (AGL-1901), after the CSS one it depends on.\nexport * from './author-html'\nexport * from './dataset-models'\nexport * from './dataset-csv'\nexport * from './marketplace-provenance'\nexport * from './marketplace-update-state'\nexport * from './dataset-query'\nexport * from './plugin-manifest'\n// After `plugin-manifest`, whose revocation predicates it asks the kill\n// question with, and after `media-ref`, whose grammar decides what counts as a\n// first-party image.\nexport * from './email-starter-policy'\nexport * from './safe-json-ld'\n// Agent readiness (AGL-2716): content negotiation, the Markdown rendering of a\n// page, `/llms.txt` and the per-site OpenAPI document. All pure, all server-safe.\nexport * from './accept-negotiation'\nexport * from './agent-api-catalog'\nexport * from './agent-openapi'\nexport * from './author-html-markdown'\nexport * from './llms-txt'\nexport * from './page-markdown'\nexport * from './request-geo'\nexport * from './request-ip'\nexport * from './search-indexing'\nexport * from './seo-title'\nexport * from './sitemap'\nexport * from './visitor-consent'\nexport * from './social-image'\nexport * from './scope-tokens'\nexport * from './org-billing-doc'\nexport * from './stripe-deployment-mode'\nexport * from './deferred-image'\n"],"names":["csvCell","csvDocument","customImportTarget","customImportTargetKey"],"mappings":"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"}
@@ -47,6 +47,11 @@ export declare class AglynNode<P = JSX.AnyProps> implements NodeSchema<P> {
47
47
  * field survives in memory but not across a save.
48
48
  */
49
49
  attrOverrides?: Record<string, Record<string, unknown>>;
50
+ /**
51
+ * A screen's layout style overrides, on the canvas root only (AGL-3286) —
52
+ * see `NodeSchema`. Same three touch points as the fields around it.
53
+ */
54
+ layoutStyleOverrides?: Record<string, Record<string, Record<string, unknown>>>;
50
55
  /**
51
56
  * Interactions authored on this element — see `NodeSchema`.
52
57
  * Third field under the same three-touch-point rule as the two above:
@@ -116,6 +116,12 @@ export class AglynNode {
116
116
  if (attrOverrides && Object.keys(attrOverrides).length > 0) {
117
117
  json['attrOverrides'] = attrOverrides;
118
118
  }
119
+ // Layout style overrides (AGL-3286): same treatment. Only the screen
120
+ // editor's root ever carries them, and its save lifts them out of the map.
121
+ const layoutStyleOverrides = stripUndefinedDeep(toJS(this.layoutStyleOverrides));
122
+ if (layoutStyleOverrides && Object.keys(layoutStyleOverrides).length > 0) {
123
+ json['layoutStyleOverrides'] = layoutStyleOverrides;
124
+ }
119
125
  // Element interactions: emitted like the bags above, absent
120
126
  // when empty. This is the field that makes them versioned with the
121
127
  // document at all — an interaction the canvas holds but this method
@@ -146,6 +152,7 @@ export class AglynNode {
146
152
  ] : _extends({}, schema.sx);
147
153
  this.styleOverrides = schema.styleOverrides ? _extends({}, schema.styleOverrides) : undefined;
148
154
  this.attrOverrides = schema.attrOverrides ? _extends({}, schema.attrOverrides) : undefined;
155
+ this.layoutStyleOverrides = schema.layoutStyleOverrides ? _extends({}, schema.layoutStyleOverrides) : undefined;
149
156
  this.interactions = Array.isArray(schema.interactions) ? [
150
157
  ...schema.interactions
151
158
  ] : undefined;