@aglyn/aglyn 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 +11 -11
- package/src/lib/app-utils/analytics-events.d.ts +12 -2
- package/src/lib/app-utils/analytics-events.js.map +1 -1
- package/src/lib/app-utils/business-profile-values.d.ts +3 -2
- package/src/lib/app-utils/business-profile-values.js +4 -3
- package/src/lib/app-utils/business-profile-values.js.map +1 -1
- package/src/lib/app-utils/docs-help-sections.generated.js +5 -5
- package/src/lib/app-utils/docs-help-sections.generated.js.map +1 -1
- package/src/lib/app-utils/docs-help.generated.d.ts +9 -3
- package/src/lib/app-utils/docs-help.generated.js +22 -1
- package/src/lib/app-utils/docs-help.generated.js.map +1 -1
- package/src/lib/app-utils/docs-index.generated.js +111 -27
- package/src/lib/app-utils/docs-index.generated.js.map +1 -1
- package/src/lib/app-utils/notifications.d.ts +31 -2
- package/src/lib/app-utils/notifications.js +18 -2
- package/src/lib/app-utils/notifications.js.map +1 -1
- package/src/lib/app-utils/site-create-return.d.ts +63 -0
- package/src/lib/app-utils/site-create-return.js +72 -0
- package/src/lib/app-utils/site-create-return.js.map +1 -0
- package/src/lib/app-utils/site-starter-pick.d.ts +51 -0
- package/src/lib/app-utils/site-starter-pick.js +47 -0
- package/src/lib/app-utils/site-starter-pick.js.map +1 -0
- package/src/lib/app-utils/site-styles.d.ts +110 -0
- package/src/lib/app-utils/site-styles.js +126 -0
- package/src/lib/app-utils/site-styles.js.map +1 -0
- package/src/lib/app-utils/site-unavailable.d.ts +96 -0
- package/src/lib/app-utils/site-unavailable.js +80 -0
- package/src/lib/app-utils/site-unavailable.js.map +1 -0
- package/src/lib/app-utils/visitor-upload.d.ts +19 -0
- package/src/lib/app-utils/visitor-upload.js +29 -1
- package/src/lib/app-utils/visitor-upload.js.map +1 -1
- package/src/lib/foundation/definitions/platform.types.d.ts +9 -0
- package/src/lib/foundation/definitions/platform.types.js.map +1 -1
- package/src/lib/plugin-manager/feature-plugins.d.ts +68 -13
- package/src/lib/plugin-manager/feature-plugins.js +16 -9
- package/src/lib/plugin-manager/feature-plugins.js.map +1 -1
- package/src/lib/plugin-manager/plugin-site-starters.d.ts +30 -0
- package/src/lib/plugin-manager/plugin-site-starters.js +19 -0
- package/src/lib/plugin-manager/plugin-site-starters.js.map +1 -1
- package/src/lib/plugin-manager/plugin-site-style-looks.d.ts +43 -0
- package/src/lib/plugin-manager/plugin-site-style-looks.js +30 -0
- package/src/lib/plugin-manager/plugin-site-style-looks.js.map +1 -0
- package/src/lib/plugin-manager/plugin-upload-storage-gate.d.ts +60 -0
- package/src/lib/plugin-manager/plugin-upload-storage-gate.js +32 -0
- package/src/lib/plugin-manager/plugin-upload-storage-gate.js.map +1 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../libs/aglyn/src/lib/app-utils/site-create-return.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 * The query a sites page opens \"Create site\" from, and the way back to it\n * after buying a starter (AGL-3761, AGL-4049).\n *\n * `/{org}/hosts?create=site` opens Create site: the empty console sends a\n * first site there once its workspace exists. A starter bought from \"Choose\n * your starter\" comes back the same way, naming the starter the person picked\n * (`&starter={listingId}`) and how the payment ended (`&purchase=success` or\n * `&purchase=canceled`), so Create site reopens on that pick. The server\n * that opens the payment builds the address from these names, and the sites\n * page reads it with them, so the two cannot disagree.\n */\n\nexport const SITE_CREATE_PARAM = 'create'\nexport const SITE_CREATE_VALUE = 'site'\n/** The starter the person picked before paying for it. */\nexport const SITE_CREATE_STARTER_PARAM = 'starter'\n/** How the payment ended, as the payment page sends the person back. */\nexport const SITE_CREATE_PURCHASE_PARAM = 'purchase'\n\nexport type SiteCreatePurchase = 'success' | 'canceled'\n\n/** A starter Create site reopens on: the person's own pick, and how buying it ended. */\nexport interface SiteCreateStarterReturn {\n listingId: string\n /** `success` once paid, `canceled` when the person came back without paying, `null` when it does not say. */\n purchase: SiteCreatePurchase | null\n}\n\n/** What a sites page's address asks of Create site. */\nexport interface SiteCreateRequest {\n /** `?create=site` is present. */\n asked: boolean\n /** The starter to reopen on, or `null`. */\n starter: SiteCreateStarterReturn | null\n}\n\n/** A listing id as an address may carry one: the marketplace's own id shape. */\nconst LISTING_ID = /^[A-Za-z0-9_-]{1,128}$/\n\n/**\n * The query that reopens Create site on a starter, in one order, for the\n * payment's way back: `create=site&starter={listingId}`, and `purchase` when\n * it is given. `null` for an id no listing can have, so a malformed one is\n * never written into an address.\n */\nexport function siteCreateReturnQuery(\n listingId: string,\n purchase?: SiteCreatePurchase,\n): URLSearchParams | null {\n const id = typeof listingId === 'string' ? listingId.trim() : ''\n if (!LISTING_ID.test(id)) return null\n const params = new URLSearchParams()\n params.set(SITE_CREATE_PARAM, SITE_CREATE_VALUE)\n params.set(SITE_CREATE_STARTER_PARAM, id)\n if (purchase) params.set(SITE_CREATE_PURCHASE_PARAM, purchase)\n return params\n}\n\n/**\n * What an address asks of Create site, read defensively. A starter is read\n * only with `create=site`, and only a well-formed listing id; a `purchase`\n * value other than the two the payment sends is no answer at all.\n */\nexport function readSiteCreateRequest(\n params: { get(name: string): string | null } | null | undefined,\n): SiteCreateRequest {\n const asked = params?.get(SITE_CREATE_PARAM) === SITE_CREATE_VALUE\n if (!asked) return { asked: false, starter: null }\n const listingId = (params?.get(SITE_CREATE_STARTER_PARAM) ?? '').trim()\n if (!LISTING_ID.test(listingId)) return { asked: true, starter: null }\n const purchase = params?.get(SITE_CREATE_PURCHASE_PARAM)\n return {\n asked: true,\n starter: {\n listingId,\n purchase: purchase === 'success' || purchase === 'canceled' ? purchase : null,\n },\n }\n}\n"],"names":["SITE_CREATE_PARAM","SITE_CREATE_VALUE","SITE_CREATE_STARTER_PARAM","SITE_CREATE_PURCHASE_PARAM","LISTING_ID","siteCreateReturnQuery","listingId","purchase","id","trim","test","params","URLSearchParams","set","readSiteCreateRequest","asked","get","starter"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAED;;;;;;;;;;;CAWC,GAED,OAAO,MAAMA,oBAAoB,SAAQ;AACzC,OAAO,MAAMC,oBAAoB,OAAM;AACvC,wDAAwD,GACxD,OAAO,MAAMC,4BAA4B,UAAS;AAClD,sEAAsE,GACtE,OAAO,MAAMC,6BAA6B,WAAU;AAmBpD,8EAA8E,GAC9E,MAAMC,aAAa;AAEnB;;;;;CAKC,GACD,OAAO,SAASC,sBACdC,SAAiB,EACjBC,QAA6B;IAE7B,MAAMC,KAAK,OAAOF,cAAc,WAAWA,UAAUG,IAAI,KAAK;IAC9D,IAAI,CAACL,WAAWM,IAAI,CAACF,KAAK,OAAO;IACjC,MAAMG,SAAS,IAAIC;IACnBD,OAAOE,GAAG,CAACb,mBAAmBC;IAC9BU,OAAOE,GAAG,CAACX,2BAA2BM;IACtC,IAAID,UAAUI,OAAOE,GAAG,CAACV,4BAA4BI;IACrD,OAAOI;AACT;AAEA;;;;CAIC,GACD,OAAO,SAASG,sBACdH,MAA+D;;IAE/D,MAAMI,QAAQJ,CAAAA,0BAAAA,OAAQK,GAAG,CAAChB,wBAAuBC;IACjD,IAAI,CAACc,OAAO,OAAO;QAAEA,OAAO;QAAOE,SAAS;IAAK;IACjD,MAAMX,YAAY,SAACK,0BAAAA,OAAQK,GAAG,CAACd,6CAA8B,IAAIO,IAAI;IACrE,IAAI,CAACL,WAAWM,IAAI,CAACJ,YAAY,OAAO;QAAES,OAAO;QAAME,SAAS;IAAK;IACrE,MAAMV,WAAWI,0BAAAA,OAAQK,GAAG,CAACb;IAC7B,OAAO;QACLY,OAAO;QACPE,SAAS;YACPX;YACAC,UAAUA,aAAa,aAAaA,aAAa,aAAaA,WAAW;QAC3E;IACF;AACF"}
|
|
@@ -0,0 +1,51 @@
|
|
|
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
|
+
import type { SiteStarterSummary } from '../plugin-manager/plugin-site-starters';
|
|
18
|
+
/**
|
|
19
|
+
* A starter picked in "Choose your starter" (AGL-4049), as Create site
|
|
20
|
+
* decides about it: whether a site can be created from it yet, and what the
|
|
21
|
+
* create's refusal of it asks for. Pure, so every surface that offers the
|
|
22
|
+
* picker — the console, the native apps — decides the same way.
|
|
23
|
+
*/
|
|
24
|
+
/**
|
|
25
|
+
* What stands between a pick and Create site: nothing picked (`none`), or a
|
|
26
|
+
* price the workspace has not paid (`purchase`); `null` when the site can be
|
|
27
|
+
* created from it. `owned` is what the surface knows better than the
|
|
28
|
+
* search's own answer (the person just paid, or the create still asked for
|
|
29
|
+
* payment); absent, the summary's `owned` stands.
|
|
30
|
+
*/
|
|
31
|
+
export type SiteStarterPickBlock = 'none' | 'purchase';
|
|
32
|
+
export declare function siteStarterPickBlock(pick: SiteStarterSummary | null | undefined, owned?: boolean): SiteStarterPickBlock | null;
|
|
33
|
+
/** What Create site does with a create that refused the starter it was asked for. */
|
|
34
|
+
export interface SiteStarterPickRefused {
|
|
35
|
+
/** The pick stays: it can still be created from, once bought. */
|
|
36
|
+
keep: boolean;
|
|
37
|
+
/** It is the price that stands in the way, so buying it is offered. */
|
|
38
|
+
purchase: boolean;
|
|
39
|
+
/** The create's own words for why. */
|
|
40
|
+
message: string;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* The create's refusal of THIS pick, or `null` for a refusal about anything
|
|
44
|
+
* else (the name, the address, the plan's site count), which Create site
|
|
45
|
+
* answers as it always has. A refusal of a pick names its listing: a 402 is
|
|
46
|
+
* a price to pay, and the pick stays with "Buy and continue"; anything else
|
|
47
|
+
* (the release not open to the workspace, a starter that is gone, one with
|
|
48
|
+
* more pages than the plan holds, an AI starter before the AI start takes
|
|
49
|
+
* them) clears the pick, with the reason said.
|
|
50
|
+
*/
|
|
51
|
+
export declare function readSiteStarterPickRefusal(status: number, payload: unknown, listingId: string): SiteStarterPickRefused | null;
|
|
@@ -0,0 +1,47 @@
|
|
|
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
|
+
*/ export function siteStarterPickBlock(pick, owned) {
|
|
17
|
+
if (!pick) return 'none';
|
|
18
|
+
if (pick.priceUsd > 0 && !(owned != null ? owned : pick.owned === true)) return 'purchase';
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* The create's refusal of THIS pick, or `null` for a refusal about anything
|
|
23
|
+
* else (the name, the address, the plan's site count), which Create site
|
|
24
|
+
* answers as it always has. A refusal of a pick names its listing: a 402 is
|
|
25
|
+
* a price to pay, and the pick stays with "Buy and continue"; anything else
|
|
26
|
+
* (the release not open to the workspace, a starter that is gone, one with
|
|
27
|
+
* more pages than the plan holds, an AI starter before the AI start takes
|
|
28
|
+
* them) clears the pick, with the reason said.
|
|
29
|
+
*/ export function readSiteStarterPickRefusal(status, payload, listingId) {
|
|
30
|
+
if (!payload || typeof payload !== 'object' || Array.isArray(payload)) return null;
|
|
31
|
+
const body = payload;
|
|
32
|
+
if (!listingId || body['listingId'] !== listingId) return null;
|
|
33
|
+
const error = body['error'];
|
|
34
|
+
const message = typeof error === 'string' && error.trim() ? error.trim() : 'That starter cannot be used.';
|
|
35
|
+
if (status === 402) return {
|
|
36
|
+
keep: true,
|
|
37
|
+
purchase: true,
|
|
38
|
+
message
|
|
39
|
+
};
|
|
40
|
+
return {
|
|
41
|
+
keep: false,
|
|
42
|
+
purchase: false,
|
|
43
|
+
message
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
//# sourceMappingURL=site-starter-pick.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../libs/aglyn/src/lib/app-utils/site-starter-pick.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\nimport type { SiteStarterSummary } from '../plugin-manager/plugin-site-starters'\n\n/**\n * A starter picked in \"Choose your starter\" (AGL-4049), as Create site\n * decides about it: whether a site can be created from it yet, and what the\n * create's refusal of it asks for. Pure, so every surface that offers the\n * picker — the console, the native apps — decides the same way.\n */\n\n/**\n * What stands between a pick and Create site: nothing picked (`none`), or a\n * price the workspace has not paid (`purchase`); `null` when the site can be\n * created from it. `owned` is what the surface knows better than the\n * search's own answer (the person just paid, or the create still asked for\n * payment); absent, the summary's `owned` stands.\n */\nexport type SiteStarterPickBlock = 'none' | 'purchase'\n\nexport function siteStarterPickBlock(\n pick: SiteStarterSummary | null | undefined,\n owned?: boolean,\n): SiteStarterPickBlock | null {\n if (!pick) return 'none'\n if (pick.priceUsd > 0 && !(owned ?? pick.owned === true)) return 'purchase'\n return null\n}\n\n/** What Create site does with a create that refused the starter it was asked for. */\nexport interface SiteStarterPickRefused {\n /** The pick stays: it can still be created from, once bought. */\n keep: boolean\n /** It is the price that stands in the way, so buying it is offered. */\n purchase: boolean\n /** The create's own words for why. */\n message: string\n}\n\n/**\n * The create's refusal of THIS pick, or `null` for a refusal about anything\n * else (the name, the address, the plan's site count), which Create site\n * answers as it always has. A refusal of a pick names its listing: a 402 is\n * a price to pay, and the pick stays with \"Buy and continue\"; anything else\n * (the release not open to the workspace, a starter that is gone, one with\n * more pages than the plan holds, an AI starter before the AI start takes\n * them) clears the pick, with the reason said.\n */\nexport function readSiteStarterPickRefusal(\n status: number,\n payload: unknown,\n listingId: string,\n): SiteStarterPickRefused | null {\n if (!payload || typeof payload !== 'object' || Array.isArray(payload)) return null\n const body = payload as Record<string, unknown>\n if (!listingId || body['listingId'] !== listingId) return null\n const error = body['error']\n const message = typeof error === 'string' && error.trim() ? error.trim() : 'That starter cannot be used.'\n if (status === 402) return { keep: true, purchase: true, message }\n return { keep: false, purchase: false, message }\n}\n"],"names":["siteStarterPickBlock","pick","owned","priceUsd","readSiteStarterPickRefusal","status","payload","listingId","Array","isArray","body","error","message","trim","keep","purchase"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAoBD,OAAO,SAASA,qBACdC,IAA2C,EAC3CC,KAAe;IAEf,IAAI,CAACD,MAAM,OAAO;IAClB,IAAIA,KAAKE,QAAQ,GAAG,KAAK,EAAED,gBAAAA,QAASD,KAAKC,KAAK,KAAK,OAAO,OAAO;IACjE,OAAO;AACT;AAYA;;;;;;;;CAQC,GACD,OAAO,SAASE,2BACdC,MAAc,EACdC,OAAgB,EAChBC,SAAiB;IAEjB,IAAI,CAACD,WAAW,OAAOA,YAAY,YAAYE,MAAMC,OAAO,CAACH,UAAU,OAAO;IAC9E,MAAMI,OAAOJ;IACb,IAAI,CAACC,aAAaG,IAAI,CAAC,YAAY,KAAKH,WAAW,OAAO;IAC1D,MAAMI,QAAQD,IAAI,CAAC,QAAQ;IAC3B,MAAME,UAAU,OAAOD,UAAU,YAAYA,MAAME,IAAI,KAAKF,MAAME,IAAI,KAAK;IAC3E,IAAIR,WAAW,KAAK,OAAO;QAAES,MAAM;QAAMC,UAAU;QAAMH;IAAQ;IACjE,OAAO;QAAEE,MAAM;QAAOC,UAAU;QAAOH;IAAQ;AACjD"}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Aglyn LLC
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/
|
|
17
|
+
/**
|
|
18
|
+
* The styles a new site can start in (AGL-4049), and the record of which one
|
|
19
|
+
* a site was created with.
|
|
20
|
+
*
|
|
21
|
+
* Nothing in "Create site" is chosen for a person: a site is created only
|
|
22
|
+
* once they have picked a style. A style is a kind of site's look — the same
|
|
23
|
+
* 21 the AI start's Style step offers, each with an example home page as its
|
|
24
|
+
* picture — so the starter site and the AI start speak one vocabulary.
|
|
25
|
+
*
|
|
26
|
+
* This module is the LIST: what a person may choose on any surface, the
|
|
27
|
+
* native apps included (the derived-values generator emits it). The LOOK a
|
|
28
|
+
* style gives a site is the AI plugin's, behind the `core.site-style-looks`
|
|
29
|
+
* seam (`plugin-manager/plugin-site-style-looks.ts`); with no plugin
|
|
30
|
+
* answering, a site still starts in the default theme and the choice is
|
|
31
|
+
* still recorded. The AI plugin's own kinds are held to this list, id for id
|
|
32
|
+
* and in order, by `ai-site-kinds.spec.ts`.
|
|
33
|
+
*
|
|
34
|
+
* Pure data and readers, safe for any surface to import.
|
|
35
|
+
*/
|
|
36
|
+
/** Where the console serves each style's picture: `<dir>/<id>.webp`. */
|
|
37
|
+
export declare const SITE_STYLE_PREVIEW_DIR = "/_static/starter/styles";
|
|
38
|
+
/** The width and height every style picture is drawn at. */
|
|
39
|
+
export declare const SITE_STYLE_PREVIEW_SIZE: {
|
|
40
|
+
readonly width: 800;
|
|
41
|
+
readonly height: 800;
|
|
42
|
+
};
|
|
43
|
+
/** One style a site can start in. */
|
|
44
|
+
export interface SiteStyle {
|
|
45
|
+
/** A persisted identifier: the AI start's kind id, stored on the site. */
|
|
46
|
+
id: string;
|
|
47
|
+
/** The card's title. */
|
|
48
|
+
name: string;
|
|
49
|
+
/** One line under it. */
|
|
50
|
+
blurb: string;
|
|
51
|
+
/** The example home page's picture, as a path on the console's origin. */
|
|
52
|
+
preview: string;
|
|
53
|
+
/** What the picture shows, for a reader who cannot see it. */
|
|
54
|
+
alt: string;
|
|
55
|
+
}
|
|
56
|
+
/** Every style, in the order a person is shown them. */
|
|
57
|
+
export declare const SITE_STYLES: readonly SiteStyle[];
|
|
58
|
+
/**
|
|
59
|
+
* "Pick for me": the AI start's style card that lets the answers decide. It
|
|
60
|
+
* is a card a person CLICKS, never a default, and it exists only where
|
|
61
|
+
* something can pick for them (the AI start); the starter site has no such
|
|
62
|
+
* card, so a site created with the starter always names a real style.
|
|
63
|
+
*/
|
|
64
|
+
export declare const SITE_STYLE_AUTO = "auto";
|
|
65
|
+
/** Whether a value names one of the {@link SITE_STYLES}. */
|
|
66
|
+
export declare function isSiteStyleId(value: unknown): value is string;
|
|
67
|
+
/** The style an id names, or `null`. */
|
|
68
|
+
export declare function siteStyleOf(id: unknown): SiteStyle | null;
|
|
69
|
+
/**
|
|
70
|
+
* How a site was started: the starter site (`starter`), the AI start (`ai`),
|
|
71
|
+
* a site brought in from somewhere else (`import`), or a program through the
|
|
72
|
+
* public API (`api`), which keeps the default and chooses no style.
|
|
73
|
+
*/
|
|
74
|
+
export type HostStarterStart = 'starter' | 'ai' | 'import' | 'api';
|
|
75
|
+
export declare const HOST_STARTER_STARTS: readonly HostStarterStart[];
|
|
76
|
+
/**
|
|
77
|
+
* `hosts/{id}.starterChoice` (AGL-4049): what a site was created with, written
|
|
78
|
+
* by the server in the create's own transaction and never by a client, so
|
|
79
|
+
* which styles people choose can be counted, and a site created and then left
|
|
80
|
+
* alone can be told apart from one that was built on.
|
|
81
|
+
*
|
|
82
|
+
* - `kind`: the style id; {@link SITE_STYLE_AUTO} when the AI start's "Pick
|
|
83
|
+
* for me" was chosen; `null` when none was (the API, a seed);
|
|
84
|
+
* - `listingId` / `version`: the marketplace starter picked, or `null`;
|
|
85
|
+
* - `mode`: `base` copies a starter's pages, `ai` writes them for the business.
|
|
86
|
+
*/
|
|
87
|
+
export interface HostStarterChoice {
|
|
88
|
+
listingId: string | null;
|
|
89
|
+
version: string | null;
|
|
90
|
+
kind: string | null;
|
|
91
|
+
mode: 'base' | 'ai';
|
|
92
|
+
start: HostStarterStart;
|
|
93
|
+
}
|
|
94
|
+
/** A choice with its unset parts filled: no listing, no style, `base`. */
|
|
95
|
+
export declare function hostStarterChoice(input: Partial<HostStarterChoice> & {
|
|
96
|
+
start: HostStarterStart;
|
|
97
|
+
}): HostStarterChoice;
|
|
98
|
+
/** A stored or answered choice, read defensively; `null` when it is not one. */
|
|
99
|
+
export declare function readHostStarterChoice(value: unknown): HostStarterChoice | null;
|
|
100
|
+
/**
|
|
101
|
+
* The `host_created` event's parameters for a site's choice: how it was
|
|
102
|
+
* started (`unknown` when the create's answer did not say), its style
|
|
103
|
+
* (`auto` for "Pick for me", `none` for no style) and the starter listing
|
|
104
|
+
* (`none` for none). Ids only, never a name a person typed.
|
|
105
|
+
*/
|
|
106
|
+
export declare function hostCreatedEventParams(choice: HostStarterChoice | null): {
|
|
107
|
+
start: string;
|
|
108
|
+
starter_kind: string;
|
|
109
|
+
starter_listing: string;
|
|
110
|
+
};
|
|
@@ -0,0 +1,126 @@
|
|
|
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
|
+
* The styles a new site can start in (AGL-4049), and the record of which one
|
|
18
|
+
* a site was created with.
|
|
19
|
+
*
|
|
20
|
+
* Nothing in "Create site" is chosen for a person: a site is created only
|
|
21
|
+
* once they have picked a style. A style is a kind of site's look — the same
|
|
22
|
+
* 21 the AI start's Style step offers, each with an example home page as its
|
|
23
|
+
* picture — so the starter site and the AI start speak one vocabulary.
|
|
24
|
+
*
|
|
25
|
+
* This module is the LIST: what a person may choose on any surface, the
|
|
26
|
+
* native apps included (the derived-values generator emits it). The LOOK a
|
|
27
|
+
* style gives a site is the AI plugin's, behind the `core.site-style-looks`
|
|
28
|
+
* seam (`plugin-manager/plugin-site-style-looks.ts`); with no plugin
|
|
29
|
+
* answering, a site still starts in the default theme and the choice is
|
|
30
|
+
* still recorded. The AI plugin's own kinds are held to this list, id for id
|
|
31
|
+
* and in order, by `ai-site-kinds.spec.ts`.
|
|
32
|
+
*
|
|
33
|
+
* Pure data and readers, safe for any surface to import.
|
|
34
|
+
*/ /** Where the console serves each style's picture: `<dir>/<id>.webp`. */ export const SITE_STYLE_PREVIEW_DIR = '/_static/starter/styles';
|
|
35
|
+
/** The width and height every style picture is drawn at. */ export const SITE_STYLE_PREVIEW_SIZE = {
|
|
36
|
+
width: 800,
|
|
37
|
+
height: 800
|
|
38
|
+
};
|
|
39
|
+
const style = (id, name, blurb, alt)=>({
|
|
40
|
+
id,
|
|
41
|
+
name,
|
|
42
|
+
blurb,
|
|
43
|
+
preview: `${SITE_STYLE_PREVIEW_DIR}/${id}.webp`,
|
|
44
|
+
alt
|
|
45
|
+
});
|
|
46
|
+
/** Every style, in the order a person is shown them. */ export const SITE_STYLES = [
|
|
47
|
+
style('business', 'Business & services', 'Say what you do, why choose you, and how to reach you', "A cleaning company's home page: its heading beside a photo of gloved hands wiping a desk, then its services as cards"),
|
|
48
|
+
style('trades', 'Home services & trades', 'Roofers, plumbers, towing, landscaping: bold, direct, built on trust', "A roofer's home page: a bold heading over a full-width photo of a roofer carrying shingles, then roofing services"),
|
|
49
|
+
style('professional', 'Law, finance & consulting', 'Law firms, accountants, advisers: calm, established, credible', "A consulting firm's home page: its heading on a white card over a full-width photo of a team at a planning board"),
|
|
50
|
+
style('wellness', 'Health & wellness', 'Therapists, clinics, dentists, coaches: warm, reassuring, clear', "A therapy practice's home page: half the page a photo of a calm, sunlit room, its heading in the other half, then its sessions"),
|
|
51
|
+
style('restaurant', 'Restaurant & café', 'Warm, photo-led pages for food, drink and a place to visit', "A café's home page: its heading centered over a photo of the owner at the counter, then menu highlights"),
|
|
52
|
+
style('store', 'Online store', 'Product-first pages for things you sell', "A handmade goods shop's home page: its heading beside two overlapping photos of wax seals, then featured products"),
|
|
53
|
+
style('portfolio', 'Portfolio', 'Minimal, image-led pages that put the work first', "A prop stylist's home page: a large heading over a grid of three styled sets"),
|
|
54
|
+
style('studio', 'Design studio & agency', 'Bold type and case studies for creative teams', "A design studio's home page: an oversized heading on black over a wide photo of the team at a brand board"),
|
|
55
|
+
style('photography', 'Photography', 'Galleries first, words second', "A photographer's home page: its heading on black over a gallery of a wedding, a portrait and a maker"),
|
|
56
|
+
style('blog', 'Blog & writing', 'Reading-first pages with a calm serif voice', "A food journal's home page: its heading centered in a narrow column over a wide photo of vegetables on a cutting board"),
|
|
57
|
+
style('events', 'Events & weddings', 'Dates, places and the details guests need', "A festival's home page: two overlapping photos of a lantern-lit night market beside its dates, then the program"),
|
|
58
|
+
style('fitness', 'Fitness & sports', 'Gyms, trainers and studios with energy', "A gym's home page: a bold heading on black beside a photo of rows of dumbbells, then this week's classes"),
|
|
59
|
+
style('yoga', 'Yoga & mindfulness', 'Calm, spacious pages for classes and retreats', "A yoga studio's home page: a quiet centered heading over a wide photo of a class stretching on mats"),
|
|
60
|
+
style('beauty', 'Beauty & salon', 'Salons, barbers, spas and studios with style', "A hair salon's home page: its heading beside two overlapping photos of a stylist at work and the salon's chairs"),
|
|
61
|
+
style('realestate', 'Real estate', 'Agents, brokers and property: polished and local', "A real estate agent's home page: its heading on a white card over a photo of a white house, then new listings"),
|
|
62
|
+
style('education', 'Courses & education', 'Tutors, schools and courses, clear and encouraging', "A tutoring center's home page: a photo of a tutor at the whiteboard beside its heading, then its courses"),
|
|
63
|
+
style('nonprofit', 'Nonprofit & community', 'A cause, its impact and how to help', "A food bank's home page: its heading over a full-width photo of volunteers sorting donations, then the ways to help"),
|
|
64
|
+
style('music', 'Music & bands', 'Artists, bands and DJs, loud and visual', "A band's home page: its name in large type over a photo of a band under stage lights, then its tour dates"),
|
|
65
|
+
style('personal', 'Personal & resume', 'A simple page about you and your work', "A product manager's personal page: a round portrait over her centered introduction, then her experience"),
|
|
66
|
+
style('landing', 'Landing page', 'One page that leads to one action', "A budgeting app's landing page: its pitch centered on a colored band over a photo of a couple planning on a phone"),
|
|
67
|
+
style('coming-soon', 'Coming soon', 'A placeholder that collects interest', "A café's coming soon page: its heading and notify button centered over a photo of the café's coffee shelves")
|
|
68
|
+
];
|
|
69
|
+
/**
|
|
70
|
+
* "Pick for me": the AI start's style card that lets the answers decide. It
|
|
71
|
+
* is a card a person CLICKS, never a default, and it exists only where
|
|
72
|
+
* something can pick for them (the AI start); the starter site has no such
|
|
73
|
+
* card, so a site created with the starter always names a real style.
|
|
74
|
+
*/ export const SITE_STYLE_AUTO = 'auto';
|
|
75
|
+
/** Whether a value names one of the {@link SITE_STYLES}. */ export function isSiteStyleId(value) {
|
|
76
|
+
return typeof value === 'string' && SITE_STYLES.some((entry)=>entry.id === value);
|
|
77
|
+
}
|
|
78
|
+
/** The style an id names, or `null`. */ export function siteStyleOf(id) {
|
|
79
|
+
var _SITE_STYLES_find;
|
|
80
|
+
return (_SITE_STYLES_find = SITE_STYLES.find((entry)=>entry.id === id)) != null ? _SITE_STYLES_find : null;
|
|
81
|
+
}
|
|
82
|
+
export const HOST_STARTER_STARTS = [
|
|
83
|
+
'starter',
|
|
84
|
+
'ai',
|
|
85
|
+
'import',
|
|
86
|
+
'api'
|
|
87
|
+
];
|
|
88
|
+
/** A choice with its unset parts filled: no listing, no style, `base`. */ export function hostStarterChoice(input) {
|
|
89
|
+
var _input_listingId, _input_kind;
|
|
90
|
+
return {
|
|
91
|
+
listingId: (_input_listingId = input.listingId) != null ? _input_listingId : null,
|
|
92
|
+
version: input.version == null ? null : String(input.version),
|
|
93
|
+
kind: (_input_kind = input.kind) != null ? _input_kind : null,
|
|
94
|
+
mode: input.mode === 'ai' ? 'ai' : 'base',
|
|
95
|
+
start: input.start
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
const textOrNull = (value)=>typeof value === 'string' && value.trim() ? value.trim() : null;
|
|
99
|
+
/** A stored or answered choice, read defensively; `null` when it is not one. */ export function readHostStarterChoice(value) {
|
|
100
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)) return null;
|
|
101
|
+
const record = value;
|
|
102
|
+
const start = record['start'];
|
|
103
|
+
if (!HOST_STARTER_STARTS.includes(start)) return null;
|
|
104
|
+
return hostStarterChoice({
|
|
105
|
+
listingId: textOrNull(record['listingId']),
|
|
106
|
+
version: textOrNull(record['version']),
|
|
107
|
+
kind: textOrNull(record['kind']),
|
|
108
|
+
mode: record['mode'] === 'ai' ? 'ai' : 'base',
|
|
109
|
+
start: start
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* The `host_created` event's parameters for a site's choice: how it was
|
|
114
|
+
* started (`unknown` when the create's answer did not say), its style
|
|
115
|
+
* (`auto` for "Pick for me", `none` for no style) and the starter listing
|
|
116
|
+
* (`none` for none). Ids only, never a name a person typed.
|
|
117
|
+
*/ export function hostCreatedEventParams(choice) {
|
|
118
|
+
var _ref, _ref1, _ref2;
|
|
119
|
+
return {
|
|
120
|
+
start: (_ref = choice == null ? void 0 : choice.start) != null ? _ref : 'unknown',
|
|
121
|
+
starter_kind: (_ref1 = choice == null ? void 0 : choice.kind) != null ? _ref1 : 'none',
|
|
122
|
+
starter_listing: (_ref2 = choice == null ? void 0 : choice.listingId) != null ? _ref2 : 'none'
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
//# sourceMappingURL=site-styles.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../libs/aglyn/src/lib/app-utils/site-styles.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 * The styles a new site can start in (AGL-4049), and the record of which one\n * a site was created with.\n *\n * Nothing in \"Create site\" is chosen for a person: a site is created only\n * once they have picked a style. A style is a kind of site's look — the same\n * 21 the AI start's Style step offers, each with an example home page as its\n * picture — so the starter site and the AI start speak one vocabulary.\n *\n * This module is the LIST: what a person may choose on any surface, the\n * native apps included (the derived-values generator emits it). The LOOK a\n * style gives a site is the AI plugin's, behind the `core.site-style-looks`\n * seam (`plugin-manager/plugin-site-style-looks.ts`); with no plugin\n * answering, a site still starts in the default theme and the choice is\n * still recorded. The AI plugin's own kinds are held to this list, id for id\n * and in order, by `ai-site-kinds.spec.ts`.\n *\n * Pure data and readers, safe for any surface to import.\n */\n\n/** Where the console serves each style's picture: `<dir>/<id>.webp`. */\nexport const SITE_STYLE_PREVIEW_DIR = '/_static/starter/styles'\n\n/** The width and height every style picture is drawn at. */\nexport const SITE_STYLE_PREVIEW_SIZE = { width: 800, height: 800 } as const\n\n/** One style a site can start in. */\nexport interface SiteStyle {\n /** A persisted identifier: the AI start's kind id, stored on the site. */\n id: string\n /** The card's title. */\n name: string\n /** One line under it. */\n blurb: string\n /** The example home page's picture, as a path on the console's origin. */\n preview: string\n /** What the picture shows, for a reader who cannot see it. */\n alt: string\n}\n\nconst style = (id: string, name: string, blurb: string, alt: string): SiteStyle => ({\n id,\n name,\n blurb,\n preview: `${SITE_STYLE_PREVIEW_DIR}/${id}.webp`,\n alt,\n})\n\n/** Every style, in the order a person is shown them. */\nexport const SITE_STYLES: readonly SiteStyle[] = [\n style('business', 'Business & services', 'Say what you do, why choose you, and how to reach you', \"A cleaning company's home page: its heading beside a photo of gloved hands wiping a desk, then its services as cards\"),\n style('trades', 'Home services & trades', 'Roofers, plumbers, towing, landscaping: bold, direct, built on trust', \"A roofer's home page: a bold heading over a full-width photo of a roofer carrying shingles, then roofing services\"),\n style('professional', 'Law, finance & consulting', 'Law firms, accountants, advisers: calm, established, credible', \"A consulting firm's home page: its heading on a white card over a full-width photo of a team at a planning board\"),\n style('wellness', 'Health & wellness', 'Therapists, clinics, dentists, coaches: warm, reassuring, clear', \"A therapy practice's home page: half the page a photo of a calm, sunlit room, its heading in the other half, then its sessions\"),\n style('restaurant', 'Restaurant & café', 'Warm, photo-led pages for food, drink and a place to visit', \"A café's home page: its heading centered over a photo of the owner at the counter, then menu highlights\"),\n style('store', 'Online store', 'Product-first pages for things you sell', \"A handmade goods shop's home page: its heading beside two overlapping photos of wax seals, then featured products\"),\n style('portfolio', 'Portfolio', 'Minimal, image-led pages that put the work first', \"A prop stylist's home page: a large heading over a grid of three styled sets\"),\n style('studio', 'Design studio & agency', 'Bold type and case studies for creative teams', \"A design studio's home page: an oversized heading on black over a wide photo of the team at a brand board\"),\n style('photography', 'Photography', 'Galleries first, words second', \"A photographer's home page: its heading on black over a gallery of a wedding, a portrait and a maker\"),\n style('blog', 'Blog & writing', 'Reading-first pages with a calm serif voice', \"A food journal's home page: its heading centered in a narrow column over a wide photo of vegetables on a cutting board\"),\n style('events', 'Events & weddings', 'Dates, places and the details guests need', \"A festival's home page: two overlapping photos of a lantern-lit night market beside its dates, then the program\"),\n style('fitness', 'Fitness & sports', 'Gyms, trainers and studios with energy', \"A gym's home page: a bold heading on black beside a photo of rows of dumbbells, then this week's classes\"),\n style('yoga', 'Yoga & mindfulness', 'Calm, spacious pages for classes and retreats', \"A yoga studio's home page: a quiet centered heading over a wide photo of a class stretching on mats\"),\n style('beauty', 'Beauty & salon', 'Salons, barbers, spas and studios with style', \"A hair salon's home page: its heading beside two overlapping photos of a stylist at work and the salon's chairs\"),\n style('realestate', 'Real estate', 'Agents, brokers and property: polished and local', \"A real estate agent's home page: its heading on a white card over a photo of a white house, then new listings\"),\n style('education', 'Courses & education', 'Tutors, schools and courses, clear and encouraging', \"A tutoring center's home page: a photo of a tutor at the whiteboard beside its heading, then its courses\"),\n style('nonprofit', 'Nonprofit & community', 'A cause, its impact and how to help', \"A food bank's home page: its heading over a full-width photo of volunteers sorting donations, then the ways to help\"),\n style('music', 'Music & bands', 'Artists, bands and DJs, loud and visual', \"A band's home page: its name in large type over a photo of a band under stage lights, then its tour dates\"),\n style('personal', 'Personal & resume', 'A simple page about you and your work', \"A product manager's personal page: a round portrait over her centered introduction, then her experience\"),\n style('landing', 'Landing page', 'One page that leads to one action', \"A budgeting app's landing page: its pitch centered on a colored band over a photo of a couple planning on a phone\"),\n style('coming-soon', 'Coming soon', 'A placeholder that collects interest', \"A café's coming soon page: its heading and notify button centered over a photo of the café's coffee shelves\"),\n]\n\n/**\n * \"Pick for me\": the AI start's style card that lets the answers decide. It\n * is a card a person CLICKS, never a default, and it exists only where\n * something can pick for them (the AI start); the starter site has no such\n * card, so a site created with the starter always names a real style.\n */\nexport const SITE_STYLE_AUTO = 'auto'\n\n/** Whether a value names one of the {@link SITE_STYLES}. */\nexport function isSiteStyleId(value: unknown): value is string {\n return typeof value === 'string' && SITE_STYLES.some((entry) => entry.id === value)\n}\n\n/** The style an id names, or `null`. */\nexport function siteStyleOf(id: unknown): SiteStyle | null {\n return SITE_STYLES.find((entry) => entry.id === id) ?? null\n}\n\n// ── What a site was created with ────────────────────────────────────────────\n\n/**\n * How a site was started: the starter site (`starter`), the AI start (`ai`),\n * a site brought in from somewhere else (`import`), or a program through the\n * public API (`api`), which keeps the default and chooses no style.\n */\nexport type HostStarterStart = 'starter' | 'ai' | 'import' | 'api'\n\nexport const HOST_STARTER_STARTS: readonly HostStarterStart[] = ['starter', 'ai', 'import', 'api']\n\n/**\n * `hosts/{id}.starterChoice` (AGL-4049): what a site was created with, written\n * by the server in the create's own transaction and never by a client, so\n * which styles people choose can be counted, and a site created and then left\n * alone can be told apart from one that was built on.\n *\n * - `kind`: the style id; {@link SITE_STYLE_AUTO} when the AI start's \"Pick\n * for me\" was chosen; `null` when none was (the API, a seed);\n * - `listingId` / `version`: the marketplace starter picked, or `null`;\n * - `mode`: `base` copies a starter's pages, `ai` writes them for the business.\n */\nexport interface HostStarterChoice {\n listingId: string | null\n version: string | null\n kind: string | null\n mode: 'base' | 'ai'\n start: HostStarterStart\n}\n\n/** A choice with its unset parts filled: no listing, no style, `base`. */\nexport function hostStarterChoice(input: Partial<HostStarterChoice> & { start: HostStarterStart }): HostStarterChoice {\n return {\n listingId: input.listingId ?? null,\n version: input.version == null ? null : String(input.version),\n kind: input.kind ?? null,\n mode: input.mode === 'ai' ? 'ai' : 'base',\n start: input.start,\n }\n}\n\nconst textOrNull = (value: unknown): string | null =>\n typeof value === 'string' && value.trim() ? value.trim() : null\n\n/** A stored or answered choice, read defensively; `null` when it is not one. */\nexport function readHostStarterChoice(value: unknown): HostStarterChoice | null {\n if (!value || typeof value !== 'object' || Array.isArray(value)) return null\n const record = value as Record<string, unknown>\n const start = record['start']\n if (!(HOST_STARTER_STARTS as readonly unknown[]).includes(start)) return null\n return hostStarterChoice({\n listingId: textOrNull(record['listingId']),\n version: textOrNull(record['version']),\n kind: textOrNull(record['kind']),\n mode: record['mode'] === 'ai' ? 'ai' : 'base',\n start: start as HostStarterStart,\n })\n}\n\n/**\n * The `host_created` event's parameters for a site's choice: how it was\n * started (`unknown` when the create's answer did not say), its style\n * (`auto` for \"Pick for me\", `none` for no style) and the starter listing\n * (`none` for none). Ids only, never a name a person typed.\n */\nexport function hostCreatedEventParams(choice: HostStarterChoice | null): {\n start: string\n starter_kind: string\n starter_listing: string\n} {\n return {\n start: choice?.start ?? 'unknown',\n starter_kind: choice?.kind ?? 'none',\n starter_listing: choice?.listingId ?? 'none',\n }\n}\n"],"names":["SITE_STYLE_PREVIEW_DIR","SITE_STYLE_PREVIEW_SIZE","width","height","style","id","name","blurb","alt","preview","SITE_STYLES","SITE_STYLE_AUTO","isSiteStyleId","value","some","entry","siteStyleOf","find","HOST_STARTER_STARTS","hostStarterChoice","input","listingId","version","String","kind","mode","start","textOrNull","trim","readHostStarterChoice","Array","isArray","record","includes","hostCreatedEventParams","choice","starter_kind","starter_listing"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAED;;;;;;;;;;;;;;;;;;CAkBC,GAED,sEAAsE,GACtE,OAAO,MAAMA,yBAAyB,0BAAyB;AAE/D,0DAA0D,GAC1D,OAAO,MAAMC,0BAA0B;IAAEC,OAAO;IAAKC,QAAQ;AAAI,EAAU;AAgB3E,MAAMC,QAAQ,CAACC,IAAYC,MAAcC,OAAeC,MAA4B,CAAA;QAClFH;QACAC;QACAC;QACAE,SAAS,GAAGT,uBAAuB,CAAC,EAAEK,GAAG,KAAK,CAAC;QAC/CG;IACF,CAAA;AAEA,sDAAsD,GACtD,OAAO,MAAME,cAAoC;IAC/CN,MAAM,YAAY,uBAAuB,yDAAyD;IAClGA,MAAM,UAAU,0BAA0B,wEAAwE;IAClHA,MAAM,gBAAgB,6BAA6B,iEAAiE;IACpHA,MAAM,YAAY,qBAAqB,mEAAmE;IAC1GA,MAAM,cAAc,qBAAqB,8DAA8D;IACvGA,MAAM,SAAS,gBAAgB,2CAA2C;IAC1EA,MAAM,aAAa,aAAa,oDAAoD;IACpFA,MAAM,UAAU,0BAA0B,iDAAiD;IAC3FA,MAAM,eAAe,eAAe,iCAAiC;IACrEA,MAAM,QAAQ,kBAAkB,+CAA+C;IAC/EA,MAAM,UAAU,qBAAqB,6CAA6C;IAClFA,MAAM,WAAW,oBAAoB,0CAA0C;IAC/EA,MAAM,QAAQ,sBAAsB,iDAAiD;IACrFA,MAAM,UAAU,kBAAkB,gDAAgD;IAClFA,MAAM,cAAc,eAAe,oDAAoD;IACvFA,MAAM,aAAa,uBAAuB,sDAAsD;IAChGA,MAAM,aAAa,yBAAyB,uCAAuC;IACnFA,MAAM,SAAS,iBAAiB,2CAA2C;IAC3EA,MAAM,YAAY,qBAAqB,yCAAyC;IAChFA,MAAM,WAAW,gBAAgB,qCAAqC;IACtEA,MAAM,eAAe,eAAe,wCAAwC;CAC7E,CAAA;AAED;;;;;CAKC,GACD,OAAO,MAAMO,kBAAkB,OAAM;AAErC,0DAA0D,GAC1D,OAAO,SAASC,cAAcC,KAAc;IAC1C,OAAO,OAAOA,UAAU,YAAYH,YAAYI,IAAI,CAAC,CAACC,QAAUA,MAAMV,EAAE,KAAKQ;AAC/E;AAEA,sCAAsC,GACtC,OAAO,SAASG,YAAYX,EAAW;QAC9BK;IAAP,QAAOA,oBAAAA,YAAYO,IAAI,CAAC,CAACF,QAAUA,MAAMV,EAAE,KAAKA,eAAzCK,oBAAgD;AACzD;AAWA,OAAO,MAAMQ,sBAAmD;IAAC;IAAW;IAAM;IAAU;CAAM,CAAA;AAqBlG,wEAAwE,GACxE,OAAO,SAASC,kBAAkBC,KAA+D;QAElFA,kBAELA;IAHR,OAAO;QACLC,SAAS,GAAED,mBAAAA,MAAMC,SAAS,YAAfD,mBAAmB;QAC9BE,SAASF,MAAME,OAAO,IAAI,OAAO,OAAOC,OAAOH,MAAME,OAAO;QAC5DE,IAAI,GAAEJ,cAAAA,MAAMI,IAAI,YAAVJ,cAAc;QACpBK,MAAML,MAAMK,IAAI,KAAK,OAAO,OAAO;QACnCC,OAAON,MAAMM,KAAK;IACpB;AACF;AAEA,MAAMC,aAAa,CAACd,QAClB,OAAOA,UAAU,YAAYA,MAAMe,IAAI,KAAKf,MAAMe,IAAI,KAAK;AAE7D,8EAA8E,GAC9E,OAAO,SAASC,sBAAsBhB,KAAc;IAClD,IAAI,CAACA,SAAS,OAAOA,UAAU,YAAYiB,MAAMC,OAAO,CAAClB,QAAQ,OAAO;IACxE,MAAMmB,SAASnB;IACf,MAAMa,QAAQM,MAAM,CAAC,QAAQ;IAC7B,IAAI,CAAC,AAACd,oBAA2Ce,QAAQ,CAACP,QAAQ,OAAO;IACzE,OAAOP,kBAAkB;QACvBE,WAAWM,WAAWK,MAAM,CAAC,YAAY;QACzCV,SAASK,WAAWK,MAAM,CAAC,UAAU;QACrCR,MAAMG,WAAWK,MAAM,CAAC,OAAO;QAC/BP,MAAMO,MAAM,CAAC,OAAO,KAAK,OAAO,OAAO;QACvCN,OAAOA;IACT;AACF;AAEA;;;;;CAKC,GACD,OAAO,SAASQ,uBAAuBC,MAAgC;;IAKrE,OAAO;QACLT,KAAK,UAAES,0BAAAA,OAAQT,KAAK,mBAAI;QACxBU,YAAY,WAAED,0BAAAA,OAAQX,IAAI,oBAAI;QAC9Ba,eAAe,WAAEF,0BAAAA,OAAQd,SAAS,oBAAI;IACxC;AACF"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Aglyn LLC
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/
|
|
17
|
+
/**
|
|
18
|
+
* The site's 503 answer, sent as a 503 (AGL-4110).
|
|
19
|
+
*
|
|
20
|
+
* Maintenance mode (AGL-131) and preview (AGL-4086) answer a visitor who is
|
|
21
|
+
* not let through with the site's designed 503 page, or the built-in notice,
|
|
22
|
+
* at every address. The body was right and the status was not: every address
|
|
23
|
+
* said `200 OK`, which tells a crawler the notice IS the page. A live site
|
|
24
|
+
* that spent a weekend in maintenance could be re-indexed as "Temporarily
|
|
25
|
+
* unavailable" and drop out of search. `503` with `Retry-After` is the answer
|
|
26
|
+
* that means "this site is briefly down, come back".
|
|
27
|
+
*
|
|
28
|
+
* The body still comes from the ISR-cached catch-all, exactly as before; only
|
|
29
|
+
* the tenant middleware can set the status, because an App Router page has no
|
|
30
|
+
* status lever and the middleware is the one layer that runs ahead of the
|
|
31
|
+
* cache on every request. It asks {@link siteUnavailableForRequest} and
|
|
32
|
+
* rewrites with the status, so a cached page body never decides it.
|
|
33
|
+
*
|
|
34
|
+
* DEPENDENCY-FREE ON PURPOSE, like `site-preview.ts`: the middleware runs on
|
|
35
|
+
* the edge and deep-imports this leaf, so it imports nothing.
|
|
36
|
+
*/
|
|
37
|
+
/**
|
|
38
|
+
* How long a crawler or uptime check is told to wait before asking again, in
|
|
39
|
+
* seconds: an hour.
|
|
40
|
+
*
|
|
41
|
+
* The bandwidth cap's figure (`BANDWIDTH_CAP_RETRY_AFTER_SECONDS`), for the
|
|
42
|
+
* same reason. Both states end the moment the owner flips a switch, and the
|
|
43
|
+
* site is back within about a minute, so no longer value is ever "correct".
|
|
44
|
+
* Too long is wrong in the direction that costs the site: a crawler staying
|
|
45
|
+
* away after the site came back. An hour is short enough to be wrong in the
|
|
46
|
+
* recoverable direction, and long enough that a crawler does not spend its
|
|
47
|
+
* visits re-reading "not yet".
|
|
48
|
+
*/
|
|
49
|
+
export declare const SITE_UNAVAILABLE_RETRY_AFTER_SECONDS = 3600;
|
|
50
|
+
/**
|
|
51
|
+
* Is the site in maintenance mode (AGL-131)?
|
|
52
|
+
*
|
|
53
|
+
* The loader's own test, shared with the verdict the middleware reads, so the
|
|
54
|
+
* status and the body are decided by one predicate: a field the loader reads as
|
|
55
|
+
* "in maintenance" is a field the middleware reads the same way.
|
|
56
|
+
*/
|
|
57
|
+
export declare function isHostInMaintenance(host: {
|
|
58
|
+
maintenance?: unknown;
|
|
59
|
+
} | null | undefined): boolean;
|
|
60
|
+
/** What the middleware knows about a site, from its verdict. */
|
|
61
|
+
export interface SiteUnavailableVerdict {
|
|
62
|
+
/** Maintenance mode is on. */
|
|
63
|
+
maintenance?: boolean;
|
|
64
|
+
/** The WHOLE site is in preview. One page in preview is not this. */
|
|
65
|
+
preview?: boolean;
|
|
66
|
+
}
|
|
67
|
+
/** How the middleware is routing this request. */
|
|
68
|
+
export interface SiteUnavailableRouting {
|
|
69
|
+
/** An entry preview link (`?aglyn_preview=`) is being opened. */
|
|
70
|
+
entryPreview: boolean;
|
|
71
|
+
/**
|
|
72
|
+
* A team cookie sent this request around the cache to the uncached preview
|
|
73
|
+
* route, which shows the team the site.
|
|
74
|
+
*/
|
|
75
|
+
teamPreview: boolean;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Does this page request get the site's 503 answer as an HTTP 503?
|
|
79
|
+
*
|
|
80
|
+
* - **Maintenance: yes, for everyone**, the site's team included. It is the
|
|
81
|
+
* switch that means "nobody", and the loader serves the 503 page to every
|
|
82
|
+
* request, the team's preview route included, so every status says so.
|
|
83
|
+
* - **A site in preview: yes, for the public**, the requests answered from the
|
|
84
|
+
* shared cache. A request carrying a team cookie goes to the uncached
|
|
85
|
+
* preview route instead, which shows the team the whole site.
|
|
86
|
+
* - **An entry preview link: no.** When the site is unavailable its route
|
|
87
|
+
* redirects to the plain address, which answers 503 by the rules above; a
|
|
88
|
+
* 503 set here would only argue with that redirect.
|
|
89
|
+
* - **One page in preview: no.** The public gets the site's 404 there, and the
|
|
90
|
+
* render's own 404 decides that status.
|
|
91
|
+
*
|
|
92
|
+
* Nothing here is a permission. The body is the loader's decision, and a
|
|
93
|
+
* request this answers `false` for is one whose body is already the site, or
|
|
94
|
+
* an answer with a status of its own.
|
|
95
|
+
*/
|
|
96
|
+
export declare function siteUnavailableForRequest(verdict: SiteUnavailableVerdict | null | undefined, routing: SiteUnavailableRouting): boolean;
|
|
@@ -0,0 +1,80 @@
|
|
|
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
|
+
* The site's 503 answer, sent as a 503 (AGL-4110).
|
|
18
|
+
*
|
|
19
|
+
* Maintenance mode (AGL-131) and preview (AGL-4086) answer a visitor who is
|
|
20
|
+
* not let through with the site's designed 503 page, or the built-in notice,
|
|
21
|
+
* at every address. The body was right and the status was not: every address
|
|
22
|
+
* said `200 OK`, which tells a crawler the notice IS the page. A live site
|
|
23
|
+
* that spent a weekend in maintenance could be re-indexed as "Temporarily
|
|
24
|
+
* unavailable" and drop out of search. `503` with `Retry-After` is the answer
|
|
25
|
+
* that means "this site is briefly down, come back".
|
|
26
|
+
*
|
|
27
|
+
* The body still comes from the ISR-cached catch-all, exactly as before; only
|
|
28
|
+
* the tenant middleware can set the status, because an App Router page has no
|
|
29
|
+
* status lever and the middleware is the one layer that runs ahead of the
|
|
30
|
+
* cache on every request. It asks {@link siteUnavailableForRequest} and
|
|
31
|
+
* rewrites with the status, so a cached page body never decides it.
|
|
32
|
+
*
|
|
33
|
+
* DEPENDENCY-FREE ON PURPOSE, like `site-preview.ts`: the middleware runs on
|
|
34
|
+
* the edge and deep-imports this leaf, so it imports nothing.
|
|
35
|
+
*/ /**
|
|
36
|
+
* How long a crawler or uptime check is told to wait before asking again, in
|
|
37
|
+
* seconds: an hour.
|
|
38
|
+
*
|
|
39
|
+
* The bandwidth cap's figure (`BANDWIDTH_CAP_RETRY_AFTER_SECONDS`), for the
|
|
40
|
+
* same reason. Both states end the moment the owner flips a switch, and the
|
|
41
|
+
* site is back within about a minute, so no longer value is ever "correct".
|
|
42
|
+
* Too long is wrong in the direction that costs the site: a crawler staying
|
|
43
|
+
* away after the site came back. An hour is short enough to be wrong in the
|
|
44
|
+
* recoverable direction, and long enough that a crawler does not spend its
|
|
45
|
+
* visits re-reading "not yet".
|
|
46
|
+
*/ export const SITE_UNAVAILABLE_RETRY_AFTER_SECONDS = 3600;
|
|
47
|
+
/**
|
|
48
|
+
* Is the site in maintenance mode (AGL-131)?
|
|
49
|
+
*
|
|
50
|
+
* The loader's own test, shared with the verdict the middleware reads, so the
|
|
51
|
+
* status and the body are decided by one predicate: a field the loader reads as
|
|
52
|
+
* "in maintenance" is a field the middleware reads the same way.
|
|
53
|
+
*/ export function isHostInMaintenance(host) {
|
|
54
|
+
return Boolean(host == null ? void 0 : host.maintenance);
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Does this page request get the site's 503 answer as an HTTP 503?
|
|
58
|
+
*
|
|
59
|
+
* - **Maintenance: yes, for everyone**, the site's team included. It is the
|
|
60
|
+
* switch that means "nobody", and the loader serves the 503 page to every
|
|
61
|
+
* request, the team's preview route included, so every status says so.
|
|
62
|
+
* - **A site in preview: yes, for the public**, the requests answered from the
|
|
63
|
+
* shared cache. A request carrying a team cookie goes to the uncached
|
|
64
|
+
* preview route instead, which shows the team the whole site.
|
|
65
|
+
* - **An entry preview link: no.** When the site is unavailable its route
|
|
66
|
+
* redirects to the plain address, which answers 503 by the rules above; a
|
|
67
|
+
* 503 set here would only argue with that redirect.
|
|
68
|
+
* - **One page in preview: no.** The public gets the site's 404 there, and the
|
|
69
|
+
* render's own 404 decides that status.
|
|
70
|
+
*
|
|
71
|
+
* Nothing here is a permission. The body is the loader's decision, and a
|
|
72
|
+
* request this answers `false` for is one whose body is already the site, or
|
|
73
|
+
* an answer with a status of its own.
|
|
74
|
+
*/ export function siteUnavailableForRequest(verdict, routing) {
|
|
75
|
+
if (!verdict || routing.entryPreview) return false;
|
|
76
|
+
if (verdict.maintenance === true) return true;
|
|
77
|
+
return verdict.preview === true && !routing.teamPreview;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
//# sourceMappingURL=site-unavailable.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../libs/aglyn/src/lib/app-utils/site-unavailable.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 * The site's 503 answer, sent as a 503 (AGL-4110).\n *\n * Maintenance mode (AGL-131) and preview (AGL-4086) answer a visitor who is\n * not let through with the site's designed 503 page, or the built-in notice,\n * at every address. The body was right and the status was not: every address\n * said `200 OK`, which tells a crawler the notice IS the page. A live site\n * that spent a weekend in maintenance could be re-indexed as \"Temporarily\n * unavailable\" and drop out of search. `503` with `Retry-After` is the answer\n * that means \"this site is briefly down, come back\".\n *\n * The body still comes from the ISR-cached catch-all, exactly as before; only\n * the tenant middleware can set the status, because an App Router page has no\n * status lever and the middleware is the one layer that runs ahead of the\n * cache on every request. It asks {@link siteUnavailableForRequest} and\n * rewrites with the status, so a cached page body never decides it.\n *\n * DEPENDENCY-FREE ON PURPOSE, like `site-preview.ts`: the middleware runs on\n * the edge and deep-imports this leaf, so it imports nothing.\n */\n\n/**\n * How long a crawler or uptime check is told to wait before asking again, in\n * seconds: an hour.\n *\n * The bandwidth cap's figure (`BANDWIDTH_CAP_RETRY_AFTER_SECONDS`), for the\n * same reason. Both states end the moment the owner flips a switch, and the\n * site is back within about a minute, so no longer value is ever \"correct\".\n * Too long is wrong in the direction that costs the site: a crawler staying\n * away after the site came back. An hour is short enough to be wrong in the\n * recoverable direction, and long enough that a crawler does not spend its\n * visits re-reading \"not yet\".\n */\nexport const SITE_UNAVAILABLE_RETRY_AFTER_SECONDS = 3600\n\n/**\n * Is the site in maintenance mode (AGL-131)?\n *\n * The loader's own test, shared with the verdict the middleware reads, so the\n * status and the body are decided by one predicate: a field the loader reads as\n * \"in maintenance\" is a field the middleware reads the same way.\n */\nexport function isHostInMaintenance(\n host: { maintenance?: unknown } | null | undefined,\n): boolean {\n return Boolean(host?.maintenance)\n}\n\n/** What the middleware knows about a site, from its verdict. */\nexport interface SiteUnavailableVerdict {\n /** Maintenance mode is on. */\n maintenance?: boolean\n /** The WHOLE site is in preview. One page in preview is not this. */\n preview?: boolean\n}\n\n/** How the middleware is routing this request. */\nexport interface SiteUnavailableRouting {\n /** An entry preview link (`?aglyn_preview=`) is being opened. */\n entryPreview: boolean\n /**\n * A team cookie sent this request around the cache to the uncached preview\n * route, which shows the team the site.\n */\n teamPreview: boolean\n}\n\n/**\n * Does this page request get the site's 503 answer as an HTTP 503?\n *\n * - **Maintenance: yes, for everyone**, the site's team included. It is the\n * switch that means \"nobody\", and the loader serves the 503 page to every\n * request, the team's preview route included, so every status says so.\n * - **A site in preview: yes, for the public**, the requests answered from the\n * shared cache. A request carrying a team cookie goes to the uncached\n * preview route instead, which shows the team the whole site.\n * - **An entry preview link: no.** When the site is unavailable its route\n * redirects to the plain address, which answers 503 by the rules above; a\n * 503 set here would only argue with that redirect.\n * - **One page in preview: no.** The public gets the site's 404 there, and the\n * render's own 404 decides that status.\n *\n * Nothing here is a permission. The body is the loader's decision, and a\n * request this answers `false` for is one whose body is already the site, or\n * an answer with a status of its own.\n */\nexport function siteUnavailableForRequest(\n verdict: SiteUnavailableVerdict | null | undefined,\n routing: SiteUnavailableRouting,\n): boolean {\n if (!verdict || routing.entryPreview) return false\n if (verdict.maintenance === true) return true\n return verdict.preview === true && !routing.teamPreview\n}\n"],"names":["SITE_UNAVAILABLE_RETRY_AFTER_SECONDS","isHostInMaintenance","host","Boolean","maintenance","siteUnavailableForRequest","verdict","routing","entryPreview","preview","teamPreview"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAED;;;;;;;;;;;;;;;;;;;CAmBC,GAED;;;;;;;;;;;CAWC,GACD,OAAO,MAAMA,uCAAuC,KAAI;AAExD;;;;;;CAMC,GACD,OAAO,SAASC,oBACdC,IAAkD;IAElD,OAAOC,QAAQD,wBAAAA,KAAME,WAAW;AAClC;AAqBA;;;;;;;;;;;;;;;;;;CAkBC,GACD,OAAO,SAASC,0BACdC,OAAkD,EAClDC,OAA+B;IAE/B,IAAI,CAACD,WAAWC,QAAQC,YAAY,EAAE,OAAO;IAC7C,IAAIF,QAAQF,WAAW,KAAK,MAAM,OAAO;IACzC,OAAOE,QAAQG,OAAO,KAAK,QAAQ,CAACF,QAAQG,WAAW;AACzD"}
|
|
@@ -145,6 +145,25 @@ export declare function visitorUploadPendingPath(scope: VisitorUploadScope, uplo
|
|
|
145
145
|
export declare function visitorUploadFolder(scope: VisitorUploadScope): string;
|
|
146
146
|
/** Where a checked file is kept: private to the site, with no download token. */
|
|
147
147
|
export declare function visitorUploadFinalPath(scope: VisitorUploadScope, uploadId: string): string;
|
|
148
|
+
/**
|
|
149
|
+
* A kept file counts toward its workspace's storage the way a media library
|
|
150
|
+
* file does. Its bytes are added to the site's storage counter,
|
|
151
|
+
* `hosts/{hostId}/counters/media`, whose `bytes` is the one figure the
|
|
152
|
+
* storage band, the Billing meter, the usage alerts and the invoice all read.
|
|
153
|
+
* So a proof, a customer's file on a quote and a form's file are measured,
|
|
154
|
+
* warned about and billed exactly as a library upload is, and no reader of
|
|
155
|
+
* storage can leave them out.
|
|
156
|
+
*
|
|
157
|
+
* The same counter says how much of `bytes` is these files, in the two fields
|
|
158
|
+
* below. That keeps `count` the number of library files and lets the media
|
|
159
|
+
* library show its own share ({@link mediaLibraryBytes}).
|
|
160
|
+
*/
|
|
161
|
+
export declare const VISITOR_UPLOAD_COUNTER_BYTES = "uploadBytes";
|
|
162
|
+
export declare const VISITOR_UPLOAD_COUNTER_FILES = "uploadCount";
|
|
163
|
+
/** The bytes of kept files a site's storage counter holds, never more than its `bytes`. */
|
|
164
|
+
export declare function visitorUploadCounterBytes(counter: Record<string, unknown> | null | undefined): number;
|
|
165
|
+
/** The media library's own files: the counter's `bytes` less the kept files counted beside them. */
|
|
166
|
+
export declare function mediaLibraryBytes(counter: Record<string, unknown> | null | undefined): number;
|
|
148
167
|
/**
|
|
149
168
|
* The files a browser picked, checked before any is sent: how many, and each
|
|
150
169
|
* one's type and size. `already` is how many the submission holds.
|