@aglyn/plugins-ai 1.0.0-beta.244 → 1.0.0-beta.246
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/activity/ai-activity-actions.js +3 -1
- package/src/lib/activity/ai-activity-actions.js.map +1 -1
- package/src/lib/components/ai-job-links.js +7 -0
- package/src/lib/components/ai-job-links.js.map +1 -1
- package/src/lib/components/ai-product-zones.d.ts +3 -1
- package/src/lib/components/ai-product-zones.js.map +1 -1
- package/src/lib/components/ai-products-hub-card.component.js +1 -1
- package/src/lib/components/ai-products-hub-card.component.js.map +1 -1
- package/src/lib/components/ai-products-proposals.component.js +17 -9
- package/src/lib/components/ai-products-proposals.component.js.map +1 -1
- package/src/lib/components/ai-site-start-card.component.js +6 -4
- package/src/lib/components/ai-site-start-card.component.js.map +1 -1
- package/src/lib/components/ai-upsell-dialog.component.js +1 -1
- package/src/lib/components/ai-upsell-dialog.component.js.map +1 -1
- package/src/lib/jobs/ai-build-capabilities.js +162 -2
- package/src/lib/jobs/ai-build-capabilities.js.map +1 -1
- package/src/lib/jobs/ai-job-build-step.d.ts +7 -0
- package/src/lib/jobs/ai-job-build-step.js +85 -16
- package/src/lib/jobs/ai-job-build-step.js.map +1 -1
- package/src/lib/jobs/ai-job-duplicate-step.d.ts +123 -0
- package/src/lib/jobs/ai-job-duplicate-step.js +269 -0
- package/src/lib/jobs/ai-job-duplicate-step.js.map +1 -0
- package/src/lib/jobs/ai-job-layout-language.js +13 -0
- package/src/lib/jobs/ai-job-layout-language.js.map +1 -1
- package/src/lib/jobs/ai-job-navigation-step.d.ts +157 -0
- package/src/lib/jobs/ai-job-navigation-step.js +439 -0
- package/src/lib/jobs/ai-job-navigation-step.js.map +1 -0
- package/src/lib/jobs/ai-job-page-language.d.ts +2 -1
- package/src/lib/jobs/ai-job-page-language.js +21 -5
- package/src/lib/jobs/ai-job-page-language.js.map +1 -1
- package/src/lib/jobs/ai-job-page-sections.js +1 -1
- package/src/lib/jobs/ai-job-page-sections.js.map +1 -1
- package/src/lib/jobs/ai-job-plan-step.d.ts +4 -2
- package/src/lib/jobs/ai-job-plan-step.js +16 -7
- package/src/lib/jobs/ai-job-plan-step.js.map +1 -1
- package/src/lib/jobs/ai-job-products-step.d.ts +2 -2
- package/src/lib/jobs/ai-job-products-step.js +2 -2
- package/src/lib/jobs/ai-job-products-step.js.map +1 -1
- package/src/lib/jobs/ai-job-settings-step.d.ts +272 -0
- package/src/lib/jobs/ai-job-settings-step.js +695 -0
- package/src/lib/jobs/ai-job-settings-step.js.map +1 -0
- package/src/lib/jobs/ai-job-site-content.d.ts +20 -6
- package/src/lib/jobs/ai-job-site-content.js +28 -12
- package/src/lib/jobs/ai-job-site-content.js.map +1 -1
- package/src/lib/jobs/ai-job-site-datasets.d.ts +2 -0
- package/src/lib/jobs/ai-job-site-datasets.js +10 -3
- package/src/lib/jobs/ai-job-site-datasets.js.map +1 -1
- package/src/lib/jobs/ai-job-site-step.d.ts +3 -1
- package/src/lib/jobs/ai-job-site-step.js +70 -10
- package/src/lib/jobs/ai-job-site-step.js.map +1 -1
- package/src/lib/jobs/ai-site-publish.d.ts +62 -4
- package/src/lib/jobs/ai-site-publish.js +203 -56
- package/src/lib/jobs/ai-site-publish.js.map +1 -1
- package/src/lib/layout-language/ai-layout-compiler.d.ts +7 -4
- package/src/lib/layout-language/ai-layout-compiler.js +26 -25
- package/src/lib/layout-language/ai-layout-compiler.js.map +1 -1
- package/src/lib/layout-language/ai-layout-frame-hollows.d.ts +41 -0
- package/src/lib/layout-language/ai-layout-frame-hollows.js +330 -0
- package/src/lib/layout-language/ai-layout-frame-hollows.js.map +1 -0
- package/src/lib/layout-language/ai-layout-frame.d.ts +18 -1
- package/src/lib/layout-language/ai-layout-frame.js +83 -13
- package/src/lib/layout-language/ai-layout-frame.js.map +1 -1
- package/src/lib/layout-language/ai-layout-listings.d.ts +35 -0
- package/src/lib/layout-language/ai-layout-listings.js +34 -0
- package/src/lib/layout-language/ai-layout-listings.js.map +1 -1
- package/src/lib/layout-language/ai-layout-tree.d.ts +2 -0
- package/src/lib/layout-language/ai-layout-tree.js +17 -0
- package/src/lib/layout-language/ai-layout-tree.js.map +1 -1
- package/src/lib/model/ai-build-job.d.ts +23 -0
- package/src/lib/model/ai-build-job.js +102 -13
- package/src/lib/model/ai-build-job.js.map +1 -1
- package/src/lib/model/ai-build-plan.d.ts +25 -0
- package/src/lib/model/ai-build-plan.js +45 -1
- package/src/lib/model/ai-build-plan.js.map +1 -1
- package/src/lib/model/ai-credit-estimate.d.ts +52 -0
- package/src/lib/model/ai-credit-estimate.js +51 -0
- package/src/lib/model/ai-credit-estimate.js.map +1 -1
- package/src/lib/model/ai-job-activity.js +4 -1
- package/src/lib/model/ai-job-activity.js.map +1 -1
- package/src/lib/model/ai-jobs.types.d.ts +10 -2
- package/src/lib/model/ai-jobs.types.js +4 -1
- package/src/lib/model/ai-jobs.types.js.map +1 -1
- package/src/lib/model/ai-layout-menus.d.ts +104 -0
- package/src/lib/model/ai-layout-menus.js +518 -0
- package/src/lib/model/ai-layout-menus.js.map +1 -0
- package/src/lib/model/ai-products.d.ts +31 -1
- package/src/lib/model/ai-products.js +34 -1
- package/src/lib/model/ai-products.js.map +1 -1
- package/src/lib/model/ai-site-inventory.d.ts +15 -0
- package/src/lib/model/ai-site-inventory.js.map +1 -1
- package/src/lib/model/ai-site-job.d.ts +10 -0
- package/src/lib/model/ai-site-job.js +36 -9
- package/src/lib/model/ai-site-job.js.map +1 -1
- package/src/lib/model/ai-site-store-pages.js +1 -1
- package/src/lib/model/ai-site-store-pages.js.map +1 -1
- package/src/lib/runtime/ai-doctrine-validators.d.ts +53 -0
- package/src/lib/runtime/ai-doctrine-validators.js +166 -25
- package/src/lib/runtime/ai-doctrine-validators.js.map +1 -1
- package/src/lib/runtime/ai-doctrine.js +7 -2
- package/src/lib/runtime/ai-doctrine.js.map +1 -1
- package/src/lib/runtime/ai-palette.generated.js +1 -1
- package/src/lib/runtime/ai-palette.generated.js.map +1 -1
- package/src/lib/runtime/ai-products-generation.d.ts +4 -2
- package/src/lib/runtime/ai-products-generation.js +12 -6
- package/src/lib/runtime/ai-products-generation.js.map +1 -1
- package/src/lib/runtime/site-inventory.d.ts +12 -0
- package/src/lib/runtime/site-inventory.js +29 -1
- package/src/lib/runtime/site-inventory.js.map +1 -1
- package/src/lib/server.js +12 -0
- package/src/lib/server.js.map +1 -1
- package/src/lib/testing/stand-in-dataset-index.js +37 -3
- package/src/lib/testing/stand-in-dataset-index.js.map +1 -1
- package/src/lib/tools/ai-products-tool.d.ts +3 -1
- package/src/lib/tools/ai-products-tool.js +15 -5
- package/src/lib/tools/ai-products-tool.js.map +1 -1
|
@@ -73,6 +73,22 @@ export interface AiSitePublishDeps {
|
|
|
73
73
|
* door). Every other build leaves drafts.
|
|
74
74
|
*/
|
|
75
75
|
export declare function aiJobPublishesBuild(job: Pick<AiJob, 'kind' | 'inputs'>): boolean;
|
|
76
|
+
/**
|
|
77
|
+
* The host fields a guided start writes for its plan's language (AGL-3750),
|
|
78
|
+
* as the Languages card saves one language: `locales` of that one and
|
|
79
|
+
* `defaultLocale` the same. `null` — nothing written — where the plan said no
|
|
80
|
+
* valid language, where it is the language the site already publishes in
|
|
81
|
+
* (English for a new site), and on a site with more than one language, whose
|
|
82
|
+
* languages are the owner's decision. Nothing is translated: the pages were
|
|
83
|
+
* written in the brief's language, and this says so to the reader.
|
|
84
|
+
*/
|
|
85
|
+
export declare function aiSiteLanguageUpdates(host: {
|
|
86
|
+
locales?: unknown;
|
|
87
|
+
defaultLocale?: unknown;
|
|
88
|
+
}, language: string | null | undefined): {
|
|
89
|
+
locales: string[];
|
|
90
|
+
defaultLocale: string;
|
|
91
|
+
} | null;
|
|
76
92
|
/** Whether a finished job of this shape publishes what it built. */
|
|
77
93
|
export declare function aiJobPublishesSite(job: Pick<AiJob, 'kind' | 'inputs'>): boolean;
|
|
78
94
|
/**
|
|
@@ -103,10 +119,12 @@ interface NavEntry {
|
|
|
103
119
|
export declare function aiSiteUnwrittenBlogHrefs(blogUnwritten: boolean | undefined): string[];
|
|
104
120
|
/**
|
|
105
121
|
* The layout's nodes with its links to the retired starter home pointed at
|
|
106
|
-
* the new home,
|
|
107
|
-
*
|
|
108
|
-
*
|
|
109
|
-
*
|
|
122
|
+
* the new home, its links to pages the start did not write taken out, and a
|
|
123
|
+
* link for each proposed entry the header does not already carry, added by
|
|
124
|
+
* the navigation op's `aiLayoutWithMenuChanges` (AGL-3747): to the header's
|
|
125
|
+
* menu and its phone menu, after their items, or after the brand in a
|
|
126
|
+
* starter's Toolbar. `null` when nothing changes, or when the layout has no
|
|
127
|
+
* header to hold an entry and no link to repoint or take out.
|
|
110
128
|
*/
|
|
111
129
|
export declare function aiLayoutWithNavigation(nodes: NodesMap, input: {
|
|
112
130
|
entries: readonly NavEntry[];
|
|
@@ -115,6 +133,41 @@ export declare function aiLayoutWithNavigation(nodes: NodesMap, input: {
|
|
|
115
133
|
/** Paths whose links come out: a blog the start linked and never wrote (AGL-3660). */
|
|
116
134
|
droppedHrefs?: readonly string[];
|
|
117
135
|
}): NodesMap | null;
|
|
136
|
+
/** The blog a start writes, as its header entry links it (`aiSiteBlogNavPage`). */
|
|
137
|
+
export interface AiSiteBlogEntry {
|
|
138
|
+
label: string;
|
|
139
|
+
href: string;
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* The layout's nodes with the blog's header entry put back (AGL-3747): a
|
|
143
|
+
* start whose posts part failed published with every link to the blog taken
|
|
144
|
+
* out (AGL-3660), and Try again's posts went live with none to reach them.
|
|
145
|
+
* Added by the navigation op's `aiLayoutWithMenuChanges`, as the start's
|
|
146
|
+
* other entries are — the bar's menu and the phone menu — second after the
|
|
147
|
+
* home page's item, as the start first linked it (AGL-3676), else last.
|
|
148
|
+
* `null` where some link already opens the blog, or the layout has no header
|
|
149
|
+
* menu to hold it.
|
|
150
|
+
*/
|
|
151
|
+
export declare function aiLayoutWithBlogEntry(nodes: NodesMap, input: {
|
|
152
|
+
blog: AiSiteBlogEntry;
|
|
153
|
+
homeId?: string | null;
|
|
154
|
+
}): NodesMap | null;
|
|
155
|
+
/**
|
|
156
|
+
* Puts the blog's header entry back on a live start whose posts Try again
|
|
157
|
+
* wrote (AGL-3747), as a new live version of the layout its published pages
|
|
158
|
+
* render inside, in one batch with the publish outbox entry that drops the
|
|
159
|
+
* live site's cached pages, the drop itself attempted at once. Returns
|
|
160
|
+
* whether the entry went live; never throws for a layout it cannot change.
|
|
161
|
+
*/
|
|
162
|
+
export declare function aiRestoreGuidedBlogEntry(firestore: Firestore, input: {
|
|
163
|
+
job: Pick<AiJob, '$id' | 'hostId'>;
|
|
164
|
+
/** The start's published pages: the layout they share is the one changed. */
|
|
165
|
+
pageIds: readonly string[];
|
|
166
|
+
/** The published home page, which the blog's entry follows. */
|
|
167
|
+
homeId?: string | null;
|
|
168
|
+
blog: AiSiteBlogEntry;
|
|
169
|
+
now: Date;
|
|
170
|
+
}, deps?: Pick<AiSitePublishDeps, 'dropCache'>): Promise<boolean>;
|
|
118
171
|
/**
|
|
119
172
|
* A retry's publish merged into the start's first (AGL-3730): the pages it
|
|
120
173
|
* put live join the published list, a page it published leaves the drafts,
|
|
@@ -144,5 +197,10 @@ export declare function aiPublishGuidedSite(firestore: Firestore, input: {
|
|
|
144
197
|
* starter still holds stays a draft and says so.
|
|
145
198
|
*/
|
|
146
199
|
retry?: boolean;
|
|
200
|
+
/**
|
|
201
|
+
* The language the plan says the brief and copy are in (AGL-3750): the
|
|
202
|
+
* site publishes in it, where `aiSiteLanguageUpdates` says so.
|
|
203
|
+
*/
|
|
204
|
+
language?: string | null;
|
|
147
205
|
}, deps?: AiSitePublishDeps): Promise<AiJobSitePublish>;
|
|
148
206
|
export {};
|
|
@@ -18,12 +18,16 @@ import { _ as _extends } from "@swc/helpers/_/_extends";
|
|
|
18
18
|
import { createResourceUid } from "@aglyn/aglyn/app-utils/create-resource-uid";
|
|
19
19
|
import { hostPublicOrigin } from "@aglyn/aglyn/app-utils/host-naming";
|
|
20
20
|
import { blockingRouteOwner, normalizeScreenSlug, SCREEN_ROOT_PATH, screenRoutePathToUrl } from "@aglyn/aglyn/app-utils/screen-route";
|
|
21
|
+
import { resolvePageLocale } from "@aglyn/aglyn/app-utils/seo-locale";
|
|
21
22
|
import { decodeStoredNodes, encodeStoredNodes } from "@aglyn/aglyn/app-utils/stored-nodes";
|
|
22
23
|
import { dropPluginSiteCache } from "@aglyn/aglyn/plugin-manager/plugin-site-cache";
|
|
23
24
|
import { sendGa4SitePublished } from "@aglyn/tenant-data-admin/server/ga4-measurement-protocol";
|
|
24
25
|
import { FieldValue } from "firebase-admin/firestore";
|
|
26
|
+
import { aiLayoutFrameHollows, aiLayoutFrameHollowsSaid, aiLayoutFrameIsHollow, aiLayoutRepairFrameHollows, aiLayoutWithoutFrameHollows } from "../layout-language/ai-layout-frame-hollows.js";
|
|
27
|
+
import { aiPlanLanguage } from "../model/ai-build-plan.js";
|
|
25
28
|
import { AI_SITE_BLOG_SLUGS } from "../model/ai-site-job.js";
|
|
26
29
|
import { aiLayoutWithStoreLinks } from "../model/ai-layout-store-links.js";
|
|
30
|
+
import { aiLayoutWithMenuChanges, aiNoMenuChanges } from "../model/ai-layout-menus.js";
|
|
27
31
|
import { AI_STORE_LINKS_SOURCE_FIELD as STORE_LINKS_SOURCE_FIELD } from "./ai-job-store-links-layout.js";
|
|
28
32
|
/**
|
|
29
33
|
* Whether a build puts its pages live (AGL-3616): only where its request
|
|
@@ -34,6 +38,34 @@ import { AI_STORE_LINKS_SOURCE_FIELD as STORE_LINKS_SOURCE_FIELD } from "./ai-jo
|
|
|
34
38
|
var _job_inputs, _job_inputs1;
|
|
35
39
|
return job.kind === 'build' && ((_job_inputs = job.inputs) == null ? void 0 : _job_inputs['publish']) === true && ((_job_inputs1 = job.inputs) == null ? void 0 : _job_inputs1['publishConfirmed']) === true;
|
|
36
40
|
}
|
|
41
|
+
/**
|
|
42
|
+
* The host fields a guided start writes for its plan's language (AGL-3750),
|
|
43
|
+
* as the Languages card saves one language: `locales` of that one and
|
|
44
|
+
* `defaultLocale` the same. `null` — nothing written — where the plan said no
|
|
45
|
+
* valid language, where it is the language the site already publishes in
|
|
46
|
+
* (English for a new site), and on a site with more than one language, whose
|
|
47
|
+
* languages are the owner's decision. Nothing is translated: the pages were
|
|
48
|
+
* written in the brief's language, and this says so to the reader.
|
|
49
|
+
*/ export function aiSiteLanguageUpdates(host, language) {
|
|
50
|
+
const code = aiPlanLanguage(language);
|
|
51
|
+
if (!code) return null;
|
|
52
|
+
const locales = Array.isArray(host.locales) ? host.locales.filter((one)=>typeof one === 'string' && one.trim() !== '') : [];
|
|
53
|
+
if (locales.length > 1) return null;
|
|
54
|
+
const current = resolvePageLocale({
|
|
55
|
+
host: _extends({}, typeof host.defaultLocale === 'string' ? {
|
|
56
|
+
defaultLocale: host.defaultLocale
|
|
57
|
+
} : {}, {
|
|
58
|
+
locales
|
|
59
|
+
})
|
|
60
|
+
});
|
|
61
|
+
if (current === code) return null;
|
|
62
|
+
return {
|
|
63
|
+
locales: [
|
|
64
|
+
code
|
|
65
|
+
],
|
|
66
|
+
defaultLocale: code
|
|
67
|
+
};
|
|
68
|
+
}
|
|
37
69
|
/** Whether a finished job of this shape publishes what it built. */ export function aiJobPublishesSite(job) {
|
|
38
70
|
var _job_inputs;
|
|
39
71
|
return job.kind === 'site' && ((_job_inputs = job.inputs) == null ? void 0 : _job_inputs['autoConfirm']) === true;
|
|
@@ -80,10 +112,12 @@ function navEntriesOf(outputs) {
|
|
|
80
112
|
}
|
|
81
113
|
/**
|
|
82
114
|
* The layout's nodes with its links to the retired starter home pointed at
|
|
83
|
-
* the new home,
|
|
84
|
-
*
|
|
85
|
-
*
|
|
86
|
-
*
|
|
115
|
+
* the new home, its links to pages the start did not write taken out, and a
|
|
116
|
+
* link for each proposed entry the header does not already carry, added by
|
|
117
|
+
* the navigation op's `aiLayoutWithMenuChanges` (AGL-3747): to the header's
|
|
118
|
+
* menu and its phone menu, after their items, or after the brand in a
|
|
119
|
+
* starter's Toolbar. `null` when nothing changes, or when the layout has no
|
|
120
|
+
* header to hold an entry and no link to repoint or take out.
|
|
87
121
|
*/ export function aiLayoutWithNavigation(nodes, input) {
|
|
88
122
|
var _input_droppedHrefs;
|
|
89
123
|
const map = {};
|
|
@@ -113,6 +147,9 @@ function navEntriesOf(outputs) {
|
|
|
113
147
|
var _node_nodes;
|
|
114
148
|
if ((_node_nodes = node.nodes) == null ? void 0 : _node_nodes.some((child)=>gone.has(child))) node.nodes = node.nodes.filter((child)=>!gone.has(child));
|
|
115
149
|
}
|
|
150
|
+
// A footer heading whose links all went goes with them, and its column
|
|
151
|
+
// when that leaves it only the heading (AGL-3735).
|
|
152
|
+
aiLayoutRepairFrameHollows(map);
|
|
116
153
|
changed = true;
|
|
117
154
|
}
|
|
118
155
|
}
|
|
@@ -128,51 +165,140 @@ function navEntriesOf(outputs) {
|
|
|
128
165
|
}
|
|
129
166
|
}
|
|
130
167
|
}
|
|
168
|
+
// The entries go into the header through the navigation op's own code
|
|
169
|
+
// (AGL-3747): the bar's menu and the phone menu's, after the items already
|
|
170
|
+
// there, each looking like its neighbours. A page some link already opens,
|
|
171
|
+
// or an item of the same name, is not added again.
|
|
131
172
|
const linked = new Set(links.map((link)=>{
|
|
132
173
|
var _link_props;
|
|
133
174
|
return (_link_props = link.props) == null ? void 0 : _link_props['screenId'];
|
|
134
175
|
}).filter(Boolean));
|
|
135
|
-
const toolbar = Object.values(map).find((node)=>node.componentId === 'muiToolbar');
|
|
136
176
|
const missing = input.entries.filter((entry)=>!linked.has(entry.screenId));
|
|
137
|
-
if (
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
componentId: 'muiScreenLink',
|
|
151
|
-
pluginId: 'mui',
|
|
152
|
-
parentId: toolbar.$id,
|
|
153
|
-
props: {
|
|
154
|
-
children: entry.label,
|
|
155
|
-
screenId: entry.screenId,
|
|
156
|
-
renderAs: 'link',
|
|
157
|
-
color: 'inherit'
|
|
158
|
-
},
|
|
159
|
-
sx: {
|
|
160
|
-
textDecoration: 'none',
|
|
161
|
-
whiteSpace: 'nowrap'
|
|
162
|
-
},
|
|
163
|
-
nodes: []
|
|
164
|
-
};
|
|
165
|
-
return id;
|
|
177
|
+
if (missing.length) {
|
|
178
|
+
const added = aiLayoutWithMenuChanges(map, [
|
|
179
|
+
'header'
|
|
180
|
+
], _extends({}, aiNoMenuChanges(), {
|
|
181
|
+
add: missing.map((entry)=>({
|
|
182
|
+
parent: null,
|
|
183
|
+
label: entry.label,
|
|
184
|
+
to: {
|
|
185
|
+
screenId: entry.screenId
|
|
186
|
+
}
|
|
187
|
+
}))
|
|
188
|
+
}), {
|
|
189
|
+
newId: ()=>`ai_nav_${createResourceUid()}`
|
|
166
190
|
});
|
|
167
|
-
|
|
168
|
-
...children.slice(0, lastLink + 1),
|
|
169
|
-
...added,
|
|
170
|
-
...children.slice(lastLink + 1)
|
|
171
|
-
];
|
|
172
|
-
changed = true;
|
|
191
|
+
if (added.nodes) return added.nodes;
|
|
173
192
|
}
|
|
174
193
|
return changed ? map : null;
|
|
175
194
|
}
|
|
195
|
+
/**
|
|
196
|
+
* The layout's nodes with the blog's header entry put back (AGL-3747): a
|
|
197
|
+
* start whose posts part failed published with every link to the blog taken
|
|
198
|
+
* out (AGL-3660), and Try again's posts went live with none to reach them.
|
|
199
|
+
* Added by the navigation op's `aiLayoutWithMenuChanges`, as the start's
|
|
200
|
+
* other entries are — the bar's menu and the phone menu — second after the
|
|
201
|
+
* home page's item, as the start first linked it (AGL-3676), else last.
|
|
202
|
+
* `null` where some link already opens the blog, or the layout has no header
|
|
203
|
+
* menu to hold it.
|
|
204
|
+
*/ export function aiLayoutWithBlogEntry(nodes, input) {
|
|
205
|
+
var _added_nodes;
|
|
206
|
+
const blogHrefs = new Set([
|
|
207
|
+
input.blog.href,
|
|
208
|
+
...AI_SITE_BLOG_SLUGS.map((slug)=>`/${slug}`)
|
|
209
|
+
]);
|
|
210
|
+
const linked = Object.values(nodes).some((node)=>{
|
|
211
|
+
var _ref;
|
|
212
|
+
var _node_props;
|
|
213
|
+
return (node == null ? void 0 : node.componentId) === 'muiScreenLink' && blogHrefs.has(String((_ref = (_node_props = node.props) == null ? void 0 : _node_props['href']) != null ? _ref : ''));
|
|
214
|
+
});
|
|
215
|
+
if (linked) return null;
|
|
216
|
+
const home = [
|
|
217
|
+
...input.homeId ? [
|
|
218
|
+
{
|
|
219
|
+
screenId: input.homeId
|
|
220
|
+
}
|
|
221
|
+
] : [],
|
|
222
|
+
{
|
|
223
|
+
href: '/'
|
|
224
|
+
}
|
|
225
|
+
];
|
|
226
|
+
const added = aiLayoutWithMenuChanges(nodes, [
|
|
227
|
+
'header'
|
|
228
|
+
], _extends({}, aiNoMenuChanges(), {
|
|
229
|
+
add: [
|
|
230
|
+
{
|
|
231
|
+
parent: null,
|
|
232
|
+
label: input.blog.label,
|
|
233
|
+
to: {
|
|
234
|
+
href: input.blog.href
|
|
235
|
+
},
|
|
236
|
+
after: home
|
|
237
|
+
}
|
|
238
|
+
]
|
|
239
|
+
}), {
|
|
240
|
+
newId: ()=>`ai_nav_${createResourceUid()}`
|
|
241
|
+
});
|
|
242
|
+
return (_added_nodes = added.nodes) != null ? _added_nodes : null;
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* Puts the blog's header entry back on a live start whose posts Try again
|
|
246
|
+
* wrote (AGL-3747), as a new live version of the layout its published pages
|
|
247
|
+
* render inside, in one batch with the publish outbox entry that drops the
|
|
248
|
+
* live site's cached pages, the drop itself attempted at once. Returns
|
|
249
|
+
* whether the entry went live; never throws for a layout it cannot change.
|
|
250
|
+
*/ export async function aiRestoreGuidedBlogEntry(firestore, input, deps = {}) {
|
|
251
|
+
var _deps_dropCache, _input_job_hostId;
|
|
252
|
+
const dropCache = (_deps_dropCache = deps.dropCache) != null ? _deps_dropCache : dropPluginSiteCache;
|
|
253
|
+
const hostId = (_input_job_hostId = input.job.hostId) != null ? _input_job_hostId : '';
|
|
254
|
+
if (!hostId || !input.pageIds.length) return false;
|
|
255
|
+
const layoutId = await aiPagesLayoutId(firestore, hostId, input.pageIds);
|
|
256
|
+
if (!layoutId) return false;
|
|
257
|
+
const write = await aiLayoutVersionWrite(firestore, {
|
|
258
|
+
hostId,
|
|
259
|
+
layoutId,
|
|
260
|
+
transform: (nodes)=>{
|
|
261
|
+
var _input_homeId;
|
|
262
|
+
return aiLayoutWithBlogEntry(nodes, {
|
|
263
|
+
blog: input.blog,
|
|
264
|
+
homeId: (_input_homeId = input.homeId) != null ? _input_homeId : null
|
|
265
|
+
});
|
|
266
|
+
},
|
|
267
|
+
storeLinks: null,
|
|
268
|
+
jobId: input.job.$id,
|
|
269
|
+
now: input.now,
|
|
270
|
+
displayName: 'Navigation for the blog'
|
|
271
|
+
});
|
|
272
|
+
if (!(write == null ? void 0 : write.version)) return false;
|
|
273
|
+
const batch = firestore.batch();
|
|
274
|
+
batch.create(write.versionRef, write.version);
|
|
275
|
+
batch.set(write.layoutRef, {
|
|
276
|
+
versionId: write.versionRef.id,
|
|
277
|
+
updatedAt: input.now
|
|
278
|
+
}, {
|
|
279
|
+
merge: true
|
|
280
|
+
});
|
|
281
|
+
// A layout change reaches every page, so the announce asks for the whole site.
|
|
282
|
+
const outboxRef = firestore.collection('publishOutbox').doc(createResourceUid());
|
|
283
|
+
batch.set(outboxRef, {
|
|
284
|
+
hostId,
|
|
285
|
+
paths: [
|
|
286
|
+
SCREEN_ROOT_PATH
|
|
287
|
+
],
|
|
288
|
+
createdAt: FieldValue.serverTimestamp(),
|
|
289
|
+
attempts: 0,
|
|
290
|
+
entireHost: true
|
|
291
|
+
});
|
|
292
|
+
await batch.commit();
|
|
293
|
+
const dropped = await dropCache({
|
|
294
|
+
hostIds: [
|
|
295
|
+
hostId
|
|
296
|
+
],
|
|
297
|
+
reason: 'guided AI site start linked its blog'
|
|
298
|
+
});
|
|
299
|
+
if (dropped.complete) await outboxRef.delete().catch(()=>undefined);
|
|
300
|
+
return true;
|
|
301
|
+
}
|
|
176
302
|
/**
|
|
177
303
|
* A retry's publish merged into the start's first (AGL-3730): the pages it
|
|
178
304
|
* put live join the published list, a page it published leaves the drafts,
|
|
@@ -342,6 +468,14 @@ function navEntriesOf(outputs) {
|
|
|
342
468
|
} else if (placeholder && entries[placeholder]) {
|
|
343
469
|
hostUpdates['defaultHomeScreenId'] = FieldValue.delete();
|
|
344
470
|
}
|
|
471
|
+
// The site's language, from its plan (AGL-3750): every page's `<html lang>`
|
|
472
|
+
// reads it, so the announce below asks for the whole site.
|
|
473
|
+
const language = aiSiteLanguageUpdates({
|
|
474
|
+
locales: host.get('locales'),
|
|
475
|
+
defaultLocale: host.get('defaultLocale')
|
|
476
|
+
}, input.language);
|
|
477
|
+
if (language) Object.assign(hostUpdates, language);
|
|
478
|
+
const entireHost = layoutWrites.length > 0 || language !== null;
|
|
345
479
|
batch.update(hostRef, hostUpdates);
|
|
346
480
|
for (const page of accepted){
|
|
347
481
|
batch.set(hostRef.collection('screens').doc(page.id), {
|
|
@@ -370,7 +504,7 @@ function navEntriesOf(outputs) {
|
|
|
370
504
|
],
|
|
371
505
|
createdAt: FieldValue.serverTimestamp(),
|
|
372
506
|
attempts: 0
|
|
373
|
-
},
|
|
507
|
+
}, entireHost ? {
|
|
374
508
|
entireHost: true
|
|
375
509
|
} : {}));
|
|
376
510
|
try {
|
|
@@ -400,7 +534,7 @@ function navEntriesOf(outputs) {
|
|
|
400
534
|
hostId
|
|
401
535
|
],
|
|
402
536
|
reason: 'guided AI site start published'
|
|
403
|
-
},
|
|
537
|
+
}, entireHost ? {} : {
|
|
404
538
|
paths: {
|
|
405
539
|
[hostId]: paths
|
|
406
540
|
}
|
|
@@ -421,9 +555,21 @@ function navEntriesOf(outputs) {
|
|
|
421
555
|
*/ async function aiNavigationLayoutWrite(firestore, input) {
|
|
422
556
|
var _input_storeLinks;
|
|
423
557
|
if (!input.entries.length && !input.retiredHomeId && !input.droppedHrefs.length && !input.storeLinks) return null;
|
|
424
|
-
const
|
|
558
|
+
const layoutId = await aiPagesLayoutId(firestore, input.hostId, input.pageIds);
|
|
559
|
+
if (!layoutId) return null;
|
|
560
|
+
return aiLayoutVersionWrite(firestore, {
|
|
561
|
+
hostId: input.hostId,
|
|
562
|
+
layoutId,
|
|
563
|
+
transform: (nodes)=>aiLayoutWithNavigation(nodes, input),
|
|
564
|
+
storeLinks: (_input_storeLinks = input.storeLinks) != null ? _input_storeLinks : null,
|
|
565
|
+
jobId: input.jobId,
|
|
566
|
+
now: input.now
|
|
567
|
+
});
|
|
568
|
+
}
|
|
569
|
+
/** The one layout the pages render inside, by their current versions; `null` where they do not share one. */ async function aiPagesLayoutId(firestore, hostId, pageIds) {
|
|
570
|
+
const hostRef = firestore.collection('hosts').doc(hostId);
|
|
425
571
|
const layoutIds = new Set();
|
|
426
|
-
for (const id of
|
|
572
|
+
for (const id of pageIds){
|
|
427
573
|
var _ref;
|
|
428
574
|
const screen = await hostRef.collection('screens').doc(id).get();
|
|
429
575
|
const versionId = screen.get('versionId');
|
|
@@ -431,18 +577,9 @@ function navEntriesOf(outputs) {
|
|
|
431
577
|
const layoutId = (_ref = version == null ? void 0 : version.get('layoutId')) != null ? _ref : screen.get('layoutId');
|
|
432
578
|
if (typeof layoutId === 'string' && layoutId) layoutIds.add(layoutId);
|
|
433
579
|
}
|
|
434
|
-
|
|
435
|
-
const [layoutId] = [
|
|
580
|
+
return layoutIds.size === 1 ? [
|
|
436
581
|
...layoutIds
|
|
437
|
-
];
|
|
438
|
-
return aiLayoutVersionWrite(firestore, {
|
|
439
|
-
hostId: input.hostId,
|
|
440
|
-
layoutId,
|
|
441
|
-
transform: (nodes)=>aiLayoutWithNavigation(nodes, input),
|
|
442
|
-
storeLinks: (_input_storeLinks = input.storeLinks) != null ? _input_storeLinks : null,
|
|
443
|
-
jobId: input.jobId,
|
|
444
|
-
now: input.now
|
|
445
|
-
});
|
|
582
|
+
][0] : null;
|
|
446
583
|
}
|
|
447
584
|
/**
|
|
448
585
|
* The new live version of one layout: `transform` applied to the version
|
|
@@ -451,6 +588,7 @@ function navEntriesOf(outputs) {
|
|
|
451
588
|
* to the live version otherwise; a draft with nothing more to add becomes
|
|
452
589
|
* the live version as it is. `null` when nothing changes.
|
|
453
590
|
*/ async function aiLayoutVersionWrite(firestore, input) {
|
|
591
|
+
var _aiLayoutWithoutFrameHollows, _input_displayName;
|
|
454
592
|
var _input_storeLinks;
|
|
455
593
|
const { layoutId } = input;
|
|
456
594
|
const layoutRef = firestore.collection('hosts').doc(input.hostId).collection('layouts').doc(layoutId);
|
|
@@ -471,6 +609,15 @@ function navEntriesOf(outputs) {
|
|
|
471
609
|
const added = aiLayoutWithStoreLinks(next != null ? next : nodes, links.links, links.screenPaths);
|
|
472
610
|
next = (_added_nodes = added.nodes) != null ? _added_nodes : next;
|
|
473
611
|
}
|
|
612
|
+
// What a publish puts live has no hollow heading, column or menu (AGL-3735).
|
|
613
|
+
next = (_aiLayoutWithoutFrameHollows = aiLayoutWithoutFrameHollows(next != null ? next : nodes)) != null ? _aiLayoutWithoutFrameHollows : next;
|
|
614
|
+
const hollow = aiLayoutFrameHollows(next != null ? next : nodes);
|
|
615
|
+
if (aiLayoutFrameIsHollow(hollow)) {
|
|
616
|
+
console.error('ai site publish: a layout is still hollow after its repair', {
|
|
617
|
+
layoutId,
|
|
618
|
+
hollow: aiLayoutFrameHollowsSaid(hollow)
|
|
619
|
+
});
|
|
620
|
+
}
|
|
474
621
|
if (!next) return fromDraft && draftRef ? {
|
|
475
622
|
layoutRef,
|
|
476
623
|
versionRef: draftRef,
|
|
@@ -485,7 +632,7 @@ function navEntriesOf(outputs) {
|
|
|
485
632
|
version: {
|
|
486
633
|
layoutId,
|
|
487
634
|
hostId: input.hostId,
|
|
488
|
-
displayName: 'Navigation for the new pages',
|
|
635
|
+
displayName: (_input_displayName = input.displayName) != null ? _input_displayName : 'Navigation for the new pages',
|
|
489
636
|
nodes: Buffer.from(packed),
|
|
490
637
|
createdAt: input.now,
|
|
491
638
|
updatedAt: input.now,
|