@phtngyn/cms 0.1.0-beta.1 → 0.1.0-beta.2
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 +192 -9
- package/package.json +30 -15
- package/src/Configuration-Br7tE9Qt.d.ts +68 -0
- package/src/{Configuration-DyKo0sLS.js → Configuration-CA_jvQKG.js} +26 -147
- package/src/Configuration-CA_jvQKG.js.map +1 -0
- package/src/Configuration.d.ts +2 -44
- package/src/Configuration.js +0 -1
- package/src/Configuration.js.map +1 -1
- package/src/{DocumentEngine-DYObwMDY.js → DocumentEngine-CgiBQU4g.js} +75 -27
- package/src/DocumentEngine-CgiBQU4g.js.map +1 -0
- package/src/DocumentModel-BB9igGC7.d.ts +34 -0
- package/src/DocumentModel.d.ts +2 -34
- package/src/DocumentModel.js +13 -3
- package/src/DocumentModel.js.map +1 -1
- package/src/Forms-BsJMev5_.d.ts +74 -0
- package/src/Forms-CfcI3tPU.js +79 -0
- package/src/Forms-CfcI3tPU.js.map +1 -0
- package/src/Forms-DxbkU3_5.js +367 -0
- package/src/Forms-DxbkU3_5.js.map +1 -0
- package/src/Forms.d.ts +35 -0
- package/src/Forms.js +13 -0
- package/src/Forms.js.map +1 -0
- package/src/{HttpPaths-BbS21Jy8.js → HttpPaths-c9nLZ9H2.js} +6 -2
- package/src/HttpPaths-c9nLZ9H2.js.map +1 -0
- package/src/I18n-DZK4CkJF.d.ts +21 -0
- package/src/I18n.d.ts +2 -0
- package/src/I18n.js +1 -0
- package/src/Module.js +57 -11
- package/src/Module.js.map +1 -1
- package/src/S3MediaObjects-JKMAWyVB.js +2664 -0
- package/src/S3MediaObjects-JKMAWyVB.js.map +1 -0
- package/src/Seed.d.ts +6 -0
- package/src/Seed.js +34 -0
- package/src/Seed.js.map +1 -0
- package/src/Seo-402YumpT.d.ts +198 -0
- package/src/{connection-CBTY-TzB.js → connection-B-iz0Y9Y.js} +5 -7
- package/src/connection-B-iz0Y9Y.js.map +1 -0
- package/src/{installation-DeuBiFRE.js → installation-DgF2M1gL.js} +1005 -2242
- package/src/installation-DgF2M1gL.js.map +1 -0
- package/src/internal/authoring-catalog.js +10 -4
- package/src/internal/authoring-catalog.js.map +1 -1
- package/src/internal/authoring-compiler.js +0 -1
- package/src/internal/authoring-compiler.js.map +1 -1
- package/src/internal/authoring-metadata.js +4 -4
- package/src/internal/authoring-metadata.js.map +1 -1
- package/src/internal/cms-config.js +0 -1
- package/src/internal/cms-config.js.map +1 -1
- package/src/internal/configuration.js +23 -10
- package/src/internal/configuration.js.map +1 -1
- package/src/internal/document-model.js +65 -20
- package/src/internal/document-model.js.map +1 -1
- package/src/internal/form-capabilities.js +12 -0
- package/src/internal/form-capabilities.js.map +1 -0
- package/src/internal/i18n.js +47 -0
- package/src/internal/i18n.js.map +1 -0
- package/src/internal/studio-app.js +2 -2
- package/src/internal/studio-app.js.map +1 -1
- package/src/{location-DtYv2aes.js → location-CFKTeK1K.js} +2 -3
- package/src/location-CFKTeK1K.js.map +1 -0
- package/src/{metadata-DE1Mc2td.js → metadata-BEZPWh-3.js} +3 -72
- package/src/metadata-BEZPWh-3.js.map +1 -0
- package/src/{models-C3witQBK.js → models-BWm1pTAf.js} +3 -2
- package/src/models-BWm1pTAf.js.map +1 -0
- package/src/{models-BkMgeaOL.js → models-DwYioyNV.js} +203 -32
- package/src/models-DwYioyNV.js.map +1 -0
- package/src/runtime/blocks.js +22 -9
- package/src/runtime/blocks.js.map +1 -1
- package/src/runtime/collaboration.js.map +1 -1
- package/src/runtime/delivery/DocumentRenderer.js +7 -4
- package/src/runtime/delivery/DocumentRenderer.js.map +1 -1
- package/src/runtime/delivery/blocks.js +3 -1
- package/src/runtime/delivery/blocks.js.map +1 -1
- package/src/runtime/delivery/context.js +1 -1
- package/src/runtime/delivery/document-page.js +12 -12
- package/src/runtime/delivery/document-page.js.map +1 -1
- package/src/runtime/delivery/document.js +4 -2
- package/src/runtime/delivery/document.js.map +1 -1
- package/src/runtime/delivery/error.js.map +1 -1
- package/src/runtime/delivery/plugin.js +22 -2
- package/src/runtime/delivery/plugin.js.map +1 -1
- package/src/runtime/delivery/types.d.ts +5 -0
- package/src/runtime/delivery/useCmsDocumentSeo.d.ts +56 -0
- package/src/runtime/delivery/useCmsDocumentSeo.js +99 -0
- package/src/runtime/delivery/useCmsDocumentSeo.js.map +1 -0
- package/src/runtime/delivery/useDocument.js +2 -2
- package/src/runtime/delivery/useDocument.js.map +1 -1
- package/src/runtime/delivery/useDocumentQuery.js +2 -2
- package/src/runtime/delivery/useDocumentQuery.js.map +1 -1
- package/src/runtime/forms/document.js +38 -0
- package/src/runtime/forms/document.js.map +1 -0
- package/src/runtime/forms/useCmsForm.js +149 -0
- package/src/runtime/forms/useCmsForm.js.map +1 -0
- package/src/runtime/i18n/translator.js +22 -0
- package/src/runtime/i18n/translator.js.map +1 -0
- package/src/runtime/i18n/useCmsI18n.d.ts +9 -0
- package/src/runtime/i18n/useCmsI18n.js +29 -0
- package/src/runtime/i18n/useCmsI18n.js.map +1 -0
- package/src/runtime/installation.js +1 -1
- package/src/runtime/plugin.js +1 -1
- package/src/runtime/plugin.js.map +1 -1
- package/src/runtime/preview/comark-document.js +0 -1
- package/src/runtime/preview/comark-document.js.map +1 -1
- package/src/runtime/preview/connection.js +1 -1
- package/src/runtime/preview/controller.js +10 -3
- package/src/runtime/preview/controller.js.map +1 -1
- package/src/runtime/preview/overlay.js.map +1 -1
- package/src/runtime/preview/plugin.client.js +59 -48
- package/src/runtime/preview/plugin.client.js.map +1 -1
- package/src/runtime/preview/protocol.js.map +1 -1
- package/src/runtime/preview/store.js +1 -1
- package/src/runtime/preview/targets.js +0 -1
- package/src/runtime/preview/targets.js.map +1 -1
- package/src/runtime/sitemap-entries.js +17 -0
- package/src/runtime/sitemap-entries.js.map +1 -0
- package/src/runtime/sitemap.js +24 -0
- package/src/runtime/sitemap.js.map +1 -0
- package/src/runtime/studio-app.js.map +1 -1
- package/src/runtime/studio-entry.js +2 -2
- package/src/runtime/studio-entry.js.map +1 -1
- package/src/runtime/studio-navigation.js +1 -1
- package/src/scalars-B2lgGUnj.js +26 -0
- package/src/scalars-B2lgGUnj.js.map +1 -0
- package/src/{store-CfFFx9Ua.js → store-DjJs3I7k.js} +12 -7
- package/src/store-DjJs3I7k.js.map +1 -0
- package/studio/{CreateDocumentDialog--L9lTfx6.js → CreateDocumentDialog-CTeIFlPb.js} +44 -44
- package/studio/{collaboration-DUuu678R.js → collaboration-DcK2F6v9.js} +7 -6
- package/studio/{documentPlanning-BXX04Woe.js → documentPlanning-Bfv-d7OU.js} +7310 -6479
- package/studio/{editor-PexnXkJY.js → editor-Bzlh3zXt.js} +7965 -7955
- package/studio/host.css +1 -1
- package/studio/host.js +10416 -7981
- package/src/Configuration-DyKo0sLS.js.map +0 -1
- package/src/DocumentEngine-DYObwMDY.js.map +0 -1
- package/src/HttpPaths-BbS21Jy8.js.map +0 -1
- package/src/StudioHttp-jR2-bc01.js +0 -718
- package/src/StudioHttp-jR2-bc01.js.map +0 -1
- package/src/connection-CBTY-TzB.js.map +0 -1
- package/src/installation-DeuBiFRE.js.map +0 -1
- package/src/location-DtYv2aes.js.map +0 -1
- package/src/metadata-DE1Mc2td.js.map +0 -1
- package/src/models-BkMgeaOL.js.map +0 -1
- package/src/models-C3witQBK.js.map +0 -1
- package/src/store-CfFFx9Ua.js.map +0 -1
package/src/Seed.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { i as CmsInitialDocumentProvider } from "./Configuration-Br7tE9Qt.js";
|
|
2
|
+
//#region src/Seed.d.ts
|
|
3
|
+
/** Read Markdown documents from a directory when Nuxt loads the CMS configuration. */
|
|
4
|
+
export declare function seedFromDirectory(directory: URL): CmsInitialDocumentProvider;
|
|
5
|
+
//#endregion
|
|
6
|
+
//# sourceMappingURL=Seed.d.ts.map
|
package/src/Seed.js
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { Effect, FileSystem, Layer, Path } from "effect";
|
|
2
|
+
import { NodeFileSystem, NodePath } from "@effect/platform-node-shared";
|
|
3
|
+
|
|
4
|
+
//#region src/Seed.ts
|
|
5
|
+
const nodeLayer = Layer.merge(NodeFileSystem.layer, NodePath.layer);
|
|
6
|
+
/** Read Markdown documents from a directory when Nuxt loads the CMS configuration. */
|
|
7
|
+
function seedFromDirectory(directory) {
|
|
8
|
+
return () => Effect.runPromise(Effect.gen(function* () {
|
|
9
|
+
const fileSystem = yield* FileSystem.FileSystem;
|
|
10
|
+
const path = yield* Path.Path;
|
|
11
|
+
const seedDirectory = yield* path.fromFileUrl(directory);
|
|
12
|
+
const files = [...yield* markdownFiles(seedDirectory)].sort((left, right) => right.split("/").length - left.split("/").length || left.localeCompare(right));
|
|
13
|
+
return yield* Effect.forEach(files, (filePath) => fileSystem.readFileString(filePath).pipe(Effect.map((markdown) => ({
|
|
14
|
+
markdown,
|
|
15
|
+
published: true,
|
|
16
|
+
sourcePath: path.relative(seedDirectory, filePath).replaceAll("\\", "/")
|
|
17
|
+
}))));
|
|
18
|
+
}).pipe(Effect.provide(nodeLayer)));
|
|
19
|
+
}
|
|
20
|
+
function markdownFiles(directory) {
|
|
21
|
+
return Effect.gen(function* () {
|
|
22
|
+
const fileSystem = yield* FileSystem.FileSystem;
|
|
23
|
+
const path = yield* Path.Path;
|
|
24
|
+
const names = yield* fileSystem.readDirectory(directory);
|
|
25
|
+
return (yield* Effect.forEach(names, (name) => Effect.gen(function* () {
|
|
26
|
+
const filePath = path.resolve(directory, name);
|
|
27
|
+
return (yield* fileSystem.stat(filePath)).type === "Directory" ? yield* markdownFiles(filePath) : [filePath];
|
|
28
|
+
}))).flat().filter((filePath) => path.extname(filePath) === ".md");
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
//#endregion
|
|
33
|
+
export { seedFromDirectory };
|
|
34
|
+
//# sourceMappingURL=Seed.js.map
|
package/src/Seed.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Seed.js","names":[],"sources":["../../../src/Seed.ts"],"sourcesContent":["import type { CmsInitialDocumentProvider } from './Configuration'\nimport { NodeFileSystem, NodePath } from '@effect/platform-node-shared'\nimport { Effect, FileSystem, Layer, Path, type PlatformError } from 'effect'\n\nconst nodeLayer = Layer.merge(NodeFileSystem.layer, NodePath.layer)\n\n/** Read Markdown documents from a directory when Nuxt loads the CMS configuration. */\nexport function seedFromDirectory(directory: URL): CmsInitialDocumentProvider {\n return () =>\n Effect.runPromise(\n Effect.gen(function* () {\n const fileSystem = yield* FileSystem.FileSystem\n const path = yield* Path.Path\n const seedDirectory = yield* path.fromFileUrl(directory)\n\n const files = [...(yield* markdownFiles(seedDirectory))].sort(\n (left, right) => right.split('/').length - left.split('/').length || left.localeCompare(right),\n )\n\n return yield* Effect.forEach(files, (filePath) =>\n fileSystem.readFileString(filePath).pipe(\n Effect.map((markdown) => ({\n markdown,\n published: true,\n sourcePath: path.relative(seedDirectory, filePath).replaceAll('\\\\', '/'),\n })),\n ),\n )\n }).pipe(Effect.provide(nodeLayer)),\n )\n}\n\nfunction markdownFiles(\n directory: string,\n): Effect.Effect<ReadonlyArray<string>, PlatformError.PlatformError, FileSystem.FileSystem | Path.Path> {\n return Effect.gen(function* () {\n const fileSystem = yield* FileSystem.FileSystem\n const path = yield* Path.Path\n const names = yield* fileSystem.readDirectory(directory)\n\n const nested = yield* Effect.forEach(names, (name) =>\n Effect.gen(function* () {\n const filePath = path.resolve(directory, name)\n const info = yield* fileSystem.stat(filePath)\n\n return info.type === 'Directory' ? yield* markdownFiles(filePath) : [filePath]\n }),\n )\n\n return nested.flat().filter((filePath) => path.extname(filePath) === '.md')\n })\n}\n"],"mappings":";;;;AAIA,MAAM,YAAY,MAAM,MAAM,eAAe,OAAO,SAAS,KAAK;;AAGlE,SAAgB,kBAAkB,WAA4C;CAC5E,aACE,OAAO,WACL,OAAO,IAAI,aAAa;EACtB,MAAM,aAAa,OAAO,WAAW;EACrC,MAAM,OAAO,OAAO,KAAK;EACzB,MAAM,gBAAgB,OAAO,KAAK,YAAY,SAAS;EAEvD,MAAM,QAAQ,CAAC,GAAI,OAAO,cAAc,aAAa,CAAE,CAAC,CAAC,MACtD,MAAM,UAAU,MAAM,MAAM,GAAG,CAAC,CAAC,SAAS,KAAK,MAAM,GAAG,CAAC,CAAC,UAAU,KAAK,cAAc,KAAK,CAC/F;EAEA,OAAO,OAAO,OAAO,QAAQ,QAAQ,aACnC,WAAW,eAAe,QAAQ,CAAC,CAAC,KAClC,OAAO,KAAK,cAAc;GACxB;GACA,WAAW;GACX,YAAY,KAAK,SAAS,eAAe,QAAQ,CAAC,CAAC,WAAW,MAAM,GAAG;EACzE,EAAE,CACJ,CACF;CACF,CAAC,CAAC,CAAC,KAAK,OAAO,QAAQ,SAAS,CAAC,CACnC;AACJ;AAEA,SAAS,cACP,WACsG;CACtG,OAAO,OAAO,IAAI,aAAa;EAC7B,MAAM,aAAa,OAAO,WAAW;EACrC,MAAM,OAAO,OAAO,KAAK;EACzB,MAAM,QAAQ,OAAO,WAAW,cAAc,SAAS;EAWvD,QAAO,OATe,OAAO,QAAQ,QAAQ,SAC3C,OAAO,IAAI,aAAa;GACtB,MAAM,WAAW,KAAK,QAAQ,WAAW,IAAI;GAG7C,QAAO,OAFa,WAAW,KAAK,QAAQ,EAEjC,CAAC,SAAS,cAAc,OAAO,cAAc,QAAQ,IAAI,CAAC,QAAQ;EAC/E,CAAC,CACH,EAEa,CAAC,KAAK,CAAC,CAAC,QAAQ,aAAa,KAAK,QAAQ,QAAQ,MAAM,KAAK;CAC5E,CAAC;AACH"}
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
import { Schema } from "effect";
|
|
2
|
+
//#region ../protocol/src/Seo.d.ts
|
|
3
|
+
declare const SiteIdentity: Schema.toTaggedUnion<"type", readonly [Schema.Struct<{
|
|
4
|
+
readonly image: Schema.optionalKey<Schema.Struct<{
|
|
5
|
+
readonly mediaId: Schema.brand<Schema.String, "MediaId">;
|
|
6
|
+
readonly url: Schema.brand<Schema.NonEmptyString, "SeoUrl">;
|
|
7
|
+
readonly alt: Schema.NonEmptyString;
|
|
8
|
+
}>>;
|
|
9
|
+
readonly name: Schema.NonEmptyString;
|
|
10
|
+
readonly url: Schema.optionalKey<Schema.brand<Schema.NonEmptyString, "SeoUrl">>;
|
|
11
|
+
readonly type: Schema.tag<"Person">;
|
|
12
|
+
}>, Schema.Struct<{
|
|
13
|
+
readonly logo: Schema.optionalKey<Schema.Struct<{
|
|
14
|
+
readonly mediaId: Schema.brand<Schema.String, "MediaId">;
|
|
15
|
+
readonly url: Schema.brand<Schema.NonEmptyString, "SeoUrl">;
|
|
16
|
+
readonly alt: Schema.NonEmptyString;
|
|
17
|
+
}>>;
|
|
18
|
+
readonly name: Schema.NonEmptyString;
|
|
19
|
+
readonly url: Schema.optionalKey<Schema.brand<Schema.NonEmptyString, "SeoUrl">>;
|
|
20
|
+
readonly type: Schema.tag<"Organization">;
|
|
21
|
+
}>, Schema.Struct<{
|
|
22
|
+
readonly logo: Schema.optionalKey<Schema.Struct<{
|
|
23
|
+
readonly mediaId: Schema.brand<Schema.String, "MediaId">;
|
|
24
|
+
readonly url: Schema.brand<Schema.NonEmptyString, "SeoUrl">;
|
|
25
|
+
readonly alt: Schema.NonEmptyString;
|
|
26
|
+
}>>;
|
|
27
|
+
readonly image: Schema.optionalKey<Schema.Struct<{
|
|
28
|
+
readonly mediaId: Schema.brand<Schema.String, "MediaId">;
|
|
29
|
+
readonly url: Schema.brand<Schema.NonEmptyString, "SeoUrl">;
|
|
30
|
+
readonly alt: Schema.NonEmptyString;
|
|
31
|
+
}>>;
|
|
32
|
+
readonly telephone: Schema.optionalKey<Schema.NonEmptyString>;
|
|
33
|
+
readonly address: Schema.optionalKey<Schema.Struct<{
|
|
34
|
+
readonly streetAddress: Schema.optionalKey<Schema.NonEmptyString>;
|
|
35
|
+
readonly addressLocality: Schema.optionalKey<Schema.NonEmptyString>;
|
|
36
|
+
readonly addressRegion: Schema.optionalKey<Schema.NonEmptyString>;
|
|
37
|
+
readonly postalCode: Schema.optionalKey<Schema.NonEmptyString>;
|
|
38
|
+
readonly addressCountry: Schema.optionalKey<Schema.NonEmptyString>;
|
|
39
|
+
}>>;
|
|
40
|
+
readonly name: Schema.NonEmptyString;
|
|
41
|
+
readonly url: Schema.optionalKey<Schema.brand<Schema.NonEmptyString, "SeoUrl">>;
|
|
42
|
+
readonly type: Schema.tag<"LocalBusiness">;
|
|
43
|
+
}>]>;
|
|
44
|
+
type SiteIdentity = typeof SiteIdentity.Type;
|
|
45
|
+
declare const DocumentSeo: Schema.Struct<{
|
|
46
|
+
readonly title: Schema.optionalKey<Schema.NonEmptyString>;
|
|
47
|
+
readonly description: Schema.optionalKey<Schema.NonEmptyString>;
|
|
48
|
+
readonly socialTitle: Schema.optionalKey<Schema.NonEmptyString>;
|
|
49
|
+
readonly socialDescription: Schema.optionalKey<Schema.NonEmptyString>;
|
|
50
|
+
readonly socialImage: Schema.optionalKey<Schema.Struct<{
|
|
51
|
+
readonly mediaId: Schema.brand<Schema.String, "MediaId">;
|
|
52
|
+
readonly url: Schema.brand<Schema.NonEmptyString, "SeoUrl">;
|
|
53
|
+
readonly alt: Schema.NonEmptyString;
|
|
54
|
+
}>>;
|
|
55
|
+
readonly index: Schema.optionalKey<Schema.Boolean>;
|
|
56
|
+
readonly follow: Schema.optionalKey<Schema.Boolean>;
|
|
57
|
+
readonly canonicalUrl: Schema.optionalKey<Schema.brand<Schema.NonEmptyString, "SeoUrl">>;
|
|
58
|
+
readonly structuredData: Schema.optionalKey<Schema.toTaggedUnion<"type", readonly [Schema.Struct<{
|
|
59
|
+
readonly type: Schema.tag<"WebPage">;
|
|
60
|
+
}>, Schema.Struct<{
|
|
61
|
+
readonly type: Schema.tag<"Article">;
|
|
62
|
+
readonly headline: Schema.optionalKey<Schema.NonEmptyString>;
|
|
63
|
+
readonly datePublished: Schema.optionalKey<Schema.String>;
|
|
64
|
+
readonly dateModified: Schema.optionalKey<Schema.String>;
|
|
65
|
+
}>]>>;
|
|
66
|
+
}>;
|
|
67
|
+
interface DocumentSeo extends Schema.Schema.Type<typeof DocumentSeo> {}
|
|
68
|
+
declare const SeoConfiguration: Schema.Struct<{
|
|
69
|
+
readonly defaults: Schema.Struct<{
|
|
70
|
+
readonly siteName: Schema.NonEmptyString;
|
|
71
|
+
readonly defaultDescription: Schema.optionalKey<Schema.NonEmptyString>;
|
|
72
|
+
readonly canonicalOrigin: Schema.brand<Schema.NonEmptyString, "SeoCanonicalOrigin">;
|
|
73
|
+
readonly titleTemplate: Schema.optionalKey<Schema.NonEmptyString>;
|
|
74
|
+
readonly socialTitle: Schema.optionalKey<Schema.NonEmptyString>;
|
|
75
|
+
readonly socialDescription: Schema.optionalKey<Schema.NonEmptyString>;
|
|
76
|
+
readonly socialImage: Schema.optionalKey<Schema.Struct<{
|
|
77
|
+
readonly mediaId: Schema.brand<Schema.String, "MediaId">;
|
|
78
|
+
readonly url: Schema.brand<Schema.NonEmptyString, "SeoUrl">;
|
|
79
|
+
readonly alt: Schema.NonEmptyString;
|
|
80
|
+
}>>;
|
|
81
|
+
readonly index: Schema.Boolean;
|
|
82
|
+
readonly follow: Schema.Boolean;
|
|
83
|
+
readonly identity: Schema.optionalKey<Schema.toTaggedUnion<"type", readonly [Schema.Struct<{
|
|
84
|
+
readonly image: Schema.optionalKey<Schema.Struct<{
|
|
85
|
+
readonly mediaId: Schema.brand<Schema.String, "MediaId">;
|
|
86
|
+
readonly url: Schema.brand<Schema.NonEmptyString, "SeoUrl">;
|
|
87
|
+
readonly alt: Schema.NonEmptyString;
|
|
88
|
+
}>>;
|
|
89
|
+
readonly name: Schema.NonEmptyString;
|
|
90
|
+
readonly url: Schema.optionalKey<Schema.brand<Schema.NonEmptyString, "SeoUrl">>;
|
|
91
|
+
readonly type: Schema.tag<"Person">;
|
|
92
|
+
}>, Schema.Struct<{
|
|
93
|
+
readonly logo: Schema.optionalKey<Schema.Struct<{
|
|
94
|
+
readonly mediaId: Schema.brand<Schema.String, "MediaId">;
|
|
95
|
+
readonly url: Schema.brand<Schema.NonEmptyString, "SeoUrl">;
|
|
96
|
+
readonly alt: Schema.NonEmptyString;
|
|
97
|
+
}>>;
|
|
98
|
+
readonly name: Schema.NonEmptyString;
|
|
99
|
+
readonly url: Schema.optionalKey<Schema.brand<Schema.NonEmptyString, "SeoUrl">>;
|
|
100
|
+
readonly type: Schema.tag<"Organization">;
|
|
101
|
+
}>, Schema.Struct<{
|
|
102
|
+
readonly logo: Schema.optionalKey<Schema.Struct<{
|
|
103
|
+
readonly mediaId: Schema.brand<Schema.String, "MediaId">;
|
|
104
|
+
readonly url: Schema.brand<Schema.NonEmptyString, "SeoUrl">;
|
|
105
|
+
readonly alt: Schema.NonEmptyString;
|
|
106
|
+
}>>;
|
|
107
|
+
readonly image: Schema.optionalKey<Schema.Struct<{
|
|
108
|
+
readonly mediaId: Schema.brand<Schema.String, "MediaId">;
|
|
109
|
+
readonly url: Schema.brand<Schema.NonEmptyString, "SeoUrl">;
|
|
110
|
+
readonly alt: Schema.NonEmptyString;
|
|
111
|
+
}>>;
|
|
112
|
+
readonly telephone: Schema.optionalKey<Schema.NonEmptyString>;
|
|
113
|
+
readonly address: Schema.optionalKey<Schema.Struct<{
|
|
114
|
+
readonly streetAddress: Schema.optionalKey<Schema.NonEmptyString>;
|
|
115
|
+
readonly addressLocality: Schema.optionalKey<Schema.NonEmptyString>;
|
|
116
|
+
readonly addressRegion: Schema.optionalKey<Schema.NonEmptyString>;
|
|
117
|
+
readonly postalCode: Schema.optionalKey<Schema.NonEmptyString>;
|
|
118
|
+
readonly addressCountry: Schema.optionalKey<Schema.NonEmptyString>;
|
|
119
|
+
}>>;
|
|
120
|
+
readonly name: Schema.NonEmptyString;
|
|
121
|
+
readonly url: Schema.optionalKey<Schema.brand<Schema.NonEmptyString, "SeoUrl">>;
|
|
122
|
+
readonly type: Schema.tag<"LocalBusiness">;
|
|
123
|
+
}>]>>;
|
|
124
|
+
}>;
|
|
125
|
+
readonly capabilities: Schema.Struct<{
|
|
126
|
+
readonly structuredDataTypes: Schema.$Array<Schema.Literals<readonly ["WebPage", "Article"]>>;
|
|
127
|
+
readonly identityTypes: Schema.$Array<Schema.Literals<readonly ["Person", "Organization", "LocalBusiness"]>>;
|
|
128
|
+
readonly generatedSocialImageTemplateIds: Schema.$Array<Schema.NonEmptyString>;
|
|
129
|
+
}>;
|
|
130
|
+
}>;
|
|
131
|
+
interface SeoConfiguration extends Schema.Schema.Type<typeof SeoConfiguration> {}
|
|
132
|
+
declare const ResolvedSeo: Schema.Struct<{
|
|
133
|
+
readonly title: Schema.NonEmptyString;
|
|
134
|
+
readonly description: Schema.optionalKey<Schema.NonEmptyString>;
|
|
135
|
+
readonly socialTitle: Schema.NonEmptyString;
|
|
136
|
+
readonly socialDescription: Schema.optionalKey<Schema.NonEmptyString>;
|
|
137
|
+
readonly socialImage: Schema.optionalKey<Schema.Struct<{
|
|
138
|
+
readonly mediaId: Schema.brand<Schema.String, "MediaId">;
|
|
139
|
+
readonly url: Schema.brand<Schema.NonEmptyString, "SeoUrl">;
|
|
140
|
+
readonly alt: Schema.NonEmptyString;
|
|
141
|
+
}>>;
|
|
142
|
+
readonly canonicalUrl: Schema.brand<Schema.NonEmptyString, "SeoUrl">;
|
|
143
|
+
readonly index: Schema.Boolean;
|
|
144
|
+
readonly follow: Schema.Boolean;
|
|
145
|
+
readonly structuredData: Schema.optionalKey<Schema.toTaggedUnion<"type", readonly [Schema.Struct<{
|
|
146
|
+
readonly type: Schema.tag<"WebPage">;
|
|
147
|
+
}>, Schema.Struct<{
|
|
148
|
+
readonly type: Schema.tag<"Article">;
|
|
149
|
+
readonly headline: Schema.optionalKey<Schema.NonEmptyString>;
|
|
150
|
+
readonly datePublished: Schema.optionalKey<Schema.String>;
|
|
151
|
+
readonly dateModified: Schema.optionalKey<Schema.String>;
|
|
152
|
+
}>]>>;
|
|
153
|
+
readonly identity: Schema.optionalKey<Schema.toTaggedUnion<"type", readonly [Schema.Struct<{
|
|
154
|
+
readonly image: Schema.optionalKey<Schema.Struct<{
|
|
155
|
+
readonly mediaId: Schema.brand<Schema.String, "MediaId">;
|
|
156
|
+
readonly url: Schema.brand<Schema.NonEmptyString, "SeoUrl">;
|
|
157
|
+
readonly alt: Schema.NonEmptyString;
|
|
158
|
+
}>>;
|
|
159
|
+
readonly name: Schema.NonEmptyString;
|
|
160
|
+
readonly url: Schema.optionalKey<Schema.brand<Schema.NonEmptyString, "SeoUrl">>;
|
|
161
|
+
readonly type: Schema.tag<"Person">;
|
|
162
|
+
}>, Schema.Struct<{
|
|
163
|
+
readonly logo: Schema.optionalKey<Schema.Struct<{
|
|
164
|
+
readonly mediaId: Schema.brand<Schema.String, "MediaId">;
|
|
165
|
+
readonly url: Schema.brand<Schema.NonEmptyString, "SeoUrl">;
|
|
166
|
+
readonly alt: Schema.NonEmptyString;
|
|
167
|
+
}>>;
|
|
168
|
+
readonly name: Schema.NonEmptyString;
|
|
169
|
+
readonly url: Schema.optionalKey<Schema.brand<Schema.NonEmptyString, "SeoUrl">>;
|
|
170
|
+
readonly type: Schema.tag<"Organization">;
|
|
171
|
+
}>, Schema.Struct<{
|
|
172
|
+
readonly logo: Schema.optionalKey<Schema.Struct<{
|
|
173
|
+
readonly mediaId: Schema.brand<Schema.String, "MediaId">;
|
|
174
|
+
readonly url: Schema.brand<Schema.NonEmptyString, "SeoUrl">;
|
|
175
|
+
readonly alt: Schema.NonEmptyString;
|
|
176
|
+
}>>;
|
|
177
|
+
readonly image: Schema.optionalKey<Schema.Struct<{
|
|
178
|
+
readonly mediaId: Schema.brand<Schema.String, "MediaId">;
|
|
179
|
+
readonly url: Schema.brand<Schema.NonEmptyString, "SeoUrl">;
|
|
180
|
+
readonly alt: Schema.NonEmptyString;
|
|
181
|
+
}>>;
|
|
182
|
+
readonly telephone: Schema.optionalKey<Schema.NonEmptyString>;
|
|
183
|
+
readonly address: Schema.optionalKey<Schema.Struct<{
|
|
184
|
+
readonly streetAddress: Schema.optionalKey<Schema.NonEmptyString>;
|
|
185
|
+
readonly addressLocality: Schema.optionalKey<Schema.NonEmptyString>;
|
|
186
|
+
readonly addressRegion: Schema.optionalKey<Schema.NonEmptyString>;
|
|
187
|
+
readonly postalCode: Schema.optionalKey<Schema.NonEmptyString>;
|
|
188
|
+
readonly addressCountry: Schema.optionalKey<Schema.NonEmptyString>;
|
|
189
|
+
}>>;
|
|
190
|
+
readonly name: Schema.NonEmptyString;
|
|
191
|
+
readonly url: Schema.optionalKey<Schema.brand<Schema.NonEmptyString, "SeoUrl">>;
|
|
192
|
+
readonly type: Schema.tag<"LocalBusiness">;
|
|
193
|
+
}>]>>;
|
|
194
|
+
}>;
|
|
195
|
+
interface ResolvedSeo extends Schema.Schema.Type<typeof ResolvedSeo> {}
|
|
196
|
+
//#endregion
|
|
197
|
+
export { SiteIdentity as i, ResolvedSeo as n, SeoConfiguration as r, DocumentSeo as t };
|
|
198
|
+
//# sourceMappingURL=Seo-402YumpT.d.ts.map
|
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import { n as DocumentPreviewMessage, o as isDocumentPreviewMessage, t as DOCUMENT_PREVIEW_CHANNEL } from "./models-
|
|
2
|
-
import { Effect, Exit, Schedule, Schema, Scope } from "effect";
|
|
1
|
+
import { n as DocumentPreviewMessage, o as isDocumentPreviewMessage, t as DOCUMENT_PREVIEW_CHANNEL } from "./models-BWm1pTAf.js";
|
|
2
|
+
import { Effect, Exit, Result, Schedule, Schema, Scope } from "effect";
|
|
3
3
|
|
|
4
4
|
//#region ../protocol/src/internal/preview/bridge.ts
|
|
5
|
-
/** Owns the preview-site side of the authenticated session handshake. */
|
|
6
5
|
function makePreviewSiteBridge(options) {
|
|
7
6
|
return Effect.acquireRelease(Effect.sync(() => createPreviewSiteBridge(options)), (bridge) => Effect.sync(() => bridge.close())).pipe(Effect.map(({ close: _close, ...bridge }) => bridge));
|
|
8
7
|
}
|
|
@@ -43,11 +42,11 @@ function createPreviewSiteBridge(options) {
|
|
|
43
42
|
};
|
|
44
43
|
}
|
|
45
44
|
function envelope(sessionId, payload) {
|
|
46
|
-
return Schema.
|
|
45
|
+
return Result.getOrThrow(Schema.decodeResult(Schema.toType(DocumentPreviewMessage))({
|
|
47
46
|
channel: DOCUMENT_PREVIEW_CHANNEL,
|
|
48
47
|
sessionId,
|
|
49
48
|
...payload
|
|
50
|
-
});
|
|
49
|
+
}));
|
|
51
50
|
}
|
|
52
51
|
function receivePreviewMessage(event, source, origin, sessionId) {
|
|
53
52
|
if (event.origin !== origin || event.source !== source || !isDocumentPreviewMessage(event.data)) return void 0;
|
|
@@ -59,7 +58,6 @@ function isStudioPreviewMessage(message) {
|
|
|
59
58
|
|
|
60
59
|
//#endregion
|
|
61
60
|
//#region src/runtime/preview/connection.ts
|
|
62
|
-
/** Owns the site-side Effect scope and origin-checked parent-window bridge. */
|
|
63
61
|
async function openSitePreviewConnection(options) {
|
|
64
62
|
const scope = await Effect.runPromise(Scope.make());
|
|
65
63
|
try {
|
|
@@ -91,4 +89,4 @@ async function openSitePreviewConnection(options) {
|
|
|
91
89
|
|
|
92
90
|
//#endregion
|
|
93
91
|
export { openSitePreviewConnection as t };
|
|
94
|
-
//# sourceMappingURL=connection-
|
|
92
|
+
//# sourceMappingURL=connection-B-iz0Y9Y.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"connection-B-iz0Y9Y.js","names":["DocumentPreviewMessageSchema"],"sources":["../../../../protocol/src/internal/preview/bridge.ts","../../../src/runtime/preview/connection.ts"],"sourcesContent":["import type {\n DocumentPreviewMessage,\n PreviewOrigin,\n PreviewSessionId,\n PreviewSitePayload,\n StudioPreviewPayload,\n} from './models'\nimport type { Scope } from 'effect'\nimport { Effect, Result, Schedule, Schema } from 'effect'\nimport {\n DOCUMENT_PREVIEW_CHANNEL,\n DocumentPreviewMessage as DocumentPreviewMessageSchema,\n isDocumentPreviewMessage,\n} from './models'\n\nexport interface PreviewMessageEvent {\n readonly data: unknown\n readonly origin: string\n readonly source: object | null\n}\n\nexport interface PreviewMessageSource {\n readonly addEventListener: (type: 'message', listener: (event: PreviewMessageEvent) => void) => void\n readonly removeEventListener: (type: 'message', listener: (event: PreviewMessageEvent) => void) => void\n}\n\nexport interface PreviewMessageTarget {\n readonly postMessage: (message: DocumentPreviewMessage, targetOrigin: string) => void\n}\n\nexport type PreviewBridgeState = 'closed' | 'connecting' | 'ready'\n\nexport interface PreviewHostBridge {\n readonly reconnect: () => void\n readonly send: (payload: Exclude<StudioPreviewPayload, { readonly type: 'studio:connect' }>) => boolean\n readonly state: () => PreviewBridgeState\n readonly subscribe: (listener: (message: PreviewSitePayload) => void) => () => void\n}\n\nexport interface PreviewSiteBridge {\n readonly send: (payload: Exclude<PreviewSitePayload, { readonly type: 'preview:ready' }>) => boolean\n readonly subscribe: (listener: (message: StudioPreviewPayload) => void) => () => void\n}\n\nexport interface PreviewHostBridgeOptions {\n readonly handshakeIntervalMs?: number\n readonly sessionId: PreviewSessionId\n readonly target: () => PreviewMessageTarget | undefined\n readonly targetOrigin: PreviewOrigin\n readonly view: PreviewMessageSource\n}\n\nexport interface PreviewSiteBridgeOptions {\n readonly parent: PreviewMessageTarget\n readonly parentOrigin: PreviewOrigin\n readonly route: PreviewSitePayload & { readonly type: 'preview:ready' }\n readonly sessionId: PreviewSessionId\n readonly view: PreviewMessageSource\n}\n\nexport function makePreviewHostBridge(\n options: PreviewHostBridgeOptions,\n): Effect.Effect<PreviewHostBridge, never, Scope.Scope> {\n return Effect.acquireRelease(\n Effect.context<never>().pipe(\n Effect.map((context) => createPreviewHostBridge(options, Effect.runForkWith(context))),\n ),\n (bridge) => Effect.sync(() => bridge.close()),\n ).pipe(Effect.map(({ close: _close, ...bridge }) => bridge))\n}\n\nexport function makePreviewSiteBridge(\n options: PreviewSiteBridgeOptions,\n): Effect.Effect<PreviewSiteBridge, never, Scope.Scope> {\n return Effect.acquireRelease(\n Effect.sync(() => createPreviewSiteBridge(options)),\n (bridge) => Effect.sync(() => bridge.close()),\n ).pipe(Effect.map(({ close: _close, ...bridge }) => bridge))\n}\n\nfunction createPreviewHostBridge(options: PreviewHostBridgeOptions, runFork: typeof Effect.runFork) {\n const listeners = new Set<(message: PreviewSitePayload) => void>()\n let retry: ReturnType<typeof Effect.runFork> | undefined\n let state: PreviewBridgeState = 'connecting'\n\n const stopRetry = (): void => {\n if (retry === undefined) return\n retry.interruptUnsafe()\n retry = undefined\n }\n\n const post = (payload: StudioPreviewPayload): boolean => {\n const target = options.target()\n\n if (!target) return false\n target.postMessage(envelope(options.sessionId, payload), options.targetOrigin)\n\n return true\n }\n\n const connect = (): void => {\n post({ type: 'studio:connect' })\n }\n\n const reconnect = (): void => {\n if (state === 'closed') return\n state = 'connecting'\n stopRetry()\n const interval = options.handshakeIntervalMs ?? 250\n retry = runFork(Effect.sync(connect).pipe(Effect.repeat(Schedule.spaced(interval)), Effect.delay(interval)))\n connect()\n }\n\n const receive = (event: PreviewMessageEvent): void => {\n const target = options.target()\n\n if (!target) return\n const message = receivePreviewMessage(event, target, options.targetOrigin, options.sessionId)\n\n if (!message || !isPreviewSiteMessage(message)) return\n\n if (message.type === 'preview:ready') {\n state = 'ready'\n stopRetry()\n }\n\n for (const listener of listeners) listener(message)\n }\n\n const close = (): void => {\n if (state === 'closed') return\n state = 'closed'\n stopRetry()\n options.view.removeEventListener('message', receive)\n listeners.clear()\n }\n\n options.view.addEventListener('message', receive)\n reconnect()\n\n return {\n close,\n reconnect,\n send: (payload: Exclude<StudioPreviewPayload, { readonly type: 'studio:connect' }>) =>\n state === 'ready' && post(payload),\n state: () => state,\n subscribe: (listener: (message: PreviewSitePayload) => void) => {\n listeners.add(listener)\n\n return () => listeners.delete(listener)\n },\n }\n}\n\nfunction createPreviewSiteBridge(options: PreviewSiteBridgeOptions) {\n const listeners = new Set<(message: StudioPreviewPayload) => void>()\n let active = false\n let closed = false\n\n const post = (payload: PreviewSitePayload): boolean => {\n if (!active || closed) return false\n options.parent.postMessage(envelope(options.sessionId, payload), options.parentOrigin)\n\n return true\n }\n\n const receive = (event: PreviewMessageEvent): void => {\n if (closed) return\n const message = receivePreviewMessage(event, options.parent, options.parentOrigin, options.sessionId)\n\n if (!message || !isStudioPreviewMessage(message)) return\n\n if (message.type === 'studio:connect') {\n active = true\n post(options.route)\n }\n\n for (const listener of listeners) listener(message)\n }\n\n const close = (): void => {\n if (closed) return\n closed = true\n active = false\n options.view.removeEventListener('message', receive)\n listeners.clear()\n }\n\n options.view.addEventListener('message', receive)\n\n return {\n close,\n send: post,\n subscribe: (listener: (message: StudioPreviewPayload) => void) => {\n listeners.add(listener)\n\n return () => listeners.delete(listener)\n },\n }\n}\n\nfunction envelope(\n sessionId: PreviewSessionId,\n payload: PreviewSitePayload | StudioPreviewPayload,\n): DocumentPreviewMessage {\n return Result.getOrThrow(\n Schema.decodeResult(Schema.toType(DocumentPreviewMessageSchema))({\n channel: DOCUMENT_PREVIEW_CHANNEL,\n sessionId,\n ...payload,\n }),\n )\n}\n\nfunction receivePreviewMessage(\n event: PreviewMessageEvent,\n source: PreviewMessageTarget,\n origin: PreviewOrigin,\n sessionId: PreviewSessionId,\n): DocumentPreviewMessage | undefined {\n if (event.origin !== origin || event.source !== source || !isDocumentPreviewMessage(event.data)) return undefined\n\n return event.data.sessionId === sessionId ? event.data : undefined\n}\n\nfunction isPreviewSiteMessage(\n message: DocumentPreviewMessage,\n): message is Extract<DocumentPreviewMessage, { readonly type: `preview:${string}` }> {\n return message.type.startsWith('preview:')\n}\n\nfunction isStudioPreviewMessage(\n message: DocumentPreviewMessage,\n): message is Extract<DocumentPreviewMessage, { readonly type: `studio:${string}` }> {\n return message.type.startsWith('studio:')\n}\n","import type { PublicPath } from '@internal/protocol/Documents'\nimport type { PreviewOrigin, PreviewSessionId, PreviewSiteBridge } from '@internal/protocol/Preview'\nimport { makePreviewSiteBridge } from '@internal/protocol/Preview'\nimport { Effect, Exit, Scope } from 'effect'\n\nexport interface SitePreviewConnection extends PreviewSiteBridge {\n readonly close: () => Promise<void>\n}\n\nexport async function openSitePreviewConnection(options: {\n readonly editorOrigin: PreviewOrigin\n readonly route: PublicPath\n readonly sessionId: PreviewSessionId\n}): Promise<SitePreviewConnection> {\n const scope = await Effect.runPromise(Scope.make())\n\n try {\n const bridge = await Effect.runPromise(\n makePreviewSiteBridge({\n parent: window.parent,\n parentOrigin: options.editorOrigin,\n route: { path: options.route, type: 'preview:ready' },\n sessionId: options.sessionId,\n view: window,\n }).pipe(Effect.provideService(Scope.Scope, scope)),\n )\n\n let closed = false\n\n return {\n async close() {\n if (closed) return\n closed = true\n await Effect.runPromise(Scope.close(scope, Exit.void))\n },\n send: bridge.send,\n subscribe: bridge.subscribe,\n }\n } catch (cause) {\n await Effect.runPromise(Scope.close(scope, Exit.fail(cause)))\n throw cause\n }\n}\n"],"mappings":";;;;AAuEA,SAAgB,sBACd,SACsD;CACtD,OAAO,OAAO,eACZ,OAAO,WAAW,wBAAwB,OAAO,CAAC,IACjD,WAAW,OAAO,WAAW,OAAO,MAAM,CAAC,CAC9C,CAAC,CAAC,KAAK,OAAO,KAAK,EAAE,OAAO,QAAQ,GAAG,aAAa,MAAM,CAAC;AAC7D;AA4EA,SAAS,wBAAwB,SAAmC;CAClE,MAAM,4BAAY,IAAI,IAA6C;CACnE,IAAI,SAAS;CACb,IAAI,SAAS;CAEb,MAAM,QAAQ,YAAyC;EACrD,IAAI,CAAC,UAAU,QAAQ,OAAO;EAC9B,QAAQ,OAAO,YAAY,SAAS,QAAQ,WAAW,OAAO,GAAG,QAAQ,YAAY;EAErF,OAAO;CACT;CAEA,MAAM,WAAW,UAAqC;EACpD,IAAI,QAAQ;EACZ,MAAM,UAAU,sBAAsB,OAAO,QAAQ,QAAQ,QAAQ,cAAc,QAAQ,SAAS;EAEpG,IAAI,CAAC,WAAW,CAAC,uBAAuB,OAAO,GAAG;EAElD,IAAI,QAAQ,SAAS,kBAAkB;GACrC,SAAS;GACT,KAAK,QAAQ,KAAK;EACpB;EAEA,KAAK,MAAM,YAAY,WAAW,SAAS,OAAO;CACpD;CAEA,MAAM,cAAoB;EACxB,IAAI,QAAQ;EACZ,SAAS;EACT,SAAS;EACT,QAAQ,KAAK,oBAAoB,WAAW,OAAO;EACnD,UAAU,MAAM;CAClB;CAEA,QAAQ,KAAK,iBAAiB,WAAW,OAAO;CAEhD,OAAO;EACL;EACA,MAAM;EACN,YAAY,aAAsD;GAChE,UAAU,IAAI,QAAQ;GAEtB,aAAa,UAAU,OAAO,QAAQ;EACxC;CACF;AACF;AAEA,SAAS,SACP,WACA,SACwB;CACxB,OAAO,OAAO,WACZ,OAAO,aAAa,OAAO,OAAOA,sBAA4B,CAAC,CAAC,CAAC;EAC/D,SAAS;EACT;EACA,GAAG;CACL,CAAC,CACH;AACF;AAEA,SAAS,sBACP,OACA,QACA,QACA,WACoC;CACpC,IAAI,MAAM,WAAW,UAAU,MAAM,WAAW,UAAU,CAAC,yBAAyB,MAAM,IAAI,GAAG,OAAO;CAExG,OAAO,MAAM,KAAK,cAAc,YAAY,MAAM,OAAO;AAC3D;AAQA,SAAS,uBACP,SACmF;CACnF,OAAO,QAAQ,KAAK,WAAW,SAAS;AAC1C;;;;AClOA,eAAsB,0BAA0B,SAIb;CACjC,MAAM,QAAQ,MAAM,OAAO,WAAW,MAAM,KAAK,CAAC;CAElD,IAAI;EACF,MAAM,SAAS,MAAM,OAAO,WAC1B,sBAAsB;GACpB,QAAQ,OAAO;GACf,cAAc,QAAQ;GACtB,OAAO;IAAE,MAAM,QAAQ;IAAO,MAAM;GAAgB;GACpD,WAAW,QAAQ;GACnB,MAAM;EACR,CAAC,CAAC,CAAC,KAAK,OAAO,eAAe,MAAM,OAAO,KAAK,CAAC,CACnD;EAEA,IAAI,SAAS;EAEb,OAAO;GACL,MAAM,QAAQ;IACZ,IAAI,QAAQ;IACZ,SAAS;IACT,MAAM,OAAO,WAAW,MAAM,MAAM,OAAO,KAAK,IAAI,CAAC;GACvD;GACA,MAAM,OAAO;GACb,WAAW,OAAO;EACpB;CACF,SAAS,OAAO;EACd,MAAM,OAAO,WAAW,MAAM,MAAM,OAAO,KAAK,KAAK,KAAK,CAAC,CAAC;EAC5D,MAAM;CACR;AACF"}
|