@phtngyn/cms 0.1.0-beta.1 → 0.1.0-beta.3
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 +212 -12
- package/bin/cms.mjs +2 -0
- package/package.json +30 -15
- package/src/{Configuration-DyKo0sLS.js → Configuration-CDMYfTre.js} +26 -147
- package/src/Configuration-CDMYfTre.js.map +1 -0
- package/src/Configuration.d.ts +24 -8
- package/src/Configuration.js +0 -1
- package/src/Configuration.js.map +1 -1
- package/src/ContentTransfer-C3Av9sWz.js +53 -0
- package/src/ContentTransfer-C3Av9sWz.js.map +1 -0
- package/src/{DocumentEngine-DYObwMDY.js → DocumentEngine-J7g-emdf.js} +75 -27
- package/src/DocumentEngine-J7g-emdf.js.map +1 -0
- package/src/DocumentModel.d.ts +8 -9
- 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-Dj6NuW66.js +367 -0
- package/src/Forms-Dj6NuW66.js.map +1 -0
- package/src/Forms.d.ts +51 -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.d.ts +20 -0
- package/src/I18n.js +1 -0
- package/src/Module.js +59 -14
- package/src/Module.js.map +1 -1
- package/src/S3MediaObjects-CpPSzJto.js +2777 -0
- package/src/S3MediaObjects-CpPSzJto.js.map +1 -0
- package/src/Seo-402YumpT.d.ts +198 -0
- package/src/cli/content.js +258 -0
- package/src/cli/content.js.map +1 -0
- package/src/cli.js +71 -0
- package/src/cli.js.map +1 -0
- package/src/{connection-CBTY-TzB.js → connection-CBAy2qGy.js} +5 -7
- package/src/connection-CBAy2qGy.js.map +1 -0
- package/src/{installation-DeuBiFRE.js → installation-CNfIriVm.js} +1007 -2246
- package/src/installation-CNfIriVm.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 +26 -17
- package/src/internal/configuration.js.map +1 -1
- package/src/internal/document-model.js +69 -21
- 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-BTqdfIzX.js} +2 -3
- package/src/location-BTqdfIzX.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-B4IoTmp7.js} +3 -2
- package/src/models-B4IoTmp7.js.map +1 -0
- package/src/{models-BkMgeaOL.js → models-Bah5B3bT.js} +205 -51
- package/src/models-Bah5B3bT.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 +28 -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 +59 -0
- package/src/runtime/delivery/useCmsDocumentSeo.js +101 -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 +190 -0
- package/src/runtime/forms/useCmsForm.js.map +1 -0
- package/src/runtime/i18n/translator.js +51 -0
- package/src/runtime/i18n/translator.js.map +1 -0
- package/src/runtime/i18n/useCmsI18n.d.ts +11 -0
- package/src/runtime/i18n/useCmsI18n.js +37 -0
- package/src/runtime/i18n/useCmsI18n.js.map +1 -0
- package/src/runtime/installation.js +1 -1
- package/src/runtime/plugin.js +3 -3
- 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-b2CSXgMt.js} +12 -7
- package/src/store-b2CSXgMt.js.map +1 -0
- package/studio/{CreateDocumentDialog--L9lTfx6.js → CreateDocumentDialog-GGey1uBc.js} +44 -44
- package/studio/{collaboration-DUuu678R.js → collaboration-DcK2F6v9.js} +7 -6
- package/studio/{documentPlanning-BXX04Woe.js → documentPlanning-DRErYmBU.js} +7340 -6469
- 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
|
@@ -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
|
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
import { t as CMS_AUTHENTICATION_PATH, u as STUDIO_API_PATH } from "../HttpPaths-c9nLZ9H2.js";
|
|
2
|
+
import { a as ContentSource, i as ContentSnapshot, n as ContentApplyResult, r as ContentPlan } from "../ContentTransfer-C3Av9sWz.js";
|
|
3
|
+
import { Config, Console, Crypto, Effect, FileSystem, Option, Path, Redacted, Result, Schema } from "effect";
|
|
4
|
+
import { Cookies, HttpClient, HttpClientRequest } from "effect/unstable/http";
|
|
5
|
+
import { createTwoFilesPatch } from "diff";
|
|
6
|
+
import { CliError, Prompt } from "effect/unstable/cli";
|
|
7
|
+
|
|
8
|
+
//#region src/cli/content.ts
|
|
9
|
+
const IndexEntry = Schema.Struct({
|
|
10
|
+
sourcePath: ContentSource.fields.sourcePath,
|
|
11
|
+
published: Schema.Boolean,
|
|
12
|
+
sha256: Schema.String.check(Schema.isPattern(/^[a-f0-9]{64}$/u))
|
|
13
|
+
});
|
|
14
|
+
const IndexMetadata = Schema.Struct({
|
|
15
|
+
version: Schema.Literal(1),
|
|
16
|
+
sources: Schema.Array(IndexEntry)
|
|
17
|
+
});
|
|
18
|
+
const ContentIndex = Schema.Struct({
|
|
19
|
+
...IndexMetadata.fields,
|
|
20
|
+
exportSha256: IndexEntry.fields.sha256
|
|
21
|
+
});
|
|
22
|
+
function userError(message) {
|
|
23
|
+
return new CliError.UserError({
|
|
24
|
+
cause: new Error(message),
|
|
25
|
+
userMessage: message
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
const hash = Effect.fn("CmsCli.content.hash")(function* (markdown) {
|
|
29
|
+
const digest = yield* (yield* Crypto.Crypto).digest("SHA-256", new TextEncoder().encode(markdown));
|
|
30
|
+
return Array.from(digest, (byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
31
|
+
});
|
|
32
|
+
const metadataHash = Effect.fn("CmsCli.content.metadataHash")(function* (metadata) {
|
|
33
|
+
return yield* hash(yield* Schema.encodeEffect(Schema.fromJsonString(IndexMetadata))(metadata));
|
|
34
|
+
});
|
|
35
|
+
const resolveConnection = Effect.fn("CmsCli.resolveConnection")(function* (options) {
|
|
36
|
+
const configuredUrl = options.url || (yield* Config.String("CMS_URL").pipe(Config.withDefault("")));
|
|
37
|
+
const configuredEmail = options.email || (yield* Config.String("CMS_EMAIL").pipe(Config.withDefault("")));
|
|
38
|
+
const rawUrl = configuredUrl || (yield* Prompt.String({ message: "CMS URL" }));
|
|
39
|
+
const email = configuredEmail || (yield* Prompt.String({ message: "Administrator email" }));
|
|
40
|
+
if (!rawUrl || !email) return yield* userError("CMS URL and administrator email are required.");
|
|
41
|
+
const url = yield* Effect.try({
|
|
42
|
+
try: () => new URL(rawUrl),
|
|
43
|
+
catch: () => userError("CMS URL is invalid.")
|
|
44
|
+
});
|
|
45
|
+
if (url.protocol !== "https:" && !(url.protocol === "http:" && [
|
|
46
|
+
"localhost",
|
|
47
|
+
"127.0.0.1",
|
|
48
|
+
"[::1]"
|
|
49
|
+
].includes(url.hostname))) throw userError("Use HTTPS for CMS credentials; HTTP is allowed only on localhost.");
|
|
50
|
+
if (url.username || url.password || url.search || url.hash) throw userError("CMS URL must be an origin without credentials, query, or fragment.");
|
|
51
|
+
return {
|
|
52
|
+
url: new URL(url.origin),
|
|
53
|
+
email
|
|
54
|
+
};
|
|
55
|
+
});
|
|
56
|
+
const SignIn = Schema.Struct({
|
|
57
|
+
email: Schema.String,
|
|
58
|
+
password: Schema.String
|
|
59
|
+
});
|
|
60
|
+
const ApiError = Schema.Struct({ message: Schema.optionalKey(Schema.String) });
|
|
61
|
+
const connect = Effect.fn("CmsCli.connect")(function* (options) {
|
|
62
|
+
const { url, email } = yield* resolveConnection(options);
|
|
63
|
+
const configured = yield* Config.Redacted("CMS_PASSWORD").pipe(Config.option);
|
|
64
|
+
const password = Option.isSome(configured) ? configured.value : yield* Prompt.Password({ message: `Password for ${email} at ${url.origin}` });
|
|
65
|
+
const client = yield* HttpClient.HttpClient;
|
|
66
|
+
const signInRequest = yield* HttpClientRequest.post(new URL(`${CMS_AUTHENTICATION_PATH}/sign-in/email`, url)).pipe(HttpClientRequest.setHeader("accept", "application/json"), HttpClientRequest.setHeader("origin", url.origin), HttpClientRequest.schemaBodyJson(SignIn)({
|
|
67
|
+
email,
|
|
68
|
+
password: Redacted.value(password)
|
|
69
|
+
}));
|
|
70
|
+
const response = yield* client.execute(signInRequest);
|
|
71
|
+
if (response.status < 200 || response.status >= 300) return yield* userError(`CMS sign-in failed (${response.status}).`);
|
|
72
|
+
const cookie = Cookies.toCookieHeader(response.cookies);
|
|
73
|
+
if (!cookie) return yield* userError("CMS sign-in did not return a session cookie.");
|
|
74
|
+
return {
|
|
75
|
+
url,
|
|
76
|
+
cookie
|
|
77
|
+
};
|
|
78
|
+
});
|
|
79
|
+
const request = Effect.fn("CmsCli.request")(function* (session, path, body) {
|
|
80
|
+
const client = yield* HttpClient.HttpClient;
|
|
81
|
+
const url = new URL(`${STUDIO_API_PATH}/content/${path}`, session.url);
|
|
82
|
+
const base = (body === void 0 ? HttpClientRequest.get(url) : HttpClientRequest.post(url)).pipe(HttpClientRequest.setHeader("accept", "application/json"), HttpClientRequest.setHeader("cookie", session.cookie));
|
|
83
|
+
const prepared = body === void 0 ? base : yield* HttpClientRequest.bodyJson(base, body);
|
|
84
|
+
const response = yield* client.execute(prepared);
|
|
85
|
+
const payload = yield* response.json;
|
|
86
|
+
if (response.status < 200 || response.status >= 300) {
|
|
87
|
+
const decoded = Schema.decodeUnknownResult(ApiError)(payload);
|
|
88
|
+
return yield* userError(`CMS content ${path} failed: ${Result.isSuccess(decoded) ? decoded.success.message ?? `HTTP ${response.status}` : `HTTP ${response.status}`}`);
|
|
89
|
+
}
|
|
90
|
+
return payload;
|
|
91
|
+
});
|
|
92
|
+
function contentPath(directory, sourcePath, path) {
|
|
93
|
+
const resolved = path.resolve(directory, sourcePath);
|
|
94
|
+
if (!resolved.startsWith(`${directory}${path.sep}`)) throw userError(`Unsafe content path: ${sourcePath}`);
|
|
95
|
+
return resolved;
|
|
96
|
+
}
|
|
97
|
+
const readIndex = Effect.fn("CmsCli.readIndex")(function* (directory) {
|
|
98
|
+
const fileSystem = yield* FileSystem.FileSystem;
|
|
99
|
+
const indexPath = (yield* Path.Path).join(directory, ".cms-content.json");
|
|
100
|
+
if (!(yield* fileSystem.exists(indexPath))) return void 0;
|
|
101
|
+
return yield* Schema.decodeEffect(Schema.fromJsonString(ContentIndex))(yield* fileSystem.readFileString(indexPath));
|
|
102
|
+
});
|
|
103
|
+
const readSources = Effect.fn("CmsCli.readSources")(function* (directory) {
|
|
104
|
+
const fileSystem = yield* FileSystem.FileSystem;
|
|
105
|
+
const path = yield* Path.Path;
|
|
106
|
+
const root = path.resolve(directory);
|
|
107
|
+
const index = yield* readIndex(root);
|
|
108
|
+
if (!index) {
|
|
109
|
+
const paths = yield* markdownFiles(root);
|
|
110
|
+
if (paths.length === 0) return yield* userError(`No Markdown files found in ${root}.`);
|
|
111
|
+
return yield* Effect.forEach(paths, (file) => Effect.gen(function* () {
|
|
112
|
+
const sourcePath = path.relative(root, file).replaceAll("\\", "/");
|
|
113
|
+
const markdown = yield* fileSystem.readFileString(file);
|
|
114
|
+
return yield* Schema.decodeEffect(ContentSource)({
|
|
115
|
+
sourcePath,
|
|
116
|
+
markdown,
|
|
117
|
+
published: true
|
|
118
|
+
});
|
|
119
|
+
}));
|
|
120
|
+
}
|
|
121
|
+
const seen = /* @__PURE__ */ new Set();
|
|
122
|
+
const sources = [];
|
|
123
|
+
for (const entry of index.sources) {
|
|
124
|
+
if (seen.has(entry.sourcePath)) return yield* userError(`Duplicate source path in index: ${entry.sourcePath}`);
|
|
125
|
+
seen.add(entry.sourcePath);
|
|
126
|
+
const markdown = yield* fileSystem.readFileString(contentPath(root, entry.sourcePath, path));
|
|
127
|
+
sources.push(ContentSource.make({
|
|
128
|
+
sourcePath: entry.sourcePath,
|
|
129
|
+
markdown,
|
|
130
|
+
published: entry.published
|
|
131
|
+
}));
|
|
132
|
+
}
|
|
133
|
+
return sources;
|
|
134
|
+
});
|
|
135
|
+
function markdownFiles(directory) {
|
|
136
|
+
return Effect.gen(function* () {
|
|
137
|
+
const fileSystem = yield* FileSystem.FileSystem;
|
|
138
|
+
const path = yield* Path.Path;
|
|
139
|
+
const names = yield* fileSystem.readDirectory(directory);
|
|
140
|
+
return (yield* Effect.forEach(names, (name) => Effect.gen(function* () {
|
|
141
|
+
const file = path.join(directory, name);
|
|
142
|
+
const info = yield* fileSystem.stat(file);
|
|
143
|
+
if (info.type === "Directory") return yield* markdownFiles(file);
|
|
144
|
+
return info.type === "File" && [".md", ".mdc"].includes(path.extname(file)) ? [file] : [];
|
|
145
|
+
}))).flat().sort((left, right) => left.localeCompare(right));
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
const exportContent = Effect.fn("CmsCli.content.export")(function* (connection, directory) {
|
|
149
|
+
const fileSystem = yield* FileSystem.FileSystem;
|
|
150
|
+
const path = yield* Path.Path;
|
|
151
|
+
const root = path.resolve(directory);
|
|
152
|
+
const session = yield* connect(connection);
|
|
153
|
+
const snapshot = yield* Schema.decodeUnknownEffect(ContentSnapshot)(yield* request(session, "snapshot"));
|
|
154
|
+
const previous = yield* readIndex(root);
|
|
155
|
+
const oldEntries = new Map(previous?.sources.map((entry) => [entry.sourcePath, entry]));
|
|
156
|
+
if (previous && (yield* metadataHash({
|
|
157
|
+
version: previous.version,
|
|
158
|
+
sources: previous.sources
|
|
159
|
+
})) !== previous.exportSha256) return yield* userError(`Local edits in ${path.join(root, ".cms-content.json")}; review them before exporting again.`);
|
|
160
|
+
for (const source of snapshot.sources) {
|
|
161
|
+
const file = contentPath(root, source.sourcePath, path);
|
|
162
|
+
if (!(yield* fileSystem.exists(file))) continue;
|
|
163
|
+
const local = yield* fileSystem.readFileString(file);
|
|
164
|
+
const old = oldEntries.get(source.sourcePath);
|
|
165
|
+
if (old ? (yield* hash(local)) !== old.sha256 : local !== source.markdown) return yield* userError(`Local edits in ${file}; review them before exporting again.`);
|
|
166
|
+
}
|
|
167
|
+
yield* fileSystem.makeDirectory(root, { recursive: true });
|
|
168
|
+
for (const source of snapshot.sources) {
|
|
169
|
+
const file = contentPath(root, source.sourcePath, path);
|
|
170
|
+
yield* fileSystem.makeDirectory(path.dirname(file), { recursive: true });
|
|
171
|
+
yield* fileSystem.writeFileString(file, source.markdown);
|
|
172
|
+
}
|
|
173
|
+
const metadata = {
|
|
174
|
+
version: 1,
|
|
175
|
+
sources: yield* Effect.forEach(snapshot.sources, (source) => hash(source.markdown).pipe(Effect.map((sha256) => ({
|
|
176
|
+
sourcePath: source.sourcePath,
|
|
177
|
+
published: source.published,
|
|
178
|
+
sha256
|
|
179
|
+
}))))
|
|
180
|
+
};
|
|
181
|
+
const index = ContentIndex.make({
|
|
182
|
+
...metadata,
|
|
183
|
+
exportSha256: yield* metadataHash(metadata)
|
|
184
|
+
});
|
|
185
|
+
yield* fileSystem.writeFileString(path.join(root, ".cms-content.json"), `${yield* Schema.encodeEffect(Schema.fromJsonString(ContentIndex))(index)}\n`);
|
|
186
|
+
yield* Console.log(`Exported ${index.sources.length} documents to ${root}`);
|
|
187
|
+
});
|
|
188
|
+
const plan = Effect.fn("CmsCli.content.plan")(function* (session, sources, options) {
|
|
189
|
+
return yield* Schema.decodeUnknownEffect(ContentPlan)(yield* request(session, "plan", {
|
|
190
|
+
sources,
|
|
191
|
+
...options
|
|
192
|
+
}));
|
|
193
|
+
});
|
|
194
|
+
function printPlan(value) {
|
|
195
|
+
return Effect.gen(function* () {
|
|
196
|
+
for (const entry of value.entries) yield* Console.log(`${entry.action.padEnd(9)} ${entry.sourcePath}`);
|
|
197
|
+
for (const issue of value.issues) yield* Console.error(`${issue.severity}: ${issue.sourcePath ?? ""} ${issue.message}`);
|
|
198
|
+
yield* Console.log(value.valid ? `Ready at generation ${value.generation}` : "Plan has conflicts or validation errors.");
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
const preparePlan = Effect.fn("CmsCli.content.preparePlan")(function* (connection, directory, options) {
|
|
202
|
+
const sources = yield* readSources(directory);
|
|
203
|
+
const session = yield* connect(connection);
|
|
204
|
+
const value = yield* plan(session, sources, options);
|
|
205
|
+
yield* printPlan(value);
|
|
206
|
+
if (!value.valid) return yield* userError("Content plan is not ready to apply.");
|
|
207
|
+
return {
|
|
208
|
+
session,
|
|
209
|
+
sources,
|
|
210
|
+
value
|
|
211
|
+
};
|
|
212
|
+
});
|
|
213
|
+
const planContent = Effect.fn("CmsCli.content.planCommand")(function* (connection, directory, options) {
|
|
214
|
+
yield* preparePlan(connection, directory, options);
|
|
215
|
+
});
|
|
216
|
+
const diffContent = Effect.fn("CmsCli.content.diff")(function* (connection, directory) {
|
|
217
|
+
const local = yield* readSources(directory);
|
|
218
|
+
const session = yield* connect(connection);
|
|
219
|
+
const comparison = describeContentDiff(local, (yield* Schema.decodeUnknownEffect(ContentSnapshot)(yield* request(session, "snapshot"))).sources);
|
|
220
|
+
for (const line of comparison.lines) yield* Console.log(line);
|
|
221
|
+
yield* Console.log(`${comparison.changed} local document${comparison.changed === 1 ? " differs" : "s differ"} from the CMS.`);
|
|
222
|
+
});
|
|
223
|
+
function describeContentDiff(local, remote) {
|
|
224
|
+
const remoteByPath = new Map(remote.map((source) => [source.sourcePath, source]));
|
|
225
|
+
const localPaths = new Set(local.map((source) => source.sourcePath));
|
|
226
|
+
const lines = [];
|
|
227
|
+
let changed = 0;
|
|
228
|
+
for (const source of local) {
|
|
229
|
+
const current = remoteByPath.get(source.sourcePath);
|
|
230
|
+
const markdownChanged = current?.markdown !== source.markdown;
|
|
231
|
+
const publicationChanged = current !== void 0 && current.published !== source.published;
|
|
232
|
+
if (!markdownChanged && !publicationChanged) continue;
|
|
233
|
+
if (markdownChanged) {
|
|
234
|
+
const patch = createTwoFilesPatch(`remote/${source.sourcePath}`, `local/${source.sourcePath}`, current?.markdown ?? "", source.markdown);
|
|
235
|
+
lines.push(patch.trimEnd());
|
|
236
|
+
}
|
|
237
|
+
if (publicationChanged) lines.push(`Publication ${source.sourcePath}: CMS ${current.published ? "published" : "draft"}, local ${source.published ? "published (use --publish to apply)" : "draft (import keeps existing publication)"}`);
|
|
238
|
+
changed++;
|
|
239
|
+
}
|
|
240
|
+
for (const source of remote) if (!localPaths.has(source.sourcePath)) lines.push(`Remote only: ${source.sourcePath}`);
|
|
241
|
+
return {
|
|
242
|
+
lines,
|
|
243
|
+
changed
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
const applyContent = Effect.fn("CmsCli.content.apply")(function* (connection, directory, options) {
|
|
247
|
+
const { session, sources, value } = yield* preparePlan(connection, directory, options);
|
|
248
|
+
const result = yield* Schema.decodeUnknownEffect(ContentApplyResult)(yield* request(session, "apply", {
|
|
249
|
+
sources,
|
|
250
|
+
...options,
|
|
251
|
+
expectedGeneration: value.generation
|
|
252
|
+
}));
|
|
253
|
+
yield* Console.log(`Applied: ${result.created} created, ${result.updated} updated, ${result.published} published, ${result.unchanged} unchanged.`);
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
//#endregion
|
|
257
|
+
export { applyContent, connect, describeContentDiff, diffContent, exportContent, planContent, readSources };
|
|
258
|
+
//# sourceMappingURL=content.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"content.js","names":["ContentSourceSchema"],"sources":["../../../../src/cli/content.ts"],"sourcesContent":["import type { ContentSource } from '@internal/protocol/ContentTransfer'\nimport {\n ContentApplyResult,\n ContentPlan,\n ContentSnapshot,\n ContentSource as ContentSourceSchema,\n} from '@internal/protocol/ContentTransfer'\nimport type { ContentApplyInput, ContentTransferInput } from '@internal/protocol/ContentTransfer'\nimport { CMS_AUTHENTICATION_PATH, STUDIO_API_PATH } from '@internal/protocol/HttpPaths'\nimport { Config, Console, Crypto, Effect, FileSystem, Option, Path, Redacted, Result, Schema } from 'effect'\nimport type { PlatformError } from 'effect'\nimport { CliError, Prompt } from 'effect/unstable/cli'\nimport { Cookies, HttpClient, HttpClientRequest } from 'effect/unstable/http'\nimport { createTwoFilesPatch } from 'diff'\n\nconst IndexEntry = Schema.Struct({\n sourcePath: ContentSourceSchema.fields.sourcePath,\n published: Schema.Boolean,\n sha256: Schema.String.check(Schema.isPattern(/^[a-f0-9]{64}$/u)),\n})\n\nconst IndexMetadata = Schema.Struct({ version: Schema.Literal(1), sources: Schema.Array(IndexEntry) })\n\nconst ContentIndex = Schema.Struct({ ...IndexMetadata.fields, exportSha256: IndexEntry.fields.sha256 })\n\ntype ContentIndex = typeof ContentIndex.Type\n\nexport interface ConnectionOptions {\n readonly url: string\n readonly email: string\n}\n\nexport interface ImportOptions {\n readonly overwrite: boolean\n readonly publish: boolean\n}\n\nfunction userError(message: string) {\n return new CliError.UserError({ cause: new Error(message), userMessage: message })\n}\n\nconst hash = Effect.fn('CmsCli.content.hash')(function* (markdown: string) {\n const crypto = yield* Crypto.Crypto\n const digest = yield* crypto.digest('SHA-256', new TextEncoder().encode(markdown))\n\n return Array.from(digest, (byte) => byte.toString(16).padStart(2, '0')).join('')\n})\n\nconst metadataHash = Effect.fn('CmsCli.content.metadataHash')(function* (metadata: typeof IndexMetadata.Type) {\n return yield* hash(yield* Schema.encodeEffect(Schema.fromJsonString(IndexMetadata))(metadata))\n})\n\nconst resolveConnection = Effect.fn('CmsCli.resolveConnection')(function* (options: ConnectionOptions) {\n const configuredUrl = options.url || (yield* Config.String('CMS_URL').pipe(Config.withDefault('')))\n const configuredEmail = options.email || (yield* Config.String('CMS_EMAIL').pipe(Config.withDefault('')))\n const rawUrl = configuredUrl || (yield* Prompt.String({ message: 'CMS URL' }))\n const email = configuredEmail || (yield* Prompt.String({ message: 'Administrator email' }))\n\n if (!rawUrl || !email) return yield* userError('CMS URL and administrator email are required.')\n\n const url = yield* Effect.try({ try: () => new URL(rawUrl), catch: () => userError('CMS URL is invalid.') })\n\n if (\n url.protocol !== 'https:' &&\n !(url.protocol === 'http:' && ['localhost', '127.0.0.1', '[::1]'].includes(url.hostname))\n )\n throw userError('Use HTTPS for CMS credentials; HTTP is allowed only on localhost.')\n\n if (url.username || url.password || url.search || url.hash)\n throw userError('CMS URL must be an origin without credentials, query, or fragment.')\n\n return { url: new URL(url.origin), email }\n})\n\ninterface Session {\n readonly url: URL\n readonly cookie: string\n}\n\nconst SignIn = Schema.Struct({ email: Schema.String, password: Schema.String })\n\nconst ApiError = Schema.Struct({ message: Schema.optionalKey(Schema.String) })\n\nexport const connect = Effect.fn('CmsCli.connect')(function* (options: ConnectionOptions) {\n const { url, email } = yield* resolveConnection(options)\n\n const configured = yield* Config.Redacted('CMS_PASSWORD').pipe(Config.option)\n\n const password = Option.isSome(configured)\n ? configured.value\n : yield* Prompt.Password({ message: `Password for ${email} at ${url.origin}` })\n\n const client = yield* HttpClient.HttpClient\n\n const signInRequest = yield* HttpClientRequest.post(new URL(`${CMS_AUTHENTICATION_PATH}/sign-in/email`, url)).pipe(\n HttpClientRequest.setHeader('accept', 'application/json'),\n HttpClientRequest.setHeader('origin', url.origin),\n HttpClientRequest.schemaBodyJson(SignIn)({ email, password: Redacted.value(password) }),\n )\n\n const response = yield* client.execute(signInRequest)\n\n if (response.status < 200 || response.status >= 300)\n return yield* userError(`CMS sign-in failed (${response.status}).`)\n\n const cookie = Cookies.toCookieHeader(response.cookies)\n\n if (!cookie) return yield* userError('CMS sign-in did not return a session cookie.')\n\n return { url, cookie } satisfies Session\n})\n\nconst request = Effect.fn('CmsCli.request')(function* (\n session: Session,\n path: string,\n body?: ContentTransferInput | ContentApplyInput,\n) {\n const client = yield* HttpClient.HttpClient\n const url = new URL(`${STUDIO_API_PATH}/content/${path}`, session.url)\n\n const base = (body === undefined ? HttpClientRequest.get(url) : HttpClientRequest.post(url)).pipe(\n HttpClientRequest.setHeader('accept', 'application/json'),\n HttpClientRequest.setHeader('cookie', session.cookie),\n )\n\n const prepared = body === undefined ? base : yield* HttpClientRequest.bodyJson(base, body)\n const response = yield* client.execute(prepared)\n\n const payload = yield* response.json\n\n if (response.status < 200 || response.status >= 300) {\n const decoded = Schema.decodeUnknownResult(ApiError)(payload)\n\n const detail = Result.isSuccess(decoded)\n ? (decoded.success.message ?? `HTTP ${response.status}`)\n : `HTTP ${response.status}`\n\n return yield* userError(`CMS content ${path} failed: ${detail}`)\n }\n\n return payload\n})\n\nfunction contentPath(directory: string, sourcePath: string, path: Path.Path): string {\n const resolved = path.resolve(directory, sourcePath)\n\n if (!resolved.startsWith(`${directory}${path.sep}`)) throw userError(`Unsafe content path: ${sourcePath}`)\n\n return resolved\n}\n\nconst readIndex = Effect.fn('CmsCli.readIndex')(function* (directory: string) {\n const fileSystem = yield* FileSystem.FileSystem\n const path = yield* Path.Path\n const indexPath = path.join(directory, '.cms-content.json')\n\n if (!(yield* fileSystem.exists(indexPath))) return undefined\n\n return yield* Schema.decodeEffect(Schema.fromJsonString(ContentIndex))(yield* fileSystem.readFileString(indexPath))\n})\n\nexport const readSources = Effect.fn('CmsCli.readSources')(function* (directory: string) {\n const fileSystem = yield* FileSystem.FileSystem\n const path = yield* Path.Path\n const root = path.resolve(directory)\n const index = yield* readIndex(root)\n\n if (!index) {\n const paths = yield* markdownFiles(root)\n\n if (paths.length === 0) return yield* userError(`No Markdown files found in ${root}.`)\n\n return yield* Effect.forEach(paths, (file) =>\n Effect.gen(function* () {\n const sourcePath = path.relative(root, file).replaceAll('\\\\', '/')\n const markdown = yield* fileSystem.readFileString(file)\n\n return yield* Schema.decodeEffect(ContentSourceSchema)({ sourcePath, markdown, published: true })\n }),\n )\n }\n\n const seen = new Set<string>()\n const sources: ContentSource[] = []\n\n for (const entry of index.sources) {\n if (seen.has(entry.sourcePath)) return yield* userError(`Duplicate source path in index: ${entry.sourcePath}`)\n seen.add(entry.sourcePath)\n const markdown = yield* fileSystem.readFileString(contentPath(root, entry.sourcePath, path))\n sources.push(ContentSourceSchema.make({ sourcePath: entry.sourcePath, markdown, published: entry.published }))\n }\n\n return sources\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 file = path.join(directory, name)\n const info = yield* fileSystem.stat(file)\n\n if (info.type === 'Directory') return yield* markdownFiles(file)\n\n return info.type === 'File' && ['.md', '.mdc'].includes(path.extname(file)) ? [file] : []\n }),\n )\n\n return nested.flat().sort((left, right) => left.localeCompare(right))\n })\n}\n\nexport const exportContent = Effect.fn('CmsCli.content.export')(function* (\n connection: ConnectionOptions,\n directory: string,\n) {\n const fileSystem = yield* FileSystem.FileSystem\n const path = yield* Path.Path\n const root = path.resolve(directory)\n const session = yield* connect(connection)\n const snapshot = yield* Schema.decodeUnknownEffect(ContentSnapshot)(yield* request(session, 'snapshot'))\n const previous = yield* readIndex(root)\n const oldEntries = new Map(previous?.sources.map((entry) => [entry.sourcePath, entry]))\n\n if (\n previous &&\n (yield* metadataHash({ version: previous.version, sources: previous.sources })) !== previous.exportSha256\n )\n return yield* userError(\n `Local edits in ${path.join(root, '.cms-content.json')}; review them before exporting again.`,\n )\n\n // Preflight every file before replacing any of them.\n for (const source of snapshot.sources) {\n const file = contentPath(root, source.sourcePath, path)\n\n if (!(yield* fileSystem.exists(file))) continue\n\n const local = yield* fileSystem.readFileString(file)\n const old = oldEntries.get(source.sourcePath)\n\n if (old ? (yield* hash(local)) !== old.sha256 : local !== source.markdown)\n return yield* userError(`Local edits in ${file}; review them before exporting again.`)\n }\n\n yield* fileSystem.makeDirectory(root, { recursive: true })\n\n for (const source of snapshot.sources) {\n const file = contentPath(root, source.sourcePath, path)\n yield* fileSystem.makeDirectory(path.dirname(file), { recursive: true })\n yield* fileSystem.writeFileString(file, source.markdown)\n }\n\n const metadata: typeof IndexMetadata.Type = {\n version: 1,\n sources: yield* Effect.forEach(snapshot.sources, (source) =>\n hash(source.markdown).pipe(\n Effect.map((sha256) => ({\n sourcePath: source.sourcePath,\n published: source.published,\n sha256,\n })),\n ),\n ),\n }\n\n const index = ContentIndex.make({ ...metadata, exportSha256: yield* metadataHash(metadata) })\n\n yield* fileSystem.writeFileString(\n path.join(root, '.cms-content.json'),\n `${yield* Schema.encodeEffect(Schema.fromJsonString(ContentIndex))(index)}\\n`,\n )\n yield* Console.log(`Exported ${index.sources.length} documents to ${root}`)\n})\n\nconst plan = Effect.fn('CmsCli.content.plan')(function* (\n session: Session,\n sources: ReadonlyArray<ContentSource>,\n options: ImportOptions,\n) {\n return yield* Schema.decodeUnknownEffect(ContentPlan)(yield* request(session, 'plan', { sources, ...options }))\n})\n\nfunction printPlan(value: ContentPlan) {\n return Effect.gen(function* () {\n for (const entry of value.entries) yield* Console.log(`${entry.action.padEnd(9)} ${entry.sourcePath}`)\n\n for (const issue of value.issues)\n yield* Console.error(`${issue.severity}: ${issue.sourcePath ?? ''} ${issue.message}`)\n\n yield* Console.log(\n value.valid ? `Ready at generation ${value.generation}` : 'Plan has conflicts or validation errors.',\n )\n })\n}\n\nconst preparePlan = Effect.fn('CmsCli.content.preparePlan')(function* (\n connection: ConnectionOptions,\n directory: string,\n options: ImportOptions,\n) {\n const sources = yield* readSources(directory)\n const session = yield* connect(connection)\n const value = yield* plan(session, sources, options)\n yield* printPlan(value)\n\n if (!value.valid) return yield* userError('Content plan is not ready to apply.')\n\n return { session, sources, value }\n})\n\nexport const planContent = Effect.fn('CmsCli.content.planCommand')(function* (\n connection: ConnectionOptions,\n directory: string,\n options: ImportOptions,\n) {\n yield* preparePlan(connection, directory, options)\n})\n\nexport const diffContent = Effect.fn('CmsCli.content.diff')(function* (\n connection: ConnectionOptions,\n directory: string,\n) {\n const local = yield* readSources(directory)\n const session = yield* connect(connection)\n const remote = yield* Schema.decodeUnknownEffect(ContentSnapshot)(yield* request(session, 'snapshot'))\n const comparison = describeContentDiff(local, remote.sources)\n\n for (const line of comparison.lines) yield* Console.log(line)\n\n yield* Console.log(\n `${comparison.changed} local document${comparison.changed === 1 ? ' differs' : 's differ'} from the CMS.`,\n )\n})\n\nexport function describeContentDiff(local: ReadonlyArray<ContentSource>, remote: ReadonlyArray<ContentSource>) {\n const remoteByPath = new Map(remote.map((source) => [source.sourcePath, source]))\n const localPaths = new Set(local.map((source) => source.sourcePath))\n const lines: string[] = []\n let changed = 0\n\n for (const source of local) {\n const current = remoteByPath.get(source.sourcePath)\n const markdownChanged = current?.markdown !== source.markdown\n const publicationChanged = current !== undefined && current.published !== source.published\n\n if (!markdownChanged && !publicationChanged) continue\n\n if (markdownChanged) {\n const patch = createTwoFilesPatch(\n `remote/${source.sourcePath}`,\n `local/${source.sourcePath}`,\n current?.markdown ?? '',\n source.markdown,\n )\n\n lines.push(patch.trimEnd())\n }\n\n if (publicationChanged)\n lines.push(\n `Publication ${source.sourcePath}: CMS ${current.published ? 'published' : 'draft'}, local ${source.published ? 'published (use --publish to apply)' : 'draft (import keeps existing publication)'}`,\n )\n\n changed++\n }\n\n for (const source of remote) if (!localPaths.has(source.sourcePath)) lines.push(`Remote only: ${source.sourcePath}`)\n\n return { lines, changed }\n}\n\nexport const applyContent = Effect.fn('CmsCli.content.apply')(function* (\n connection: ConnectionOptions,\n directory: string,\n options: ImportOptions,\n) {\n const { session, sources, value } = yield* preparePlan(connection, directory, options)\n\n const result = yield* Schema.decodeUnknownEffect(ContentApplyResult)(\n yield* request(session, 'apply', { sources, ...options, expectedGeneration: value.generation }),\n )\n\n yield* Console.log(\n `Applied: ${result.created} created, ${result.updated} updated, ${result.published} published, ${result.unchanged} unchanged.`,\n )\n})\n"],"mappings":"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"}
|
package/src/cli.js
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { applyContent, diffContent, exportContent, planContent } from "./cli/content.js";
|
|
2
|
+
import { Effect, Layer } from "effect";
|
|
3
|
+
import { NodeChildProcessSpawner, NodeCrypto, NodeFileSystem, NodePath, NodeRuntime, NodeStdio, NodeTerminal } from "@effect/platform-node-shared";
|
|
4
|
+
import { FetchHttpClient } from "effect/unstable/http";
|
|
5
|
+
import { Argument, Command, Flag } from "effect/unstable/cli";
|
|
6
|
+
|
|
7
|
+
//#region package.json
|
|
8
|
+
var version = "0.1.0-beta.3";
|
|
9
|
+
|
|
10
|
+
//#endregion
|
|
11
|
+
//#region src/cli.ts
|
|
12
|
+
const root = Command.make("cms").pipe(Command.withSharedFlags({
|
|
13
|
+
url: Flag.String("url").pipe(Flag.withDefault("")),
|
|
14
|
+
email: Flag.String("email").pipe(Flag.withDefault(""))
|
|
15
|
+
}));
|
|
16
|
+
const directory = Argument.String("directory");
|
|
17
|
+
const overwrite = Flag.Boolean("overwrite").pipe(Flag.withDefault(false));
|
|
18
|
+
const publish = Flag.Boolean("publish").pipe(Flag.withDefault(false));
|
|
19
|
+
const exportCommand = Command.make("export", { directory }, ({ directory }) => Effect.gen(function* () {
|
|
20
|
+
const { url, email } = yield* root;
|
|
21
|
+
return yield* exportContent({
|
|
22
|
+
url,
|
|
23
|
+
email
|
|
24
|
+
}, directory);
|
|
25
|
+
})).pipe(Command.withDescription("Export authored Markdown from a CMS installation"));
|
|
26
|
+
const diffCommand = Command.make("diff", { directory }, ({ directory }) => Effect.gen(function* () {
|
|
27
|
+
const { url, email } = yield* root;
|
|
28
|
+
return yield* diffContent({
|
|
29
|
+
url,
|
|
30
|
+
email
|
|
31
|
+
}, directory);
|
|
32
|
+
})).pipe(Command.withDescription("Compare local Markdown with the current CMS content"));
|
|
33
|
+
const planCommand = Command.make("plan", {
|
|
34
|
+
directory,
|
|
35
|
+
overwrite,
|
|
36
|
+
publish
|
|
37
|
+
}, ({ directory, overwrite, publish }) => Effect.gen(function* () {
|
|
38
|
+
const { url, email } = yield* root;
|
|
39
|
+
return yield* planContent({
|
|
40
|
+
url,
|
|
41
|
+
email
|
|
42
|
+
}, directory, {
|
|
43
|
+
overwrite,
|
|
44
|
+
publish
|
|
45
|
+
});
|
|
46
|
+
})).pipe(Command.withDescription("Preview content changes without writing to the CMS"));
|
|
47
|
+
const applyCommand = Command.make("apply", {
|
|
48
|
+
directory,
|
|
49
|
+
overwrite,
|
|
50
|
+
publish
|
|
51
|
+
}, ({ directory, overwrite, publish }) => Effect.gen(function* () {
|
|
52
|
+
const { url, email } = yield* root;
|
|
53
|
+
return yield* applyContent({
|
|
54
|
+
url,
|
|
55
|
+
email
|
|
56
|
+
}, directory, {
|
|
57
|
+
overwrite,
|
|
58
|
+
publish
|
|
59
|
+
});
|
|
60
|
+
})).pipe(Command.withDescription("Apply a validated content plan to the CMS"));
|
|
61
|
+
const content = Command.make("content").pipe(Command.withSubcommands([
|
|
62
|
+
exportCommand,
|
|
63
|
+
diffCommand,
|
|
64
|
+
planCommand,
|
|
65
|
+
applyCommand
|
|
66
|
+
]));
|
|
67
|
+
root.pipe(Command.withSubcommands([content]), Command.run({ version }), Effect.provide(Layer.mergeAll(NodeFileSystem.layer, NodePath.layer, NodeCrypto.layer, NodeTerminal.layer, NodeStdio.layer, NodeChildProcessSpawner.layer.pipe(Layer.provide(Layer.merge(NodeFileSystem.layer, NodePath.layer))), FetchHttpClient.layer)), NodeRuntime.runMain);
|
|
68
|
+
|
|
69
|
+
//#endregion
|
|
70
|
+
export { };
|
|
71
|
+
//# sourceMappingURL=cli.js.map
|
package/src/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","names":["packageManifest.version"],"sources":["../../../package.json","../../../src/cli.ts"],"sourcesContent":["","import {\n NodeChildProcessSpawner,\n NodeCrypto,\n NodeFileSystem,\n NodePath,\n NodeRuntime,\n NodeStdio,\n NodeTerminal,\n} from '@effect/platform-node-shared'\nimport { Effect, Layer } from 'effect'\nimport { Argument, Command, Flag } from 'effect/unstable/cli'\nimport { FetchHttpClient } from 'effect/unstable/http'\nimport packageManifest from '../package.json' with { type: 'json' }\nimport { applyContent, diffContent, exportContent, planContent } from './cli/content'\n\nconst root = Command.make('cms').pipe(\n Command.withSharedFlags({\n url: Flag.String('url').pipe(Flag.withDefault('')),\n email: Flag.String('email').pipe(Flag.withDefault('')),\n }),\n)\n\nconst directory = Argument.String('directory')\n\nconst overwrite = Flag.Boolean('overwrite').pipe(Flag.withDefault(false))\n\nconst publish = Flag.Boolean('publish').pipe(Flag.withDefault(false))\n\nconst exportCommand = Command.make('export', { directory }, ({ directory }) =>\n Effect.gen(function* () {\n const { url, email } = yield* root\n\n return yield* exportContent({ url, email }, directory)\n }),\n).pipe(Command.withDescription('Export authored Markdown from a CMS installation'))\n\nconst diffCommand = Command.make('diff', { directory }, ({ directory }) =>\n Effect.gen(function* () {\n const { url, email } = yield* root\n\n return yield* diffContent({ url, email }, directory)\n }),\n).pipe(Command.withDescription('Compare local Markdown with the current CMS content'))\n\nconst planCommand = Command.make('plan', { directory, overwrite, publish }, ({ directory, overwrite, publish }) =>\n Effect.gen(function* () {\n const { url, email } = yield* root\n\n return yield* planContent({ url, email }, directory, { overwrite, publish })\n }),\n).pipe(Command.withDescription('Preview content changes without writing to the CMS'))\n\nconst applyCommand = Command.make('apply', { directory, overwrite, publish }, ({ directory, overwrite, publish }) =>\n Effect.gen(function* () {\n const { url, email } = yield* root\n\n return yield* applyContent({ url, email }, directory, { overwrite, publish })\n }),\n).pipe(Command.withDescription('Apply a validated content plan to the CMS'))\n\nconst content = Command.make('content').pipe(\n Command.withSubcommands([exportCommand, diffCommand, planCommand, applyCommand]),\n)\n\nroot.pipe(\n Command.withSubcommands([content]),\n Command.run({ version: packageManifest.version }),\n Effect.provide(\n Layer.mergeAll(\n NodeFileSystem.layer,\n NodePath.layer,\n NodeCrypto.layer,\n NodeTerminal.layer,\n NodeStdio.layer,\n NodeChildProcessSpawner.layer.pipe(Layer.provide(Layer.merge(NodeFileSystem.layer, NodePath.layer))),\n FetchHttpClient.layer,\n ),\n ),\n NodeRuntime.runMain,\n)\n"],"mappings":";;;;;;;;;;;ACeA,MAAM,OAAO,QAAQ,KAAK,KAAK,CAAC,CAAC,KAC/B,QAAQ,gBAAgB;CACtB,KAAK,KAAK,OAAO,KAAK,CAAC,CAAC,KAAK,KAAK,YAAY,EAAE,CAAC;CACjD,OAAO,KAAK,OAAO,OAAO,CAAC,CAAC,KAAK,KAAK,YAAY,EAAE,CAAC;AACvD,CAAC,CACH;AAEA,MAAM,YAAY,SAAS,OAAO,WAAW;AAE7C,MAAM,YAAY,KAAK,QAAQ,WAAW,CAAC,CAAC,KAAK,KAAK,YAAY,KAAK,CAAC;AAExE,MAAM,UAAU,KAAK,QAAQ,SAAS,CAAC,CAAC,KAAK,KAAK,YAAY,KAAK,CAAC;AAEpE,MAAM,gBAAgB,QAAQ,KAAK,UAAU,EAAE,UAAU,IAAI,EAAE,gBAC7D,OAAO,IAAI,aAAa;CACtB,MAAM,EAAE,KAAK,UAAU,OAAO;CAE9B,OAAO,OAAO,cAAc;EAAE;EAAK;CAAM,GAAG,SAAS;AACvD,CAAC,CACH,CAAC,CAAC,KAAK,QAAQ,gBAAgB,kDAAkD,CAAC;AAElF,MAAM,cAAc,QAAQ,KAAK,QAAQ,EAAE,UAAU,IAAI,EAAE,gBACzD,OAAO,IAAI,aAAa;CACtB,MAAM,EAAE,KAAK,UAAU,OAAO;CAE9B,OAAO,OAAO,YAAY;EAAE;EAAK;CAAM,GAAG,SAAS;AACrD,CAAC,CACH,CAAC,CAAC,KAAK,QAAQ,gBAAgB,qDAAqD,CAAC;AAErF,MAAM,cAAc,QAAQ,KAAK,QAAQ;CAAE;CAAW;CAAW;AAAQ,IAAI,EAAE,WAAW,WAAW,cACnG,OAAO,IAAI,aAAa;CACtB,MAAM,EAAE,KAAK,UAAU,OAAO;CAE9B,OAAO,OAAO,YAAY;EAAE;EAAK;CAAM,GAAG,WAAW;EAAE;EAAW;CAAQ,CAAC;AAC7E,CAAC,CACH,CAAC,CAAC,KAAK,QAAQ,gBAAgB,oDAAoD,CAAC;AAEpF,MAAM,eAAe,QAAQ,KAAK,SAAS;CAAE;CAAW;CAAW;AAAQ,IAAI,EAAE,WAAW,WAAW,cACrG,OAAO,IAAI,aAAa;CACtB,MAAM,EAAE,KAAK,UAAU,OAAO;CAE9B,OAAO,OAAO,aAAa;EAAE;EAAK;CAAM,GAAG,WAAW;EAAE;EAAW;CAAQ,CAAC;AAC9E,CAAC,CACH,CAAC,CAAC,KAAK,QAAQ,gBAAgB,2CAA2C,CAAC;AAE3E,MAAM,UAAU,QAAQ,KAAK,SAAS,CAAC,CAAC,KACtC,QAAQ,gBAAgB;CAAC;CAAe;CAAa;CAAa;AAAY,CAAC,CACjF;AAEA,KAAK,KACH,QAAQ,gBAAgB,CAAC,OAAO,CAAC,GACjC,QAAQ,IAAI,EAAWA,QAAwB,CAAC,GAChD,OAAO,QACL,MAAM,SACJ,eAAe,OACf,SAAS,OACT,WAAW,OACX,aAAa,OACb,UAAU,OACV,wBAAwB,MAAM,KAAK,MAAM,QAAQ,MAAM,MAAM,eAAe,OAAO,SAAS,KAAK,CAAC,CAAC,GACnG,gBAAgB,KAClB,CACF,GACA,YAAY,OACd"}
|
|
@@ -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-B4IoTmp7.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-CBAy2qGy.js.map
|