@fluid-app/fluid-cli-portal 0.1.58 → 0.1.60
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/dist/{backend-dev-plugin-CA3i3_ge.mjs → backend-dev-plugin-20fLk-4t.mjs} +2 -2
- package/dist/{backend-dev-plugin-CA3i3_ge.mjs.map → backend-dev-plugin-20fLk-4t.mjs.map} +1 -1
- package/dist/index.d.mts +18 -0
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +127 -40
- package/dist/index.mjs.map +1 -1
- package/dist/{portal-dev-plugin-DfEBjr96.mjs → portal-dev-plugin-5BbRo9QT.mjs} +2 -2
- package/dist/{portal-dev-plugin-DfEBjr96.mjs.map → portal-dev-plugin-5BbRo9QT.mjs.map} +1 -1
- package/dist/{portal-widget-dev-plugin-DUPIALuT.mjs → portal-widget-dev-plugin-NBHcnvFJ.mjs} +7 -5
- package/dist/{portal-widget-dev-plugin-DUPIALuT.mjs.map → portal-widget-dev-plugin-NBHcnvFJ.mjs.map} +1 -1
- package/dist/{pull-BZqZAiSF.mjs → pull-BlG6pMwC.mjs} +110 -62
- package/dist/pull-BlG6pMwC.mjs.map +1 -0
- package/dist/{src-CpaIqsaL.mjs → src-2znVq55R.mjs} +151 -26
- package/dist/src-2znVq55R.mjs.map +1 -0
- package/dist/vite-plugin.mjs +4 -4
- package/package.json +4 -4
- package/templates/base/skills/fluid-portal-authoring/SKILL.md +6 -2
- package/dist/pull-BZqZAiSF.mjs.map +0 -1
- package/dist/src-CpaIqsaL.mjs.map +0 -1
|
@@ -6,6 +6,150 @@ import { failure, success } from "@fluid-app/fluid-cli";
|
|
|
6
6
|
import { execa } from "execa";
|
|
7
7
|
import { createHash } from "node:crypto";
|
|
8
8
|
import fs from "fs-extra";
|
|
9
|
+
const REMOTE_DOM_WIDGET_RUNTIME = "remote-dom";
|
|
10
|
+
const PACKAGE_FIELDS = new Set([
|
|
11
|
+
"manifestVersion",
|
|
12
|
+
"runtime",
|
|
13
|
+
"packageId",
|
|
14
|
+
"source",
|
|
15
|
+
"version",
|
|
16
|
+
"workerEntryUrl",
|
|
17
|
+
"cssUrls",
|
|
18
|
+
"assetUrls",
|
|
19
|
+
"widgets"
|
|
20
|
+
]);
|
|
21
|
+
const WIDGET_FIELDS = new Set([
|
|
22
|
+
"type",
|
|
23
|
+
"displayName",
|
|
24
|
+
"description",
|
|
25
|
+
"icon",
|
|
26
|
+
"category",
|
|
27
|
+
"propertySchema",
|
|
28
|
+
"defaultProps",
|
|
29
|
+
"container",
|
|
30
|
+
"resizable",
|
|
31
|
+
"minSdkVersion",
|
|
32
|
+
"capabilities"
|
|
33
|
+
]);
|
|
34
|
+
const CAPABILITY_FIELDS = new Set(["name", "version"]);
|
|
35
|
+
const UNSAFE_JSON_KEYS = new Set([
|
|
36
|
+
"__proto__",
|
|
37
|
+
"constructor",
|
|
38
|
+
"prototype"
|
|
39
|
+
]);
|
|
40
|
+
function isRemoteDomWidgetPackageDescriptor(value) {
|
|
41
|
+
return getRemoteDomWidgetPackageInvalidReason(value) === void 0;
|
|
42
|
+
}
|
|
43
|
+
function getRemoteDomWidgetPackageInvalidReason(value) {
|
|
44
|
+
if (!isRecord$6(value)) return "descriptor must be an object";
|
|
45
|
+
const unexpectedFieldReason = getUnexpectedFieldReason(value, PACKAGE_FIELDS, "descriptor");
|
|
46
|
+
if (unexpectedFieldReason) return unexpectedFieldReason;
|
|
47
|
+
if (value.manifestVersion !== 1) return `manifestVersion must be 1`;
|
|
48
|
+
if (value.runtime !== "remote-dom") return `runtime must be ${REMOTE_DOM_WIDGET_RUNTIME}`;
|
|
49
|
+
const packageIdReason = getNonEmptyStringReason(value.packageId, "packageId");
|
|
50
|
+
if (packageIdReason) return packageIdReason;
|
|
51
|
+
if (value.source !== "company" && value.source !== "droplet") return "source must be company or droplet";
|
|
52
|
+
const versionReason = getNonEmptyStringReason(value.version, "version");
|
|
53
|
+
if (versionReason) return versionReason;
|
|
54
|
+
const workerEntryUrlReason = getHttpUrlReason(value.workerEntryUrl, "workerEntryUrl");
|
|
55
|
+
if (workerEntryUrlReason) return workerEntryUrlReason;
|
|
56
|
+
const cssUrlsReason = getUrlArrayReason(value.cssUrls, "cssUrls");
|
|
57
|
+
if (cssUrlsReason) return cssUrlsReason;
|
|
58
|
+
const assetUrlsReason = getUrlArrayReason(value.assetUrls, "assetUrls");
|
|
59
|
+
if (assetUrlsReason) return assetUrlsReason;
|
|
60
|
+
if (!Array.isArray(value.widgets) || value.widgets.length === 0) return "widgets must be a non-empty array";
|
|
61
|
+
const widgetTypes = /* @__PURE__ */ new Set();
|
|
62
|
+
for (let index = 0; index < value.widgets.length; index += 1) {
|
|
63
|
+
const widget = value.widgets[index];
|
|
64
|
+
const widgetReason = getWidgetReason(widget, `widgets[${index}]`);
|
|
65
|
+
if (widgetReason) return widgetReason;
|
|
66
|
+
const widgetType = widget.type;
|
|
67
|
+
if (widgetTypes.has(widgetType)) return `widgets contains duplicate type ${widgetType}`;
|
|
68
|
+
widgetTypes.add(widgetType);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
function getWidgetReason(value, path) {
|
|
72
|
+
if (!isRecord$6(value)) return `${path} must be an object`;
|
|
73
|
+
const unexpectedFieldReason = getUnexpectedFieldReason(value, WIDGET_FIELDS, path);
|
|
74
|
+
if (unexpectedFieldReason) return unexpectedFieldReason;
|
|
75
|
+
for (const field of [
|
|
76
|
+
"type",
|
|
77
|
+
"displayName",
|
|
78
|
+
"description",
|
|
79
|
+
"icon",
|
|
80
|
+
"category",
|
|
81
|
+
"minSdkVersion"
|
|
82
|
+
]) {
|
|
83
|
+
const reason = getNonEmptyStringReason(value[field], `${path}.${field}`);
|
|
84
|
+
if (reason) return reason;
|
|
85
|
+
}
|
|
86
|
+
if (!isRecord$6(value.propertySchema) || !isJsonValue(value.propertySchema)) return `${path}.propertySchema must be a JSON object`;
|
|
87
|
+
if (!isRecord$6(value.defaultProps) || !isJsonValue(value.defaultProps)) return `${path}.defaultProps must be a JSON object`;
|
|
88
|
+
if (value.container !== "inline" && value.container !== "block" && value.container !== "card" && value.container !== "fullscreen") return `${path}.container is unsupported`;
|
|
89
|
+
if (typeof value.resizable !== "boolean" && value.resizable !== "horizontal" && value.resizable !== "vertical" && value.resizable !== "both") return `${path}.resizable is unsupported`;
|
|
90
|
+
if (!Array.isArray(value.capabilities)) return `${path}.capabilities must be an array`;
|
|
91
|
+
const capabilityNames = /* @__PURE__ */ new Set();
|
|
92
|
+
for (let index = 0; index < value.capabilities.length; index += 1) {
|
|
93
|
+
const capability = value.capabilities[index];
|
|
94
|
+
const capabilityPath = `${path}.capabilities[${index}]`;
|
|
95
|
+
if (!isRecord$6(capability)) return `${capabilityPath} must be an object`;
|
|
96
|
+
const unexpectedFieldReason = getUnexpectedFieldReason(capability, CAPABILITY_FIELDS, capabilityPath);
|
|
97
|
+
if (unexpectedFieldReason) return unexpectedFieldReason;
|
|
98
|
+
const capabilityName = capability.name;
|
|
99
|
+
const nameReason = getNonEmptyStringReason(capabilityName, `${capabilityPath}.name`);
|
|
100
|
+
if (nameReason) return nameReason;
|
|
101
|
+
if (typeof capabilityName !== "string") return `${capabilityPath}.name must be a non-empty string`;
|
|
102
|
+
const versionReason = getNonEmptyStringReason(capability.version, `${capabilityPath}.version`);
|
|
103
|
+
if (versionReason) return versionReason;
|
|
104
|
+
if (capabilityNames.has(capabilityName)) return `${path}.capabilities contains duplicate name ${capabilityName}`;
|
|
105
|
+
capabilityNames.add(capabilityName);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
function getUrlArrayReason(value, path) {
|
|
109
|
+
if (!Array.isArray(value)) return `${path} must be an array`;
|
|
110
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
111
|
+
const reason = getHttpUrlReason(value[index], `${path}[${index}]`);
|
|
112
|
+
if (reason) return reason;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
function getHttpUrlReason(value, path) {
|
|
116
|
+
const stringReason = getNonEmptyStringReason(value, path);
|
|
117
|
+
if (stringReason) return stringReason;
|
|
118
|
+
if (typeof value !== "string") return `${path} must be a non-empty string`;
|
|
119
|
+
try {
|
|
120
|
+
const url = new URL(value);
|
|
121
|
+
if (url.protocol !== "http:" && url.protocol !== "https:") return `${path} must use http or https`;
|
|
122
|
+
if (url.username || url.password) return `${path} must not contain credentials`;
|
|
123
|
+
} catch {
|
|
124
|
+
return `${path} must be an absolute URL`;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
function getNonEmptyStringReason(value, path) {
|
|
128
|
+
if (typeof value !== "string" || value.trim().length === 0) return `${path} must be a non-empty string`;
|
|
129
|
+
if (value !== value.trim()) return `${path} must not have surrounding whitespace`;
|
|
130
|
+
if (/\p{Cc}/u.test(value)) return `${path} must not contain control characters`;
|
|
131
|
+
}
|
|
132
|
+
function isJsonValue(value) {
|
|
133
|
+
return isJsonValueAtDepth(value, /* @__PURE__ */ new WeakSet(), 0);
|
|
134
|
+
}
|
|
135
|
+
function isJsonValueAtDepth(value, ancestors, depth) {
|
|
136
|
+
if (value === null || typeof value === "string" || typeof value === "boolean") return true;
|
|
137
|
+
if (typeof value === "number") return Number.isFinite(value);
|
|
138
|
+
if (typeof value !== "object" || depth > 50 || ancestors.has(value)) return false;
|
|
139
|
+
ancestors.add(value);
|
|
140
|
+
const prototype = Object.getPrototypeOf(value);
|
|
141
|
+
const isJson = Array.isArray(value) ? value.every((item) => isJsonValueAtDepth(item, ancestors, depth + 1)) : (prototype === Object.prototype || prototype === null) && isRecord$6(value) && Object.entries(value).every(([key, item]) => !UNSAFE_JSON_KEYS.has(key) && isJsonValueAtDepth(item, ancestors, depth + 1));
|
|
142
|
+
ancestors.delete(value);
|
|
143
|
+
return isJson;
|
|
144
|
+
}
|
|
145
|
+
function isRecord$6(value) {
|
|
146
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
147
|
+
}
|
|
148
|
+
function getUnexpectedFieldReason(value, allowedFields, path) {
|
|
149
|
+
const unexpectedField = Object.keys(value).find((field) => !allowedFields.has(field));
|
|
150
|
+
return unexpectedField ? `${path} contains unsupported field ${unexpectedField}` : void 0;
|
|
151
|
+
}
|
|
152
|
+
//#endregion
|
|
9
153
|
//#region ../widget-tooling/src/errors.ts
|
|
10
154
|
var WidgetToolingError = class extends Error {
|
|
11
155
|
code;
|
|
@@ -121,29 +265,6 @@ function toPosixPath$1(value) {
|
|
|
121
265
|
return value.split(path.sep).join("/");
|
|
122
266
|
}
|
|
123
267
|
//#endregion
|
|
124
|
-
//#region ../../portal/core/src/remote-dom-widget-package.ts
|
|
125
|
-
const UNSAFE_JSON_KEYS = new Set([
|
|
126
|
-
"__proto__",
|
|
127
|
-
"constructor",
|
|
128
|
-
"prototype"
|
|
129
|
-
]);
|
|
130
|
-
function isJsonValue(value) {
|
|
131
|
-
return isJsonValueAtDepth(value, /* @__PURE__ */ new WeakSet(), 0);
|
|
132
|
-
}
|
|
133
|
-
function isJsonValueAtDepth(value, ancestors, depth) {
|
|
134
|
-
if (value === null || typeof value === "string" || typeof value === "boolean") return true;
|
|
135
|
-
if (typeof value === "number") return Number.isFinite(value);
|
|
136
|
-
if (typeof value !== "object" || depth > 50 || ancestors.has(value)) return false;
|
|
137
|
-
ancestors.add(value);
|
|
138
|
-
const prototype = Object.getPrototypeOf(value);
|
|
139
|
-
const isJson = Array.isArray(value) ? value.every((item) => isJsonValueAtDepth(item, ancestors, depth + 1)) : (prototype === Object.prototype || prototype === null) && isRecord$6(value) && Object.entries(value).every(([key, item]) => !UNSAFE_JSON_KEYS.has(key) && isJsonValueAtDepth(item, ancestors, depth + 1));
|
|
140
|
-
ancestors.delete(value);
|
|
141
|
-
return isJson;
|
|
142
|
-
}
|
|
143
|
-
function isRecord$6(value) {
|
|
144
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
145
|
-
}
|
|
146
|
-
//#endregion
|
|
147
268
|
//#region ../widget-tooling/src/internal/widget-package-validation.ts
|
|
148
269
|
const URL_SAFE_SEGMENT_SOURCE = "[A-Za-z0-9][A-Za-z0-9_~-]*";
|
|
149
270
|
const URL_SAFE_WIDGET_NAME_PATTERN = new RegExp(`^${URL_SAFE_SEGMENT_SOURCE}$`);
|
|
@@ -701,6 +822,7 @@ const WIDGET_CONFIG_MODULE_PATH = "/fluid.widget.config.ts";
|
|
|
701
822
|
*/
|
|
702
823
|
function buildRuntimeEntryBootstrapScript(entryPath, origin) {
|
|
703
824
|
const refreshRuntimeUrl = new URL("/@react-refresh", origin).toString();
|
|
825
|
+
const workerSdkUrl = new URL("/@id/@fluid-app/portal-sdk/widgets/worker", origin).toString();
|
|
704
826
|
const entryUrl = new URL(entryPath, origin).toString();
|
|
705
827
|
return [
|
|
706
828
|
"// Dev-only worker bootstrap — see buildRuntimeEntryBootstrapScript",
|
|
@@ -711,6 +833,8 @@ function buildRuntimeEntryBootstrapScript(entryPath, origin) {
|
|
|
711
833
|
"const __buf = (e) => { __q.push(e.data); };",
|
|
712
834
|
"self.addEventListener(\"message\", __buf);",
|
|
713
835
|
"if (typeof window === \"undefined\") { globalThis.window = globalThis; }",
|
|
836
|
+
`const { prepareRemoteDomWidgetWorker } = await import(${JSON.stringify(workerSdkUrl)});`,
|
|
837
|
+
"prepareRemoteDomWidgetWorker();",
|
|
714
838
|
"try {",
|
|
715
839
|
` const { default: RefreshRuntime } = await import(${JSON.stringify(refreshRuntimeUrl)});`,
|
|
716
840
|
" RefreshRuntime.injectIntoGlobalHook(window);",
|
|
@@ -1174,9 +1298,10 @@ async function buildSharedWidgetPackage(options) {
|
|
|
1174
1298
|
}
|
|
1175
1299
|
function createWidgetPackageEntrySource(options) {
|
|
1176
1300
|
return `import { createElement } from "react";
|
|
1177
|
-
import { startWidgetPackage } from "@fluid-app/portal-sdk/widgets/worker";
|
|
1301
|
+
import { prepareRemoteDomWidgetWorker, startWidgetPackage } from "@fluid-app/portal-sdk/widgets/worker";
|
|
1178
1302
|
${options.cssImportPath ? `import ${JSON.stringify(options.cssImportPath)};` : ""}
|
|
1179
1303
|
|
|
1304
|
+
prepareRemoteDomWidgetWorker();
|
|
1180
1305
|
const widgetConfig = await import(${JSON.stringify(options.configImportPath)});
|
|
1181
1306
|
const SOURCE_PACKAGE_MARKER = "__fluidSourceWidgetPackage";
|
|
1182
1307
|
const descriptors = ${JSON.stringify(options.validated.widgets, null, 2)};
|
|
@@ -2152,6 +2277,6 @@ function isRecord(value) {
|
|
|
2152
2277
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2153
2278
|
}
|
|
2154
2279
|
//#endregion
|
|
2155
|
-
export { resolvePublishVersion as a, fluidWidgetDevPlugin as c, readCompanyWidgetPackages as i, handleOptions as l, preflightCompanyPackage as n, loadAndValidateWidgetPackage as o, readCompanyWidgetPackage as r, publishWidgetPackage as s, formatPackageKeyMismatch as t, setCorsHeaders as u };
|
|
2280
|
+
export { resolvePublishVersion as a, fluidWidgetDevPlugin as c, isRemoteDomWidgetPackageDescriptor as d, readCompanyWidgetPackages as i, handleOptions as l, preflightCompanyPackage as n, loadAndValidateWidgetPackage as o, readCompanyWidgetPackage as r, publishWidgetPackage as s, formatPackageKeyMismatch as t, setCorsHeaders as u };
|
|
2156
2281
|
|
|
2157
|
-
//# sourceMappingURL=src-
|
|
2282
|
+
//# sourceMappingURL=src-2znVq55R.mjs.map
|