@gaulatti/giorgia 0.1.98 → 0.1.99
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/README.md +65 -3
- package/dist/cronkite-manifest.d.ts +51 -0
- package/dist/cronkite-manifest.js +115 -0
- package/dist/cronkite-manifest.json +130 -0
- package/dist/json-schema-formats.d.ts +2 -0
- package/dist/json-schema-formats.js +24 -0
- package/dist/layouts.d.ts +14 -0
- package/dist/layouts.js +13 -0
- package/dist/live-program-page/live-program.css +1 -1
- package/dist/live-program-page/live-program.js +1 -1
- package/dist/manifest-validation.d.ts +10 -0
- package/dist/manifest-validation.js +27 -0
- package/dist/outlet-config.d.ts +0 -1
- package/dist/outlet-config.js +1 -2
- package/dist/renderer.core.d.ts +2 -1
- package/dist/renderer.core.js +2 -1
- package/dist/renderer.d.ts +2 -0
- package/dist/renderer.js +1 -0
- package/dist/renderer.node.js +1 -12
- package/dist/schemas/canonical-document.schema.json +1071 -0
- package/dist/schemas/cronkite-manifest.schema.json +501 -0
- package/dist/schemas/search-index.schema.json +27 -0
- package/dist/schemas/search-manifest.schema.json +34 -0
- package/dist/types/canonical-article.d.ts +7 -254
- package/dist/types/canonical-article.js +21 -242
- package/dist/types/canonical-document-schema.generated.d.ts +1634 -0
- package/dist/types/canonical-document-schema.generated.js +1730 -0
- package/dist/types/canonical-document.generated.d.ts +541 -0
- package/dist/types/canonical-document.generated.js +3 -0
- package/dist/types/cronkite-manifest.generated.d.ts +339 -0
- package/dist/types/cronkite-manifest.generated.js +3 -0
- package/dist/video/Root.d.ts +1 -0
- package/dist/video/Root.js +40 -0
- package/dist/video/ShortVideo.d.ts +3 -0
- package/dist/video/ShortVideo.js +92 -0
- package/dist/video/index.d.ts +2 -0
- package/dist/video/index.js +4 -0
- package/dist/video/types.d.ts +37 -0
- package/dist/video/types.js +1 -0
- package/package.json +22 -9
- package/src/styles/compiled.css +1 -1
- package/src/templates/partials/components/coming-soon/main.hbs +1 -1
package/README.md
CHANGED
|
@@ -5,8 +5,11 @@ Server-side renderer and Handlebars template bundle for ModoItaliano pages.
|
|
|
5
5
|
## What it does
|
|
6
6
|
|
|
7
7
|
- Renders canonical content documents into HTML
|
|
8
|
-
- Supports
|
|
8
|
+
- Supports the layouts declared by the packaged Cronkite manifest, including
|
|
9
|
+
article, homepage, category, search, 404, coming-soon, live-story,
|
|
10
|
+
link-in-bio, media, and standalone pages
|
|
9
11
|
- Ships reusable Handlebars templates, partial dependency metadata, and compiled CSS
|
|
12
|
+
- Ships provider-neutral social-image and Remotion short-video renderables
|
|
10
13
|
- Preserves the masthead, footer, and radio player across same-language internal navigation
|
|
11
14
|
|
|
12
15
|
## Installation
|
|
@@ -18,18 +21,31 @@ npm install @gaulatti/giorgia
|
|
|
18
21
|
## Basic usage
|
|
19
22
|
|
|
20
23
|
```ts
|
|
21
|
-
import { render } from
|
|
24
|
+
import { render } from "@gaulatti/giorgia";
|
|
22
25
|
|
|
23
26
|
const html = render(doc);
|
|
24
27
|
```
|
|
25
28
|
|
|
26
|
-
`doc` must match the canonical schema
|
|
29
|
+
`doc` must match the normative canonical schema in
|
|
30
|
+
[src/schemas/canonical-document.schema.json](src/schemas/canonical-document.schema.json).
|
|
31
|
+
TypeScript declarations are generated from that schema; runtime rendering validates
|
|
32
|
+
against the same artifact.
|
|
27
33
|
|
|
28
34
|
## Exports
|
|
29
35
|
|
|
30
36
|
- `@gaulatti/giorgia` -> renderer entrypoint
|
|
37
|
+
- `@gaulatti/giorgia/cronkite-manifest.json` -> data-only CLS capability manifest
|
|
38
|
+
- `@gaulatti/giorgia/video` -> bundleable Remotion short-video entrypoint
|
|
39
|
+
- `@gaulatti/giorgia/schemas/canonical-document.schema.json` -> canonical input contract
|
|
40
|
+
- `@gaulatti/giorgia/schemas/search-manifest.schema.json` and
|
|
41
|
+
`@gaulatti/giorgia/schemas/search-index.schema.json` -> static-search resource contract
|
|
31
42
|
- `@gaulatti/giorgia/partial-deps.json` -> partial-to-layout dependency map
|
|
32
43
|
|
|
44
|
+
The root module also exports `cronkiteManifest`, `outletConfig`, `version`,
|
|
45
|
+
`render`, `fontFiles`, `assetFiles`, and `buildInstagramImageHtml`. See
|
|
46
|
+
[docs/cronkite-compatibility.md](docs/cronkite-compatibility.md) for ownership,
|
|
47
|
+
validation, search, and asset-rendering details.
|
|
48
|
+
|
|
33
49
|
## Development
|
|
34
50
|
|
|
35
51
|
```bash
|
|
@@ -37,6 +53,7 @@ npm install
|
|
|
37
53
|
npm run typecheck
|
|
38
54
|
npm run test:unit
|
|
39
55
|
npm run build
|
|
56
|
+
npm run verify:packed-remotion
|
|
40
57
|
npm run storybook
|
|
41
58
|
```
|
|
42
59
|
|
|
@@ -50,3 +67,48 @@ Page-local scripts that must run after a content swap use `data-swup-reload-scri
|
|
|
50
67
|
|
|
51
68
|
- CI validates typecheck, unit tests, and package build on pull requests and `main` pushes.
|
|
52
69
|
- Package publish is triggered by pushing a `v*` tag.
|
|
70
|
+
- Storybook pull requests build an immutable artifact but receive no AWS token.
|
|
71
|
+
A push or manual run on `main` deploys that exact artifact to
|
|
72
|
+
`https://ui.modoitaliano.fm` through the `giorgia-storybook` GitHub
|
|
73
|
+
environment and short-lived AWS OIDC role
|
|
74
|
+
`giorgia-storybook-github-deploy`. Storybook deployment never runs
|
|
75
|
+
`npm publish` or changes the package version.
|
|
76
|
+
|
|
77
|
+
### Storybook infrastructure and rollback
|
|
78
|
+
|
|
79
|
+
The Modo Italiano `Loredana` CloudFormation stack owns the dedicated Storybook
|
|
80
|
+
bucket and CloudFront distribution. The workflow resolves outputs
|
|
81
|
+
`LoredanaGiorgiaStorybookBucketName` and
|
|
82
|
+
`LoredanaGiorgiaStorybookDistributionId`; it must never target the Fifthbell
|
|
83
|
+
`ui.fifthbell.com` resources used by Brokaw.
|
|
84
|
+
|
|
85
|
+
Each build carries `deployment.json` with its repository, package version, run,
|
|
86
|
+
and full Git SHA. Deployment uploads to `/releases/<sha>` and changes the
|
|
87
|
+
CloudFront origin path only after the complete immutable prefix is present.
|
|
88
|
+
The previous origin path is retained and restored automatically if the public
|
|
89
|
+
identity check fails after promotion. A failed build or upload therefore
|
|
90
|
+
cannot partially overwrite the last known-good documentation.
|
|
91
|
+
|
|
92
|
+
The deployment log records the previous origin path. For an
|
|
93
|
+
operator-authorized manual rollback, fetch the current distribution config and
|
|
94
|
+
ETag, restore only the dedicated S3 origin's `OriginPath` to that recorded
|
|
95
|
+
`/releases/<sha>` value, submit the update with the ETag, wait for CloudFront to
|
|
96
|
+
deploy, and invalidate `/*`. Confirm the public `deployment.json` reports the
|
|
97
|
+
expected prior SHA. Do not delete release prefixes until a separately reviewed
|
|
98
|
+
retention policy exists.
|
|
99
|
+
|
|
100
|
+
The deployment role must trust only audience `sts.amazonaws.com` and the
|
|
101
|
+
repository's current immutable GitHub OIDC subject:
|
|
102
|
+
|
|
103
|
+
```text
|
|
104
|
+
repo:modoitaliano@327696306/giorgia@1304750193:environment:giorgia-storybook
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Its permissions are limited to `cloudformation:DescribeStacks` for Loredana;
|
|
108
|
+
`s3:ListBucket` and `s3:GetBucketLocation` on the dedicated bucket;
|
|
109
|
+
`s3:GetObject` and `s3:PutObject` on that bucket's `releases/*`; and
|
|
110
|
+
`cloudfront:GetDistribution`,
|
|
111
|
+
`cloudfront:GetDistributionConfig`, `cloudfront:UpdateDistribution`,
|
|
112
|
+
`cloudfront:CreateInvalidation`, and `cloudfront:GetInvalidation` on the one
|
|
113
|
+
Storybook distribution. It has no delete permission. No long-lived AWS key
|
|
114
|
+
belongs in GitHub secrets.
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
export declare const cronkiteManifest: {
|
|
2
|
+
readonly contract: "cronkite.cls";
|
|
3
|
+
readonly contractVersion: 1;
|
|
4
|
+
readonly package: "@gaulatti/giorgia";
|
|
5
|
+
readonly version: string;
|
|
6
|
+
readonly layouts: ["article-page" | "homepage" | "category-page" | "search-page" | "404" | "coming-soon" | "live-story" | "link-in-bio" | "media-page" | "standalone-page", ...("article-page" | "homepage" | "category-page" | "search-page" | "404" | "coming-soon" | "live-story" | "link-in-bio" | "media-page" | "standalone-page")[]];
|
|
7
|
+
readonly languages: ["es", "en", "it"];
|
|
8
|
+
readonly collections: {
|
|
9
|
+
readonly "article-page": "json/articles";
|
|
10
|
+
readonly "standalone-page": "json/pages";
|
|
11
|
+
};
|
|
12
|
+
readonly systemPages: import("./types/cronkite-manifest.generated.js").SystemPage[];
|
|
13
|
+
readonly renderables: {
|
|
14
|
+
readonly "search-page": {
|
|
15
|
+
readonly engine: "handlebars";
|
|
16
|
+
readonly export: "render";
|
|
17
|
+
readonly outputMode: "single";
|
|
18
|
+
readonly lifecycle: "request";
|
|
19
|
+
readonly contentType: "text/html; charset=utf-8";
|
|
20
|
+
readonly resources: {
|
|
21
|
+
readonly "search-manifest": {
|
|
22
|
+
readonly key: "search-manifest-{language}.json";
|
|
23
|
+
readonly schema: "dist/schemas/search-manifest.schema.json";
|
|
24
|
+
readonly contentType: "application/json";
|
|
25
|
+
readonly perLanguage: true;
|
|
26
|
+
};
|
|
27
|
+
};
|
|
28
|
+
};
|
|
29
|
+
readonly "social-image": {
|
|
30
|
+
readonly engine: "html-raster";
|
|
31
|
+
readonly export: "buildInstagramImageHtml";
|
|
32
|
+
readonly contentType: "image/jpeg";
|
|
33
|
+
readonly width: 1080;
|
|
34
|
+
readonly height: 1350;
|
|
35
|
+
};
|
|
36
|
+
readonly "short-video": {
|
|
37
|
+
readonly engine: "remotion";
|
|
38
|
+
readonly entry: "dist/video/index.js";
|
|
39
|
+
readonly compositionId: "ModoItalianoShort";
|
|
40
|
+
readonly contentType: "video/mp4";
|
|
41
|
+
};
|
|
42
|
+
};
|
|
43
|
+
readonly capabilities: {
|
|
44
|
+
readonly fonts: {
|
|
45
|
+
readonly export: "fontFiles";
|
|
46
|
+
};
|
|
47
|
+
readonly assets: {
|
|
48
|
+
readonly export: "assetFiles";
|
|
49
|
+
};
|
|
50
|
+
};
|
|
51
|
+
};
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { layoutNames } from "./layouts.js";
|
|
2
|
+
import { outletConfig } from "./outlet-config.js";
|
|
3
|
+
import { version } from "./version.js";
|
|
4
|
+
const systemPages = [
|
|
5
|
+
{
|
|
6
|
+
layout: "404",
|
|
7
|
+
route: "/{language}/404",
|
|
8
|
+
key: "html/{language}/404/index.html",
|
|
9
|
+
cacheControl: "public, max-age=0, must-revalidate",
|
|
10
|
+
perLanguage: true,
|
|
11
|
+
copy: {
|
|
12
|
+
es: {
|
|
13
|
+
title: "Página no encontrada",
|
|
14
|
+
description: "La página que buscas no existe.",
|
|
15
|
+
},
|
|
16
|
+
en: {
|
|
17
|
+
title: "Page Not Found",
|
|
18
|
+
description: "The page you are looking for does not exist.",
|
|
19
|
+
},
|
|
20
|
+
it: {
|
|
21
|
+
title: "Pagina non trovata",
|
|
22
|
+
description: "La pagina che stai cercando non esiste.",
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
layout: "search-page",
|
|
28
|
+
route: "/{language}/search",
|
|
29
|
+
key: "html/{language}/search/index.html",
|
|
30
|
+
cacheControl: "public, max-age=0, must-revalidate",
|
|
31
|
+
perLanguage: true,
|
|
32
|
+
copy: {
|
|
33
|
+
es: {
|
|
34
|
+
title: "Buscar",
|
|
35
|
+
description: outletConfig.searchDescriptions.es,
|
|
36
|
+
},
|
|
37
|
+
en: {
|
|
38
|
+
title: "Search",
|
|
39
|
+
description: outletConfig.searchDescriptions.en,
|
|
40
|
+
},
|
|
41
|
+
it: {
|
|
42
|
+
title: "Cerca",
|
|
43
|
+
description: outletConfig.searchDescriptions.it,
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
layout: "coming-soon",
|
|
49
|
+
route: "/{language}/coming-soon",
|
|
50
|
+
key: "html/{language}/coming-soon/index.html",
|
|
51
|
+
cacheControl: "public, max-age=0, must-revalidate",
|
|
52
|
+
perLanguage: true,
|
|
53
|
+
copy: {
|
|
54
|
+
es: {
|
|
55
|
+
title: "Próximamente",
|
|
56
|
+
description: "Estamos preparando algo especial. Vuelve pronto para descubrirlo.",
|
|
57
|
+
},
|
|
58
|
+
en: {
|
|
59
|
+
title: "Coming soon",
|
|
60
|
+
description: "We are preparing something special. Come back soon.",
|
|
61
|
+
},
|
|
62
|
+
it: {
|
|
63
|
+
title: "Prossimamente",
|
|
64
|
+
description: "Stiamo preparando qualcosa di speciale. Torna presto.",
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
];
|
|
69
|
+
export const cronkiteManifest = {
|
|
70
|
+
contract: "cronkite.cls",
|
|
71
|
+
contractVersion: 1,
|
|
72
|
+
package: "@gaulatti/giorgia",
|
|
73
|
+
version,
|
|
74
|
+
layouts: [...layoutNames],
|
|
75
|
+
languages: [...outletConfig.supportedLanguages],
|
|
76
|
+
collections: {
|
|
77
|
+
"article-page": "json/articles",
|
|
78
|
+
"standalone-page": "json/pages",
|
|
79
|
+
},
|
|
80
|
+
systemPages,
|
|
81
|
+
renderables: {
|
|
82
|
+
"search-page": {
|
|
83
|
+
engine: "handlebars",
|
|
84
|
+
export: "render",
|
|
85
|
+
outputMode: "single",
|
|
86
|
+
lifecycle: "request",
|
|
87
|
+
contentType: "text/html; charset=utf-8",
|
|
88
|
+
resources: {
|
|
89
|
+
"search-manifest": {
|
|
90
|
+
key: "search-manifest-{language}.json",
|
|
91
|
+
schema: "dist/schemas/search-manifest.schema.json",
|
|
92
|
+
contentType: "application/json",
|
|
93
|
+
perLanguage: true,
|
|
94
|
+
},
|
|
95
|
+
},
|
|
96
|
+
},
|
|
97
|
+
"social-image": {
|
|
98
|
+
engine: "html-raster",
|
|
99
|
+
export: "buildInstagramImageHtml",
|
|
100
|
+
contentType: "image/jpeg",
|
|
101
|
+
width: 1080,
|
|
102
|
+
height: 1350,
|
|
103
|
+
},
|
|
104
|
+
"short-video": {
|
|
105
|
+
engine: "remotion",
|
|
106
|
+
entry: "dist/video/index.js",
|
|
107
|
+
compositionId: "ModoItalianoShort",
|
|
108
|
+
contentType: "video/mp4",
|
|
109
|
+
},
|
|
110
|
+
},
|
|
111
|
+
capabilities: {
|
|
112
|
+
fonts: { export: "fontFiles" },
|
|
113
|
+
assets: { export: "assetFiles" },
|
|
114
|
+
},
|
|
115
|
+
};
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
{
|
|
2
|
+
"contract": "cronkite.cls",
|
|
3
|
+
"contractVersion": 1,
|
|
4
|
+
"package": "@gaulatti/giorgia",
|
|
5
|
+
"version": "0.1.99",
|
|
6
|
+
"layouts": [
|
|
7
|
+
"404",
|
|
8
|
+
"article-page",
|
|
9
|
+
"homepage",
|
|
10
|
+
"category-page",
|
|
11
|
+
"search-page",
|
|
12
|
+
"coming-soon",
|
|
13
|
+
"live-story",
|
|
14
|
+
"link-in-bio",
|
|
15
|
+
"media-page",
|
|
16
|
+
"standalone-page"
|
|
17
|
+
],
|
|
18
|
+
"languages": [
|
|
19
|
+
"es",
|
|
20
|
+
"en",
|
|
21
|
+
"it"
|
|
22
|
+
],
|
|
23
|
+
"collections": {
|
|
24
|
+
"article-page": "json/articles",
|
|
25
|
+
"standalone-page": "json/pages"
|
|
26
|
+
},
|
|
27
|
+
"systemPages": [
|
|
28
|
+
{
|
|
29
|
+
"layout": "404",
|
|
30
|
+
"route": "/{language}/404",
|
|
31
|
+
"key": "html/{language}/404/index.html",
|
|
32
|
+
"cacheControl": "public, max-age=0, must-revalidate",
|
|
33
|
+
"perLanguage": true,
|
|
34
|
+
"copy": {
|
|
35
|
+
"es": {
|
|
36
|
+
"title": "Página no encontrada",
|
|
37
|
+
"description": "La página que buscas no existe."
|
|
38
|
+
},
|
|
39
|
+
"en": {
|
|
40
|
+
"title": "Page Not Found",
|
|
41
|
+
"description": "The page you are looking for does not exist."
|
|
42
|
+
},
|
|
43
|
+
"it": {
|
|
44
|
+
"title": "Pagina non trovata",
|
|
45
|
+
"description": "La pagina che stai cercando non esiste."
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
"layout": "search-page",
|
|
51
|
+
"route": "/{language}/search",
|
|
52
|
+
"key": "html/{language}/search/index.html",
|
|
53
|
+
"cacheControl": "public, max-age=0, must-revalidate",
|
|
54
|
+
"perLanguage": true,
|
|
55
|
+
"copy": {
|
|
56
|
+
"es": {
|
|
57
|
+
"title": "Buscar",
|
|
58
|
+
"description": "Busca noticias de ModoItaliano."
|
|
59
|
+
},
|
|
60
|
+
"en": {
|
|
61
|
+
"title": "Search",
|
|
62
|
+
"description": "Search ModoItaliano news."
|
|
63
|
+
},
|
|
64
|
+
"it": {
|
|
65
|
+
"title": "Cerca",
|
|
66
|
+
"description": "Cerca le notizie di ModoItaliano."
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
"layout": "coming-soon",
|
|
72
|
+
"route": "/{language}/coming-soon",
|
|
73
|
+
"key": "html/{language}/coming-soon/index.html",
|
|
74
|
+
"cacheControl": "public, max-age=0, must-revalidate",
|
|
75
|
+
"perLanguage": true,
|
|
76
|
+
"copy": {
|
|
77
|
+
"es": {
|
|
78
|
+
"title": "Próximamente",
|
|
79
|
+
"description": "Estamos preparando algo especial. Vuelve pronto para descubrirlo."
|
|
80
|
+
},
|
|
81
|
+
"en": {
|
|
82
|
+
"title": "Coming soon",
|
|
83
|
+
"description": "We are preparing something special. Come back soon."
|
|
84
|
+
},
|
|
85
|
+
"it": {
|
|
86
|
+
"title": "Prossimamente",
|
|
87
|
+
"description": "Stiamo preparando qualcosa di speciale. Torna presto."
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
],
|
|
92
|
+
"renderables": {
|
|
93
|
+
"search-page": {
|
|
94
|
+
"engine": "handlebars",
|
|
95
|
+
"export": "render",
|
|
96
|
+
"outputMode": "single",
|
|
97
|
+
"lifecycle": "request",
|
|
98
|
+
"contentType": "text/html; charset=utf-8",
|
|
99
|
+
"resources": {
|
|
100
|
+
"search-manifest": {
|
|
101
|
+
"key": "search-manifest-{language}.json",
|
|
102
|
+
"schema": "dist/schemas/search-manifest.schema.json",
|
|
103
|
+
"contentType": "application/json",
|
|
104
|
+
"perLanguage": true
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
},
|
|
108
|
+
"social-image": {
|
|
109
|
+
"engine": "html-raster",
|
|
110
|
+
"export": "buildInstagramImageHtml",
|
|
111
|
+
"contentType": "image/jpeg",
|
|
112
|
+
"width": 1080,
|
|
113
|
+
"height": 1350
|
|
114
|
+
},
|
|
115
|
+
"short-video": {
|
|
116
|
+
"engine": "remotion",
|
|
117
|
+
"entry": "dist/video/index.js",
|
|
118
|
+
"compositionId": "ModoItalianoShort",
|
|
119
|
+
"contentType": "video/mp4"
|
|
120
|
+
}
|
|
121
|
+
},
|
|
122
|
+
"capabilities": {
|
|
123
|
+
"fonts": {
|
|
124
|
+
"export": "fontFiles"
|
|
125
|
+
},
|
|
126
|
+
"assets": {
|
|
127
|
+
"export": "assetFiles"
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
const rfc3339 = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}:\d{2})$/;
|
|
2
|
+
const uuid = /^(?:[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$/i;
|
|
3
|
+
export function addContractFormats(ajv) {
|
|
4
|
+
ajv.addFormat("date-time", {
|
|
5
|
+
type: "string",
|
|
6
|
+
validate: (value) => rfc3339.test(value) && !Number.isNaN(Date.parse(value)),
|
|
7
|
+
});
|
|
8
|
+
ajv.addFormat("uri", {
|
|
9
|
+
type: "string",
|
|
10
|
+
validate: (value) => {
|
|
11
|
+
try {
|
|
12
|
+
const parsed = new URL(value);
|
|
13
|
+
return Boolean(parsed.protocol);
|
|
14
|
+
}
|
|
15
|
+
catch {
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
});
|
|
20
|
+
ajv.addFormat("uuid", {
|
|
21
|
+
type: "string",
|
|
22
|
+
validate: (value) => uuid.test(value),
|
|
23
|
+
});
|
|
24
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export declare const layoutFiles: {
|
|
2
|
+
readonly "article-page": "article-page.hbs";
|
|
3
|
+
readonly homepage: "homepage.hbs";
|
|
4
|
+
readonly "category-page": "category-page.hbs";
|
|
5
|
+
readonly "search-page": "search-page.hbs";
|
|
6
|
+
readonly "404": "404.hbs";
|
|
7
|
+
readonly "coming-soon": "coming-soon.hbs";
|
|
8
|
+
readonly "live-story": "live-story.hbs";
|
|
9
|
+
readonly "link-in-bio": "link-in-bio.hbs";
|
|
10
|
+
readonly "media-page": "media-page.hbs";
|
|
11
|
+
readonly "standalone-page": "standalone-page.hbs";
|
|
12
|
+
};
|
|
13
|
+
export type LayoutName = keyof typeof layoutFiles;
|
|
14
|
+
export declare const layoutNames: readonly ["article-page" | "homepage" | "category-page" | "search-page" | "404" | "coming-soon" | "live-story" | "link-in-bio" | "media-page" | "standalone-page", ...("article-page" | "homepage" | "category-page" | "search-page" | "404" | "coming-soon" | "live-story" | "link-in-bio" | "media-page" | "standalone-page")[]];
|
package/dist/layouts.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export const layoutFiles = {
|
|
2
|
+
"article-page": "article-page.hbs",
|
|
3
|
+
homepage: "homepage.hbs",
|
|
4
|
+
"category-page": "category-page.hbs",
|
|
5
|
+
"search-page": "search-page.hbs",
|
|
6
|
+
"404": "404.hbs",
|
|
7
|
+
"coming-soon": "coming-soon.hbs",
|
|
8
|
+
"live-story": "live-story.hbs",
|
|
9
|
+
"link-in-bio": "link-in-bio.hbs",
|
|
10
|
+
"media-page": "media-page.hbs",
|
|
11
|
+
"standalone-page": "standalone-page.hbs",
|
|
12
|
+
};
|
|
13
|
+
export const layoutNames = Object.freeze(Object.keys(layoutFiles));
|