@aglyn/plugins-ai 1.0.0-beta.291 → 1.0.0-beta.293
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 +17 -17
- package/src/lib/components/ai-site-import-job.component.js +5 -4
- package/src/lib/components/ai-site-import-job.component.js.map +1 -1
- package/src/lib/components/ai-site-import-start.component.js +3 -3
- package/src/lib/components/ai-site-import-start.component.js.map +1 -1
- package/src/lib/components/ai-site-start-card.component.d.ts +1 -1
- package/src/lib/components/ai-site-start-card.component.js +129 -29
- package/src/lib/components/ai-site-start-card.component.js.map +1 -1
- package/src/lib/components/ai-site-start-steps.component.d.ts +15 -3
- package/src/lib/components/ai-site-start-steps.component.js +42 -25
- package/src/lib/components/ai-site-start-steps.component.js.map +1 -1
- package/src/lib/components/ai-site-style-previews.d.ts +17 -0
- package/src/lib/components/ai-site-style-previews.js +26 -95
- package/src/lib/components/ai-site-style-previews.js.map +1 -1
- package/src/lib/declarations.server.js +22 -0
- package/src/lib/declarations.server.js.map +1 -1
- package/src/lib/jobs/ai-job-import-step.d.ts +21 -2
- package/src/lib/jobs/ai-job-import-step.js +179 -49
- package/src/lib/jobs/ai-job-import-step.js.map +1 -1
- package/src/lib/jobs/ai-job-layout-language.d.ts +27 -3
- package/src/lib/jobs/ai-job-layout-language.js +156 -113
- package/src/lib/jobs/ai-job-layout-language.js.map +1 -1
- package/src/lib/jobs/ai-job-layout-step.js +56 -17
- package/src/lib/jobs/ai-job-layout-step.js.map +1 -1
- package/src/lib/jobs/ai-job-page-language.d.ts +25 -15
- package/src/lib/jobs/ai-job-page-language.js +120 -66
- package/src/lib/jobs/ai-job-page-language.js.map +1 -1
- package/src/lib/jobs/ai-job-page-step.js +27 -7
- package/src/lib/jobs/ai-job-page-step.js.map +1 -1
- package/src/lib/jobs/ai-job-site-datasets.d.ts +12 -4
- package/src/lib/jobs/ai-job-site-datasets.js +36 -16
- package/src/lib/jobs/ai-job-site-datasets.js.map +1 -1
- package/src/lib/jobs/ai-jobs.js +6 -2
- package/src/lib/jobs/ai-jobs.js.map +1 -1
- package/src/lib/jobs/ai-layout-stock-photos.d.ts +50 -1
- package/src/lib/jobs/ai-layout-stock-photos.js +586 -35
- package/src/lib/jobs/ai-layout-stock-photos.js.map +1 -1
- package/src/lib/jobs/ai-site-import-compile.d.ts +147 -0
- package/src/lib/jobs/ai-site-import-compile.js +1143 -0
- package/src/lib/jobs/ai-site-import-compile.js.map +1 -0
- package/src/lib/jobs/ai-site-import-document.d.ts +9 -36
- package/src/lib/jobs/ai-site-import-document.js +23 -489
- package/src/lib/jobs/ai-site-import-document.js.map +1 -1
- package/src/lib/jobs/ai-site-import-look.d.ts +54 -7
- package/src/lib/jobs/ai-site-import-look.js +163 -52
- package/src/lib/jobs/ai-site-import-look.js.map +1 -1
- package/src/lib/jobs/ai-site-import-publish.d.ts +7 -1
- package/src/lib/jobs/ai-site-import-publish.js +19 -5
- package/src/lib/jobs/ai-site-import-publish.js.map +1 -1
- package/src/lib/jobs/ai-site-late-photos.js +4 -2
- package/src/lib/jobs/ai-site-late-photos.js.map +1 -1
- package/src/lib/jobs/ai-site-publish.d.ts +10 -1
- package/src/lib/jobs/ai-site-publish.js +8 -3
- package/src/lib/jobs/ai-site-publish.js.map +1 -1
- package/src/lib/jobs/fixtures/ai-stock-photo-agl4092-1029-recordings.d.ts +23 -0
- package/src/lib/jobs/fixtures/ai-stock-photo-agl4092-1029-recordings.js +677 -0
- package/src/lib/jobs/fixtures/ai-stock-photo-agl4092-1029-recordings.js.map +1 -0
- package/src/lib/layout-language/ai-layout-compiler.d.ts +26 -0
- package/src/lib/layout-language/ai-layout-compiler.js +677 -33
- package/src/lib/layout-language/ai-layout-compiler.js.map +1 -1
- package/src/lib/layout-language/ai-layout-frame-hollows.js +5 -1
- package/src/lib/layout-language/ai-layout-frame-hollows.js.map +1 -1
- package/src/lib/layout-language/ai-layout-frame-source.d.ts +196 -0
- package/src/lib/layout-language/ai-layout-frame-source.js +726 -0
- package/src/lib/layout-language/ai-layout-frame-source.js.map +1 -0
- package/src/lib/layout-language/ai-layout-frame.d.ts +22 -0
- package/src/lib/layout-language/ai-layout-frame.js +121 -29
- package/src/lib/layout-language/ai-layout-frame.js.map +1 -1
- package/src/lib/layout-language/ai-layout-language.d.ts +103 -37
- package/src/lib/layout-language/ai-layout-language.js +85 -120
- package/src/lib/layout-language/ai-layout-language.js.map +1 -1
- package/src/lib/model/ai-credit-estimate.d.ts +11 -7
- package/src/lib/model/ai-credit-estimate.js +11 -7
- package/src/lib/model/ai-credit-estimate.js.map +1 -1
- package/src/lib/model/ai-site-import.d.ts +307 -13
- package/src/lib/model/ai-site-import.js +227 -19
- package/src/lib/model/ai-site-import.js.map +1 -1
- package/src/lib/model/ai-site-look.d.ts +65 -1
- package/src/lib/model/ai-site-look.js +141 -23
- package/src/lib/model/ai-site-look.js.map +1 -1
- package/src/lib/model/ai-site-photos.d.ts +2 -0
- package/src/lib/model/ai-site-photos.js.map +1 -1
- package/src/lib/model/ai-site-start-steps.d.ts +4 -3
- package/src/lib/model/ai-site-start-steps.js +11 -3
- package/src/lib/model/ai-site-start-steps.js.map +1 -1
- package/src/lib/model/ai-site-start.d.ts +23 -2
- package/src/lib/model/ai-site-start.js +25 -3
- package/src/lib/model/ai-site-start.js.map +1 -1
- package/src/lib/providers/routing.d.ts +11 -0
- package/src/lib/providers/routing.js +23 -0
- package/src/lib/providers/routing.js.map +1 -1
- package/src/lib/runtime/ai-doctrine-validators.d.ts +4 -2
- package/src/lib/runtime/ai-doctrine-validators.js +7 -2
- package/src/lib/runtime/ai-doctrine-validators.js.map +1 -1
- package/src/lib/runtime/ai-icon-library.d.ts +4 -0
- package/src/lib/runtime/ai-icon-library.js +4 -0
- package/src/lib/runtime/ai-icon-library.js.map +1 -1
- package/src/lib/runtime/ai-node-tree.js +5 -1
- package/src/lib/runtime/ai-node-tree.js.map +1 -1
- package/src/lib/runtime/ai-palette.d.ts +2 -0
- package/src/lib/runtime/ai-palette.generated.js +19 -3
- package/src/lib/runtime/ai-palette.generated.js.map +1 -1
- package/src/lib/runtime/ai-palette.js +2 -1
- package/src/lib/runtime/ai-palette.js.map +1 -1
- package/src/lib/site-import/fixtures/site-layout-recordings.d.ts +50 -0
- package/src/lib/site-import/fixtures/site-layout-recordings.js +86 -0
- package/src/lib/site-import/fixtures/site-layout-recordings.js.map +1 -0
- package/src/lib/site-import/site-import-crawl.d.ts +18 -1
- package/src/lib/site-import/site-import-crawl.js +70 -10
- package/src/lib/site-import/site-import-crawl.js.map +1 -1
- package/src/lib/site-import/site-import-css.d.ts +110 -0
- package/src/lib/site-import/site-import-css.js +826 -0
- package/src/lib/site-import/site-import-css.js.map +1 -0
- package/src/lib/site-import/site-import-html.d.ts +116 -1
- package/src/lib/site-import/site-import-html.js +538 -46
- package/src/lib/site-import/site-import-html.js.map +1 -1
- package/src/lib/site-import/site-import-layout.d.ts +79 -0
- package/src/lib/site-import/site-import-layout.js +1608 -0
- package/src/lib/site-import/site-import-layout.js.map +1 -0
- package/src/lib/site-import/site-import-nav.d.ts +40 -0
- package/src/lib/site-import/site-import-nav.js +437 -0
- package/src/lib/site-import/site-import-nav.js.map +1 -0
- package/src/lib/site-import/site-import-page.d.ts +8 -1
- package/src/lib/site-import/site-import-page.js +24 -2
- package/src/lib/site-import/site-import-page.js.map +1 -1
- package/src/lib/assets/site-styles/beauty.webp +0 -0
- package/src/lib/assets/site-styles/blog.webp +0 -0
- package/src/lib/assets/site-styles/business.webp +0 -0
- package/src/lib/assets/site-styles/coming-soon.webp +0 -0
- package/src/lib/assets/site-styles/education.webp +0 -0
- package/src/lib/assets/site-styles/events.webp +0 -0
- package/src/lib/assets/site-styles/fitness.webp +0 -0
- package/src/lib/assets/site-styles/landing.webp +0 -0
- package/src/lib/assets/site-styles/music.webp +0 -0
- package/src/lib/assets/site-styles/nonprofit.webp +0 -0
- package/src/lib/assets/site-styles/personal.webp +0 -0
- package/src/lib/assets/site-styles/photography.webp +0 -0
- package/src/lib/assets/site-styles/portfolio.webp +0 -0
- package/src/lib/assets/site-styles/professional.webp +0 -0
- package/src/lib/assets/site-styles/realestate.webp +0 -0
- package/src/lib/assets/site-styles/restaurant.webp +0 -0
- package/src/lib/assets/site-styles/store.webp +0 -0
- package/src/lib/assets/site-styles/studio.webp +0 -0
- package/src/lib/assets/site-styles/trades.webp +0 -0
- package/src/lib/assets/site-styles/wellness.webp +0 -0
- package/src/lib/assets/site-styles/yoga.webp +0 -0
- package/src/lib/site-import/site-import-review.d.ts +0 -40
- package/src/lib/site-import/site-import-review.js +0 -149
- package/src/lib/site-import/site-import-review.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../libs/plugins/ai/src/lib/declarations.server.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// Each registry from its own module, not the `@aglyn/aglyn/server` barrel:\n// boot needs three registries rather than the whole server surface, and a\n// suite that stubs that barrel wholesale still loads these declarations\n// against the real registries.\nimport {\n listPluginEventHandlers,\n registerPluginEventHandler,\n} from '@aglyn/aglyn/plugin-manager/plugin-events'\nimport {\n listPluginUserErasers,\n registerPluginUserEraser,\n} from '@aglyn/aglyn/plugin-manager/plugin-user-erasure'\nimport {\n listUsageAlertContributors,\n registerUsageAlertContributor,\n} from '@aglyn/aglyn/plugin-manager/usage-alert-contributors'\nimport { registerPluginUsageMeter } from '@aglyn/aglyn/plugin-manager/plugin-usage-meters'\nimport { registerOperatorAlerts } from '@aglyn/aglyn/plugin-manager/operator-alerts'\nimport { registerStockPhotoPicker } from '@aglyn/aglyn/plugin-manager/stock-photo-provider'\nimport { AI_PLUGIN_ID, AI_USAGE_METER_ID } from './constants'\nimport { AI_BUILD_PARTLY_FAILED, AI_JOB_FAILED, AI_PROVIDER_UNAVAILABLE } from './operator-alerts'\nimport { registerAiDeclarations } from './declarations'\n\n/** The provider-spend staff alerts' contributor id under the plugin. */\nconst AI_USAGE_ALERTS_ID = 'provider-spend'\n\n/**\n * The plugin's SERVER declarations (AGL-2939): what the server must know\n * at boot, before any door of the plugin has been called. The two platform\n * events the plugin writes activity for — the AI add-on bought or dropped,\n * an `ai.*` permission moved — are raised by core billing and membership\n * routes that never load the plugin's API surface, so the subscriptions\n * have to be in place from the first request. So does the eraser: an\n * account erasure is a core route too, and a person's AI usage months sit\n * under each org, keyed by the uid, where no core delete reaches them. So\n * does the usage alert contributor (AGL-2984): the usage-alerts sweep is a\n * core cron, and it evaluates the plugin's staff alerts on provider spend for\n * every org it reads.\n *\n * Light at boot by construction: the writers behind the handlers are\n * imported when the first event arrives, and the alert rules when the sweep\n * first evaluates an org, not when the process starts, so the boot cost is\n * the registration and nothing that touches Firestore.\n */\nexport function registerAiServerDeclarations(): void {\n registerAiDeclarations()\n // Idempotent against each REGISTRY rather than a module flag, so a\n // registry reset (a spec) or a second module instance registers again.\n if (!listPluginEventHandlers('org.seatAddons.changed').includes(AI_PLUGIN_ID)) {\n registerPluginEventHandler(\n 'org.seatAddons.changed',\n async ({ orgId, actor, before, after }) => {\n const { logAiAddonChanged } = await import('./activity/ai-activity')\n await logAiAddonChanged(orgId, actor, { before, after })\n },\n { pluginId: AI_PLUGIN_ID },\n )\n registerPluginEventHandler(\n 'org.permissions.changed',\n async ({ orgId, actor, subject, permission, granted }) => {\n if (!permission.startsWith('ai.')) return\n const { logAiPermissionChanged } = await import('./activity/ai-activity')\n await logAiPermissionChanged(orgId, actor, { subject, permission, granted })\n },\n { pluginId: AI_PLUGIN_ID },\n )\n }\n // THE PLATFORM'S PER-SITE TOGGLE DOOR (AGL-4047). The collaborators card\n // sets every per-site key through the platform's generic door now, so this\n // plugin keeps its display copy (`aiPermissions` on the site's roster row,\n // which the native apps read) in step from the verdict that door wrote.\n if (!listPluginEventHandlers('host.member.permissions.changed').includes(AI_PLUGIN_ID)) {\n registerPluginEventHandler(\n 'host.member.permissions.changed',\n async ({ hostId, memberId, permissions }) => {\n const { recordAiPermissionsOnRoster } = await import('./server/ai-host-permissions-roster')\n await recordAiPermissionsOnRoster(hostId, memberId, permissions)\n },\n { pluginId: AI_PLUGIN_ID },\n )\n }\n // THE PLATFORM'S BILLING EVENTS (AGL-3011). Subscribed at boot for the\n // same reason as the two above: they are raised by the billing webhook,\n // which never loads an AI door, and a workspace's overage standing moving\n // late is a workspace charged or refused against a fact we already had.\n //\n // The handler modules are imported when the first event arrives, so a\n // process that never receives one pays only for the registration.\n if (!listPluginEventHandlers('billing.invoice.paid').includes(AI_PLUGIN_ID)) {\n registerPluginEventHandler(\n 'billing.invoice.paid',\n async (payload) => {\n const { onAiBillingInvoicePaid } = await import('./billing/ai-overage-events')\n await onAiBillingInvoicePaid(payload)\n },\n { pluginId: AI_PLUGIN_ID },\n )\n registerPluginEventHandler(\n 'billing.invoice.failed',\n async (payload) => {\n const { onAiBillingInvoiceFailed } = await import('./billing/ai-overage-events')\n await onAiBillingInvoiceFailed(payload)\n },\n { pluginId: AI_PLUGIN_ID },\n )\n registerPluginEventHandler(\n 'billing.invoice.closed',\n async (payload) => {\n const { onAiBillingInvoiceClosed } = await import('./billing/ai-overage-events')\n await onAiBillingInvoiceClosed(payload)\n },\n { pluginId: AI_PLUGIN_ID },\n )\n registerPluginEventHandler(\n 'billing.dispute.opened',\n async (payload) => {\n const { onAiBillingDisputeOpened } = await import('./billing/ai-overage-events')\n await onAiBillingDisputeOpened(payload)\n },\n { pluginId: AI_PLUGIN_ID },\n )\n registerPluginEventHandler(\n 'billing.paymentMethod.changed',\n async (payload) => {\n const { onAiBillingPaymentMethodChanged } = await import(\n './billing/ai-overage-events'\n )\n await onAiBillingPaymentMethodChanged(payload)\n },\n { pluginId: AI_PLUGIN_ID },\n )\n }\n // The plugin's meter in the monthly usage sweep: the month's provider spend\n // onto the rollup, the credits past the band onto the invoice, and — from\n // the cutover month (AGL-3011) — the close-out of what the plugin invoices\n // itself. Registered at boot because the sweep is a core cron, and declared\n // in `usageAxes` so the sweep refuses to bill a month without it. The same\n // registration again replaces itself.\n registerPluginUsageMeter({\n pluginId: AI_PLUGIN_ID,\n id: AI_USAGE_METER_ID,\n measure: async (context) => {\n const { measureAiMonth } = await import('./billing/ai-month-meter')\n return measureAiMonth(context)\n },\n closeMonth: async (context) => {\n const { closeAiMonth } = await import('./billing/ai-month-meter')\n await closeAiMonth(context)\n },\n })\n if (!listPluginUserErasers().includes(AI_PLUGIN_ID)) {\n registerPluginUserEraser(\n async (request) => {\n const { eraseAiUsageForUser } = await import('./usage/ai-usage-eraser')\n return eraseAiUsageForUser(request)\n },\n { pluginId: AI_PLUGIN_ID },\n )\n }\n // The platform provider account alert (AGL-3377), and a job failing or a\n // build finishing with parts failed on our side (AGL-3683), listed on\n // Staff → Operator alerts before the first one is raised.\n registerOperatorAlerts([AI_PROVIDER_UNAVAILABLE, AI_JOB_FAILED, AI_BUILD_PARTLY_FAILED], {\n pluginId: AI_PLUGIN_ID,\n })\n // The stock photo picker another plugin's draft writer asks for (AGL-3755):\n // an event's cover, chosen as a page's pictures are. The choosing loads on\n // the first pick; registering again replaces it.\n registerStockPhotoPicker(\n {\n pick: async (request) => {\n const { aiStockPhotoPick } = await import('./jobs/ai-stock-photo-picker')\n return aiStockPhotoPick(request)\n },\n },\n { pluginId: AI_PLUGIN_ID },\n )\n if (\n !listUsageAlertContributors().some(\n (contributor) =>\n contributor.pluginId === AI_PLUGIN_ID &&\n contributor.id === AI_USAGE_ALERTS_ID,\n )\n ) {\n registerUsageAlertContributor({\n pluginId: AI_PLUGIN_ID,\n id: AI_USAGE_ALERTS_ID,\n evaluate: async (context) => {\n const { evaluateAiUsageAlerts } = await import('./usage/ai-usage-alerts')\n await evaluateAiUsageAlerts(context)\n },\n quotaChecks: async (context) => {\n const { aiQuotaChecks } = await import('./usage/ai-quota-checks')\n return aiQuotaChecks(context)\n },\n })\n }\n}\n\nregisterAiServerDeclarations()\n"],"names":["listPluginEventHandlers","registerPluginEventHandler","listPluginUserErasers","registerPluginUserEraser","listUsageAlertContributors","registerUsageAlertContributor","registerPluginUsageMeter","registerOperatorAlerts","registerStockPhotoPicker","AI_PLUGIN_ID","AI_USAGE_METER_ID","AI_BUILD_PARTLY_FAILED","AI_JOB_FAILED","AI_PROVIDER_UNAVAILABLE","registerAiDeclarations","AI_USAGE_ALERTS_ID","registerAiServerDeclarations","includes","orgId","actor","before","after","logAiAddonChanged","pluginId","subject","permission","granted","startsWith","logAiPermissionChanged","hostId","memberId","permissions","recordAiPermissionsOnRoster","payload","onAiBillingInvoicePaid","onAiBillingInvoiceFailed","onAiBillingInvoiceClosed","onAiBillingDisputeOpened","onAiBillingPaymentMethodChanged","id","measure","context","measureAiMonth","closeMonth","closeAiMonth","request","eraseAiUsageForUser","pick","aiStockPhotoPick","some","contributor","evaluate","evaluateAiUsageAlerts","quotaChecks","aiQuotaChecks"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../../../../libs/plugins/ai/src/lib/declarations.server.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// Each registry from its own module, not the `@aglyn/aglyn/server` barrel:\n// boot needs three registries rather than the whole server surface, and a\n// suite that stubs that barrel wholesale still loads these declarations\n// against the real registries.\nimport {\n listPluginEventHandlers,\n registerPluginEventHandler,\n} from '@aglyn/aglyn/plugin-manager/plugin-events'\nimport {\n listPluginUserErasers,\n registerPluginUserEraser,\n} from '@aglyn/aglyn/plugin-manager/plugin-user-erasure'\nimport {\n listUsageAlertContributors,\n registerUsageAlertContributor,\n} from '@aglyn/aglyn/plugin-manager/usage-alert-contributors'\nimport { registerPluginUsageMeter } from '@aglyn/aglyn/plugin-manager/plugin-usage-meters'\nimport { registerOperatorAlerts } from '@aglyn/aglyn/plugin-manager/operator-alerts'\nimport { registerStockPhotoPicker } from '@aglyn/aglyn/plugin-manager/stock-photo-provider'\nimport { registerPluginSiteStyleLooks } from '@aglyn/aglyn/plugin-manager/plugin-site-style-looks'\nimport { listServerThemePresets } from '@aglyn/aglyn/plugin-manager/plugin-theme-presets'\nimport { AI_PLUGIN_ID, AI_USAGE_METER_ID } from './constants'\nimport { AI_BUILD_PARTLY_FAILED, AI_JOB_FAILED, AI_PROVIDER_UNAVAILABLE } from './operator-alerts'\nimport { registerAiDeclarations } from './declarations'\n\n/** The provider-spend staff alerts' contributor id under the plugin. */\nconst AI_USAGE_ALERTS_ID = 'provider-spend'\n\n/**\n * The plugin's SERVER declarations (AGL-2939): what the server must know\n * at boot, before any door of the plugin has been called. The two platform\n * events the plugin writes activity for — the AI add-on bought or dropped,\n * an `ai.*` permission moved — are raised by core billing and membership\n * routes that never load the plugin's API surface, so the subscriptions\n * have to be in place from the first request. So does the eraser: an\n * account erasure is a core route too, and a person's AI usage months sit\n * under each org, keyed by the uid, where no core delete reaches them. So\n * does the usage alert contributor (AGL-2984): the usage-alerts sweep is a\n * core cron, and it evaluates the plugin's staff alerts on provider spend for\n * every org it reads.\n *\n * Light at boot by construction: the writers behind the handlers are\n * imported when the first event arrives, and the alert rules when the sweep\n * first evaluates an org, not when the process starts, so the boot cost is\n * the registration and nothing that touches Firestore.\n */\nexport function registerAiServerDeclarations(): void {\n registerAiDeclarations()\n // Idempotent against each REGISTRY rather than a module flag, so a\n // registry reset (a spec) or a second module instance registers again.\n if (!listPluginEventHandlers('org.seatAddons.changed').includes(AI_PLUGIN_ID)) {\n registerPluginEventHandler(\n 'org.seatAddons.changed',\n async ({ orgId, actor, before, after }) => {\n const { logAiAddonChanged } = await import('./activity/ai-activity')\n await logAiAddonChanged(orgId, actor, { before, after })\n },\n { pluginId: AI_PLUGIN_ID },\n )\n registerPluginEventHandler(\n 'org.permissions.changed',\n async ({ orgId, actor, subject, permission, granted }) => {\n if (!permission.startsWith('ai.')) return\n const { logAiPermissionChanged } = await import('./activity/ai-activity')\n await logAiPermissionChanged(orgId, actor, { subject, permission, granted })\n },\n { pluginId: AI_PLUGIN_ID },\n )\n }\n // THE PLATFORM'S PER-SITE TOGGLE DOOR (AGL-4047). The collaborators card\n // sets every per-site key through the platform's generic door now, so this\n // plugin keeps its display copy (`aiPermissions` on the site's roster row,\n // which the native apps read) in step from the verdict that door wrote.\n if (!listPluginEventHandlers('host.member.permissions.changed').includes(AI_PLUGIN_ID)) {\n registerPluginEventHandler(\n 'host.member.permissions.changed',\n async ({ hostId, memberId, permissions }) => {\n const { recordAiPermissionsOnRoster } = await import('./server/ai-host-permissions-roster')\n await recordAiPermissionsOnRoster(hostId, memberId, permissions)\n },\n { pluginId: AI_PLUGIN_ID },\n )\n }\n // THE PLATFORM'S BILLING EVENTS (AGL-3011). Subscribed at boot for the\n // same reason as the two above: they are raised by the billing webhook,\n // which never loads an AI door, and a workspace's overage standing moving\n // late is a workspace charged or refused against a fact we already had.\n //\n // The handler modules are imported when the first event arrives, so a\n // process that never receives one pays only for the registration.\n if (!listPluginEventHandlers('billing.invoice.paid').includes(AI_PLUGIN_ID)) {\n registerPluginEventHandler(\n 'billing.invoice.paid',\n async (payload) => {\n const { onAiBillingInvoicePaid } = await import('./billing/ai-overage-events')\n await onAiBillingInvoicePaid(payload)\n },\n { pluginId: AI_PLUGIN_ID },\n )\n registerPluginEventHandler(\n 'billing.invoice.failed',\n async (payload) => {\n const { onAiBillingInvoiceFailed } = await import('./billing/ai-overage-events')\n await onAiBillingInvoiceFailed(payload)\n },\n { pluginId: AI_PLUGIN_ID },\n )\n registerPluginEventHandler(\n 'billing.invoice.closed',\n async (payload) => {\n const { onAiBillingInvoiceClosed } = await import('./billing/ai-overage-events')\n await onAiBillingInvoiceClosed(payload)\n },\n { pluginId: AI_PLUGIN_ID },\n )\n registerPluginEventHandler(\n 'billing.dispute.opened',\n async (payload) => {\n const { onAiBillingDisputeOpened } = await import('./billing/ai-overage-events')\n await onAiBillingDisputeOpened(payload)\n },\n { pluginId: AI_PLUGIN_ID },\n )\n registerPluginEventHandler(\n 'billing.paymentMethod.changed',\n async (payload) => {\n const { onAiBillingPaymentMethodChanged } = await import(\n './billing/ai-overage-events'\n )\n await onAiBillingPaymentMethodChanged(payload)\n },\n { pluginId: AI_PLUGIN_ID },\n )\n }\n // The plugin's meter in the monthly usage sweep: the month's provider spend\n // onto the rollup, the credits past the band onto the invoice, and — from\n // the cutover month (AGL-3011) — the close-out of what the plugin invoices\n // itself. Registered at boot because the sweep is a core cron, and declared\n // in `usageAxes` so the sweep refuses to bill a month without it. The same\n // registration again replaces itself.\n registerPluginUsageMeter({\n pluginId: AI_PLUGIN_ID,\n id: AI_USAGE_METER_ID,\n measure: async (context) => {\n const { measureAiMonth } = await import('./billing/ai-month-meter')\n return measureAiMonth(context)\n },\n closeMonth: async (context) => {\n const { closeAiMonth } = await import('./billing/ai-month-meter')\n await closeAiMonth(context)\n },\n })\n if (!listPluginUserErasers().includes(AI_PLUGIN_ID)) {\n registerPluginUserEraser(\n async (request) => {\n const { eraseAiUsageForUser } = await import('./usage/ai-usage-eraser')\n return eraseAiUsageForUser(request)\n },\n { pluginId: AI_PLUGIN_ID },\n )\n }\n // The platform provider account alert (AGL-3377), and a job failing or a\n // build finishing with parts failed on our side (AGL-3683), listed on\n // Staff → Operator alerts before the first one is raised.\n registerOperatorAlerts([AI_PROVIDER_UNAVAILABLE, AI_JOB_FAILED, AI_BUILD_PARTLY_FAILED], {\n pluginId: AI_PLUGIN_ID,\n })\n // The stock photo picker another plugin's draft writer asks for (AGL-3755):\n // an event's cover, chosen as a page's pictures are. The choosing loads on\n // the first pick; registering again replaces it.\n registerStockPhotoPicker(\n {\n pick: async (request) => {\n const { aiStockPhotoPick } = await import('./jobs/ai-stock-photo-picker')\n return aiStockPhotoPick(request)\n },\n },\n { pluginId: AI_PLUGIN_ID },\n )\n // The look each style starts a new site in (AGL-4049): Create site asks a\n // style before it creates anything, and the 21 styles are this plugin's\n // kinds of site. Asked on the create, so the look module loads then; the\n // built-in themes this deployment has are read at that moment too.\n registerPluginSiteStyleLooks(\n {\n look: async (styleId) => {\n const [{ aiSiteKind }, { aiSiteKindDefaultLook }] = await Promise.all([\n import('./model/ai-site-kinds'),\n import('./model/ai-site-look'),\n ])\n const kind = aiSiteKind(styleId)\n if (!kind) return null\n const presetIds = new Set(listServerThemePresets().map((preset) => preset.id))\n return aiSiteKindDefaultLook(kind, { presetIds }).theme\n },\n },\n { pluginId: AI_PLUGIN_ID },\n )\n if (\n !listUsageAlertContributors().some(\n (contributor) =>\n contributor.pluginId === AI_PLUGIN_ID &&\n contributor.id === AI_USAGE_ALERTS_ID,\n )\n ) {\n registerUsageAlertContributor({\n pluginId: AI_PLUGIN_ID,\n id: AI_USAGE_ALERTS_ID,\n evaluate: async (context) => {\n const { evaluateAiUsageAlerts } = await import('./usage/ai-usage-alerts')\n await evaluateAiUsageAlerts(context)\n },\n quotaChecks: async (context) => {\n const { aiQuotaChecks } = await import('./usage/ai-quota-checks')\n return aiQuotaChecks(context)\n },\n })\n }\n}\n\nregisterAiServerDeclarations()\n"],"names":["listPluginEventHandlers","registerPluginEventHandler","listPluginUserErasers","registerPluginUserEraser","listUsageAlertContributors","registerUsageAlertContributor","registerPluginUsageMeter","registerOperatorAlerts","registerStockPhotoPicker","registerPluginSiteStyleLooks","listServerThemePresets","AI_PLUGIN_ID","AI_USAGE_METER_ID","AI_BUILD_PARTLY_FAILED","AI_JOB_FAILED","AI_PROVIDER_UNAVAILABLE","registerAiDeclarations","AI_USAGE_ALERTS_ID","registerAiServerDeclarations","includes","orgId","actor","before","after","logAiAddonChanged","pluginId","subject","permission","granted","startsWith","logAiPermissionChanged","hostId","memberId","permissions","recordAiPermissionsOnRoster","payload","onAiBillingInvoicePaid","onAiBillingInvoiceFailed","onAiBillingInvoiceClosed","onAiBillingDisputeOpened","onAiBillingPaymentMethodChanged","id","measure","context","measureAiMonth","closeMonth","closeAiMonth","request","eraseAiUsageForUser","pick","aiStockPhotoPick","look","styleId","aiSiteKind","aiSiteKindDefaultLook","Promise","all","kind","presetIds","Set","map","preset","theme","some","contributor","evaluate","evaluateAiUsageAlerts","quotaChecks","aiQuotaChecks"],"mappings":"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"}
|
|
@@ -19,10 +19,10 @@ import type { AiJob, AiJobItemLedger } from '../model/ai-jobs.types';
|
|
|
19
19
|
import { type AiSiteImportBuild, type AiSiteImportHome, type AiSiteImportLeftOutReason, type AiSiteImportPage, type AiSiteImportPageRead, type AiSiteImportState, type AiSiteImportWave } from '../model/ai-site-import';
|
|
20
20
|
import { crawlSiteForImport, type SiteImportCrawlSeams, type SiteImportInventory } from '../site-import/site-import-crawl';
|
|
21
21
|
import { type SiteImportPhotosDeps } from '../site-import/site-import-images';
|
|
22
|
+
import { type AiLayoutFrameSource, type AiLayoutFrameSourceGround, type AiLayoutFrameSourceTo } from '../layout-language/ai-layout-frame-source';
|
|
22
23
|
import { type AiSiteImportDocument } from './ai-site-import-document';
|
|
23
24
|
import { aiRunSiteImportLook, type AiSiteImportLookDeps } from './ai-site-import-look';
|
|
24
25
|
import { aiPublishImportedWave } from './ai-site-import-publish';
|
|
25
|
-
import { fileSiteImportReview } from '../site-import/site-import-review';
|
|
26
26
|
import { type AiJobAdmission } from './ai-job-admission';
|
|
27
27
|
import { readAiScreenRoom } from './ai-job-drafts';
|
|
28
28
|
import { type AiLayoutSitePage } from './ai-job-layout-site-pages';
|
|
@@ -90,7 +90,6 @@ export interface AiSiteImportStepDeps {
|
|
|
90
90
|
fetchImage?: SiteImportPhotosDeps['fetch'];
|
|
91
91
|
readRoom?: typeof readAiScreenRoom;
|
|
92
92
|
readSiteName?: (firestore: FirebaseFirestore.Firestore, hostId: string) => Promise<string>;
|
|
93
|
-
fileReview?: typeof fileSiteImportReview;
|
|
94
93
|
pageWritten?: typeof aiSitePageWritten;
|
|
95
94
|
mintId?: () => string;
|
|
96
95
|
clock?: () => number;
|
|
@@ -122,6 +121,26 @@ export declare function aiSiteImportBuildOf(page: Pick<AiSiteImportPage, 'group'
|
|
|
122
121
|
* punctuation, else the person's.
|
|
123
122
|
*/
|
|
124
123
|
export declare function aiSiteImportBrandName(given: string, own: string): string;
|
|
124
|
+
/**
|
|
125
|
+
* Where a link of the source's header or footer goes on the new site
|
|
126
|
+
* (AGL-4108): a page the import brings in by its id, once its wave is the
|
|
127
|
+
* header's or before it; a page of a later wave by its address on the new
|
|
128
|
+
* site, which the page takes when its wave lands, since a link by id to a
|
|
129
|
+
* page not yet live is taken out when a wave goes live; and anywhere else by
|
|
130
|
+
* the source's own address, so a button that leaves the source leaves the
|
|
131
|
+
* new site too. `null` for an address no link may carry.
|
|
132
|
+
*/
|
|
133
|
+
export declare function aiSiteImportFrameLinkTo(state: Pick<AiSiteImportState, 'domain' | 'pages'>, wave: number): (href: string | null | undefined) => AiLayoutFrameSourceTo | null;
|
|
134
|
+
/** The ground a source's header bar sits on (AGL-4108): dark, the brand's color, the page's own, or paper. */
|
|
135
|
+
export declare function aiSiteImportHeaderGround(background: string | null, look: AiSiteImportHome['look']): AiLayoutFrameSourceGround;
|
|
136
|
+
/**
|
|
137
|
+
* The site's header and footer as the source builds them (AGL-4108): its
|
|
138
|
+
* menu with its menus and their entries, its buttons with their own
|
|
139
|
+
* addresses and how they are drawn, and its footer, every link resolved
|
|
140
|
+
* (`aiSiteImportFrameLinkTo`). Every label is the source's, as written.
|
|
141
|
+
* `null` where the reader found no menu on the home page.
|
|
142
|
+
*/
|
|
143
|
+
export declare function aiSiteImportFrameSource(state: AiSiteImportState, wave: Pick<AiSiteImportWave, 'index'>): AiLayoutFrameSource | null;
|
|
125
144
|
/** The header and footer's job: a layout of the site's brand, linking the wave's pages, in the layout language. */
|
|
126
145
|
export declare function aiSiteImportFrameJob(job: AiJob, state: AiSiteImportState, wave: AiSiteImportWave, items: readonly AiJobItemLedger[]): AiJob;
|
|
127
146
|
/** The page brought in, as its page job carries it: its lines, its photos, and the pages its links may go to (AGL-4084). */
|
|
@@ -21,8 +21,8 @@ import { _ as _extends } from "@swc/helpers/_/_extends";
|
|
|
21
21
|
*
|
|
22
22
|
* 1. READ the proved site (no model): the crawler reads it as AglynBot,
|
|
23
23
|
* main pages first, up to the plan's page count; the inventory is cut
|
|
24
|
-
* into waves (`model/ai-site-import.ts`)
|
|
25
|
-
*
|
|
24
|
+
* into waves (`model/ai-site-import.ts`) and every page gets a ledger
|
|
25
|
+
* row. The job then WAITS (`needs_review`,
|
|
26
26
|
* reason `wave`): nothing is brought in until the person starts wave 1.
|
|
27
27
|
* 2. START A WAVE (no model), on the person's say-so: the proof is still
|
|
28
28
|
* current, the day's limit has room, the plan still has room; the
|
|
@@ -31,9 +31,13 @@ import { _ as _extends } from "@swc/helpers/_/_extends";
|
|
|
31
31
|
* 3. THE LOOK, in the first wave (no model, AGL-4084): the theme drawn
|
|
32
32
|
* from the owner's own home page, its logo into the library, the site's
|
|
33
33
|
* listing from the home page's own words (`ai-site-import-look.ts`).
|
|
34
|
-
* 4. THE HEADER AND FOOTER, in the first wave: the
|
|
35
|
-
*
|
|
36
|
-
*
|
|
34
|
+
* 4. THE HEADER AND FOOTER, in the first wave: the source's own menu, its
|
|
35
|
+
* menus, its buttons and its footer as its home page builds them
|
|
36
|
+
* (AGL-4108, `aiSiteImportFrameSource`), drawn by the layout step with
|
|
37
|
+
* no model; for a source whose menu could not be read, the layout
|
|
38
|
+
* step's own pass, with the source's brand as its header draws it, its
|
|
39
|
+
* own header and footer words as the footer's facts, and the site's
|
|
40
|
+
* menu order.
|
|
37
41
|
* 5. EACH PAGE: its photos into the media library (no model, deduped by
|
|
38
42
|
* source key), then the page step's own passes, NEVER REWRITTEN
|
|
39
43
|
* (AGL-4084, `ai-site-import-document.ts`): a collection's page or a
|
|
@@ -57,18 +61,20 @@ import { listDomainOwnershipClaims, normalizeOwnershipDomain } from "@aglyn/tena
|
|
|
57
61
|
import { getOrgForUser, memberHasOrgPermission } from "@aglyn/tenant-data-admin/server/organizations";
|
|
58
62
|
import { consumeRateLimit } from "@aglyn/tenant-data-admin/server/rate-limit-store";
|
|
59
63
|
import { isServerReleaseFlagOnForOrg } from "@aglyn/tenant-data-admin/server/release-flags";
|
|
60
|
-
import { AI_SITE_IMPORT_DOMAIN_INPUT, AI_SITE_IMPORT_FRAME_SLOT, AI_SITE_IMPORT_LABEL_MAX_CHARS, AI_SITE_IMPORT_LEFT_OUT_COPY, AI_SITE_IMPORT_MAX_PAGES, AI_SITE_IMPORT_MIN_WORDS, AI_SITE_IMPORT_WAVE_PAGES, aiSiteImportInventory, aiSiteImportItemOpen, aiSiteImportLedger, aiSiteImportNextWork, aiSiteImportPageBuild, aiSiteImportPageSettled, aiSiteImportPagesRead, aiSiteImportPhotosIn, aiSiteImportReadStops, aiSiteImportReadVerdict, aiSiteImportReadVerdictMessage, aiSiteImportReadVerdictReason, aiSiteImportWaveClosed, aiSiteImportWaveMessage, aiSiteImportWaveStarted } from "../model/ai-site-import.js";
|
|
64
|
+
import { AI_SITE_IMPORT_DOMAIN_INPUT, AI_SITE_IMPORT_FRAME_SLOT, AI_SITE_IMPORT_LABEL_MAX_CHARS, AI_SITE_IMPORT_LEFT_OUT_COPY, AI_SITE_IMPORT_MAX_PAGES, AI_SITE_IMPORT_MIN_WORDS, AI_SITE_IMPORT_WAVE_PAGES, aiSiteImportFrameIsRead, aiSiteImportInventory, aiSiteImportItemOpen, aiSiteImportLedger, aiSiteImportNextWork, aiSiteImportPageBuild, aiSiteImportPageSettled, aiSiteImportPagesRead, aiSiteImportPhotosIn, aiSiteImportReadStops, aiSiteImportReadVerdict, aiSiteImportReadVerdictMessage, aiSiteImportReadVerdictReason, aiSiteImportWaveClosed, aiSiteImportWaveMessage, aiSiteImportWaveStarted } from "../model/ai-site-import.js";
|
|
61
65
|
import { aiModelForStep } from "../providers/routing.js";
|
|
62
66
|
import { SITE_IMPORT_RELEASE_FLAG } from "../site-import/site-import-flag.js";
|
|
63
|
-
import { crawlSiteForImport } from "../site-import/site-import-crawl.js";
|
|
67
|
+
import { crawlSiteForImport, siteImportOrigins } from "../site-import/site-import-crawl.js";
|
|
64
68
|
import { bringInSiteImportPhotos } from "../site-import/site-import-images.js";
|
|
65
69
|
import { siteImportHeaderBrand, siteImportLabel, siteImportLeftOutReason, siteImportListedPage, siteImportPageRead, siteImportPageWords, siteImportSiteFacts, siteImportSiteName } from "../site-import/site-import-page.js";
|
|
66
70
|
import { aiSiteKindFor } from "../model/ai-site-kinds.js";
|
|
67
|
-
import { AI_LAYOUT_SITE_BRAND_INPUT, AI_LAYOUT_SITE_FACTS_INPUT } from "./ai-job-layout-language.js";
|
|
68
|
-
import {
|
|
71
|
+
import { AI_LAYOUT_SITE_BRAND_INPUT, AI_LAYOUT_SITE_FACTS_INPUT, AI_LAYOUT_SITE_FRAME_INPUT } from "./ai-job-layout-language.js";
|
|
72
|
+
import { aiLayoutTelHref } from "../layout-language/ai-layout-frame-source.js";
|
|
73
|
+
import { aiHexOklch } from "../model/ai-site-look.js";
|
|
74
|
+
import { AI_LAYOUT_IMPORTED_SECTIONS_INPUT } from "./ai-site-import-document.js";
|
|
75
|
+
import { aiSiteImportSectionNames } from "./ai-site-import-compile.js";
|
|
69
76
|
import { aiRunSiteImportLook } from "./ai-site-import-look.js";
|
|
70
77
|
import { aiPublishImportedWave } from "./ai-site-import-publish.js";
|
|
71
|
-
import { fileSiteImportReview } from "../site-import/site-import-review.js";
|
|
72
78
|
import { aiUnitErrorRetryable, aiUnitFailure, aiUnitSpend } from "./ai-build-unit-outcome.js";
|
|
73
79
|
import { registerAiJobAdmission } from "./ai-job-admission.js";
|
|
74
80
|
import { AI_JOB_STEP_OVERHEAD_MS } from "./ai-job-budget.js";
|
|
@@ -210,9 +216,127 @@ const delivered = (items, slot)=>items.some((row)=>row.slot === slot && (row.sta
|
|
|
210
216
|
} : {})
|
|
211
217
|
} : {});
|
|
212
218
|
}
|
|
219
|
+
/**
|
|
220
|
+
* Where a link of the source's header or footer goes on the new site
|
|
221
|
+
* (AGL-4108): a page the import brings in by its id, once its wave is the
|
|
222
|
+
* header's or before it; a page of a later wave by its address on the new
|
|
223
|
+
* site, which the page takes when its wave lands, since a link by id to a
|
|
224
|
+
* page not yet live is taken out when a wave goes live; and anywhere else by
|
|
225
|
+
* the source's own address, so a button that leaves the source leaves the
|
|
226
|
+
* new site too. `null` for an address no link may carry.
|
|
227
|
+
*/ export function aiSiteImportFrameLinkTo(state, wave) {
|
|
228
|
+
const origins = new Set(siteImportOrigins(state.domain));
|
|
229
|
+
const key = (path)=>path.replace(/\/+$/, '') || '/';
|
|
230
|
+
const pages = new Map(state.pages.filter((page)=>!page.refused).map((page)=>[
|
|
231
|
+
key(page.path),
|
|
232
|
+
page
|
|
233
|
+
]));
|
|
234
|
+
return (href)=>{
|
|
235
|
+
const raw = String(href != null ? href : '').trim();
|
|
236
|
+
if (!raw) return null;
|
|
237
|
+
if (/^tel:/i.test(raw)) return aiLayoutTelHref(raw.slice(4));
|
|
238
|
+
if (/^mailto:/i.test(raw)) return /^mailto:[^\s@<>?#"]+@[^\s@<>?#"]+\.[^\s@<>?#".]{2,}$/i.test(raw) ? raw : null;
|
|
239
|
+
let url;
|
|
240
|
+
try {
|
|
241
|
+
url = new URL(raw);
|
|
242
|
+
} catch (unused) {
|
|
243
|
+
return null;
|
|
244
|
+
}
|
|
245
|
+
if (url.protocol !== 'https:' && url.protocol !== 'http:') return null;
|
|
246
|
+
if (origins.has(`https://${url.host}`)) {
|
|
247
|
+
const page = pages.get(key(decodeURIComponent(url.pathname)));
|
|
248
|
+
if (page) return page.slug === '/' || page.wave <= wave ? `page:${page.draftId}` : `/${page.slug}`;
|
|
249
|
+
}
|
|
250
|
+
// Anywhere else stays where the source sends it, over https.
|
|
251
|
+
url.protocol = 'https:';
|
|
252
|
+
return url.toString();
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
/** The ground a source's header bar sits on (AGL-4108): dark, the brand's color, the page's own, or paper. */ export function aiSiteImportHeaderGround(background, look) {
|
|
256
|
+
const hex = /^#[0-9a-f]{6}$/i.test(background != null ? background : '') ? background : null;
|
|
257
|
+
if (!hex) return 'paper';
|
|
258
|
+
const own = aiHexOklch(hex);
|
|
259
|
+
if (own.L < 0.4) return 'dark';
|
|
260
|
+
const near = (other, within)=>{
|
|
261
|
+
if (!other || !/^#[0-9a-f]{6}$/i.test(other)) return false;
|
|
262
|
+
const them = aiHexOklch(other);
|
|
263
|
+
const a = own.C * Math.cos(own.h * Math.PI / 180) - them.C * Math.cos(them.h * Math.PI / 180);
|
|
264
|
+
const b = own.C * Math.sin(own.h * Math.PI / 180) - them.C * Math.sin(them.h * Math.PI / 180);
|
|
265
|
+
return Math.hypot(own.L - them.L, a, b) <= within;
|
|
266
|
+
};
|
|
267
|
+
if (near(look == null ? void 0 : look.buttonFill, 0.05)) return 'brand';
|
|
268
|
+
// The page's own ground, unless that ground is white, which paper is.
|
|
269
|
+
if (near(look == null ? void 0 : look.background, 0.02) && own.L < 0.99) return 'page';
|
|
270
|
+
return 'paper';
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* The site's header and footer as the source builds them (AGL-4108): its
|
|
274
|
+
* menu with its menus and their entries, its buttons with their own
|
|
275
|
+
* addresses and how they are drawn, and its footer, every link resolved
|
|
276
|
+
* (`aiSiteImportFrameLinkTo`). Every label is the source's, as written.
|
|
277
|
+
* `null` where the reader found no menu on the home page.
|
|
278
|
+
*/ export function aiSiteImportFrameSource(state, wave) {
|
|
279
|
+
var _home_footer, _home_look, _footer_copyright;
|
|
280
|
+
const home = state.home;
|
|
281
|
+
const nav = home == null ? void 0 : home.nav;
|
|
282
|
+
if (!home || !nav || !aiSiteImportFrameIsRead(state)) return null;
|
|
283
|
+
const to = aiSiteImportFrameLinkTo(state, wave.index);
|
|
284
|
+
const link = (label, href)=>{
|
|
285
|
+
const target = to(href);
|
|
286
|
+
return label && target ? {
|
|
287
|
+
label,
|
|
288
|
+
to: target
|
|
289
|
+
} : null;
|
|
290
|
+
};
|
|
291
|
+
const present = (value)=>value !== null;
|
|
292
|
+
const footer = (_home_footer = home.footer) != null ? _home_footer : null;
|
|
293
|
+
return {
|
|
294
|
+
nav: nav.items.map((group)=>({
|
|
295
|
+
label: group.label,
|
|
296
|
+
to: to(group.href),
|
|
297
|
+
items: group.items.map((entry)=>{
|
|
298
|
+
var _entry_viewBox;
|
|
299
|
+
const target = link(entry.label, entry.href);
|
|
300
|
+
if (!target) return null;
|
|
301
|
+
return _extends({}, target, entry.text ? {
|
|
302
|
+
text: entry.text
|
|
303
|
+
} : {}, entry.iconPath && ((_entry_viewBox = entry.viewBox) != null ? _entry_viewBox : '0 0 24 24') === '0 0 24 24' ? {
|
|
304
|
+
iconPath: entry.iconPath
|
|
305
|
+
} : {}, entry.column ? {
|
|
306
|
+
column: entry.column
|
|
307
|
+
} : {});
|
|
308
|
+
}).filter(present)
|
|
309
|
+
})).filter((group)=>group.items.length || group.to),
|
|
310
|
+
ctas: nav.ctas.map((cta)=>{
|
|
311
|
+
const target = link(cta.label, cta.href);
|
|
312
|
+
return target ? _extends({}, target, {
|
|
313
|
+
style: cta.style
|
|
314
|
+
}) : null;
|
|
315
|
+
}).filter(present),
|
|
316
|
+
header: aiSiteImportHeaderGround(nav.background, (_home_look = home.look) != null ? _home_look : null),
|
|
317
|
+
footer: footer ? {
|
|
318
|
+
columns: footer.columns.map((column)=>({
|
|
319
|
+
heading: column.heading,
|
|
320
|
+
links: column.links.map((entry)=>link(entry.label, entry.href)).filter(present)
|
|
321
|
+
})).filter((column)=>column.links.length),
|
|
322
|
+
links: footer.links.map((entry)=>link(entry.label, entry.href)).filter(present),
|
|
323
|
+
text: footer.text,
|
|
324
|
+
social: footer.social.map((entry)=>/^https:\/\//i.test(entry.href) ? {
|
|
325
|
+
label: entry.label,
|
|
326
|
+
to: entry.href,
|
|
327
|
+
network: entry.network
|
|
328
|
+
} : null).filter(present),
|
|
329
|
+
address: footer.address,
|
|
330
|
+
phone: footer.phone,
|
|
331
|
+
email: footer.email,
|
|
332
|
+
// The © line as the source writes it; where it writes none, the source's own name.
|
|
333
|
+
copyright: (_footer_copyright = footer.copyright) != null ? _footer_copyright : home.siteName ? `© ${home.siteName}` : null
|
|
334
|
+
} : null
|
|
335
|
+
};
|
|
336
|
+
}
|
|
213
337
|
/** The header and footer's job: a layout of the site's brand, linking the wave's pages, in the layout language. */ export function aiSiteImportFrameJob(job, state, wave, items) {
|
|
214
338
|
var _ref, _state_home, _ref1, _ref2;
|
|
215
|
-
var _state_frame, _state_look;
|
|
339
|
+
var _state_frame, _state_look, _home_brand_logo;
|
|
216
340
|
const draftId = (_ref = (_state_frame = state.frame) == null ? void 0 : _state_frame.draftId) != null ? _ref : `${job.$id}-${AI_SITE_IMPORT_FRAME_SLOT}`;
|
|
217
341
|
const creation = {
|
|
218
342
|
kind: 'layout',
|
|
@@ -230,13 +354,23 @@ const delivered = (items, slot)=>items.some((row)=>row.slot === slot && (row.sta
|
|
|
230
354
|
const home = (_state_home = state.home) != null ? _state_home : null;
|
|
231
355
|
const logo = (_ref1 = (_state_look = state.look) == null ? void 0 : _state_look.logo) != null ? _ref1 : null;
|
|
232
356
|
// The brand as the source's header draws it; with no logo in the library, its name.
|
|
233
|
-
|
|
357
|
+
// The logo is named as the source names it, never by the host's name (AGL-4108).
|
|
358
|
+
const withLogo = !!logo && !!home && home.brand.kind !== 'name-only';
|
|
359
|
+
const alt = home ? (((_home_brand_logo = home.brand.logo) == null ? void 0 : _home_brand_logo.alt) || home.siteName || home.brand.text).replace(/\s+/g, ' ').trim().slice(0, 120) : '';
|
|
360
|
+
const aspect = (logo == null ? void 0 : logo.width) && logo.height ? Math.round(logo.width / logo.height * 1000) / 1000 : null;
|
|
361
|
+
const brand = home ? _extends({}, withLogo ? _extends({
|
|
234
362
|
logo: {
|
|
235
363
|
src: logo.src
|
|
236
364
|
}
|
|
237
|
-
}
|
|
365
|
+
}, alt ? {
|
|
366
|
+
alt
|
|
367
|
+
} : {}, aspect ? {
|
|
368
|
+
aspect
|
|
369
|
+
} : {}) : {}, {
|
|
238
370
|
name: !logo || home.brand.kind !== 'logo-only'
|
|
239
371
|
}) : null;
|
|
372
|
+
// The source's own menu, buttons and footer, drawn with no model (AGL-4108).
|
|
373
|
+
const source = aiSiteImportFrameSource(state, wave);
|
|
240
374
|
return _extends({}, job, {
|
|
241
375
|
$id: draftId,
|
|
242
376
|
kind: 'layout',
|
|
@@ -256,6 +390,8 @@ const delivered = (items, slot)=>items.some((row)=>row.slot === slot && (row.sta
|
|
|
256
390
|
[AI_LAYOUT_SITE_PAGES_INPUT]: aiSiteImportLinkedPages(state, items, wave.index)
|
|
257
391
|
}, aiSiteImportDesignInputs(state), brand ? {
|
|
258
392
|
[AI_LAYOUT_SITE_BRAND_INPUT]: brand
|
|
393
|
+
} : {}, source ? {
|
|
394
|
+
[AI_LAYOUT_SITE_FRAME_INPUT]: source
|
|
259
395
|
} : {}, home ? {
|
|
260
396
|
[AI_LAYOUT_SITE_FACTS_INPUT]: {
|
|
261
397
|
url: home.url,
|
|
@@ -269,16 +405,18 @@ const delivered = (items, slot)=>items.some((row)=>row.slot === slot && (row.sta
|
|
|
269
405
|
}
|
|
270
406
|
/** The page brought in, as its page job carries it: its lines, its photos, and the pages its links may go to (AGL-4084). */ export function aiSiteImportDocumentFor(state, page) {
|
|
271
407
|
var _page_build, _ref;
|
|
272
|
-
var _page_read, _page_photos;
|
|
408
|
+
var _page_read, _page_photos, _page_read1;
|
|
273
409
|
const blocks = (_page_read = page.read) == null ? void 0 : _page_read.blocks;
|
|
274
410
|
if (!(blocks == null ? void 0 : blocks.length)) return null;
|
|
275
|
-
return {
|
|
411
|
+
return _extends({
|
|
276
412
|
build: (_page_build = page.build) != null ? _page_build : aiSiteImportBuildOf(page),
|
|
277
413
|
title: page.title,
|
|
278
414
|
url: page.url,
|
|
279
415
|
blocks,
|
|
280
416
|
photos: (_ref = (_page_photos = page.photos) == null ? void 0 : _page_photos.assets) != null ? _ref : [],
|
|
281
|
-
//
|
|
417
|
+
// Every page the import plans, in any wave (AGL-4107): a link to one still
|
|
418
|
+
// to come shows its words until it is live. Home's own links are words: a
|
|
419
|
+
// link home says home, which the source's words may not.
|
|
282
420
|
links: state.pages.filter((entry)=>entry.slug !== '/' && !entry.refused).map((entry)=>({
|
|
283
421
|
path: entry.path.replace(/\/+$/, '') || '/',
|
|
284
422
|
id: entry.draftId
|
|
@@ -287,14 +425,17 @@ const delivered = (items, slot)=>items.some((row)=>row.slot === slot && (row.sta
|
|
|
287
425
|
`https://${state.domain}`,
|
|
288
426
|
`https://www.${state.domain.replace(/^www\./, '')}`
|
|
289
427
|
]
|
|
290
|
-
}
|
|
428
|
+
}, ((_page_read1 = page.read) == null ? void 0 : _page_read1.layout) ? {
|
|
429
|
+
layout: page.read.layout
|
|
430
|
+
} : {});
|
|
291
431
|
}
|
|
292
432
|
/** One page's job: a page job's plan of one screen, its sections the old page's own, its words carried as they are. */ export function aiSiteImportPageJob(job, state, page, items) {
|
|
293
|
-
var _ref, _ref1, _ref2, _ref3;
|
|
294
|
-
var _page_read,
|
|
433
|
+
var _ref, _ref1, _ref2, _ref3, _ref4;
|
|
434
|
+
var _page_read, _page_read_meta, _page_read1, _page_read_meta1, _page_read2, _state_home, _page_read3, _page_photos;
|
|
295
435
|
const doc = aiSiteImportDocumentFor(state, page);
|
|
296
|
-
// The page's sections are the source's own (AGL-
|
|
297
|
-
|
|
436
|
+
// The page's sections are the source's own (AGL-4107): as its layout names
|
|
437
|
+
// them, else its opening and one at each second-level heading.
|
|
438
|
+
const names = doc ? aiSiteImportSectionNames(doc) : (_ref = (_page_read = page.read) == null ? void 0 : _page_read.sections) != null ? _ref : [];
|
|
298
439
|
const sections = (names.length ? names : [
|
|
299
440
|
'Introduction'
|
|
300
441
|
]).map((name)=>({
|
|
@@ -310,8 +451,9 @@ const delivered = (items, slot)=>items.some((row)=>row.slot === slot && (row.sta
|
|
|
310
451
|
template: null,
|
|
311
452
|
duplicateOf: null,
|
|
312
453
|
nav: false,
|
|
313
|
-
|
|
314
|
-
|
|
454
|
+
// The source's own title and description, word for word (AGL-4107).
|
|
455
|
+
seoTitle: ((_page_read1 = page.read) == null ? void 0 : (_page_read_meta = _page_read1.meta) == null ? void 0 : _page_read_meta.title) || page.title,
|
|
456
|
+
seoDescription: (_ref1 = (_page_read2 = page.read) == null ? void 0 : (_page_read_meta1 = _page_read2.meta) == null ? void 0 : _page_read_meta1.description) != null ? _ref1 : '',
|
|
315
457
|
sections,
|
|
316
458
|
record: null,
|
|
317
459
|
id: page.draftId
|
|
@@ -332,7 +474,7 @@ const delivered = (items, slot)=>items.some((row)=>row.slot === slot && (row.sta
|
|
|
332
474
|
}),
|
|
333
475
|
inputs: _extends({
|
|
334
476
|
originJobId: job.$id,
|
|
335
|
-
businessName: aiSiteImportBrandName(state.siteName, (
|
|
477
|
+
businessName: aiSiteImportBrandName(state.siteName, (_ref2 = (_state_home = state.home) == null ? void 0 : _state_home.siteName) != null ? _ref2 : ''),
|
|
336
478
|
[AI_LAYOUT_LANGUAGE_INPUT]: true,
|
|
337
479
|
[AI_LAYOUT_SITE_PAGES_INPUT]: aiSiteImportLinkedPages(state, items, page.wave)
|
|
338
480
|
}, aiSiteImportDesignInputs(state), doc ? {
|
|
@@ -340,10 +482,10 @@ const delivered = (items, slot)=>items.some((row)=>row.slot === slot && (row.sta
|
|
|
340
482
|
} : {
|
|
341
483
|
[AI_LAYOUT_IMPORTED_PAGE_INPUT]: {
|
|
342
484
|
url: page.url,
|
|
343
|
-
text: (
|
|
485
|
+
text: (_ref3 = (_page_read3 = page.read) == null ? void 0 : _page_read3.text) != null ? _ref3 : ''
|
|
344
486
|
}
|
|
345
487
|
}, {
|
|
346
|
-
[AI_LAYOUT_PAGE_PHOTOS_INPUT]: (
|
|
488
|
+
[AI_LAYOUT_PAGE_PHOTOS_INPUT]: (_ref4 = (_page_photos = page.photos) == null ? void 0 : _page_photos.assets) != null ? _ref4 : []
|
|
347
489
|
}, others.length ? {
|
|
348
490
|
[AI_STOCK_PHOTO_PAGES_INPUT]: others
|
|
349
491
|
} : {}),
|
|
@@ -380,7 +522,7 @@ const delivered = (items, slot)=>items.some((row)=>row.slot === slot && (row.sta
|
|
|
380
522
|
const text = (line != null ? line : '').replace(/\s+/g, ' ').trim();
|
|
381
523
|
if (text && !lines.some((entry)=>entry.includes(text))) lines.push(text);
|
|
382
524
|
}
|
|
383
|
-
return {
|
|
525
|
+
return _extends({
|
|
384
526
|
url: page.url,
|
|
385
527
|
title: siteImportLabel((_page_title = page.title) != null ? _page_title : '', 160),
|
|
386
528
|
description: siteImportLabel((_page_description = page.description) != null ? _page_description : '', 320),
|
|
@@ -402,7 +544,13 @@ const delivered = (items, slot)=>items.some((row)=>row.slot === slot && (row.sta
|
|
|
402
544
|
social: facts.social,
|
|
403
545
|
address: (_ref = (_facts_organization = facts.organization) == null ? void 0 : _facts_organization.address) != null ? _ref : ''
|
|
404
546
|
}
|
|
405
|
-
}
|
|
547
|
+
}, page.nav ? {
|
|
548
|
+
nav: page.nav
|
|
549
|
+
} : {}, page.footer ? {
|
|
550
|
+
footer: page.footer
|
|
551
|
+
} : {}, page.look ? {
|
|
552
|
+
look: page.look
|
|
553
|
+
} : {});
|
|
406
554
|
}
|
|
407
555
|
/** The least time the import's next pass needs: a read's, a photo pass's, or the time of the step its unit is handed to. */ export function aiSiteImportRunMinimumMs(job, runnerFor = aiJobStepRunnerFor) {
|
|
408
556
|
var _job_siteImport, _job_items;
|
|
@@ -499,7 +647,7 @@ async function readDraftWords(firestore, hostId, draftId) {
|
|
|
499
647
|
return wave.slots.every((slot)=>!aiSiteImportItemOpen(items, slot));
|
|
500
648
|
}
|
|
501
649
|
export function createAiJobImportStep(deps = {}) {
|
|
502
|
-
var _deps_crawl, _deps_runnerFor, _deps_ownership, _deps_rateLimit, _deps_releaseFlagOn, _deps_ingest, _deps_readRoom, _deps_readSiteName,
|
|
650
|
+
var _deps_crawl, _deps_runnerFor, _deps_ownership, _deps_rateLimit, _deps_releaseFlagOn, _deps_ingest, _deps_readRoom, _deps_readSiteName, _deps_pageWritten, _deps_mintId, _deps_clock, _deps_look, _deps_publishWave, _deps_draftWords;
|
|
503
651
|
const crawl = (_deps_crawl = deps.crawl) != null ? _deps_crawl : crawlSiteForImport;
|
|
504
652
|
const runnerFor = (_deps_runnerFor = deps.runnerFor) != null ? _deps_runnerFor : aiJobStepRunnerFor;
|
|
505
653
|
const ownershipOf = (_deps_ownership = deps.ownership) != null ? _deps_ownership : readOwnership;
|
|
@@ -508,7 +656,6 @@ export function createAiJobImportStep(deps = {}) {
|
|
|
508
656
|
const ingestOf = (_deps_ingest = deps.ingest) != null ? _deps_ingest : pluginMediaIngest;
|
|
509
657
|
const readRoom = (_deps_readRoom = deps.readRoom) != null ? _deps_readRoom : readAiScreenRoom;
|
|
510
658
|
const siteNameOf = (_deps_readSiteName = deps.readSiteName) != null ? _deps_readSiteName : readSiteName;
|
|
511
|
-
const fileReview = (_deps_fileReview = deps.fileReview) != null ? _deps_fileReview : fileSiteImportReview;
|
|
512
659
|
const pageWritten = (_deps_pageWritten = deps.pageWritten) != null ? _deps_pageWritten : aiSitePageWritten;
|
|
513
660
|
const mintId = (_deps_mintId = deps.mintId) != null ? _deps_mintId : createResourceUid;
|
|
514
661
|
const clock = (_deps_clock = deps.clock) != null ? _deps_clock : Date.now;
|
|
@@ -533,17 +680,6 @@ export function createAiJobImportStep(deps = {}) {
|
|
|
533
680
|
const items = (_job_items = job.items) != null ? _job_items : [];
|
|
534
681
|
const work = aiSiteImportNextWork(state, items);
|
|
535
682
|
const nowIso = now.toISOString();
|
|
536
|
-
const review = (event, next, ledger, wave)=>fileReview(firestore, _extends({
|
|
537
|
-
orgId: job.orgId,
|
|
538
|
-
hostId,
|
|
539
|
-
jobId: job.$id,
|
|
540
|
-
state: next,
|
|
541
|
-
items: ledger,
|
|
542
|
-
event,
|
|
543
|
-
nowMs: now.getTime()
|
|
544
|
-
}, wave !== undefined ? {
|
|
545
|
-
wave
|
|
546
|
-
} : {}));
|
|
547
683
|
/** Closes the wave when this pass settled its last row: the review, or the job's end after the last wave. */ const closing = async (next, ledger, wave, outcome)=>{
|
|
548
684
|
var _closed_waves_find;
|
|
549
685
|
if (!waveSettled(next, wave, ledger)) return _extends({}, outcome, {
|
|
@@ -578,7 +714,6 @@ export function createAiJobImportStep(deps = {}) {
|
|
|
578
714
|
const published = sitePublish ? {
|
|
579
715
|
sitePublish
|
|
580
716
|
} : {};
|
|
581
|
-
await review('wave-finished', closed, ledger, wave.index);
|
|
582
717
|
const waiting = ((_closed_waves_find = closed.waves.find((entry)=>entry.index === wave.index)) == null ? void 0 : _closed_waves_find.status) === 'review';
|
|
583
718
|
if (waiting) {
|
|
584
719
|
const message = (sitePublish == null ? void 0 : sitePublish.published.length) ? aiSiteImportPreviewMessage(closed, wave, sitePublish.published.length) : aiSiteImportWaveMessage(closed, ledger);
|
|
@@ -701,14 +836,10 @@ export function createAiJobImportStep(deps = {}) {
|
|
|
701
836
|
home: aiSiteImportHomeOf(crawled)
|
|
702
837
|
});
|
|
703
838
|
const ledger = aiSiteImportLedger(planned);
|
|
704
|
-
const reviewId = await review('read', planned, ledger);
|
|
705
|
-
const next = _extends({}, planned, {
|
|
706
|
-
reviewId
|
|
707
|
-
});
|
|
708
839
|
return unspent({
|
|
709
840
|
items: ledger,
|
|
710
|
-
siteImport:
|
|
711
|
-
review: waveReview(aiSiteImportWaveMessage(
|
|
841
|
+
siteImport: planned,
|
|
842
|
+
review: waveReview(aiSiteImportWaveMessage(planned, ledger))
|
|
712
843
|
});
|
|
713
844
|
}
|
|
714
845
|
if (!state) return unspent({
|
|
@@ -771,7 +902,6 @@ export function createAiJobImportStep(deps = {}) {
|
|
|
771
902
|
}) : row);
|
|
772
903
|
}
|
|
773
904
|
const started = aiSiteImportWithBuilds(aiSiteImportWaveStarted(state, wave.index, nowIso, reads));
|
|
774
|
-
await review('wave-started', started, ledger, wave.index);
|
|
775
905
|
const running = started.waves.find((entry)=>entry.index === wave.index);
|
|
776
906
|
return closing(started, ledger, running, unspent({
|
|
777
907
|
items: ledger
|