@aglyn/aglyn 1.0.0-beta.213 → 1.0.0-beta.215
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.
- package/package.json +11 -11
- package/src/lib/app-utils/docs-help.generated.d.ts +2 -2
- package/src/lib/app-utils/docs-help.generated.js +2 -0
- package/src/lib/app-utils/docs-help.generated.js.map +1 -1
- package/src/lib/app-utils/docs-index.generated.js +16 -9
- package/src/lib/app-utils/docs-index.generated.js.map +1 -1
- package/src/lib/app-utils/enabled-plugins-context.d.ts +8 -4
- package/src/lib/app-utils/enabled-plugins-context.js +9 -4
- package/src/lib/app-utils/enabled-plugins-context.js.map +1 -1
- package/src/lib/app-utils/host-naming.d.ts +2 -29
- package/src/lib/app-utils/host-naming.js +5 -28
- package/src/lib/app-utils/host-naming.js.map +1 -1
- package/src/lib/app-utils/media-ref.js +1 -1
- package/src/lib/app-utils/media-ref.js.map +1 -1
- package/src/lib/app-utils/notifications.d.ts +7 -0
- package/src/lib/app-utils/notifications.js.map +1 -1
- package/src/lib/app-utils/plan-entitlements.js +14 -8
- package/src/lib/app-utils/plan-entitlements.js.map +1 -1
- package/src/lib/app-utils/platform-brand.d.ts +4 -0
- package/src/lib/app-utils/platform-brand.js +2 -0
- package/src/lib/app-utils/platform-brand.js.map +1 -1
- package/src/lib/app-utils/plugin-bundle-checks.js +193 -15
- package/src/lib/app-utils/plugin-bundle-checks.js.map +1 -1
- package/src/lib/app-utils/realm-elements-context.d.ts +17 -0
- package/src/lib/app-utils/realm-elements-context.js +35 -0
- package/src/lib/app-utils/realm-elements-context.js.map +1 -0
- package/src/lib/app-utils/tenant-apex.d.ts +45 -0
- package/src/lib/app-utils/tenant-apex.js +48 -0
- package/src/lib/app-utils/tenant-apex.js.map +1 -0
- package/src/lib/app-utils/wire-nodes.d.ts +64 -0
- package/src/lib/app-utils/wire-nodes.js +112 -0
- package/src/lib/app-utils/wire-nodes.js.map +1 -0
- package/src/lib/foundation/definitions/org-billing.types.d.ts +12 -0
- package/src/lib/foundation/definitions/org-billing.types.js.map +1 -1
- package/src/lib/plugin-manager/plugin-contributions.d.ts +8 -3
- package/src/lib/plugin-manager/plugin-contributions.js +5 -3
- package/src/lib/plugin-manager/plugin-contributions.js.map +1 -1
- package/src/lib/plugin-manager/realm-plugins.d.ts +70 -0
- package/src/lib/plugin-manager/realm-plugins.js +143 -29
- package/src/lib/plugin-manager/realm-plugins.js.map +1 -1
|
@@ -0,0 +1,35 @@
|
|
|
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 { createContext } from "react";
|
|
17
|
+
/**
|
|
18
|
+
* How a namespaced element waits for the realm bundle that registers it
|
|
19
|
+
* (AGL-3390).
|
|
20
|
+
*
|
|
21
|
+
* A signed marketplace plugin's elements render on the server, and the
|
|
22
|
+
* browser has to register the same component before it can hydrate that
|
|
23
|
+
* HTML. The host app answers, for a component id, the load that registers
|
|
24
|
+
* it, or `undefined` when no load on this page will. The renderer suspends a
|
|
25
|
+
* namespaced element on that load inside the element's own Suspense
|
|
26
|
+
* boundary, so React keeps the server's HTML in place until the bundle has
|
|
27
|
+
* run, and the rest of the page hydrates without waiting.
|
|
28
|
+
*
|
|
29
|
+
* `undefined` as a whole means the surface loads no realm bundles in the
|
|
30
|
+
* render path (the Besigner loads them before its canvas mounts), and no
|
|
31
|
+
* element waits.
|
|
32
|
+
*/ export const RealmElementsContext = createContext(undefined);
|
|
33
|
+
RealmElementsContext.displayName = 'RealmElementsContext';
|
|
34
|
+
|
|
35
|
+
//# sourceMappingURL=realm-elements-context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../libs/aglyn/src/lib/app-utils/realm-elements-context.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 */\nimport { createContext } from 'react'\n\n/**\n * How a namespaced element waits for the realm bundle that registers it\n * (AGL-3390).\n *\n * A signed marketplace plugin's elements render on the server, and the\n * browser has to register the same component before it can hydrate that\n * HTML. The host app answers, for a component id, the load that registers\n * it, or `undefined` when no load on this page will. The renderer suspends a\n * namespaced element on that load inside the element's own Suspense\n * boundary, so React keeps the server's HTML in place until the bundle has\n * run, and the rest of the page hydrates without waiting.\n *\n * `undefined` as a whole means the surface loads no realm bundles in the\n * render path (the Besigner loads them before its canvas mounts), and no\n * element waits.\n */\nexport const RealmElementsContext = createContext<\n ((componentId: string) => Promise<void> | undefined) | undefined\n>(undefined)\nRealmElementsContext.displayName = 'RealmElementsContext'\n"],"names":["createContext","RealmElementsContext","undefined","displayName"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GACD,SAASA,aAAa,QAAQ,QAAO;AAErC;;;;;;;;;;;;;;;CAeC,GACD,OAAO,MAAMC,uBAAuBD,cAElCE,WAAU;AACZD,qBAAqBE,WAAW,GAAG"}
|
|
@@ -0,0 +1,45 @@
|
|
|
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
|
+
* The apex tenant sites are served from. Console lives on `app.aglyn.com`.
|
|
19
|
+
*
|
|
20
|
+
* CONFIGURABLE, not a literal (AGL-2121). AGL-2022 moved the console's
|
|
21
|
+
* *display* links onto `NEXT_PUBLIC_TENANT_DOMAIN` and shipped a green spec
|
|
22
|
+
* for it; this constant — which every OTHER consumer reads — stayed a bare
|
|
23
|
+
* `'aglyn.app'`. So a self-hoster who set the variable got correct "View live"
|
|
24
|
+
* links in their own console while the software went on emitting our apex
|
|
25
|
+
* everywhere that actually reaches the public: `<link rel="canonical">`,
|
|
26
|
+
* `/api/sitemap`, `/api/robots`, `/api/collections-rss` item links,
|
|
27
|
+
* `/api/manifest`, `og:image`, and the origin inbox-bound `<img src>` resolves
|
|
28
|
+
* against. Their customers' sites told Google, every feed reader and every
|
|
29
|
+
* inbox that they lived at a name the operator does not control and we do not
|
|
30
|
+
* serve for them.
|
|
31
|
+
*
|
|
32
|
+
* Same variable and same default as `tenant-links.ts` — one value, one name
|
|
33
|
+
* (AGL-733). Dot notation is load-bearing: this module reaches client bundles,
|
|
34
|
+
* and Next inlines `NEXT_PUBLIC_*` by substituting `process.env.NAME`
|
|
35
|
+
* textually; the bracket form is never substituted and would read `undefined`
|
|
36
|
+
* in the browser. Trimmed so a half-finished `.env` line reads as absent
|
|
37
|
+
* rather than as a whitespace apex.
|
|
38
|
+
*
|
|
39
|
+
* The asymmetry with `operator-identity.ts` — which refuses to default at all
|
|
40
|
+
* — is deliberate. A wrong apex is visible to the operator on the first click
|
|
41
|
+
* in their own console, so a default they can see and correct is a default. A
|
|
42
|
+
* wrong contact address fails silently and off-site, which is why that one
|
|
43
|
+
* refuses to guess.
|
|
44
|
+
*/
|
|
45
|
+
export declare const TENANT_APEX: string;
|
|
@@ -0,0 +1,48 @@
|
|
|
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
|
+
*/ // A leaf of its own (AGL-3401): `media-ref.ts` is on every published page and
|
|
17
|
+
// needs this one constant, and reaching it through `host-naming.ts` put the
|
|
18
|
+
// subdomain policy and the phishing screen's brand list on every page too.
|
|
19
|
+
/**
|
|
20
|
+
* The apex tenant sites are served from. Console lives on `app.aglyn.com`.
|
|
21
|
+
*
|
|
22
|
+
* CONFIGURABLE, not a literal (AGL-2121). AGL-2022 moved the console's
|
|
23
|
+
* *display* links onto `NEXT_PUBLIC_TENANT_DOMAIN` and shipped a green spec
|
|
24
|
+
* for it; this constant — which every OTHER consumer reads — stayed a bare
|
|
25
|
+
* `'aglyn.app'`. So a self-hoster who set the variable got correct "View live"
|
|
26
|
+
* links in their own console while the software went on emitting our apex
|
|
27
|
+
* everywhere that actually reaches the public: `<link rel="canonical">`,
|
|
28
|
+
* `/api/sitemap`, `/api/robots`, `/api/collections-rss` item links,
|
|
29
|
+
* `/api/manifest`, `og:image`, and the origin inbox-bound `<img src>` resolves
|
|
30
|
+
* against. Their customers' sites told Google, every feed reader and every
|
|
31
|
+
* inbox that they lived at a name the operator does not control and we do not
|
|
32
|
+
* serve for them.
|
|
33
|
+
*
|
|
34
|
+
* Same variable and same default as `tenant-links.ts` — one value, one name
|
|
35
|
+
* (AGL-733). Dot notation is load-bearing: this module reaches client bundles,
|
|
36
|
+
* and Next inlines `NEXT_PUBLIC_*` by substituting `process.env.NAME`
|
|
37
|
+
* textually; the bracket form is never substituted and would read `undefined`
|
|
38
|
+
* in the browser. Trimmed so a half-finished `.env` line reads as absent
|
|
39
|
+
* rather than as a whitespace apex.
|
|
40
|
+
*
|
|
41
|
+
* The asymmetry with `operator-identity.ts` — which refuses to default at all
|
|
42
|
+
* — is deliberate. A wrong apex is visible to the operator on the first click
|
|
43
|
+
* in their own console, so a default they can see and correct is a default. A
|
|
44
|
+
* wrong contact address fails silently and off-site, which is why that one
|
|
45
|
+
* refuses to guess.
|
|
46
|
+
*/ export const TENANT_APEX = (process.env.NEXT_PUBLIC_TENANT_DOMAIN || '').trim() || 'aglyn.app';
|
|
47
|
+
|
|
48
|
+
//# sourceMappingURL=tenant-apex.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../libs/aglyn/src/lib/app-utils/tenant-apex.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// A leaf of its own (AGL-3401): `media-ref.ts` is on every published page and\n// needs this one constant, and reaching it through `host-naming.ts` put the\n// subdomain policy and the phishing screen's brand list on every page too.\n\n/**\n * The apex tenant sites are served from. Console lives on `app.aglyn.com`.\n *\n * CONFIGURABLE, not a literal (AGL-2121). AGL-2022 moved the console's\n * *display* links onto `NEXT_PUBLIC_TENANT_DOMAIN` and shipped a green spec\n * for it; this constant — which every OTHER consumer reads — stayed a bare\n * `'aglyn.app'`. So a self-hoster who set the variable got correct \"View live\"\n * links in their own console while the software went on emitting our apex\n * everywhere that actually reaches the public: `<link rel=\"canonical\">`,\n * `/api/sitemap`, `/api/robots`, `/api/collections-rss` item links,\n * `/api/manifest`, `og:image`, and the origin inbox-bound `<img src>` resolves\n * against. Their customers' sites told Google, every feed reader and every\n * inbox that they lived at a name the operator does not control and we do not\n * serve for them.\n *\n * Same variable and same default as `tenant-links.ts` — one value, one name\n * (AGL-733). Dot notation is load-bearing: this module reaches client bundles,\n * and Next inlines `NEXT_PUBLIC_*` by substituting `process.env.NAME`\n * textually; the bracket form is never substituted and would read `undefined`\n * in the browser. Trimmed so a half-finished `.env` line reads as absent\n * rather than as a whitespace apex.\n *\n * The asymmetry with `operator-identity.ts` — which refuses to default at all\n * — is deliberate. A wrong apex is visible to the operator on the first click\n * in their own console, so a default they can see and correct is a default. A\n * wrong contact address fails silently and off-site, which is why that one\n * refuses to guess.\n */\nexport const TENANT_APEX =\n (process.env.NEXT_PUBLIC_TENANT_DOMAIN || '').trim() || 'aglyn.app'\n"],"names":["TENANT_APEX","process","env","NEXT_PUBLIC_TENANT_DOMAIN","trim"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAED,8EAA8E;AAC9E,4EAA4E;AAC5E,2EAA2E;AAE3E;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2BC,GACD,OAAO,MAAMA,cACX,AAACC,CAAAA,QAAQC,GAAG,CAACC,yBAAyB,IAAI,EAAC,EAAGC,IAAI,MAAM,YAAW"}
|
|
@@ -0,0 +1,64 @@
|
|
|
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
|
+
* A published page's node map as it crosses from the server into the
|
|
19
|
+
* browser, without the two fields the map already states (AGL-3401).
|
|
20
|
+
*
|
|
21
|
+
* The map rides in the page's flight payload, inside its HTML, and on
|
|
22
|
+
* aglyn.com it was 242 KB of it. Every node repeats its own key as `$id` and
|
|
23
|
+
* its parent's key as `parentId`, though the key IS the id and the parent's
|
|
24
|
+
* `nodes` list already says whose child it is. Both are random ids, which is
|
|
25
|
+
* the part of the map compression does least with: dropping them took the
|
|
26
|
+
* map from 34.5 KB to about 28.5 KB gzipped on that page.
|
|
27
|
+
*
|
|
28
|
+
* `packNodesForWire` drops a field only when `unpackWireNodes` will put back
|
|
29
|
+
* the same value — an `$id` that differs from its key, or a `parentId` no
|
|
30
|
+
* single parent's `nodes` list agrees with, is left in place — so a node that
|
|
31
|
+
* carries both comes back exactly as it left, well-formed map or not. (One
|
|
32
|
+
* that carried neither comes back with them.) Unpacking is idempotent, which is
|
|
33
|
+
* what lets a full map (a withheld panel's patch from `/api/screen/nodes`, a
|
|
34
|
+
* members-only tree) be merged over a packed one and unpacked together.
|
|
35
|
+
*
|
|
36
|
+
* Banner-free and dependency-free: the tenant's server page packs and its
|
|
37
|
+
* client root unpacks, so it must be importable from both.
|
|
38
|
+
*/
|
|
39
|
+
/** A node as the map carries it: an object, keyed by its id. */
|
|
40
|
+
type WireNode = Record<string, unknown> & {
|
|
41
|
+
$id?: unknown;
|
|
42
|
+
parentId?: unknown;
|
|
43
|
+
nodes?: unknown;
|
|
44
|
+
};
|
|
45
|
+
/** A node map, packed or not. */
|
|
46
|
+
export type WireNodeMap<N = WireNode> = Record<string, N | null | undefined>;
|
|
47
|
+
/**
|
|
48
|
+
* The map without each `$id` that equals its key and each `parentId` its
|
|
49
|
+
* parent's `nodes` list states. A new map of new node objects; the argument
|
|
50
|
+
* is never mutated, because the server's is the cached loader's.
|
|
51
|
+
*
|
|
52
|
+
* Typed as the map it is handed rather than as a looser one: the packed form
|
|
53
|
+
* has one reader, `unpackWireNodes`, and the prop it travels in is read
|
|
54
|
+
* nowhere else, so a second type would buy a cast at both ends.
|
|
55
|
+
*/
|
|
56
|
+
export declare function packNodesForWire<M extends WireNodeMap | null | undefined>(nodes: M): M;
|
|
57
|
+
/**
|
|
58
|
+
* The map with every node's `$id` and `parentId` back, from its key and its
|
|
59
|
+
* parent's `nodes` list. A node that already carries either keeps its own,
|
|
60
|
+
* so an unpacked map comes back equal and a packed one merged with an
|
|
61
|
+
* unpacked patch comes back whole.
|
|
62
|
+
*/
|
|
63
|
+
export declare function unpackWireNodes<M extends WireNodeMap | null | undefined>(nodes: M): M;
|
|
64
|
+
export {};
|
|
@@ -0,0 +1,112 @@
|
|
|
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
|
+
* A published page's node map as it crosses from the server into the
|
|
18
|
+
* browser, without the two fields the map already states (AGL-3401).
|
|
19
|
+
*
|
|
20
|
+
* The map rides in the page's flight payload, inside its HTML, and on
|
|
21
|
+
* aglyn.com it was 242 KB of it. Every node repeats its own key as `$id` and
|
|
22
|
+
* its parent's key as `parentId`, though the key IS the id and the parent's
|
|
23
|
+
* `nodes` list already says whose child it is. Both are random ids, which is
|
|
24
|
+
* the part of the map compression does least with: dropping them took the
|
|
25
|
+
* map from 34.5 KB to about 28.5 KB gzipped on that page.
|
|
26
|
+
*
|
|
27
|
+
* `packNodesForWire` drops a field only when `unpackWireNodes` will put back
|
|
28
|
+
* the same value — an `$id` that differs from its key, or a `parentId` no
|
|
29
|
+
* single parent's `nodes` list agrees with, is left in place — so a node that
|
|
30
|
+
* carries both comes back exactly as it left, well-formed map or not. (One
|
|
31
|
+
* that carried neither comes back with them.) Unpacking is idempotent, which is
|
|
32
|
+
* what lets a full map (a withheld panel's patch from `/api/screen/nodes`, a
|
|
33
|
+
* members-only tree) be merged over a packed one and unpacked together.
|
|
34
|
+
*
|
|
35
|
+
* Banner-free and dependency-free: the tenant's server page packs and its
|
|
36
|
+
* client root unpacks, so it must be importable from both.
|
|
37
|
+
*/ /** A node as the map carries it: an object, keyed by its id. */ import { _ as _extends } from "@swc/helpers/_/_extends";
|
|
38
|
+
import { _ as _object_without_properties_loose } from "@swc/helpers/_/_object_without_properties_loose";
|
|
39
|
+
/** Each child id to the key of the node whose `nodes` list names it. */ function parentsOf(nodes) {
|
|
40
|
+
const parents = new Map();
|
|
41
|
+
const claimed = new Set();
|
|
42
|
+
for (const [key, node] of Object.entries(nodes)){
|
|
43
|
+
const children = node == null ? void 0 : node.nodes;
|
|
44
|
+
if (!Array.isArray(children)) continue;
|
|
45
|
+
for (const child of children){
|
|
46
|
+
if (typeof child !== 'string') continue;
|
|
47
|
+
// A child two parents list has no single answer, so neither may stand
|
|
48
|
+
// in for the `parentId` it stores.
|
|
49
|
+
if (claimed.has(child)) parents.delete(child);
|
|
50
|
+
else parents.set(child, key);
|
|
51
|
+
claimed.add(child);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return parents;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* The map without each `$id` that equals its key and each `parentId` its
|
|
58
|
+
* parent's `nodes` list states. A new map of new node objects; the argument
|
|
59
|
+
* is never mutated, because the server's is the cached loader's.
|
|
60
|
+
*
|
|
61
|
+
* Typed as the map it is handed rather than as a looser one: the packed form
|
|
62
|
+
* has one reader, `unpackWireNodes`, and the prop it travels in is read
|
|
63
|
+
* nowhere else, so a second type would buy a cast at both ends.
|
|
64
|
+
*/ export function packNodesForWire(nodes) {
|
|
65
|
+
if (!nodes) return nodes;
|
|
66
|
+
const parents = parentsOf(nodes);
|
|
67
|
+
const packed = {};
|
|
68
|
+
for (const [key, node] of Object.entries(nodes)){
|
|
69
|
+
if (!node || typeof node !== 'object') {
|
|
70
|
+
packed[key] = node;
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
const { $id, parentId } = node, rest = _object_without_properties_loose(node, [
|
|
74
|
+
"$id",
|
|
75
|
+
"parentId"
|
|
76
|
+
]);
|
|
77
|
+
const out = rest;
|
|
78
|
+
if ($id !== key) out.$id = $id;
|
|
79
|
+
if (parentId !== undefined && parentId !== parents.get(key)) {
|
|
80
|
+
out.parentId = parentId;
|
|
81
|
+
}
|
|
82
|
+
packed[key] = out;
|
|
83
|
+
}
|
|
84
|
+
return packed;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* The map with every node's `$id` and `parentId` back, from its key and its
|
|
88
|
+
* parent's `nodes` list. A node that already carries either keeps its own,
|
|
89
|
+
* so an unpacked map comes back equal and a packed one merged with an
|
|
90
|
+
* unpacked patch comes back whole.
|
|
91
|
+
*/ export function unpackWireNodes(nodes) {
|
|
92
|
+
if (!nodes) return nodes;
|
|
93
|
+
const parents = parentsOf(nodes);
|
|
94
|
+
const unpacked = {};
|
|
95
|
+
for (const [key, node] of Object.entries(nodes)){
|
|
96
|
+
if (!node || typeof node !== 'object') {
|
|
97
|
+
unpacked[key] = node;
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
const parent = parents.get(key);
|
|
101
|
+
const needsId = !('$id' in node);
|
|
102
|
+
const needsParent = !('parentId' in node) && parent !== undefined;
|
|
103
|
+
unpacked[key] = needsId || needsParent ? _extends({}, needsId ? {
|
|
104
|
+
$id: key
|
|
105
|
+
} : {}, node, needsParent ? {
|
|
106
|
+
parentId: parent
|
|
107
|
+
} : {}) : node;
|
|
108
|
+
}
|
|
109
|
+
return unpacked;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
//# sourceMappingURL=wire-nodes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../libs/aglyn/src/lib/app-utils/wire-nodes.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 * A published page's node map as it crosses from the server into the\n * browser, without the two fields the map already states (AGL-3401).\n *\n * The map rides in the page's flight payload, inside its HTML, and on\n * aglyn.com it was 242 KB of it. Every node repeats its own key as `$id` and\n * its parent's key as `parentId`, though the key IS the id and the parent's\n * `nodes` list already says whose child it is. Both are random ids, which is\n * the part of the map compression does least with: dropping them took the\n * map from 34.5 KB to about 28.5 KB gzipped on that page.\n *\n * `packNodesForWire` drops a field only when `unpackWireNodes` will put back\n * the same value — an `$id` that differs from its key, or a `parentId` no\n * single parent's `nodes` list agrees with, is left in place — so a node that\n * carries both comes back exactly as it left, well-formed map or not. (One\n * that carried neither comes back with them.) Unpacking is idempotent, which is\n * what lets a full map (a withheld panel's patch from `/api/screen/nodes`, a\n * members-only tree) be merged over a packed one and unpacked together.\n *\n * Banner-free and dependency-free: the tenant's server page packs and its\n * client root unpacks, so it must be importable from both.\n */\n\n/** A node as the map carries it: an object, keyed by its id. */\ntype WireNode = Record<string, unknown> & {\n $id?: unknown\n parentId?: unknown\n nodes?: unknown\n}\n\n/** A node map, packed or not. */\nexport type WireNodeMap<N = WireNode> = Record<string, N | null | undefined>\n\n/** Each child id to the key of the node whose `nodes` list names it. */\nfunction parentsOf(nodes: WireNodeMap): Map<string, string> {\n const parents = new Map<string, string>()\n const claimed = new Set<string>()\n for (const [key, node] of Object.entries(nodes)) {\n const children = node?.nodes\n if (!Array.isArray(children)) continue\n for (const child of children) {\n if (typeof child !== 'string') continue\n // A child two parents list has no single answer, so neither may stand\n // in for the `parentId` it stores.\n if (claimed.has(child)) parents.delete(child)\n else parents.set(child, key)\n claimed.add(child)\n }\n }\n return parents\n}\n\n/**\n * The map without each `$id` that equals its key and each `parentId` its\n * parent's `nodes` list states. A new map of new node objects; the argument\n * is never mutated, because the server's is the cached loader's.\n *\n * Typed as the map it is handed rather than as a looser one: the packed form\n * has one reader, `unpackWireNodes`, and the prop it travels in is read\n * nowhere else, so a second type would buy a cast at both ends.\n */\nexport function packNodesForWire<M extends WireNodeMap | null | undefined>(\n nodes: M,\n): M {\n if (!nodes) return nodes\n const parents = parentsOf(nodes)\n const packed: WireNodeMap = {}\n for (const [key, node] of Object.entries(nodes)) {\n if (!node || typeof node !== 'object') {\n packed[key] = node\n continue\n }\n const { $id, parentId, ...rest } = node\n const out: WireNode = rest\n if ($id !== key) out.$id = $id\n if (parentId !== undefined && parentId !== parents.get(key)) {\n out.parentId = parentId\n }\n packed[key] = out\n }\n return packed as M\n}\n\n/**\n * The map with every node's `$id` and `parentId` back, from its key and its\n * parent's `nodes` list. A node that already carries either keeps its own,\n * so an unpacked map comes back equal and a packed one merged with an\n * unpacked patch comes back whole.\n */\nexport function unpackWireNodes<M extends WireNodeMap | null | undefined>(\n nodes: M,\n): M {\n if (!nodes) return nodes\n const parents = parentsOf(nodes)\n const unpacked: WireNodeMap = {}\n for (const [key, node] of Object.entries(nodes)) {\n if (!node || typeof node !== 'object') {\n unpacked[key] = node\n continue\n }\n const parent = parents.get(key)\n const needsId = !('$id' in node)\n const needsParent = !('parentId' in node) && parent !== undefined\n unpacked[key] =\n needsId || needsParent\n ? {\n ...(needsId ? { $id: key } : {}),\n ...node,\n ...(needsParent ? { parentId: parent } : {}),\n }\n : node\n }\n return unpacked as M\n}\n"],"names":["parentsOf","nodes","parents","Map","claimed","Set","key","node","Object","entries","children","Array","isArray","child","has","delete","set","add","packNodesForWire","packed","$id","parentId","rest","out","undefined","get","unpackWireNodes","unpacked","parent","needsId","needsParent"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAED;;;;;;;;;;;;;;;;;;;;;CAqBC,GAED,8DAA8D;;AAU9D,sEAAsE,GACtE,SAASA,UAAUC,KAAkB;IACnC,MAAMC,UAAU,IAAIC;IACpB,MAAMC,UAAU,IAAIC;IACpB,KAAK,MAAM,CAACC,KAAKC,KAAK,IAAIC,OAAOC,OAAO,CAACR,OAAQ;QAC/C,MAAMS,WAAWH,wBAAAA,KAAMN,KAAK;QAC5B,IAAI,CAACU,MAAMC,OAAO,CAACF,WAAW;QAC9B,KAAK,MAAMG,SAASH,SAAU;YAC5B,IAAI,OAAOG,UAAU,UAAU;YAC/B,sEAAsE;YACtE,mCAAmC;YACnC,IAAIT,QAAQU,GAAG,CAACD,QAAQX,QAAQa,MAAM,CAACF;iBAClCX,QAAQc,GAAG,CAACH,OAAOP;YACxBF,QAAQa,GAAG,CAACJ;QACd;IACF;IACA,OAAOX;AACT;AAEA;;;;;;;;CAQC,GACD,OAAO,SAASgB,iBACdjB,KAAQ;IAER,IAAI,CAACA,OAAO,OAAOA;IACnB,MAAMC,UAAUF,UAAUC;IAC1B,MAAMkB,SAAsB,CAAC;IAC7B,KAAK,MAAM,CAACb,KAAKC,KAAK,IAAIC,OAAOC,OAAO,CAACR,OAAQ;QAC/C,IAAI,CAACM,QAAQ,OAAOA,SAAS,UAAU;YACrCY,MAAM,CAACb,IAAI,GAAGC;YACd;QACF;QACA,MAAM,EAAEa,GAAG,EAAEC,QAAQ,EAAW,GAAGd,MAATe,wCAASf;;;;QACnC,MAAMgB,MAAgBD;QACtB,IAAIF,QAAQd,KAAKiB,IAAIH,GAAG,GAAGA;QAC3B,IAAIC,aAAaG,aAAaH,aAAanB,QAAQuB,GAAG,CAACnB,MAAM;YAC3DiB,IAAIF,QAAQ,GAAGA;QACjB;QACAF,MAAM,CAACb,IAAI,GAAGiB;IAChB;IACA,OAAOJ;AACT;AAEA;;;;;CAKC,GACD,OAAO,SAASO,gBACdzB,KAAQ;IAER,IAAI,CAACA,OAAO,OAAOA;IACnB,MAAMC,UAAUF,UAAUC;IAC1B,MAAM0B,WAAwB,CAAC;IAC/B,KAAK,MAAM,CAACrB,KAAKC,KAAK,IAAIC,OAAOC,OAAO,CAACR,OAAQ;QAC/C,IAAI,CAACM,QAAQ,OAAOA,SAAS,UAAU;YACrCoB,QAAQ,CAACrB,IAAI,GAAGC;YAChB;QACF;QACA,MAAMqB,SAAS1B,QAAQuB,GAAG,CAACnB;QAC3B,MAAMuB,UAAU,CAAE,CAAA,SAAStB,IAAG;QAC9B,MAAMuB,cAAc,CAAE,CAAA,cAAcvB,IAAG,KAAMqB,WAAWJ;QACxDG,QAAQ,CAACrB,IAAI,GACXuB,WAAWC,cACP,aACMD,UAAU;YAAET,KAAKd;QAAI,IAAI,CAAC,GAC3BC,MACCuB,cAAc;YAAET,UAAUO;QAAO,IAAI,CAAC,KAE5CrB;IACR;IACA,OAAOoB;AACT"}
|
|
@@ -296,8 +296,20 @@ export interface OrgBrandingProfile {
|
|
|
296
296
|
productName?: string;
|
|
297
297
|
/** Primary/full-color logo URL (light backgrounds, console chrome). */
|
|
298
298
|
logoUrl?: string;
|
|
299
|
+
/**
|
|
300
|
+
* The logo for DARK grounds (AGL-3406): the console chrome in dark mode and the
|
|
301
|
+
* published site's attribution badge, which always sits on a dark pill.
|
|
302
|
+
* Unset falls back to {@link logoUrl}.
|
|
303
|
+
*/
|
|
304
|
+
logoDarkUrl?: string;
|
|
299
305
|
/** Favicon URL for branded surfaces. */
|
|
300
306
|
faviconUrl?: string;
|
|
307
|
+
/**
|
|
308
|
+
* The favicon for a browser whose tab strip is dark, emitted as a second
|
|
309
|
+
* `<link rel="icon">` under `(prefers-color-scheme: dark)`. Unset falls back
|
|
310
|
+
* to {@link faviconUrl}.
|
|
311
|
+
*/
|
|
312
|
+
faviconDarkUrl?: string;
|
|
301
313
|
/** Brand primary color as a CSS color (hex), e.g. `#1a73e8`. */
|
|
302
314
|
primaryColor?: string;
|
|
303
315
|
/** Support/help destination linked from branded surfaces and emails. */
|