@aglyn/aglyn 1.0.0-beta.143 → 1.0.0-beta.145

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/README.md CHANGED
@@ -1,11 +1,122 @@
1
1
  # @aglyn/aglyn
2
2
 
3
- This library was generated with [Nx](https://nx.dev).
3
+ The core of Aglyn: the platform's data model (hosts, screens, layouts, node
4
+ trees), the runtime managers that hold components, plugins and the canvas, and
5
+ the framework-independent utilities the rest of the `@aglyn` packages are built
6
+ on. Install it if you are building on Aglyn's model: a renderer, an editor, a
7
+ plugin, or a tool that reads and writes Aglyn documents.
4
8
 
5
- ## Building
9
+ > Beta. Published from the Aglyn monorepo under the `beta` dist-tag; APIs can change between beta releases.
6
10
 
7
- Run `nx build aglyn` to build the library.
11
+ ## Install
8
12
 
9
- ## Running unit tests
13
+ npm install @aglyn/aglyn@beta
10
14
 
11
- Run `nx test aglyn` to execute the unit tests via [Jest](https://jestjs.io).
15
+ Peer dependencies:
16
+
17
+ - `react` is required.
18
+ - `next`, `firebase`, `@mui/material` and `@mui/system` are declared optional
19
+ (`peerDependenciesMeta`). The package installs and bundles with only `react`.
20
+ Bring the optional ones only for the modules that use them:
21
+ - `@mui/material` for the consent UI modules
22
+ (`@aglyn/aglyn/app-utils/consent-banner-ui`,
23
+ `@aglyn/aglyn/app-utils/consent-preferences-dialog`); `@mui/material` and
24
+ `@mui/system` also supply types that some node and component type
25
+ definitions refer to.
26
+ - `next` for `@aglyn/aglyn/app-utils/advertising-tag-mounts`, which uses
27
+ `next/script`.
28
+ - `firebase` is declared for apps that pair the model with Firebase, as
29
+ Aglyn's own apps do. No module in this package needs it to load.
30
+
31
+ This is the "logic only" consumer story: `@aglyn/aglyn` together with
32
+ `@aglyn/besigner` installs with `react` as the only peer, and needs no UI
33
+ library, no `next`, and no Firebase SDK.
34
+
35
+ ## What's in it
36
+
37
+ Entry points:
38
+
39
+ - `@aglyn/aglyn` is the full barrel, for client code.
40
+ - `@aglyn/aglyn/server` is the server-safe barrel. It re-exports the same
41
+ model, managers and pure utilities without the client React contexts, so it
42
+ can be imported from React Server Components. It also carries the modules
43
+ that use Node built-ins or a JavaScript parser and are therefore kept out of
44
+ the client barrel: the Web-to-`(req, res)` API adapter, API idempotency,
45
+ the person key, the plugin bundle checks, and the server side of realm
46
+ plugins.
47
+ - `@aglyn/aglyn/*` maps to a file under `src/lib`, for example
48
+ `@aglyn/aglyn/aglyn` or `@aglyn/aglyn/app-utils/markdown-lite`. A subpath
49
+ names a file, not a folder. Importing by subpath keeps a bundle to what it
50
+ uses.
51
+
52
+ Main areas under `src/lib`:
53
+
54
+ - `aglyn` is the runtime singleton. It exports `aglyn` and its parts:
55
+ `emitter`, `plugins`, `components`, `canvas` and `logger`. The instance is
56
+ keyed on `globalThis`, so duplicate module copies in one JavaScript realm
57
+ share one runtime.
58
+ - `types` holds the node and screen model: `NodeSchema`, `NodesMap`,
59
+ `ComponentSchema`, `PresetSchema`, `ScreenSchema`, routing and AST types.
60
+ - `foundation` holds the platform document types (`AglynHost`, `AglynScreen`,
61
+ `AglynLayout`, `AglynHostTheme`, organization and billing shapes, and their
62
+ id types) and shared constants.
63
+ - `emit-manager` is `EmitManager` (an `eventemitter2` emitter) and the
64
+ `AglynEvent` enum of lifecycle and action events.
65
+ - `components-manager` is `ComponentManager`, the registry of component
66
+ factories, their schemas, and presets.
67
+ - `plugin-manager` is `PluginManager` (plugin registration and dependency
68
+ status) plus the plugin seams: the plugin loader (`createPluginLoader`),
69
+ contributions, configuration, permissions, entitlements, events, services
70
+ and jobs. Aglyn's feature plugins attach to the platform through these.
71
+ - `canvas-manager` is `CanvasManager`, the observable node tree: set, create,
72
+ delete, duplicate, reparent and reorder nodes, with undo and redo history.
73
+ - `app-utils` is a large set of pure helpers over the model: node composition
74
+ and sanitizing, binding tokens and variables, datasets and collections, SEO
75
+ and sitemap helpers, the markdown-lite dialect, permissions and roles,
76
+ consent, analytics keys, media references, and more. Its React contexts
77
+ (site context, media picker, enabled plugins and others) are exported from
78
+ the client barrel only.
79
+ - `utils` has the feature-flag predicates such as `isFeatureEnabled`.
80
+
81
+ ## Usage
82
+
83
+ ```ts
84
+ import { AglynEvent, canvas, components, emitter } from '@aglyn/aglyn'
85
+
86
+ emitter.on(AglynEvent.COMPONENT_REGISTERED, ({ $id }) => {
87
+ console.log('registered', $id)
88
+ })
89
+
90
+ components.registerComponent(MyBox, {
91
+ $id: 'my-box',
92
+ pluginId: 'my-plugin',
93
+ displayName: 'My box',
94
+ })
95
+
96
+ components.getSchema('my-box')
97
+
98
+ // `nodes` is a NodesMap: node id -> NodeSchema
99
+ canvas.setNodes(nodes)
100
+ const root = canvas.rootNode
101
+ ```
102
+
103
+ From a Server Component or other server code:
104
+
105
+ ```ts
106
+ import type { AglynScreen, NodeSchema } from '@aglyn/aglyn/server'
107
+ ```
108
+
109
+ ## How it fits
110
+
111
+ `@aglyn/aglyn` is the `core` scope of the package map. It imports only itself
112
+ and the generic `@aglyn/shared-*` packages. It holds no rendering, no designer,
113
+ no tenancy and no plugin: the core never imports a plugin, and a plugin's
114
+ domain lives in that plugin. Everything else stands on it:
115
+ `@aglyn/aglyn-node-renderer` turns its node trees into React,
116
+ `@aglyn/besigner` and `@aglyn/besigner-ui` edit them, the `@aglyn/tenant-*`
117
+ packages serve them, and every `@aglyn/plugins-*` package registers into its
118
+ managers.
119
+
120
+ ## License
121
+
122
+ Apache-2.0. Source: https://github.com/aglyn/aglyn/tree/main/libs/aglyn
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aglyn/aglyn",
3
- "version": "1.0.0-beta.143",
3
+ "version": "1.0.0-beta.145",
4
4
  "license": "Apache-2.0",
5
5
  "homepage": "https://aglyn.com",
6
6
  "repository": {
@@ -22,6 +22,10 @@
22
22
  "types": "./src/server.d.ts",
23
23
  "default": "./src/server.js"
24
24
  },
25
+ "./foundation": {
26
+ "types": "./src/lib/foundation/index.d.ts",
27
+ "default": "./src/lib/foundation/index.js"
28
+ },
25
29
  "./*": {
26
30
  "types": "./src/lib/*.d.ts",
27
31
  "default": "./src/lib/*.js"
@@ -29,15 +33,15 @@
29
33
  "./package.json": "./package.json"
30
34
  },
31
35
  "dependencies": {
32
- "@aglyn/shared-data-enums": "1.0.0-beta.143",
33
- "@aglyn/shared-data-mdi": "1.0.0-beta.143",
34
- "@aglyn/shared-data-types": "1.0.0-beta.143",
35
- "@aglyn/shared-util-email": "1.0.0-beta.143",
36
- "@aglyn/shared-util-http": "1.0.0-beta.143",
37
- "@aglyn/shared-util-logger": "1.0.0-beta.143",
38
- "@aglyn/shared-util-timestamp": "1.0.0-beta.143",
39
- "@aglyn/shared-util-tools": "1.0.0-beta.143",
40
- "@aglyn/shared-util-vendor": "1.0.0-beta.143",
36
+ "@aglyn/shared-data-enums": "1.0.0-beta.145",
37
+ "@aglyn/shared-data-mdi": "1.0.0-beta.145",
38
+ "@aglyn/shared-data-types": "1.0.0-beta.145",
39
+ "@aglyn/shared-util-email": "1.0.0-beta.145",
40
+ "@aglyn/shared-util-http": "1.0.0-beta.145",
41
+ "@aglyn/shared-util-logger": "1.0.0-beta.145",
42
+ "@aglyn/shared-util-timestamp": "1.0.0-beta.145",
43
+ "@aglyn/shared-util-tools": "1.0.0-beta.145",
44
+ "@aglyn/shared-util-vendor": "1.0.0-beta.145",
41
45
  "@data-driven-forms/react-form-renderer": "^4.2.0",
42
46
  "@msgpack/msgpack": "^3.1.3",
43
47
  "@types/unist": "^3.0.3",
@@ -56,6 +60,20 @@
56
60
  "next": "16.3.3",
57
61
  "react": "^19.2.8"
58
62
  },
63
+ "peerDependenciesMeta": {
64
+ "@mui/material": {
65
+ "optional": true
66
+ },
67
+ "@mui/system": {
68
+ "optional": true
69
+ },
70
+ "firebase": {
71
+ "optional": true
72
+ },
73
+ "next": {
74
+ "optional": true
75
+ }
76
+ },
59
77
  "sideEffects": [
60
78
  "./src/lib/foundation/constants/_internal.*",
61
79
  "./src/lib/foundation/constants/symbol.*"
@@ -0,0 +1,56 @@
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 two names the live-site preview of a collection entry is built from
19
+ * (AGL-3205), and nothing else.
20
+ *
21
+ * DEPENDENCY-FREE ON PURPOSE. The tenant middleware reads the parameter name
22
+ * to decide whether a request is a preview, and the middleware runs on the
23
+ * edge: it deep-imports its pure helpers precisely so a bundle meant to answer
24
+ * in a millisecond does not drag a barrel — `accept-negotiation` and the theme
25
+ * utilities carry the same note. This module imports nothing at all, so it
26
+ * costs the edge bundle two string constants.
27
+ *
28
+ * Four surfaces have to agree on these, in three different apps: the console
29
+ * mints the URL, the tenant middleware routes on the parameter, the tenant
30
+ * preview page reads it, and the screens authoring rules reserve the segment.
31
+ * A literal in four places is a rename waiting to break one of them.
32
+ */
33
+ /**
34
+ * The query parameter a preview link carries.
35
+ *
36
+ * Namespaced with the brand so it cannot collide with a parameter a customer's
37
+ * own page already reads, and `snake_case` to match the `aglyn_edit_hint`
38
+ * cookie rather than the `data-aglyn-*` attribute family.
39
+ */
40
+ export declare const ENTRY_PREVIEW_PARAM = "aglyn_preview";
41
+ /**
42
+ * The internal path segment the middleware rewrites a preview request to —
43
+ * `/{host}/{scheme}/aglyn-preview/{the public path}`.
44
+ *
45
+ * Never seen by a reader: the address bar keeps the post's real URL. It exists
46
+ * because the preview MUST be a different Next route from the catch-all, which
47
+ * is ISR-cached per pathname and would otherwise serve an unpublished post to
48
+ * the public for an hour.
49
+ *
50
+ * It is a reserved screen slug for the ordinary reason a segment ends up in
51
+ * {@link RESERVED_SCREEN_ROUTE_SEGMENTS}: a static route folder wins over the
52
+ * optional catch-all beside it, so a screen published at `/aglyn-preview/…`
53
+ * would be answered by the preview route and never render. Brand-prefixed so
54
+ * the slug it costs a customer is one nobody wants.
55
+ */
56
+ export declare const ENTRY_PREVIEW_ROUTE_SEGMENT = "aglyn-preview";
@@ -0,0 +1,54 @@
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
+ * The two names the live-site preview of a collection entry is built from
18
+ * (AGL-3205), and nothing else.
19
+ *
20
+ * DEPENDENCY-FREE ON PURPOSE. The tenant middleware reads the parameter name
21
+ * to decide whether a request is a preview, and the middleware runs on the
22
+ * edge: it deep-imports its pure helpers precisely so a bundle meant to answer
23
+ * in a millisecond does not drag a barrel — `accept-negotiation` and the theme
24
+ * utilities carry the same note. This module imports nothing at all, so it
25
+ * costs the edge bundle two string constants.
26
+ *
27
+ * Four surfaces have to agree on these, in three different apps: the console
28
+ * mints the URL, the tenant middleware routes on the parameter, the tenant
29
+ * preview page reads it, and the screens authoring rules reserve the segment.
30
+ * A literal in four places is a rename waiting to break one of them.
31
+ */ /**
32
+ * The query parameter a preview link carries.
33
+ *
34
+ * Namespaced with the brand so it cannot collide with a parameter a customer's
35
+ * own page already reads, and `snake_case` to match the `aglyn_edit_hint`
36
+ * cookie rather than the `data-aglyn-*` attribute family.
37
+ */ export const ENTRY_PREVIEW_PARAM = 'aglyn_preview';
38
+ /**
39
+ * The internal path segment the middleware rewrites a preview request to —
40
+ * `/{host}/{scheme}/aglyn-preview/{the public path}`.
41
+ *
42
+ * Never seen by a reader: the address bar keeps the post's real URL. It exists
43
+ * because the preview MUST be a different Next route from the catch-all, which
44
+ * is ISR-cached per pathname and would otherwise serve an unpublished post to
45
+ * the public for an hour.
46
+ *
47
+ * It is a reserved screen slug for the ordinary reason a segment ends up in
48
+ * {@link RESERVED_SCREEN_ROUTE_SEGMENTS}: a static route folder wins over the
49
+ * optional catch-all beside it, so a screen published at `/aglyn-preview/…`
50
+ * would be answered by the preview route and never render. Brand-prefixed so
51
+ * the slug it costs a customer is one nobody wants.
52
+ */ export const ENTRY_PREVIEW_ROUTE_SEGMENT = 'aglyn-preview';
53
+
54
+ //# sourceMappingURL=entry-preview-link.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../libs/aglyn/src/lib/app-utils/entry-preview-link.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 * The two names the live-site preview of a collection entry is built from\n * (AGL-3205), and nothing else.\n *\n * DEPENDENCY-FREE ON PURPOSE. The tenant middleware reads the parameter name\n * to decide whether a request is a preview, and the middleware runs on the\n * edge: it deep-imports its pure helpers precisely so a bundle meant to answer\n * in a millisecond does not drag a barrel — `accept-negotiation` and the theme\n * utilities carry the same note. This module imports nothing at all, so it\n * costs the edge bundle two string constants.\n *\n * Four surfaces have to agree on these, in three different apps: the console\n * mints the URL, the tenant middleware routes on the parameter, the tenant\n * preview page reads it, and the screens authoring rules reserve the segment.\n * A literal in four places is a rename waiting to break one of them.\n */\n\n/**\n * The query parameter a preview link carries.\n *\n * Namespaced with the brand so it cannot collide with a parameter a customer's\n * own page already reads, and `snake_case` to match the `aglyn_edit_hint`\n * cookie rather than the `data-aglyn-*` attribute family.\n */\nexport const ENTRY_PREVIEW_PARAM = 'aglyn_preview'\n\n/**\n * The internal path segment the middleware rewrites a preview request to —\n * `/{host}/{scheme}/aglyn-preview/{the public path}`.\n *\n * Never seen by a reader: the address bar keeps the post's real URL. It exists\n * because the preview MUST be a different Next route from the catch-all, which\n * is ISR-cached per pathname and would otherwise serve an unpublished post to\n * the public for an hour.\n *\n * It is a reserved screen slug for the ordinary reason a segment ends up in\n * {@link RESERVED_SCREEN_ROUTE_SEGMENTS}: a static route folder wins over the\n * optional catch-all beside it, so a screen published at `/aglyn-preview/…`\n * would be answered by the preview route and never render. Brand-prefixed so\n * the slug it costs a customer is one nobody wants.\n */\nexport const ENTRY_PREVIEW_ROUTE_SEGMENT = 'aglyn-preview'\n"],"names":["ENTRY_PREVIEW_PARAM","ENTRY_PREVIEW_ROUTE_SEGMENT"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAED;;;;;;;;;;;;;;;CAeC,GAED;;;;;;CAMC,GACD,OAAO,MAAMA,sBAAsB,gBAAe;AAElD;;;;;;;;;;;;;;CAcC,GACD,OAAO,MAAMC,8BAA8B,gBAAe"}
@@ -444,9 +444,28 @@ export const PLAN_ENTITLEMENTS = {
444
444
  // rule — a positive band with no rate beside it is usage past a bound
445
445
  // that is silently free, which `plan-entitlements.spec.ts` forbids.
446
446
  //
447
- // `features.aiAssist` stays false: the band is credits, not the guided
448
- // rung of the console assistant, exactly as on Free. The AI add-on adds
449
- // `AI_ADDON_CREDITS_PER_MONTH.starter` on top and switches both flags on.
447
+ // `features.aiAssist` is TRUE, and AGL-3203 shipping it false was the
448
+ // defect AGL-3207 closes. The reasoning then was "the band is credits,
449
+ // not the guided rung, exactly as on Free" — but on Free the band IS
450
+ // spendable, through `aiGenerative`, which is the door the taste exists
451
+ // for. Starter carried neither flag, so it was the only row on the
452
+ // ladder sold a band with nothing to spend it through: 750 credits
453
+ // reachable only by buying the $9 add-on that was also the only thing
454
+ // that made them usable. "No plan bands at zero any more" was true of
455
+ // the number and false of the capability.
456
+ //
457
+ // It opens `aiAssist` rather than `aiGenerative` because that is the
458
+ // shape of every paid rung above it — the included band funds the guided
459
+ // assistant and generation is the add-on. Opening the generative door
460
+ // here instead would hand the FIRST paid rung a door Pro through Agency
461
+ // have to buy.
462
+ //
463
+ // No cost moves: `tier-margin-floor.spec.ts` already prices this tier's
464
+ // assist term at 100% burn of the 750 credits, 75¢/mo. A door does not
465
+ // widen a band; it only makes spend that was already modeled reachable.
466
+ //
467
+ // The AI add-on adds `AI_ADDON_CREDITS_PER_MONTH.starter` on top and
468
+ // switches `aiGenerative` on as well.
450
469
  assistCreditsPerMonth: 750,
451
470
  apiRequestsPerMonth: 0,
452
471
  datasetsPerOrg: 3,
@@ -481,7 +500,7 @@ export const PLAN_ENTITLEMENTS = {
481
500
  removeBranding: true,
482
501
  scheduledPublishing: false,
483
502
  marketplaceSelling: false,
484
- aiAssist: false,
503
+ aiAssist: true,
485
504
  aiGenerative: false,
486
505
  workflows: true,
487
506
  dataStore: true,