@phtngyn/cms 0.2.0-beta.1 → 0.2.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/CHANGELOG.md +13 -0
- package/README.md +40 -45
- package/package.json +7 -5
- package/src/ApplicationTypes.d.ts +7 -5
- package/src/{Configuration-CjVUBBwa.js → Configuration-BU-UyGoH.js} +4 -4
- package/src/{Configuration-CjVUBBwa.js.map → Configuration-BU-UyGoH.js.map} +1 -1
- package/src/Configuration.d.ts +41 -24
- package/src/Configuration.js.map +1 -1
- package/src/Content.js +42 -19
- package/src/Content.js.map +1 -1
- package/src/{ContentTransfer-CTzGGKFV.js → ContentTransfer-BhF9G56s.js} +2 -2
- package/src/{ContentTransfer-CTzGGKFV.js.map → ContentTransfer-BhF9G56s.js.map} +1 -1
- package/src/{DocumentEngine-BbhfnTAc.js → DocumentEngine-ClhFXW9M.js} +4 -4
- package/src/{DocumentEngine-BbhfnTAc.js.map → DocumentEngine-ClhFXW9M.js.map} +1 -1
- package/src/DocumentModel.d.ts +6 -1
- package/src/DocumentModel.js +4 -3
- package/src/DocumentModel.js.map +1 -1
- package/src/{Forms-CfcI3tPU.js → Forms-BbkE7QfC.js} +47 -16
- package/src/Forms-BbkE7QfC.js.map +1 -0
- package/src/{Forms-02-p8qEw.js → Forms-DoB56hfe.js} +24 -7
- package/src/Forms-DoB56hfe.js.map +1 -0
- package/src/{Forms-BorTcIlp.d.ts → Forms-R0HoTR-o.d.ts} +30 -9
- package/src/Forms.d.ts +16 -15
- package/src/Forms.js.map +1 -1
- package/src/{I18n-BXlVunfa.d.ts → I18n-zbqpWxki.d.ts} +3 -1
- package/src/I18n.d.ts +1 -1
- package/src/Module.js +4 -2
- package/src/Module.js.map +1 -1
- package/src/{S3MediaObjects-DC0c8sYC.js → S3MediaObjects-CR3p1WTg.js} +21 -13
- package/src/S3MediaObjects-CR3p1WTg.js.map +1 -0
- package/src/cli.js +60 -34
- package/src/cli.js.map +1 -1
- package/src/{connection-BPf4BQUZ.js → connection-D5S9Iph-.js} +2 -2
- package/src/{connection-BPf4BQUZ.js.map → connection-D5S9Iph-.js.map} +1 -1
- package/src/{dev-lifecycle-vQLxwCFq.js → dev-lifecycle-D3f9-upa.js} +129 -42
- package/src/dev-lifecycle-D3f9-upa.js.map +1 -0
- package/src/{installation-DsGst1BH.js → installation-fZtNxtoW.js} +68 -41
- package/src/installation-fZtNxtoW.js.map +1 -0
- package/src/internal/authoring-catalog.js +2 -2
- package/src/internal/authoring-metadata.js +1 -1
- package/src/internal/configuration.js +149 -50
- package/src/internal/configuration.js.map +1 -1
- package/src/internal/dev-lifecycle.js +2 -2
- package/src/internal/diagnostics.js +47 -0
- package/src/internal/diagnostics.js.map +1 -0
- package/src/internal/document-model.js +2 -2
- package/src/internal/form-capabilities.js +1 -1
- package/src/internal/i18n.js +6 -1
- package/src/internal/i18n.js.map +1 -1
- package/src/internal/studio-app.js +8 -6
- package/src/internal/studio-app.js.map +1 -1
- package/src/{location-BgYhXEZp.js → location-CPX7oj0o.js} +2 -2
- package/src/{location-BgYhXEZp.js.map → location-CPX7oj0o.js.map} +1 -1
- package/src/{models-k2nXyD6q.js → models-C9kF9JlQ.js} +2 -2
- package/src/{models-k2nXyD6q.js.map → models-C9kF9JlQ.js.map} +1 -1
- package/src/{models-DgkGTFus.js → models-ChRxBChy.js} +4 -2
- package/src/{models-DgkGTFus.js.map → models-ChRxBChy.js.map} +1 -1
- package/src/runtime/delivery/context.js +1 -1
- package/src/runtime/delivery/plugin.js +3 -2
- package/src/runtime/delivery/plugin.js.map +1 -1
- package/src/runtime/forms/document.js +1 -1
- package/src/runtime/forms/useCmsForm.js +73 -46
- package/src/runtime/forms/useCmsForm.js.map +1 -1
- package/src/runtime/i18n/useCmsI18n.d.ts +1 -1
- package/src/runtime/i18n/useCmsI18n.js.map +1 -1
- package/src/runtime/installation.js +1 -1
- package/src/runtime/plugin.js +12 -4
- package/src/runtime/plugin.js.map +1 -1
- package/src/runtime/preview/connection.js +1 -1
- package/src/runtime/preview/controller.js +2 -2
- package/src/runtime/preview/plugin.client.js +3 -3
- package/src/runtime/preview/plugin.client.js.map +1 -1
- package/src/runtime/preview/store.js +1 -1
- package/src/runtime/sitemap.js +1 -1
- package/src/{store-BYgSt7E3.js → store-CCsjHaZm.js} +8 -8
- package/src/store-CCsjHaZm.js.map +1 -0
- package/studio/{CreateDocumentDialog-BdiM77bb.js → CreateDocumentDialog-DJ8c0WZb.js} +3 -3
- package/studio/{documentPlanning-B7fyUj9r.js → documentPlanning-CDb31mnl.js} +6417 -6358
- package/studio/host.css +1 -1
- package/studio/host.js +7612 -7249
- package/src/Forms-02-p8qEw.js.map +0 -1
- package/src/Forms-CfcI3tPU.js.map +0 -1
- package/src/S3MediaObjects-DC0c8sYC.js.map +0 -1
- package/src/dev-lifecycle-vQLxwCFq.js.map +0 -1
- package/src/installation-DsGst1BH.js.map +0 -1
- package/src/store-BYgSt7E3.js.map +0 -1
package/src/cli.js
CHANGED
|
@@ -1,18 +1,27 @@
|
|
|
1
1
|
import { applyContent, diffContent, exportContent, planContent } from "./cli/content.js";
|
|
2
|
-
import { n as doctorCmsDevelopment, r as
|
|
3
|
-
import {
|
|
2
|
+
import { i as resetCmsDevelopment, n as doctorCmsDevelopment, r as loadCmsProjectEnvironment, t as bootstrapCmsDevelopment } from "./dev-lifecycle-D3f9-upa.js";
|
|
3
|
+
import { diagnosticFromCause, renderDiagnostic } from "./internal/diagnostics.js";
|
|
4
|
+
import { Config, Console, Effect, Layer, Match, Option, Redacted, Runtime, Schema } from "effect";
|
|
4
5
|
import { NodeChildProcessSpawner, NodeCrypto, NodeFileSystem, NodePath, NodeRuntime, NodeStdio, NodeTerminal } from "@effect/platform-node-shared";
|
|
5
6
|
import { FetchHttpClient } from "effect/unstable/http";
|
|
6
7
|
import { Argument, CliError, Command, Flag, Prompt } from "effect/unstable/cli";
|
|
7
8
|
|
|
8
9
|
//#region package.json
|
|
9
|
-
var version = "0.2.0-beta.
|
|
10
|
+
var version = "0.2.0-beta.3";
|
|
10
11
|
|
|
11
12
|
//#endregion
|
|
12
13
|
//#region src/cli.ts
|
|
14
|
+
const rootDirectory = Flag.String("root").pipe(Flag.withDefault("."));
|
|
15
|
+
const envFile = Flag.String("env-file").pipe(Flag.withDefault(""));
|
|
16
|
+
const verbose = Flag.Boolean("verbose").pipe(Flag.withDefault(false));
|
|
17
|
+
const json = Flag.Boolean("json").pipe(Flag.withDefault(false));
|
|
13
18
|
const root = Command.make("cms").pipe(Command.withSharedFlags({
|
|
14
19
|
url: Flag.String("url").pipe(Flag.withDefault("")),
|
|
15
|
-
email: Flag.String("email").pipe(Flag.withDefault(""))
|
|
20
|
+
email: Flag.String("email").pipe(Flag.withDefault("")),
|
|
21
|
+
rootDirectory,
|
|
22
|
+
envFile,
|
|
23
|
+
verbose,
|
|
24
|
+
json
|
|
16
25
|
}));
|
|
17
26
|
const directory = Argument.String("directory");
|
|
18
27
|
const overwrite = Flag.Boolean("overwrite").pipe(Flag.withDefault(false));
|
|
@@ -65,61 +74,62 @@ const content = Command.make("content").pipe(Command.withSubcommands([
|
|
|
65
74
|
planCommand,
|
|
66
75
|
applyCommand
|
|
67
76
|
]));
|
|
68
|
-
const json = Flag.Boolean("json").pipe(Flag.withDefault(false));
|
|
69
77
|
const full = Flag.Boolean("full").pipe(Flag.withDefault(false));
|
|
70
|
-
const rootDirectory = Flag.String("root").pipe(Flag.withDefault("."));
|
|
71
78
|
const contentDirectory = Flag.String("content").pipe(Flag.withDefault(""));
|
|
72
79
|
const administratorName = Flag.String("name").pipe(Flag.withDefault(""));
|
|
73
80
|
const database = Flag.Boolean("database").pipe(Flag.withDefault(false));
|
|
74
81
|
const media = Flag.Boolean("media").pipe(Flag.withDefault(false));
|
|
75
82
|
const bootstrap = Flag.Boolean("bootstrap").pipe(Flag.withDefault(false));
|
|
76
83
|
const yes = Flag.Boolean("yes").pipe(Flag.withDefault(false));
|
|
77
|
-
const doctorCommand = Command.make("doctor", {
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
}, ({ full, json, rootDirectory }) => Effect.gen(function* () {
|
|
82
|
-
const report = yield* attempt(() => doctorCmsDevelopment(rootDirectory, full));
|
|
83
|
-
if (json) yield* Console.log(JSON.stringify(report));
|
|
84
|
+
const doctorCommand = Command.make("doctor", { full }, ({ full }) => Effect.gen(function* () {
|
|
85
|
+
const options = yield* root;
|
|
86
|
+
const report = yield* attempt("doctor.configuration", options, () => doctorCmsDevelopment(options.rootDirectory, full, options.envFile || void 0));
|
|
87
|
+
if (options.json) yield* Console.log(JSON.stringify(report));
|
|
84
88
|
else for (const check of report.checks) {
|
|
85
89
|
const icon = Match.value(check.status).pipe(Match.when("pass", () => "✓"), Match.when("fail", () => "✗"), Match.when("not-verified", () => "−"), Match.exhaustive);
|
|
86
90
|
yield* Console.log(`${icon} ${check.label}${check.detail ? `\n\n ${check.detail}` : ""}`);
|
|
87
91
|
}
|
|
88
|
-
if (!report.ok) return yield* cliError("One or more CMS development checks failed.");
|
|
92
|
+
if (!report.ok) return yield* options.json ? new JsonCommandFailed({}) : cliError("One or more CMS development checks failed.");
|
|
89
93
|
})).pipe(Command.withDescription("Check local CMS configuration and infrastructure"));
|
|
90
94
|
const bootstrapCommand = Command.make("bootstrap", {
|
|
91
95
|
contentDirectory,
|
|
92
96
|
administratorName,
|
|
93
|
-
publish
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
const
|
|
98
|
-
|
|
97
|
+
publish
|
|
98
|
+
}, ({ contentDirectory, administratorName, publish }) => Effect.gen(function* () {
|
|
99
|
+
const options = yield* root;
|
|
100
|
+
yield* attempt("bootstrap.environment", options, () => loadCmsProjectEnvironment(options.rootDirectory, options.envFile || void 0));
|
|
101
|
+
const administrator = yield* administratorOptions(administratorName, contentDirectory, publish, options, "bootstrap.credentials");
|
|
102
|
+
const result = yield* attempt("bootstrap.installation", options, () => bootstrapCmsDevelopment({
|
|
103
|
+
rootDir: options.rootDirectory,
|
|
104
|
+
envFile: options.envFile || void 0,
|
|
105
|
+
verbose: options.verbose,
|
|
99
106
|
...administrator
|
|
100
107
|
}));
|
|
101
|
-
yield* Console.log(
|
|
108
|
+
if (options.json) yield* Console.log(JSON.stringify(result));
|
|
109
|
+
else yield* Console.log(`Bootstrap complete: administrator ${result.administrator}${result.contentApplied ? ", content applied" : ""}.`);
|
|
102
110
|
})).pipe(Command.withDescription("Provision and initialize a local CMS installation"));
|
|
103
111
|
const resetCommand = Command.make("reset", {
|
|
104
112
|
bootstrap,
|
|
105
113
|
contentDirectory,
|
|
106
114
|
database,
|
|
107
|
-
json,
|
|
108
115
|
media,
|
|
109
116
|
publish,
|
|
110
|
-
rootDirectory,
|
|
111
117
|
yes
|
|
112
|
-
}, ({ bootstrap, contentDirectory, database,
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
118
|
+
}, ({ bootstrap, contentDirectory, database, media, publish, yes }) => Effect.gen(function* () {
|
|
119
|
+
const options = yield* root;
|
|
120
|
+
if (!database && !media) return yield* commandFailure("reset.arguments", options, /* @__PURE__ */ new Error("Choose --database, --media, or both."));
|
|
121
|
+
if (bootstrap && yes) yield* attempt("reset.environment", options, () => loadCmsProjectEnvironment(options.rootDirectory, options.envFile || void 0));
|
|
122
|
+
const administrator = bootstrap && yes ? yield* administratorOptions("", contentDirectory, publish, options, "reset.credentials") : void 0;
|
|
123
|
+
const result = yield* attempt("reset.installation", options, () => resetCmsDevelopment({
|
|
124
|
+
rootDir: options.rootDirectory,
|
|
125
|
+
envFile: options.envFile || void 0,
|
|
117
126
|
database,
|
|
118
127
|
media,
|
|
119
128
|
yes,
|
|
129
|
+
verbose: options.verbose,
|
|
120
130
|
bootstrap: administrator
|
|
121
131
|
}));
|
|
122
|
-
if (json) return yield* Console.log(JSON.stringify(result));
|
|
132
|
+
if (options.json) return yield* Console.log(JSON.stringify(result));
|
|
123
133
|
for (const target of result.targets) yield* Console.log(`${result.executed ? "✓ Reset" : "Would reset"} ${target}`);
|
|
124
134
|
if (!result.executed) yield* Console.log("Dry run only. Add --yes to execute these exact targets.");
|
|
125
135
|
})).pipe(Command.withDescription("Reset CMS-owned local data with a dry-run default"));
|
|
@@ -128,11 +138,13 @@ const dev = Command.make("dev").pipe(Command.withSubcommands([
|
|
|
128
138
|
bootstrapCommand,
|
|
129
139
|
resetCommand
|
|
130
140
|
]));
|
|
131
|
-
const administratorOptions = Effect.fn("CmsCli.dev.administratorOptions")(function* (name, content, publishContent) {
|
|
141
|
+
const administratorOptions = Effect.fn("CmsCli.dev.administratorOptions")(function* (name, content, publishContent, options, phase) {
|
|
132
142
|
const email = yield* Config.String("CMS_EMAIL").pipe(Config.withDefault(""));
|
|
133
143
|
const configuredPassword = yield* Config.Redacted("CMS_PASSWORD").pipe(Config.option);
|
|
134
|
-
|
|
135
|
-
if (
|
|
144
|
+
if (!email) return yield* commandFailure(phase, options, /* @__PURE__ */ new Error("CMS_EMAIL is required."));
|
|
145
|
+
if (Option.isNone(configuredPassword) && options.json) return yield* commandFailure(phase, options, /* @__PURE__ */ new Error("CMS_PASSWORD is required."));
|
|
146
|
+
const password = Option.isSome(configuredPassword) ? Redacted.value(configuredPassword.value) : Redacted.value(yield* Prompt.Password({ message: `Password for ${email}` }));
|
|
147
|
+
if (!password) return yield* commandFailure(phase, options, /* @__PURE__ */ new Error("CMS_PASSWORD is required."));
|
|
136
148
|
return {
|
|
137
149
|
content: content || void 0,
|
|
138
150
|
email,
|
|
@@ -147,10 +159,24 @@ function cliError(message) {
|
|
|
147
159
|
userMessage: message
|
|
148
160
|
});
|
|
149
161
|
}
|
|
150
|
-
|
|
162
|
+
var CliOperationFailed = class extends Schema.TaggedError()("CliOperationFailed", { cause: Schema.Defect() }) {};
|
|
163
|
+
var JsonCommandFailed = class extends Schema.TaggedError()("JsonCommandFailed", {}) {
|
|
164
|
+
[Runtime.errorExitCode] = 1;
|
|
165
|
+
[Runtime.errorReported] = false;
|
|
166
|
+
};
|
|
167
|
+
function attempt(phase, options, operation) {
|
|
151
168
|
return Effect.tryPromise({
|
|
152
169
|
try: () => Promise.resolve(operation()),
|
|
153
|
-
catch: (cause) =>
|
|
170
|
+
catch: (cause) => new CliOperationFailed({ cause })
|
|
171
|
+
}).pipe(Effect.catch((failure) => commandFailure(phase, options, failure.cause)));
|
|
172
|
+
}
|
|
173
|
+
function commandFailure(phase, options, cause) {
|
|
174
|
+
return Effect.gen(function* () {
|
|
175
|
+
const diagnostic = diagnosticFromCause(phase, cause);
|
|
176
|
+
if (!options.json) return yield* cliError(renderDiagnostic(diagnostic, options.verbose));
|
|
177
|
+
const { details: _details, ...output } = diagnostic;
|
|
178
|
+
yield* Console.log(JSON.stringify(output));
|
|
179
|
+
return yield* new JsonCommandFailed({});
|
|
154
180
|
});
|
|
155
181
|
}
|
|
156
182
|
root.pipe(Command.withSubcommands([content, dev]), 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);
|
package/src/cli.js.map
CHANGED
|
@@ -1 +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 { Config, Console, Effect, Layer, Match, Option, Redacted } from 'effect'\nimport { Argument, CliError, Command, Flag, Prompt } 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'\nimport { bootstrapCmsDevelopment, doctorCmsDevelopment, resetCmsDevelopment } from './internal/dev-lifecycle'\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\nconst json = Flag.Boolean('json').pipe(Flag.withDefault(false))\n\nconst full = Flag.Boolean('full').pipe(Flag.withDefault(false))\n\nconst rootDirectory = Flag.String('root').pipe(Flag.withDefault('.'))\n\nconst contentDirectory = Flag.String('content').pipe(Flag.withDefault(''))\n\nconst administratorName = Flag.String('name').pipe(Flag.withDefault(''))\n\nconst database = Flag.Boolean('database').pipe(Flag.withDefault(false))\n\nconst media = Flag.Boolean('media').pipe(Flag.withDefault(false))\n\nconst bootstrap = Flag.Boolean('bootstrap').pipe(Flag.withDefault(false))\n\nconst yes = Flag.Boolean('yes').pipe(Flag.withDefault(false))\n\nconst doctorCommand = Command.make('doctor', { full, json, rootDirectory }, ({ full, json, rootDirectory }) =>\n Effect.gen(function* () {\n const report = yield* attempt(() => doctorCmsDevelopment(rootDirectory, full))\n\n if (json) {\n // oxlint-disable-next-line effecttsgo/prefer-schema-over-json -- This flag intentionally emits the report's exact JSON representation.\n yield* Console.log(JSON.stringify(report))\n } else\n for (const check of report.checks) {\n const icon = Match.value(check.status).pipe(\n Match.when('pass', () => '✓'),\n Match.when('fail', () => '✗'),\n Match.when('not-verified', () => '−'),\n Match.exhaustive,\n )\n\n yield* Console.log(`${icon} ${check.label}${check.detail ? `\\n\\n ${check.detail}` : ''}`)\n }\n\n if (!report.ok) return yield* cliError('One or more CMS development checks failed.')\n }),\n).pipe(Command.withDescription('Check local CMS configuration and infrastructure'))\n\nconst bootstrapCommand = Command.make(\n 'bootstrap',\n { contentDirectory, administratorName, publish, rootDirectory },\n ({ contentDirectory, administratorName, publish, rootDirectory }) =>\n Effect.gen(function* () {\n const administrator = yield* administratorOptions(administratorName, contentDirectory, publish)\n const result = yield* attempt(() => bootstrapCmsDevelopment({ rootDir: rootDirectory, ...administrator }))\n yield* Console.log(\n `Bootstrap complete: administrator ${result.administrator}${result.contentApplied ? ', content applied' : ''}.`,\n )\n }),\n).pipe(Command.withDescription('Provision and initialize a local CMS installation'))\n\nconst resetCommand = Command.make(\n 'reset',\n { bootstrap, contentDirectory, database, json, media, publish, rootDirectory, yes },\n ({ bootstrap, contentDirectory, database, json, media, publish, rootDirectory, yes }) =>\n Effect.gen(function* () {\n if (!database && !media) return yield* cliError('Choose --database, --media, or both.')\n const administrator = bootstrap && yes ? yield* administratorOptions('', contentDirectory, publish) : undefined\n\n const result = yield* attempt(() =>\n resetCmsDevelopment({ rootDir: rootDirectory, database, media, yes, bootstrap: administrator }),\n )\n\n if (json) {\n // oxlint-disable-next-line effecttsgo/prefer-schema-over-json -- This flag intentionally emits the report's exact JSON representation.\n return yield* Console.log(JSON.stringify(result))\n }\n\n for (const target of result.targets)\n yield* Console.log(`${result.executed ? '✓ Reset' : 'Would reset'} ${target}`)\n\n if (!result.executed) yield* Console.log('Dry run only. Add --yes to execute these exact targets.')\n }),\n).pipe(Command.withDescription('Reset CMS-owned local data with a dry-run default'))\n\nconst dev = Command.make('dev').pipe(Command.withSubcommands([doctorCommand, bootstrapCommand, resetCommand]))\n\nconst administratorOptions = Effect.fn('CmsCli.dev.administratorOptions')(function* (\n name: string,\n content: string,\n publishContent: boolean,\n) {\n const email = yield* Config.String('CMS_EMAIL').pipe(Config.withDefault(''))\n const configuredPassword = yield* Config.Redacted('CMS_PASSWORD').pipe(Config.option)\n\n const password = Option.isSome(configuredPassword)\n ? Redacted.value(configuredPassword.value)\n : Redacted.value(yield* Prompt.Password({ message: `Password for ${email || 'local administrator'}` }))\n\n if (!email || !password) return yield* cliError('CMS_EMAIL and CMS_PASSWORD are required.')\n\n return {\n content: content || undefined,\n email,\n name: name || (yield* Config.String('CMS_NAME').pipe(Config.withDefault('Administrator'))),\n password,\n publish: publishContent,\n }\n})\n\nfunction cliError(message: string) {\n return new CliError.UserError({ cause: new Error(message), userMessage: message })\n}\n\nfunction attempt<Value>(operation: () => Value | PromiseLike<Value>) {\n return Effect.tryPromise({\n try: () => Promise.resolve(operation()),\n catch: (cause) => cliError(cause instanceof Error ? cause.message : String(cause)),\n })\n}\n\nroot.pipe(\n Command.withSubcommands([content, dev]),\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":"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"}
|
|
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 { Config, Console, Effect, Layer, Match, Option, Redacted, Runtime, Schema } from 'effect'\nimport { Argument, CliError, Command, Flag, Prompt } 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'\nimport {\n bootstrapCmsDevelopment,\n doctorCmsDevelopment,\n loadCmsProjectEnvironment,\n resetCmsDevelopment,\n} from './internal/dev-lifecycle'\nimport { diagnosticFromCause, renderDiagnostic } from './internal/diagnostics'\n\nconst rootDirectory = Flag.String('root').pipe(Flag.withDefault('.'))\n\nconst envFile = Flag.String('env-file').pipe(Flag.withDefault(''))\n\nconst verbose = Flag.Boolean('verbose').pipe(Flag.withDefault(false))\n\nconst json = Flag.Boolean('json').pipe(Flag.withDefault(false))\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 rootDirectory,\n envFile,\n verbose,\n json,\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\nconst full = Flag.Boolean('full').pipe(Flag.withDefault(false))\n\nconst contentDirectory = Flag.String('content').pipe(Flag.withDefault(''))\n\nconst administratorName = Flag.String('name').pipe(Flag.withDefault(''))\n\nconst database = Flag.Boolean('database').pipe(Flag.withDefault(false))\n\nconst media = Flag.Boolean('media').pipe(Flag.withDefault(false))\n\nconst bootstrap = Flag.Boolean('bootstrap').pipe(Flag.withDefault(false))\n\nconst yes = Flag.Boolean('yes').pipe(Flag.withDefault(false))\n\nconst doctorCommand = Command.make('doctor', { full }, ({ full }) =>\n Effect.gen(function* () {\n const options = yield* root\n\n const report = yield* attempt('doctor.configuration', options, () =>\n doctorCmsDevelopment(options.rootDirectory, full, options.envFile || undefined),\n )\n\n if (options.json) {\n // oxlint-disable-next-line effecttsgo/prefer-schema-over-json -- This flag intentionally emits the report's exact JSON representation.\n yield* Console.log(JSON.stringify(report))\n } else\n for (const check of report.checks) {\n const icon = Match.value(check.status).pipe(\n Match.when('pass', () => '✓'),\n Match.when('fail', () => '✗'),\n Match.when('not-verified', () => '−'),\n Match.exhaustive,\n )\n\n yield* Console.log(`${icon} ${check.label}${check.detail ? `\\n\\n ${check.detail}` : ''}`)\n }\n\n if (!report.ok)\n return yield* options.json ? new JsonCommandFailed({}) : cliError('One or more CMS development checks failed.')\n }),\n).pipe(Command.withDescription('Check local CMS configuration and infrastructure'))\n\nconst bootstrapCommand = Command.make(\n 'bootstrap',\n { contentDirectory, administratorName, publish },\n ({ contentDirectory, administratorName, publish }) =>\n Effect.gen(function* () {\n const options = yield* root\n yield* attempt('bootstrap.environment', options, () =>\n loadCmsProjectEnvironment(options.rootDirectory, options.envFile || undefined),\n )\n\n const administrator = yield* administratorOptions(\n administratorName,\n contentDirectory,\n publish,\n options,\n 'bootstrap.credentials',\n )\n\n const result = yield* attempt('bootstrap.installation', options, () =>\n bootstrapCmsDevelopment({\n rootDir: options.rootDirectory,\n envFile: options.envFile || undefined,\n verbose: options.verbose,\n ...administrator,\n }),\n )\n\n if (options.json) {\n // oxlint-disable-next-line effecttsgo/prefer-schema-over-json -- This flag intentionally emits the report's exact JSON representation.\n yield* Console.log(JSON.stringify(result))\n } else\n yield* Console.log(\n `Bootstrap complete: administrator ${result.administrator}${result.contentApplied ? ', content applied' : ''}.`,\n )\n }),\n).pipe(Command.withDescription('Provision and initialize a local CMS installation'))\n\nconst resetCommand = Command.make(\n 'reset',\n { bootstrap, contentDirectory, database, media, publish, yes },\n ({ bootstrap, contentDirectory, database, media, publish, yes }) =>\n Effect.gen(function* () {\n const options = yield* root\n\n if (!database && !media)\n return yield* commandFailure('reset.arguments', options, new Error('Choose --database, --media, or both.'))\n\n if (bootstrap && yes)\n yield* attempt('reset.environment', options, () =>\n loadCmsProjectEnvironment(options.rootDirectory, options.envFile || undefined),\n )\n\n const administrator =\n bootstrap && yes\n ? yield* administratorOptions('', contentDirectory, publish, options, 'reset.credentials')\n : undefined\n\n const result = yield* attempt('reset.installation', options, () =>\n resetCmsDevelopment({\n rootDir: options.rootDirectory,\n envFile: options.envFile || undefined,\n database,\n media,\n yes,\n verbose: options.verbose,\n bootstrap: administrator,\n }),\n )\n\n if (options.json) {\n // oxlint-disable-next-line effecttsgo/prefer-schema-over-json -- This flag intentionally emits the report's exact JSON representation.\n return yield* Console.log(JSON.stringify(result))\n }\n\n for (const target of result.targets)\n yield* Console.log(`${result.executed ? '✓ Reset' : 'Would reset'} ${target}`)\n\n if (!result.executed) yield* Console.log('Dry run only. Add --yes to execute these exact targets.')\n }),\n).pipe(Command.withDescription('Reset CMS-owned local data with a dry-run default'))\n\nconst dev = Command.make('dev').pipe(Command.withSubcommands([doctorCommand, bootstrapCommand, resetCommand]))\n\nconst administratorOptions = Effect.fn('CmsCli.dev.administratorOptions')(function* (\n name: string,\n content: string,\n publishContent: boolean,\n options: { readonly json: boolean; readonly verbose: boolean },\n phase: string,\n) {\n const email = yield* Config.String('CMS_EMAIL').pipe(Config.withDefault(''))\n const configuredPassword = yield* Config.Redacted('CMS_PASSWORD').pipe(Config.option)\n\n if (!email) return yield* commandFailure(phase, options, new Error('CMS_EMAIL is required.'))\n\n if (Option.isNone(configuredPassword) && options.json)\n return yield* commandFailure(phase, options, new Error('CMS_PASSWORD is required.'))\n\n const password = Option.isSome(configuredPassword)\n ? Redacted.value(configuredPassword.value)\n : Redacted.value(yield* Prompt.Password({ message: `Password for ${email}` }))\n\n if (!password) return yield* commandFailure(phase, options, new Error('CMS_PASSWORD is required.'))\n\n return {\n content: content || undefined,\n email,\n name: name || (yield* Config.String('CMS_NAME').pipe(Config.withDefault('Administrator'))),\n password,\n publish: publishContent,\n }\n})\n\nfunction cliError(message: string) {\n return new CliError.UserError({ cause: new Error(message), userMessage: message })\n}\n\nclass CliOperationFailed extends Schema.TaggedError<CliOperationFailed>()('CliOperationFailed', {\n cause: Schema.Defect(),\n}) {}\n\nclass JsonCommandFailed extends Schema.TaggedError<JsonCommandFailed>()('JsonCommandFailed', {}) {\n override readonly [Runtime.errorExitCode] = 1\n override [Runtime.errorReported] = false\n}\n\nfunction attempt<Value>(\n phase: string,\n options: { readonly json: boolean; readonly verbose: boolean },\n operation: () => Value | PromiseLike<Value>,\n) {\n return Effect.tryPromise({\n try: () => Promise.resolve(operation()),\n catch: (cause) => new CliOperationFailed({ cause }),\n }).pipe(Effect.catch((failure) => commandFailure(phase, options, failure.cause)))\n}\n\nfunction commandFailure(phase: string, options: { readonly json: boolean; readonly verbose: boolean }, cause: unknown) {\n return Effect.gen(function* () {\n const diagnostic = diagnosticFromCause(phase, cause)\n\n if (!options.json) return yield* cliError(renderDiagnostic(diagnostic, options.verbose))\n\n const { details: _details, ...output } = diagnostic\n\n // oxlint-disable-next-line effecttsgo/prefer-schema-over-json -- CLI JSON is an intentionally stable plain object.\n yield* Console.log(JSON.stringify(output))\n\n return yield* new JsonCommandFailed({})\n })\n}\n\nroot.pipe(\n Command.withSubcommands([content, dev]),\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":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as DocumentPreviewMessage, o as isDocumentPreviewMessage, t as DOCUMENT_PREVIEW_CHANNEL } from "./models-
|
|
1
|
+
import { n as DocumentPreviewMessage, o as isDocumentPreviewMessage, t as DOCUMENT_PREVIEW_CHANNEL } from "./models-C9kF9JlQ.js";
|
|
2
2
|
import { Effect, Exit, Result, Schedule, Schema, Scope } from "effect";
|
|
3
3
|
|
|
4
4
|
//#region ../protocol/src/internal/preview/bridge.ts
|
|
@@ -89,4 +89,4 @@ async function openSitePreviewConnection(options) {
|
|
|
89
89
|
|
|
90
90
|
//#endregion
|
|
91
91
|
export { openSitePreviewConnection as t };
|
|
92
|
-
//# sourceMappingURL=connection-
|
|
92
|
+
//# sourceMappingURL=connection-D5S9Iph-.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"connection-BPf4BQUZ.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"}
|
|
1
|
+
{"version":3,"file":"connection-D5S9Iph-.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\n// oxlint-disable-next-line effecttsgo/async-function -- This browser adapter exposes the Effect-managed preview bridge through a Promise API consumed by Nuxt.\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 // oxlint-disable-next-line effecttsgo/async-function -- Closing adapts Effect scope finalization to the connection's Promise contract.\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;;;;ACjOA,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;GAEL,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"}
|
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
import { l as CMS_READINESS_PATH, p as STUDIO_COLLABORATION_PATH, u as STUDIO_API_PATH } from "./HttpPaths-c9nLZ9H2.js";
|
|
2
2
|
import { createCmsContentClient, readCmsContentDirectory } from "./Content.js";
|
|
3
|
-
import { t as AuthoringCatalog } from "./Configuration-
|
|
3
|
+
import { t as AuthoringCatalog } from "./Configuration-BU-UyGoH.js";
|
|
4
4
|
import { loadCmsConfiguration } from "./internal/cms-config.js";
|
|
5
|
-
import { compileCmsConfiguration, resolveCmsInstallation } from "./internal/configuration.js";
|
|
6
|
-
import { a as embeddedMigrations, i as createCmsBetterAuth, n as scopedDatabaseUrl, t as installCms } from "./installation-
|
|
7
|
-
import { Effect, Layer, Result, Schema } from "effect";
|
|
5
|
+
import { cmsRuntimeConfigurationDefaults, cmsRuntimeConfigurationFromEnvironment, compileCmsConfiguration, resolveCmsInstallation } from "./internal/configuration.js";
|
|
6
|
+
import { a as embeddedMigrations, i as createCmsBetterAuth, n as scopedDatabaseUrl, t as installCms } from "./installation-fZtNxtoW.js";
|
|
7
|
+
import { Effect, Layer, References, Result, Schema } from "effect";
|
|
8
8
|
import { randomUUID } from "node:crypto";
|
|
9
9
|
import { readFile } from "node:fs/promises";
|
|
10
10
|
import { resolve } from "node:path";
|
|
11
|
-
import { loadNuxt } from "@nuxt/kit";
|
|
11
|
+
import { loadNuxt, loadNuxtConfig } from "@nuxt/kit";
|
|
12
12
|
import { NodeCrypto, NodeFileSystem, NodePath } from "@effect/platform-node-shared";
|
|
13
13
|
import { DeleteObjectCommand, HeadBucketCommand, ListObjectsV2Command, PutObjectCommand, S3Client } from "@aws-sdk/client-s3";
|
|
14
|
+
import { setupDotenv } from "c12";
|
|
14
15
|
import { Pool } from "pg";
|
|
15
16
|
import { existsSync } from "node:fs";
|
|
16
17
|
|
|
@@ -88,12 +89,22 @@ const reconcileLocalAdministrator = Effect.fn("LocalAdministrator.reconcile")(fu
|
|
|
88
89
|
const nodeLayer = Layer.merge(NodeCrypto.layer, Layer.merge(NodeFileSystem.layer, NodePath.layer));
|
|
89
90
|
const InitializationStatus = Schema.Struct({ needsAdministrator: Schema.optionalKey(Schema.Boolean) });
|
|
90
91
|
const CauseCarrier = Schema.Struct({ cause: Schema.Unknown });
|
|
91
|
-
|
|
92
|
+
var CmsLifecycleFailed = class extends Schema.TaggedError()("CmsLifecycleFailed", {
|
|
93
|
+
cause: Schema.Defect(),
|
|
94
|
+
message: Schema.String,
|
|
95
|
+
phase: Schema.String
|
|
96
|
+
}) {};
|
|
97
|
+
const isCmsLifecycleFailed = Schema.is(CmsLifecycleFailed);
|
|
98
|
+
async function doctorCmsDevelopment(rootDir, full = false, envFile) {
|
|
92
99
|
const checks = [];
|
|
93
100
|
let configuration;
|
|
94
101
|
try {
|
|
95
|
-
|
|
96
|
-
compileCmsConfiguration(configuration);
|
|
102
|
+
const project = await loadConfiguration(rootDir, envFile);
|
|
103
|
+
compileCmsConfiguration(project.authored.configuration);
|
|
104
|
+
configuration = resolveCmsInstallation(project.authored.configuration, project.runtime, {
|
|
105
|
+
revision: "doctor",
|
|
106
|
+
components: []
|
|
107
|
+
});
|
|
97
108
|
checks.push(pass("configuration", "Configuration loaded"));
|
|
98
109
|
} catch (cause) {
|
|
99
110
|
checks.push(fail("configuration", "Configuration loaded", message(cause)));
|
|
@@ -123,16 +134,17 @@ async function doctorCmsDevelopment(rootDir, full = false) {
|
|
|
123
134
|
} finally {
|
|
124
135
|
await pool.end();
|
|
125
136
|
}
|
|
126
|
-
if (configuration.media ===
|
|
137
|
+
if (configuration.media === void 0) checks.push(pass("s3", "Media storage disabled"));
|
|
127
138
|
else {
|
|
128
|
-
const storage = configuration.media
|
|
139
|
+
const storage = configuration.media;
|
|
129
140
|
const client = s3Client(storage);
|
|
130
141
|
let publicProbeKey;
|
|
131
142
|
try {
|
|
132
143
|
await client.send(new HeadBucketCommand({ Bucket: storage.bucket }));
|
|
133
144
|
checks.push(pass("s3", "S3 bucket reachable"));
|
|
134
145
|
if (full) {
|
|
135
|
-
const
|
|
146
|
+
const relativeKey = `.doctor/${randomUUID()}`;
|
|
147
|
+
const key = `${storage.prefix}${relativeKey}`;
|
|
136
148
|
await client.send(new PutObjectCommand({
|
|
137
149
|
Bucket: storage.bucket,
|
|
138
150
|
Key: key,
|
|
@@ -147,7 +159,7 @@ async function doctorCmsDevelopment(rootDir, full = false) {
|
|
|
147
159
|
try {
|
|
148
160
|
if (full && !publicProbeKey) checks.push(notVerified("media-url", "Public media URL reachable", "The transient S3 upload failed."));
|
|
149
161
|
else {
|
|
150
|
-
const url = publicProbeKey ? publicObjectUrl(
|
|
162
|
+
const url = publicProbeKey ? publicObjectUrl(storage.publicBaseUrl, publicProbeKey.slice(storage.prefix.length)) : new URL(storage.publicBaseUrl);
|
|
151
163
|
const response = await fetch(url, { method: "HEAD" });
|
|
152
164
|
checks.push(response.ok || !full && response.status === 404 ? pass("media-url", "Public media URL reachable") : fail("media-url", "Public media URL reachable", `${url.href} returned HTTP ${response.status}.`));
|
|
153
165
|
}
|
|
@@ -187,36 +199,45 @@ async function doctorCmsDevelopment(rootDir, full = false) {
|
|
|
187
199
|
}
|
|
188
200
|
async function bootstrapCmsDevelopment(options) {
|
|
189
201
|
if (!options.email || !options.password) throw new Error("CMS_EMAIL and CMS_PASSWORD are required for bootstrap.");
|
|
190
|
-
const
|
|
191
|
-
const authoring = await prepareAuthoring(options.rootDir);
|
|
192
|
-
const resolved = resolveCmsInstallation(configuration, authoring);
|
|
193
|
-
const installation = await Effect.runPromise(installCms(resolved));
|
|
194
|
-
const localFetch = (input, init) =>
|
|
202
|
+
const project = await inPhase("bootstrap.configuration", () => loadConfiguration(options.rootDir, options.envFile));
|
|
203
|
+
const authoring = await inPhase("bootstrap.authoring", () => prepareAuthoring(options.rootDir, options.verbose));
|
|
204
|
+
const resolved = inPhaseSync("bootstrap.configuration", () => resolveCmsInstallation(project.authored.configuration, project.runtime, authoring));
|
|
205
|
+
const installation = await inPhase("bootstrap.installation", () => Effect.runPromise(installCms(resolved).pipe(Effect.provideService(References.MinimumLogLevel, options.verbose ? "Info" : "None"))));
|
|
206
|
+
const localFetch = (input, init) => {
|
|
207
|
+
const request = input instanceof Request ? new Request(input, init) : new Request(input, init);
|
|
208
|
+
const headers = new Headers(request.headers);
|
|
209
|
+
headers.set("x-forwarded-for", "127.0.0.1");
|
|
210
|
+
return installation.fetch(new Request(request, { headers }));
|
|
211
|
+
};
|
|
195
212
|
try {
|
|
196
|
-
const status = await localFetch(new URL(`${STUDIO_API_PATH}/initialization`,
|
|
197
|
-
const state = Result.getOrThrow(Schema.decodeUnknownResult(InitializationStatus)(await status.json()));
|
|
213
|
+
const status = await inPhase("bootstrap.initialization", () => localFetch(new URL(`${STUDIO_API_PATH}/initialization`, resolved.baseUrl)));
|
|
214
|
+
const state = await inPhase("bootstrap.initialization", async () => Result.getOrThrow(Schema.decodeUnknownResult(InitializationStatus)(await status.json())));
|
|
198
215
|
let initialized = false;
|
|
199
216
|
if (state.needsAdministrator) {
|
|
200
|
-
const claimed = await localFetch(new URL(`${STUDIO_API_PATH}/initialization`,
|
|
217
|
+
const claimed = await inPhase("bootstrap.initialization", () => localFetch(new URL(`${STUDIO_API_PATH}/initialization`, resolved.baseUrl), {
|
|
201
218
|
method: "POST",
|
|
202
219
|
headers: { "content-type": "application/json" },
|
|
203
220
|
body: JSON.stringify({
|
|
204
221
|
email: options.email,
|
|
205
|
-
initializationToken:
|
|
222
|
+
initializationToken: resolved.initializationToken,
|
|
206
223
|
name: options.name,
|
|
207
224
|
password: options.password
|
|
208
225
|
})
|
|
226
|
+
}));
|
|
227
|
+
if (!claimed.ok) throw new CmsLifecycleFailed({
|
|
228
|
+
cause: /* @__PURE__ */ new Error(`Administrator initialization failed (${claimed.status}).`),
|
|
229
|
+
message: `Administrator initialization failed (${claimed.status}).`,
|
|
230
|
+
phase: "bootstrap.initialization"
|
|
209
231
|
});
|
|
210
|
-
if (!claimed.ok) throw new Error(`Administrator initialization failed (${claimed.status}).`);
|
|
211
232
|
initialized = true;
|
|
212
233
|
}
|
|
213
|
-
const administrator = initialized ? "created" : await reconcileAdministrator(
|
|
234
|
+
const administrator = initialized ? "created" : await inPhase("bootstrap.administrator", () => reconcileAdministrator(resolved, {
|
|
214
235
|
email: options.email,
|
|
215
236
|
name: options.name,
|
|
216
237
|
password: options.password
|
|
217
|
-
});
|
|
238
|
+
}));
|
|
218
239
|
const content = createCmsContentClient({
|
|
219
|
-
baseUrl:
|
|
240
|
+
baseUrl: resolved.baseUrl,
|
|
220
241
|
credentials: {
|
|
221
242
|
email: options.email,
|
|
222
243
|
password: options.password
|
|
@@ -224,19 +245,27 @@ async function bootstrapCmsDevelopment(options) {
|
|
|
224
245
|
fetch: localFetch
|
|
225
246
|
});
|
|
226
247
|
if (!options.content) {
|
|
227
|
-
await content.diff({ sources: [] });
|
|
248
|
+
await inPhase("bootstrap.content", () => content.diff({ sources: [] }));
|
|
228
249
|
return {
|
|
229
250
|
administrator,
|
|
230
251
|
contentApplied: false
|
|
231
252
|
};
|
|
232
253
|
}
|
|
233
|
-
const
|
|
234
|
-
const
|
|
254
|
+
const contentDirectory = options.content;
|
|
255
|
+
const source = await inPhase("bootstrap.content", () => readCmsContentDirectory(contentDirectory));
|
|
256
|
+
const plan = await inPhase("bootstrap.content", () => content.plan(source, {
|
|
235
257
|
overwrite: true,
|
|
236
258
|
publish: options.publish
|
|
237
|
-
});
|
|
238
|
-
if (!plan.valid)
|
|
239
|
-
|
|
259
|
+
}));
|
|
260
|
+
if (!plan.valid) {
|
|
261
|
+
const details = [...plan.conflicts.map((entry) => `${entry.sourcePath}: conflicts with the current CMS content`), ...plan.issues.map((issue) => `${issue.sourcePath ?? issue.key ?? "content"}${issue.field ? ` (${issue.field})` : ""}: ${issue.message}`)];
|
|
262
|
+
throw new CmsLifecycleFailed({
|
|
263
|
+
cause: /* @__PURE__ */ new Error(`Bootstrap content has conflicts or validation errors. ${details.join(" ")}`),
|
|
264
|
+
message: `Bootstrap content has conflicts or validation errors. ${details.join(" ")}`,
|
|
265
|
+
phase: "bootstrap.content"
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
await inPhase("bootstrap.content", () => content.apply(plan));
|
|
240
269
|
return {
|
|
241
270
|
administrator,
|
|
242
271
|
contentApplied: true
|
|
@@ -261,18 +290,25 @@ async function reconcileAdministrator(configuration, administrator) {
|
|
|
261
290
|
}
|
|
262
291
|
}
|
|
263
292
|
async function resetCmsDevelopment(options) {
|
|
264
|
-
const
|
|
265
|
-
const
|
|
293
|
+
const project = await inPhase("reset.configuration", () => loadConfiguration(options.rootDir, options.envFile));
|
|
294
|
+
const configuration = inPhaseSync("reset.configuration", () => resolveCmsInstallation(project.authored.configuration, project.runtime, {
|
|
295
|
+
revision: "reset",
|
|
296
|
+
components: []
|
|
297
|
+
}));
|
|
298
|
+
const targets = [...options.database ? [`PostgreSQL schema ${configuration.database.schema}`] : [], ...options.media && configuration.media !== void 0 ? [`S3 prefix ${configuration.media.bucket}/${configuration.media.prefix}`] : []];
|
|
266
299
|
if (!options.yes) return {
|
|
267
300
|
executed: false,
|
|
268
301
|
targets,
|
|
269
302
|
bootstrapped: false
|
|
270
303
|
};
|
|
271
|
-
await refuseRunningInstallation(configuration.baseUrl);
|
|
272
|
-
if (options.database) await resetDatabase(configuration.database);
|
|
273
|
-
|
|
304
|
+
await inPhase("reset.safety", () => refuseRunningInstallation(configuration.baseUrl));
|
|
305
|
+
if (options.database) await inPhase("reset.database", () => resetDatabase(configuration.database));
|
|
306
|
+
const media = configuration.media;
|
|
307
|
+
if (options.media && media !== void 0) await inPhase("reset.media", () => resetMedia(media));
|
|
274
308
|
if (options.bootstrap) await bootstrapCmsDevelopment({
|
|
275
309
|
rootDir: options.rootDir,
|
|
310
|
+
envFile: options.envFile,
|
|
311
|
+
verbose: options.verbose,
|
|
276
312
|
...options.bootstrap
|
|
277
313
|
});
|
|
278
314
|
return {
|
|
@@ -281,14 +317,38 @@ async function resetCmsDevelopment(options) {
|
|
|
281
317
|
bootstrapped: options.bootstrap !== void 0
|
|
282
318
|
};
|
|
283
319
|
}
|
|
284
|
-
async function
|
|
285
|
-
|
|
320
|
+
async function loadCmsProjectEnvironment(rootDir, envFile) {
|
|
321
|
+
await setupDotenv({
|
|
322
|
+
cwd: resolve(rootDir),
|
|
323
|
+
fileName: envFile ? [".env", envFile] : ".env"
|
|
324
|
+
});
|
|
286
325
|
}
|
|
287
|
-
async function
|
|
326
|
+
async function loadConfiguration(rootDir, envFile) {
|
|
327
|
+
const absoluteRoot = resolve(rootDir);
|
|
328
|
+
await loadCmsProjectEnvironment(absoluteRoot, envFile);
|
|
329
|
+
const authored = await Effect.runPromise(loadCmsConfiguration(absoluteRoot).pipe(Effect.provide(nodeLayer)));
|
|
330
|
+
const nuxt = await loadNuxtConfig({
|
|
331
|
+
cwd: absoluteRoot,
|
|
332
|
+
dotenv: false
|
|
333
|
+
});
|
|
334
|
+
const defaults = cmsRuntimeConfigurationDefaults(authored.configuration, nuxt.runtimeConfig.cms);
|
|
335
|
+
return {
|
|
336
|
+
authored,
|
|
337
|
+
runtime: await Effect.runPromise(cmsRuntimeConfigurationFromEnvironment(defaults))
|
|
338
|
+
};
|
|
339
|
+
}
|
|
340
|
+
async function prepareAuthoring(rootDir, verbose = false) {
|
|
288
341
|
const nuxt = await loadNuxt({
|
|
289
342
|
cwd: rootDir,
|
|
290
343
|
dev: true,
|
|
291
|
-
ready: true
|
|
344
|
+
ready: true,
|
|
345
|
+
overrides: {
|
|
346
|
+
logLevel: verbose ? "verbose" : "silent",
|
|
347
|
+
...verbose ? void 0 : {
|
|
348
|
+
devtools: { enabled: false },
|
|
349
|
+
seo: { metaDataFiles: false }
|
|
350
|
+
}
|
|
351
|
+
}
|
|
292
352
|
});
|
|
293
353
|
try {
|
|
294
354
|
const source = (await readFile(resolve(nuxt.options.buildDir, "cms/authoring.mjs"), "utf8")).replace(/^export default /u, "").trim();
|
|
@@ -392,6 +452,7 @@ function pass(id, label) {
|
|
|
392
452
|
return {
|
|
393
453
|
id,
|
|
394
454
|
label,
|
|
455
|
+
phase: `doctor.${id}`,
|
|
395
456
|
status: "pass"
|
|
396
457
|
};
|
|
397
458
|
}
|
|
@@ -399,6 +460,7 @@ function fail(id, label, detail) {
|
|
|
399
460
|
return {
|
|
400
461
|
id,
|
|
401
462
|
label,
|
|
463
|
+
phase: `doctor.${id}`,
|
|
402
464
|
status: "fail",
|
|
403
465
|
detail
|
|
404
466
|
};
|
|
@@ -407,6 +469,7 @@ function notVerified(id, label, detail) {
|
|
|
407
469
|
return {
|
|
408
470
|
id,
|
|
409
471
|
label,
|
|
472
|
+
phase: `doctor.${id}`,
|
|
410
473
|
status: "not-verified",
|
|
411
474
|
detail
|
|
412
475
|
};
|
|
@@ -422,7 +485,31 @@ function message(cause) {
|
|
|
422
485
|
if (Schema.is(CauseCarrier)(cause)) return message(cause.cause);
|
|
423
486
|
return String(cause);
|
|
424
487
|
}
|
|
488
|
+
async function inPhase(phase, operation) {
|
|
489
|
+
try {
|
|
490
|
+
return await operation();
|
|
491
|
+
} catch (cause) {
|
|
492
|
+
if (isCmsLifecycleFailed(cause)) throw cause;
|
|
493
|
+
throw new CmsLifecycleFailed({
|
|
494
|
+
cause,
|
|
495
|
+
message: message(cause),
|
|
496
|
+
phase
|
|
497
|
+
});
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
function inPhaseSync(phase, operation) {
|
|
501
|
+
try {
|
|
502
|
+
return operation();
|
|
503
|
+
} catch (cause) {
|
|
504
|
+
if (isCmsLifecycleFailed(cause)) throw cause;
|
|
505
|
+
throw new CmsLifecycleFailed({
|
|
506
|
+
cause,
|
|
507
|
+
message: message(cause),
|
|
508
|
+
phase
|
|
509
|
+
});
|
|
510
|
+
}
|
|
511
|
+
}
|
|
425
512
|
|
|
426
513
|
//#endregion
|
|
427
|
-
export { doctorCmsDevelopment as n,
|
|
428
|
-
//# sourceMappingURL=dev-lifecycle-
|
|
514
|
+
export { resetCmsDevelopment as i, doctorCmsDevelopment as n, loadCmsProjectEnvironment as r, bootstrapCmsDevelopment as t };
|
|
515
|
+
//# sourceMappingURL=dev-lifecycle-D3f9-upa.js.map
|