@aglyn/aglyn 1.0.0-beta.234 → 1.0.0-beta.236

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 (87) hide show
  1. package/package.json +11 -11
  2. package/src/lib/app-utils/activity-labels.d.ts +117 -0
  3. package/src/lib/app-utils/activity-labels.js +343 -0
  4. package/src/lib/app-utils/activity-labels.js.map +1 -0
  5. package/src/lib/app-utils/admin-audit-index.d.ts +11 -0
  6. package/src/lib/app-utils/admin-audit-index.js +12 -1
  7. package/src/lib/app-utils/admin-audit-index.js.map +1 -1
  8. package/src/lib/app-utils/advertising-consent.d.ts +111 -0
  9. package/src/lib/app-utils/advertising-consent.js +216 -0
  10. package/src/lib/app-utils/advertising-consent.js.map +1 -0
  11. package/src/lib/app-utils/advertising-events.d.ts +98 -0
  12. package/src/lib/app-utils/advertising-events.js +340 -0
  13. package/src/lib/app-utils/advertising-events.js.map +1 -0
  14. package/src/lib/app-utils/advertising-tag-mounts.js +15 -8
  15. package/src/lib/app-utils/advertising-tag-mounts.js.map +1 -1
  16. package/src/lib/app-utils/advertising-tags.d.ts +54 -8
  17. package/src/lib/app-utils/advertising-tags.js +126 -28
  18. package/src/lib/app-utils/advertising-tags.js.map +1 -1
  19. package/src/lib/app-utils/analytics-events.d.ts +15 -86
  20. package/src/lib/app-utils/analytics-events.js +21 -6
  21. package/src/lib/app-utils/analytics-events.js.map +1 -1
  22. package/src/lib/app-utils/consent-banner-ui.d.ts +14 -0
  23. package/src/lib/app-utils/consent-banner-ui.js +23 -2
  24. package/src/lib/app-utils/consent-banner-ui.js.map +1 -1
  25. package/src/lib/app-utils/docs-help-section-excerpt-text.d.ts +14 -0
  26. package/src/lib/app-utils/docs-help-section-excerpt-text.js +31 -0
  27. package/src/lib/app-utils/docs-help-section-excerpt-text.js.map +1 -0
  28. package/src/lib/app-utils/docs-help-section-excerpt.d.ts +13 -0
  29. package/src/lib/app-utils/docs-help-section-excerpt.js +37 -0
  30. package/src/lib/app-utils/docs-help-section-excerpt.js.map +1 -0
  31. package/src/lib/app-utils/docs-help-sections.generated.d.ts +31 -0
  32. package/src/lib/app-utils/docs-help-sections.generated.js +660 -0
  33. package/src/lib/app-utils/docs-help-sections.generated.js.map +1 -0
  34. package/src/lib/app-utils/docs-help.d.ts +16 -4
  35. package/src/lib/app-utils/docs-help.generated.d.ts +171 -34
  36. package/src/lib/app-utils/docs-help.generated.js +1104 -3
  37. package/src/lib/app-utils/docs-help.generated.js.map +1 -1
  38. package/src/lib/app-utils/docs-help.js +25 -6
  39. package/src/lib/app-utils/docs-help.js.map +1 -1
  40. package/src/lib/app-utils/docs-index.generated.js +1008 -91
  41. package/src/lib/app-utils/docs-index.generated.js.map +1 -1
  42. package/src/lib/app-utils/health-report.js +12 -0
  43. package/src/lib/app-utils/health-report.js.map +1 -1
  44. package/src/lib/app-utils/plugin-release-flags.generated.d.ts +1 -1
  45. package/src/lib/app-utils/plugin-release-flags.generated.js +7 -1
  46. package/src/lib/app-utils/plugin-release-flags.generated.js.map +1 -1
  47. package/src/lib/app-utils/realm-host-surface.generated.js +1 -0
  48. package/src/lib/app-utils/realm-host-surface.generated.js.map +1 -1
  49. package/src/lib/app-utils/variables.d.ts +2 -0
  50. package/src/lib/app-utils/variables.js +3 -0
  51. package/src/lib/app-utils/variables.js.map +1 -1
  52. package/src/lib/app-utils/visitor-consent.d.ts +34 -0
  53. package/src/lib/app-utils/visitor-consent.js +49 -2
  54. package/src/lib/app-utils/visitor-consent.js.map +1 -1
  55. package/src/lib/app-utils/where-used-summary.d.ts +41 -0
  56. package/src/lib/app-utils/where-used-summary.js +33 -0
  57. package/src/lib/app-utils/where-used-summary.js.map +1 -0
  58. package/src/lib/app-utils/where-used.d.ts +2 -20
  59. package/src/lib/app-utils/where-used.js +13 -12
  60. package/src/lib/app-utils/where-used.js.map +1 -1
  61. package/src/lib/plugin-manager/first-party-plugins.generated.d.ts +7 -0
  62. package/src/lib/plugin-manager/first-party-plugins.generated.js +166 -2
  63. package/src/lib/plugin-manager/first-party-plugins.generated.js.map +1 -1
  64. package/src/lib/plugin-manager/plugin-activity-actions.d.ts +51 -0
  65. package/src/lib/plugin-manager/plugin-activity-actions.js +43 -0
  66. package/src/lib/plugin-manager/plugin-activity-actions.js.map +1 -1
  67. package/src/lib/plugin-manager/plugin-advertising-conversions.d.ts +84 -0
  68. package/src/lib/plugin-manager/plugin-advertising-conversions.js +86 -0
  69. package/src/lib/plugin-manager/plugin-advertising-conversions.js.map +1 -0
  70. package/src/lib/plugin-manager/plugin-config.d.ts +23 -0
  71. package/src/lib/plugin-manager/plugin-config.js.map +1 -1
  72. package/src/lib/plugin-manager/plugin-local-deliveries.d.ts +161 -0
  73. package/src/lib/plugin-manager/plugin-local-deliveries.js +46 -0
  74. package/src/lib/plugin-manager/plugin-local-deliveries.js.map +1 -0
  75. package/src/lib/plugin-manager/plugin-order-email-copies.d.ts +93 -0
  76. package/src/lib/plugin-manager/plugin-order-email-copies.js +104 -0
  77. package/src/lib/plugin-manager/plugin-order-email-copies.js.map +1 -0
  78. package/src/lib/plugin-manager/plugin-shipment-records.d.ts +7 -0
  79. package/src/lib/plugin-manager/plugin-shipment-records.js.map +1 -1
  80. package/src/lib/plugin-manager/plugin-site-csp.d.ts +58 -0
  81. package/src/lib/plugin-manager/plugin-site-csp.js +103 -0
  82. package/src/lib/plugin-manager/plugin-site-csp.js.map +1 -0
  83. package/src/lib/plugin-manager/realm-host-aglyn.generated.js +1 -0
  84. package/src/lib/plugin-manager/realm-host-aglyn.generated.js.map +1 -1
  85. package/src/lib/plugin-manager/site-page-hooks.d.ts +13 -0
  86. package/src/lib/plugin-manager/site-page-hooks.js +31 -0
  87. package/src/lib/plugin-manager/site-page-hooks.js.map +1 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aglyn/aglyn",
3
- "version": "1.0.0-beta.234",
3
+ "version": "1.0.0-beta.236",
4
4
  "license": "Apache-2.0",
5
5
  "homepage": "https://aglyn.com",
6
6
  "repository": {
@@ -37,16 +37,16 @@
37
37
  "./package.json": "./package.json"
38
38
  },
