@aglyn/aglyn 1.0.0-beta.268 → 1.0.0-beta.270

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 (82) hide show
  1. package/package.json +11 -11
  2. package/src/lib/app-utils/account-preferences.d.ts +248 -0
  3. package/src/lib/app-utils/account-preferences.js +434 -0
  4. package/src/lib/app-utils/account-preferences.js.map +1 -0
  5. package/src/lib/app-utils/country-options.d.ts +27 -0
  6. package/src/lib/app-utils/country-options.js +96 -0
  7. package/src/lib/app-utils/country-options.js.map +1 -0
  8. package/src/lib/app-utils/docs-help.generated.d.ts +6 -0
  9. package/src/lib/app-utils/docs-help.generated.js +13 -0
  10. package/src/lib/app-utils/docs-help.generated.js.map +1 -1
  11. package/src/lib/app-utils/docs-index.generated.js +17 -10
  12. package/src/lib/app-utils/docs-index.generated.js.map +1 -1
  13. package/src/lib/app-utils/element-motion.d.ts +14 -2
  14. package/src/lib/app-utils/element-motion.js +33 -13
  15. package/src/lib/app-utils/element-motion.js.map +1 -1
  16. package/src/lib/app-utils/mobile-push.d.ts +8 -0
  17. package/src/lib/app-utils/mobile-push.js +4 -1
  18. package/src/lib/app-utils/mobile-push.js.map +1 -1
  19. package/src/lib/app-utils/native-app-association.d.ts +3 -2
  20. package/src/lib/app-utils/native-app-association.js +4 -2
  21. package/src/lib/app-utils/native-app-association.js.map +1 -1
  22. package/src/lib/app-utils/native-nav.d.ts +265 -0
  23. package/src/lib/app-utils/native-nav.js +741 -0
  24. package/src/lib/app-utils/native-nav.js.map +1 -0
  25. package/src/lib/app-utils/native-themes.d.ts +249 -0
  26. package/src/lib/app-utils/native-themes.js +732 -0
  27. package/src/lib/app-utils/native-themes.js.map +1 -0
  28. package/src/lib/app-utils/notifications.d.ts +1 -1
  29. package/src/lib/app-utils/notifications.js +10 -0
  30. package/src/lib/app-utils/notifications.js.map +1 -1
  31. package/src/lib/app-utils/one-box-search.d.ts +108 -0
  32. package/src/lib/app-utils/one-box-search.js +167 -0
  33. package/src/lib/app-utils/one-box-search.js.map +1 -0
  34. package/src/lib/app-utils/org-permissions.js +10 -61
  35. package/src/lib/app-utils/org-permissions.js.map +1 -1
  36. package/src/lib/app-utils/org-role-grants.d.ts +95 -0
  37. package/src/lib/app-utils/org-role-grants.js +193 -0
  38. package/src/lib/app-utils/org-role-grants.js.map +1 -0
  39. package/src/lib/app-utils/plan-entitlements.d.ts +41 -1
  40. package/src/lib/app-utils/plan-entitlements.js +65 -3
  41. package/src/lib/app-utils/plan-entitlements.js.map +1 -1
  42. package/src/lib/app-utils/tenant-dns-targets.d.ts +62 -0
  43. package/src/lib/app-utils/tenant-dns-targets.js +80 -0
  44. package/src/lib/app-utils/tenant-dns-targets.js.map +1 -0
  45. package/src/lib/foundation/definitions/org-billing.types.d.ts +14 -0
  46. package/src/lib/foundation/definitions/org-billing.types.js.map +1 -1
  47. package/src/lib/foundation/definitions/platform.types.d.ts +9 -0
  48. package/src/lib/foundation/definitions/platform.types.js.map +1 -1
  49. package/src/lib/plugin-manager/feature-plugins.d.ts +38 -0
  50. package/src/lib/plugin-manager/feature-plugins.js +20 -0
  51. package/src/lib/plugin-manager/feature-plugins.js.map +1 -1
  52. package/src/lib/plugin-manager/first-party-plugins.generated.js +22 -1
  53. package/src/lib/plugin-manager/first-party-plugins.generated.js.map +1 -1
  54. package/src/lib/plugin-manager/operator-alerts.js +10 -1
  55. package/src/lib/plugin-manager/operator-alerts.js.map +1 -1
  56. package/src/lib/plugin-manager/plugin-config.js +10 -1
  57. package/src/lib/plugin-manager/plugin-config.js.map +1 -1
  58. package/src/lib/plugin-manager/plugin-consent-group-change.js +11 -2
  59. package/src/lib/plugin-manager/plugin-consent-group-change.js.map +1 -1
  60. package/src/lib/plugin-manager/plugin-console-crons.js +10 -1
  61. package/src/lib/plugin-manager/plugin-console-crons.js.map +1 -1
  62. package/src/lib/plugin-manager/plugin-domain-events.d.ts +4 -3
  63. package/src/lib/plugin-manager/plugin-domain-events.js.map +1 -1
  64. package/src/lib/plugin-manager/plugin-events.js +11 -2
  65. package/src/lib/plugin-manager/plugin-events.js.map +1 -1
  66. package/src/lib/plugin-manager/plugin-lead-conversion.js +10 -1
  67. package/src/lib/plugin-manager/plugin-lead-conversion.js.map +1 -1
  68. package/src/lib/plugin-manager/plugin-media-ingest.d.ts +25 -0
  69. package/src/lib/plugin-manager/plugin-media-ingest.js.map +1 -1
  70. package/src/lib/plugin-manager/plugin-membership-detach.js +10 -1
  71. package/src/lib/plugin-manager/plugin-membership-detach.js.map +1 -1
  72. package/src/lib/plugin-manager/plugin-person-matches.js +10 -1
  73. package/src/lib/plugin-manager/plugin-person-matches.js.map +1 -1
  74. package/src/lib/plugin-manager/plugin-search-sources.d.ts +85 -0
  75. package/src/lib/plugin-manager/plugin-search-sources.js +91 -0
  76. package/src/lib/plugin-manager/plugin-search-sources.js.map +1 -0
  77. package/src/lib/plugin-manager/plugin-services.js +6 -0
  78. package/src/lib/plugin-manager/plugin-services.js.map +1 -1
  79. package/src/lib/plugin-manager/plugin-usage-meters.js +10 -1
  80. package/src/lib/plugin-manager/plugin-usage-meters.js.map +1 -1
  81. package/src/lib/plugin-manager/usage-alert-contributors.js +10 -1
  82. package/src/lib/plugin-manager/usage-alert-contributors.js.map +1 -1
