@aglyn/aglyn 1.0.0-beta.255 → 1.0.0-beta.257

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aglyn/aglyn",
3
- "version": "1.0.0-beta.255",
3
+ "version": "1.0.0-beta.257",
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.255",
41
- "@aglyn/shared-data-mdi": "1.0.0-beta.255",
42
- "@aglyn/shared-data-types": "1.0.0-beta.255",
43
- "@aglyn/shared-util-email": "1.0.0-beta.255",
44
- "@aglyn/shared-util-first-touch": "1.0.0-beta.255",
45
- "@aglyn/shared-util-http": "1.0.0-beta.255",
46
- "@aglyn/shared-util-logger": "1.0.0-beta.255",
47
- "@aglyn/shared-util-timestamp": "1.0.0-beta.255",
48
- "@aglyn/shared-util-tools": "1.0.0-beta.255",
49
- "@aglyn/shared-util-vendor": "1.0.0-beta.255",
40
+ "@aglyn/shared-data-enums": "1.0.0-beta.257",
41
+ "@aglyn/shared-data-mdi": "1.0.0-beta.257",
42
+ "@aglyn/shared-data-types": "1.0.0-beta.257",
43
+ "@aglyn/shared-util-email": "1.0.0-beta.257",
44
+ "@aglyn/shared-util-first-touch": "1.0.0-beta.257",
45
+ "@aglyn/shared-util-http": "1.0.0-beta.257",
46
+ "@aglyn/shared-util-logger": "1.0.0-beta.257",
47
+ "@aglyn/shared-util-timestamp": "1.0.0-beta.257",
48
+ "@aglyn/shared-util-tools": "1.0.0-beta.257",
49
+ "@aglyn/shared-util-vendor": "1.0.0-beta.257",
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",
@@ -186,6 +186,8 @@ import { isPluginJobTargetType, pluginActivityActionSentence, pluginActivityTarg
186
186
  'user.acquisition-viewed': 'Viewed where the account came from',
187
187
  'user.erased': 'Erased the account',
188
188
  'user.impersonate': 'Signed in as the account',
189
+ 'user.nativeAppCheck': 'Verified the desktop app for the account',
190
+ 'user.nativeAppSignIn': 'Signed in to the app through the console',
189
191
  'user.sendPasswordReset': 'Sent a password reset',
190
192
  'user.setAdAudienceOptOut': 'Changed the ad audience opt-out',
191
193
  'user.setPassword': 'Set the password',
@@ -1 +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.paymentFraudHold': 'Put a workspace on hold for payment fraud',\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.setAdAudienceOptOut': 'Changed the ad audience opt-out',\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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"}
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.paymentFraudHold': 'Put a workspace on hold for payment fraud',\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.nativeAppCheck': 'Verified the desktop app for the account',\n 'user.nativeAppSignIn': 'Signed in to the app through the console',\n 'user.sendPasswordReset': 'Sent a password reset',\n 'user.setAdAudienceOptOut': 'Changed the ad audience opt-out',\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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"}
@@ -358,6 +358,11 @@ export declare const PLUGIN_DOCS: {
358
358
  readonly title: "Funnels";
359
359
  readonly excerpt: "See how visitors move through the steps you care about, where they drop off and how long each step takes; build or explain a funnel with Aglyn AI, and follow up with people who dropped off.";
360
360
  };
361
+ readonly helpDesks: {
362
+ readonly path: "/commerce-and-bookings/commerce/help-desks";
363
+ readonly title: "Help desks (Gorgias, Re:amaze, Kustomer, Gladly and Richpanel)";
364
+ readonly excerpt: "Show your support team each buyer's recent orders beside their tickets in your own Gorgias, Re:amaze, Kustomer, Gladly or Richpanel account, and send contact form messages there as new tickets. Rolling out.";
365
+ };
361
366
  readonly installYourFirstPlugin: {
362
367
  readonly path: "/guides/install-your-first-plugin";
363
368
  readonly title: "Install your first marketplace item";
@@ -365,8 +370,8 @@ export declare const PLUGIN_DOCS: {
365
370
  };
366
371
  readonly inventorySync: {
367
372
  readonly path: "/commerce-and-bookings/commerce/inventory-and-erp-sync";
368
- readonly title: "Inventory and ERP sync (Cin7 Core, inFlow, Brightpearl)";
369
- readonly excerpt: "Keep stock counts, products and paid orders in step with your own Cin7 Core, inFlow Inventory or Brightpearl account. Rolling out.";
373
+ readonly title: "Inventory and ERP sync (Cin7 Core, inFlow, Brightpearl, Ordoro)";
374
+ readonly excerpt: "Keep stock counts, products and paid orders in step with your own Cin7 Core, inFlow Inventory, Brightpearl or Ordoro account. Rolling out.";
370
375
  };
371
376
  readonly inviteTeammates: {
372
377
  readonly path: "/workspace-and-billing/teams-and-roles/invite-teammates";
@@ -606,8 +611,9 @@ export declare const PLUGIN_DOCS_ANCHORS: {
606
611
  readonly emailPlatforms: readonly ["#connect", "#who-is-sent", "#unsubscribes-from-the-platform", "#settings", "#sync-log", "#disconnect", "#one-off-imports"];
607
612
  readonly events: readonly ["#manage-events", "#import-and-export-events", "#columns", "#how-a-row-finds-an-existing-event", "#conflicts-the-dry-run-and-undo", "#files-from-other-calendars", "#show-events-on-a-screen", "#ask-aglyn-ai", "#search-engines", "#related"];
608
613
  readonly forms: readonly ["#reading-submissions-from-code", "#build-a-form", "#place-a-saved-form", "#saved-forms-per-site", "#monthly-allowance-per-plan", "#spam-and-abuse-protection", "#the-per-site-monthly-ceiling", "#field-types", "#labels-and-placeholders", "#example-a-quick-survey", "#style-a-field", "#after-submit", "#example-grow-an-email-list-from-a-signup-form", "#consent-group-disclosure", "#where-submissions-go", "#the-inbox", "#filter-the-inbox", "#who-a-submission-is-from", "#what-it-links-to", "#where-this-one-went", "#replying-to-a-submission", "#inbox-card", "#every-sites-inbox-at-once", "#one-forms-own-page", "#form-details", "#form-crm-routing", "#form-versions", "#form-collected", "#form-submissions", "#form-saves-to-contact-fields", "#export-submissions", "#find-a-form", "#duplicate-a-form", "#switch-forms-off-for-one-site", "#related"];
609
- readonly fulfillmentNetworks: readonly ["#connect-a-network", "#shipmonk-connect-with-your-api-key", "#settings", "#how-orders-are-sent", "#stock-counts", "#shipments-and-tracking", "#canceling-and-refunds", "#activity"];
614
+ readonly fulfillmentNetworks: readonly ["#connect-a-network", "#shipmonk-connect-with-your-api-key", "#flexport-connect-with-your-api-token", "#settings", "#how-orders-are-sent", "#stock-counts", "#shipments-and-tracking", "#canceling-and-refunds", "#activity"];
610
615
  readonly funnels: readonly ["#step-types", "#how-it-counts", "#what-is-a-visit", "#identified-visitors", "#create", "#create-with-ai", "#drafts", "#act-on-drop-off", "#ask-ai"];
616
+ readonly helpDesks: readonly ["#before-you-start", "#connect", "#credentials", "#what-agents-see", "#contact-form-tickets", "#settings", "#sync-log", "#disconnect", "#related"];
611
617
  readonly installYourFirstPlugin: readonly ["#before-you-start", "#step-1-open", "#step-2-browse", "#step-3-reviews", "#step-4-targeting", "#step-5-install", "#step-6-use", "#step-7-off", "#manage-plugins", "#find-plugins", "#built-in-plugins", "#a-plugins-page", "#where-a-plugin-runs", "#permissions-and-data", "#site-plugins", "#plugin-on-one-site", "#what-to-do-next", "#related"];
612
618
  readonly inventorySync: readonly ["#connect-a-system", "#stock-counts", "#products", "#orders", "#canceling-and-refunds", "#activity"];
613
619
  readonly inviteTeammates: readonly ["#invite-someone", "#pending-invites", "#who-gets-told", "#accepting-an-invite", "#declining-an-invite", "#an-ordinary-invitation-never-changes-who-owns-the-workspace", "#owner-handoff", "#aglyn-staff", "#how-team-members-act", "#you-are-a-site-collaborators-support-channel", "#member-page", "#member-access", "#member-activity", "#member-changes", "#help-a-teammate-who-is-locked-out", "#why-you-cant-always-set-a-password", "#activity-log", "#site-activity-log", "#ai-actions", "#ai-usage", "#ai-allotment", "#tips", "#related"];
@@ -355,6 +355,11 @@ export const PLUGIN_DOCS = {
355
355
  title: 'Funnels',
356
356
  excerpt: 'See how visitors move through the steps you care about, where they drop off and how long each step takes; build or explain a funnel with Aglyn AI, and follow up with people who dropped off.'
357
357
  },
358
+ helpDesks: {
359
+ path: '/commerce-and-bookings/commerce/help-desks',
360
+ title: 'Help desks (Gorgias, Re:amaze, Kustomer, Gladly and Richpanel)',
361
+ excerpt: 'Show your support team each buyer\'s recent orders beside their tickets in your own Gorgias, Re:amaze, Kustomer, Gladly or Richpanel account, and send contact form messages there as new tickets. Rolling out.'
362
+ },
358
363
  installYourFirstPlugin: {
359
364
  path: '/guides/install-your-first-plugin',
360
365
  title: 'Install your first marketplace item',
@@ -362,8 +367,8 @@ export const PLUGIN_DOCS = {
362
367
  },
363
368
  inventorySync: {
364
369
  path: '/commerce-and-bookings/commerce/inventory-and-erp-sync',
365
- title: 'Inventory and ERP sync (Cin7 Core, inFlow, Brightpearl)',
366
- excerpt: 'Keep stock counts, products and paid orders in step with your own Cin7 Core, inFlow Inventory or Brightpearl account. Rolling out.'
370
+ title: 'Inventory and ERP sync (Cin7 Core, inFlow, Brightpearl, Ordoro)',
371
+ excerpt: 'Keep stock counts, products and paid orders in step with your own Cin7 Core, inFlow Inventory, Brightpearl or Ordoro account. Rolling out.'
367
372
  },
368
373
  inviteTeammates: {
369
374
  path: '/workspace-and-billing/teams-and-roles/invite-teammates',
@@ -1506,6 +1511,7 @@ export const PLUGIN_DOCS_ANCHORS = {
1506
1511
  fulfillmentNetworks: [
1507
1512
  '#connect-a-network',
1508
1513
  '#shipmonk-connect-with-your-api-key',
1514
+ '#flexport-connect-with-your-api-token',
1509
1515
  '#settings',
1510
1516
  '#how-orders-are-sent',
1511
1517
  '#stock-counts',
@@ -1524,6 +1530,17 @@ export const PLUGIN_DOCS_ANCHORS = {
1524
1530
  '#act-on-drop-off',
1525
1531
  '#ask-ai'
1526
1532
  ],
1533
+ helpDesks: [
1534
+ '#before-you-start',
1535
+ '#connect',
1536
+ '#credentials',
1537
+ '#what-agents-see',
1538
+ '#contact-form-tickets',
1539
+ '#settings',
1540
+ '#sync-log',
1541
+ '#disconnect',
1542
+ '#related'
1543
+ ],
1527
1544
  installYourFirstPlugin: [
1528
1545
  '#before-you-start',
1529
1546
  '#step-1-open',