39
39
  "dependencies": {
40
- "@aglyn/shared-data-enums": "1.0.0-beta.234",
41
- "@aglyn/shared-data-mdi": "1.0.0-beta.234",
42
- "@aglyn/shared-data-types": "1.0.0-beta.234",
43
- "@aglyn/shared-util-email": "1.0.0-beta.234",
44
- "@aglyn/shared-util-first-touch": "1.0.0-beta.234",
45
- "@aglyn/shared-util-http": "1.0.0-beta.234",
46
- "@aglyn/shared-util-logger": "1.0.0-beta.234",
47
- "@aglyn/shared-util-timestamp": "1.0.0-beta.234",
48
- "@aglyn/shared-util-tools": "1.0.0-beta.234",
49
- "@aglyn/shared-util-vendor": "1.0.0-beta.234",
40
+ "@aglyn/shared-data-enums": "1.0.0-beta.236",
41
+ "@aglyn/shared-data-mdi": "1.0.0-beta.236",
42
+ "@aglyn/shared-data-types": "1.0.0-beta.236",
43
+ "@aglyn/shared-util-email": "1.0.0-beta.236",
44
+ "@aglyn/shared-util-first-touch": "1.0.0-beta.236",
45
+ "@aglyn/shared-util-http": "1.0.0-beta.236",
46
+ "@aglyn/shared-util-logger": "1.0.0-beta.236",
47
+ "@aglyn/shared-util-timestamp": "1.0.0-beta.236",
48
+ "@aglyn/shared-util-tools": "1.0.0-beta.236",
49
+ "@aglyn/shared-util-vendor": "1.0.0-beta.236",
50
50
  "@data-driven-forms/react-form-renderer": "^4.2.0",
51
51
  "@msgpack/msgpack": "^3.1.3",
52
52
  "@types/unist": "^3.0.3",
@@ -0,0 +1,117 @@
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
+ * ONE LABEL MAP FOR EVERY ACTIVITY AND AUDIT LIST (AGL-3660).
19
+ *
20
+ * Two logs feed the console's lists. The activity logs
21
+ * (`orgs/{id}/activity`, `hosts/{id}/activity`) store a prose sentence or a
22
+ * plugin's code plus a `{ type, id, name }` target. The staff audit trail
23
+ * (`adminAudit`) stores a dotted code (`ai.job.output`, `org.override`) and
24
+ * a Firestore PATH as its target (`orgs/abc/aiJobs/xyz`). The staff tables
25
+ * printed both raw, so a reader saw `ai.job.output` next to
26
+ * `orgs/9fK…/aiJobs/Qe2…` and had to know the schema to read their own
27
+ * audit trail.
28
+ *
29
+ * Every list now draws its words from here: an action as a sentence
30
+ * (`Created page Home with Aglyn AI`), a target as the site and the item,
31
+ * and — for an audit row — why, the credits it spent and what came of it.
32
+ * The raw code and path are kept on the description, for a tooltip and for
33
+ * the staff details dialog, and never as the visible text.
34
+ */
35
+ import { type ActivityEntryLike, type ActivityTargetLike } from './activity-presenter';
36
+ /** What a list row and the details dialog show for one entry. */
37
+ export interface ActivityDescription {
38
+ /** The act, as a sentence. Never a code. */
39
+ action: string;
40
+ /** What it was done to, in words: the site and the item. Never a path. */
41
+ target: string;
42
+ /** Why it was done, when the writer recorded a reason. */
43
+ why: string | null;
44
+ /** AI credits it spent, when it spent any. */
45
+ credits: number | null;
46
+ /** What came of it, when the writer recorded an outcome. */
47
+ result: string | null;
48
+ /** The stored code, when the action was one — for a tooltip and staff. */
49
+ code: string | null;
50
+ /** The stored target path (audit) or `type/id` (activity) — staff only. */
51
+ path: string | null;
52
+ /** The organization the entry concerns, when it names one. */
53
+ orgId: string | null;
54
+ /** The site the entry concerns, when it names one. */
55
+ hostId: string | null;
56
+ /** The plugin job behind the entry (an AI job), when there is one. */
57
+ jobId: string | null;
58
+ /** The account the entry concerns, when it names one. */
59
+ uid: string | null;
60
+ }
61
+ /** Names a route resolved for the ids an entry carries. */
62
+ export interface ActivityNames {
63
+ /** Organization name by org id. */
64
+ orgs?: Readonly<Record<string, string | null | undefined>>;
65
+ /** Site name by host id. */
66
+ hosts?: Readonly<Record<string, string | null | undefined>>;
67
+ /** An account's address (or name) by uid. */
68
+ users?: Readonly<Record<string, string | null | undefined>>;
69
+ }
70
+ /** `screen` → `page`, `Home` → `page Home`: the noun a sentence uses. */
71
+ export declare function activityTargetPhrase(target: ActivityTargetLike | null | undefined): string;
72
+ /**
73
+ * An activity row's action as a sentence about its target. A plugin code
74
+ * with a declared sentence fills it (`Created {target} with Aglyn AI`); any
75
+ * other code reads as its label, and a prose action as itself.
76
+ */
77
+ export declare function activityActionSentence(action: string | undefined, target?: ActivityTargetLike | null): string;
78
+ /**
79
+ * A one-column feed's line: the sentence when the code declares one, else
80
+ * the action with its target's name (`Saved the screen — Home`).
81
+ */
82
+ export declare function activityRowText(entry: ActivityEntryLike): string;
83
+ /** Whether a stored action is a dotted code rather than a sentence. */
84
+ export declare function isActivityCode(action: unknown): action is string;
85
+ export declare const STAFF_AUDIT_ACTION_LABELS: Readonly<Record<string, string>>;
86
+ /** A code nobody named, as words: `billing.invoice.paid` → `Billing: invoice paid`. */
87
+ export declare function humanizeActivityCode(code: string): string;
88
+ /** What a staff audit code reads as, everywhere it is shown. */
89
+ export declare function staffAuditActionLabel(action: string | null | undefined): string;
90
+ /** The stored audit row, read defensively. */
91
+ export interface StaffAuditEntryLike {
92
+ action?: string | null;
93
+ target?: string | null;
94
+ subjectUid?: string | null;
95
+ reason?: string | null;
96
+ note?: string | null;
97
+ /** The state the act left; AI rows carry `{ label, hostId, credits }`. */
98
+ after?: Record<string, unknown> | null;
99
+ }
100
+ /** What an audit act did, in words, and the words it was about. */
101
+ export declare function describeStaffAudit(entry: StaffAuditEntryLike, names?: ActivityNames): ActivityDescription;
102
+ /** A stored activity row, read defensively, with where it was read from. */
103
+ export interface ActivityRowLike {
104
+ action?: string | null;
105
+ target?: (ActivityTargetLike & {
106
+ jobId?: string;
107
+ credits?: number;
108
+ }) | null;
109
+ /** `host` or `org`: which log the row came from. */
110
+ scopeType?: string;
111
+ scopeId?: string;
112
+ }
113
+ /**
114
+ * An activity row as the lists show it. Where is the site when the row came
115
+ * from a site's log, else the organization.
116
+ */
117
+ export declare function describeActivity(entry: ActivityRowLike, names?: ActivityNames): ActivityDescription;
@@ -0,0 +1,343 @@
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
+ * ONE LABEL MAP FOR EVERY ACTIVITY AND AUDIT LIST (AGL-3660).
18
+ *
19
+ * Two logs feed the console's lists. The activity logs
20
+ * (`orgs/{id}/activity`, `hosts/{id}/activity`) store a prose sentence or a
21
+ * plugin's code plus a `{ type, id, name }` target. The staff audit trail
22
+ * (`adminAudit`) stores a dotted code (`ai.job.output`, `org.override`) and
23
+ * a Firestore PATH as its target (`orgs/abc/aiJobs/xyz`). The staff tables
24
+ * printed both raw, so a reader saw `ai.job.output` next to
25
+ * `orgs/9fK…/aiJobs/Qe2…` and had to know the schema to read their own
26
+ * audit trail.
27
+ *
28
+ * Every list now draws its words from here: an action as a sentence
29
+ * (`Created page Home with Aglyn AI`), a target as the site and the item,
30
+ * and — for an audit row — why, the credits it spent and what came of it.
31
+ * The raw code and path are kept on the description, for a tooltip and for
32
+ * the staff details dialog, and never as the visible text.
33
+ */ import { activityActionLabel, activityPrimaryText, activityTypeLabel } from "./activity-presenter.js";
34
+ import { orgOverrideReasonSummary } from "./org-override-reason.js";
35
+ import { isPluginJobTargetType, pluginActivityActionSentence, pluginActivityTargetLabel, pluginStaffAuditActionLabel, pluginStaffAuditCollection, pluginStaffAuditDescribe } from "../plugin-manager/plugin-activity-actions.js";
36
+ /** `screen` → `page`, `Home` → `page Home`: the noun a sentence uses. */ export function activityTargetPhrase(target) {
37
+ var _target_name;
38
+ const noun = activityTypeLabel(target == null ? void 0 : target.type);
39
+ const lower = noun === 'Item' ? 'item' : noun.charAt(0).toLowerCase() + noun.slice(1);
40
+ const name = target == null ? void 0 : (_target_name = target.name) == null ? void 0 : _target_name.trim();
41
+ return name ? `${lower} ${name}` : lower;
42
+ }
43
+ /**
44
+ * An activity row's action as a sentence about its target. A plugin code
45
+ * with a declared sentence fills it (`Created {target} with Aglyn AI`); any
46
+ * other code reads as its label, and a prose action as itself.
47
+ */ export function activityActionSentence(action, target) {
48
+ var _ref;
49
+ const stored = (_ref = action == null ? void 0 : action.trim()) != null ? _ref : '';
50
+ const sentence = pluginActivityActionSentence(stored);
51
+ if (sentence) return sentence.replace('{target}', activityTargetPhrase(target));
52
+ return activityActionLabel(stored);
53
+ }
54
+ /**
55
+ * A one-column feed's line: the sentence when the code declares one, else
56
+ * the action with its target's name (`Saved the screen — Home`).
57
+ */ export function activityRowText(entry) {
58
+ var _ref;
59
+ var _entry_action;
60
+ const stored = (_ref = (_entry_action = entry.action) == null ? void 0 : _entry_action.trim()) != null ? _ref : '';
61
+ return pluginActivityActionSentence(stored) ? activityActionSentence(stored, entry.target) : activityPrimaryText(entry);
62
+ }
63
+ /** Whether a stored action is a dotted code rather than a sentence. */ export function isActivityCode(action) {
64
+ return typeof action === 'string' && /^[a-z][\w-]*(\.[\w-]+)+$/i.test(action.trim());
65
+ }
66
+ /*==========================================
67
+ * THE STAFF AUDIT TRAIL'S WORDS.
68
+ *
69
+ * Every code core's doors write. A plugin's doors declare their own through
70
+ * `staffAuditLabels` (the AI plugin's `ai.job.*`), and a code neither knows
71
+ * is humanized from its segments rather than shown raw, so a new writer
72
+ * reads as `Billing: invoice paid` until somebody names it properly.
73
+ *==========================================*/ export const STAFF_AUDIT_ACTION_LABELS = {
74
+ 'account.closed.self': 'Closed their own account',
75
+ 'account.exported.self': 'Exported their own account data',
76
+ 'ai-usage.exported': 'Exported AI usage',
77
+ 'billing.assistOverage.setCap': 'Set the AI overage ceiling',
78
+ 'billing.assistOverage.setHardCap': 'Set the AI stop-at-band switch',
79
+ 'billing.autoLocked': 'Locked automatically for billing',
80
+ 'billing.collaboratorAllocation': 'Changed collaborator seats',
81
+ 'billing.dispute.opened': 'Payment dispute opened',
82
+ 'billing.disputeClosed': 'Payment dispute closed',
83
+ 'billing.disputeOpened': 'Payment dispute opened',
84
+ 'billing.disputeUnattributed': 'Unattributed payment dispute',
85
+ 'billing.invoice': 'Invoice event',
86
+ 'billing.invoice.closed': 'Invoice closed',
87
+ 'billing.invoice.failed': 'Invoice payment failed',
88
+ 'billing.invoice.paid': 'Invoice paid',
89
+ 'billing.manage': 'Opened billing management',
90
+ 'billing.orphanedSubscription': 'Found a subscription with no workspace',
91
+ 'billing.paymentFailed': 'Payment failed',
92
+ 'billing.paymentMethod.changed': 'Changed the payment method',
93
+ 'billing.platformDisputeLost': 'Lost a payment dispute',
94
+ 'billing.platformInvoiceUncollectible': 'Invoice marked uncollectible',
95
+ 'billing.registerAllocation': 'Changed register allocation',
96
+ 'billing.storageOverage.setCap': 'Set the storage overage ceiling',
97
+ 'billing.subscriptionCanceled': 'Subscription canceled',
98
+ 'billing.usage': 'Recorded usage',
99
+ 'billing.usageBudget.set': 'Set the usage budget',
100
+ 'billing.view': 'Viewed billing',
101
+ 'billing.webhookInert': 'Ignored a billing webhook',
102
+ 'billing.webhookSignatureRejected': 'Rejected a billing webhook signature',
103
+ 'broadcast.send': 'Sent a broadcast',
104
+ 'contact.phone.erased': 'Erased a phone number',
105
+ 'contact.suppression.recorded': 'Added a contact suppression',
106
+ 'contact.suppression.released': 'Released a contact suppression',
107
+ 'coupon.create': 'Created a coupon',
108
+ 'coupon.promotion_code.update': 'Updated a promotion code',
109
+ 'data.transfer.export': 'Exported data',
110
+ 'data.transfer.plan': 'Planned a data transfer',
111
+ 'email.history-imported': 'Imported email history',
112
+ 'email.message-viewed': 'Viewed an email message',
113
+ 'email.sending-domains.reap': 'Removed unused sending domains',
114
+ 'email.suppression.release': 'Released an email suppression',
115
+ 'emailSendRate.update': 'Changed the email send rate',
116
+ 'erasure.runBatch': 'Ran an erasure batch',
117
+ 'erasures.replayed': 'Replayed erasures',
118
+ 'firestore.export': 'Exported the database',
119
+ 'firstPartyHosts.update': 'Changed first-party sites',
120
+ 'flags.update': 'Changed feature flags',
121
+ 'freeWorkspaceCap.update': 'Changed the free workspace cap',
122
+ 'host.deleted': 'Deleted a site',
123
+ 'host.domain.released': 'Released a domain',
124
+ 'host.reattach-domain': 'Reattached a domain',
125
+ 'host.set-subdomain': 'Changed a site address',
126
+ 'host.transfer': 'Transferred a site',
127
+ 'lockdown.lock': 'Locked the workspace down',
128
+ 'lockdown.payouts-pause': 'Paused payouts',
129
+ 'lockdown.payouts-restore': 'Restored payouts',
130
+ 'lockdown.renewals-pause': 'Paused renewals',
131
+ 'lockdown.renewals-resume': 'Resumed renewals',
132
+ 'lockdown.resend-notice': 'Resent the lockdown notice',
133
+ 'maintenance.auditArchive.run': 'Archived the audit log',
134
+ 'maintenance.reapArtifacts.run': 'Removed stale build artifacts',
135
+ 'maintenance.reverifyPlugins.run': 'Re-verified plugins',
136
+ 'operatorAlerts.test': 'Sent a test operator alert',
137
+ 'operatorAlerts.update': 'Changed operator alerts',
138
+ 'org.acquisition-viewed': 'Viewed where the organization came from',
139
+ 'org.auditLog': 'Viewed the organization audit log',
140
+ 'org.discount.apply': 'Applied a discount',
141
+ 'org.discount.remove': 'Removed a discount',
142
+ 'org.enterprise.provision': 'Provisioned enterprise billing',
143
+ 'org.erase-failed': 'Organization erasure failed',
144
+ 'org.erased': 'Erased the organization',
145
+ 'org.erasureCanceled': 'Canceled the organization erasure',
146
+ 'org.erasureRequested': 'Requested organization erasure',
147
+ 'org.exported': 'Exported the organization',
148
+ 'org.name': 'Renamed the organization',
149
+ 'org.note': 'Added a staff note',
150
+ 'org.override': 'Overrode the plan',
151
+ 'org.refund': 'Issued a refund',
152
+ 'org.seatAddons.changed': 'Changed seat add-ons',
153
+ 'org.sso.enforceSignInMethods': 'Changed enforced sign-in methods',
154
+ 'org.sso.jit': 'Changed single sign-on provisioning',
155
+ 'org.subscription-cancel': 'Canceled the subscription',
156
+ 'org.subscriptionStarted.settle': 'Settled a new subscription',
157
+ 'org.successManagerCleared': 'Removed the success manager',
158
+ 'org.successManagerSet': 'Assigned a success manager',
159
+ 'org.upgradeProposal.propose': 'Proposed an upgrade',
160
+ 'org.upgradeProposal.withdraw': 'Withdrew an upgrade proposal',
161
+ 'orgs.unverified.reap': 'Removed unverified organizations',
162
+ 'person.erased': 'Erased a person',
163
+ 'person.erasure-requested': 'Requested erasure of a person',
164
+ 'plan.name': 'Renamed a plan',
165
+ 'plugins.artifacts.reap': 'Removed stale plugin builds',
166
+ 'plugins.remoteServer.load': 'Loaded a remote plugin server',
167
+ 'plugins.verification.decline': 'Declined a plugin verification',
168
+ 'plugins.verifier.regression': 'Plugin verifier regression',
169
+ 'security.pageSecurityHold': 'Put a page on security hold',
170
+ 'security.staffGranted': 'Granted staff access',
171
+ 'site.package.apply': 'Applied a site package',
172
+ 'site.package.undo': 'Undid a site package',
173
+ 'sso.domain.driftDetected': 'Single sign-on domain drift detected',
174
+ 'staff.evidence': 'Recorded evidence',
175
+ 'staff.paymentFailed': 'Payment failed (staff notice)',
176
+ 'staff.planChanged': 'Plan changed (staff notice)',
177
+ 'staff.subscriptionCanceled': 'Subscription canceled (staff notice)',
178
+ 'staff.subscriptionStarted': 'Subscription started (staff notice)',
179
+ 'systemEmail.staffSend': 'Sent a system email',
180
+ 'systemEmail.test': 'Sent a test system email',
181
+ 'taxFilingConfig.clear': 'Cleared the tax filing settings',
182
+ 'taxFilingConfig.update': 'Changed the tax filing settings',
183
+ 'taxablePurchases.clear': 'Cleared taxable purchases',
184
+ 'taxablePurchases.update': 'Changed taxable purchases',
185
+ 'user.acquisition-viewed': 'Viewed where the account came from',
186
+ 'user.erased': 'Erased the account',
187
+ 'user.impersonate': 'Signed in as the account',
188
+ 'user.sendPasswordReset': 'Sent a password reset',
189
+ 'user.setPassword': 'Set the password',
190
+ 'user.signOutDevice': 'Signed a device out',
191
+ 'user.updateProfile': 'Updated the profile'
192
+ };
193
+ /** Leading namespaces as a reader names them. */ const NAMESPACE_LABELS = {
194
+ org: 'Organization',
195
+ orgs: 'Organizations',
196
+ user: 'Account',
197
+ host: 'Site'
198
+ };
199
+ /** `paymentMethod` → `payment method`, `reattach-domain` → `reattach domain`. */ function words(segment) {
200
+ return segment.replace(/([a-z0-9])([A-Z])/g, '$1 $2').replace(/[-_]+/g, ' ').toLowerCase().trim();
201
+ }
202
+ /** A code nobody named, as words: `billing.invoice.paid` → `Billing: invoice paid`. */ export function humanizeActivityCode(code) {
203
+ var _NAMESPACE_LABELS_head;
204
+ const [head = '', ...rest] = code.trim().split('.').filter(Boolean);
205
+ const lead = (_NAMESPACE_LABELS_head = NAMESPACE_LABELS[head]) != null ? _NAMESPACE_LABELS_head : words(head).replace(/^./, (c)=>c.toUpperCase());
206
+ if (!rest.length) return lead;
207
+ return `${lead}: ${rest.map(words).join(' ')}`;
208
+ }
209
+ /** What a staff audit code reads as, everywhere it is shown. */ export function staffAuditActionLabel(action) {
210
+ var _ref, _ref1, _STAFF_AUDIT_ACTION_LABELS_code;
211
+ const code = (_ref = action == null ? void 0 : action.trim()) != null ? _ref : '';
212
+ if (!code) return '—';
213
+ return (_ref1 = (_STAFF_AUDIT_ACTION_LABELS_code = STAFF_AUDIT_ACTION_LABELS[code]) != null ? _STAFF_AUDIT_ACTION_LABELS_code : pluginStaffAuditActionLabel(code)) != null ? _ref1 : isActivityCode(code) ? humanizeActivityCode(code) : code;
214
+ }
215
+ /** The collections an audit path walks, named for a reader. */ const COLLECTION_NOUNS = {
216
+ orgs: 'Organization',
217
+ hosts: 'Site',
218
+ users: 'Account',
219
+ members: 'Member',
220
+ invites: 'Invitation',
221
+ screens: 'Page',
222
+ layouts: 'Layout',
223
+ components: 'Component',
224
+ templates: 'Template',
225
+ media: 'Media',
226
+ emailDeliveries: 'Email',
227
+ coupons: 'Coupon',
228
+ flags: 'Feature flag',
229
+ plugins: 'Plugin',
230
+ subscriptions: 'Subscription'
231
+ };
232
+ /** `orgs/a/aiJobs/b` → `{ orgs: 'a', aiJobs: 'b' }`, in walk order. */ function pathPairs(path) {
233
+ const segments = path.split('/').filter(Boolean);
234
+ const pairs = [];
235
+ for(let at = 0; at < segments.length; at += 2){
236
+ var _segments_at, _segments_;
237
+ pairs.push([
238
+ (_segments_at = segments[at]) != null ? _segments_at : '',
239
+ (_segments_ = segments[at + 1]) != null ? _segments_ : ''
240
+ ]);
241
+ }
242
+ return pairs;
243
+ }
244
+ const str = (value)=>typeof value === 'string' && value.trim() ? value.trim() : null;
245
+ const num = (value)=>typeof value === 'number' && Number.isFinite(value) ? value : null;
246
+ /** What an audit act did, in words, and the words it was about. */ export function describeStaffAudit(entry, names = {}) {
247
+ var _entry_after, _str, _idOf, _ref, _ref1, _ref2, _ref3, _ref4, _ref5, _ref6, _str1, _orgOverrideReasonSummary, _entry_reason, _entry_note;
248
+ var _names_hosts, _names_orgs, _names_users, _pluginStaffAuditCollection;
249
+ const code = str(entry.action);
250
+ const path = str(entry.target);
251
+ const after = (_entry_after = entry.after) != null ? _entry_after : {};
252
+ const pairs = path && path.includes('/') ? pathPairs(path) : [];
253
+ const idOf = (collection)=>{
254
+ var _pairs_find;
255
+ return ((_pairs_find = pairs.find(([name])=>name === collection)) == null ? void 0 : _pairs_find[1]) || null;
256
+ };
257
+ const orgId = idOf('orgs');
258
+ // A plugin's job collection (the AI plugin's jobs) names the job the row
259
+ // links to; core knows it only through the plugin's declaration.
260
+ const jobPair = pairs.find(([name])=>{
261
+ var _pluginStaffAuditCollection;
262
+ return (_pluginStaffAuditCollection = pluginStaffAuditCollection(name)) == null ? void 0 : _pluginStaffAuditCollection.job;
263
+ });
264
+ const jobId = (jobPair == null ? void 0 : jobPair[1]) || null;
265
+ const hostId = (_str = str(after['hostId'])) != null ? _str : idOf('hosts');
266
+ const uid = (_idOf = idOf('users')) != null ? _idOf : str(entry.subjectUid);
267
+ const label = str(after['label']);
268
+ // A plugin may word the row from what the act left: the AI plugin names
269
+ // what a job made (`Created page Home with Aglyn AI`).
270
+ const declared = code ? pluginStaffAuditDescribe(code, after) : undefined;
271
+ const action = (_ref = declared == null ? void 0 : declared.action) != null ? _ref : staffAuditActionLabel(code);
272
+ const site = hostId ? (_ref1 = (_names_hosts = names.hosts) == null ? void 0 : _names_hosts[hostId]) != null ? _ref1 : null : null;
273
+ const org = orgId ? (_ref2 = (_names_orgs = names.orgs) == null ? void 0 : _names_orgs[orgId]) != null ? _ref2 : null : null;
274
+ const person = uid ? (_ref3 = (_names_users = names.users) == null ? void 0 : _names_users[uid]) != null ? _ref3 : null : null;
275
+ const last = pairs[pairs.length - 1];
276
+ const parts = [];
277
+ if (site) parts.push(site);
278
+ else if (org) parts.push(org);
279
+ if (jobPair) parts.push((_ref4 = label != null ? label : (_pluginStaffAuditCollection = pluginStaffAuditCollection(jobPair[0])) == null ? void 0 : _pluginStaffAuditCollection.noun) != null ? _ref4 : 'Job');
280
+ else if (last && last[0] === 'users') parts.push(person != null ? person : 'Account');
281
+ else if (last && last[0] !== 'orgs' && last[0] !== 'hosts') {
282
+ var _ref7, _COLLECTION_NOUNS_last_;
283
+ var _pluginStaffAuditCollection1;
284
+ parts.push((_ref7 = (_COLLECTION_NOUNS_last_ = COLLECTION_NOUNS[last[0]]) != null ? _COLLECTION_NOUNS_last_ : (_pluginStaffAuditCollection1 = pluginStaffAuditCollection(last[0])) == null ? void 0 : _pluginStaffAuditCollection1.noun) != null ? _ref7 : activityTypeLabel(last[0]));
285
+ }
286
+ if (!parts.length) {
287
+ var _ref8, _COLLECTION_NOUNS_last_1;
288
+ var _pluginStaffAuditCollection2;
289
+ if (last) parts.push((_ref8 = (_COLLECTION_NOUNS_last_1 = COLLECTION_NOUNS[last[0]]) != null ? _COLLECTION_NOUNS_last_1 : (_pluginStaffAuditCollection2 = pluginStaffAuditCollection(last[0])) == null ? void 0 : _pluginStaffAuditCollection2.noun) != null ? _ref8 : 'Item');
290
+ else if (path) parts.push(isActivityCode(path) || /^[\w-]{16,}$/.test(path) ? 'Platform' : path);
291
+ else parts.push('—');
292
+ }
293
+ const result = (_ref5 = (_ref6 = (_str1 = str(after['result'])) != null ? _str1 : str(after['status'])) != null ? _ref6 : declared == null ? void 0 : declared.result) != null ? _ref5 : null;
294
+ return {
295
+ action,
296
+ target: parts.join(' · '),
297
+ why: (_orgOverrideReasonSummary = orgOverrideReasonSummary((_entry_reason = entry.reason) != null ? _entry_reason : null, (_entry_note = entry.note) != null ? _entry_note : null)) != null ? _orgOverrideReasonSummary : str(entry.note),
298
+ credits: num(after['credits']),
299
+ result,
300
+ code,
301
+ path,
302
+ orgId,
303
+ hostId,
304
+ jobId,
305
+ uid
306
+ };
307
+ }
308
+ /**
309
+ * An activity row as the lists show it. Where is the site when the row came
310
+ * from a site's log, else the organization.
311
+ */ export function describeActivity(entry, names = {}) {
312
+ var _entry_target, _entry_scopeId, _entry_scopeId1, _ref, _pluginActivityTargetLabel, _str;
313
+ var _names_hosts;
314
+ const stored = str(entry.action);
315
+ const code = isActivityCode(stored) ? stored : null;
316
+ const target = (_entry_target = entry.target) != null ? _entry_target : null;
317
+ const hostId = entry.scopeType === 'host' ? (_entry_scopeId = entry.scopeId) != null ? _entry_scopeId : null : null;
318
+ const orgId = entry.scopeType === 'org' ? (_entry_scopeId1 = entry.scopeId) != null ? _entry_scopeId1 : null : null;
319
+ const site = hostId ? (_ref = (_names_hosts = names.hosts) == null ? void 0 : _names_hosts[hostId]) != null ? _ref : null : null;
320
+ const type = str(target == null ? void 0 : target.type);
321
+ const jobId = isPluginJobTargetType(type) ? str(target == null ? void 0 : target.id) : str(target == null ? void 0 : target.jobId);
322
+ const noun = type ? (_pluginActivityTargetLabel = pluginActivityTargetLabel(type)) != null ? _pluginActivityTargetLabel : activityTypeLabel(type) : null;
323
+ const item = (_str = str(target == null ? void 0 : target.name)) != null ? _str : noun;
324
+ const parts = [
325
+ site,
326
+ item
327
+ ].filter((part)=>Boolean(part));
328
+ return {
329
+ action: activityActionSentence(stored != null ? stored : undefined, target) || '—',
330
+ target: parts.join(' · ') || '—',
331
+ why: null,
332
+ credits: num(target == null ? void 0 : target.credits),
333
+ result: null,
334
+ code,
335
+ path: type ? `${type}${(target == null ? void 0 : target.id) ? `/${target.id}` : ''}` : null,
336
+ orgId,
337
+ hostId,
338
+ jobId,
339
+ uid: type === 'member' ? str(target == null ? void 0 : target.id) : null
340
+ };
341
+ }
342
+
343
+ //# sourceMappingURL=activity-labels.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../libs/aglyn/src/lib/app-utils/activity-labels.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 * ONE LABEL MAP FOR EVERY ACTIVITY AND AUDIT LIST (AGL-3660).\n *\n * Two logs feed the console's lists. The activity logs\n * (`orgs/{id}/activity`, `hosts/{id}/activity`) store a prose sentence or a\n * plugin's code plus a `{ type, id, name }` target. The staff audit trail\n * (`adminAudit`) stores a dotted code (`ai.job.output`, `org.override`) and\n * a Firestore PATH as its target (`orgs/abc/aiJobs/xyz`). The staff tables\n * printed both raw, so a reader saw `ai.job.output` next to\n * `orgs/9fK…/aiJobs/Qe2…` and had to know the schema to read their own\n * audit trail.\n *\n * Every list now draws its words from here: an action as a sentence\n * (`Created page Home with Aglyn AI`), a target as the site and the item,\n * and — for an audit row — why, the credits it spent and what came of it.\n * The raw code and path are kept on the description, for a tooltip and for\n * the staff details dialog, and never as the visible text.\n */\n\nimport {\n activityActionLabel,\n activityPrimaryText,\n activityTypeLabel,\n type ActivityEntryLike,\n type ActivityTargetLike,\n} from './activity-presenter'\nimport { orgOverrideReasonSummary } from './org-override-reason'\nimport {\n isPluginJobTargetType,\n pluginActivityActionSentence,\n pluginActivityTargetLabel,\n pluginStaffAuditActionLabel,\n pluginStaffAuditCollection,\n pluginStaffAuditDescribe,\n} from '../plugin-manager/plugin-activity-actions'\n\n/** What a list row and the details dialog show for one entry. */\nexport interface ActivityDescription {\n /** The act, as a sentence. Never a code. */\n action: string\n /** What it was done to, in words: the site and the item. Never a path. */\n target: string\n /** Why it was done, when the writer recorded a reason. */\n why: string | null\n /** AI credits it spent, when it spent any. */\n credits: number | null\n /** What came of it, when the writer recorded an outcome. */\n result: string | null\n /** The stored code, when the action was one — for a tooltip and staff. */\n code: string | null\n /** The stored target path (audit) or `type/id` (activity) — staff only. */\n path: string | null\n /** The organization the entry concerns, when it names one. */\n orgId: string | null\n /** The site the entry concerns, when it names one. */\n hostId: string | null\n /** The plugin job behind the entry (an AI job), when there is one. */\n jobId: string | null\n /** The account the entry concerns, when it names one. */\n uid: string | null\n}\n\n/** Names a route resolved for the ids an entry carries. */\nexport interface ActivityNames {\n /** Organization name by org id. */\n orgs?: Readonly<Record<string, string | null | undefined>>\n /** Site name by host id. */\n hosts?: Readonly<Record<string, string | null | undefined>>\n /** An account's address (or name) by uid. */\n users?: Readonly<Record<string, string | null | undefined>>\n}\n\n/** `screen` → `page`, `Home` → `page Home`: the noun a sentence uses. */\nexport function activityTargetPhrase(target: ActivityTargetLike | null | undefined): string {\n const noun = activityTypeLabel(target?.type)\n const lower = noun === 'Item' ? 'item' : noun.charAt(0).toLowerCase() + noun.slice(1)\n const name = target?.name?.trim()\n return name ? `${lower} ${name}` : lower\n}\n\n/**\n * An activity row's action as a sentence about its target. A plugin code\n * with a declared sentence fills it (`Created {target} with Aglyn AI`); any\n * other code reads as its label, and a prose action as itself.\n */\nexport function activityActionSentence(\n action: string | undefined,\n target?: ActivityTargetLike | null,\n): string {\n const stored = action?.trim() ?? ''\n const sentence = pluginActivityActionSentence(stored)\n if (sentence) return sentence.replace('{target}', activityTargetPhrase(target))\n return activityActionLabel(stored)\n}\n\n/**\n * A one-column feed's line: the sentence when the code declares one, else\n * the action with its target's name (`Saved the screen — Home`).\n */\nexport function activityRowText(entry: ActivityEntryLike): string {\n const stored = entry.action?.trim() ?? ''\n return pluginActivityActionSentence(stored)\n ? activityActionSentence(stored, entry.target)\n : activityPrimaryText(entry)\n}\n\n/** Whether a stored action is a dotted code rather than a sentence. */\nexport function isActivityCode(action: unknown): action is string {\n return typeof action === 'string' && /^[a-z][\\w-]*(\\.[\\w-]+)+$/i.test(action.trim())\n}\n\n/*==========================================\n * THE STAFF AUDIT TRAIL'S WORDS.\n *\n * Every code core's doors write. A plugin's doors declare their own through\n * `staffAuditLabels` (the AI plugin's `ai.job.*`), and a code neither knows\n * is humanized from its segments rather than shown raw, so a new writer\n * reads as `Billing: invoice paid` until somebody names it properly.\n *==========================================*/\nexport const STAFF_AUDIT_ACTION_LABELS: Readonly<Record<string, string>> = {\n 'account.closed.self': 'Closed their own account',\n 'account.exported.self': 'Exported their own account data',\n 'ai-usage.exported': 'Exported AI usage',\n 'billing.assistOverage.setCap': 'Set the AI overage ceiling',\n 'billing.assistOverage.setHardCap': 'Set the AI stop-at-band switch',\n 'billing.autoLocked': 'Locked automatically for billing',\n 'billing.collaboratorAllocation': 'Changed collaborator seats',\n 'billing.dispute.opened': 'Payment dispute opened',\n 'billing.disputeClosed': 'Payment dispute closed',\n 'billing.disputeOpened': 'Payment dispute opened',\n 'billing.disputeUnattributed': 'Unattributed payment dispute',\n 'billing.invoice': 'Invoice event',\n 'billing.invoice.closed': 'Invoice closed',\n 'billing.invoice.failed': 'Invoice payment failed',\n 'billing.invoice.paid': 'Invoice paid',\n 'billing.manage': 'Opened billing management',\n 'billing.orphanedSubscription': 'Found a subscription with no workspace',\n 'billing.paymentFailed': 'Payment failed',\n 'billing.paymentMethod.changed': 'Changed the payment method',\n 'billing.platformDisputeLost': 'Lost a payment dispute',\n 'billing.platformInvoiceUncollectible': 'Invoice marked uncollectible',\n 'billing.registerAllocation': 'Changed register allocation',\n 'billing.storageOverage.setCap': 'Set the storage overage ceiling',\n 'billing.subscriptionCanceled': 'Subscription canceled',\n 'billing.usage': 'Recorded usage',\n 'billing.usageBudget.set': 'Set the usage budget',\n 'billing.view': 'Viewed billing',\n 'billing.webhookInert': 'Ignored a billing webhook',\n 'billing.webhookSignatureRejected': 'Rejected a billing webhook signature',\n 'broadcast.send': 'Sent a broadcast',\n 'contact.phone.erased': 'Erased a phone number',\n 'contact.suppression.recorded': 'Added a contact suppression',\n 'contact.suppression.released': 'Released a contact suppression',\n 'coupon.create': 'Created a coupon',\n 'coupon.promotion_code.update': 'Updated a promotion code',\n 'data.transfer.export': 'Exported data',\n 'data.transfer.plan': 'Planned a data transfer',\n 'email.history-imported': 'Imported email history',\n 'email.message-viewed': 'Viewed an email message',\n 'email.sending-domains.reap': 'Removed unused sending domains',\n 'email.suppression.release': 'Released an email suppression',\n 'emailSendRate.update': 'Changed the email send rate',\n 'erasure.runBatch': 'Ran an erasure batch',\n 'erasures.replayed': 'Replayed erasures',\n 'firestore.export': 'Exported the database',\n 'firstPartyHosts.update': 'Changed first-party sites',\n 'flags.update': 'Changed feature flags',\n 'freeWorkspaceCap.update': 'Changed the free workspace cap',\n 'host.deleted': 'Deleted a site',\n 'host.domain.released': 'Released a domain',\n 'host.reattach-domain': 'Reattached a domain',\n 'host.set-subdomain': 'Changed a site address',\n 'host.transfer': 'Transferred a site',\n 'lockdown.lock': 'Locked the workspace down',\n 'lockdown.payouts-pause': 'Paused payouts',\n 'lockdown.payouts-restore': 'Restored payouts',\n 'lockdown.renewals-pause': 'Paused renewals',\n 'lockdown.renewals-resume': 'Resumed renewals',\n 'lockdown.resend-notice': 'Resent the lockdown notice',\n 'maintenance.auditArchive.run': 'Archived the audit log',\n 'maintenance.reapArtifacts.run': 'Removed stale build artifacts',\n 'maintenance.reverifyPlugins.run': 'Re-verified plugins',\n 'operatorAlerts.test': 'Sent a test operator alert',\n 'operatorAlerts.update': 'Changed operator alerts',\n 'org.acquisition-viewed': 'Viewed where the organization came from',\n 'org.auditLog': 'Viewed the organization audit log',\n 'org.discount.apply': 'Applied a discount',\n 'org.discount.remove': 'Removed a discount',\n 'org.enterprise.provision': 'Provisioned enterprise billing',\n 'org.erase-failed': 'Organization erasure failed',\n 'org.erased': 'Erased the organization',\n 'org.erasureCanceled': 'Canceled the organization erasure',\n 'org.erasureRequested': 'Requested organization erasure',\n 'org.exported': 'Exported the organization',\n 'org.name': 'Renamed the organization',\n 'org.note': 'Added a staff note',\n 'org.override': 'Overrode the plan',\n 'org.refund': 'Issued a refund',\n 'org.seatAddons.changed': 'Changed seat add-ons',\n 'org.sso.enforceSignInMethods': 'Changed enforced sign-in methods',\n 'org.sso.jit': 'Changed single sign-on provisioning',\n 'org.subscription-cancel': 'Canceled the subscription',\n 'org.subscriptionStarted.settle': 'Settled a new subscription',\n 'org.successManagerCleared': 'Removed the success manager',\n 'org.successManagerSet': 'Assigned a success manager',\n 'org.upgradeProposal.propose': 'Proposed an upgrade',\n 'org.upgradeProposal.withdraw': 'Withdrew an upgrade proposal',\n 'orgs.unverified.reap': 'Removed unverified organizations',\n 'person.erased': 'Erased a person',\n 'person.erasure-requested': 'Requested erasure of a person',\n 'plan.name': 'Renamed a plan',\n 'plugins.artifacts.reap': 'Removed stale plugin builds',\n 'plugins.remoteServer.load': 'Loaded a remote plugin server',\n 'plugins.verification.decline': 'Declined a plugin verification',\n 'plugins.verifier.regression': 'Plugin verifier regression',\n 'security.pageSecurityHold': 'Put a page on security hold',\n 'security.staffGranted': 'Granted staff access',\n 'site.package.apply': 'Applied a site package',\n 'site.package.undo': 'Undid a site package',\n 'sso.domain.driftDetected': 'Single sign-on domain drift detected',\n 'staff.evidence': 'Recorded evidence',\n 'staff.paymentFailed': 'Payment failed (staff notice)',\n 'staff.planChanged': 'Plan changed (staff notice)',\n 'staff.subscriptionCanceled': 'Subscription canceled (staff notice)',\n 'staff.subscriptionStarted': 'Subscription started (staff notice)',\n 'systemEmail.staffSend': 'Sent a system email',\n 'systemEmail.test': 'Sent a test system email',\n 'taxFilingConfig.clear': 'Cleared the tax filing settings',\n 'taxFilingConfig.update': 'Changed the tax filing settings',\n 'taxablePurchases.clear': 'Cleared taxable purchases',\n 'taxablePurchases.update': 'Changed taxable purchases',\n 'user.acquisition-viewed': 'Viewed where the account came from',\n 'user.erased': 'Erased the account',\n 'user.impersonate': 'Signed in as the account',\n 'user.sendPasswordReset': 'Sent a password reset',\n 'user.setPassword': 'Set the password',\n 'user.signOutDevice': 'Signed a device out',\n 'user.updateProfile': 'Updated the profile',\n}\n\n/** Leading namespaces as a reader names them. */\nconst NAMESPACE_LABELS: Readonly<Record<string, string>> = {\n org: 'Organization',\n orgs: 'Organizations',\n user: 'Account',\n host: 'Site',\n}\n\n/** `paymentMethod` → `payment method`, `reattach-domain` → `reattach domain`. */\nfunction words(segment: string): string {\n return segment\n .replace(/([a-z0-9])([A-Z])/g, '$1 $2')\n .replace(/[-_]+/g, ' ')\n .toLowerCase()\n .trim()\n}\n\n/** A code nobody named, as words: `billing.invoice.paid` → `Billing: invoice paid`. */\nexport function humanizeActivityCode(code: string): string {\n const [head = '', ...rest] = code.trim().split('.').filter(Boolean)\n const lead = NAMESPACE_LABELS[head] ?? words(head).replace(/^./, (c) => c.toUpperCase())\n if (!rest.length) return lead\n return `${lead}: ${rest.map(words).join(' ')}`\n}\n\n/** What a staff audit code reads as, everywhere it is shown. */\nexport function staffAuditActionLabel(action: string | null | undefined): string {\n const code = action?.trim() ?? ''\n if (!code) return '—'\n return (\n STAFF_AUDIT_ACTION_LABELS[code] ??\n pluginStaffAuditActionLabel(code) ??\n (isActivityCode(code) ? humanizeActivityCode(code) : code)\n )\n}\n\n/** The collections an audit path walks, named for a reader. */\nconst COLLECTION_NOUNS: Readonly<Record<string, string>> = {\n orgs: 'Organization',\n hosts: 'Site',\n users: 'Account',\n members: 'Member',\n invites: 'Invitation',\n screens: 'Page',\n layouts: 'Layout',\n components: 'Component',\n templates: 'Template',\n media: 'Media',\n emailDeliveries: 'Email',\n coupons: 'Coupon',\n flags: 'Feature flag',\n plugins: 'Plugin',\n subscriptions: 'Subscription',\n}\n\n/** `orgs/a/aiJobs/b` → `{ orgs: 'a', aiJobs: 'b' }`, in walk order. */\nfunction pathPairs(path: string): Array<[string, string]> {\n const segments = path.split('/').filter(Boolean)\n const pairs: Array<[string, string]> = []\n for (let at = 0; at < segments.length; at += 2) {\n pairs.push([segments[at] ?? '', segments[at + 1] ?? ''])\n }\n return pairs\n}\n\n/** The stored audit row, read defensively. */\nexport interface StaffAuditEntryLike {\n action?: string | null\n target?: string | null\n subjectUid?: string | null\n reason?: string | null\n note?: string | null\n /** The state the act left; AI rows carry `{ label, hostId, credits }`. */\n after?: Record<string, unknown> | null\n}\n\nconst str = (value: unknown): string | null =>\n typeof value === 'string' && value.trim() ? value.trim() : null\nconst num = (value: unknown): number | null =>\n typeof value === 'number' && Number.isFinite(value) ? value : null\n\n/** What an audit act did, in words, and the words it was about. */\nexport function describeStaffAudit(\n entry: StaffAuditEntryLike,\n names: ActivityNames = {},\n): ActivityDescription {\n const code = str(entry.action)\n const path = str(entry.target)\n const after = entry.after ?? {}\n const pairs = path && path.includes('/') ? pathPairs(path) : []\n const idOf = (collection: string) => pairs.find(([name]) => name === collection)?.[1] || null\n const orgId = idOf('orgs')\n // A plugin's job collection (the AI plugin's jobs) names the job the row\n // links to; core knows it only through the plugin's declaration.\n const jobPair = pairs.find(([name]) => pluginStaffAuditCollection(name)?.job)\n const jobId = jobPair?.[1] || null\n const hostId = str(after['hostId']) ?? idOf('hosts')\n const uid = idOf('users') ?? str(entry.subjectUid)\n const label = str(after['label'])\n // A plugin may word the row from what the act left: the AI plugin names\n // what a job made (`Created page Home with Aglyn AI`).\n const declared = code ? pluginStaffAuditDescribe(code, after) : undefined\n const action = declared?.action ?? staffAuditActionLabel(code)\n\n const site = hostId ? (names.hosts?.[hostId] ?? null) : null\n const org = orgId ? (names.orgs?.[orgId] ?? null) : null\n const person = uid ? (names.users?.[uid] ?? null) : null\n const last = pairs[pairs.length - 1]\n const parts: string[] = []\n if (site) parts.push(site)\n else if (org) parts.push(org)\n if (jobPair) parts.push(label ?? pluginStaffAuditCollection(jobPair[0])?.noun ?? 'Job')\n else if (last && last[0] === 'users') parts.push(person ?? 'Account')\n else if (last && last[0] !== 'orgs' && last[0] !== 'hosts') {\n parts.push(\n COLLECTION_NOUNS[last[0]] ??\n pluginStaffAuditCollection(last[0])?.noun ??\n activityTypeLabel(last[0]),\n )\n }\n if (!parts.length) {\n if (last) parts.push(COLLECTION_NOUNS[last[0]] ?? pluginStaffAuditCollection(last[0])?.noun ?? 'Item')\n else if (path) parts.push(isActivityCode(path) || /^[\\w-]{16,}$/.test(path) ? 'Platform' : path)\n else parts.push('—')\n }\n\n const result = str(after['result']) ?? str(after['status']) ?? declared?.result ?? null\n\n return {\n action,\n target: parts.join(' · '),\n why: orgOverrideReasonSummary(entry.reason ?? null, entry.note ?? null) ?? str(entry.note),\n credits: num(after['credits']),\n result,\n code,\n path,\n orgId,\n hostId,\n jobId,\n uid,\n }\n}\n\n/** A stored activity row, read defensively, with where it was read from. */\nexport interface ActivityRowLike {\n action?: string | null\n target?: (ActivityTargetLike & { jobId?: string; credits?: number }) | null\n /** `host` or `org`: which log the row came from. */\n scopeType?: string\n scopeId?: string\n}\n\n/**\n * An activity row as the lists show it. Where is the site when the row came\n * from a site's log, else the organization.\n */\nexport function describeActivity(\n entry: ActivityRowLike,\n names: ActivityNames = {},\n): ActivityDescription {\n const stored = str(entry.action)\n const code = isActivityCode(stored) ? stored : null\n const target = entry.target ?? null\n const hostId = entry.scopeType === 'host' ? (entry.scopeId ?? null) : null\n const orgId = entry.scopeType === 'org' ? (entry.scopeId ?? null) : null\n const site = hostId ? (names.hosts?.[hostId] ?? null) : null\n const type = str(target?.type)\n const jobId = isPluginJobTargetType(type) ? str(target?.id) : str(target?.jobId)\n const noun = type ? (pluginActivityTargetLabel(type) ?? activityTypeLabel(type)) : null\n const item = str(target?.name) ?? noun\n const parts = [site, item].filter((part): part is string => Boolean(part))\n return {\n action: activityActionSentence(stored ?? undefined, target) || '—',\n target: parts.join(' · ') || '—',\n why: null,\n credits: num(target?.credits),\n result: null,\n code,\n path: type ? `${type}${target?.id ? `/${target.id}` : ''}` : null,\n orgId,\n hostId,\n jobId,\n uid: type === 'member' ? str(target?.id) : null,\n }\n}\n"],"names":["activityActionLabel","activityPrimaryText","activityTypeLabel","orgOverrideReasonSummary","isPluginJobTargetType","pluginActivityActionSentence","pluginActivityTargetLabel","pluginStaffAuditActionLabel","pluginStaffAuditCollection","pluginStaffAuditDescribe","activityTargetPhrase","target","noun","type","lower","charAt","toLowerCase","slice","name","trim","activityActionSentence","action","stored","sentence","replace","activityRowText","entry","isActivityCode","test","STAFF_AUDIT_ACTION_LABELS","NAMESPACE_LABELS","org","orgs","user","host","words","segment","humanizeActivityCode","code","head","rest","split","filter","Boolean","lead","c","toUpperCase","length","map","join","staffAuditActionLabel","COLLECTION_NOUNS","hosts","users","members","invites","screens","layouts","components","templates","media","emailDeliveries","coupons","flags","plugins","subscriptions","pathPairs","path","segments","pairs","at","push","str","value","num","Number","isFinite","describeStaffAudit","names","idOf","label","after","includes","collection","find","orgId","jobPair","job","jobId","hostId","uid","subjectUid","declared","undefined","site","person","last","parts","result","why","reason","note","credits","describeActivity","scopeType","scopeId","id","item","part"],"mappings":"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"}
@@ -51,6 +51,17 @@ export type AdminAuditKind = 'access' | 'change';
51
51
  * high-consequence act even though it mutates nothing, and it belongs beside
52
52
  * the impersonations rather than beside the record views.
53
53
  */
54
+ /**
55
+ * Staff opened a workspace's or a site's media library — one row per page
56
+ * read — on the staff organization or site page. The target is the library
57
+ * (`orgs/{id}/media`, `hosts/{id}/media`).
58
+ */
59
+ export declare const ADMIN_AUDIT_MEDIA_LIBRARY_VIEWED = "media.library-viewed";
60
+ /**
61
+ * Staff opened one asset of a media library — its preview, storage path,
62
+ * owner and usage. The target is the asset (`orgs/{id}/media/{mediaId}`).
63
+ */
64
+ export declare const ADMIN_AUDIT_MEDIA_ASSET_VIEWED = "media.asset-viewed";
54
65
  export declare const ADMIN_AUDIT_ACCESS_ACTIONS: readonly string[];
55
66
  /** What a row carries that the stamped fields are derived from. */
56
67
  export type AdminAuditIndexSource = Partial<Record<(typeof ADMIN_AUDIT_SEARCHED_FIELDS)[number], unknown>>;
@@ -88,8 +88,19 @@ import { nameSearchTokens } from "./name-search.js";
88
88
  * An export is deliberately NOT here. Data leaving the platform is a
89
89
  * high-consequence act even though it mutates nothing, and it belongs beside
90
90
  * the impersonations rather than beside the record views.
91
- */ export const ADMIN_AUDIT_ACCESS_ACTIONS = [
91
+ */ /**
92
+ * Staff opened a workspace's or a site's media library — one row per page
93
+ * read — on the staff organization or site page. The target is the library
94
+ * (`orgs/{id}/media`, `hosts/{id}/media`).
95
+ */ export const ADMIN_AUDIT_MEDIA_LIBRARY_VIEWED = 'media.library-viewed';
96
+ /**
97
+ * Staff opened one asset of a media library — its preview, storage path,
98
+ * owner and usage. The target is the asset (`orgs/{id}/media/{mediaId}`).
99
+ */ export const ADMIN_AUDIT_MEDIA_ASSET_VIEWED = 'media.asset-viewed';
100
+ export const ADMIN_AUDIT_ACCESS_ACTIONS = [
92
101
  'email.message-viewed',
102
+ ADMIN_AUDIT_MEDIA_LIBRARY_VIEWED,
103
+ ADMIN_AUDIT_MEDIA_ASSET_VIEWED,
93
104
  // The acquisition card (AGL-3289). No longer written; the rows already in
94
105
  // the log still classify as reads.
95
106
  'user.acquisition-viewed',