@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 +116 -5
- package/package.json +28 -10
- package/src/lib/app-utils/entry-preview-link.d.ts +56 -0
- package/src/lib/app-utils/entry-preview-link.js +54 -0
- package/src/lib/app-utils/entry-preview-link.js.map +1 -0
- package/src/lib/app-utils/plan-entitlements.js +23 -4
- package/src/lib/app-utils/plan-entitlements.js.map +1 -1
- package/src/lib/app-utils/screen-route.d.ts +10 -0
- package/src/lib/app-utils/screen-route.js +12 -0
- package/src/lib/app-utils/screen-route.js.map +1 -1
- package/src/lib/app-utils/wistia-embed.d.ts +18 -0
- package/src/lib/app-utils/wistia-embed.js +20 -1
- package/src/lib/app-utils/wistia-embed.js.map +1 -1
- package/src/lib/plugin-manager/feature-plugins.d.ts +54 -0
- package/src/lib/plugin-manager/feature-plugins.js.map +1 -1
package/README.md
CHANGED
|
@@ -1,11 +1,122 @@
|
|
|
1
1
|
# @aglyn/aglyn
|
|
2
2
|
|
|
3
|
-
|
|
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
|
-
|
|
9
|
+
> Beta. Published from the Aglyn monorepo under the `beta` dist-tag; APIs can change between beta releases.
|
|
6
10
|
|
|
7
|
-
|
|
11
|
+
## Install
|
|
8
12
|
|
|
9
|
-
|
|
13
|
+
npm install @aglyn/aglyn@beta
|
|
10
14
|
|
|
11
|
-
|
|
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.
|
|
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.
|
|
33
|
-
"@aglyn/shared-data-mdi": "1.0.0-beta.
|
|
34
|
-
"@aglyn/shared-data-types": "1.0.0-beta.
|
|
35
|
-
"@aglyn/shared-util-email": "1.0.0-beta.
|
|
36
|
-
"@aglyn/shared-util-http": "1.0.0-beta.
|
|
37
|
-
"@aglyn/shared-util-logger": "1.0.0-beta.
|
|
38
|
-
"@aglyn/shared-util-timestamp": "1.0.0-beta.
|
|
39
|
-
"@aglyn/shared-util-tools": "1.0.0-beta.
|
|
40
|
-
"@aglyn/shared-util-vendor": "1.0.0-beta.
|
|
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`
|
|
448
|
-
//
|
|
449
|
-
//
|
|
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:
|
|
503
|
+
aiAssist: true,
|
|
485
504
|
aiGenerative: false,
|
|
486
505
|
workflows: true,
|
|
487
506
|
dataStore: true,
|