@drawnagency/primitives 0.1.104 → 0.1.106
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/dist/auth/cookies.d.ts +21 -1
- package/dist/auth/cookies.d.ts.map +1 -1
- package/dist/auth/index.d.ts +2 -1
- package/dist/auth/index.d.ts.map +1 -1
- package/dist/auth/index.js +3 -1
- package/dist/auth/types.d.ts +28 -0
- package/dist/auth/types.d.ts.map +1 -1
- package/dist/{chunk-PTOLUMGV.js → chunk-4RNF2DRG.js} +1 -0
- package/dist/{chunk-MUTHF2GT.js → chunk-5IZ2KTMU.js} +2 -2
- package/dist/{chunk-LZKVV4K2.js → chunk-6P4CJCXB.js} +7 -1
- package/dist/{chunk-CZLYECHC.js → chunk-AB3XVXI3.js} +4 -4
- package/dist/chunk-B7VBSE5X.js +12 -0
- package/dist/{chunk-BGHWUJFV.js → chunk-BOZUEKWL.js} +107 -171
- package/dist/{chunk-TGNS7D4F.js → chunk-CPTFFLK2.js} +1 -1
- package/dist/{chunk-26ALJO4K.js → chunk-D6TLUVOP.js} +1 -1
- package/dist/{chunk-EM5DFHDZ.js → chunk-GEENI3OC.js} +13 -4
- package/dist/chunk-GGXZZ77Z.js +70 -0
- package/dist/{chunk-EWNDBKYK.js → chunk-LUAI5DWR.js} +1 -1
- package/dist/chunk-NLQ5F3RQ.js +43 -0
- package/dist/{chunk-X4PRBGB3.js → chunk-QLBHERK6.js} +9 -9
- package/dist/{chunk-3COSXTOY.js → chunk-XBYJQ5RS.js} +1 -1
- package/dist/{chunk-CXQWLG6X.js → chunk-Z7VXESB6.js} +18 -18
- package/dist/{chunk-WA6QPDJI.js → chunk-ZHHJVKU7.js} +6 -6
- package/dist/collab/rebase.js +2 -1
- package/dist/components/chat/ChatPanel.d.ts.map +1 -1
- package/dist/components/chat/ChatWidget.d.ts.map +1 -1
- package/dist/components/docfile/DocFileOverlay.d.ts.map +1 -1
- package/dist/components/docfile/DocFilePane.d.ts +4 -3
- package/dist/components/docfile/DocFilePane.d.ts.map +1 -1
- package/dist/components/editor/SectionOrderingModal.d.ts.map +1 -1
- package/dist/components/editor/index.js +8 -7
- package/dist/components/primitives/index.js +7 -6
- package/dist/components/sections/brand-guide.js +8 -7
- package/dist/components/sections/register-schemas.js +13 -12
- package/dist/components/sections/register.js +13 -12
- package/dist/components/shared/Navigation.d.ts +16 -1
- package/dist/components/shared/Navigation.d.ts.map +1 -1
- package/dist/components/shared/SectionSummaryRow.d.ts +24 -0
- package/dist/components/shared/SectionSummaryRow.d.ts.map +1 -0
- package/dist/components/shell/AudienceAddForm.d.ts +4 -1
- package/dist/components/shell/AudienceAddForm.d.ts.map +1 -1
- package/dist/components/shell/AudienceDetailsPanel.d.ts +28 -0
- package/dist/components/shell/AudienceDetailsPanel.d.ts.map +1 -0
- package/dist/components/shell/AudienceRow.d.ts +15 -1
- package/dist/components/shell/AudienceRow.d.ts.map +1 -1
- package/dist/components/shell/CredentialList.d.ts +18 -0
- package/dist/components/shell/CredentialList.d.ts.map +1 -0
- package/dist/components/shell/EditorShell.d.ts.map +1 -1
- package/dist/components/shell/SiteSettingsViewerAccess.d.ts.map +1 -1
- package/dist/components/shell/ViewerLoginForm.d.ts +5 -1
- package/dist/components/shell/ViewerLoginForm.d.ts.map +1 -1
- package/dist/index.js +47 -29
- package/dist/lib/audience-overview.d.ts +53 -0
- package/dist/lib/audience-overview.d.ts.map +1 -0
- package/dist/lib/audience-secret.d.ts +11 -0
- package/dist/lib/audience-secret.d.ts.map +1 -0
- package/dist/lib/audience-secret.js +70 -0
- package/dist/lib/events.d.ts +3 -0
- package/dist/lib/events.d.ts.map +1 -1
- package/dist/lib/index-ops.js +3 -2
- package/dist/lib/index.js +13 -12
- package/dist/lib/nav.d.ts.map +1 -1
- package/dist/lib/thumb-views.d.ts +17 -0
- package/dist/lib/thumb-views.d.ts.map +1 -0
- package/dist/media/index.js +4 -3
- package/dist/schemas/audience.d.ts +29 -0
- package/dist/schemas/audience.d.ts.map +1 -1
- package/dist/schemas/audience.js +24 -0
- package/dist/schemas/auth.d.ts +1 -0
- package/dist/schemas/auth.d.ts.map +1 -1
- package/dist/schemas/auth.js +1 -1
- package/dist/schemas/index.js +28 -12
- package/dist/schemas/site-config.d.ts +1 -1
- package/dist/schemas/site-config.d.ts.map +1 -1
- package/dist/types/database.d.ts +59 -5
- package/dist/types/database.d.ts.map +1 -1
- package/package.json +9 -1
- package/src/auth/cookies.ts +37 -4
- package/src/auth/index.ts +2 -1
- package/src/auth/types.ts +32 -0
- package/src/components/chat/ChatPanel.tsx +4 -2
- package/src/components/chat/ChatWidget.tsx +4 -1
- package/src/components/docfile/DocFileOverlay.tsx +28 -2
- package/src/components/docfile/DocFilePane.tsx +4 -3
- package/src/components/editor/SectionOrderingModal.tsx +8 -73
- package/src/components/shared/Navigation.tsx +113 -7
- package/src/components/shared/SectionSummaryRow.tsx +73 -0
- package/src/components/shell/AudienceAddForm.tsx +18 -9
- package/src/components/shell/AudienceDetailsPanel.tsx +263 -0
- package/src/components/shell/AudienceRow.tsx +55 -13
- package/src/components/shell/CredentialList.tsx +285 -0
- package/src/components/shell/EditorShell.tsx +94 -4
- package/src/components/shell/SiteSettingsViewerAccess.tsx +57 -6
- package/src/components/shell/ViewerLoginForm.tsx +35 -15
- package/src/lib/audience-overview.ts +110 -0
- package/src/lib/audience-secret.ts +99 -0
- package/src/lib/events.ts +3 -0
- package/src/lib/nav.ts +6 -2
- package/src/lib/thumb-views.ts +28 -0
- package/src/schemas/audience.ts +52 -0
- package/src/schemas/auth.ts +6 -0
- package/src/schemas/site-config.ts +1 -1
- package/src/types/database.ts +59 -5
- package/dist/chunk-ZDQ3TT47.js +0 -30
package/dist/auth/cookies.d.ts
CHANGED
|
@@ -5,7 +5,27 @@ export declare const SESSION_MAX_AGE_SECONDS: number;
|
|
|
5
5
|
export declare const AUDIENCE_MAX_AGE_SECONDS: number;
|
|
6
6
|
export declare function signSessionToken(session: Session): Promise<string>;
|
|
7
7
|
export declare function verifySessionToken(token: string): Promise<Session | null>;
|
|
8
|
-
export declare function signAudienceToken(audience: string): Promise<string>;
|
|
8
|
+
export declare function signAudienceToken(audience: string, isDefault?: boolean, username?: string | null): Promise<string>;
|
|
9
|
+
export interface AudienceClaims {
|
|
10
|
+
audience: string;
|
|
11
|
+
/** Is this the site's default audience? Gates the Audience Details page. */
|
|
12
|
+
isDefault: boolean;
|
|
13
|
+
/**
|
|
14
|
+
* The named sign-in used, in credential mode. Null in `.env`/audience mode,
|
|
15
|
+
* and on any cookie issued before credentials shipped. Drives the sidebar's
|
|
16
|
+
* "Logged in as" label and the reveal audit log — NOT any access decision,
|
|
17
|
+
* which stays keyed on the audience.
|
|
18
|
+
*/
|
|
19
|
+
username: string | null;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Full audience claims. The `isDefault` claim exists so a viewer page can gate
|
|
23
|
+
* the Audience Details link without a per-render lookup of the audience list.
|
|
24
|
+
* A cookie issued before the claim shipped reads as `false` — the viewer sees
|
|
25
|
+
* the link after their next login, which is at most AUDIENCE_MAX_AGE_SECONDS
|
|
26
|
+
* away, so no compatibility path is needed.
|
|
27
|
+
*/
|
|
28
|
+
export declare function verifyAudienceClaims(token: string): Promise<AudienceClaims | null>;
|
|
9
29
|
export declare function verifyAudienceToken(token: string): Promise<string | null>;
|
|
10
30
|
export declare function setSessionCookie(cookies: CookieLike, token: string, isProduction: boolean): void;
|
|
11
31
|
//# sourceMappingURL=cookies.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cookies.d.ts","sourceRoot":"","sources":["../../src/auth/cookies.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAGnD,eAAO,MAAM,cAAc,eAAe,CAAC;AAC3C,eAAO,MAAM,eAAe,gBAAgB,CAAC;AAC7C,eAAO,MAAM,uBAAuB,QAAe,CAAC;AAMpD,eAAO,MAAM,wBAAwB,QAAe,CAAC;AAErD,wBAAsB,gBAAgB,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAWxE;AAED,wBAAsB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,CAe/E;AAMD,wBAAsB,iBAAiB,
|
|
1
|
+
{"version":3,"file":"cookies.d.ts","sourceRoot":"","sources":["../../src/auth/cookies.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAGnD,eAAO,MAAM,cAAc,eAAe,CAAC;AAC3C,eAAO,MAAM,eAAe,gBAAgB,CAAC;AAC7C,eAAO,MAAM,uBAAuB,QAAe,CAAC;AAMpD,eAAO,MAAM,wBAAwB,QAAe,CAAC;AAErD,wBAAsB,gBAAgB,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAWxE;AAED,wBAAsB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,CAe/E;AAMD,wBAAsB,iBAAiB,CACrC,QAAQ,EAAE,MAAM,EAChB,SAAS,UAAQ,EACjB,QAAQ,GAAE,MAAM,GAAG,IAAW,GAC7B,OAAO,CAAC,MAAM,CAAC,CAMjB;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,4EAA4E;IAC5E,SAAS,EAAE,OAAO,CAAC;IACnB;;;;;OAKG;IACH,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB;AAED;;;;;;GAMG;AACH,wBAAsB,oBAAoB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,CAcxF;AAED,wBAAsB,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAE/E;AAED,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,UAAU,EACnB,KAAK,EAAE,MAAM,EACb,YAAY,EAAE,OAAO,GACpB,IAAI,CAQN"}
|
package/dist/auth/index.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ export type { Role, Session, SiteUser, Audience, SignInMethod, SignInResult, Tok
|
|
|
2
2
|
export type { UiCapabilities } from "./capabilities";
|
|
3
3
|
export { deriveUiCapabilities } from "./capabilities";
|
|
4
4
|
export { requireSessionSecret, isSameOriginRequest, safeNextPath } from "./security";
|
|
5
|
-
export { signSessionToken, verifySessionToken, signAudienceToken, verifyAudienceToken, setSessionCookie, SESSION_COOKIE, AUDIENCE_COOKIE, SESSION_MAX_AGE_SECONDS, AUDIENCE_MAX_AGE_SECONDS } from "./cookies";
|
|
5
|
+
export { signSessionToken, verifySessionToken, signAudienceToken, verifyAudienceToken, verifyAudienceClaims, setSessionCookie, SESSION_COOKIE, AUDIENCE_COOKIE, SESSION_MAX_AGE_SECONDS, AUDIENCE_MAX_AGE_SECONDS } from "./cookies";
|
|
6
|
+
export type { AudienceClaims } from "./cookies";
|
|
6
7
|
export { LastOwnerError, SessionExpiredError } from "./errors";
|
|
7
8
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/auth/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/auth/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,IAAI,EACJ,OAAO,EACP,QAAQ,EACR,QAAQ,EACR,YAAY,EACZ,YAAY,EACZ,iBAAiB,EACjB,mBAAmB,EACnB,YAAY,EACZ,UAAU,EACV,WAAW,GACZ,MAAM,SAAS,CAAC;AAEjB,YAAY,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AACrD,OAAO,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAEtD,OAAO,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AACrF,OAAO,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,cAAc,EAAE,eAAe,EAAE,uBAAuB,EAAE,wBAAwB,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/auth/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,IAAI,EACJ,OAAO,EACP,QAAQ,EACR,QAAQ,EACR,YAAY,EACZ,YAAY,EACZ,iBAAiB,EACjB,mBAAmB,EACnB,YAAY,EACZ,UAAU,EACV,WAAW,GACZ,MAAM,SAAS,CAAC;AAEjB,YAAY,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AACrD,OAAO,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAEtD,OAAO,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AACrF,OAAO,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,cAAc,EAAE,eAAe,EAAE,uBAAuB,EAAE,wBAAwB,EAAE,MAAM,WAAW,CAAC;AACrO,YAAY,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAC"}
|
package/dist/auth/index.js
CHANGED
|
@@ -9,9 +9,10 @@ import {
|
|
|
9
9
|
setSessionCookie,
|
|
10
10
|
signAudienceToken,
|
|
11
11
|
signSessionToken,
|
|
12
|
+
verifyAudienceClaims,
|
|
12
13
|
verifyAudienceToken,
|
|
13
14
|
verifySessionToken
|
|
14
|
-
} from "../chunk-
|
|
15
|
+
} from "../chunk-GEENI3OC.js";
|
|
15
16
|
import {
|
|
16
17
|
isSameOriginRequest,
|
|
17
18
|
requireSessionSecret,
|
|
@@ -33,6 +34,7 @@ export {
|
|
|
33
34
|
setSessionCookie,
|
|
34
35
|
signAudienceToken,
|
|
35
36
|
signSessionToken,
|
|
37
|
+
verifyAudienceClaims,
|
|
36
38
|
verifyAudienceToken,
|
|
37
39
|
verifySessionToken
|
|
38
40
|
};
|
package/dist/auth/types.d.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
export type { Role, Session, SiteUser, Audience } from "../schemas/auth";
|
|
2
2
|
import type { Role, Session, SiteUser, Audience } from "../schemas/auth";
|
|
3
|
+
export type { ViewerCredential } from "../schemas/audience";
|
|
4
|
+
import type { ViewerCredential } from "../schemas/audience";
|
|
3
5
|
export type SignInMethod = {
|
|
4
6
|
type: "oauth";
|
|
5
7
|
provider: "google" | "github";
|
|
@@ -44,6 +46,32 @@ export interface AuthProvider {
|
|
|
44
46
|
list(): Promise<Audience[]>;
|
|
45
47
|
verify(name: string, password: string): Promise<boolean>;
|
|
46
48
|
get?(name: string): Promise<Audience | null>;
|
|
49
|
+
credentials?: {
|
|
50
|
+
/** Every credential on the site, each carrying the audience it grants. */
|
|
51
|
+
list(): Promise<ViewerCredential[]>;
|
|
52
|
+
/**
|
|
53
|
+
* Authenticate a viewer login. Returns the audience to put in the cookie,
|
|
54
|
+
* or ONE uniform null for both an unknown username and a wrong password —
|
|
55
|
+
* the login page must not become a username oracle.
|
|
56
|
+
*/
|
|
57
|
+
verify(username: string, password: string): Promise<{
|
|
58
|
+
audienceName: string;
|
|
59
|
+
isDefault: boolean;
|
|
60
|
+
} | null>;
|
|
61
|
+
/**
|
|
62
|
+
* Show an existing password. Returns null for "not revealable": no sealed
|
|
63
|
+
* copy (predates the feature, or a writer skipped it), an unopenable seal
|
|
64
|
+
* (rotated SESSION_SECRET), or a seal that no longer matches
|
|
65
|
+
* `password_hash`. That last check is what stops a stale seal being shown
|
|
66
|
+
* as the live password — any implementation MUST verify against the hash
|
|
67
|
+
* before returning.
|
|
68
|
+
*/
|
|
69
|
+
reveal(username: string): Promise<string | null>;
|
|
70
|
+
create(audienceName: string, username: string, label: string | null, password: string): Promise<void>;
|
|
71
|
+
setPassword(username: string, password: string): Promise<void>;
|
|
72
|
+
setLabel(username: string, label: string | null): Promise<void>;
|
|
73
|
+
delete(username: string): Promise<void>;
|
|
74
|
+
};
|
|
47
75
|
manage?: {
|
|
48
76
|
create(displayName: string, color: string | null, password: string): Promise<void>;
|
|
49
77
|
setPassword(name: string, password: string): Promise<void>;
|
package/dist/auth/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/auth/types.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AACzE,OAAO,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/auth/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -21,6 +21,7 @@ var historyRestoreFailedEvent = createEvent("history-restore-failed");
|
|
|
21
21
|
var editorDirtyEvent = createEvent("editor-dirty");
|
|
22
22
|
var siteNavChangeEvent = createEvent("sitenavchange-v2");
|
|
23
23
|
var pageSelectEvent = createEvent("pageselect");
|
|
24
|
+
var audienceDetailsEvent = createEvent("audiencedetailsopen");
|
|
24
25
|
|
|
25
26
|
export {
|
|
26
27
|
createEvent,
|
|
@@ -6,10 +6,10 @@ import {
|
|
|
6
6
|
SettingsIcon,
|
|
7
7
|
useMediaLibrary,
|
|
8
8
|
useResolvedMedia
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-D6TLUVOP.js";
|
|
10
10
|
import {
|
|
11
11
|
rebindImageRef
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-XBYJQ5RS.js";
|
|
13
13
|
import {
|
|
14
14
|
cn
|
|
15
15
|
} from "./chunk-7EOSDFS3.js";
|
|
@@ -18,8 +18,14 @@ var AudienceSchema = z.object({
|
|
|
18
18
|
displayName: z.string(),
|
|
19
19
|
color: z.string().nullable(),
|
|
20
20
|
readonly: z.boolean(),
|
|
21
|
+
/** Some way in exists: a credential in credential mode, an audience-level
|
|
22
|
+
* password in `.env` mode. Consumers that only ask "is this gated?" (admin
|
|
23
|
+
* dashboard, MCP) keep using this and need no knowledge of credentials. */
|
|
21
24
|
hasPassword: z.boolean(),
|
|
22
|
-
isDefault: z.boolean()
|
|
25
|
+
isDefault: z.boolean(),
|
|
26
|
+
/** Named sign-ins pointing at this audience. Always 0 in `.env` mode, which
|
|
27
|
+
* has no credentials — use `hasPassword` there. */
|
|
28
|
+
credentialCount: z.number().int().nonnegative().default(0)
|
|
23
29
|
});
|
|
24
30
|
|
|
25
31
|
export {
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
safeNextPath
|
|
3
|
-
} from "./chunk-S2L3BPLS.js";
|
|
4
1
|
import {
|
|
5
2
|
upgradeLegacySection
|
|
6
3
|
} from "./chunk-5BM2Y3NJ.js";
|
|
4
|
+
import {
|
|
5
|
+
safeNextPath
|
|
6
|
+
} from "./chunk-S2L3BPLS.js";
|
|
7
7
|
import {
|
|
8
8
|
NavEntrySchema
|
|
9
9
|
} from "./chunk-REDDTTGJ.js";
|
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
} from "./chunk-VKAGMEKE.js";
|
|
16
16
|
import {
|
|
17
17
|
IndexSchema
|
|
18
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-BOZUEKWL.js";
|
|
19
19
|
import {
|
|
20
20
|
MAX_BLOCK_DEPTH,
|
|
21
21
|
blockDepth
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// src/schemas/media-grid-options.ts
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
var MediaGridOptionsSchema = z.object({
|
|
4
|
+
square: z.boolean().optional(),
|
|
5
|
+
border: z.boolean().optional(),
|
|
6
|
+
crop: z.boolean().optional(),
|
|
7
|
+
showCaptions: z.boolean().optional()
|
|
8
|
+
}).default({});
|
|
9
|
+
|
|
10
|
+
export {
|
|
11
|
+
MediaGridOptionsSchema
|
|
12
|
+
};
|
|
@@ -1,159 +1,100 @@
|
|
|
1
1
|
import {
|
|
2
2
|
documentOptionsSchema
|
|
3
3
|
} from "./chunk-FM4M4Q2W.js";
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
type: z.literal("heading"),
|
|
9
|
-
text: z.string()
|
|
10
|
-
});
|
|
11
|
-
var TextParagraphLine = z.object({
|
|
12
|
-
type: z.enum(["paragraph", "paragraph_large"]),
|
|
13
|
-
text: z.string()
|
|
14
|
-
});
|
|
15
|
-
var TextLabelValueLine = z.object({
|
|
16
|
-
type: z.literal("label_value"),
|
|
17
|
-
label: z.string(),
|
|
18
|
-
text: z.string()
|
|
19
|
-
});
|
|
20
|
-
var TextListItemLine = z.object({
|
|
21
|
-
type: z.enum(["list_item_unordered", "list_item_ordered"]),
|
|
22
|
-
text: z.string()
|
|
23
|
-
});
|
|
24
|
-
var TextLineSchema = z.discriminatedUnion("type", [
|
|
25
|
-
TextHeadingLine,
|
|
26
|
-
TextParagraphLine,
|
|
27
|
-
TextLabelValueLine,
|
|
28
|
-
TextListItemLine
|
|
29
|
-
]);
|
|
30
|
-
var BaseMediaRef = z.object({
|
|
31
|
-
imageId: z.string().default("").describe("Media-library id of the image/video asset."),
|
|
32
|
-
caption: z.union([z.string(), z.array(z.string())]).optional().describe("Optional caption: a single string, or multiple lines as an array of strings."),
|
|
33
|
-
background: z.string().optional().describe("Optional CSS background color/value shown behind a transparent image."),
|
|
34
|
-
invertFrom: z.string().optional().describe("Optional CSS color; the image inverts when the page background matches it (e.g. for dark-mode logo swaps)."),
|
|
35
|
-
border: z.boolean().optional().describe("When true, draw a border around the media."),
|
|
36
|
-
objectFit: z.enum(["cover", "contain"]).optional().describe("How the image fills its box: 'contain' (fit whole image) or 'cover' (fill and crop).")
|
|
37
|
-
});
|
|
38
|
-
var ImageRef = BaseMediaRef.extend({
|
|
39
|
-
type: z.literal("image")
|
|
40
|
-
});
|
|
41
|
-
var VideoRef = BaseMediaRef.extend({
|
|
42
|
-
type: z.literal("video"),
|
|
43
|
-
poster: z.string().optional().describe("Optional poster-image URL shown before playback starts."),
|
|
44
|
-
autoplay: z.boolean().optional().describe("When true, the video starts playing automatically."),
|
|
45
|
-
loop: z.boolean().optional().describe("When true, the video repeats when it finishes."),
|
|
46
|
-
muted: z.boolean().optional().describe("When true, the video plays without sound.")
|
|
47
|
-
});
|
|
48
|
-
var DoDontImageRef = BaseMediaRef.extend({
|
|
49
|
-
type: z.literal("doDontImage"),
|
|
50
|
-
doDont: z.enum(["do", "dont"]).describe("Whether this is a 'do' (correct) or 'dont' (incorrect) example.")
|
|
51
|
-
});
|
|
52
|
-
var LinkedImageRef = BaseMediaRef.extend({
|
|
53
|
-
type: z.literal("linkedImage"),
|
|
54
|
-
href: z.string().describe("URL the image links to."),
|
|
55
|
-
target: z.string().optional().describe("Link target, e.g. '_self' or '_blank'."),
|
|
56
|
-
linkText: z.string().optional().describe("Optional accessible link text/label.")
|
|
57
|
-
});
|
|
58
|
-
var MediaReferenceSchema = z.discriminatedUnion("type", [
|
|
59
|
-
ImageRef,
|
|
60
|
-
VideoRef,
|
|
61
|
-
DoDontImageRef,
|
|
62
|
-
LinkedImageRef
|
|
63
|
-
]);
|
|
64
|
-
var SingleMediaReferenceSchema = z.discriminatedUnion("type", [ImageRef, VideoRef]);
|
|
65
|
-
var HexColorSchema = z.string().regex(/^#[0-9a-fA-F]{6}$/, "must be a 6-digit hex color");
|
|
66
|
-
var FontNameSchema = z.string().max(120).regex(/^[a-zA-Z0-9 ,'"-]+$/, "contains invalid font-name characters");
|
|
4
|
+
import {
|
|
5
|
+
FontNameSchema,
|
|
6
|
+
HexColorSchema
|
|
7
|
+
} from "./chunk-GGXZZ77Z.js";
|
|
67
8
|
|
|
68
9
|
// src/schemas/media.ts
|
|
69
|
-
import { z
|
|
70
|
-
var VariantSchema =
|
|
71
|
-
width:
|
|
72
|
-
height:
|
|
73
|
-
size:
|
|
10
|
+
import { z } from "zod";
|
|
11
|
+
var VariantSchema = z.object({
|
|
12
|
+
width: z.number().int().positive(),
|
|
13
|
+
height: z.number().int().positive(),
|
|
14
|
+
size: z.number().int().nonnegative()
|
|
74
15
|
});
|
|
75
|
-
var MediaFolderSchema =
|
|
76
|
-
name:
|
|
77
|
-
parentId:
|
|
16
|
+
var MediaFolderSchema = z.object({
|
|
17
|
+
name: z.string().min(1),
|
|
18
|
+
parentId: z.string().nullable()
|
|
78
19
|
// null = root
|
|
79
20
|
});
|
|
80
|
-
var MediaItemSchema =
|
|
81
|
-
id:
|
|
82
|
-
hash:
|
|
83
|
-
kind:
|
|
84
|
-
originalName:
|
|
85
|
-
width:
|
|
86
|
-
height:
|
|
87
|
-
mimeType:
|
|
88
|
-
size:
|
|
89
|
-
folder:
|
|
90
|
-
variants:
|
|
91
|
-
alt:
|
|
21
|
+
var MediaItemSchema = z.object({
|
|
22
|
+
id: z.string(),
|
|
23
|
+
hash: z.string(),
|
|
24
|
+
kind: z.enum(["image", "animated", "video"]),
|
|
25
|
+
originalName: z.string(),
|
|
26
|
+
width: z.number().int().positive(),
|
|
27
|
+
height: z.number().int().positive(),
|
|
28
|
+
mimeType: z.string(),
|
|
29
|
+
size: z.number().int().nonnegative(),
|
|
30
|
+
folder: z.string(),
|
|
31
|
+
variants: z.array(VariantSchema),
|
|
32
|
+
alt: z.string().default(""),
|
|
92
33
|
// Where the original bytes live. "github" = committed to the repo (images,
|
|
93
34
|
// small loops); "assets" = large original in the AssetStore bucket. Legacy
|
|
94
35
|
// manifests have no field — default keeps them on the git path.
|
|
95
|
-
storage:
|
|
36
|
+
storage: z.enum(["github", "assets"]).default("github"),
|
|
96
37
|
// Public CDN URL for assets-backed originals, baked at upload time so
|
|
97
38
|
// resolution needs no env access in the browser or at SSR.
|
|
98
|
-
url:
|
|
39
|
+
url: z.string().optional(),
|
|
99
40
|
// Seconds; videos only. Informational (library UI).
|
|
100
|
-
duration:
|
|
41
|
+
duration: z.number().positive().optional(),
|
|
101
42
|
// Display folder (MediaFolderSchema key). Absent = root/unfiled. NOT the
|
|
102
43
|
// git storage dir — that's `folder` above, which never changes.
|
|
103
|
-
folderId:
|
|
44
|
+
folderId: z.string().optional(),
|
|
104
45
|
// System-generated assets (e.g. the Phase 3 social-preview raster) set this
|
|
105
46
|
// so the media-library UI can exclude them. Absent on all user uploads.
|
|
106
|
-
hidden:
|
|
47
|
+
hidden: z.boolean().optional()
|
|
107
48
|
});
|
|
108
|
-
var ImageManifestSchema =
|
|
109
|
-
images:
|
|
110
|
-
folders:
|
|
49
|
+
var ImageManifestSchema = z.object({
|
|
50
|
+
images: z.record(z.string(), MediaItemSchema),
|
|
51
|
+
folders: z.record(z.string(), MediaFolderSchema).default({})
|
|
111
52
|
});
|
|
112
|
-
var MediaConfigSchema =
|
|
113
|
-
sizes:
|
|
114
|
-
maxFileSize:
|
|
115
|
-
quality:
|
|
53
|
+
var MediaConfigSchema = z.object({
|
|
54
|
+
sizes: z.array(z.number()).default([640, 1080, 1920]),
|
|
55
|
+
maxFileSize: z.number().default(5242880),
|
|
56
|
+
quality: z.number().min(1).max(100).default(85),
|
|
116
57
|
// Per-file cap for bucket-backed video uploads (bytes). The git-path cap is
|
|
117
58
|
// maxFileSize; anything between the two routes to the AssetStore.
|
|
118
|
-
maxAssetSize:
|
|
59
|
+
maxAssetSize: z.number().default(209715200)
|
|
119
60
|
});
|
|
120
61
|
|
|
121
62
|
// src/schemas/site-config.ts
|
|
122
|
-
import { z as
|
|
63
|
+
import { z as z2 } from "zod";
|
|
123
64
|
|
|
124
65
|
// src/lib/corner-radius.ts
|
|
125
66
|
var CORNER_RADIUS_OPTIONS = ["none", "small", "medium", "large"];
|
|
126
67
|
|
|
127
68
|
// src/schemas/site-config.ts
|
|
128
|
-
var StatusSchema =
|
|
69
|
+
var StatusSchema = z2.enum(["draft", "live", "archived", "published"]).transform(
|
|
129
70
|
(val) => val === "published" ? "live" : val
|
|
130
71
|
);
|
|
131
|
-
var SectionMetaSchema =
|
|
132
|
-
type:
|
|
72
|
+
var SectionMetaSchema = z2.object({
|
|
73
|
+
type: z2.string(),
|
|
133
74
|
status: StatusSchema,
|
|
134
|
-
access:
|
|
75
|
+
access: z2.array(z2.string())
|
|
135
76
|
});
|
|
136
|
-
var RESERVED_SLUGS = ["edit", "api", "login", "set-password", "404", "present", "print"];
|
|
77
|
+
var RESERVED_SLUGS = ["edit", "api", "login", "set-password", "404", "present", "print", "audiences"];
|
|
137
78
|
var PARSE_REJECTED_SLUGS = ["edit", "api", "login", "set-password", "404"];
|
|
138
|
-
var PageStatusSchema =
|
|
139
|
-
var PageSchema =
|
|
140
|
-
id:
|
|
141
|
-
title:
|
|
142
|
-
slug:
|
|
143
|
-
isHome:
|
|
144
|
-
showInNav:
|
|
79
|
+
var PageStatusSchema = z2.enum(["live", "archived"]);
|
|
80
|
+
var PageSchema = z2.object({
|
|
81
|
+
id: z2.string().min(1),
|
|
82
|
+
title: z2.string(),
|
|
83
|
+
slug: z2.string(),
|
|
84
|
+
isHome: z2.boolean(),
|
|
85
|
+
showInNav: z2.boolean(),
|
|
145
86
|
status: PageStatusSchema,
|
|
146
|
-
access:
|
|
147
|
-
order:
|
|
87
|
+
access: z2.array(z2.string()),
|
|
88
|
+
order: z2.array(z2.string()),
|
|
148
89
|
document: documentOptionsSchema.optional()
|
|
149
90
|
});
|
|
150
91
|
var SLUG_RE = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
151
|
-
var RawIndexSchema =
|
|
152
|
-
siteId:
|
|
153
|
-
order:
|
|
154
|
-
pages:
|
|
155
|
-
sections:
|
|
156
|
-
lastModified:
|
|
92
|
+
var RawIndexSchema = z2.object({
|
|
93
|
+
siteId: z2.string(),
|
|
94
|
+
order: z2.array(z2.string()).optional(),
|
|
95
|
+
pages: z2.array(PageSchema).optional(),
|
|
96
|
+
sections: z2.record(z2.string(), SectionMetaSchema),
|
|
97
|
+
lastModified: z2.string().nullable().optional()
|
|
157
98
|
});
|
|
158
99
|
function normalizeRawIndex(data) {
|
|
159
100
|
if (data.pages && data.pages.length > 0) {
|
|
@@ -183,34 +124,34 @@ function normalizeRawIndex(data) {
|
|
|
183
124
|
lastModified: data.lastModified ?? null
|
|
184
125
|
};
|
|
185
126
|
}
|
|
186
|
-
var CanonicalIndexSchema =
|
|
187
|
-
siteId:
|
|
188
|
-
pages:
|
|
189
|
-
sections:
|
|
190
|
-
lastModified:
|
|
127
|
+
var CanonicalIndexSchema = z2.object({
|
|
128
|
+
siteId: z2.string(),
|
|
129
|
+
pages: z2.array(PageSchema),
|
|
130
|
+
sections: z2.record(z2.string(), SectionMetaSchema),
|
|
131
|
+
lastModified: z2.string().nullable().optional()
|
|
191
132
|
}).superRefine((data, ctx) => {
|
|
192
133
|
const homes = data.pages.filter((p) => p.isHome);
|
|
193
134
|
if (homes.length !== 1) {
|
|
194
|
-
ctx.addIssue({ code:
|
|
135
|
+
ctx.addIssue({ code: z2.ZodIssueCode.custom, message: "Exactly one page must be the home page" });
|
|
195
136
|
}
|
|
196
137
|
if (homes[0]?.status === "archived") {
|
|
197
|
-
ctx.addIssue({ code:
|
|
138
|
+
ctx.addIssue({ code: z2.ZodIssueCode.custom, message: "The home page cannot be archived" });
|
|
198
139
|
}
|
|
199
140
|
if (homes[0] && homes[0].slug !== "") {
|
|
200
|
-
ctx.addIssue({ code:
|
|
141
|
+
ctx.addIssue({ code: z2.ZodIssueCode.custom, message: "The home page slug must be empty" });
|
|
201
142
|
}
|
|
202
143
|
const seenSlugs = /* @__PURE__ */ new Set();
|
|
203
144
|
for (const p of data.pages) {
|
|
204
145
|
if (!p.isHome) {
|
|
205
146
|
if (!SLUG_RE.test(p.slug)) {
|
|
206
|
-
ctx.addIssue({ code:
|
|
147
|
+
ctx.addIssue({ code: z2.ZodIssueCode.custom, message: `Invalid slug "${p.slug}"` });
|
|
207
148
|
}
|
|
208
149
|
if (PARSE_REJECTED_SLUGS.includes(p.slug)) {
|
|
209
|
-
ctx.addIssue({ code:
|
|
150
|
+
ctx.addIssue({ code: z2.ZodIssueCode.custom, message: `Slug "${p.slug}" is reserved` });
|
|
210
151
|
}
|
|
211
152
|
}
|
|
212
153
|
if (seenSlugs.has(p.slug)) {
|
|
213
|
-
ctx.addIssue({ code:
|
|
154
|
+
ctx.addIssue({ code: z2.ZodIssueCode.custom, message: `Duplicate slug "${p.slug}"` });
|
|
214
155
|
}
|
|
215
156
|
seenSlugs.add(p.slug);
|
|
216
157
|
}
|
|
@@ -225,21 +166,21 @@ var CanonicalIndexSchema = z3.object({
|
|
|
225
166
|
const duplicated = [...counts].filter(([, n]) => n > 1).map(([id]) => id);
|
|
226
167
|
if (duplicated.length > 0) {
|
|
227
168
|
ctx.addIssue({
|
|
228
|
-
code:
|
|
169
|
+
code: z2.ZodIssueCode.custom,
|
|
229
170
|
message: `Section id(s) appear in more than one page order: ${fmtIds(duplicated)}`
|
|
230
171
|
});
|
|
231
172
|
}
|
|
232
173
|
const orderedNotInSections = [...fromPagesSet].filter((id) => !sectionSet.has(id));
|
|
233
174
|
if (orderedNotInSections.length > 0) {
|
|
234
175
|
ctx.addIssue({
|
|
235
|
-
code:
|
|
176
|
+
code: z2.ZodIssueCode.custom,
|
|
236
177
|
message: `Section id(s) in a page order but missing from sections{}: ${fmtIds(orderedNotInSections)}`
|
|
237
178
|
});
|
|
238
179
|
}
|
|
239
180
|
const sectionsNotOrdered = sectionKeys.filter((id) => !fromPagesSet.has(id));
|
|
240
181
|
if (sectionsNotOrdered.length > 0) {
|
|
241
182
|
ctx.addIssue({
|
|
242
|
-
code:
|
|
183
|
+
code: z2.ZodIssueCode.custom,
|
|
243
184
|
message: `Section id(s) in sections{} but not in any page order: ${fmtIds(sectionsNotOrdered)}`
|
|
244
185
|
});
|
|
245
186
|
}
|
|
@@ -248,51 +189,51 @@ var IndexSchema = RawIndexSchema.transform(normalizeRawIndex).pipe(CanonicalInde
|
|
|
248
189
|
function normalizeSiteIndex(raw) {
|
|
249
190
|
return IndexSchema.parse(raw);
|
|
250
191
|
}
|
|
251
|
-
var ChatbotTaskIdSchema =
|
|
192
|
+
var ChatbotTaskIdSchema = z2.string().min(1).max(32).regex(
|
|
252
193
|
/^[a-z0-9](?:[a-z0-9_-]*[a-z0-9])?$/,
|
|
253
194
|
"Task id must be lowercase letters, numbers, dashes, or underscores"
|
|
254
195
|
);
|
|
255
|
-
var ChatbotTaskSchema =
|
|
196
|
+
var ChatbotTaskSchema = z2.object({
|
|
256
197
|
id: ChatbotTaskIdSchema,
|
|
257
|
-
label:
|
|
258
|
-
prompt:
|
|
198
|
+
label: z2.string().min(1).max(60),
|
|
199
|
+
prompt: z2.string().max(4e3),
|
|
259
200
|
// Audience names allowed to see this task; [] = all — same semantics as SectionMeta.access.
|
|
260
|
-
access:
|
|
201
|
+
access: z2.array(z2.string()).default([])
|
|
261
202
|
});
|
|
262
|
-
var ChatbotConfigSchema =
|
|
263
|
-
enabled:
|
|
203
|
+
var ChatbotConfigSchema = z2.object({
|
|
204
|
+
enabled: z2.boolean().default(false),
|
|
264
205
|
// Assistant display name shown in the widget header and used in the system
|
|
265
206
|
// prompt. Blank falls back to "Portal Assistant" (resolveChatbotName).
|
|
266
|
-
name:
|
|
207
|
+
name: z2.string().max(60).default("Portal Assistant"),
|
|
267
208
|
// Per-audience name overrides, keyed by audience name — same inert-when-
|
|
268
209
|
// deselected semantics as audiencePrompts.
|
|
269
|
-
audienceNames:
|
|
210
|
+
audienceNames: z2.record(z2.string(), z2.string().max(60)).default({}),
|
|
270
211
|
// Brand-flavored waiting phrases, shown (with "…" appended) while the
|
|
271
212
|
// assistant streams no text yet. Empty = the widget's "Thinking…" default.
|
|
272
|
-
thinkingPhrases:
|
|
273
|
-
systemPrompt:
|
|
213
|
+
thinkingPhrases: z2.array(z2.string().max(80)).max(30).default([]),
|
|
214
|
+
systemPrompt: z2.string().max(8e3).default(""),
|
|
274
215
|
// Audience names the widget is shown to — strict opt-in: [] = no viewer
|
|
275
216
|
// sees it (editors always can via /edit). Gates: [...slug].astro + /api/chat.
|
|
276
|
-
audiences:
|
|
217
|
+
audiences: z2.array(z2.string()).default([]),
|
|
277
218
|
// Per-audience prompt overlays, keyed by audience name. Appended AFTER the
|
|
278
219
|
// base systemPrompt, and ONLY for requests whose session audience matches
|
|
279
220
|
// (or an editor's explicit test-panel simulation) — enforced in
|
|
280
221
|
// assembleBrandChat. Keys are not validated against the audience list:
|
|
281
222
|
// entries for deselected/renamed audiences are inert (strict opt-in means
|
|
282
223
|
// those audiences cannot chat at all).
|
|
283
|
-
audiencePrompts:
|
|
284
|
-
tasks:
|
|
224
|
+
audiencePrompts: z2.record(z2.string(), z2.string().max(8e3)).default({}),
|
|
225
|
+
tasks: z2.array(ChatbotTaskSchema).max(20).default([])
|
|
285
226
|
}).superRefine((cfg, ctx) => {
|
|
286
227
|
const seen = /* @__PURE__ */ new Set();
|
|
287
228
|
for (const t of cfg.tasks) {
|
|
288
229
|
if (seen.has(t.id)) {
|
|
289
|
-
ctx.addIssue({ code:
|
|
230
|
+
ctx.addIssue({ code: z2.ZodIssueCode.custom, message: `Duplicate task id "${t.id}"` });
|
|
290
231
|
}
|
|
291
232
|
seen.add(t.id);
|
|
292
233
|
}
|
|
293
234
|
});
|
|
294
|
-
var SiteConfigSchema =
|
|
295
|
-
siteName:
|
|
235
|
+
var SiteConfigSchema = z2.object({
|
|
236
|
+
siteName: z2.string().default("Brand Portal"),
|
|
296
237
|
primaryColor: HexColorSchema.default("#009ca6"),
|
|
297
238
|
primaryContrast: HexColorSchema.default("#f0f0f0"),
|
|
298
239
|
// Dark-mode overrides for the brand primary / accent. Only applied when
|
|
@@ -301,28 +242,28 @@ var SiteConfigSchema = z3.object({
|
|
|
301
242
|
// CSS light-dark() function (see lib/theme-vars.ts).
|
|
302
243
|
primaryColorDark: HexColorSchema.nullable().default(null),
|
|
303
244
|
primaryContrastDark: HexColorSchema.nullable().default(null),
|
|
304
|
-
darkMode:
|
|
245
|
+
darkMode: z2.enum(["light", "dark", "optional"]).default("light"),
|
|
305
246
|
// Maps to the --radius-outer design token (see lib/corner-radius.ts);
|
|
306
247
|
// defaults so pre-existing site-config.json files keep parsing.
|
|
307
|
-
cornerRadius:
|
|
248
|
+
cornerRadius: z2.enum(CORNER_RADIUS_OPTIONS).default("medium"),
|
|
308
249
|
headingFont: FontNameSchema.default("system-ui"),
|
|
309
250
|
bodyFont: FontNameSchema.default("system-ui"),
|
|
310
|
-
uppercaseHeadings:
|
|
311
|
-
uppercaseSubheadings:
|
|
312
|
-
uppercaseNavHeadings:
|
|
313
|
-
googleFontsUrl:
|
|
251
|
+
uppercaseHeadings: z2.boolean().default(true),
|
|
252
|
+
uppercaseSubheadings: z2.boolean().default(true),
|
|
253
|
+
uppercaseNavHeadings: z2.boolean().default(true),
|
|
254
|
+
googleFontsUrl: z2.string().refine((url) => url.startsWith("https://fonts.googleapis.com/"), "Must be a Google Fonts URL").nullable().default(null),
|
|
314
255
|
// Favicon stored as a data URL (SVG/PNG, small) so it travels with
|
|
315
256
|
// site-config.json — no media manifest or CDN round-trip needed.
|
|
316
|
-
favicon:
|
|
257
|
+
favicon: z2.string().refine((v) => v.startsWith("data:image/"), "Favicon must be an image data URL").nullable().default(null),
|
|
317
258
|
// Optional site logo, stored as media-library references (so it participates
|
|
318
259
|
// in usage tracking + GC protection, and its resolved URL is reusable for the
|
|
319
260
|
// Phase 3 social-preview image). Every field defaults so pre-existing
|
|
320
261
|
// site-config.json files keep parsing.
|
|
321
|
-
logo:
|
|
322
|
-
light:
|
|
323
|
-
dark:
|
|
324
|
-
invertInDark:
|
|
325
|
-
showInNav:
|
|
262
|
+
logo: z2.object({
|
|
263
|
+
light: z2.object({ imageId: z2.string() }),
|
|
264
|
+
dark: z2.object({ imageId: z2.string() }).nullable().default(null),
|
|
265
|
+
invertInDark: z2.boolean().default(false),
|
|
266
|
+
showInNav: z2.boolean().default(true)
|
|
326
267
|
}).nullable().default(null),
|
|
327
268
|
media: MediaConfigSchema.default(MediaConfigSchema.parse({})),
|
|
328
269
|
// Composed social-preview raster, stored as a media-library reference so it
|
|
@@ -331,17 +272,17 @@ var SiteConfigSchema = z3.object({
|
|
|
331
272
|
// (the /api/media route only serves exact generated-variant widths), so the
|
|
332
273
|
// og:image URL + dimensions are correct. Defaults null so pre-existing
|
|
333
274
|
// configs keep parsing and sites without a preview emit no og:image tags.
|
|
334
|
-
previewImage:
|
|
335
|
-
imageId:
|
|
336
|
-
width:
|
|
337
|
-
height:
|
|
275
|
+
previewImage: z2.object({
|
|
276
|
+
imageId: z2.string(),
|
|
277
|
+
width: z2.number().int().positive(),
|
|
278
|
+
height: z2.number().int().positive(),
|
|
338
279
|
// Compose-logic version that produced this raster. Pre-existing rasters
|
|
339
280
|
// (and manifests written before this field) default to 0, which is below
|
|
340
281
|
// any current PREVIEW_COMPOSE_VERSION, so the editor regenerates them.
|
|
341
|
-
version:
|
|
282
|
+
version: z2.number().int().nonnegative().default(0)
|
|
342
283
|
}).nullable().default(null),
|
|
343
284
|
// Optional site description → og:description + <meta name="description">.
|
|
344
|
-
description:
|
|
285
|
+
description: z2.string().max(300).nullable().default(null),
|
|
345
286
|
// Brand chatbot config (editor-owned; the platform kill switch lives in the
|
|
346
287
|
// sites table, not here). Every field defaults so pre-existing
|
|
347
288
|
// site-config.json files keep parsing.
|
|
@@ -349,11 +290,6 @@ var SiteConfigSchema = z3.object({
|
|
|
349
290
|
});
|
|
350
291
|
|
|
351
292
|
export {
|
|
352
|
-
TextLineSchema,
|
|
353
|
-
MediaReferenceSchema,
|
|
354
|
-
SingleMediaReferenceSchema,
|
|
355
|
-
HexColorSchema,
|
|
356
|
-
FontNameSchema,
|
|
357
293
|
VariantSchema,
|
|
358
294
|
MediaFolderSchema,
|
|
359
295
|
MediaItemSchema,
|