@@ -0,0 +1,193 @@
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
+ * WHAT EACH ORG ROLE MAY DO, AS DATA (AGL-243, AGL-3950).
18
+ *
19
+ * The core permission catalog and the core keys each org role holds when
20
+ * nothing refines it. `org-permissions.ts` builds the console's live
21
+ * catalog from these (adding the keys plugins declare, with their own role
22
+ * defaults), and the native apps read the same grants through the generated
23
+ * contracts, so a native gate (`hosts.create`, `data.manage`) answers as the
24
+ * console does for a member row that carries no `resolvedPermissions` stamp.
25
+ *
26
+ * `ORG_ROLE_GRANTS` in the contracts is this table with every plugin's
27
+ * declared catalog keys added (`assembleOrgRoleGrants`, run by
28
+ * `generate:native-contracts` over each plugin's declarations), which is
29
+ * exactly the set the console's `DEFAULT_ROLE_PERMISSIONS` holds once the
30
+ * plugins have registered.
31
+ *
32
+ * NO IMPORTS, on purpose: the native apps read it through the generated
33
+ * contracts.
34
+ */ /** The four org roles. */ import { _ as _extends } from "@swc/helpers/_/_extends";
35
+ export const ORG_ROLE_NAMES = [
36
+ 'owner',
37
+ 'admin',
38
+ 'editor',
39
+ 'viewer'
40
+ ];
41
+ /**
42
+ * The core keys, in display order for role editors. Every key here is
43
+ * enforced server-side (`apps/console/specs/org-permissions-are-enforced.spec.ts`).
44
+ */ export const CORE_ORG_PERMISSION_ENTRIES = [
45
+ {
46
+ key: 'org.settings',
47
+ label: 'Organization settings',
48
+ description: 'Rename the organization, change its slug, transfer it.'
49
+ },
50
+ {
51
+ key: 'org.auditLog',
52
+ label: 'Activity & audit log',
53
+ description: 'See the organization activity feed.'
54
+ },
55
+ {
56
+ key: 'billing.view',
57
+ label: 'View billing',
58
+ description: 'See the plan, usage meters, and invoices.'
59
+ },
60
+ {
61
+ key: 'billing.manage',
62
+ label: 'Manage billing',
63
+ description: 'Change plans, buy add-ons, update payment details.'
64
+ },
65
+ {
66
+ key: 'members.manage',
67
+ label: 'Manage members',
68
+ description: 'Invite, remove, and re-role organization members.'
69
+ },
70
+ {
71
+ key: 'hosts.create',
72
+ label: 'Create sites',
73
+ description: 'Create new sites in the organization.'
74
+ },
75
+ {
76
+ key: 'hosts.delete',
77
+ label: 'Delete sites',
78
+ description: 'Delete sites the member can access.'
79
+ },
80
+ {
81
+ key: 'data.manage',
82
+ label: 'Manage data',
83
+ description: 'Create, edit, and delete organization datasets.'
84
+ },
85
+ {
86
+ key: 'marketplace.publish',
87
+ label: 'Publish to marketplace',
88
+ description: 'Publish listings under the organization profile.'
89
+ },
90
+ {
91
+ key: 'plugins.install',
92
+ label: 'Install plugins',
93
+ description: 'Install or remove marketplace plugins.'
94
+ }
95
+ ];
96
+ const CORE_KEYS = CORE_ORG_PERMISSION_ENTRIES.map((entry)=>entry.key);
97
+ /**
98
+ * The core keys each org role holds when nothing refines it: owners and
99
+ * admins hold every core key (owner-only acts like deleting the
100
+ * organization stay role-checked, not permission-checked); editors work on
101
+ * content and see no money or roster controls; viewers read only.
102
+ */ export const CORE_ORG_ROLE_GRANTS = {
103
+ owner: CORE_KEYS,
104
+ admin: CORE_KEYS,
105
+ editor: [
106
+ 'data.manage',
107
+ 'marketplace.publish',
108
+ 'plugins.install'
109
+ ],
110
+ viewer: []
111
+ };
112
+ /** The core's catalog and grants; the contracts' value adds the plugins' keys. */ export const ORG_ROLE_GRANTS = {
113
+ permissions: CORE_ORG_PERMISSION_ENTRIES.map((entry)=>_extends({}, entry)),
114
+ grants: {
115
+ owner: [
116
+ ...CORE_ORG_ROLE_GRANTS.owner
117
+ ],
118
+ admin: [
119
+ ...CORE_ORG_ROLE_GRANTS.admin
120
+ ],
121
+ editor: [
122
+ ...CORE_ORG_ROLE_GRANTS.editor
123
+ ],
124
+ viewer: [
125
+ ...CORE_ORG_ROLE_GRANTS.viewer
126
+ ]
127
+ }
128
+ };
129
+ /**
130
+ * The catalog with plugins' declared keys after the core ones, each role
131
+ * holding a declared key when its declaration's `roleDefaults` says so. A
132
+ * declaration naming a core key is refused, as the console's catalog refuses
133
+ * it: the core key keeps its meaning and defaults.
134
+ */ export function assembleOrgRoleGrants(core, declarations) {
135
+ const permissions = [
136
+ ...core.permissions
137
+ ];
138
+ const grants = Object.fromEntries(ORG_ROLE_NAMES.map((role)=>[
139
+ role,
140
+ [
141
+ ...core.grants[role]
142
+ ]
143
+ ]));
144
+ const taken = new Set(permissions.map((entry)=>entry.key));
145
+ for (const declaration of declarations){
146
+ if (!(declaration == null ? void 0 : declaration.key) || taken.has(declaration.key)) continue;
147
+ taken.add(declaration.key);
148
+ permissions.push(_extends({
149
+ key: declaration.key,
150
+ label: declaration.label,
151
+ description: declaration.description
152
+ }, declaration.pluginId ? {
153
+ pluginId: declaration.pluginId
154
+ } : {}));
155
+ for (const role of ORG_ROLE_NAMES){
156
+ var _declaration_roleDefaults;
157
+ if (((_declaration_roleDefaults = declaration.roleDefaults) == null ? void 0 : _declaration_roleDefaults[role]) === true) grants[role].push(declaration.key);
158
+ }
159
+ }
160
+ return {
161
+ permissions,
162
+ grants
163
+ };
164
+ }
165
+ /**
166
+ * A member's effective permissions, as the console's `resolveOrgPermissions`
167
+ * answers them: the role's defaults, then the custom role's explicit
168
+ * verdicts (when the member has one), then the member's own overrides,
169
+ * later layers winning key by key, over the catalog's keys only. A missing
170
+ * role reads as viewer; a role the catalog does not know holds nothing.
171
+ */ export function rolePermissions(catalog, role, customRole, overrides) {
172
+ var _catalog_grants_name;
173
+ const keys = catalog.permissions.map((entry)=>entry.key);
174
+ const name = role != null ? role : 'viewer';
175
+ const held = new Set((_catalog_grants_name = catalog.grants[name]) != null ? _catalog_grants_name : []);
176
+ const out = Object.fromEntries(keys.map((key)=>[
177
+ key,
178
+ held.has(key)
179
+ ]));
180
+ for (const layer of [
181
+ customRole,
182
+ overrides
183
+ ]){
184
+ const values = layer == null ? void 0 : layer.permissions;
185
+ if (!values) continue;
186
+ for (const key of keys){
187
+ if (typeof values[key] === 'boolean') out[key] = values[key];
188
+ }
189
+ }
190
+ return out;
191
+ }
192
+
193
+ //# sourceMappingURL=org-role-grants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../libs/aglyn/src/lib/app-utils/org-role-grants.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 * WHAT EACH ORG ROLE MAY DO, AS DATA (AGL-243, AGL-3950).\n *\n * The core permission catalog and the core keys each org role holds when\n * nothing refines it. `org-permissions.ts` builds the console's live\n * catalog from these (adding the keys plugins declare, with their own role\n * defaults), and the native apps read the same grants through the generated\n * contracts, so a native gate (`hosts.create`, `data.manage`) answers as the\n * console does for a member row that carries no `resolvedPermissions` stamp.\n *\n * `ORG_ROLE_GRANTS` in the contracts is this table with every plugin's\n * declared catalog keys added (`assembleOrgRoleGrants`, run by\n * `generate:native-contracts` over each plugin's declarations), which is\n * exactly the set the console's `DEFAULT_ROLE_PERMISSIONS` holds once the\n * plugins have registered.\n *\n * NO IMPORTS, on purpose: the native apps read it through the generated\n * contracts.\n */\n\n/** The four org roles. */\nexport type OrgRoleName = 'owner' | 'admin' | 'editor' | 'viewer'\n\n/** One key of the org permission catalog. */\nexport interface OrgPermissionEntry {\n key: string\n label: string\n description: string\n /** The plugin that declared it; absent for a core key. */\n pluginId?: string\n}\n\n/** The catalog and each role's default grants. */\nexport interface OrgRoleGrants {\n /** Every key, in the order the role editor lists them. */\n permissions: OrgPermissionEntry[]\n /** The keys each role holds when no custom role or per-member override sets them. */\n grants: Record<OrgRoleName, string[]>\n}\n\n/** A key a plugin declares into the catalog, as `PluginOrgPermissionDeclaration` carries it. */\nexport interface OrgPermissionDeclaration {\n key: string\n label: string\n description: string\n roleDefaults: Record<OrgRoleName, boolean>\n}\n\n/** A custom role (`orgs/{orgId}/roles/{roleId}`) or a member's overrides: explicit verdicts per key. */\nexport interface OrgPermissionLayer {\n permissions?: Record<string, boolean>\n}\n\nexport const ORG_ROLE_NAMES: readonly OrgRoleName[] = ['owner', 'admin', 'editor', 'viewer']\n\n/**\n * The core keys, in display order for role editors. Every key here is\n * enforced server-side (`apps/console/specs/org-permissions-are-enforced.spec.ts`).\n */\nexport const CORE_ORG_PERMISSION_ENTRIES: readonly OrgPermissionEntry[] = [\n {\n key: 'org.settings',\n label: 'Organization settings',\n description: 'Rename the organization, change its slug, transfer it.',\n },\n {\n key: 'org.auditLog',\n label: 'Activity & audit log',\n description: 'See the organization activity feed.',\n },\n {\n key: 'billing.view',\n label: 'View billing',\n description: 'See the plan, usage meters, and invoices.',\n },\n {\n key: 'billing.manage',\n label: 'Manage billing',\n description: 'Change plans, buy add-ons, update payment details.',\n },\n {\n key: 'members.manage',\n label: 'Manage members',\n description: 'Invite, remove, and re-role organization members.',\n },\n {\n key: 'hosts.create',\n label: 'Create sites',\n description: 'Create new sites in the organization.',\n },\n {\n key: 'hosts.delete',\n label: 'Delete sites',\n description: 'Delete sites the member can access.',\n },\n {\n key: 'data.manage',\n label: 'Manage data',\n description: 'Create, edit, and delete organization datasets.',\n },\n {\n key: 'marketplace.publish',\n label: 'Publish to marketplace',\n description: 'Publish listings under the organization profile.',\n },\n {\n key: 'plugins.install',\n label: 'Install plugins',\n description: 'Install or remove marketplace plugins.',\n },\n]\n\nconst CORE_KEYS = CORE_ORG_PERMISSION_ENTRIES.map((entry) => entry.key)\n\n/**\n * The core keys each org role holds when nothing refines it: owners and\n * admins hold every core key (owner-only acts like deleting the\n * organization stay role-checked, not permission-checked); editors work on\n * content and see no money or roster controls; viewers read only.\n */\nexport const CORE_ORG_ROLE_GRANTS: Readonly<Record<OrgRoleName, readonly string[]>> = {\n owner: CORE_KEYS,\n admin: CORE_KEYS,\n editor: ['data.manage', 'marketplace.publish', 'plugins.install'],\n viewer: [],\n}\n\n/** The core's catalog and grants; the contracts' value adds the plugins' keys. */\nexport const ORG_ROLE_GRANTS: OrgRoleGrants = {\n permissions: CORE_ORG_PERMISSION_ENTRIES.map((entry) => ({ ...entry })),\n grants: {\n owner: [...CORE_ORG_ROLE_GRANTS.owner],\n admin: [...CORE_ORG_ROLE_GRANTS.admin],\n editor: [...CORE_ORG_ROLE_GRANTS.editor],\n viewer: [...CORE_ORG_ROLE_GRANTS.viewer],\n },\n}\n\n/**\n * The catalog with plugins' declared keys after the core ones, each role\n * holding a declared key when its declaration's `roleDefaults` says so. A\n * declaration naming a core key is refused, as the console's catalog refuses\n * it: the core key keeps its meaning and defaults.\n */\nexport function assembleOrgRoleGrants(\n core: OrgRoleGrants,\n declarations: readonly (OrgPermissionDeclaration & { pluginId?: string })[],\n): OrgRoleGrants {\n const permissions = [...core.permissions]\n const grants = Object.fromEntries(ORG_ROLE_NAMES.map((role) => [role, [...core.grants[role]]])) as Record<\n OrgRoleName,\n string[]\n >\n const taken = new Set(permissions.map((entry) => entry.key))\n for (const declaration of declarations) {\n if (!declaration?.key || taken.has(declaration.key)) continue\n taken.add(declaration.key)\n permissions.push({\n key: declaration.key,\n label: declaration.label,\n description: declaration.description,\n ...(declaration.pluginId ? { pluginId: declaration.pluginId } : {}),\n })\n for (const role of ORG_ROLE_NAMES) {\n if (declaration.roleDefaults?.[role] === true) grants[role].push(declaration.key)\n }\n }\n return { permissions, grants }\n}\n\n/**\n * A member's effective permissions, as the console's `resolveOrgPermissions`\n * answers them: the role's defaults, then the custom role's explicit\n * verdicts (when the member has one), then the member's own overrides,\n * later layers winning key by key, over the catalog's keys only. A missing\n * role reads as viewer; a role the catalog does not know holds nothing.\n */\nexport function rolePermissions(\n catalog: OrgRoleGrants,\n role: string | null | undefined,\n customRole?: OrgPermissionLayer | null,\n overrides?: OrgPermissionLayer | null,\n): Record<string, boolean> {\n const keys = catalog.permissions.map((entry) => entry.key)\n const name = role ?? 'viewer'\n const held = new Set((catalog.grants as Record<string, string[] | undefined>)[name] ?? [])\n const out: Record<string, boolean> = Object.fromEntries(keys.map((key) => [key, held.has(key)]))\n for (const layer of [customRole, overrides]) {\n const values = layer?.permissions\n if (!values) continue\n for (const key of keys) {\n if (typeof values[key] === 'boolean') out[key] = values[key]\n }\n }\n return out\n}\n"],"names":["ORG_ROLE_NAMES","CORE_ORG_PERMISSION_ENTRIES","key","label","description","CORE_KEYS","map","entry","CORE_ORG_ROLE_GRANTS","owner","admin","editor","viewer","ORG_ROLE_GRANTS","permissions","grants","assembleOrgRoleGrants","core","declarations","Object","fromEntries","role","taken","Set","declaration","has","add","push","pluginId","roleDefaults","rolePermissions","catalog","customRole","overrides","keys","name","held","out","layer","values"],"mappings":"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"}
@@ -220,6 +220,14 @@ export declare const SELF_SERVE_PLANS: OrgPlan[];
220
220
  * "free". Revenue for such an org comes from `subscription.customMonthlyUsd`.
221
221
  */
222
222
  export declare function isCustomPricedPlan(plan: OrgPlan | undefined | null): boolean;
223
+ /**
224
+ * Whether a plan sells the Site Care add-on (AGL-3954): every paid self-serve
225
+ * plan, never `free` (no subscription to bill it on) and never a
226
+ * custom-priced plan (Enterprise names it in the agreement instead). An
227
+ * unknown plan string sells nothing. The ONE reading of that rule — the
228
+ * add-on ceiling, the checkout refusal and the Billing card all ask it.
229
+ */
230
+ export declare function planSellsSiteCare(plan: OrgPlan | string | undefined | null): boolean;
223
231
  /** Human plan names — the ONE source every plan badge/label reads. */
224
232
  export declare const PLAN_LABELS: Record<OrgPlan, string>;
225
233
  /**
@@ -235,6 +243,24 @@ export declare const PLAN_LABELS: Record<OrgPlan, string>;
235
243
  * The marketing copy on /pricing is written against that behaviour.
236
244
  */
237
245
  export declare const EVENT_CALENDAR_ADDON_MONTHLY_USD = 9;
246
+ /**
247
+ * Site Care add-on (AGL-3954): $49/mo per organization, the managed-website
248
+ * service. It buys staff time, not capacity: small changes to the owner's
249
+ * existing site (hours, prices, photos, a staff member, a seasonal banner, a
250
+ * section on an existing page), up to about one hour of work a month, done
251
+ * within two business days, minutes logged and no rollover. New pages, new
252
+ * forms, redesigns, brand work, photography, whole-site copy and ads are
253
+ * quoted separately, and it never raises a plan limit — a 26th page or a
254
+ * second site is still an upgrade.
255
+ *
256
+ * Flat across plans, like the Event Calendar, because the work it pays for
257
+ * is the same hour whichever tier the site is on; the yearly price is ×12
258
+ * with no discount, as every add-on's is. Sold on every paid self-serve plan
259
+ * and never on Free (no subscription to carry it) or Enterprise (quoted per
260
+ * deal) — `planSellsSiteCare` is that rule. `resolveOrgEntitlements` flips
261
+ * the org-wide `features.siteCare` from any purchased quantity >= 1.
262
+ */
263
+ export declare const SITE_CARE_ADDON_MONTHLY_USD = 49;
238
264
  /**
239
265
  * POS Pro register add-on (AGL-329): $89/mo per extra register/location
240
266
  * (Shopify POS Pro parity). Purchased add-ons land as a per-org
@@ -762,6 +788,12 @@ export declare function orgListPriceMonthlyUsd(org: Partial<AglynOrgBilling> | n
762
788
  * `NaN` or a negative is none.
763
789
  */
764
790
  export declare function aiAddonUnits(addons: OrgSeatAddons | null | undefined): 0 | 1;
791
+ /**
792
+ * How many Site Care add-ons a purchase map counts as: 0 or 1 (AGL-3954).
793
+ * Org-wide like the Aglyn AI add-on, so a quantity above one is one
794
+ * purchase, and a non-number, `NaN` or a negative is none.
795
+ */
796
+ export declare function siteCareUnits(addons: OrgSeatAddons | null | undefined): 0 | 1;
765
797
  /**
766
798
  * A list price net of a discount (AGL-1105). Percentage discounts scale the
767
799
  * whole bill; fixed discounts subtract a flat USD amount. Never below 0, and
@@ -1458,6 +1490,14 @@ export declare function resolveEffectivePlan(org: Partial<AglynOrgBilling> | nul
1458
1490
  * together rather than leaving a rate on a band that has gone.
1459
1491
  */
1460
1492
  export declare function hasAiAddon(org: Partial<AglynOrgBilling> | null | undefined): boolean;
1493
+ /**
1494
+ * Whether the org's Site Care add-on currently applies (AGL-3954): bought,
1495
+ * and on a subscription that is still paying for it, so a dead subscription
1496
+ * reads false here exactly as it drops `features.siteCare`. The reader for
1497
+ * surfaces that ask about the purchase rather than the resolved feature —
1498
+ * the staff org page's chip, the request intake.
1499
+ */
1500
+ export declare function hasSiteCare(org: Partial<AglynOrgBilling> | null | undefined): boolean;
1461
1501
  /**
1462
1502
  * Numeric entitlement keys that were REMOVED from `PLAN_ENTITLEMENTS` and
1463
1503
  * must never be resolved again from a stored override (AGL-2133).
@@ -1504,7 +1544,7 @@ export declare const PRICE_ENTITLEMENT_KEYS: ReadonlySet<string>;
1504
1544
  * per-key overrides applied (features merge key-by-key too), then
1505
1545
  * purchased add-ons stacked on top (AGL-524): `seatAddons.hosts` raises
1506
1546
  * `hostLimit`, `seatAddons.eventCalendar` switches the `eventCalendar`
1507
- * feature on, and every seat add-on a plugin declared through
1547
+ * feature on, `seatAddons.siteCare` switches `siteCare` on, and every seat add-on a plugin declared through
1508
1548
  * `registerPluginEntitlements` (AGL-2940) widens the quota it names by its
1509
1549
  * per-plan figure per unit and switches its features on — the Aglyn AI
1510
1550
  * add-on (AGL-2896) is the first such declaration. (Seat/dataset add-ons
@@ -259,6 +259,10 @@ export const PLAN_ENTITLEMENTS = {
259
259
  siteExport: false,
260
260
  multilingual: false,
261
261
  eventCalendar: false,
262
+ // Site Care (AGL-3954) is never granted by a tier, on this plan or any
263
+ // other: it is the managed-website add-on, switched on only by a live
264
+ // `seatAddons.siteCare` purchase (or a staff override), never by a row.
265
+ siteCare: false,
262
266
  redirects: false,
263
267
  screenAnalytics: false,
264
268
  /**
@@ -377,6 +381,7 @@ export const PLAN_ENTITLEMENTS = {
377
381
  siteExport: false,
378
382
  multilingual: false,
379
383
  eventCalendar: false,
384
+ siteCare: false,
380
385
  redirects: true,
381
386
  screenAnalytics: false,
382
387
  mediaCdn: true,
@@ -490,6 +495,7 @@ export const PLAN_ENTITLEMENTS = {
490
495
  siteExport: true,
491
496
  multilingual: false,
492
497
  eventCalendar: false,
498
+ siteCare: false,
493
499
  redirects: true,
494
500
  screenAnalytics: true,
495
501
  mediaCdn: true,
@@ -560,6 +566,7 @@ export const PLAN_ENTITLEMENTS = {
560
566
  siteExport: true,
561
567
  multilingual: true,
562
568
  eventCalendar: false,
569
+ siteCare: false,
563
570
  redirects: true,
564
571
  screenAnalytics: true,
565
572
  mediaCdn: true,
@@ -633,6 +640,7 @@ export const PLAN_ENTITLEMENTS = {
633
640
  siteExport: true,
634
641
  multilingual: true,
635
642
  eventCalendar: false,
643
+ siteCare: false,
636
644
  redirects: true,
637
645
  screenAnalytics: true,
638
646
  mediaCdn: true,
@@ -703,6 +711,7 @@ export const PLAN_ENTITLEMENTS = {
703
711
  siteExport: true,
704
712
  multilingual: true,
705
713
  eventCalendar: false,
714
+ siteCare: false,
706
715
  redirects: true,
707
716
  screenAnalytics: true,
708
717
  mediaCdn: true,
@@ -777,6 +786,7 @@ export const PLAN_ENTITLEMENTS = {
777
786
  siteExport: true,
778
787
  multilingual: true,
779
788
  eventCalendar: false,
789
+ siteCare: false,
780
790
  redirects: true,
781
791
  screenAnalytics: true,
782
792
  mediaCdn: true,
@@ -888,6 +898,7 @@ export const PLAN_ENTITLEMENTS = {
888
898
  multilingual: true,
889
899
  // Event Calendar stays an add-on purchase, as on every other tier.
890
900
  eventCalendar: false,
901
+ siteCare: false,
891
902
  redirects: true,
892
903
  screenAnalytics: true,
893
904
  mediaCdn: true,
@@ -955,6 +966,17 @@ fillPluginPlanEntitlements(PLAN_ENTITLEMENTS);
955
966
  */ export function isCustomPricedPlan(plan) {
956
967
  return plan === 'enterprise';
957
968
  }
969
+ /**
970
+ * Whether a plan sells the Site Care add-on (AGL-3954): every paid self-serve
971
+ * plan, never `free` (no subscription to bill it on) and never a
972
+ * custom-priced plan (Enterprise names it in the agreement instead). An
973
+ * unknown plan string sells nothing. The ONE reading of that rule — the
974
+ * add-on ceiling, the checkout refusal and the Billing card all ask it.
975
+ */ export function planSellsSiteCare(plan) {
976
+ if (!plan || plan === 'free') return false;
977
+ if (isCustomPricedPlan(plan)) return false;
978
+ return SELF_SERVE_PLANS.includes(plan);
979
+ }
958
980
  /** Human plan names — the ONE source every plan badge/label reads. */ export const PLAN_LABELS = {
959
981
  free: 'Free',
960
982
  starter: 'Starter',
@@ -977,6 +999,23 @@ fillPluginPlanEntitlements(PLAN_ENTITLEMENTS);
977
999
  * boolean from any quantity >= 1. One purchase covers every host in the org.
978
1000
  * The marketing copy on /pricing is written against that behaviour.
979
1001
  */ export const EVENT_CALENDAR_ADDON_MONTHLY_USD = 9;
1002
+ /**
1003
+ * Site Care add-on (AGL-3954): $49/mo per organization, the managed-website
1004
+ * service. It buys staff time, not capacity: small changes to the owner's
1005
+ * existing site (hours, prices, photos, a staff member, a seasonal banner, a
1006
+ * section on an existing page), up to about one hour of work a month, done
1007
+ * within two business days, minutes logged and no rollover. New pages, new
1008
+ * forms, redesigns, brand work, photography, whole-site copy and ads are
1009
+ * quoted separately, and it never raises a plan limit — a 26th page or a
1010
+ * second site is still an upgrade.
1011
+ *
1012
+ * Flat across plans, like the Event Calendar, because the work it pays for
1013
+ * is the same hour whichever tier the site is on; the yearly price is ×12
1014
+ * with no discount, as every add-on's is. Sold on every paid self-serve plan
1015
+ * and never on Free (no subscription to carry it) or Enterprise (quoted per
1016
+ * deal) — `planSellsSiteCare` is that rule. `resolveOrgEntitlements` flips
1017
+ * the org-wide `features.siteCare` from any purchased quantity >= 1.
1018
+ */ export const SITE_CARE_ADDON_MONTHLY_USD = 49;
980
1019
  /**
981
1020
  * POS Pro register add-on (AGL-329): $89/mo per extra register/location
982
1021
  * (Shopify POS Pro parity). Purchased add-ons land as a per-org
@@ -1582,7 +1621,7 @@ function trimmedOrNull(value) {
1582
1621
  const annual = (org == null ? void 0 : (_org_subscription1 = org.subscription) == null ? void 0 : _org_subscription1.interval) === 'year';
1583
1622
  const addons = (_ref = org == null ? void 0 : org.seatAddons) != null ? _ref : {};
1584
1623
  const seats = (quantity, price)=>Math.max(0, quantity != null ? quantity : 0) * (price != null ? price : 0);
1585
- return (annual ? pricing.basePriceAnnualMonthlyUsd : pricing.basePriceMonthlyUsd) + seats(addons.managers, pricing.extraSeatMonthlyUsd) + seats(addons.members, pricing.extraCollaboratorMonthlyUsd) + seats(addons.datasets, pricing.extraDatasetMonthlyUsd) + seats(addons.hosts, pricing.extraHostMonthlyUsd) + seats(addons.posRegisters, POS_REGISTER_ADDON_MONTHLY_USD) + seats(addons.eventCalendar, EVENT_CALENDAR_ADDON_MONTHLY_USD) + // A toggle, not a quantity: one purchase covers the org, so a stored
1624
+ return (annual ? pricing.basePriceAnnualMonthlyUsd : pricing.basePriceMonthlyUsd) + seats(addons.managers, pricing.extraSeatMonthlyUsd) + seats(addons.members, pricing.extraCollaboratorMonthlyUsd) + seats(addons.datasets, pricing.extraDatasetMonthlyUsd) + seats(addons.hosts, pricing.extraHostMonthlyUsd) + seats(addons.posRegisters, POS_REGISTER_ADDON_MONTHLY_USD) + seats(addons.eventCalendar, EVENT_CALENDAR_ADDON_MONTHLY_USD) + seats(siteCareUnits(addons), SITE_CARE_ADDON_MONTHLY_USD) + // A toggle, not a quantity: one purchase covers the org, so a stored
1586
1625
  // quantity above one bills once.
1587
1626
  seats(aiAddonUnits(addons), pricing.aiAddonMonthlyUsd);
1588
1627
  }
@@ -1596,6 +1635,15 @@ function trimmedOrNull(value) {
1596
1635
  const quantity = Number((_ref = addons == null ? void 0 : addons.aiAddon) != null ? _ref : 0);
1597
1636
  return Number.isFinite(quantity) && quantity >= 1 ? 1 : 0;
1598
1637
  }
1638
+ /**
1639
+ * How many Site Care add-ons a purchase map counts as: 0 or 1 (AGL-3954).
1640
+ * Org-wide like the Aglyn AI add-on, so a quantity above one is one
1641
+ * purchase, and a non-number, `NaN` or a negative is none.
1642
+ */ export function siteCareUnits(addons) {
1643
+ var _ref;
1644
+ const quantity = Number((_ref = addons == null ? void 0 : addons.siteCare) != null ? _ref : 0);
1645
+ return Number.isFinite(quantity) && quantity >= 1 ? 1 : 0;
1646
+ }
1599
1647
  /**
1600
1648
  * A list price net of a discount (AGL-1105). Percentage discounts scale the
1601
1649
  * whole bill; fixed discounts subtract a flat USD amount. Never below 0, and
@@ -2401,6 +2449,15 @@ function resolvePlan(org) {
2401
2449
  */ export function hasAiAddon(org) {
2402
2450
  return aiAddonUnits(resolvePurchasedAddons(org)) === 1;
2403
2451
  }
2452
+ /**
2453
+ * Whether the org's Site Care add-on currently applies (AGL-3954): bought,
2454
+ * and on a subscription that is still paying for it, so a dead subscription
2455
+ * reads false here exactly as it drops `features.siteCare`. The reader for
2456
+ * surfaces that ask about the purchase rather than the resolved feature —
2457
+ * the staff org page's chip, the request intake.
2458
+ */ export function hasSiteCare(org) {
2459
+ return siteCareUnits(resolvePurchasedAddons(org)) === 1;
2460
+ }
2404
2461
  /**
2405
2462
  * Numeric entitlement keys that were REMOVED from `PLAN_ENTITLEMENTS` and
2406
2463
  * must never be resolved again from a stored override (AGL-2133).
@@ -2484,7 +2541,7 @@ function resolvePlan(org) {
2484
2541
  * per-key overrides applied (features merge key-by-key too), then
2485
2542
  * purchased add-ons stacked on top (AGL-524): `seatAddons.hosts` raises
2486
2543
  * `hostLimit`, `seatAddons.eventCalendar` switches the `eventCalendar`
2487
- * feature on, and every seat add-on a plugin declared through
2544
+ * feature on, `seatAddons.siteCare` switches `siteCare` on, and every seat add-on a plugin declared through
2488
2545
  * `registerPluginEntitlements` (AGL-2940) widens the quota it names by its
2489
2546
  * per-plan figure per unit and switches its features on — the Aglyn AI
2490
2547
  * add-on (AGL-2896) is the first such declaration. (Seat/dataset add-ons
@@ -2589,17 +2646,22 @@ function resolvePlan(org) {
2589
2646
  const purchased = resolvePurchasedAddons(org);
2590
2647
  const extraHosts = Math.max(0, (_purchased_hosts = purchased.hosts) != null ? _purchased_hosts : 0);
2591
2648
  const eventCalendar = ((_purchased_eventCalendar = purchased.eventCalendar) != null ? _purchased_eventCalendar : 0) >= 1;
2649
+ const siteCare = siteCareUnits(purchased) === 1;
2592
2650
  // A declared add-on's quota is added AFTER the per-org override, so a
2593
2651
  // contracted figure and a purchased add-on stack the way a raised
2594
2652
  // `hostLimit` and purchased sites do. The per-unit figure is the PLAN's,
2595
2653
  // read off the effective plan rather than the stored one, so a dead
2596
2654
  // subscription that resolved to free adds free's figure.
2597
2655
  const folded = foldPluginSeatAddons(resolved, purchased, resolvePlan(org));
2598
- if (!extraHosts && !eventCalendar && folded === resolved) return resolved;
2656
+ if (!extraHosts && !eventCalendar && !siteCare && folded === resolved) {
2657
+ return resolved;
2658
+ }
2599
2659
  return _extends({}, folded, {
2600
2660
  hostLimit: folded.hostLimit + extraHosts,
2601
2661
  features: _extends({}, folded.features, eventCalendar ? {
2602
2662
  eventCalendar: true
2663
+ } : {}, siteCare ? {
2664
+ siteCare: true
2603
2665
  } : {})
2604
2666
  });
2605
2667
  }