@aglyn/aglyn 1.0.0-beta.149 → 1.0.0-beta.150
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 +10 -10
- package/src/lib/app-utils/console-routes.d.ts +0 -34
- package/src/lib/app-utils/console-routes.js +15 -11
- package/src/lib/app-utils/console-routes.js.map +1 -1
- package/src/lib/app-utils/contexts.d.ts +1 -0
- package/src/lib/app-utils/contexts.js +1 -0
- package/src/lib/app-utils/contexts.js.map +1 -1
- package/src/lib/app-utils/docs-help.generated.d.ts +12 -0
- package/src/lib/app-utils/docs-help.generated.js +34 -0
- package/src/lib/app-utils/docs-help.generated.js.map +1 -1
- package/src/lib/app-utils/media-src.d.ts +93 -0
- package/src/lib/app-utils/media-src.js +114 -0
- package/src/lib/app-utils/media-src.js.map +1 -0
- package/src/lib/app-utils/page-header-help-context.d.ts +83 -0
- package/src/lib/app-utils/page-header-help-context.js +56 -0
- package/src/lib/app-utils/page-header-help-context.js.map +1 -0
- package/src/lib/app-utils/release-flags.js +5 -4
- package/src/lib/app-utils/release-flags.js.map +1 -1
- package/src/lib/plugin-manager/feature-plugins.d.ts +52 -23
- package/src/lib/plugin-manager/feature-plugins.js +15 -19
- package/src/lib/plugin-manager/feature-plugins.js.map +1 -1
- package/src/lib/plugin-manager/plugin-media-publish.d.ts +88 -0
- package/src/lib/plugin-manager/plugin-media-publish.js +118 -0
- package/src/lib/plugin-manager/plugin-media-publish.js.map +1 -0
- package/src/lib/plugin-manager/plugin-route-metadata.d.ts +141 -0
- package/src/lib/plugin-manager/plugin-route-metadata.js +140 -0
- package/src/lib/plugin-manager/plugin-route-metadata.js.map +1 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../libs/aglyn/src/lib/app-utils/docs-help.generated.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// GENERATED FILE — do not edit. Regenerate with:\n// node tools/scripts/generate-docs-help.mjs\n// Source of truth: apps/docs/docs frontmatter + headings (AGL-602).\n\n// The first-party plugin consoles live in `libs/plugins/*` and cannot import\n// the console's constants, so they carry their own generated subset of the\n// docs help registry — the topics their cards actually link to, and no others.\n\nexport interface PluginDocsTopic {\n /** Docs-site path, e.g. `/commerce-and-bookings/commerce/overview`. */\n path: string\n /** Docs page title. */\n title: string\n /** Verbatim docs frontmatter description — the tooltip excerpt. */\n excerpt: string\n}\n\nexport const PLUGIN_DOCS = {\n actionsBuilder: {\n path: '/marketing-and-automation/workflows-and-actions/actions-builder',\n title: 'Actions builder',\n excerpt: 'Map a single event to a single action without building a full workflow.',\n },\n aglynAssist: {\n path: '/getting-started/aglyn-assist',\n title: 'Aglyn Assist',\n excerpt: 'Ask the built-in AI helper how to do anything in Aglyn — it answers from these docs and links you straight to the right page.',\n },\n aiAutomations: {\n path: '/ai/automations-with-ai',\n title: 'Explain automations with AI',\n excerpt: 'Aglyn AI can explain an automation you already have and tell you why one of its runs failed. Drafting an automation from a description is not available yet.',\n },\n aiCrm: {\n path: '/ai/crm-by-ai',\n title: 'The AI CRM built into Aglyn',\n excerpt: 'An AI CRM for small business: a short summary and a suggested next step on a contact, company, deal or lead, a one-to-one email drafted into the composer, and an import\\'s columns matched to fields.',\n },\n aiExperiments: {\n path: '/ai/ab-tests-with-ai',\n title: 'A/B tests by AI: write variants, read the result',\n excerpt: 'Have Aglyn AI write two to four variants for a screen, section or email experiment, and put a finished test into plain language — with the verdict decided from the counts before the model is asked anything.',\n },\n aiMonitoring: {\n path: '/staff-console/ai-monitoring',\n title: 'AI monitoring',\n excerpt: 'How staff watch one organization\\'s AI usage — the add-on, credit pool, overage, refusals, jobs, tokens and cache hit rate, top spenders and margin — and where those figures appear across the staff console.',\n },\n aiProducts: {\n path: '/ai/products-with-ai',\n title: 'Product copy and catalogs with AI',\n excerpt: 'An AI product description generator for your catalog: write copy for one product or a whole import, propose a first catalog, and propose categories and discounts — all as proposals you review.',\n },\n aiSeo: {\n path: '/building-sites/seo/seo-by-ai',\n title: 'AI SEO for your website',\n excerpt: 'AI SEO for websites, on the pages you already have: have AI write a page or product\\'s search listing, audit every published page with a proposed fix for each finding, and draft your structured data and /llms.txt.',\n },\n aiThemes: {\n path: '/ai/theme-assist',\n title: 'Change your site\\'s theme with AI',\n excerpt: 'Describe a change to your site\\'s theme and get a proposal for the theme editor\\'s own controls, previewed before and after, that you save in the editor. Rolling out.',\n },\n assistSignals: {\n path: '/staff-console/assist-signals',\n title: 'Assist Signal',\n excerpt: 'The docs-gap and cost board behind Assist — how the ranking is ordered, why ungrounded questions are counted separately, and what the cache-read rate says about margin.',\n },\n billing: {\n path: '/workspace-and-billing/billing-and-plans/overview',\n title: 'Billing & Plans',\n excerpt: 'How Aglyn\\'s tiers, entitlements, quotas, usage meters, and seat add-ons work.',\n },\n bindings: {\n path: '/building-sites/bindings/overview',\n title: 'Bindings, Variables & Functions',\n excerpt: 'Live values in your content — typed variables, no-code functions, and rename-safe id tokens.',\n },\n bookings: {\n path: '/commerce-and-bookings/bookings/overview',\n title: 'Bookings & Scheduling',\n excerpt: 'Offer services with availability, let visitors book, take payment, and send reminders.',\n },\n buildAWorkflow: {\n path: '/marketing-and-automation/workflows-and-actions/build-a-workflow',\n title: 'Build a workflow',\n excerpt: 'Create a multi-step workflow that runs when a site event fires.',\n },\n catalog: {\n path: '/commerce-and-bookings/commerce/catalog',\n title: 'Product catalog',\n excerpt: 'Products with options and variants, categories, tags, and manual or smart collections.',\n },\n commerce: {\n path: '/commerce-and-bookings/commerce/overview',\n title: 'Commerce',\n excerpt: 'Sell physical, digital, and service products with a full catalog, orders pipeline, shipping, taxes, and your own Stripe account.',\n },\n commerceEndToEnd: {\n path: '/guides/commerce-end-to-end',\n title: 'Commerce end to end',\n excerpt: 'Create products with billing modes, design the storefront with Commerce blocks, take Stripe checkout for one-time and subscription sales, and run orders from the console.',\n },\n companies: {\n path: '/content-and-data/crm/companies',\n title: 'Companies',\n excerpt: 'Group your contacts under the businesses they belong to — one record per company, with its domain, owner, address and the people who work there.',\n },\n consoleTour: {\n path: '/getting-started/console-tour',\n title: 'The console tour',\n excerpt: 'Where things live in the Aglyn console app bar and navigation.',\n },\n contactActivities: {\n path: '/content-and-data/crm/activities',\n title: 'Activities & the timeline',\n excerpt: 'Log calls, emails, meetings and notes against a contact, a company, a deal or a lead, email one person from their record, and read it all in one timeline beside everything captured and every campaign sent.',\n },\n contactFields: {\n path: '/content-and-data/crm/custom-fields',\n title: 'Custom fields',\n excerpt: 'Define your own properties on contacts, companies and deals — text, number, date, choice, checkbox or link — show them on every record and its list, and save form answers straight into a contact\\'s.',\n },\n contactRecord: {\n path: '/content-and-data/crm/contact-record',\n title: 'The contact record',\n excerpt: 'Add a contact by hand, keep a profile on them — phone, company, title, address, owner and lifecycle stage — open their own page in the CRM, and merge two records that turn out to be one person.',\n },\n contacts: {\n path: '/content-and-data/crm/overview',\n title: 'CRM',\n excerpt: 'One place for the people who interact with your sites — contacts captured from forms, members, orders and bookings, with leads, companies, a deals pipeline, tasks, a timeline, reports and custom fields.',\n },\n crmEmailTemplates: {\n path: '/content-and-data/crm/email-templates',\n title: 'Email templates',\n excerpt: 'Keep the letters your team sends from a record — templates that fill in the subject and the message, snippets that drop in a paragraph, and merge fields that fill in the person\\'s name, their company, the deal and you.',\n },\n crmLeads: {\n path: '/content-and-data/crm/leads',\n title: 'Leads',\n excerpt: 'Work the people your site has captured — a status, an owner and notes on every lead — and convert one into a contact, a company and a deal.',\n },\n crmReports: {\n path: '/content-and-data/crm/reports',\n title: 'Reports',\n excerpt: 'New contacts, where they came from and which sources convert, the lead funnel, the open pipeline and its forecast, won and lost, who logged what, and the task load — counted on the server, every table exportable as CSV.',\n },\n crmSettings: {\n path: '/content-and-data/crm/settings',\n title: 'CRM settings',\n excerpt: 'What the CRM does on its own for every site — whether a company is created from a contact\\'s work email domain, who a new contact is assigned to, the address that files replies on a record, and each site\\'s recipes.',\n },\n crmTasks: {\n path: '/content-and-data/crm/tasks',\n title: 'Tasks & follow-ups',\n excerpt: 'Calls, emails, meetings and to-dos with a due date, an assignee and a link to the record they are for — overdue and today read off the clock, a snooze, a reminder at its own time, and a morning digest.',\n },\n crmViews: {\n path: '/content-and-data/crm/views',\n title: 'Saved views',\n excerpt: 'Keep a CRM list\\'s filters, columns and sort under a name, open it from the views menu or a link, share it with the team, and use a contacts view as an email audience.',\n },\n datasets: {\n path: '/content-and-data/datasets/overview',\n title: 'Datasets & Dynamic Content',\n excerpt: 'Model structured content with typed fields and relations, then bind it into repeatable components.',\n },\n deals: {\n path: '/content-and-data/crm/deals',\n title: 'Deals pipeline',\n excerpt: 'Every open deal by stage — with an amount, an owner and an expected close — as a board you drag across or a table you page through, and the won and lost history behind it.',\n },\n designedEmails: {\n path: '/marketing-and-automation/email-campaigns/designed-emails',\n title: 'Designed emails',\n excerpt: 'Build campaign emails in the besigner with email-safe blocks and merge tokens — no separate editor.',\n },\n emailCampaigns: {\n path: '/marketing-and-automation/email-campaigns/overview',\n title: 'Email Campaigns',\n excerpt: 'Campaigns to audiences built from your contacts. Campaign email starts at Pro and needs a sending domain of the site\\'s own; receipts and account email send on every plan.',\n },\n events: {\n path: '/content-and-data/events/overview',\n title: 'Events Calendar',\n excerpt: 'Keep a schedule of events in the console and publish the ones you choose to any screen, with search-engine event markup.',\n },\n forms: {\n path: '/content-and-data/forms/overview',\n title: 'Forms & Lead Capture',\n excerpt: 'Add forms to your site, collect submissions in an inbox, and write them into datasets.',\n },\n installYourFirstPlugin: {\n path: '/guides/install-your-first-plugin',\n title: 'Install your first marketplace item',\n excerpt: 'A click-by-click walkthrough of the Marketplace — find something, choose which sites get it, install it, and turn it off again.',\n },\n inviteTeammates: {\n path: '/workspace-and-billing/teams-and-roles/invite-teammates',\n title: 'Invite teammates',\n excerpt: 'Add people to your site and understand how team members act within your organization.',\n },\n marketingOverlays: {\n path: '/marketing-and-automation/marketing-overlays/overview',\n title: 'Marketing Overlays',\n excerpt: 'Site-wide announcement bars and promotional popups with triggers, scheduling, and email capture.',\n },\n membersOnly: {\n path: '/workspace-and-billing/teams-and-roles/members-only',\n title: 'Members-only areas',\n excerpt: 'Let visitors sign up as members and gate screens so only members can view them.',\n },\n plugins: {\n path: '/developers/plugins/overview',\n title: 'Plugins & Marketplace',\n excerpt: 'Extend Aglyn with sandboxed plugins — install from the marketplace, configure them, and publish your own.',\n },\n pos: {\n path: '/commerce-and-bookings/commerce/pos-and-reservations',\n title: 'POS & reservations',\n excerpt: 'Sell in person from the console register and take date-range reservations with deposits.',\n },\n publisherHandbook: {\n path: '/developers/plugins/publishing/publisher-handbook',\n title: 'Publisher handbook',\n excerpt: 'Publishing to the Aglyn marketplace — from profile setup through listing authoring, review, updates, and getting paid.',\n },\n redirects: {\n path: '/building-sites/redirects/overview',\n title: 'Redirects',\n excerpt: 'Manage URL redirects with validation, loop detection, and hit metrics.',\n },\n sequences: {\n path: '/content-and-data/crm/sequences',\n title: 'Sequences',\n excerpt: 'One-to-one email sequences a rep sends to a person from their own connected mailbox, kept with the CRM. Rolling out.',\n },\n webhooks: {\n path: '/marketing-and-automation/workflows-and-actions/webhooks',\n title: 'Webhooks',\n excerpt: 'Connect Aglyn to other systems with outbound and inbound webhooks.',\n },\n} as const satisfies Record<string, PluginDocsTopic>\n\nexport type PluginDocsKey = keyof typeof PLUGIN_DOCS\n\nexport const PLUGIN_DOCS_ANCHORS = {\n actionsBuilder: ['#create-an-action', '#recipes', '#describe-it', '#triggers', '#crm-events', '#only-run-when-a-field-matches', '#chain-multiple-conditions-andor', '#steps', '#crm-steps', '#step-conditions', '#sequences', '#run-history', '#what-is-and-isnt-recorded', '#interactions-from-the-besigner', '#when-to-use-which', '#related'],\n aglynAssist: ['#what-it-can-do', '#aglyn-ai', '#answers-for-beginners-and-developers', '#offers-to-open-a-page', '#edits-in-the-besigner', '#where-an-answer-came-from', '#answers-straight-from-the-documentation', '#message-limits', '#feedback', '#privacy'],\n aiAutomations: ['#draft', '#explain', '#why-a-run-failed', '#what-is-sent', '#who-can-use-it', '#related'],\n aiCrm: ['#summarize-a-record', '#summaries-are-reused-until-the-record-changes', '#draft-an-email', '#match-columns', '#what-is-sent', '#who-can-use-it', '#related'],\n aiExperiments: ['#it-proposes-you-write', '#write-variants', '#putting-them-in', '#what-it-will-not-write', '#read-a-result', '#the-verdict', '#the-words', '#undecided', '#what-is-sent', '#who-can-use-it', '#related'],\n aiMonitoring: ['#the-ai-card', '#where-else', '#one-account', '#the-spend-leaderboard', '#alerts', '#related'],\n aiProducts: ['#write-a-products-copy', '#write-copy-for-many-products', '#when-you-import-products', '#propose-a-first-catalog', '#propose-categories-and-discounts', '#what-the-copy-never-says', '#what-is-sent-to-the-ai-provider', '#who-can-use-it', '#related'],\n aiSeo: ['#write-a-pages-listing', '#write-a-products-listing', '#audit-the-whole-site', '#target-keywords', '#apply-all-as-drafts', '#structured-data-and-llmstxt', '#related'],\n aiThemes: ['#change-what-you-describe-or-design-a-new-theme', '#match-your-brand', '#review-the-proposal', '#save-it-or-dont', '#who-can-use-it', '#related'],\n assistSignals: ['#the-workflow-this-board-exists-for', '#fleet', '#the-cache-read-rate-and-what-a-bad-number-looks-like', '#where-the-money-goes', '#tokens-by-kind', '#docs-gaps', '#questions-the-docs-could-not-answer', '#what-people-actually-asked', '#what-assist-costs-by-workspace', '#reading-the-sample-honestly', '#related'],\n billing: ['#tiers--entitlements', '#enterprise', '#single-sign-on-and-enforcement', '#usage-meters', '#who-is-generating-what', '#ai-allotments', '#storage-overage', '#if-you-would-rather-uploads-stopped', '#assist-overage', '#stop-ai-assist-at-the-included-band', '#ai-overage-ceiling', '#free-ai-credits', '#ai-credit-alerts', '#usage-budget', '#seats', '#crm-records', '#the-crm-suite', '#one-to-one-email', '#organization-data', '#api-access', '#payments', '#outstanding', '#plan-total', '#billing-email', '#payment-methods', '#billing-address', '#tax-ids', '#sales-tax', '#platform-fees', '#related'],\n bindings: ['#binding-tokens', '#rename-safe-id-tokens', '#insert-a-variable', '#token-pills', '#in-the-canvas-text-editor', '#site-details', '#typed-variables', '#no-code-functions', '#parameters-a-visitor-can-answer', '#a-calculator-you-lay-out', '#where-used--safety', '#workflows', '#related'],\n bookings: ['#set-up-bookings', '#taking-bookings', '#reminders', '#payments-and-fees', '#service-tax', '#manage', '#booking-from-the-crm', '#canceling-and-refunding', '#related'],\n buildAWorkflow: ['#1-open-the-workflows-page', '#2-choose-a-trigger', '#3-add-steps', '#waiting', '#4-save-and-test', '#duplicate-a-workflow', '#tips', '#related'],\n catalog: ['#products-options-and-variants', '#billing-modes-and-subscriptions', '#ai', '#categories-and-tags', '#collections', '#slugs', '#merchant-center-feed', '#related'],\n commerce: ['#products-hub', '#inventory', '#reserved-stock', '#stock-movements', '#gift-cards', '#recovery-and-alerts', '#orders', '#orders-screen', '#order-statuses', '#order-money-tiles', '#a-lost-dispute', '#shipping--taxes', '#lodging-tax-on-reservations', '#storefront-sales-tax', '#destination-coverage', '#dropshipping', '#related'],\n commerceEndToEnd: ['#1-connect-payments', '#2-create-products', '#3-design-the-storefront', '#catalog-search-filters-and-sort', '#category-pages', '#the-product-page-template', '#4-what-checkout-does', '#paying-without-leaving-your-site', '#5-run-orders-from-the-console', '#6-subscriptions--the-stripe-portal', '#related'],\n companies: ['#the-companies-list', '#create-a-company', '#a-companys-page', '#contacts-at-a-company', '#linked-on-capture', '#import-from-csv', '#export-csv', '#deleting-a-company', '#who-can-see-a-company', '#files', '#related'],\n consoleTour: ['#the-app-bar', '#in-context-help', '#primary-navigation', '#editing-vs-managing', '#the-sites-list', '#the-status-pill', '#how-the-pill-is-decided', '#your-site-allowance', '#a-sites-dashboard', '#next', '#workspace-settings--notifications', '#the-notifications-feed', '#notification-settings', '#workspace-and-site-overrides', '#daily-digests', '#alerts-on-this-device'],\n contactActivities: ['#four-kinds-of-history', '#campaign-email', '#logging-an-activity', '#meeting-from-a-booking', '#click-to-call', '#sending-an-email', '#delivery-states', '#captured-email', '#where-an-activity-is-visible', '#the-recent-activity-feed', '#related'],\n contactFields: ['#define-a-field', '#fields-per-record', '#where-values-show', '#save-a-form-field', '#over-the-api', '#retire-restore-delete', '#recompute-next-activity', '#related'],\n contactRecord: ['#adding-a-contact-by-hand', '#the-record-page', '#deleting-and-erasing', '#what-each-site-keeps-to-itself', '#merging-two-records', '#likely-duplicates', '#owner', '#last-engaged', '#lifecycle-stages', '#where-the-persons-lead-is', '#finding-a-contact', '#files', '#related'],\n contacts: ['#whats-in-the-crm-area', '#unified-ingestion', '#what-each-plan-includes', '#the-contacts-page', '#import-from-csv', '#segments', '#everywhere-the-crm-shows-up', '#capture-replies', '#at-the-organization-level', '#who-can-open-the-crm', '#related'],\n crmEmailTemplates: ['#templates-and-snippets', '#merge-fields', '#saving', '#managing-templates', '#duplicate-a-template', '#shared-or-personal', '#over-the-rest-api', '#related'],\n crmLeads: ['#what-makes-a-lead', '#the-leads-list', '#working-a-lead-from-the-row', '#several-leads-at-once', '#export-csv', '#import-from-csv', '#who-owns-a-lead', '#a-leads-page', '#converting-a-lead', '#unqualifying-a-lead', '#erasing-the-person', '#who-can-do-this', '#related'],\n crmReports: ['#choosing-a-period', '#contacts', '#sources-and-lifecycle', '#conversion-by-source', '#lead-funnel', '#pipeline', '#forecast-by-close-month', '#won-and-lost', '#won-and-lost-by-owner', '#activity-by-teammate', '#tasks', '#exporting-a-table', '#crm-at-a-glance', '#how-the-numbers-are-counted', '#related'],\n crmSettings: ['#companies', '#create-companies-from-work-email-domains', '#default-owner', '#assignment-rules', '#round-robin', '#email-templates', '#email-capture', '#your-sending-addresses', '#recipes', '#related'],\n crmTasks: ['#the-tasks-page', '#the-calendar-view', '#snoozing-a-task', '#selecting-exporting-and-acting-on-many', '#import-from-csv', '#creating-a-task', '#assigning-a-task-to-someone-else', '#completing-and-reopening', '#organization-tasks', '#tasks-on-a-contact-company-or-deal', '#reminders', '#turning-reminders-off', '#next-activity', '#the-daily-digest', '#turning-it-off', '#the-dashboard-card', '#who-can-do-what', '#related'],\n crmViews: ['#the-views-control', '#a-view-is-a-link', '#filters-on-the-contacts-list', '#columns-and-sort', '#segments-and-views', '#who-sees-what', '#related'],\n datasets: ['#model-builder', '#typed-documents', '#relations', '#query-layer', '#repeatable-components', '#who-a-dataset-is-shared-with', '#import--export', '#related'],\n deals: ['#pipelines', '#stages', '#the-board-and-the-table', '#import-from-csv', '#creating-a-deal', '#line-items', '#moving-winning-and-losing', '#a-won-deal-makes-its-contact-a-customer', '#a-deals-page', '#files', '#related'],\n designedEmails: ['#create-a-template', '#duplicate-a-template', '#styling-email-blocks', '#merge-tokens', '#send-it', '#the-plain-text-version', '#start-from-a-brief-instead'],\n emailCampaigns: ['#send-a-campaign', '#campaigns-group-emails', '#what-belongs-to-a-campaign', '#who-the-email-comes-from', '#sending-domains', '#account-email-always-sends', '#marketing-needs-a-domain', '#two-ways-to-get-a-domain', '#a-domain-we-set-up-is-a-request', '#domain-states', '#senders', '#send-a-test', '#preview-the-email', '#monthly-send-cap', '#personalize-with-merge-tags', '#recipient-count', '#who-a-campaign-is-allowed-to-reach', '#schedule-a-send', '#duplicate-an-email', '#email-lists', '#manual-lists', '#list-members', '#add-to-a-list', '#import-a-list', '#remove-from-a-list', '#lists-built-from-a-rule', '#experiments', '#opens--clicks', '#the-campaign-report', '#per-contact-engagement', '#which-links-were-clicked', '#revenue-from-a-campaign', '#compliance', '#topics', '#preference-page', '#frequency-opt-down', '#double-opt-in', '#marketing-mail', '#frequency-cap', '#suppressions', '#add-a-suppression', '#platform-suppressions', '#related'],\n events: ['#manage-events', '#show-events-on-a-screen', '#search-engines', '#related'],\n forms: ['#reading-submissions-from-code', '#build-a-form', '#monthly-allowance-per-plan', '#spam-and-abuse-protection', '#the-per-site-monthly-ceiling', '#field-types', '#labels-and-placeholders', '#example-a-quick-survey', '#after-submit', '#example-grow-an-email-list-from-a-signup-form', '#where-submissions-go', '#the-inbox', '#who-a-submission-is-from', '#where-this-one-went', '#replying-to-a-submission', '#one-forms-own-page', '#duplicate-a-form', '#switch-forms-off-for-one-site', '#related'],\n installYourFirstPlugin: ['#before-you-start', '#step-1-open', '#step-2-browse', '#step-3-reviews', '#step-4-targeting', '#step-5-install', '#step-6-use', '#step-7-off', '#what-to-do-next', '#related'],\n inviteTeammates: ['#invite-someone', '#pending-invites', '#who-gets-told', '#accepting-an-invite', '#an-invitation-never-changes-who-owns-the-workspace', '#how-team-members-act', '#you-are-a-site-collaborators-support-channel', '#help-a-teammate-who-is-locked-out', '#why-you-cant-always-set-a-password', '#activity-log', '#ai-actions', '#ai-usage', '#ai-allotment', '#tips', '#related'],\n marketingOverlays: ['#announcement-bar', '#promotional-popups', '#frequency', '#popup-v2', '#multiple-overlays-scheduling--page-targeting', '#variables-in-copy', '#engagement-stats', '#related'],\n membersOnly: ['#let-visitors-sign-up', '#sign-in-sign-up-and-recovery-pages', '#forgotten-passwords', '#gate-a-screen', '#manage-your-members', '#suspend-or-reactivate-a-member', '#tips', '#related'],\n plugins: ['#install--upgrade', '#browse-card', '#whats-included', '#what-the-badges-on-a-listing-mean', '#how-plugins-run', '#when-one-plugin-depends-on-another', '#a-dependency-that-is-off-for-one-site', '#configure', '#configure-site', '#publish-your-own', '#related'],\n pos: ['#registers', '#the-register', '#platform-fees-at-the-register', '#selling-past-the-count', '#when-something-disconnects', '#reservations', '#related'],\n publisherHandbook: ['#before-your-first-publish', '#the-publisher-agreement', '#where-to-publish-from', '#what-installing-each-type-does', '#rules-an-email-starter-has-to-meet', '#publishing-a-version', '#before-you-publish', '#review-what-happens-after-you-publish', '#the-two-badges-and-what-each-one-promises', '#asking-to-be-verified', '#testing-a-version-before-it-is-approved', '#watching-your-own-submission', '#disabled-versions', '#private-plugins', '#authoring-your-listing', '#what-your-listing-can-say-about-aglyn', '#versioning--updates', '#shipping-a-new-version', '#how-installs-work-the-buyer-side', '#getting-paid', '#low-prices-and-processing'],\n redirects: ['#manage-redirects', '#sending-visitors-to-another-site', '#metrics', '#match-modes-v2', '#related'],\n sequences: ['#what-it-is-for', '#sent-from-your-own-mailbox', '#where-it-lives', '#connect-a-mailbox', '#send-as', '#daily-cap', '#mailbox-status', '#auto-pause', '#mailbox-actions', '#compliance-settings', '#allowed-countries', '#sequences', '#build-a-sequence', '#sequence-status', '#enroll', '#cold-contacts', '#enrollments', '#sending', '#what-stops-a-sequence', '#unsubscribe', '#related'],\n webhooks: ['#outbound-webhooks', '#inbound-webhooks', '#tips', '#related'],\n} as const satisfies Partial<Record<PluginDocsKey, readonly `#${string}`[]>>\n\ntype PluginAnchorMap = typeof PLUGIN_DOCS_ANCHORS\n\n/** Valid heading anchors for a plugin docs page (`never` when none). */\nexport type PluginDocsAnchor<K extends PluginDocsKey> =\n K extends keyof PluginAnchorMap ? PluginAnchorMap[K][number] : never\n"],"names":["PLUGIN_DOCS","actionsBuilder","path","title","excerpt","aglynAssist","aiAutomations","aiCrm","aiExperiments","aiMonitoring","aiProducts","aiSeo","aiThemes","assistSignals","billing","bindings","bookings","buildAWorkflow","catalog","commerce","commerceEndToEnd","companies","consoleTour","contactActivities","contactFields","contactRecord","contacts","crmEmailTemplates","crmLeads","crmReports","crmSettings","crmTasks","crmViews","datasets","deals","designedEmails","emailCampaigns","events","forms","installYourFirstPlugin","inviteTeammates","marketingOverlays","membersOnly","plugins","pos","publisherHandbook","redirects","sequences","webhooks","PLUGIN_DOCS_ANCHORS"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GACD,iDAAiD;AACjD,8CAA8C;AAC9C,oEAAoE;AAEpE,6EAA6E;AAC7E,2EAA2E;AAC3E,+EAA+E;AAW/E,OAAO,MAAMA,cAAc;IACzBC,gBAAgB;QACdC,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAC,aAAa;QACXH,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAE,eAAe;QACbJ,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAG,OAAO;QACLL,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAI,eAAe;QACbN,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAK,cAAc;QACZP,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAM,YAAY;QACVR,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAO,OAAO;QACLT,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAQ,UAAU;QACRV,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAS,eAAe;QACbX,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAU,SAAS;QACPZ,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAW,UAAU;QACRb,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAY,UAAU;QACRd,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAa,gBAAgB;QACdf,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAc,SAAS;QACPhB,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAe,UAAU;QACRjB,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAgB,kBAAkB;QAChBlB,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAiB,WAAW;QACTnB,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAkB,aAAa;QACXpB,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAmB,mBAAmB;QACjBrB,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAoB,eAAe;QACbtB,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAqB,eAAe;QACbvB,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAsB,UAAU;QACRxB,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAuB,mBAAmB;QACjBzB,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAwB,UAAU;QACR1B,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAyB,YAAY;QACV3B,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACA0B,aAAa;QACX5B,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACA2B,UAAU;QACR7B,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACA4B,UAAU;QACR9B,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACA6B,UAAU;QACR/B,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACA8B,OAAO;QACLhC,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACA+B,gBAAgB;QACdjC,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAgC,gBAAgB;QACdlC,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAiC,QAAQ;QACNnC,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAkC,OAAO;QACLpC,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAmC,wBAAwB;QACtBrC,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAoC,iBAAiB;QACftC,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAqC,mBAAmB;QACjBvC,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAsC,aAAa;QACXxC,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAuC,SAAS;QACPzC,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAwC,KAAK;QACH1C,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAyC,mBAAmB;QACjB3C,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACA0C,WAAW;QACT5C,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACA2C,WAAW;QACT7C,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACA4C,UAAU;QACR9C,MAAM;QACNC,OAAO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"}
|
|
1
|
+
{"version":3,"sources":["../../../../../../libs/aglyn/src/lib/app-utils/docs-help.generated.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// GENERATED FILE — do not edit. Regenerate with:\n// node tools/scripts/generate-docs-help.mjs\n// Source of truth: apps/docs/docs frontmatter + headings (AGL-602).\n\n// The first-party plugin consoles live in `libs/plugins/*` and cannot import\n// the console's constants, so they carry their own generated subset of the\n// docs help registry — the topics their cards actually link to, and no others.\n\nexport interface PluginDocsTopic {\n /** Docs-site path, e.g. `/commerce-and-bookings/commerce/overview`. */\n path: string\n /** Docs page title. */\n title: string\n /** Verbatim docs frontmatter description — the tooltip excerpt. */\n excerpt: string\n}\n\nexport const PLUGIN_DOCS = {\n abuseReports: {\n path: '/staff-console/abuse-reports',\n title: 'Abuse reports',\n excerpt: 'The public abuse-report queue — where outside reports land, how to triage by severity, which lever answers which report, and the CSAM and DMCA paths that are not takedown buttons.',\n },\n actionsBuilder: {\n path: '/marketing-and-automation/workflows-and-actions/actions-builder',\n title: 'Actions builder',\n excerpt: 'Map a single event to a single action without building a full workflow.',\n },\n aglynAssist: {\n path: '/getting-started/aglyn-assist',\n title: 'Aglyn Assist',\n excerpt: 'Ask the built-in AI helper how to do anything in Aglyn — it answers from these docs and links you straight to the right page.',\n },\n aiAutomations: {\n path: '/ai/automations-with-ai',\n title: 'Explain automations with AI',\n excerpt: 'Aglyn AI can explain an automation you already have and tell you why one of its runs failed. Drafting an automation from a description is not available yet.',\n },\n aiCrm: {\n path: '/ai/crm-by-ai',\n title: 'The AI CRM built into Aglyn',\n excerpt: 'An AI CRM for small business: a short summary and a suggested next step on a contact, company, deal or lead, a one-to-one email drafted into the composer, and an import\\'s columns matched to fields.',\n },\n aiExperiments: {\n path: '/ai/ab-tests-with-ai',\n title: 'A/B tests by AI: write variants, read the result',\n excerpt: 'Have Aglyn AI write two to four variants for a screen, section or email experiment, and put a finished test into plain language — with the verdict decided from the counts before the model is asked anything.',\n },\n aiMonitoring: {\n path: '/staff-console/ai-monitoring',\n title: 'AI monitoring',\n excerpt: 'How staff watch one organization\\'s AI usage — the add-on, credit pool, overage, refusals, jobs, tokens and cache hit rate, top spenders and margin — and where those figures appear across the staff console.',\n },\n aiProducts: {\n path: '/ai/products-with-ai',\n title: 'Product copy and catalogs with AI',\n excerpt: 'An AI product description generator for your catalog: write copy for one product or a whole import, propose a first catalog, and propose categories and discounts — all as proposals you review.',\n },\n aiSeo: {\n path: '/building-sites/seo/seo-by-ai',\n title: 'AI SEO for your website',\n excerpt: 'AI SEO for websites, on the pages you already have: have AI write a page or product\\'s search listing, audit every published page with a proposed fix for each finding, and draft your structured data and /llms.txt.',\n },\n aiThemes: {\n path: '/ai/theme-assist',\n title: 'Change your site\\'s theme with AI',\n excerpt: 'Describe a change to your site\\'s theme and get a proposal for the theme editor\\'s own controls, previewed before and after, that you save in the editor. Rolling out.',\n },\n assistSignals: {\n path: '/staff-console/assist-signals',\n title: 'Assist Signal',\n excerpt: 'The docs-gap and cost board behind Assist — how the ranking is ordered, why ungrounded questions are counted separately, and what the cache-read rate says about margin.',\n },\n billing: {\n path: '/workspace-and-billing/billing-and-plans/overview',\n title: 'Billing & Plans',\n excerpt: 'How Aglyn\\'s tiers, entitlements, quotas, usage meters, and seat add-ons work.',\n },\n bindings: {\n path: '/building-sites/bindings/overview',\n title: 'Bindings, Variables & Functions',\n excerpt: 'Live values in your content — typed variables, no-code functions, and rename-safe id tokens.',\n },\n bookings: {\n path: '/commerce-and-bookings/bookings/overview',\n title: 'Bookings & Scheduling',\n excerpt: 'Offer services with availability, let visitors book, take payment, and send reminders.',\n },\n buildAWorkflow: {\n path: '/marketing-and-automation/workflows-and-actions/build-a-workflow',\n title: 'Build a workflow',\n excerpt: 'Create a multi-step workflow that runs when a site event fires.',\n },\n catalog: {\n path: '/commerce-and-bookings/commerce/catalog',\n title: 'Product catalog',\n excerpt: 'Products with options and variants, categories, tags, and manual or smart collections.',\n },\n commerce: {\n path: '/commerce-and-bookings/commerce/overview',\n title: 'Commerce',\n excerpt: 'Sell physical, digital, and service products with a full catalog, orders pipeline, shipping, taxes, and your own Stripe account.',\n },\n commerceEndToEnd: {\n path: '/guides/commerce-end-to-end',\n title: 'Commerce end to end',\n excerpt: 'Create products with billing modes, design the storefront with Commerce blocks, take Stripe checkout for one-time and subscription sales, and run orders from the console.',\n },\n companies: {\n path: '/content-and-data/crm/companies',\n title: 'Companies',\n excerpt: 'Group your contacts under the businesses they belong to — one record per company, with its domain, owner, address and the people who work there.',\n },\n consoleTour: {\n path: '/getting-started/console-tour',\n title: 'The console tour',\n excerpt: 'Where things live in the Aglyn console app bar and navigation.',\n },\n contactActivities: {\n path: '/content-and-data/crm/activities',\n title: 'Activities & the timeline',\n excerpt: 'Log calls, emails, meetings and notes against a contact, a company, a deal or a lead, email one person from their record, and read it all in one timeline beside everything captured and every campaign sent.',\n },\n contactFields: {\n path: '/content-and-data/crm/custom-fields',\n title: 'Custom fields',\n excerpt: 'Define your own properties on contacts, companies and deals — text, number, date, choice, checkbox or link — show them on every record and its list, and save form answers straight into a contact\\'s.',\n },\n contactRecord: {\n path: '/content-and-data/crm/contact-record',\n title: 'The contact record',\n excerpt: 'Add a contact by hand, keep a profile on them — phone, company, title, address, owner and lifecycle stage — open their own page in the CRM, and merge two records that turn out to be one person.',\n },\n contacts: {\n path: '/content-and-data/crm/overview',\n title: 'CRM',\n excerpt: 'One place for the people who interact with your sites — contacts captured from forms, members, orders and bookings, with leads, companies, a deals pipeline, tasks, a timeline, reports and custom fields.',\n },\n crmEmailTemplates: {\n path: '/content-and-data/crm/email-templates',\n title: 'Email templates',\n excerpt: 'Keep the letters your team sends from a record — templates that fill in the subject and the message, snippets that drop in a paragraph, and merge fields that fill in the person\\'s name, their company, the deal and you.',\n },\n crmLeads: {\n path: '/content-and-data/crm/leads',\n title: 'Leads',\n excerpt: 'Work the people your site has captured — a status, an owner and notes on every lead — and convert one into a contact, a company and a deal.',\n },\n crmReports: {\n path: '/content-and-data/crm/reports',\n title: 'Reports',\n excerpt: 'New contacts, where they came from and which sources convert, the lead funnel, the open pipeline and its forecast, won and lost, who logged what, and the task load — counted on the server, every table exportable as CSV.',\n },\n crmSettings: {\n path: '/content-and-data/crm/settings',\n title: 'CRM settings',\n excerpt: 'What the CRM does on its own for every site — whether a company is created from a contact\\'s work email domain, who a new contact is assigned to, the address that files replies on a record, and each site\\'s recipes.',\n },\n crmTasks: {\n path: '/content-and-data/crm/tasks',\n title: 'Tasks & follow-ups',\n excerpt: 'Calls, emails, meetings and to-dos with a due date, an assignee and a link to the record they are for — overdue and today read off the clock, a snooze, a reminder at its own time, and a morning digest.',\n },\n crmViews: {\n path: '/content-and-data/crm/views',\n title: 'Saved views',\n excerpt: 'Keep a CRM list\\'s filters, columns and sort under a name, open it from the views menu or a link, share it with the team, and use a contacts view as an email audience.',\n },\n datasets: {\n path: '/content-and-data/datasets/overview',\n title: 'Datasets & Dynamic Content',\n excerpt: 'Model structured content with typed fields and relations, then bind it into repeatable components.',\n },\n deals: {\n path: '/content-and-data/crm/deals',\n title: 'Deals pipeline',\n excerpt: 'Every open deal by stage — with an amount, an owner and an expected close — as a board you drag across or a table you page through, and the won and lost history behind it.',\n },\n designedEmails: {\n path: '/marketing-and-automation/email-campaigns/designed-emails',\n title: 'Designed emails',\n excerpt: 'Build campaign emails in the besigner with email-safe blocks and merge tokens — no separate editor.',\n },\n emailCampaigns: {\n path: '/marketing-and-automation/email-campaigns/overview',\n title: 'Email Campaigns',\n excerpt: 'Campaigns to audiences built from your contacts. Campaign email starts at Pro and needs a sending domain of the site\\'s own; receipts and account email send on every plan.',\n },\n events: {\n path: '/content-and-data/events/overview',\n title: 'Events Calendar',\n excerpt: 'Keep a schedule of events in the console and publish the ones you choose to any screen, with search-engine event markup.',\n },\n forms: {\n path: '/content-and-data/forms/overview',\n title: 'Forms & Lead Capture',\n excerpt: 'Add forms to your site, collect submissions in an inbox, and write them into datasets.',\n },\n installYourFirstPlugin: {\n path: '/guides/install-your-first-plugin',\n title: 'Install your first marketplace item',\n excerpt: 'A click-by-click walkthrough of the Marketplace — find something, choose which sites get it, install it, and turn it off again.',\n },\n inviteTeammates: {\n path: '/workspace-and-billing/teams-and-roles/invite-teammates',\n title: 'Invite teammates',\n excerpt: 'Add people to your site and understand how team members act within your organization.',\n },\n marketingOverlays: {\n path: '/marketing-and-automation/marketing-overlays/overview',\n title: 'Marketing Overlays',\n excerpt: 'Site-wide announcement bars and promotional popups with triggers, scheduling, and email capture.',\n },\n membersOnly: {\n path: '/workspace-and-billing/teams-and-roles/members-only',\n title: 'Members-only areas',\n excerpt: 'Let visitors sign up as members and gate screens so only members can view them.',\n },\n plugins: {\n path: '/developers/plugins/overview',\n title: 'Plugins & Marketplace',\n excerpt: 'Extend Aglyn with sandboxed plugins — install from the marketplace, configure them, and publish your own.',\n },\n pos: {\n path: '/commerce-and-bookings/commerce/pos-and-reservations',\n title: 'POS & reservations',\n excerpt: 'Sell in person from the console register and take date-range reservations with deposits.',\n },\n publishAPlugin: {\n path: '/developers/plugins/publish-a-plugin',\n title: 'Publish a plugin',\n excerpt: 'Ship your own plugin to the marketplace with version pinning.',\n },\n publisherHandbook: {\n path: '/developers/plugins/publishing/publisher-handbook',\n title: 'Publisher handbook',\n excerpt: 'Publishing to the Aglyn marketplace — from profile setup through listing authoring, review, updates, and getting paid.',\n },\n redirects: {\n path: '/building-sites/redirects/overview',\n title: 'Redirects',\n excerpt: 'Manage URL redirects with validation, loop detection, and hit metrics.',\n },\n sequences: {\n path: '/content-and-data/crm/sequences',\n title: 'Sequences',\n excerpt: 'One-to-one email sequences a rep sends to a person from their own connected mailbox, kept with the CRM. Rolling out.',\n },\n webhooks: {\n path: '/marketing-and-automation/workflows-and-actions/webhooks',\n title: 'Webhooks',\n excerpt: 'Connect Aglyn to other systems with outbound and inbound webhooks.',\n },\n} as const satisfies Record<string, PluginDocsTopic>\n\nexport type PluginDocsKey = keyof typeof PLUGIN_DOCS\n\nexport const PLUGIN_DOCS_ANCHORS = {\n abuseReports: ['#where-reports-come-from', '#triage-by-severity', '#csam', '#which-lever', '#statuses', '#disclosure', '#dmca', '#counter-notices', '#counter-notice-clock', '#counter-notice-steps', '#repeat-infringers', '#repeat-infringer-threshold', '#known-gaps', '#related'],\n actionsBuilder: ['#create-an-action', '#recipes', '#describe-it', '#triggers', '#crm-events', '#only-run-when-a-field-matches', '#chain-multiple-conditions-andor', '#steps', '#crm-steps', '#step-conditions', '#sequences', '#run-history', '#what-is-and-isnt-recorded', '#interactions-from-the-besigner', '#when-to-use-which', '#related'],\n aglynAssist: ['#what-it-can-do', '#aglyn-ai', '#answers-for-beginners-and-developers', '#offers-to-open-a-page', '#edits-in-the-besigner', '#where-an-answer-came-from', '#answers-straight-from-the-documentation', '#message-limits', '#feedback', '#privacy'],\n aiAutomations: ['#draft', '#explain', '#why-a-run-failed', '#what-is-sent', '#who-can-use-it', '#related'],\n aiCrm: ['#summarize-a-record', '#summaries-are-reused-until-the-record-changes', '#draft-an-email', '#match-columns', '#what-is-sent', '#who-can-use-it', '#related'],\n aiExperiments: ['#it-proposes-you-write', '#write-variants', '#putting-them-in', '#what-it-will-not-write', '#read-a-result', '#the-verdict', '#the-words', '#undecided', '#what-is-sent', '#who-can-use-it', '#related'],\n aiMonitoring: ['#the-ai-card', '#where-else', '#one-account', '#the-spend-leaderboard', '#alerts', '#related'],\n aiProducts: ['#write-a-products-copy', '#write-copy-for-many-products', '#when-you-import-products', '#propose-a-first-catalog', '#propose-categories-and-discounts', '#what-the-copy-never-says', '#what-is-sent-to-the-ai-provider', '#who-can-use-it', '#related'],\n aiSeo: ['#write-a-pages-listing', '#write-a-products-listing', '#audit-the-whole-site', '#target-keywords', '#apply-all-as-drafts', '#structured-data-and-llmstxt', '#related'],\n aiThemes: ['#change-what-you-describe-or-design-a-new-theme', '#match-your-brand', '#review-the-proposal', '#save-it-or-dont', '#who-can-use-it', '#related'],\n assistSignals: ['#the-workflow-this-board-exists-for', '#fleet', '#the-cache-read-rate-and-what-a-bad-number-looks-like', '#where-the-money-goes', '#tokens-by-kind', '#docs-gaps', '#questions-the-docs-could-not-answer', '#what-people-actually-asked', '#what-assist-costs-by-workspace', '#reading-the-sample-honestly', '#related'],\n billing: ['#tiers--entitlements', '#enterprise', '#single-sign-on-and-enforcement', '#usage-meters', '#who-is-generating-what', '#ai-allotments', '#storage-overage', '#if-you-would-rather-uploads-stopped', '#assist-overage', '#stop-ai-assist-at-the-included-band', '#ai-overage-ceiling', '#free-ai-credits', '#ai-credit-alerts', '#usage-budget', '#seats', '#crm-records', '#the-crm-suite', '#one-to-one-email', '#organization-data', '#api-access', '#payments', '#outstanding', '#plan-total', '#billing-email', '#payment-methods', '#billing-address', '#tax-ids', '#sales-tax', '#platform-fees', '#related'],\n bindings: ['#binding-tokens', '#rename-safe-id-tokens', '#insert-a-variable', '#token-pills', '#in-the-canvas-text-editor', '#site-details', '#typed-variables', '#no-code-functions', '#parameters-a-visitor-can-answer', '#a-calculator-you-lay-out', '#where-used--safety', '#workflows', '#related'],\n bookings: ['#set-up-bookings', '#taking-bookings', '#reminders', '#payments-and-fees', '#service-tax', '#manage', '#booking-from-the-crm', '#canceling-and-refunding', '#related'],\n buildAWorkflow: ['#1-open-the-workflows-page', '#2-choose-a-trigger', '#3-add-steps', '#waiting', '#4-save-and-test', '#duplicate-a-workflow', '#tips', '#related'],\n catalog: ['#products-options-and-variants', '#billing-modes-and-subscriptions', '#ai', '#categories-and-tags', '#collections', '#slugs', '#merchant-center-feed', '#related'],\n commerce: ['#products-hub', '#inventory', '#reserved-stock', '#stock-movements', '#gift-cards', '#recovery-and-alerts', '#orders', '#orders-screen', '#order-statuses', '#order-money-tiles', '#a-lost-dispute', '#shipping--taxes', '#lodging-tax-on-reservations', '#storefront-sales-tax', '#destination-coverage', '#dropshipping', '#related'],\n commerceEndToEnd: ['#1-connect-payments', '#2-create-products', '#3-design-the-storefront', '#catalog-search-filters-and-sort', '#category-pages', '#the-product-page-template', '#4-what-checkout-does', '#paying-without-leaving-your-site', '#5-run-orders-from-the-console', '#6-subscriptions--the-stripe-portal', '#related'],\n companies: ['#the-companies-list', '#create-a-company', '#a-companys-page', '#contacts-at-a-company', '#linked-on-capture', '#import-from-csv', '#export-csv', '#deleting-a-company', '#who-can-see-a-company', '#files', '#related'],\n consoleTour: ['#the-app-bar', '#in-context-help', '#primary-navigation', '#editing-vs-managing', '#the-sites-list', '#the-status-pill', '#how-the-pill-is-decided', '#your-site-allowance', '#a-sites-dashboard', '#next', '#workspace-settings--notifications', '#the-notifications-feed', '#notification-settings', '#workspace-and-site-overrides', '#daily-digests', '#alerts-on-this-device'],\n contactActivities: ['#four-kinds-of-history', '#campaign-email', '#logging-an-activity', '#meeting-from-a-booking', '#click-to-call', '#sending-an-email', '#delivery-states', '#captured-email', '#where-an-activity-is-visible', '#the-recent-activity-feed', '#related'],\n contactFields: ['#define-a-field', '#fields-per-record', '#where-values-show', '#save-a-form-field', '#over-the-api', '#retire-restore-delete', '#recompute-next-activity', '#related'],\n contactRecord: ['#adding-a-contact-by-hand', '#the-record-page', '#deleting-and-erasing', '#what-each-site-keeps-to-itself', '#merging-two-records', '#likely-duplicates', '#owner', '#last-engaged', '#lifecycle-stages', '#where-the-persons-lead-is', '#finding-a-contact', '#files', '#related'],\n contacts: ['#whats-in-the-crm-area', '#unified-ingestion', '#what-each-plan-includes', '#the-contacts-page', '#import-from-csv', '#segments', '#everywhere-the-crm-shows-up', '#capture-replies', '#at-the-organization-level', '#who-can-open-the-crm', '#related'],\n crmEmailTemplates: ['#templates-and-snippets', '#merge-fields', '#saving', '#managing-templates', '#duplicate-a-template', '#shared-or-personal', '#over-the-rest-api', '#related'],\n crmLeads: ['#what-makes-a-lead', '#the-leads-list', '#working-a-lead-from-the-row', '#several-leads-at-once', '#export-csv', '#import-from-csv', '#who-owns-a-lead', '#a-leads-page', '#converting-a-lead', '#unqualifying-a-lead', '#erasing-the-person', '#who-can-do-this', '#related'],\n crmReports: ['#choosing-a-period', '#contacts', '#sources-and-lifecycle', '#conversion-by-source', '#lead-funnel', '#pipeline', '#forecast-by-close-month', '#won-and-lost', '#won-and-lost-by-owner', '#activity-by-teammate', '#tasks', '#exporting-a-table', '#crm-at-a-glance', '#how-the-numbers-are-counted', '#related'],\n crmSettings: ['#companies', '#create-companies-from-work-email-domains', '#default-owner', '#assignment-rules', '#round-robin', '#email-templates', '#email-capture', '#your-sending-addresses', '#recipes', '#related'],\n crmTasks: ['#the-tasks-page', '#the-calendar-view', '#snoozing-a-task', '#selecting-exporting-and-acting-on-many', '#import-from-csv', '#creating-a-task', '#assigning-a-task-to-someone-else', '#completing-and-reopening', '#organization-tasks', '#tasks-on-a-contact-company-or-deal', '#reminders', '#turning-reminders-off', '#next-activity', '#the-daily-digest', '#turning-it-off', '#the-dashboard-card', '#who-can-do-what', '#related'],\n crmViews: ['#the-views-control', '#a-view-is-a-link', '#filters-on-the-contacts-list', '#columns-and-sort', '#segments-and-views', '#who-sees-what', '#related'],\n datasets: ['#model-builder', '#typed-documents', '#relations', '#query-layer', '#repeatable-components', '#who-a-dataset-is-shared-with', '#import--export', '#related'],\n deals: ['#pipelines', '#stages', '#the-board-and-the-table', '#import-from-csv', '#creating-a-deal', '#line-items', '#moving-winning-and-losing', '#a-won-deal-makes-its-contact-a-customer', '#a-deals-page', '#files', '#related'],\n designedEmails: ['#create-a-template', '#duplicate-a-template', '#styling-email-blocks', '#merge-tokens', '#send-it', '#the-plain-text-version', '#start-from-a-brief-instead'],\n emailCampaigns: ['#send-a-campaign', '#campaigns-group-emails', '#what-belongs-to-a-campaign', '#who-the-email-comes-from', '#sending-domains', '#account-email-always-sends', '#marketing-needs-a-domain', '#two-ways-to-get-a-domain', '#a-domain-we-set-up-is-a-request', '#domain-states', '#senders', '#send-a-test', '#preview-the-email', '#monthly-send-cap', '#personalize-with-merge-tags', '#recipient-count', '#who-a-campaign-is-allowed-to-reach', '#schedule-a-send', '#duplicate-an-email', '#email-lists', '#manual-lists', '#list-members', '#add-to-a-list', '#import-a-list', '#remove-from-a-list', '#lists-built-from-a-rule', '#experiments', '#opens--clicks', '#the-campaign-report', '#per-contact-engagement', '#which-links-were-clicked', '#revenue-from-a-campaign', '#compliance', '#topics', '#preference-page', '#frequency-opt-down', '#double-opt-in', '#marketing-mail', '#frequency-cap', '#suppressions', '#add-a-suppression', '#platform-suppressions', '#related'],\n events: ['#manage-events', '#show-events-on-a-screen', '#search-engines', '#related'],\n forms: ['#reading-submissions-from-code', '#build-a-form', '#monthly-allowance-per-plan', '#spam-and-abuse-protection', '#the-per-site-monthly-ceiling', '#field-types', '#labels-and-placeholders', '#example-a-quick-survey', '#after-submit', '#example-grow-an-email-list-from-a-signup-form', '#where-submissions-go', '#the-inbox', '#who-a-submission-is-from', '#where-this-one-went', '#replying-to-a-submission', '#one-forms-own-page', '#duplicate-a-form', '#switch-forms-off-for-one-site', '#related'],\n installYourFirstPlugin: ['#before-you-start', '#step-1-open', '#step-2-browse', '#step-3-reviews', '#step-4-targeting', '#step-5-install', '#step-6-use', '#step-7-off', '#what-to-do-next', '#related'],\n inviteTeammates: ['#invite-someone', '#pending-invites', '#who-gets-told', '#accepting-an-invite', '#an-invitation-never-changes-who-owns-the-workspace', '#how-team-members-act', '#you-are-a-site-collaborators-support-channel', '#help-a-teammate-who-is-locked-out', '#why-you-cant-always-set-a-password', '#activity-log', '#ai-actions', '#ai-usage', '#ai-allotment', '#tips', '#related'],\n marketingOverlays: ['#announcement-bar', '#promotional-popups', '#frequency', '#popup-v2', '#multiple-overlays-scheduling--page-targeting', '#variables-in-copy', '#engagement-stats', '#related'],\n membersOnly: ['#let-visitors-sign-up', '#sign-in-sign-up-and-recovery-pages', '#forgotten-passwords', '#gate-a-screen', '#manage-your-members', '#suspend-or-reactivate-a-member', '#tips', '#related'],\n plugins: ['#install--upgrade', '#browse-card', '#whats-included', '#what-the-badges-on-a-listing-mean', '#how-plugins-run', '#when-one-plugin-depends-on-another', '#a-dependency-that-is-off-for-one-site', '#configure', '#configure-site', '#publish-your-own', '#related'],\n pos: ['#registers', '#the-register', '#platform-fees-at-the-register', '#selling-past-the-count', '#when-something-disconnects', '#reservations', '#related'],\n publishAPlugin: ['#the-publish-pipeline', '#private-plugins', '#paid-listings', '#your-publisher-profile', '#tips', '#related'],\n publisherHandbook: ['#before-your-first-publish', '#the-publisher-agreement', '#where-to-publish-from', '#what-installing-each-type-does', '#rules-an-email-starter-has-to-meet', '#publishing-a-version', '#before-you-publish', '#review-what-happens-after-you-publish', '#the-two-badges-and-what-each-one-promises', '#asking-to-be-verified', '#testing-a-version-before-it-is-approved', '#watching-your-own-submission', '#disabled-versions', '#private-plugins', '#authoring-your-listing', '#what-your-listing-can-say-about-aglyn', '#versioning--updates', '#shipping-a-new-version', '#how-installs-work-the-buyer-side', '#getting-paid', '#low-prices-and-processing'],\n redirects: ['#manage-redirects', '#sending-visitors-to-another-site', '#metrics', '#match-modes-v2', '#related'],\n sequences: ['#what-it-is-for', '#sent-from-your-own-mailbox', '#where-it-lives', '#connect-a-mailbox', '#send-as', '#daily-cap', '#mailbox-status', '#auto-pause', '#mailbox-actions', '#compliance-settings', '#allowed-countries', '#sequences', '#build-a-sequence', '#sequence-status', '#enroll', '#cold-contacts', '#enrollments', '#sending', '#what-stops-a-sequence', '#unsubscribe', '#related'],\n webhooks: ['#outbound-webhooks', '#inbound-webhooks', '#tips', '#related'],\n} as const satisfies Partial<Record<PluginDocsKey, readonly `#${string}`[]>>\n\ntype PluginAnchorMap = typeof PLUGIN_DOCS_ANCHORS\n\n/** Valid heading anchors for a plugin docs page (`never` when none). */\nexport type PluginDocsAnchor<K extends PluginDocsKey> =\n K extends keyof PluginAnchorMap ? PluginAnchorMap[K][number] : never\n"],"names":["PLUGIN_DOCS","abuseReports","path","title","excerpt","actionsBuilder","aglynAssist","aiAutomations","aiCrm","aiExperiments","aiMonitoring","aiProducts","aiSeo","aiThemes","assistSignals","billing","bindings","bookings","buildAWorkflow","catalog","commerce","commerceEndToEnd","companies","consoleTour","contactActivities","contactFields","contactRecord","contacts","crmEmailTemplates","crmLeads","crmReports","crmSettings","crmTasks","crmViews","datasets","deals","designedEmails","emailCampaigns","events","forms","installYourFirstPlugin","inviteTeammates","marketingOverlays","membersOnly","plugins","pos","publishAPlugin","publisherHandbook","redirects","sequences","webhooks","PLUGIN_DOCS_ANCHORS"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GACD,iDAAiD;AACjD,8CAA8C;AAC9C,oEAAoE;AAEpE,6EAA6E;AAC7E,2EAA2E;AAC3E,+EAA+E;AAW/E,OAAO,MAAMA,cAAc;IACzBC,cAAc;QACZC,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAC,gBAAgB;QACdH,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAE,aAAa;QACXJ,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAG,eAAe;QACbL,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAI,OAAO;QACLN,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAK,eAAe;QACbP,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAM,cAAc;QACZR,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAO,YAAY;QACVT,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAQ,OAAO;QACLV,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAS,UAAU;QACRX,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAU,eAAe;QACbZ,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAW,SAAS;QACPb,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAY,UAAU;QACRd,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAa,UAAU;QACRf,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAc,gBAAgB;QACdhB,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAe,SAAS;QACPjB,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAgB,UAAU;QACRlB,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAiB,kBAAkB;QAChBnB,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAkB,WAAW;QACTpB,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAmB,aAAa;QACXrB,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAoB,mBAAmB;QACjBtB,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAqB,eAAe;QACbvB,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAsB,eAAe;QACbxB,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAuB,UAAU;QACRzB,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAwB,mBAAmB;QACjB1B,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAyB,UAAU;QACR3B,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACA0B,YAAY;QACV5B,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACA2B,aAAa;QACX7B,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACA4B,UAAU;QACR9B,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACA6B,UAAU;QACR/B,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACA8B,UAAU;QACRhC,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACA+B,OAAO;QACLjC,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAgC,gBAAgB;QACdlC,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAiC,gBAAgB;QACdnC,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAkC,QAAQ;QACNpC,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAmC,OAAO;QACLrC,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAoC,wBAAwB;QACtBtC,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAqC,iBAAiB;QACfvC,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAsC,mBAAmB;QACjBxC,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAuC,aAAa;QACXzC,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAwC,SAAS;QACP1C,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAyC,KAAK;QACH3C,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACA0C,gBAAgB;QACd5C,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACA2C,mBAAmB;QACjB7C,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACA4C,WAAW;QACT9C,MAAM;QACNC,OA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"}
|
|
@@ -0,0 +1,93 @@
|
|
|
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
|
+
* A usable `src` for a picked media asset.
|
|
19
|
+
*
|
|
20
|
+
* Lifted out of the listing detail editor when the publish form gained a
|
|
21
|
+
* media picker of its own (AGL-1080).
|
|
22
|
+
*
|
|
23
|
+
* NO LONGER THE WRITER FOR MARKDOWN BODIES (AGL-1705). This helper used to
|
|
24
|
+
* justify prefixing the origin by saying the markdown "renders elsewhere".
|
|
25
|
+
* That claim was checked and is false: the marketplace README's only renderer
|
|
26
|
+
* is the console's own `marketplaceListing` slot, and `apps/tenant` does not
|
|
27
|
+
* import the marketplace plugin. The two README writers and the blog body now
|
|
28
|
+
* store `mediaNodeSrc`'s `media:` reference, which `resolveMediaSrc` turns
|
|
29
|
+
* back into this same `/api/media/cdn/…` path at render — without freezing
|
|
30
|
+
* either the origin or the route shape into the document.
|
|
31
|
+
*
|
|
32
|
+
* What is left for this helper is the listing's image FIELDS —
|
|
33
|
+
* `previewImageUrl`, `logoUrl`, `screenshots` — read out of band by
|
|
34
|
+
* `og:image` and by `resolveSocialImage`, where an absolute URL is the point
|
|
35
|
+
* (AGL-1701). The origin prefix stays for them.
|
|
36
|
+
*/
|
|
37
|
+
export declare function mediaSrc(media: {
|
|
38
|
+
url?: string;
|
|
39
|
+
cdnPath?: string;
|
|
40
|
+
}): string;
|
|
41
|
+
/**
|
|
42
|
+
* A `src` for a THUMBNAIL — a grid tile, a picker cell, a preview strip.
|
|
43
|
+
*
|
|
44
|
+
* Separate from {@link mediaSrc} because the two answer different questions.
|
|
45
|
+
* `mediaSrc` produces a URL that gets *persisted* (markdown bodies, listing
|
|
46
|
+
* images), so it must stay width-free. This one produces a URL that is only
|
|
47
|
+
* ever rendered, so it can ask for the smallest generated WebP variant.
|
|
48
|
+
*
|
|
49
|
+
* The DAM grid read `media.url` directly, which is the raw
|
|
50
|
+
* `firebasestorage.googleapis.com` download URL: every tile fetched the
|
|
51
|
+
* FULL-SIZE original straight from Cloud Storage, bypassing both the WebP
|
|
52
|
+
* variants (AGL-175) and the Vercel edge cache. A library page of 24 assets
|
|
53
|
+
* at ~200 KB each is ~4.8 MB of Storage egress per view, re-fetched by every
|
|
54
|
+
* viewer, where the 320px variants are ~15 KB each.
|
|
55
|
+
*
|
|
56
|
+
* `?w=` degrades safely: `serveMediaCdn` only serves a variant when the
|
|
57
|
+
* asset's `variants` array actually contains that width, and otherwise
|
|
58
|
+
* serves the original — so an SVG, a small logo, or an asset uploaded before
|
|
59
|
+
* variants existed still renders, just without the saving.
|
|
60
|
+
*/
|
|
61
|
+
export declare function mediaThumbnailSrc(media: {
|
|
62
|
+
url?: string;
|
|
63
|
+
cdnPath?: string;
|
|
64
|
+
}, width: number): string;
|
|
65
|
+
/**
|
|
66
|
+
* A `src` for a VIDEO's poster still, or `undefined` when it has none
|
|
67
|
+
* (AGL-2742).
|
|
68
|
+
*
|
|
69
|
+
* The DAM grid drew a video tile as a `<video src>` pointing at the master.
|
|
70
|
+
* A browser paints a first frame by fetching enough of the file to decode
|
|
71
|
+
* one, so a folder of eight clips was tens of megabytes of Storage egress
|
|
72
|
+
* per view — the same defect {@link mediaThumbnailSrc} was written to fix for
|
|
73
|
+
* images, on the type where each tile costs a hundred times more. And unlike
|
|
74
|
+
* an image tile it could not be helped by a variant, because until now a
|
|
75
|
+
* video had nothing smaller to serve.
|
|
76
|
+
*
|
|
77
|
+
* Returns `undefined` rather than a fallback URL on purpose: the caller has
|
|
78
|
+
* to branch anyway (a `<video>` with no poster still needs `preload="none"`
|
|
79
|
+
* so it stops fetching), and an "always answers" helper would hand back a URL
|
|
80
|
+
* that 404s for every video uploaded before this shipped.
|
|
81
|
+
*
|
|
82
|
+
* Mirrors `Aglyn.mediaPosterSrc` for a media DOCUMENT rather than a stored
|
|
83
|
+
* `media:` reference — the console holds documents, the renderer holds
|
|
84
|
+
* references, and neither can use the other's input.
|
|
85
|
+
*/
|
|
86
|
+
export declare function mediaPosterThumbnailSrc(media: {
|
|
87
|
+
url?: string;
|
|
88
|
+
cdnPath?: string;
|
|
89
|
+
poster?: {
|
|
90
|
+
variants?: number[];
|
|
91
|
+
} | null;
|
|
92
|
+
}, width?: number): string | undefined;
|
|
93
|
+
export default mediaSrc;
|
|
@@ -0,0 +1,114 @@
|
|
|
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
|
+
* A usable `src` for a picked media asset.
|
|
18
|
+
*
|
|
19
|
+
* Lifted out of the listing detail editor when the publish form gained a
|
|
20
|
+
* media picker of its own (AGL-1080).
|
|
21
|
+
*
|
|
22
|
+
* NO LONGER THE WRITER FOR MARKDOWN BODIES (AGL-1705). This helper used to
|
|
23
|
+
* justify prefixing the origin by saying the markdown "renders elsewhere".
|
|
24
|
+
* That claim was checked and is false: the marketplace README's only renderer
|
|
25
|
+
* is the console's own `marketplaceListing` slot, and `apps/tenant` does not
|
|
26
|
+
* import the marketplace plugin. The two README writers and the blog body now
|
|
27
|
+
* store `mediaNodeSrc`'s `media:` reference, which `resolveMediaSrc` turns
|
|
28
|
+
* back into this same `/api/media/cdn/…` path at render — without freezing
|
|
29
|
+
* either the origin or the route shape into the document.
|
|
30
|
+
*
|
|
31
|
+
* What is left for this helper is the listing's image FIELDS —
|
|
32
|
+
* `previewImageUrl`, `logoUrl`, `screenshots` — read out of band by
|
|
33
|
+
* `og:image` and by `resolveSocialImage`, where an absolute URL is the point
|
|
34
|
+
* (AGL-1701). The origin prefix stays for them.
|
|
35
|
+
*/ export function mediaSrc(media) {
|
|
36
|
+
// `cdnPath` FIRST (AGL-1215). It is keyed by media id, so it survives a
|
|
37
|
+
// folder move — which physically copies the object, rewrites `url` and
|
|
38
|
+
// deletes the original, permanently breaking anything holding the old
|
|
39
|
+
// raw URL. Preferring `url` meant this helper emitted the fragile form
|
|
40
|
+
// for every paid org, where both fields are always populated. `url`
|
|
41
|
+
// stays the fallback for free-tier orgs (`cdnPath` is a paid `mediaCdn`
|
|
42
|
+
// entitlement) and legacy uploads that predate it.
|
|
43
|
+
if (media.cdnPath) return typeof window === 'undefined' ? media.cdnPath : `${window.location.origin}${media.cdnPath}`;
|
|
44
|
+
if (media.url) return media.url;
|
|
45
|
+
return '';
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* A `src` for a THUMBNAIL — a grid tile, a picker cell, a preview strip.
|
|
49
|
+
*
|
|
50
|
+
* Separate from {@link mediaSrc} because the two answer different questions.
|
|
51
|
+
* `mediaSrc` produces a URL that gets *persisted* (markdown bodies, listing
|
|
52
|
+
* images), so it must stay width-free. This one produces a URL that is only
|
|
53
|
+
* ever rendered, so it can ask for the smallest generated WebP variant.
|
|
54
|
+
*
|
|
55
|
+
* The DAM grid read `media.url` directly, which is the raw
|
|
56
|
+
* `firebasestorage.googleapis.com` download URL: every tile fetched the
|
|
57
|
+
* FULL-SIZE original straight from Cloud Storage, bypassing both the WebP
|
|
58
|
+
* variants (AGL-175) and the Vercel edge cache. A library page of 24 assets
|
|
59
|
+
* at ~200 KB each is ~4.8 MB of Storage egress per view, re-fetched by every
|
|
60
|
+
* viewer, where the 320px variants are ~15 KB each.
|
|
61
|
+
*
|
|
62
|
+
* `?w=` degrades safely: `serveMediaCdn` only serves a variant when the
|
|
63
|
+
* asset's `variants` array actually contains that width, and otherwise
|
|
64
|
+
* serves the original — so an SVG, a small logo, or an asset uploaded before
|
|
65
|
+
* variants existed still renders, just without the saving.
|
|
66
|
+
*/ export function mediaThumbnailSrc(media, width) {
|
|
67
|
+
const cdnPath = media.cdnPath;
|
|
68
|
+
// No `cdnPath` means a free-tier or private asset, and a width parameter
|
|
69
|
+
// on a raw storage URL means nothing — appending one would only fork the
|
|
70
|
+
// browser cache for identical bytes.
|
|
71
|
+
if (!cdnPath) return mediaSrc(media);
|
|
72
|
+
// A signed private URL already carries `?exp=&sig=`; a second `?` makes a
|
|
73
|
+
// path the route rejects outright.
|
|
74
|
+
if (cdnPath.includes('?')) return mediaSrc(media);
|
|
75
|
+
return `${mediaSrc(media)}?w=${width}`;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* A `src` for a VIDEO's poster still, or `undefined` when it has none
|
|
79
|
+
* (AGL-2742).
|
|
80
|
+
*
|
|
81
|
+
* The DAM grid drew a video tile as a `<video src>` pointing at the master.
|
|
82
|
+
* A browser paints a first frame by fetching enough of the file to decode
|
|
83
|
+
* one, so a folder of eight clips was tens of megabytes of Storage egress
|
|
84
|
+
* per view — the same defect {@link mediaThumbnailSrc} was written to fix for
|
|
85
|
+
* images, on the type where each tile costs a hundred times more. And unlike
|
|
86
|
+
* an image tile it could not be helped by a variant, because until now a
|
|
87
|
+
* video had nothing smaller to serve.
|
|
88
|
+
*
|
|
89
|
+
* Returns `undefined` rather than a fallback URL on purpose: the caller has
|
|
90
|
+
* to branch anyway (a `<video>` with no poster still needs `preload="none"`
|
|
91
|
+
* so it stops fetching), and an "always answers" helper would hand back a URL
|
|
92
|
+
* that 404s for every video uploaded before this shipped.
|
|
93
|
+
*
|
|
94
|
+
* Mirrors `Aglyn.mediaPosterSrc` for a media DOCUMENT rather than a stored
|
|
95
|
+
* `media:` reference — the console holds documents, the renderer holds
|
|
96
|
+
* references, and neither can use the other's input.
|
|
97
|
+
*/ export function mediaPosterThumbnailSrc(media, width) {
|
|
98
|
+
var _media_poster_variants;
|
|
99
|
+
// A poster is only reachable through the CDN route, so a free-tier or
|
|
100
|
+
// private asset has no URL that could serve one — the same reason
|
|
101
|
+
// `mediaThumbnailSrc` gives up on `?w=` there.
|
|
102
|
+
if (!media.poster || !media.cdnPath || media.cdnPath.includes('?')) {
|
|
103
|
+
return undefined;
|
|
104
|
+
}
|
|
105
|
+
const variants = (_media_poster_variants = media.poster.variants) != null ? _media_poster_variants : [];
|
|
106
|
+
// Only a width that was actually generated. `serveMediaCdn` would fall
|
|
107
|
+
// back to the full poster for any other, which works and defeats the point
|
|
108
|
+
// — a 1920px still in a 116px tile.
|
|
109
|
+
const narrowed = width && variants.includes(width) ? `&w=${width}` : '';
|
|
110
|
+
return `${mediaSrc(media)}?poster=1${narrowed}`;
|
|
111
|
+
}
|
|
112
|
+
export default mediaSrc;
|
|
113
|
+
|
|
114
|
+
//# sourceMappingURL=media-src.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../libs/aglyn/src/lib/app-utils/media-src.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 * A usable `src` for a picked media asset.\n *\n * Lifted out of the listing detail editor when the publish form gained a\n * media picker of its own (AGL-1080).\n *\n * NO LONGER THE WRITER FOR MARKDOWN BODIES (AGL-1705). This helper used to\n * justify prefixing the origin by saying the markdown \"renders elsewhere\".\n * That claim was checked and is false: the marketplace README's only renderer\n * is the console's own `marketplaceListing` slot, and `apps/tenant` does not\n * import the marketplace plugin. The two README writers and the blog body now\n * store `mediaNodeSrc`'s `media:` reference, which `resolveMediaSrc` turns\n * back into this same `/api/media/cdn/…` path at render — without freezing\n * either the origin or the route shape into the document.\n *\n * What is left for this helper is the listing's image FIELDS —\n * `previewImageUrl`, `logoUrl`, `screenshots` — read out of band by\n * `og:image` and by `resolveSocialImage`, where an absolute URL is the point\n * (AGL-1701). The origin prefix stays for them.\n */\nexport function mediaSrc(media: {\n url?: string\n cdnPath?: string\n}): string {\n // `cdnPath` FIRST (AGL-1215). It is keyed by media id, so it survives a\n // folder move — which physically copies the object, rewrites `url` and\n // deletes the original, permanently breaking anything holding the old\n // raw URL. Preferring `url` meant this helper emitted the fragile form\n // for every paid org, where both fields are always populated. `url`\n // stays the fallback for free-tier orgs (`cdnPath` is a paid `mediaCdn`\n // entitlement) and legacy uploads that predate it.\n if (media.cdnPath)\n return typeof window === 'undefined'\n ? media.cdnPath\n : `${window.location.origin}${media.cdnPath}`\n if (media.url) return media.url\n return ''\n}\n\n/**\n * A `src` for a THUMBNAIL — a grid tile, a picker cell, a preview strip.\n *\n * Separate from {@link mediaSrc} because the two answer different questions.\n * `mediaSrc` produces a URL that gets *persisted* (markdown bodies, listing\n * images), so it must stay width-free. This one produces a URL that is only\n * ever rendered, so it can ask for the smallest generated WebP variant.\n *\n * The DAM grid read `media.url` directly, which is the raw\n * `firebasestorage.googleapis.com` download URL: every tile fetched the\n * FULL-SIZE original straight from Cloud Storage, bypassing both the WebP\n * variants (AGL-175) and the Vercel edge cache. A library page of 24 assets\n * at ~200 KB each is ~4.8 MB of Storage egress per view, re-fetched by every\n * viewer, where the 320px variants are ~15 KB each.\n *\n * `?w=` degrades safely: `serveMediaCdn` only serves a variant when the\n * asset's `variants` array actually contains that width, and otherwise\n * serves the original — so an SVG, a small logo, or an asset uploaded before\n * variants existed still renders, just without the saving.\n */\nexport function mediaThumbnailSrc(\n media: { url?: string; cdnPath?: string },\n width: number,\n): string {\n const cdnPath = media.cdnPath\n // No `cdnPath` means a free-tier or private asset, and a width parameter\n // on a raw storage URL means nothing — appending one would only fork the\n // browser cache for identical bytes.\n if (!cdnPath) return mediaSrc(media)\n // A signed private URL already carries `?exp=&sig=`; a second `?` makes a\n // path the route rejects outright.\n if (cdnPath.includes('?')) return mediaSrc(media)\n return `${mediaSrc(media)}?w=${width}`\n}\n\n/**\n * A `src` for a VIDEO's poster still, or `undefined` when it has none\n * (AGL-2742).\n *\n * The DAM grid drew a video tile as a `<video src>` pointing at the master.\n * A browser paints a first frame by fetching enough of the file to decode\n * one, so a folder of eight clips was tens of megabytes of Storage egress\n * per view — the same defect {@link mediaThumbnailSrc} was written to fix for\n * images, on the type where each tile costs a hundred times more. And unlike\n * an image tile it could not be helped by a variant, because until now a\n * video had nothing smaller to serve.\n *\n * Returns `undefined` rather than a fallback URL on purpose: the caller has\n * to branch anyway (a `<video>` with no poster still needs `preload=\"none\"`\n * so it stops fetching), and an \"always answers\" helper would hand back a URL\n * that 404s for every video uploaded before this shipped.\n *\n * Mirrors `Aglyn.mediaPosterSrc` for a media DOCUMENT rather than a stored\n * `media:` reference — the console holds documents, the renderer holds\n * references, and neither can use the other's input.\n */\nexport function mediaPosterThumbnailSrc(\n media: {\n url?: string\n cdnPath?: string\n poster?: { variants?: number[] } | null\n },\n width?: number,\n): string | undefined {\n // A poster is only reachable through the CDN route, so a free-tier or\n // private asset has no URL that could serve one — the same reason\n // `mediaThumbnailSrc` gives up on `?w=` there.\n if (!media.poster || !media.cdnPath || media.cdnPath.includes('?')) {\n return undefined\n }\n const variants = media.poster.variants ?? []\n // Only a width that was actually generated. `serveMediaCdn` would fall\n // back to the full poster for any other, which works and defeats the point\n // — a 1920px still in a 116px tile.\n const narrowed = width && variants.includes(width) ? `&w=${width}` : ''\n return `${mediaSrc(media)}?poster=1${narrowed}`\n}\n\nexport default mediaSrc\n"],"names":["mediaSrc","media","cdnPath","window","location","origin","url","mediaThumbnailSrc","width","includes","mediaPosterThumbnailSrc","poster","undefined","variants","narrowed"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAED;;;;;;;;;;;;;;;;;;;CAmBC,GACD,OAAO,SAASA,SAASC,KAGxB;IACC,wEAAwE;IACxE,uEAAuE;IACvE,sEAAsE;IACtE,uEAAuE;IACvE,oEAAoE;IACpE,wEAAwE;IACxE,mDAAmD;IACnD,IAAIA,MAAMC,OAAO,EACf,OAAO,OAAOC,WAAW,cACrBF,MAAMC,OAAO,GACb,GAAGC,OAAOC,QAAQ,CAACC,MAAM,GAAGJ,MAAMC,OAAO,EAAE;IACjD,IAAID,MAAMK,GAAG,EAAE,OAAOL,MAAMK,GAAG;IAC/B,OAAO;AACT;AAEA;;;;;;;;;;;;;;;;;;;CAmBC,GACD,OAAO,SAASC,kBACdN,KAAyC,EACzCO,KAAa;IAEb,MAAMN,UAAUD,MAAMC,OAAO;IAC7B,yEAAyE;IACzE,yEAAyE;IACzE,qCAAqC;IACrC,IAAI,CAACA,SAAS,OAAOF,SAASC;IAC9B,0EAA0E;IAC1E,mCAAmC;IACnC,IAAIC,QAAQO,QAAQ,CAAC,MAAM,OAAOT,SAASC;IAC3C,OAAO,GAAGD,SAASC,OAAO,GAAG,EAAEO,OAAO;AACxC;AAEA;;;;;;;;;;;;;;;;;;;;CAoBC,GACD,OAAO,SAASE,wBACdT,KAIC,EACDO,KAAc;QAQGP;IANjB,sEAAsE;IACtE,kEAAkE;IAClE,+CAA+C;IAC/C,IAAI,CAACA,MAAMU,MAAM,IAAI,CAACV,MAAMC,OAAO,IAAID,MAAMC,OAAO,CAACO,QAAQ,CAAC,MAAM;QAClE,OAAOG;IACT;IACA,MAAMC,YAAWZ,yBAAAA,MAAMU,MAAM,CAACE,QAAQ,YAArBZ,yBAAyB,EAAE;IAC5C,uEAAuE;IACvE,2EAA2E;IAC3E,oCAAoC;IACpC,MAAMa,WAAWN,SAASK,SAASJ,QAAQ,CAACD,SAAS,CAAC,GAAG,EAAEA,OAAO,GAAG;IACrE,OAAO,GAAGR,SAASC,OAAO,SAAS,EAAEa,UAAU;AACjD;AAEA,eAAed,SAAQ"}
|
|
@@ -0,0 +1,83 @@
|
|
|
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
|
+
* Lets a surface say where its header's help `?` should LAND — the third
|
|
19
|
+
* sibling of `PageHeaderActions` and `PageHeaderRecord`, which do the same
|
|
20
|
+
* for the header's controls and its heading.
|
|
21
|
+
*
|
|
22
|
+
* WHAT A PAGE OWES THE READER WHO CLICKS `?`. AGL-2200 is the issue that
|
|
23
|
+
* found this: `DashboardLayout` could only name a topic, so all seven
|
|
24
|
+
* Plugins/Marketplace pages opened the same "Plugins & Marketplace" tooltip
|
|
25
|
+
* and dropped the reader at the top of one long page. Naming a heading is
|
|
26
|
+
* what turns the affordance from "here is the manual" into an answer.
|
|
27
|
+
*
|
|
28
|
+
* WHY A CONTEXT AND NOT A DECLARATION, which is the difference from the two
|
|
29
|
+
* siblings' rationale. A surface's own help IS declarable — the nav item
|
|
30
|
+
* carries `header.docsTopic`, and a section could carry an anchor — but the
|
|
31
|
+
* pages that need this are the ENTITY pages beneath a surface that owns its
|
|
32
|
+
* subtree (`ConsoleNavItem.ownsSubtree`). Those have no declaration to hang
|
|
33
|
+
* one on: the set of ids is a property of the workspace's data, and what a
|
|
34
|
+
* listing's `?` should explain ("what the badges mean") is a different page
|
|
35
|
+
* of the docs from what the hub's explains ("install & upgrade"). A static
|
|
36
|
+
* list cannot say that, and a route that owns its own layout never had to.
|
|
37
|
+
*
|
|
38
|
+
* TWO STRINGS, and deliberately not the console's `DocsHelpTarget`. That type
|
|
39
|
+
* is keyed to the console's own registry, which a plugin may not import —
|
|
40
|
+
* plugins carry their own generated subset (`PLUGIN_DOCS`). The console
|
|
41
|
+
* resolves whatever arrives against its registry and falls back when it does
|
|
42
|
+
* not recognize it, exactly as it already does for `header.docsTopic`: a
|
|
43
|
+
* third-party plugin can name any string, and the alternative to a fallback
|
|
44
|
+
* is a help button that throws on hover (AGL-1074).
|
|
45
|
+
*/
|
|
46
|
+
export interface PageHeaderHelpValue {
|
|
47
|
+
/** Docs topic key. Resolved by the shell; an unknown one falls back. */
|
|
48
|
+
topic: string;
|
|
49
|
+
/** Heading anchor on that page, including the leading `#`. */
|
|
50
|
+
anchor?: string;
|
|
51
|
+
}
|
|
52
|
+
export interface PageHeaderHelpContextValue {
|
|
53
|
+
/**
|
|
54
|
+
* Points the header's help at a topic; `null` restores the route's own.
|
|
55
|
+
*
|
|
56
|
+
* Absent when no provider is mounted, so a surface rendered outside one —
|
|
57
|
+
* a test harness, a storybook mount — publishes nothing rather than
|
|
58
|
+
* throwing.
|
|
59
|
+
*/
|
|
60
|
+
setHeaderHelp?: (help: PageHeaderHelpValue | null) => void;
|
|
61
|
+
}
|
|
62
|
+
export declare const PageHeaderHelpContext: import("react").Context<PageHeaderHelpContextValue>;
|
|
63
|
+
/** Hook form of {@link PageHeaderHelpContext}. */
|
|
64
|
+
export declare function usePageHeaderHelp(): PageHeaderHelpContextValue;
|
|
65
|
+
export type PageHeaderHelpProps = PageHeaderHelpValue;
|
|
66
|
+
/**
|
|
67
|
+
* Points the page header's help at this page's own docs, and renders nothing
|
|
68
|
+
* where it sits.
|
|
69
|
+
*
|
|
70
|
+
* THE SLOT IS EMPTIED ON UNMOUNT, which is what keeps one page's answer off
|
|
71
|
+
* the next one. Navigating from a listing back to the hub unmounts this
|
|
72
|
+
* publisher and the cleanup runs in the same commit the hub mounts in, so
|
|
73
|
+
* the `?` returns to the surface's declared topic rather than going on
|
|
74
|
+
* explaining badges.
|
|
75
|
+
*
|
|
76
|
+
* Published from PRIMITIVES rather than an object, deliberately: the effect's
|
|
77
|
+
* dependencies are the two strings, so a surface that re-renders while its
|
|
78
|
+
* data settles publishes once per actual change rather than once per render.
|
|
79
|
+
*/
|
|
80
|
+
export declare function PageHeaderHelp(props: PageHeaderHelpProps): null;
|
|
81
|
+
export declare namespace PageHeaderHelp {
|
|
82
|
+
var displayName: string;
|
|
83
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Aglyn LLC
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/ // Same placement rationale as page-header-actions-context.ts: lives in
|
|
17
|
+
// @aglyn/aglyn without a 'use client' banner so both the console app and
|
|
18
|
+
// relocated feature plugins share one context module.
|
|
19
|
+
import { createContext, useContext, useEffect } from "react";
|
|
20
|
+
export const PageHeaderHelpContext = createContext({});
|
|
21
|
+
PageHeaderHelpContext.displayName = 'PageHeaderHelpContext';
|
|
22
|
+
/** Hook form of {@link PageHeaderHelpContext}. */ export function usePageHeaderHelp() {
|
|
23
|
+
return useContext(PageHeaderHelpContext);
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Points the page header's help at this page's own docs, and renders nothing
|
|
27
|
+
* where it sits.
|
|
28
|
+
*
|
|
29
|
+
* THE SLOT IS EMPTIED ON UNMOUNT, which is what keeps one page's answer off
|
|
30
|
+
* the next one. Navigating from a listing back to the hub unmounts this
|
|
31
|
+
* publisher and the cleanup runs in the same commit the hub mounts in, so
|
|
32
|
+
* the `?` returns to the surface's declared topic rather than going on
|
|
33
|
+
* explaining badges.
|
|
34
|
+
*
|
|
35
|
+
* Published from PRIMITIVES rather than an object, deliberately: the effect's
|
|
36
|
+
* dependencies are the two strings, so a surface that re-renders while its
|
|
37
|
+
* data settles publishes once per actual change rather than once per render.
|
|
38
|
+
*/ export function PageHeaderHelp(props) {
|
|
39
|
+
const { topic, anchor } = props;
|
|
40
|
+
const { setHeaderHelp } = usePageHeaderHelp();
|
|
41
|
+
useEffect(()=>{
|
|
42
|
+
setHeaderHelp == null ? void 0 : setHeaderHelp(topic ? {
|
|
43
|
+
topic,
|
|
44
|
+
anchor
|
|
45
|
+
} : null);
|
|
46
|
+
return ()=>setHeaderHelp == null ? void 0 : setHeaderHelp(null);
|
|
47
|
+
}, [
|
|
48
|
+
setHeaderHelp,
|
|
49
|
+
topic,
|
|
50
|
+
anchor
|
|
51
|
+
]);
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
PageHeaderHelp.displayName = 'PageHeaderHelp';
|
|
55
|
+
|
|
56
|
+
//# sourceMappingURL=page-header-help-context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../libs/aglyn/src/lib/app-utils/page-header-help-context.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// Same placement rationale as page-header-actions-context.ts: lives in\n// @aglyn/aglyn without a 'use client' banner so both the console app and\n// relocated feature plugins share one context module.\nimport { createContext, useContext, useEffect } from 'react'\n\n/**\n * Lets a surface say where its header's help `?` should LAND — the third\n * sibling of `PageHeaderActions` and `PageHeaderRecord`, which do the same\n * for the header's controls and its heading.\n *\n * WHAT A PAGE OWES THE READER WHO CLICKS `?`. AGL-2200 is the issue that\n * found this: `DashboardLayout` could only name a topic, so all seven\n * Plugins/Marketplace pages opened the same \"Plugins & Marketplace\" tooltip\n * and dropped the reader at the top of one long page. Naming a heading is\n * what turns the affordance from \"here is the manual\" into an answer.\n *\n * WHY A CONTEXT AND NOT A DECLARATION, which is the difference from the two\n * siblings' rationale. A surface's own help IS declarable — the nav item\n * carries `header.docsTopic`, and a section could carry an anchor — but the\n * pages that need this are the ENTITY pages beneath a surface that owns its\n * subtree (`ConsoleNavItem.ownsSubtree`). Those have no declaration to hang\n * one on: the set of ids is a property of the workspace's data, and what a\n * listing's `?` should explain (\"what the badges mean\") is a different page\n * of the docs from what the hub's explains (\"install & upgrade\"). A static\n * list cannot say that, and a route that owns its own layout never had to.\n *\n * TWO STRINGS, and deliberately not the console's `DocsHelpTarget`. That type\n * is keyed to the console's own registry, which a plugin may not import —\n * plugins carry their own generated subset (`PLUGIN_DOCS`). The console\n * resolves whatever arrives against its registry and falls back when it does\n * not recognize it, exactly as it already does for `header.docsTopic`: a\n * third-party plugin can name any string, and the alternative to a fallback\n * is a help button that throws on hover (AGL-1074).\n */\nexport interface PageHeaderHelpValue {\n /** Docs topic key. Resolved by the shell; an unknown one falls back. */\n topic: string\n /** Heading anchor on that page, including the leading `#`. */\n anchor?: string\n}\n\nexport interface PageHeaderHelpContextValue {\n /**\n * Points the header's help at a topic; `null` restores the route's own.\n *\n * Absent when no provider is mounted, so a surface rendered outside one —\n * a test harness, a storybook mount — publishes nothing rather than\n * throwing.\n */\n setHeaderHelp?: (help: PageHeaderHelpValue | null) => void\n}\n\nexport const PageHeaderHelpContext =\n createContext<PageHeaderHelpContextValue>({})\nPageHeaderHelpContext.displayName = 'PageHeaderHelpContext'\n\n/** Hook form of {@link PageHeaderHelpContext}. */\nexport function usePageHeaderHelp(): PageHeaderHelpContextValue {\n return useContext(PageHeaderHelpContext)\n}\n\nexport type PageHeaderHelpProps = PageHeaderHelpValue\n\n/**\n * Points the page header's help at this page's own docs, and renders nothing\n * where it sits.\n *\n * THE SLOT IS EMPTIED ON UNMOUNT, which is what keeps one page's answer off\n * the next one. Navigating from a listing back to the hub unmounts this\n * publisher and the cleanup runs in the same commit the hub mounts in, so\n * the `?` returns to the surface's declared topic rather than going on\n * explaining badges.\n *\n * Published from PRIMITIVES rather than an object, deliberately: the effect's\n * dependencies are the two strings, so a surface that re-renders while its\n * data settles publishes once per actual change rather than once per render.\n */\nexport function PageHeaderHelp(props: PageHeaderHelpProps): null {\n const { topic, anchor } = props\n const { setHeaderHelp } = usePageHeaderHelp()\n useEffect(() => {\n setHeaderHelp?.(topic ? { topic, anchor } : null)\n return () => setHeaderHelp?.(null)\n }, [setHeaderHelp, topic, anchor])\n return null\n}\nPageHeaderHelp.displayName = 'PageHeaderHelp'\n"],"names":["createContext","useContext","useEffect","PageHeaderHelpContext","displayName","usePageHeaderHelp","PageHeaderHelp","props","topic","anchor","setHeaderHelp"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAED,uEAAuE;AACvE,yEAAyE;AACzE,sDAAsD;AACtD,SAASA,aAAa,EAAEC,UAAU,EAAEC,SAAS,QAAQ,QAAO;AAiD5D,OAAO,MAAMC,wBACXH,cAA0C,CAAC,GAAE;AAC/CG,sBAAsBC,WAAW,GAAG;AAEpC,gDAAgD,GAChD,OAAO,SAASC;IACd,OAAOJ,WAAWE;AACpB;AAIA;;;;;;;;;;;;;CAaC,GACD,OAAO,SAASG,eAAeC,KAA0B;IACvD,MAAM,EAAEC,KAAK,EAAEC,MAAM,EAAE,GAAGF;IAC1B,MAAM,EAAEG,aAAa,EAAE,GAAGL;IAC1BH,UAAU;QACRQ,iCAAAA,cAAgBF,QAAQ;YAAEA;YAAOC;QAAO,IAAI;QAC5C,OAAO,IAAMC,iCAAAA,cAAgB;IAC/B,GAAG;QAACA;QAAeF;QAAOC;KAAO;IACjC,OAAO;AACT;AACAH,eAAeF,WAAW,GAAG"}
|
|
@@ -102,10 +102,11 @@ import { PLATFORM_BRAND_NAME } from "./platform-brand.js";
|
|
|
102
102
|
description: 'Marketplace browsing, publishing and plugin installs.',
|
|
103
103
|
defaultEnabled: true,
|
|
104
104
|
// AGL-1654: was 'nav-tab-marketplace', which matched no nav item, so
|
|
105
|
-
// `gateNavTabItems` never hid the tab. The
|
|
106
|
-
//
|
|
107
|
-
//
|
|
108
|
-
// `
|
|
105
|
+
// `gateNavTabItems` never hid the tab. The id is still held to a real
|
|
106
|
+
// declaration by `release-flag-nav-tab-ids.spec.ts` — but it is no longer
|
|
107
|
+
// held there BY HAND: AGL-3080 made the org Marketplace tab the
|
|
108
|
+
// marketplace plugin's own `orgNavItems` entry, so the tab and the
|
|
109
|
+
// surface behind it are one declaration that names this id once.
|
|
109
110
|
//
|
|
110
111
|
// The second half of that comment — "the page behind it carries no
|
|
111
112
|
// `<FeatureGate>`" — was still true until AGL-2019 and is no longer.
|