@aglyn/plugins-ai 1.0.0-beta.288 → 1.0.0-beta.290
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.d.ts +3 -2
- package/src/lib/activity/ai-activity-actions.js +3 -0
- package/src/lib/activity/ai-activity-actions.js.map +1 -1
- package/src/lib/components/ai-job-requests.d.ts +2 -0
- package/src/lib/components/ai-job-requests.js +2 -0
- package/src/lib/components/ai-job-requests.js.map +1 -1
- package/src/lib/components/ai-site-build-page.component.js +4 -0
- package/src/lib/components/ai-site-build-page.component.js.map +1 -1
- package/src/lib/components/ai-site-import-job.component.d.ts +6 -1
- package/src/lib/components/ai-site-import-job.component.js +124 -17
- package/src/lib/components/ai-site-import-job.component.js.map +1 -1
- package/src/lib/components/ai-site-import-start.component.d.ts +6 -0
- package/src/lib/components/ai-site-import-start.component.js +18 -4
- package/src/lib/components/ai-site-import-start.component.js.map +1 -1
- package/src/lib/components/ai-site-start-card.component.js +2 -1
- package/src/lib/components/ai-site-start-card.component.js.map +1 -1
- package/src/lib/jobs/ai-image-reads.d.ts +20 -2
- package/src/lib/jobs/ai-image-reads.js +47 -0
- package/src/lib/jobs/ai-image-reads.js.map +1 -1
- package/src/lib/jobs/ai-job-import-step.d.ts +53 -3
- package/src/lib/jobs/ai-job-import-step.js +386 -64
- package/src/lib/jobs/ai-job-import-step.js.map +1 -1
- package/src/lib/jobs/ai-job-layout-language.d.ts +33 -0
- package/src/lib/jobs/ai-job-layout-language.js +75 -1
- package/src/lib/jobs/ai-job-layout-language.js.map +1 -1
- package/src/lib/jobs/ai-job-layout-step.js +8 -3
- package/src/lib/jobs/ai-job-layout-step.js.map +1 -1
- package/src/lib/jobs/ai-job-page-language.d.ts +29 -0
- package/src/lib/jobs/ai-job-page-language.js +178 -2
- package/src/lib/jobs/ai-job-page-language.js.map +1 -1
- package/src/lib/jobs/ai-job-page-step.js +3 -0
- package/src/lib/jobs/ai-job-page-step.js.map +1 -1
- package/src/lib/jobs/ai-site-import-document.d.ts +117 -0
- package/src/lib/jobs/ai-site-import-document.js +710 -0
- package/src/lib/jobs/ai-site-import-document.js.map +1 -0
- package/src/lib/jobs/ai-site-import-look.d.ts +112 -0
- package/src/lib/jobs/ai-site-import-look.js +402 -0
- package/src/lib/jobs/ai-site-import-look.js.map +1 -0
- package/src/lib/jobs/ai-site-import-publish.d.ts +41 -0
- package/src/lib/jobs/ai-site-import-publish.js +92 -0
- package/src/lib/jobs/ai-site-import-publish.js.map +1 -0
- package/src/lib/jobs/ai-theme-brand-inputs.d.ts +27 -2
- package/src/lib/jobs/ai-theme-brand-inputs.js +37 -8
- package/src/lib/jobs/ai-theme-brand-inputs.js.map +1 -1
- package/src/lib/layout-language/ai-layout-frame.d.ts +17 -0
- package/src/lib/layout-language/ai-layout-frame.js +73 -2
- package/src/lib/layout-language/ai-layout-frame.js.map +1 -1
- package/src/lib/layout-language/ai-layout-language.d.ts +43 -0
- package/src/lib/layout-language/ai-layout-language.js +199 -0
- package/src/lib/layout-language/ai-layout-language.js.map +1 -1
- package/src/lib/model/ai-credit-estimate.d.ts +15 -0
- package/src/lib/model/ai-credit-estimate.js +14 -1
- package/src/lib/model/ai-credit-estimate.js.map +1 -1
- package/src/lib/model/ai-jobs.types.d.ts +13 -1
- package/src/lib/model/ai-jobs.types.js.map +1 -1
- package/src/lib/model/ai-site-import-view.d.ts +47 -3
- package/src/lib/model/ai-site-import-view.js +122 -20
- package/src/lib/model/ai-site-import-view.js.map +1 -1
- package/src/lib/model/ai-site-import.d.ts +232 -7
- package/src/lib/model/ai-site-import.js +365 -35
- package/src/lib/model/ai-site-import.js.map +1 -1
- package/src/lib/runtime/ai-doctrine-validators.d.ts +18 -0
- package/src/lib/runtime/ai-doctrine-validators.js +16 -5
- package/src/lib/runtime/ai-doctrine-validators.js.map +1 -1
- package/src/lib/runtime/ai-palette.generated.js +31 -0
- package/src/lib/runtime/ai-palette.generated.js.map +1 -1
- package/src/lib/server/ai-image-reads-route.js +24 -1
- package/src/lib/server/ai-image-reads-route.js.map +1 -1
- package/src/lib/server/ai-jobs-resume.js +7 -1
- package/src/lib/server/ai-jobs-resume.js.map +1 -1
- package/src/lib/site-import/fixtures/aglyn-com-recordings.d.ts +57 -0
- package/src/lib/site-import/fixtures/aglyn-com-recordings.js +172 -0
- package/src/lib/site-import/fixtures/aglyn-com-recordings.js.map +1 -0
- package/src/lib/site-import/site-import-crawl.d.ts +32 -7
- package/src/lib/site-import/site-import-crawl.js +133 -44
- package/src/lib/site-import/site-import-crawl.js.map +1 -1
- package/src/lib/site-import/site-import-edge-server.d.ts +31 -0
- package/src/lib/site-import/site-import-edge-server.js +31 -0
- package/src/lib/site-import/site-import-edge-server.js.map +1 -0
- package/src/lib/site-import/site-import-edge.d.ts +44 -0
- package/src/lib/site-import/site-import-edge.js +108 -0
- package/src/lib/site-import/site-import-edge.js.map +1 -0
- package/src/lib/site-import/site-import-html.d.ts +73 -3
- package/src/lib/site-import/site-import-html.js +332 -45
- package/src/lib/site-import/site-import-html.js.map +1 -1
- package/src/lib/site-import/site-import-images.d.ts +22 -0
- package/src/lib/site-import/site-import-images.js +78 -2
- package/src/lib/site-import/site-import-images.js.map +1 -1
- package/src/lib/site-import/site-import-page.d.ts +44 -2
- package/src/lib/site-import/site-import-page.js +116 -16
- package/src/lib/site-import/site-import-page.js.map +1 -1
|
@@ -0,0 +1,108 @@
|
|
|
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
|
+
* AGLYNBOT THROUGH AGLYN'S OWN EDGE (AGL-4085).
|
|
18
|
+
*
|
|
19
|
+
* The tenant deployment's bot protection answers a client that runs no
|
|
20
|
+
* JavaScript with a 429 challenge page, and AglynBot is such a client. So a
|
|
21
|
+
* site we host, aglyn.com included, could not be brought in: on 2026-10-20 the
|
|
22
|
+
* import read 10 of 121 pages, the ten the store-review bypass happens to
|
|
23
|
+
* admit, and no home page.
|
|
24
|
+
*
|
|
25
|
+
* The edge rule "Site import crawler bypass" (declared in
|
|
26
|
+
* `tools/scripts/lib/firewall-posture.mjs`) lifts that challenge, and nothing
|
|
27
|
+
* else, for a request carrying BOTH this header with the secret AND a
|
|
28
|
+
* user agent starting `AglynBot/`. This module is the only place that holds
|
|
29
|
+
* the secret, and it gives it out for one reason: a request to a hostname this
|
|
30
|
+
* platform serves (`isPlatformServedDomain`: our host records, then the hosting
|
|
31
|
+
* platform's live view). A site anywhere else never sees it.
|
|
32
|
+
*
|
|
33
|
+
* - The secret is `SITE_IMPORT_EDGE_TOKEN`, a server variable on the console,
|
|
34
|
+
* where the crawl runs. Read in the bracket form, so Next never substitutes
|
|
35
|
+
* it into a bundle. Unset, or not shaped like a secret, nothing is sent and
|
|
36
|
+
* nothing is read: the crawler is challenged as it was before.
|
|
37
|
+
* - The decision is per hostname and per request: the fetch asks
|
|
38
|
+
* `headersFor(url)` again on every redirect hop, so a hop to another host
|
|
39
|
+
* carries nothing even where the caller would follow it.
|
|
40
|
+
* - Rotation: a new value in the console's env and the same value in the
|
|
41
|
+
* rule, together. See `apps/docs/docs/operations/firewall-posture.md`.
|
|
42
|
+
*=========================================*/ /** The header the edge rule matches. Lowercase, as the rule declares it. */ export const SITE_IMPORT_EDGE_HEADER = 'x-aglyn-import';
|
|
43
|
+
/** A secret shorter than this is treated as unset: `openssl rand -hex 32` makes 64. */ export const SITE_IMPORT_EDGE_TOKEN_MIN_LENGTH = 32;
|
|
44
|
+
/** Header-safe characters only, so the value can neither break a header nor fail the rule's match. */ const TOKEN_PATTERN = /^[A-Za-z0-9_-]+$/;
|
|
45
|
+
/** Sends nothing anywhere. */ export const NO_SITE_IMPORT_HEADERS = ()=>({});
|
|
46
|
+
/** The edge secret, or null when it is unset or not shaped like one. Never logged. */ export function siteImportEdgeToken(env) {
|
|
47
|
+
var _ref;
|
|
48
|
+
// The direct read is spelled out so the self-host env reference guard sees it.
|
|
49
|
+
const token = String((_ref = env ? env['SITE_IMPORT_EDGE_TOKEN'] : process.env['SITE_IMPORT_EDGE_TOKEN']) != null ? _ref : '').trim();
|
|
50
|
+
if (token.length < SITE_IMPORT_EDGE_TOKEN_MIN_LENGTH || token.length > 256) return null;
|
|
51
|
+
return TOKEN_PATTERN.test(token) ? token : null;
|
|
52
|
+
}
|
|
53
|
+
async function defaultServed(hostname) {
|
|
54
|
+
// Loaded only once a secret is configured, so a crawl that has none (every
|
|
55
|
+
// spec, every self-hosted deployment without the rule) never opens Firestore.
|
|
56
|
+
// By relative path: see `site-import-edge-server.ts`.
|
|
57
|
+
const { isPlatformServedDomain } = await import("./site-import-edge-server.js");
|
|
58
|
+
return isPlatformServedDomain(hostname);
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* The edge header for requests to one hostname: the secret when this platform
|
|
62
|
+
* serves it, else nothing. Never throws.
|
|
63
|
+
*/ export async function siteImportEdgeHeaders(hostname, deps = {}) {
|
|
64
|
+
const token = siteImportEdgeToken(deps.env);
|
|
65
|
+
if (!token) return {};
|
|
66
|
+
const name = String(hostname != null ? hostname : '').trim().toLowerCase();
|
|
67
|
+
if (!name) return {};
|
|
68
|
+
try {
|
|
69
|
+
var _deps_served;
|
|
70
|
+
const served = await ((_deps_served = deps.served) != null ? _deps_served : defaultServed)(name);
|
|
71
|
+
return served ? {
|
|
72
|
+
[SITE_IMPORT_EDGE_HEADER]: token
|
|
73
|
+
} : {};
|
|
74
|
+
} catch (error) {
|
|
75
|
+
console.error('[site-import-edge] could not tell whether the platform serves', name, error);
|
|
76
|
+
return {};
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Per-request headers for a crawl of these origins: each origin's hostname is
|
|
81
|
+
* decided once, and a request is given the header only when it is https on
|
|
82
|
+
* the default port to an origin decided "served". Anything else, a hop to
|
|
83
|
+
* another host included, gets nothing.
|
|
84
|
+
*/ export async function siteImportEdgeHeadersFor(origins, deps = {}) {
|
|
85
|
+
if (!siteImportEdgeToken(deps.env)) return NO_SITE_IMPORT_HEADERS;
|
|
86
|
+
const decided = new Map();
|
|
87
|
+
for (const raw of origins){
|
|
88
|
+
let origin;
|
|
89
|
+
try {
|
|
90
|
+
origin = new URL(raw);
|
|
91
|
+
} catch (unused) {
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
if (!isPlainHttpsOrigin(origin) || decided.has(origin.origin)) continue;
|
|
95
|
+
const headers = await siteImportEdgeHeaders(origin.hostname, deps);
|
|
96
|
+
if (Object.keys(headers).length) decided.set(origin.origin, headers);
|
|
97
|
+
}
|
|
98
|
+
if (!decided.size) return NO_SITE_IMPORT_HEADERS;
|
|
99
|
+
return (url)=>{
|
|
100
|
+
var _decided_get;
|
|
101
|
+
return isPlainHttpsOrigin(url) ? (_decided_get = decided.get(url.origin)) != null ? _decided_get : {} : {};
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
function isPlainHttpsOrigin(url) {
|
|
105
|
+
return url.protocol === 'https:' && (!url.port || url.port === '443') && !url.username && !url.password;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
//# sourceMappingURL=site-import-edge.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/site-import/site-import-edge.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 * AGLYNBOT THROUGH AGLYN'S OWN EDGE (AGL-4085).\n *\n * The tenant deployment's bot protection answers a client that runs no\n * JavaScript with a 429 challenge page, and AglynBot is such a client. So a\n * site we host, aglyn.com included, could not be brought in: on 2026-10-20 the\n * import read 10 of 121 pages, the ten the store-review bypass happens to\n * admit, and no home page.\n *\n * The edge rule \"Site import crawler bypass\" (declared in\n * `tools/scripts/lib/firewall-posture.mjs`) lifts that challenge, and nothing\n * else, for a request carrying BOTH this header with the secret AND a\n * user agent starting `AglynBot/`. This module is the only place that holds\n * the secret, and it gives it out for one reason: a request to a hostname this\n * platform serves (`isPlatformServedDomain`: our host records, then the hosting\n * platform's live view). A site anywhere else never sees it.\n *\n * - The secret is `SITE_IMPORT_EDGE_TOKEN`, a server variable on the console,\n * where the crawl runs. Read in the bracket form, so Next never substitutes\n * it into a bundle. Unset, or not shaped like a secret, nothing is sent and\n * nothing is read: the crawler is challenged as it was before.\n * - The decision is per hostname and per request: the fetch asks\n * `headersFor(url)` again on every redirect hop, so a hop to another host\n * carries nothing even where the caller would follow it.\n * - Rotation: a new value in the console's env and the same value in the\n * rule, together. See `apps/docs/docs/operations/firewall-posture.md`.\n *=========================================*/\n\n/** The header the edge rule matches. Lowercase, as the rule declares it. */\nexport const SITE_IMPORT_EDGE_HEADER = 'x-aglyn-import'\n\n/** A secret shorter than this is treated as unset: `openssl rand -hex 32` makes 64. */\nexport const SITE_IMPORT_EDGE_TOKEN_MIN_LENGTH = 32\n\n/** Header-safe characters only, so the value can neither break a header nor fail the rule's match. */\nconst TOKEN_PATTERN = /^[A-Za-z0-9_-]+$/\n\n/** Extra headers for one request, asked per address. */\nexport type SiteImportHeadersFor = (url: URL) => Readonly<Record<string, string>>\n\n/** Sends nothing anywhere. */\nexport const NO_SITE_IMPORT_HEADERS: SiteImportHeadersFor = () => ({})\n\nexport interface SiteImportEdgeDeps {\n /** Where the secret is read from; `process.env` by default. */\n env?: Readonly<Record<string, string | undefined>>\n /** Whether this platform serves a hostname; `isPlatformServedDomain` by default. */\n served?: (hostname: string) => Promise<boolean>\n}\n\n/** The edge secret, or null when it is unset or not shaped like one. Never logged. */\nexport function siteImportEdgeToken(env?: SiteImportEdgeDeps['env']): string | null {\n // The direct read is spelled out so the self-host env reference guard sees it.\n const token = String((env ? env['SITE_IMPORT_EDGE_TOKEN'] : process.env['SITE_IMPORT_EDGE_TOKEN']) ?? '').trim()\n if (token.length < SITE_IMPORT_EDGE_TOKEN_MIN_LENGTH || token.length > 256) return null\n return TOKEN_PATTERN.test(token) ? token : null\n}\n\nasync function defaultServed(hostname: string): Promise<boolean> {\n // Loaded only once a secret is configured, so a crawl that has none (every\n // spec, every self-hosted deployment without the rule) never opens Firestore.\n // By relative path: see `site-import-edge-server.ts`.\n const { isPlatformServedDomain } = await import('./site-import-edge-server')\n return isPlatformServedDomain(hostname)\n}\n\n/**\n * The edge header for requests to one hostname: the secret when this platform\n * serves it, else nothing. Never throws.\n */\nexport async function siteImportEdgeHeaders(\n hostname: string,\n deps: SiteImportEdgeDeps = {},\n): Promise<Readonly<Record<string, string>>> {\n const token = siteImportEdgeToken(deps.env)\n if (!token) return {}\n const name = String(hostname ?? '').trim().toLowerCase()\n if (!name) return {}\n try {\n const served = await (deps.served ?? defaultServed)(name)\n return served ? { [SITE_IMPORT_EDGE_HEADER]: token } : {}\n } catch (error) {\n console.error('[site-import-edge] could not tell whether the platform serves', name, error)\n return {}\n }\n}\n\n/**\n * Per-request headers for a crawl of these origins: each origin's hostname is\n * decided once, and a request is given the header only when it is https on\n * the default port to an origin decided \"served\". Anything else, a hop to\n * another host included, gets nothing.\n */\nexport async function siteImportEdgeHeadersFor(\n origins: readonly string[],\n deps: SiteImportEdgeDeps = {},\n): Promise<SiteImportHeadersFor> {\n if (!siteImportEdgeToken(deps.env)) return NO_SITE_IMPORT_HEADERS\n const decided = new Map<string, Readonly<Record<string, string>>>()\n for (const raw of origins) {\n let origin: URL\n try {\n origin = new URL(raw)\n } catch {\n continue\n }\n if (!isPlainHttpsOrigin(origin) || decided.has(origin.origin)) continue\n const headers = await siteImportEdgeHeaders(origin.hostname, deps)\n if (Object.keys(headers).length) decided.set(origin.origin, headers)\n }\n if (!decided.size) return NO_SITE_IMPORT_HEADERS\n return (url: URL) => (isPlainHttpsOrigin(url) ? decided.get(url.origin) ?? {} : {})\n}\n\nfunction isPlainHttpsOrigin(url: URL): boolean {\n return url.protocol === 'https:' && (!url.port || url.port === '443') && !url.username && !url.password\n}\n"],"names":["SITE_IMPORT_EDGE_HEADER","SITE_IMPORT_EDGE_TOKEN_MIN_LENGTH","TOKEN_PATTERN","NO_SITE_IMPORT_HEADERS","siteImportEdgeToken","env","token","String","process","trim","length","test","defaultServed","hostname","isPlatformServedDomain","siteImportEdgeHeaders","deps","name","toLowerCase","served","error","console","siteImportEdgeHeadersFor","origins","decided","Map","raw","origin","URL","isPlainHttpsOrigin","has","headers","Object","keys","set","size","url","get","protocol","port","username","password"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAED;;;;;;;;;;;;;;;;;;;;;;;;;;2CA0B2C,GAE3C,0EAA0E,GAC1E,OAAO,MAAMA,0BAA0B,iBAAgB;AAEvD,qFAAqF,GACrF,OAAO,MAAMC,oCAAoC,GAAE;AAEnD,oGAAoG,GACpG,MAAMC,gBAAgB;AAKtB,4BAA4B,GAC5B,OAAO,MAAMC,yBAA+C,IAAO,CAAA,CAAC,CAAA,EAAE;AAStE,oFAAoF,GACpF,OAAO,SAASC,oBAAoBC,GAA+B;QAE3CA;IADtB,+EAA+E;IAC/E,MAAMC,QAAQC,QAAQF,OAAAA,MAAMA,GAAG,CAAC,yBAAyB,GAAGG,QAAQH,GAAG,CAAC,yBAAyB,YAA3EA,OAAgF,IAAII,IAAI;IAC9G,IAAIH,MAAMI,MAAM,GAAGT,qCAAqCK,MAAMI,MAAM,GAAG,KAAK,OAAO;IACnF,OAAOR,cAAcS,IAAI,CAACL,SAASA,QAAQ;AAC7C;AAEA,eAAeM,cAAcC,QAAgB;IAC3C,2EAA2E;IAC3E,8EAA8E;IAC9E,sDAAsD;IACtD,MAAM,EAAEC,sBAAsB,EAAE,GAAG,MAAM,MAAM,CAAC;IAChD,OAAOA,uBAAuBD;AAChC;AAEA;;;CAGC,GACD,OAAO,eAAeE,sBACpBF,QAAgB,EAChBG,OAA2B,CAAC,CAAC;IAE7B,MAAMV,QAAQF,oBAAoBY,KAAKX,GAAG;IAC1C,IAAI,CAACC,OAAO,OAAO,CAAC;IACpB,MAAMW,OAAOV,OAAOM,mBAAAA,WAAY,IAAIJ,IAAI,GAAGS,WAAW;IACtD,IAAI,CAACD,MAAM,OAAO,CAAC;IACnB,IAAI;YACoBD;QAAtB,MAAMG,SAAS,MAAM,EAACH,eAAAA,KAAKG,MAAM,YAAXH,eAAeJ,eAAeK;QACpD,OAAOE,SAAS;YAAE,CAACnB,wBAAwB,EAAEM;QAAM,IAAI,CAAC;IAC1D,EAAE,OAAOc,OAAO;QACdC,QAAQD,KAAK,CAAC,iEAAiEH,MAAMG;QACrF,OAAO,CAAC;IACV;AACF;AAEA;;;;;CAKC,GACD,OAAO,eAAeE,yBACpBC,OAA0B,EAC1BP,OAA2B,CAAC,CAAC;IAE7B,IAAI,CAACZ,oBAAoBY,KAAKX,GAAG,GAAG,OAAOF;IAC3C,MAAMqB,UAAU,IAAIC;IACpB,KAAK,MAAMC,OAAOH,QAAS;QACzB,IAAII;QACJ,IAAI;YACFA,SAAS,IAAIC,IAAIF;QACnB,EAAE,eAAM;YACN;QACF;QACA,IAAI,CAACG,mBAAmBF,WAAWH,QAAQM,GAAG,CAACH,OAAOA,MAAM,GAAG;QAC/D,MAAMI,UAAU,MAAMhB,sBAAsBY,OAAOd,QAAQ,EAAEG;QAC7D,IAAIgB,OAAOC,IAAI,CAACF,SAASrB,MAAM,EAAEc,QAAQU,GAAG,CAACP,OAAOA,MAAM,EAAEI;IAC9D;IACA,IAAI,CAACP,QAAQW,IAAI,EAAE,OAAOhC;IAC1B,OAAO,CAACiC;YAAwCZ;eAA1BK,mBAAmBO,QAAOZ,eAAAA,QAAQa,GAAG,CAACD,IAAIT,MAAM,aAAtBH,eAA2B,CAAC,IAAI,CAAC;;AACnF;AAEA,SAASK,mBAAmBO,GAAQ;IAClC,OAAOA,IAAIE,QAAQ,KAAK,YAAa,CAAA,CAACF,IAAIG,IAAI,IAAIH,IAAIG,IAAI,KAAK,KAAI,KAAM,CAACH,IAAII,QAAQ,IAAI,CAACJ,IAAIK,QAAQ;AACzG"}
|
|
@@ -29,6 +29,19 @@ export type SiteImportBlock = {
|
|
|
29
29
|
url: string;
|
|
30
30
|
alt: string;
|
|
31
31
|
region: SiteImportRegion;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* A link the page shows outside its menus (AGL-4083): `href` is an absolute
|
|
35
|
+
* http(s) address, a `mailto:` or a `tel:`. `inline` when its words are
|
|
36
|
+
* already in the block before it (a link inside a sentence); a link on its
|
|
37
|
+
* own (a button, an email address in a card) is only this block.
|
|
38
|
+
*/
|
|
39
|
+
| {
|
|
40
|
+
kind: 'link';
|
|
41
|
+
text: string;
|
|
42
|
+
href: string;
|
|
43
|
+
region: SiteImportRegion;
|
|
44
|
+
inline?: true;
|
|
32
45
|
};
|
|
33
46
|
/** Where on the page a block sat: the header and footer carry business details. */
|
|
34
47
|
export type SiteImportRegion = 'header' | 'main' | 'footer';
|
|
@@ -38,6 +51,46 @@ export interface SiteImportImage {
|
|
|
38
51
|
alt: string;
|
|
39
52
|
/** On the site's own origin; otherwise a CDN or a third party. The importer decides. */
|
|
40
53
|
sameSite: boolean;
|
|
54
|
+
/** Where on the page it sat, its menus included (AGL-4083): a header's picture is often the logo. */
|
|
55
|
+
region: SiteImportRegion;
|
|
56
|
+
}
|
|
57
|
+
/** A `<link rel="icon">` or `apple-touch-icon` of the page's head (AGL-4083). */
|
|
58
|
+
export interface SiteImportIcon {
|
|
59
|
+
url: string;
|
|
60
|
+
rel: 'icon' | 'apple-touch-icon';
|
|
61
|
+
/** The larger side its `sizes` names, or `null` for none or `any`. */
|
|
62
|
+
size: number | null;
|
|
63
|
+
/** Its declared type, as written. */
|
|
64
|
+
type: string | null;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* The link to the home page in a page's header (AGL-4083): what its brand is
|
|
68
|
+
* drawn with. `logo` is the first picture inside it; `text` its words, which
|
|
69
|
+
* are the site's name when the header prints one.
|
|
70
|
+
*/
|
|
71
|
+
export interface SiteImportBrandMark {
|
|
72
|
+
logo: {
|
|
73
|
+
url: string;
|
|
74
|
+
alt: string;
|
|
75
|
+
} | null;
|
|
76
|
+
text: string;
|
|
77
|
+
region: SiteImportRegion;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* The page's Organization (or LocalBusiness) structured data (AGL-4083), as
|
|
81
|
+
* written: the site's own statement of its name, address, phone, email and
|
|
82
|
+
* profiles. Every field is the empty string, or an empty list, when absent.
|
|
83
|
+
*/
|
|
84
|
+
export interface SiteImportOrganization {
|
|
85
|
+
name: string;
|
|
86
|
+
description: string;
|
|
87
|
+
url: string;
|
|
88
|
+
logo: string;
|
|
89
|
+
telephone: string;
|
|
90
|
+
email: string;
|
|
91
|
+
/** One line: street, town, region and postal code, country. */
|
|
92
|
+
address: string;
|
|
93
|
+
sameAs: string[];
|
|
41
94
|
}
|
|
42
95
|
export interface SiteImportNavLink {
|
|
43
96
|
text: string;
|
|
@@ -55,6 +108,13 @@ export interface SiteImportExtract {
|
|
|
55
108
|
description: string;
|
|
56
109
|
lang: string | null;
|
|
57
110
|
canonical: string | null;
|
|
111
|
+
/** The share card, `og:image` (or `twitter:image`), as an absolute address (AGL-4083). */
|
|
112
|
+
ogImage: string | null;
|
|
113
|
+
/** The site's own name, `og:site_name` (or `application-name`); empty when absent. */
|
|
114
|
+
siteName: string;
|
|
115
|
+
icons: SiteImportIcon[];
|
|
116
|
+
brand: SiteImportBrandMark | null;
|
|
117
|
+
organization: SiteImportOrganization | null;
|
|
58
118
|
blocks: SiteImportBlock[];
|
|
59
119
|
images: SiteImportImage[];
|
|
60
120
|
navLinks: SiteImportNavLink[];
|
|
@@ -69,13 +129,17 @@ export interface SiteImportExtract {
|
|
|
69
129
|
}
|
|
70
130
|
/** Ceilings that keep one odd page from becoming the whole inventory. */
|
|
71
131
|
export declare const SITE_IMPORT_PAGE_LIMITS: {
|
|
72
|
-
|
|
73
|
-
readonly
|
|
132
|
+
/** A pricing page's plan table runs past 400 (AGL-4083); a wave's read keeps fewer, under its own budget. */
|
|
133
|
+
readonly blocks: 2000;
|
|
134
|
+
/** A legal page's paragraph runs past 2,000 characters. */
|
|
135
|
+
readonly blockChars: 10000;
|
|
74
136
|
readonly images: 100;
|
|
75
137
|
readonly links: 300;
|
|
76
|
-
|
|
138
|
+
/** A mega-menu's entries and the footer's columns together. */
|
|
139
|
+
readonly navLinks: 150;
|
|
77
140
|
readonly forms: 10;
|
|
78
141
|
readonly fieldsPerForm: 30;
|
|
142
|
+
readonly icons: 12;
|
|
79
143
|
};
|
|
80
144
|
/** Character references to characters; an unknown name stays as written. */
|
|
81
145
|
export declare function decodeHtmlEntities(text: string): string;
|
|
@@ -85,6 +149,12 @@ export declare function parseAttributes(source: string): Record<string, string>;
|
|
|
85
149
|
export declare function readMetaValues(html: string, name: string): string[];
|
|
86
150
|
/** `raw` against the page, as an absolute http(s) address without a fragment. */
|
|
87
151
|
export declare function resolveSiteUrl(raw: string | undefined, base: string): URL | null;
|
|
152
|
+
/**
|
|
153
|
+
* Where a link a page shows goes (AGL-4083): an absolute http(s) address
|
|
154
|
+
* without its fragment, a `mailto:` with an address in it, or a `tel:` with
|
|
155
|
+
* a number in it; `null` for anything else (a script, a jump on the page).
|
|
156
|
+
*/
|
|
157
|
+
export declare function resolveSiteLink(raw: string | undefined, base: string): string | null;
|
|
88
158
|
/**
|
|
89
159
|
* The words, structure, pictures and links of one page.
|
|
90
160
|
*
|