@cms0/cms0 0.2.19 → 0.2.21
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 +11 -0
- package/dist/cjs/custom-types/registry.cjs +6 -0
- package/dist/cjs/descriptor-sidecar.cjs +5 -0
- package/dist/cjs/index.cjs +425 -70
- package/dist/cjs/libs/cli/browser-sidecar.cjs +30 -0
- package/dist/cjs/libs/cli/config-loader.cjs +45 -4
- package/dist/cjs/libs/cli/publisher.cjs +24 -11
- package/dist/cjs/schema-descriptors.cjs +49 -0
- package/dist/esm/custom-types/registry.js +6 -0
- package/dist/esm/descriptor-sidecar.js +5 -1
- package/dist/esm/index.js +427 -72
- package/dist/esm/libs/cli/browser-sidecar.js +30 -0
- package/dist/esm/libs/cli/config-loader.js +45 -4
- package/dist/esm/libs/cli/publisher.js +24 -11
- package/dist/esm/schema-descriptors.js +48 -1
- package/dist/types/custom-types/index.d.ts +2 -1
- package/dist/types/custom-types/index.d.ts.map +1 -1
- package/dist/types/custom-types/registry.d.ts.map +1 -1
- package/dist/types/descriptor-sidecar.d.ts +2 -1
- package/dist/types/descriptor-sidecar.d.ts.map +1 -1
- package/dist/types/index.d.ts +131 -7
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/libs/cli/browser-sidecar.d.ts.map +1 -1
- package/dist/types/libs/cli/config-loader.d.ts.map +1 -1
- package/dist/types/libs/cli/publisher.d.ts.map +1 -1
- package/dist/types/schema-descriptors.d.ts +2 -0
- package/dist/types/schema-descriptors.d.ts.map +1 -1
- package/package.json +13 -9
- package/dist/cjs/index-old-1.cjs +0 -866
- package/dist/cjs/index-old.cjs +0 -1016
- package/dist/cjs/libs/cli/descriptor-builder.cjs +0 -273
- package/dist/cjs/utils/index.cjs +0 -2
- package/dist/esm/index-old-1.js +0 -862
- package/dist/esm/index-old.js +0 -1012
- package/dist/esm/libs/cli/descriptor-builder.js +0 -268
- package/dist/esm/utils/index.js +0 -1
- package/dist/types/index-old-1.d.ts +0 -175
- package/dist/types/index-old-1.d.ts.map +0 -1
- package/dist/types/index-old.d.ts +0 -151
- package/dist/types/index-old.d.ts.map +0 -1
- package/dist/types/libs/cli/descriptor-builder.d.ts +0 -5
- package/dist/types/libs/cli/descriptor-builder.d.ts.map +0 -1
- package/dist/types/utils/index.d.ts +0 -2
- package/dist/types/utils/index.d.ts.map +0 -1
|
@@ -6,9 +6,14 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.startBrowserDescriptorSidecar = startBrowserDescriptorSidecar;
|
|
7
7
|
const node_http_1 = __importDefault(require("node:http"));
|
|
8
8
|
const descriptor_sidecar_js_1 = require("../../descriptor-sidecar.cjs");
|
|
9
|
+
function writeSchemaVersionEvent(response, version) {
|
|
10
|
+
response.write(`event: schema-version\ndata: ${JSON.stringify({ version })}\n\n`);
|
|
11
|
+
}
|
|
9
12
|
function startBrowserDescriptorSidecar(resolved, initialDescriptor) {
|
|
10
13
|
const port = (0, descriptor_sidecar_js_1.getCms0DescriptorSidecarPort)(resolved.apiBaseUrl, resolved.apiKey);
|
|
11
14
|
let currentDescriptor = initialDescriptor;
|
|
15
|
+
let currentVersion = 1;
|
|
16
|
+
const eventClients = new Set();
|
|
12
17
|
const server = node_http_1.default.createServer((request, response) => {
|
|
13
18
|
const requestUrl = new URL(request.url ?? "/", `http://127.0.0.1:${port}`);
|
|
14
19
|
response.setHeader("Access-Control-Allow-Origin", "*");
|
|
@@ -19,6 +24,19 @@ function startBrowserDescriptorSidecar(resolved, initialDescriptor) {
|
|
|
19
24
|
response.end();
|
|
20
25
|
return;
|
|
21
26
|
}
|
|
27
|
+
if (request.method === "GET" && requestUrl.pathname === "/schema-events") {
|
|
28
|
+
response.writeHead(200, {
|
|
29
|
+
"content-type": "text/event-stream; charset=utf-8",
|
|
30
|
+
"cache-control": "no-store",
|
|
31
|
+
connection: "keep-alive",
|
|
32
|
+
});
|
|
33
|
+
response.write(": cms0 browser schema sidecar\n\n");
|
|
34
|
+
eventClients.add(response);
|
|
35
|
+
request.on("close", () => {
|
|
36
|
+
eventClients.delete(response);
|
|
37
|
+
});
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
22
40
|
if (request.method !== "GET" || requestUrl.pathname !== "/schema-descriptor") {
|
|
23
41
|
response.writeHead(404, { "content-type": "application/json; charset=utf-8" });
|
|
24
42
|
response.end(JSON.stringify({ error: "Not found" }));
|
|
@@ -38,9 +56,21 @@ function startBrowserDescriptorSidecar(resolved, initialDescriptor) {
|
|
|
38
56
|
resolve({
|
|
39
57
|
updateDescriptor(descriptor) {
|
|
40
58
|
currentDescriptor = descriptor;
|
|
59
|
+
currentVersion += 1;
|
|
60
|
+
for (const client of [...eventClients]) {
|
|
61
|
+
if (client.destroyed || client.writableEnded) {
|
|
62
|
+
eventClients.delete(client);
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
writeSchemaVersionEvent(client, currentVersion);
|
|
66
|
+
}
|
|
41
67
|
},
|
|
42
68
|
close() {
|
|
43
69
|
return new Promise((closeResolve, closeReject) => {
|
|
70
|
+
for (const client of eventClients) {
|
|
71
|
+
client.end();
|
|
72
|
+
}
|
|
73
|
+
eventClients.clear();
|
|
44
74
|
server.close((error) => {
|
|
45
75
|
if (error) {
|
|
46
76
|
closeReject(error);
|
|
@@ -46,6 +46,7 @@ const fs_1 = __importDefault(require("fs"));
|
|
|
46
46
|
const path_1 = __importDefault(require("path"));
|
|
47
47
|
const url_1 = require("url");
|
|
48
48
|
const crypto_1 = __importDefault(require("crypto"));
|
|
49
|
+
const module_1 = require("module");
|
|
49
50
|
const DEFAULT_CONFIG_BASENAMES = [
|
|
50
51
|
"cms0.config.ts",
|
|
51
52
|
"cms0.config.js",
|
|
@@ -145,9 +146,7 @@ function resolvePaths(cfgPath, config) {
|
|
|
145
146
|
}
|
|
146
147
|
const baseDir = path_1.default.dirname(cfgPath);
|
|
147
148
|
const packageJsonPath = findNearestPackageJson(cfgPath);
|
|
148
|
-
const projectRoot = packageJsonPath
|
|
149
|
-
? path_1.default.dirname(packageJsonPath)
|
|
150
|
-
: baseDir;
|
|
149
|
+
const projectRoot = packageJsonPath ? path_1.default.dirname(packageJsonPath) : baseDir;
|
|
151
150
|
const entryFile = path_1.default.resolve(baseDir, config.entry);
|
|
152
151
|
const tsconfigPath = config.tsconfig
|
|
153
152
|
? path_1.default.resolve(baseDir, config.tsconfig)
|
|
@@ -178,7 +177,7 @@ function findTsConfig(entryFile) {
|
|
|
178
177
|
return undefined;
|
|
179
178
|
}
|
|
180
179
|
async function transpileTsModuleToTemp(tsPath, format) {
|
|
181
|
-
const ts = await
|
|
180
|
+
const ts = await loadTypescriptCompiler(tsPath);
|
|
182
181
|
const source = fs_1.default.readFileSync(tsPath, "utf8");
|
|
183
182
|
const transpiled = ts.transpileModule(source, {
|
|
184
183
|
compilerOptions: {
|
|
@@ -204,3 +203,45 @@ function cleanupTempModule(tempPath) {
|
|
|
204
203
|
// ignore cleanup failures
|
|
205
204
|
}
|
|
206
205
|
}
|
|
206
|
+
async function loadTypescriptCompiler(tsPath) {
|
|
207
|
+
const attemptedErrors = [];
|
|
208
|
+
const manifestCandidates = [
|
|
209
|
+
findNearestPackageJson(tsPath),
|
|
210
|
+
path_1.default.join(process.cwd(), "package.json"),
|
|
211
|
+
].filter((candidate) => Boolean(candidate && fs_1.default.existsSync(candidate)));
|
|
212
|
+
for (const manifest of manifestCandidates) {
|
|
213
|
+
try {
|
|
214
|
+
const resolver = (0, module_1.createRequire)(manifest);
|
|
215
|
+
const mod = resolver("typescript");
|
|
216
|
+
return normalizeTypescriptModule(mod);
|
|
217
|
+
}
|
|
218
|
+
catch (error) {
|
|
219
|
+
attemptedErrors.push(error);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
try {
|
|
223
|
+
const mod = (0, module_1.createRequire)(path_1.default.resolve("package.json"))("typescript");
|
|
224
|
+
return normalizeTypescriptModule(mod);
|
|
225
|
+
}
|
|
226
|
+
catch (error) {
|
|
227
|
+
attemptedErrors.push(error);
|
|
228
|
+
}
|
|
229
|
+
try {
|
|
230
|
+
const mod = await Promise.resolve().then(() => __importStar(require("typescript")));
|
|
231
|
+
return normalizeTypescriptModule(mod);
|
|
232
|
+
}
|
|
233
|
+
catch (error) {
|
|
234
|
+
attemptedErrors.push(error);
|
|
235
|
+
}
|
|
236
|
+
throw new AggregateError(attemptedErrors, 'cms0: Unable to resolve the "typescript" package required to load cms0.config.* files. Ensure it is installed in your project.');
|
|
237
|
+
}
|
|
238
|
+
function normalizeTypescriptModule(mod) {
|
|
239
|
+
if (mod && typeof mod.transpileModule === "function") {
|
|
240
|
+
return mod;
|
|
241
|
+
}
|
|
242
|
+
const candidate = mod?.default;
|
|
243
|
+
if (candidate && typeof candidate.transpileModule === "function") {
|
|
244
|
+
return candidate;
|
|
245
|
+
}
|
|
246
|
+
throw new Error("cms0: resolved 'typescript' module does not provide transpileModule");
|
|
247
|
+
}
|
|
@@ -20,6 +20,17 @@ function shouldRetryPublishError(error) {
|
|
|
20
20
|
}
|
|
21
21
|
return true;
|
|
22
22
|
}
|
|
23
|
+
function trimTrailingSlashes(value) {
|
|
24
|
+
return value.replace(/\/+$/, "");
|
|
25
|
+
}
|
|
26
|
+
function buildSchemaPublishUrl(baseUrl) {
|
|
27
|
+
const normalized = trimTrailingSlashes(baseUrl);
|
|
28
|
+
return `${normalized}/schema`;
|
|
29
|
+
}
|
|
30
|
+
function buildHealthUrls(baseUrl) {
|
|
31
|
+
const normalized = trimTrailingSlashes(baseUrl);
|
|
32
|
+
return [`${normalized}/health`];
|
|
33
|
+
}
|
|
23
34
|
const startSpinner = (label) => {
|
|
24
35
|
if (!process.stdout.isTTY) {
|
|
25
36
|
console.log(`${label}...`);
|
|
@@ -47,7 +58,7 @@ const startSpinner = (label) => {
|
|
|
47
58
|
};
|
|
48
59
|
};
|
|
49
60
|
async function waitForAdminReady(baseUrl, headers) {
|
|
50
|
-
const
|
|
61
|
+
const healthUrls = buildHealthUrls(baseUrl);
|
|
51
62
|
const maxWaitMs = 30_000;
|
|
52
63
|
const startedAt = Date.now();
|
|
53
64
|
const spinner = startSpinner("cms0: waiting for admin to reload");
|
|
@@ -55,15 +66,17 @@ async function waitForAdminReady(baseUrl, headers) {
|
|
|
55
66
|
let attempt = 0;
|
|
56
67
|
while (Date.now() - startedAt < maxWaitMs) {
|
|
57
68
|
attempt += 1;
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
69
|
+
for (const healthUrl of healthUrls) {
|
|
70
|
+
try {
|
|
71
|
+
const res = await fetch(healthUrl, { headers });
|
|
72
|
+
if (res.ok) {
|
|
73
|
+
spinner.stop("cms0: admin ready");
|
|
74
|
+
return true;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
// ignore transient errors during restart
|
|
63
79
|
}
|
|
64
|
-
}
|
|
65
|
-
catch {
|
|
66
|
-
// ignore transient errors during restart
|
|
67
80
|
}
|
|
68
81
|
await sleep(Math.min(500 + attempt * 250, 2000));
|
|
69
82
|
}
|
|
@@ -84,7 +97,7 @@ async function publishDescriptor(resolved, descriptor) {
|
|
|
84
97
|
if (resolved.apiKey) {
|
|
85
98
|
headers["Authorization"] = `Bearer ${resolved.apiKey}`;
|
|
86
99
|
}
|
|
87
|
-
const target =
|
|
100
|
+
const target = buildSchemaPublishUrl(resolved.apiBaseUrl);
|
|
88
101
|
const maxAttempts = 5;
|
|
89
102
|
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
90
103
|
try {
|
|
@@ -96,7 +109,7 @@ async function publishDescriptor(resolved, descriptor) {
|
|
|
96
109
|
if (!res.ok) {
|
|
97
110
|
throw new PublishHttpError(res.status);
|
|
98
111
|
}
|
|
99
|
-
const ready = await waitForAdminReady(resolved.apiBaseUrl
|
|
112
|
+
const ready = await waitForAdminReady(trimTrailingSlashes(resolved.apiBaseUrl), headers);
|
|
100
113
|
if (!ready) {
|
|
101
114
|
console.warn("cms0: publish succeeded, but admin did not become healthy in time.");
|
|
102
115
|
}
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.schemaDescriptor = void 0;
|
|
4
4
|
exports.readLocalSchemaDescriptor = readLocalSchemaDescriptor;
|
|
5
|
+
exports.invalidateBrowserSchemaDescriptorCache = invalidateBrowserSchemaDescriptorCache;
|
|
6
|
+
exports.ensureBrowserSchemaDescriptorDevSubscription = ensureBrowserSchemaDescriptorDevSubscription;
|
|
5
7
|
exports.resolveBrowserSchemaDescriptor = resolveBrowserSchemaDescriptor;
|
|
6
8
|
exports.getActiveSchemaDescriptor = getActiveSchemaDescriptor;
|
|
7
9
|
exports.syncActiveSchemaDescriptorGlobals = syncActiveSchemaDescriptorGlobals;
|
|
@@ -14,6 +16,7 @@ const LOCAL_DESCRIPTOR_RELATIVE_SEGMENTS = [
|
|
|
14
16
|
];
|
|
15
17
|
let cachedLocalDescriptor = null;
|
|
16
18
|
const browserDescriptorPromiseCache = new Map();
|
|
19
|
+
const browserDescriptorSubscriptionCache = new Map();
|
|
17
20
|
exports.schemaDescriptor = schema_descriptor_1.schemaDescriptor;
|
|
18
21
|
function setSchemaDescriptorGlobals(descriptor) {
|
|
19
22
|
const globals = globalThis;
|
|
@@ -205,6 +208,52 @@ function createBrowserDescriptorFetchError(sidecarUrl, reason) {
|
|
|
205
208
|
const details = reason ? ` ${reason}` : "";
|
|
206
209
|
return new Error(`cms0: failed to load the browser schema descriptor from ${sidecarUrl}.${details} Start the cms0 sidecar before calling cms0() in the browser.`);
|
|
207
210
|
}
|
|
211
|
+
function clearBrowserSchemaDescriptorGlobals() {
|
|
212
|
+
const globals = globalThis;
|
|
213
|
+
delete globals.__CMS0_SCHEMA_DESCRIPTOR__;
|
|
214
|
+
delete globals.__CMS0_CANVAS_SCHEMA_DESCRIPTOR__;
|
|
215
|
+
}
|
|
216
|
+
function invalidateBrowserSchemaDescriptorCache(baseUrl, apiKey) {
|
|
217
|
+
clearBrowserSchemaDescriptorGlobals();
|
|
218
|
+
browserDescriptorPromiseCache.delete((0, descriptor_sidecar_js_1.getCms0DescriptorSidecarUrl)(baseUrl, apiKey));
|
|
219
|
+
}
|
|
220
|
+
function ensureBrowserSchemaDescriptorDevSubscription(baseUrl, apiKey, onInvalidate) {
|
|
221
|
+
if (typeof window === "undefined")
|
|
222
|
+
return;
|
|
223
|
+
if (readBundledBrowserDescriptor())
|
|
224
|
+
return;
|
|
225
|
+
if (typeof globalThis.EventSource !== "function")
|
|
226
|
+
return;
|
|
227
|
+
const eventsUrl = (0, descriptor_sidecar_js_1.getCms0DescriptorSidecarEventsUrl)(baseUrl, apiKey);
|
|
228
|
+
let subscription = browserDescriptorSubscriptionCache.get(eventsUrl);
|
|
229
|
+
if (!subscription) {
|
|
230
|
+
const listeners = new Set();
|
|
231
|
+
const source = new globalThis.EventSource(eventsUrl);
|
|
232
|
+
const handleSchemaVersion = () => {
|
|
233
|
+
invalidateBrowserSchemaDescriptorCache(baseUrl, apiKey);
|
|
234
|
+
for (const listener of listeners) {
|
|
235
|
+
listener();
|
|
236
|
+
}
|
|
237
|
+
};
|
|
238
|
+
const handleError = () => {
|
|
239
|
+
const activeSubscription = browserDescriptorSubscriptionCache.get(eventsUrl);
|
|
240
|
+
if (activeSubscription?.source === source) {
|
|
241
|
+
browserDescriptorSubscriptionCache.delete(eventsUrl);
|
|
242
|
+
}
|
|
243
|
+
source.close();
|
|
244
|
+
};
|
|
245
|
+
source.addEventListener("schema-version", handleSchemaVersion);
|
|
246
|
+
source.onerror = handleError;
|
|
247
|
+
subscription = {
|
|
248
|
+
listeners,
|
|
249
|
+
source,
|
|
250
|
+
};
|
|
251
|
+
browserDescriptorSubscriptionCache.set(eventsUrl, subscription);
|
|
252
|
+
}
|
|
253
|
+
if (onInvalidate) {
|
|
254
|
+
subscription.listeners.add(onInvalidate);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
208
257
|
async function resolveBrowserSchemaDescriptor(baseUrl, apiKey) {
|
|
209
258
|
const injectedDescriptor = readGlobalSchemaDescriptor();
|
|
210
259
|
if (injectedDescriptor) {
|
|
@@ -8,6 +8,12 @@ const primitive = (type) => ({
|
|
|
8
8
|
const fileFieldDescriptors = {
|
|
9
9
|
name: primitive("string"),
|
|
10
10
|
filename: primitive("string"),
|
|
11
|
+
storageKey: {
|
|
12
|
+
kind: "primitive",
|
|
13
|
+
type: "string",
|
|
14
|
+
optional: true,
|
|
15
|
+
nullable: false,
|
|
16
|
+
},
|
|
11
17
|
extension: primitive("string"),
|
|
12
18
|
mimeType: primitive("string"),
|
|
13
19
|
size: primitive("number"),
|
|
@@ -13,4 +13,8 @@ function getCms0DescriptorSidecarUrl(baseUrl, apiKey) {
|
|
|
13
13
|
const port = getCms0DescriptorSidecarPort(baseUrl, apiKey);
|
|
14
14
|
return `http://127.0.0.1:${port}/schema-descriptor`;
|
|
15
15
|
}
|
|
16
|
-
|
|
16
|
+
function getCms0DescriptorSidecarEventsUrl(baseUrl, apiKey) {
|
|
17
|
+
const port = getCms0DescriptorSidecarPort(baseUrl, apiKey);
|
|
18
|
+
return `http://127.0.0.1:${port}/schema-events`;
|
|
19
|
+
}
|
|
20
|
+
export { getCms0DescriptorSidecarPort, getCms0DescriptorSidecarUrl, getCms0DescriptorSidecarEventsUrl, hashCms0SidecarSeed, };
|