@fluid-app/portal-sdk 0.1.370 → 0.1.372
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/{CardWidget-CqdJHxX0.cjs → CardWidget-BWwI1G0Z.cjs} +2 -2
- package/dist/{CardWidget-CqdJHxX0.cjs.map → CardWidget-BWwI1G0Z.cjs.map} +1 -1
- package/dist/{CardWidget-DCrXorb0.cjs → CardWidget-aJYbzWG9.cjs} +2 -2
- package/dist/{CardWidget-DdV1HDy0.mjs → CardWidget-cIc9cOG9.mjs} +2 -2
- package/dist/{CardWidget-DdV1HDy0.mjs.map → CardWidget-cIc9cOG9.mjs.map} +1 -1
- package/dist/{ContainerWidget-CYIOGpgy.cjs → ContainerWidget-C2LMzXVj.cjs} +3 -3
- package/dist/{ContainerWidget-CZTRim0A.cjs → ContainerWidget-bMMdFhLg.cjs} +2 -2
- package/dist/{ContainerWidget-CZTRim0A.cjs.map → ContainerWidget-bMMdFhLg.cjs.map} +1 -1
- package/dist/{ContainerWidget-BKaiiPlW.mjs → ContainerWidget-mSWihekF.mjs} +2 -2
- package/dist/{ContainerWidget-BKaiiPlW.mjs.map → ContainerWidget-mSWihekF.mjs.map} +1 -1
- package/dist/{FluidProvider-DG7duKf4.cjs → FluidProvider-C6d1TUVm.cjs} +8 -10
- package/dist/{FluidProvider-DG7duKf4.cjs.map → FluidProvider-C6d1TUVm.cjs.map} +1 -1
- package/dist/{FluidProvider-Bmmdax4d.mjs → FluidProvider-C80gc4Yi.mjs} +8 -10
- package/dist/{FluidProvider-Bmmdax4d.mjs.map → FluidProvider-C80gc4Yi.mjs.map} +1 -1
- package/dist/{LayoutWidget-xw1zY6cc.cjs → LayoutWidget-BqUbneWw.cjs} +2 -2
- package/dist/{LayoutWidget-xw1zY6cc.cjs.map → LayoutWidget-BqUbneWw.cjs.map} +1 -1
- package/dist/{LayoutWidget-VU6uFW3-.cjs → LayoutWidget-C1BzDeQI.cjs} +2 -2
- package/dist/{LayoutWidget-C0TbnxQW.mjs → LayoutWidget-D3qYKt9F.mjs} +2 -2
- package/dist/{LayoutWidget-C0TbnxQW.mjs.map → LayoutWidget-D3qYKt9F.mjs.map} +1 -1
- package/dist/{MessagingScreen-BY8IowR0.mjs → MessagingScreen-D3si8TPx.mjs} +6 -6
- package/dist/{MessagingScreen-CyxUDdcb.mjs → MessagingScreen-DKzYThAY.mjs} +2 -2
- package/dist/{MessagingScreen-CyxUDdcb.mjs.map → MessagingScreen-DKzYThAY.mjs.map} +1 -1
- package/dist/{MessagingScreen-ylXd2Um7.cjs → MessagingScreen-DqxRu2x3.cjs} +2 -2
- package/dist/{MessagingScreen-ylXd2Um7.cjs.map → MessagingScreen-DqxRu2x3.cjs.map} +1 -1
- package/dist/{MessagingScreen-BIJU7dWT.cjs → MessagingScreen-PZyO11S1.cjs} +6 -6
- package/dist/{OrdersScreen-BVRpsxMF.mjs → OrdersScreen-BbDkjTd_.mjs} +6 -6
- package/dist/{OrdersScreen-B-biRUNQ.cjs → OrdersScreen-CUfyr7Y0.cjs} +29 -20
- package/dist/OrdersScreen-CUfyr7Y0.cjs.map +1 -0
- package/dist/{OrdersScreen-1b2ZzMEg.cjs → OrdersScreen-NSQ51uu5.cjs} +6 -6
- package/dist/{OrdersScreen-DsTMrxlo.mjs → OrdersScreen-ewbXb5cz.mjs} +29 -20
- package/dist/OrdersScreen-ewbXb5cz.mjs.map +1 -0
- package/dist/{ProfileScreen-DvnWtXlF.mjs → ProfileScreen-BCwdwO_p.mjs} +3 -3
- package/dist/{ProfileScreen-DvnWtXlF.mjs.map → ProfileScreen-BCwdwO_p.mjs.map} +1 -1
- package/dist/{ProfileScreen-DzgGP3lr.mjs → ProfileScreen-D7UA604p.mjs} +7 -7
- package/dist/{ProfileScreen-DYe6Msda.cjs → ProfileScreen-DlIXDIeu.cjs} +3 -3
- package/dist/{ProfileScreen-DYe6Msda.cjs.map → ProfileScreen-DlIXDIeu.cjs.map} +1 -1
- package/dist/{ProfileScreen-Dsbr8wip.cjs → ProfileScreen-MypXufrO.cjs} +7 -7
- package/dist/{ScreenRenderer-CKu-Jc1I.mjs → ScreenRenderer-CcT_j-WQ.mjs} +1 -4
- package/dist/{ScreenRenderer-CKu-Jc1I.mjs.map → ScreenRenderer-CcT_j-WQ.mjs.map} +1 -1
- package/dist/{ScreenRenderer-CZTdJd2G.cjs → ScreenRenderer-Ce8MJPnR.cjs} +1 -4
- package/dist/{ScreenRenderer-CZTdJd2G.cjs.map → ScreenRenderer-Ce8MJPnR.cjs.map} +1 -1
- package/dist/{ShopScreen-DcgyX3Wk.cjs → ShopScreen-29SZwMWF.cjs} +2 -2
- package/dist/{ShopScreen-DcgyX3Wk.cjs.map → ShopScreen-29SZwMWF.cjs.map} +1 -1
- package/dist/{ShopScreen-nUFdeac6.cjs → ShopScreen-BC9NDysQ.cjs} +6 -6
- package/dist/{ShopScreen-Cy5cf6tn.mjs → ShopScreen-BKVNW6ya.mjs} +6 -6
- package/dist/{ShopScreen-DVYzIHJA.mjs → ShopScreen-CgN-6gic.mjs} +2 -2
- package/dist/{ShopScreen-DVYzIHJA.mjs.map → ShopScreen-CgN-6gic.mjs.map} +1 -1
- package/dist/{SubscriptionsScreen-BnRWR4Df.mjs → SubscriptionsScreen-CPiLzWhm.mjs} +7 -7
- package/dist/{SubscriptionsScreen-Dw68LWDh.cjs → SubscriptionsScreen-Dz6Y_1oD.cjs} +3 -3
- package/dist/{SubscriptionsScreen-Dw68LWDh.cjs.map → SubscriptionsScreen-Dz6Y_1oD.cjs.map} +1 -1
- package/dist/{SubscriptionsScreen-DqG_qHS_.mjs → SubscriptionsScreen-M2WaVHH7.mjs} +3 -3
- package/dist/{SubscriptionsScreen-DqG_qHS_.mjs.map → SubscriptionsScreen-M2WaVHH7.mjs.map} +1 -1
- package/dist/{SubscriptionsScreen-Day2TSrY.cjs → SubscriptionsScreen-dN42J-MR.cjs} +7 -7
- package/dist/{authoring-BlXhd4Sj.d.cts → authoring--rXPyZca.d.cts} +2 -2
- package/dist/{authoring-BlXhd4Sj.d.cts.map → authoring--rXPyZca.d.cts.map} +1 -1
- package/dist/{authoring-BMuHXNFy.d.mts → authoring-V0sXg_j4.d.mts} +2 -2
- package/dist/{authoring-BMuHXNFy.d.mts.map → authoring-V0sXg_j4.d.mts.map} +1 -1
- package/dist/index.cjs +22 -24
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -8
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +3 -9
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +22 -24
- package/dist/index.mjs.map +1 -1
- package/dist/preview/preview-entry.cjs +6 -6
- package/dist/preview/preview-entry.d.cts +1 -1
- package/dist/preview/preview-entry.d.mts +1 -1
- package/dist/preview/preview-entry.mjs +6 -6
- package/dist/{use-portal-card-add-3ds-flow-hGLvDBZT.cjs → use-portal-card-add-3ds-flow-C0YUg213.cjs} +2 -2
- package/dist/{use-portal-card-add-3ds-flow-hGLvDBZT.cjs.map → use-portal-card-add-3ds-flow-C0YUg213.cjs.map} +1 -1
- package/dist/{use-portal-card-add-3ds-flow-FSWDlXtP.mjs → use-portal-card-add-3ds-flow-DKXraYw-.mjs} +2 -2
- package/dist/{use-portal-card-add-3ds-flow-FSWDlXtP.mjs.map → use-portal-card-add-3ds-flow-DKXraYw-.mjs.map} +1 -1
- package/dist/vite/builder-preview-entry.cjs +573 -0
- package/dist/vite/builder-preview-entry.cjs.map +1 -0
- package/dist/vite/builder-preview-entry.d.cts +11 -0
- package/dist/vite/builder-preview-entry.d.cts.map +1 -0
- package/dist/vite/builder-preview-entry.d.mts +11 -0
- package/dist/vite/builder-preview-entry.d.mts.map +1 -0
- package/dist/vite/builder-preview-entry.mjs +571 -0
- package/dist/vite/builder-preview-entry.mjs.map +1 -0
- package/dist/vite/index.cjs +16 -28
- package/dist/vite/index.cjs.map +1 -1
- package/dist/vite/index.d.cts.map +1 -1
- package/dist/vite/index.d.mts.map +1 -1
- package/dist/vite/index.mjs +16 -28
- package/dist/vite/index.mjs.map +1 -1
- package/dist/{widget-package-descriptor-BnVCE5Fz.d.cts → widget-package-descriptor-ByCz_FNh.d.cts} +177 -9
- package/dist/widget-package-descriptor-ByCz_FNh.d.cts.map +1 -0
- package/dist/{widget-package-descriptor-Dt8BkF85.d.mts → widget-package-descriptor-CPIPAdUO.d.mts} +177 -9
- package/dist/widget-package-descriptor-CPIPAdUO.d.mts.map +1 -0
- package/dist/widget-package-utils-BWn56ZFw.cjs +1553 -0
- package/dist/widget-package-utils-BWn56ZFw.cjs.map +1 -0
- package/dist/widget-package-utils-BdS0B0pI.mjs +1486 -0
- package/dist/widget-package-utils-BdS0B0pI.mjs.map +1 -0
- package/dist/widgets/authoring.d.cts +1 -1
- package/dist/widgets/authoring.d.mts +1 -1
- package/package.json +13 -17
- package/dist/OrdersScreen-B-biRUNQ.cjs.map +0 -1
- package/dist/OrdersScreen-DsTMrxlo.mjs.map +0 -1
- package/dist/widget-package-descriptor-BnVCE5Fz.d.cts.map +0 -1
- package/dist/widget-package-descriptor-Dt8BkF85.d.mts.map +0 -1
- package/dist/widget-package-utils-BGu5fWAU.cjs +0 -650
- package/dist/widget-package-utils-BGu5fWAU.cjs.map +0 -1
- package/dist/widget-package-utils-DzdFCK04.mjs +0 -582
- package/dist/widget-package-utils-DzdFCK04.mjs.map +0 -1
|
@@ -0,0 +1,1553 @@
|
|
|
1
|
+
const require_chunk = require("./chunk-9hOWP6kD.cjs");
|
|
2
|
+
const require_FluidProvider = require("./FluidProvider-C6d1TUVm.cjs");
|
|
3
|
+
let react = require("react");
|
|
4
|
+
react = require_chunk.__toESM(react);
|
|
5
|
+
let react_jsx_runtime = require("react/jsx-runtime");
|
|
6
|
+
react_jsx_runtime = require_chunk.__toESM(react_jsx_runtime);
|
|
7
|
+
let react_dom = require("react-dom");
|
|
8
|
+
react_dom = require_chunk.__toESM(react_dom);
|
|
9
|
+
//#region src/config/env.ts
|
|
10
|
+
/**
|
|
11
|
+
* Read Vite environment variables at runtime.
|
|
12
|
+
*
|
|
13
|
+
* Isolated into its own module so that Jest tests can mock it
|
|
14
|
+
* (import.meta is a syntax-level construct that CJS/Jest cannot parse).
|
|
15
|
+
*/
|
|
16
|
+
function getViteEnv(key) {
|
|
17
|
+
return {}.env?.[key];
|
|
18
|
+
}
|
|
19
|
+
//#endregion
|
|
20
|
+
//#region src/config/defaults.ts
|
|
21
|
+
/**
|
|
22
|
+
* Creates a FluidSDKConfig with sensible defaults.
|
|
23
|
+
*
|
|
24
|
+
* Default behavior:
|
|
25
|
+
* - baseUrl: reads from `VITE_API_URL` env var, falls back to `""` (same-origin relative)
|
|
26
|
+
* - Auth: relies on session cookies sent via `credentials: 'include'`
|
|
27
|
+
*
|
|
28
|
+
* Pass overrides to customize any field:
|
|
29
|
+
* ```ts
|
|
30
|
+
* const config = createDefaultFluidConfig({ baseUrl: "https://my-api.example.com" });
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
function createDefaultFluidConfig(overrides) {
|
|
34
|
+
return {
|
|
35
|
+
baseUrl: getViteEnv("VITE_API_URL") ?? "",
|
|
36
|
+
smartyEmbeddedKey: getViteEnv("NEXT_PUBLIC_SMARTY_EMBEDDED_KEY"),
|
|
37
|
+
googleMapsApiKey: getViteEnv("NEXT_PUBLIC_GOOGLE_MAPS_API_KEY"),
|
|
38
|
+
...overrides
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
//#endregion
|
|
42
|
+
//#region ../../platform/widget-runtime/src/errors.ts
|
|
43
|
+
var WidgetRuntimeError = class extends Error {
|
|
44
|
+
code;
|
|
45
|
+
packageId;
|
|
46
|
+
version;
|
|
47
|
+
cause;
|
|
48
|
+
constructor(details) {
|
|
49
|
+
super(details.message);
|
|
50
|
+
this.name = "WidgetRuntimeError";
|
|
51
|
+
this.code = details.code;
|
|
52
|
+
this.packageId = details.packageId;
|
|
53
|
+
this.version = details.version;
|
|
54
|
+
this.cause = details.cause;
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
function toWidgetRuntimeError(error, fallback) {
|
|
58
|
+
if (error instanceof WidgetRuntimeError) return error;
|
|
59
|
+
return new WidgetRuntimeError({
|
|
60
|
+
...fallback,
|
|
61
|
+
cause: error
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
//#endregion
|
|
65
|
+
//#region ../../platform/widget-runtime/src/fluid-widgets.ts
|
|
66
|
+
const globalMarker$1 = Symbol.for("fluid.widget-runtime.FluidWidgetsGlobal");
|
|
67
|
+
const cleanupRegistrationMarker = Symbol.for("fluid.widget-runtime.FluidWidgetsGlobal.cleanupRegistration");
|
|
68
|
+
function ensureFluidWidgetsGlobal() {
|
|
69
|
+
const existing = window.FluidWidgets;
|
|
70
|
+
if (isFluidWidgetsGlobal(existing)) return existing;
|
|
71
|
+
const registrationsByPackageKey = /* @__PURE__ */ new Map();
|
|
72
|
+
const subscribers = /* @__PURE__ */ new Set();
|
|
73
|
+
const fluidWidgets = {
|
|
74
|
+
[globalMarker$1]: true,
|
|
75
|
+
[cleanupRegistrationMarker](registration, previousRegistration) {
|
|
76
|
+
const registrationKey = createPackageRegistrationKey(registration.packageId, registration.version);
|
|
77
|
+
if (registrationsByPackageKey.get(registrationKey) !== registration) return;
|
|
78
|
+
if (previousRegistration === void 0) {
|
|
79
|
+
registrationsByPackageKey.delete(registrationKey);
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
registrationsByPackageKey.set(registrationKey, previousRegistration);
|
|
83
|
+
},
|
|
84
|
+
registerPackage(registration) {
|
|
85
|
+
const registrationKey = createPackageRegistrationKey(registration.packageId, registration.version);
|
|
86
|
+
const previousRegistration = registrationsByPackageKey.get(registrationKey);
|
|
87
|
+
registrationsByPackageKey.set(registrationKey, registration);
|
|
88
|
+
notify({
|
|
89
|
+
kind: "register",
|
|
90
|
+
registration,
|
|
91
|
+
previousRegistration
|
|
92
|
+
});
|
|
93
|
+
},
|
|
94
|
+
getPackageRegistration(packageId, version) {
|
|
95
|
+
return registrationsByPackageKey.get(createPackageRegistrationKey(packageId, version));
|
|
96
|
+
},
|
|
97
|
+
getRegisteredWidgets() {
|
|
98
|
+
return Array.from(registrationsByPackageKey.values()).flatMap((registration) => registration.widgets.map((widget) => ({
|
|
99
|
+
...widget,
|
|
100
|
+
packageId: registration.packageId,
|
|
101
|
+
version: registration.version
|
|
102
|
+
})));
|
|
103
|
+
},
|
|
104
|
+
getRegistry() {
|
|
105
|
+
const registry = /* @__PURE__ */ new Map();
|
|
106
|
+
for (const registration of registrationsByPackageKey.values()) for (const widget of registration.widgets) {
|
|
107
|
+
const globalWidget = {
|
|
108
|
+
...widget,
|
|
109
|
+
packageId: registration.packageId,
|
|
110
|
+
version: registration.version
|
|
111
|
+
};
|
|
112
|
+
registry.set(createGlobalWidgetRegistryKey(registration.packageId, registration.version, widget.type), globalWidget);
|
|
113
|
+
}
|
|
114
|
+
return registry;
|
|
115
|
+
},
|
|
116
|
+
clear(packageId, version) {
|
|
117
|
+
if (packageId === void 0) {
|
|
118
|
+
registrationsByPackageKey.clear();
|
|
119
|
+
notify({ kind: "clear" });
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
let cleared = false;
|
|
123
|
+
for (const [key, registration] of registrationsByPackageKey) if (registration.packageId === packageId && (version === void 0 || registration.version === version)) {
|
|
124
|
+
registrationsByPackageKey.delete(key);
|
|
125
|
+
cleared = true;
|
|
126
|
+
}
|
|
127
|
+
if (cleared) notify({
|
|
128
|
+
kind: "clear",
|
|
129
|
+
packageId,
|
|
130
|
+
version
|
|
131
|
+
});
|
|
132
|
+
},
|
|
133
|
+
subscribe(listener) {
|
|
134
|
+
subscribers.add(listener);
|
|
135
|
+
return () => {
|
|
136
|
+
subscribers.delete(listener);
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
window.FluidWidgets = fluidWidgets;
|
|
141
|
+
return fluidWidgets;
|
|
142
|
+
function notify(event) {
|
|
143
|
+
for (const subscriber of Array.from(subscribers)) subscriber(event);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
function cleanupUnexpectedFluidWidgetsRegistration(registration, previousRegistration) {
|
|
147
|
+
const fluidWidgets = window.FluidWidgets;
|
|
148
|
+
if (!isFluidWidgetsGlobal(fluidWidgets)) return;
|
|
149
|
+
fluidWidgets[cleanupRegistrationMarker](registration, previousRegistration);
|
|
150
|
+
}
|
|
151
|
+
function isFluidWidgetsGlobal(value) {
|
|
152
|
+
return value !== void 0 && value[globalMarker$1] === true;
|
|
153
|
+
}
|
|
154
|
+
function createPackageRegistrationKey(packageId, version) {
|
|
155
|
+
return JSON.stringify([packageId, version]);
|
|
156
|
+
}
|
|
157
|
+
function createGlobalWidgetRegistryKey(packageId, version, type) {
|
|
158
|
+
return JSON.stringify([
|
|
159
|
+
packageId,
|
|
160
|
+
version,
|
|
161
|
+
type
|
|
162
|
+
]);
|
|
163
|
+
}
|
|
164
|
+
const DEFAULT_WIDGET_CONTAINER = "block";
|
|
165
|
+
const widgetPackageTypes$1 = new Set([
|
|
166
|
+
"fluid",
|
|
167
|
+
"company",
|
|
168
|
+
"droplet",
|
|
169
|
+
"partner",
|
|
170
|
+
"internal"
|
|
171
|
+
]);
|
|
172
|
+
const widgetContainers$1 = new Set([
|
|
173
|
+
"inline",
|
|
174
|
+
"block",
|
|
175
|
+
"card",
|
|
176
|
+
"fullscreen"
|
|
177
|
+
]);
|
|
178
|
+
const widgetResizableValues$1 = new Set([
|
|
179
|
+
"horizontal",
|
|
180
|
+
"vertical",
|
|
181
|
+
"both"
|
|
182
|
+
]);
|
|
183
|
+
function readNonEmptyString(value) {
|
|
184
|
+
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
185
|
+
}
|
|
186
|
+
function hasControlCharacter(value) {
|
|
187
|
+
for (let index = 0; index < value.length; index++) {
|
|
188
|
+
const code = value.charCodeAt(index);
|
|
189
|
+
if (code <= 31 || code >= 127 && code <= 159) return true;
|
|
190
|
+
}
|
|
191
|
+
return false;
|
|
192
|
+
}
|
|
193
|
+
function isWidgetPackageType(value) {
|
|
194
|
+
return typeof value === "string" && widgetPackageTypes$1.has(value);
|
|
195
|
+
}
|
|
196
|
+
function normalizeWidgetPackageType(value) {
|
|
197
|
+
return isWidgetPackageType(value) ? value : null;
|
|
198
|
+
}
|
|
199
|
+
function isWidgetRuntimeContainer(value) {
|
|
200
|
+
return typeof value === "string" && widgetContainers$1.has(value);
|
|
201
|
+
}
|
|
202
|
+
function normalizeWidgetRuntimeContainer(value) {
|
|
203
|
+
return isWidgetRuntimeContainer(value) ? value : DEFAULT_WIDGET_CONTAINER;
|
|
204
|
+
}
|
|
205
|
+
function isWidgetRuntimeResizableString(value) {
|
|
206
|
+
return typeof value === "string" && widgetResizableValues$1.has(value);
|
|
207
|
+
}
|
|
208
|
+
function normalizeWidgetRuntimeResizable(value) {
|
|
209
|
+
if (typeof value === "boolean") return value;
|
|
210
|
+
if (isWidgetRuntimeResizableString(value)) return value;
|
|
211
|
+
if (!isRecord$1(value)) return false;
|
|
212
|
+
const horizontal = value.horizontal === true;
|
|
213
|
+
const vertical = value.vertical === true;
|
|
214
|
+
if (horizontal && vertical) return "both";
|
|
215
|
+
if (horizontal) return "horizontal";
|
|
216
|
+
if (vertical) return "vertical";
|
|
217
|
+
return false;
|
|
218
|
+
}
|
|
219
|
+
function isRecord$1(value) {
|
|
220
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
221
|
+
}
|
|
222
|
+
//#endregion
|
|
223
|
+
//#region ../../platform/widget-runtime/src/validation.ts
|
|
224
|
+
const widgetPackageTypes = new Set([
|
|
225
|
+
"fluid",
|
|
226
|
+
"company",
|
|
227
|
+
"droplet",
|
|
228
|
+
"partner",
|
|
229
|
+
"internal"
|
|
230
|
+
]);
|
|
231
|
+
const widgetContainers = new Set([
|
|
232
|
+
"inline",
|
|
233
|
+
"block",
|
|
234
|
+
"card",
|
|
235
|
+
"fullscreen"
|
|
236
|
+
]);
|
|
237
|
+
const widgetResizableValues = new Set([
|
|
238
|
+
"horizontal",
|
|
239
|
+
"vertical",
|
|
240
|
+
"both"
|
|
241
|
+
]);
|
|
242
|
+
function validateWidgetPackageDescriptor(descriptor) {
|
|
243
|
+
if (!isObjectRecord(descriptor)) throwInvalidDescriptor("Widget package descriptor must be an object");
|
|
244
|
+
if (descriptor.manifestVersion !== 1) throwInvalidDescriptor(`Unsupported widget package manifestVersion: ${String(descriptor.manifestVersion)}`, descriptor);
|
|
245
|
+
assertNonEmptyString(descriptor.packageId, "packageId", descriptor);
|
|
246
|
+
assertNonEmptyString(descriptor.version, "version", descriptor);
|
|
247
|
+
assertNonEmptyString(descriptor.remoteEntryUrl, "remoteEntryUrl", descriptor);
|
|
248
|
+
assertValidUrl(descriptor.remoteEntryUrl, "remoteEntryUrl", descriptor);
|
|
249
|
+
if (!widgetPackageTypes.has(descriptor.packageType)) throwInvalidDescriptor(`Unsupported widget packageType: ${String(descriptor.packageType)}`, descriptor);
|
|
250
|
+
if (!Array.isArray(descriptor.cssUrls)) throwInvalidDescriptor("Widget package cssUrls must be an array", descriptor);
|
|
251
|
+
for (const cssUrl of descriptor.cssUrls) {
|
|
252
|
+
if (typeof cssUrl !== "string" || cssUrl.length === 0) throwInvalidDescriptor("Widget package cssUrls must contain only non-empty strings", descriptor);
|
|
253
|
+
assertValidUrl(cssUrl, "cssUrls[]", descriptor);
|
|
254
|
+
}
|
|
255
|
+
if (!Array.isArray(descriptor.widgets) || descriptor.widgets.length === 0) throwInvalidDescriptor("Widget package widgets must be a non-empty array", descriptor);
|
|
256
|
+
const seenTypes = /* @__PURE__ */ new Set();
|
|
257
|
+
for (const widget of descriptor.widgets) {
|
|
258
|
+
validateWidgetDescriptor(widget, descriptor);
|
|
259
|
+
if (seenTypes.has(widget.type)) throwInvalidDescriptor(`Widget package descriptor contains duplicate widget type: ${widget.type}`, descriptor);
|
|
260
|
+
seenTypes.add(widget.type);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
function validateWidgetPackageRegistration(registration, descriptor) {
|
|
264
|
+
if (!registration) throw new WidgetRuntimeError({
|
|
265
|
+
code: "REGISTRATION_MISSING",
|
|
266
|
+
message: `Remote widget package ${descriptor.packageId}@${descriptor.version} did not call window.FluidWidgets.registerPackage`,
|
|
267
|
+
packageId: descriptor.packageId,
|
|
268
|
+
version: descriptor.version
|
|
269
|
+
});
|
|
270
|
+
if (!isObjectRecord(registration)) throwInvalidRegistration("Widget package registration must be an object", descriptor);
|
|
271
|
+
if (registration.packageId !== descriptor.packageId) throw new WidgetRuntimeError({
|
|
272
|
+
code: "REGISTRATION_MISMATCH",
|
|
273
|
+
message: `Remote widget package registered packageId ${String(registration.packageId)} but descriptor expected ${descriptor.packageId}`,
|
|
274
|
+
packageId: descriptor.packageId,
|
|
275
|
+
version: descriptor.version
|
|
276
|
+
});
|
|
277
|
+
if (registration.version !== descriptor.version) throw new WidgetRuntimeError({
|
|
278
|
+
code: "REGISTRATION_MISMATCH",
|
|
279
|
+
message: `Remote widget package ${descriptor.packageId} registered version ${String(registration.version)} but descriptor expected ${descriptor.version}`,
|
|
280
|
+
packageId: descriptor.packageId,
|
|
281
|
+
version: descriptor.version
|
|
282
|
+
});
|
|
283
|
+
if (!Array.isArray(registration.widgets)) throwInvalidRegistration("Widget package registration widgets must be an array", descriptor);
|
|
284
|
+
const descriptorWidgetsByType = new Map(descriptor.widgets.map((widget) => [widget.type, widget]));
|
|
285
|
+
const registeredTypes = /* @__PURE__ */ new Set();
|
|
286
|
+
for (const widget of registration.widgets) {
|
|
287
|
+
validateRuntimeWidgetRegistration(widget, descriptor, descriptorWidgetsByType);
|
|
288
|
+
if (registeredTypes.has(widget.type)) throwInvalidRegistration(`Widget package registration contains duplicate widget type: ${widget.type}`, descriptor);
|
|
289
|
+
registeredTypes.add(widget.type);
|
|
290
|
+
}
|
|
291
|
+
for (const descriptorWidget of descriptor.widgets) if (!registeredTypes.has(descriptorWidget.type)) throwInvalidRegistration(`Widget package registration is missing widget type: ${descriptorWidget.type}`, descriptor);
|
|
292
|
+
}
|
|
293
|
+
function validateWidgetDescriptor(widget, descriptor) {
|
|
294
|
+
if (!isObjectRecord(widget)) throwInvalidDescriptor("Widget descriptor must be an object", descriptor);
|
|
295
|
+
assertNonEmptyString(widget.type, "widgets[].type", descriptor);
|
|
296
|
+
assertNonEmptyString(widget.name, "widgets[].name", descriptor);
|
|
297
|
+
assertNonEmptyString(widget.displayName, "widgets[].displayName", descriptor);
|
|
298
|
+
assertNonEmptyString(widget.description, "widgets[].description", descriptor);
|
|
299
|
+
assertNonEmptyString(widget.icon, "widgets[].icon", descriptor);
|
|
300
|
+
assertNonEmptyString(widget.category, "widgets[].category", descriptor);
|
|
301
|
+
assertNonEmptyString(widget.minSdkVersion, "widgets[].minSdkVersion", descriptor);
|
|
302
|
+
if (!isObjectRecord(widget.propertySchema)) throwInvalidDescriptor("Widget propertySchema must be an object", descriptor);
|
|
303
|
+
validatePropertySchemaWidgetType(widget.propertySchema, widget.type, descriptor, "INVALID_DESCRIPTOR");
|
|
304
|
+
if (!isObjectRecord(widget.defaultProps)) throwInvalidDescriptor("Widget defaultProps must be an object", descriptor);
|
|
305
|
+
if (!widgetContainers.has(widget.container)) throwInvalidDescriptor(`Unsupported widget container: ${String(widget.container)}`, descriptor);
|
|
306
|
+
validateResizable(widget.resizable, descriptor);
|
|
307
|
+
}
|
|
308
|
+
function validateRuntimeWidgetRegistration(widget, descriptor, descriptorWidgetsByType) {
|
|
309
|
+
if (!isObjectRecord(widget)) throwInvalidRegistration("Registered widget must be an object", descriptor);
|
|
310
|
+
assertNonEmptyString(widget.type, "registered widgets[].type", descriptor);
|
|
311
|
+
const descriptorWidget = descriptorWidgetsByType.get(widget.type);
|
|
312
|
+
if (!descriptorWidget) throwInvalidRegistration(`Widget package registration contains unknown widget type: ${widget.type}`, descriptor);
|
|
313
|
+
if (!isWidgetComponent(widget.component)) throwInvalidRegistration(`Registered widget ${widget.type} must include a React component`, descriptor);
|
|
314
|
+
if (!isObjectRecord(widget.propertySchema)) throwInvalidRegistration(`Registered widget ${widget.type} propertySchema must be an object`, descriptor);
|
|
315
|
+
validatePropertySchemaWidgetType(widget.propertySchema, widget.type, descriptor, "INVALID_REGISTRATION");
|
|
316
|
+
if (!isObjectRecord(widget.defaultProps)) throwInvalidRegistration(`Registered widget ${widget.type} defaultProps must be an object`, descriptor);
|
|
317
|
+
validateOptionalRuntimeMetadataStrings(widget, descriptor);
|
|
318
|
+
if (widget.container !== void 0 && !widgetContainers.has(widget.container)) throwInvalidRegistration(`Registered widget ${widget.type} has unsupported container: ${String(widget.container)}`, descriptor);
|
|
319
|
+
if (widget.resizable !== void 0) validateResizable(widget.resizable, descriptor, "INVALID_REGISTRATION");
|
|
320
|
+
validatePropertySchemaWidgetType(descriptorWidget.propertySchema, widget.type, descriptor, "INVALID_DESCRIPTOR");
|
|
321
|
+
}
|
|
322
|
+
function validateOptionalRuntimeMetadataStrings(widget, descriptor) {
|
|
323
|
+
for (const field of [
|
|
324
|
+
"name",
|
|
325
|
+
"displayName",
|
|
326
|
+
"description",
|
|
327
|
+
"icon",
|
|
328
|
+
"category",
|
|
329
|
+
"minSdkVersion"
|
|
330
|
+
]) {
|
|
331
|
+
const value = widget[field];
|
|
332
|
+
if (value === void 0) continue;
|
|
333
|
+
if (typeof value !== "string" || value.length === 0) throwInvalidRegistration(`Registered widget ${widget.type} ${field} must be a non-empty string when present`, descriptor);
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
function validatePropertySchemaWidgetType(propertySchema, widgetType, descriptor, code) {
|
|
337
|
+
if (propertySchema.widgetType !== void 0 && propertySchema.widgetType !== widgetType) throwValidationError(code, `Widget type ${widgetType} must match propertySchema.widgetType ${propertySchema.widgetType}`, descriptor);
|
|
338
|
+
}
|
|
339
|
+
function validateResizable(resizable, descriptor, code = "INVALID_DESCRIPTOR") {
|
|
340
|
+
if (!(typeof resizable === "boolean" || typeof resizable === "string" && widgetResizableValues.has(resizable))) throwValidationError(code, `Unsupported widget resizable value: ${String(resizable)}`, descriptor);
|
|
341
|
+
}
|
|
342
|
+
function throwValidationError(code, message, descriptor) {
|
|
343
|
+
if (code === "INVALID_REGISTRATION") throwInvalidRegistration(message, descriptor);
|
|
344
|
+
throwInvalidDescriptor(message, descriptor);
|
|
345
|
+
}
|
|
346
|
+
function assertNonEmptyString(value, field, descriptor) {
|
|
347
|
+
if (typeof value !== "string" || value.length === 0) throwInvalidDescriptor(`Widget package ${field} must be a non-empty string`, descriptor);
|
|
348
|
+
}
|
|
349
|
+
function assertValidUrl(url, field, descriptor) {
|
|
350
|
+
if (url.trim() !== url || containsUnsafeUrlCharacter(url) || hasAmbiguousHttpScheme$1(url)) throwInvalidDescriptor(`Widget package ${field} contains invalid URL: ${url}`, descriptor);
|
|
351
|
+
if (/^[a-zA-Z][a-zA-Z\d+.-]*:/.exec(url)) {
|
|
352
|
+
let parsedUrl;
|
|
353
|
+
try {
|
|
354
|
+
parsedUrl = new URL(url);
|
|
355
|
+
} catch {
|
|
356
|
+
throwInvalidDescriptor(`Widget package ${field} contains invalid URL: ${url}`, descriptor);
|
|
357
|
+
}
|
|
358
|
+
if (parsedUrl.protocol !== "https:" && !isTrustedLocalHttpUrl(parsedUrl, url)) throwInvalidDescriptor(`Widget package ${field} must be an https absolute URL, a trusted local http URL, or a relative URL: ${url}`, descriptor);
|
|
359
|
+
return;
|
|
360
|
+
}
|
|
361
|
+
if (url.slice(0, 2) === "//") throwInvalidDescriptor(`Widget package ${field} must be an https absolute URL, a trusted local http URL, or a relative URL: ${url}`, descriptor);
|
|
362
|
+
try {
|
|
363
|
+
new URL(url, getValidationBaseUrl());
|
|
364
|
+
} catch {
|
|
365
|
+
throwInvalidDescriptor(`Widget package ${field} contains invalid URL: ${url}`, descriptor);
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
function isTrustedLocalHttpUrl(url, rawUrl) {
|
|
369
|
+
if (url.protocol !== "http:") return false;
|
|
370
|
+
const hostname = extractRawHostname(rawUrl).toLowerCase();
|
|
371
|
+
return hostname === "localhost" || hostname === "[::1]" || hostname === "::1" || isLoopbackIpv4Hostname(hostname);
|
|
372
|
+
}
|
|
373
|
+
function extractRawHostname(rawUrl) {
|
|
374
|
+
const authorityStart = rawUrl.indexOf("://") + 3;
|
|
375
|
+
const authorityEnd = findAuthorityEnd(rawUrl, authorityStart);
|
|
376
|
+
const authority = rawUrl.slice(authorityStart, authorityEnd);
|
|
377
|
+
const hostAndPort = authority.slice(authority.lastIndexOf("@") + 1);
|
|
378
|
+
if (hostAndPort.charAt(0) === "[") {
|
|
379
|
+
const bracketEnd = hostAndPort.indexOf("]");
|
|
380
|
+
return bracketEnd === -1 ? hostAndPort : hostAndPort.slice(0, bracketEnd + 1);
|
|
381
|
+
}
|
|
382
|
+
const portStart = hostAndPort.indexOf(":");
|
|
383
|
+
return portStart === -1 ? hostAndPort : hostAndPort.slice(0, portStart);
|
|
384
|
+
}
|
|
385
|
+
function findAuthorityEnd(rawUrl, authorityStart) {
|
|
386
|
+
let authorityEnd = rawUrl.length;
|
|
387
|
+
for (const delimiter of [
|
|
388
|
+
"/",
|
|
389
|
+
"?",
|
|
390
|
+
"#"
|
|
391
|
+
]) {
|
|
392
|
+
const delimiterIndex = rawUrl.indexOf(delimiter, authorityStart);
|
|
393
|
+
if (delimiterIndex !== -1 && delimiterIndex < authorityEnd) authorityEnd = delimiterIndex;
|
|
394
|
+
}
|
|
395
|
+
return authorityEnd;
|
|
396
|
+
}
|
|
397
|
+
function isLoopbackIpv4Hostname(hostname) {
|
|
398
|
+
const octets = hostname.split(".");
|
|
399
|
+
if (octets.length !== 4 || octets[0] !== "127") return false;
|
|
400
|
+
return octets.every(isBoundedIpv4Octet);
|
|
401
|
+
}
|
|
402
|
+
function isBoundedIpv4Octet(octet) {
|
|
403
|
+
if (!/^\d{1,3}$/.test(octet)) return false;
|
|
404
|
+
if (octet.length > 1 && octet.charAt(0) === "0") return false;
|
|
405
|
+
const value = Number(octet);
|
|
406
|
+
return value >= 0 && value <= 255;
|
|
407
|
+
}
|
|
408
|
+
function containsUnsafeUrlCharacter(url) {
|
|
409
|
+
return hasControlCharacter(url) || url.includes("\\");
|
|
410
|
+
}
|
|
411
|
+
function hasAmbiguousHttpScheme$1(url) {
|
|
412
|
+
return /^https?:(?!\/\/)/i.test(url);
|
|
413
|
+
}
|
|
414
|
+
function getValidationBaseUrl() {
|
|
415
|
+
if (typeof window === "undefined") return "http://localhost";
|
|
416
|
+
return window.location.href;
|
|
417
|
+
}
|
|
418
|
+
function throwInvalidDescriptor(message, descriptor) {
|
|
419
|
+
throw new WidgetRuntimeError({
|
|
420
|
+
code: "INVALID_DESCRIPTOR",
|
|
421
|
+
message,
|
|
422
|
+
packageId: descriptor?.packageId,
|
|
423
|
+
version: descriptor?.version
|
|
424
|
+
});
|
|
425
|
+
}
|
|
426
|
+
function throwInvalidRegistration(message, descriptor) {
|
|
427
|
+
throw new WidgetRuntimeError({
|
|
428
|
+
code: "INVALID_REGISTRATION",
|
|
429
|
+
message,
|
|
430
|
+
packageId: descriptor.packageId,
|
|
431
|
+
version: descriptor.version
|
|
432
|
+
});
|
|
433
|
+
}
|
|
434
|
+
function isObjectRecord(value) {
|
|
435
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
436
|
+
}
|
|
437
|
+
function isWidgetComponent(value) {
|
|
438
|
+
if (typeof value === "function") return true;
|
|
439
|
+
return isObjectRecord(value) && typeof value["$$typeof"] === "symbol";
|
|
440
|
+
}
|
|
441
|
+
//#endregion
|
|
442
|
+
//#region ../../platform/widget-runtime/src/loader.ts
|
|
443
|
+
const defaultTimeoutMs = 15e3;
|
|
444
|
+
/**
|
|
445
|
+
* Shared remote script queue for the page.
|
|
446
|
+
*
|
|
447
|
+
* Classic remote scripts register through the shared `window.FluidWidgets`
|
|
448
|
+
* callback, so the loader intentionally appends only one remote entry script at
|
|
449
|
+
* a time across all loader instances. Each queued load waits for the previous
|
|
450
|
+
* load to settle, even when the previous load fails, which keeps registration
|
|
451
|
+
* attribution deterministic and prevents overlapping classic-script remotes
|
|
452
|
+
* from racing their global registrations.
|
|
453
|
+
*/
|
|
454
|
+
let remoteScriptLoadQueue;
|
|
455
|
+
const pendingRemoteRegistrationsByPackageKey = /* @__PURE__ */ new Map();
|
|
456
|
+
function createWidgetRuntimeLoader(options = {}) {
|
|
457
|
+
const timeoutMs = options.timeoutMs ?? defaultTimeoutMs;
|
|
458
|
+
const fluidWidgets = ensureFluidWidgetsGlobal();
|
|
459
|
+
const packagesByKey = /* @__PURE__ */ new Map();
|
|
460
|
+
const pendingPackagesByKey = /* @__PURE__ */ new Map();
|
|
461
|
+
const packageGenerationsByKey = /* @__PURE__ */ new Map();
|
|
462
|
+
const cssByKey = /* @__PURE__ */ new Map();
|
|
463
|
+
const widgetsByKey = /* @__PURE__ */ new Map();
|
|
464
|
+
let isApplyingLocalGlobalClear = false;
|
|
465
|
+
fluidWidgets.subscribe((event) => {
|
|
466
|
+
if (isApplyingLocalGlobalClear || event.kind !== "clear") return;
|
|
467
|
+
if (event.packageId === void 0) {
|
|
468
|
+
invalidateCacheKeys(new Set([...packagesByKey.keys(), ...pendingPackagesByKey.keys()]));
|
|
469
|
+
return;
|
|
470
|
+
}
|
|
471
|
+
invalidateCacheKeys(collectMatchingCacheKeys(event.packageId, event.version));
|
|
472
|
+
});
|
|
473
|
+
async function loadPackage(descriptor) {
|
|
474
|
+
try {
|
|
475
|
+
validateWidgetPackageDescriptor(descriptor);
|
|
476
|
+
const cacheKey = createPackageCacheKey(descriptor.packageId, descriptor.version);
|
|
477
|
+
const cachedPackage = packagesByKey.get(cacheKey);
|
|
478
|
+
if (cachedPackage) return createSuccess(cachedPackage);
|
|
479
|
+
const pendingPackage = pendingPackagesByKey.get(cacheKey);
|
|
480
|
+
if (pendingPackage) return await pendingPackage.promise;
|
|
481
|
+
const globalRegistration = fluidWidgets.getPackageRegistration(descriptor.packageId, descriptor.version);
|
|
482
|
+
if (globalRegistration) return createSuccess(cachePreRegisteredPackage(descriptor, cacheKey, createCssLoadRef(cacheKey, getPackageGeneration(cacheKey)), globalRegistration));
|
|
483
|
+
const generation = getPackageGeneration(cacheKey);
|
|
484
|
+
const pendingLoad = {
|
|
485
|
+
cacheKey,
|
|
486
|
+
cssLoadRef: createCssLoadRef(cacheKey, generation),
|
|
487
|
+
generation,
|
|
488
|
+
packageId: descriptor.packageId,
|
|
489
|
+
remoteEntryUrlKey: normalizeAssetUrl(descriptor.remoteEntryUrl, descriptor),
|
|
490
|
+
version: descriptor.version
|
|
491
|
+
};
|
|
492
|
+
addPendingRemoteRegistration(pendingLoad);
|
|
493
|
+
const promise = loadPackageUncached(descriptor, pendingLoad);
|
|
494
|
+
const pendingPackageEntry = {
|
|
495
|
+
load: pendingLoad,
|
|
496
|
+
promise
|
|
497
|
+
};
|
|
498
|
+
promise.then(() => {
|
|
499
|
+
removePendingRemoteRegistration(pendingLoad);
|
|
500
|
+
if (pendingPackagesByKey.get(cacheKey) === pendingPackageEntry) pendingPackagesByKey.delete(cacheKey);
|
|
501
|
+
}, () => {
|
|
502
|
+
removePendingRemoteRegistration(pendingLoad);
|
|
503
|
+
if (pendingPackagesByKey.get(cacheKey) === pendingPackageEntry) pendingPackagesByKey.delete(cacheKey);
|
|
504
|
+
});
|
|
505
|
+
pendingPackagesByKey.set(cacheKey, pendingPackageEntry);
|
|
506
|
+
return await pendingPackageEntry.promise;
|
|
507
|
+
} catch (error) {
|
|
508
|
+
const descriptorIdentity = getDescriptorIdentity(descriptor);
|
|
509
|
+
const runtimeError = toWidgetRuntimeError(error, {
|
|
510
|
+
code: "SCRIPT_LOAD_FAILED",
|
|
511
|
+
message: "Failed to load widget package",
|
|
512
|
+
packageId: descriptorIdentity.packageId,
|
|
513
|
+
version: descriptorIdentity.version
|
|
514
|
+
});
|
|
515
|
+
if (options.throwOnError === true) throw runtimeError;
|
|
516
|
+
return {
|
|
517
|
+
ok: false,
|
|
518
|
+
packageId: descriptorIdentity.packageId ?? "",
|
|
519
|
+
version: descriptorIdentity.version ?? "",
|
|
520
|
+
error: runtimeError
|
|
521
|
+
};
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
async function loadPackageUncached(descriptor, pendingLoad) {
|
|
525
|
+
let scriptElement;
|
|
526
|
+
try {
|
|
527
|
+
installCssUrls(descriptor, pendingLoad.cssLoadRef);
|
|
528
|
+
const scriptLoadResult = await loadRemoteEntryScript(descriptor, timeoutMs, options.cacheBust, () => {
|
|
529
|
+
throwIfStalePackageLoad(pendingLoad);
|
|
530
|
+
}, () => isFreshPackageLoad(pendingLoad), pendingLoad.remoteEntryUrlKey);
|
|
531
|
+
scriptElement = scriptLoadResult.scriptElement;
|
|
532
|
+
throwIfStalePackageLoad(pendingLoad);
|
|
533
|
+
const registration = fluidWidgets.getPackageRegistration(descriptor.packageId, descriptor.version) ?? scriptLoadResult.registration;
|
|
534
|
+
const cached = cachePackageRegistrationWithRemoteCleanup(descriptor, pendingLoad.cacheKey, pendingLoad.cssLoadRef, registration, scriptLoadResult, scriptElement);
|
|
535
|
+
throwIfStalePackageLoad(pendingLoad);
|
|
536
|
+
return createSuccess(cached);
|
|
537
|
+
} catch (error) {
|
|
538
|
+
scriptElement?.remove();
|
|
539
|
+
removeCssForLoad(pendingLoad.cssLoadRef);
|
|
540
|
+
throw error;
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
async function loadPackages(descriptors) {
|
|
544
|
+
return await Promise.all(descriptors.map(loadPackage));
|
|
545
|
+
}
|
|
546
|
+
function getRegisteredWidgets() {
|
|
547
|
+
return Array.from(widgetsByKey.values());
|
|
548
|
+
}
|
|
549
|
+
function getRegistry() {
|
|
550
|
+
return new Map(widgetsByKey);
|
|
551
|
+
}
|
|
552
|
+
function cachePreRegisteredPackage(descriptor, cacheKey, cssLoadRef, registration) {
|
|
553
|
+
try {
|
|
554
|
+
installCssUrls(descriptor, cssLoadRef);
|
|
555
|
+
return cachePackageRegistration(descriptor, cacheKey, cssLoadRef, registration);
|
|
556
|
+
} catch (error) {
|
|
557
|
+
removeCssForLoad(cssLoadRef);
|
|
558
|
+
throw error;
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
function cachePackageRegistrationWithRemoteCleanup(descriptor, cacheKey, cssLoadRef, registration, scriptLoadResult, scriptElement) {
|
|
562
|
+
try {
|
|
563
|
+
return cachePackageRegistration(descriptor, cacheKey, cssLoadRef, registration, scriptElement);
|
|
564
|
+
} catch (error) {
|
|
565
|
+
if (scriptLoadResult.registration !== void 0 && registration === scriptLoadResult.registration) cleanupUnexpectedFluidWidgetsRegistration(scriptLoadResult.registration, scriptLoadResult.previousRegistration);
|
|
566
|
+
throw error;
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
function cachePackageRegistration(descriptor, cacheKey, cssLoadRef, registration, scriptElement) {
|
|
570
|
+
validateWidgetPackageRegistration(registration, descriptor);
|
|
571
|
+
const widgets = mergeRegisteredWidgets(descriptor, registration);
|
|
572
|
+
const cached = {
|
|
573
|
+
cacheKey,
|
|
574
|
+
cssLoadRef,
|
|
575
|
+
packageId: descriptor.packageId,
|
|
576
|
+
version: descriptor.version,
|
|
577
|
+
scriptElement,
|
|
578
|
+
widgets
|
|
579
|
+
};
|
|
580
|
+
packagesByKey.set(cacheKey, cached);
|
|
581
|
+
for (const widget of widgets) widgetsByKey.set(createWidgetRegistryKey(widget.packageId, widget.version, widget.type), widget);
|
|
582
|
+
return cached;
|
|
583
|
+
}
|
|
584
|
+
function invalidatePackage(packageId, version) {
|
|
585
|
+
isApplyingLocalGlobalClear = true;
|
|
586
|
+
try {
|
|
587
|
+
fluidWidgets.clear(packageId, version);
|
|
588
|
+
} finally {
|
|
589
|
+
isApplyingLocalGlobalClear = false;
|
|
590
|
+
}
|
|
591
|
+
invalidateCacheKeys(collectMatchingCacheKeys(packageId, version));
|
|
592
|
+
}
|
|
593
|
+
function clear() {
|
|
594
|
+
isApplyingLocalGlobalClear = true;
|
|
595
|
+
try {
|
|
596
|
+
fluidWidgets.clear();
|
|
597
|
+
} finally {
|
|
598
|
+
isApplyingLocalGlobalClear = false;
|
|
599
|
+
}
|
|
600
|
+
invalidateCacheKeys(new Set([...packagesByKey.keys(), ...pendingPackagesByKey.keys()]));
|
|
601
|
+
}
|
|
602
|
+
function collectMatchingCacheKeys(packageId, version) {
|
|
603
|
+
const cacheKeys = /* @__PURE__ */ new Set();
|
|
604
|
+
for (const cachedPackage of packagesByKey.values()) if (matchesPackage(cachedPackage, packageId, version)) cacheKeys.add(cachedPackage.cacheKey);
|
|
605
|
+
for (const pendingPackage of pendingPackagesByKey.values()) if (matchesPackage(pendingPackage.load, packageId, version)) cacheKeys.add(pendingPackage.load.cacheKey);
|
|
606
|
+
return cacheKeys;
|
|
607
|
+
}
|
|
608
|
+
function invalidateCacheKeys(cacheKeys) {
|
|
609
|
+
for (const cacheKey of cacheKeys) invalidatePackageCacheKey(cacheKey);
|
|
610
|
+
}
|
|
611
|
+
function installCssUrls(descriptor, cssLoadRef) {
|
|
612
|
+
const normalizedCssUrls = descriptor.cssUrls.map((cssUrl) => ({ key: normalizeAssetUrl(cssUrl, descriptor) }));
|
|
613
|
+
const keys = [];
|
|
614
|
+
for (const { key } of normalizedCssUrls) {
|
|
615
|
+
const existing = cssByKey.get(key);
|
|
616
|
+
if (existing) {
|
|
617
|
+
existing.packageRefs.add(cssLoadRef);
|
|
618
|
+
keys.push(key);
|
|
619
|
+
continue;
|
|
620
|
+
}
|
|
621
|
+
const linkElement = document.createElement("link");
|
|
622
|
+
linkElement.rel = "stylesheet";
|
|
623
|
+
linkElement.href = key;
|
|
624
|
+
linkElement.dataset.fluidWidgetRuntimeCss = "true";
|
|
625
|
+
linkElement.dataset.fluidWidgetRuntimeCssKey = key;
|
|
626
|
+
document.head.appendChild(linkElement);
|
|
627
|
+
cssByKey.set(key, {
|
|
628
|
+
key,
|
|
629
|
+
element: linkElement,
|
|
630
|
+
packageRefs: new Set([cssLoadRef])
|
|
631
|
+
});
|
|
632
|
+
keys.push(key);
|
|
633
|
+
}
|
|
634
|
+
return keys;
|
|
635
|
+
}
|
|
636
|
+
function invalidatePackageCacheKey(cacheKey) {
|
|
637
|
+
bumpPackageGeneration(cacheKey);
|
|
638
|
+
const pendingPackage = pendingPackagesByKey.get(cacheKey);
|
|
639
|
+
if (pendingPackage) {
|
|
640
|
+
removeCssForLoad(pendingPackage.load.cssLoadRef);
|
|
641
|
+
removePendingRemoteRegistration(pendingPackage.load);
|
|
642
|
+
pendingPackagesByKey.delete(cacheKey);
|
|
643
|
+
}
|
|
644
|
+
removePackage(cacheKey);
|
|
645
|
+
}
|
|
646
|
+
function removePackage(cacheKey) {
|
|
647
|
+
const cachedPackage = packagesByKey.get(cacheKey);
|
|
648
|
+
if (!cachedPackage) return;
|
|
649
|
+
cachedPackage.scriptElement?.remove();
|
|
650
|
+
for (const widget of cachedPackage.widgets) widgetsByKey.delete(createWidgetRegistryKey(widget.packageId, widget.version, widget.type));
|
|
651
|
+
removeCssForLoad(cachedPackage.cssLoadRef);
|
|
652
|
+
packagesByKey.delete(cacheKey);
|
|
653
|
+
}
|
|
654
|
+
function removeCssForLoad(cssLoadRef) {
|
|
655
|
+
for (const entry of Array.from(cssByKey.values())) {
|
|
656
|
+
entry.packageRefs.delete(cssLoadRef);
|
|
657
|
+
if (entry.packageRefs.size === 0) {
|
|
658
|
+
entry.element.remove();
|
|
659
|
+
cssByKey.delete(entry.key);
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
function getPackageGeneration(cacheKey) {
|
|
664
|
+
return packageGenerationsByKey.get(cacheKey) ?? 0;
|
|
665
|
+
}
|
|
666
|
+
function bumpPackageGeneration(cacheKey) {
|
|
667
|
+
packageGenerationsByKey.set(cacheKey, getPackageGeneration(cacheKey) + 1);
|
|
668
|
+
}
|
|
669
|
+
function isFreshPackageLoad(pendingLoad) {
|
|
670
|
+
return getPackageGeneration(pendingLoad.cacheKey) === pendingLoad.generation;
|
|
671
|
+
}
|
|
672
|
+
function throwIfStalePackageLoad(pendingLoad) {
|
|
673
|
+
if (isFreshPackageLoad(pendingLoad)) return;
|
|
674
|
+
throw new WidgetRuntimeError({
|
|
675
|
+
code: "SCRIPT_LOAD_FAILED",
|
|
676
|
+
message: `Widget package load ${pendingLoad.packageId}@${pendingLoad.version} was invalidated before it completed`,
|
|
677
|
+
packageId: pendingLoad.packageId,
|
|
678
|
+
version: pendingLoad.version
|
|
679
|
+
});
|
|
680
|
+
}
|
|
681
|
+
function matchesPackage(cachedPackage, packageId, version) {
|
|
682
|
+
if (cachedPackage.packageId !== packageId) return false;
|
|
683
|
+
return version === void 0 || cachedPackage.version === version;
|
|
684
|
+
}
|
|
685
|
+
return {
|
|
686
|
+
loadPackage,
|
|
687
|
+
loadPackages,
|
|
688
|
+
getRegisteredWidgets,
|
|
689
|
+
getRegistry,
|
|
690
|
+
invalidatePackage,
|
|
691
|
+
clear
|
|
692
|
+
};
|
|
693
|
+
}
|
|
694
|
+
function mergeRegisteredWidgets(descriptor, registration) {
|
|
695
|
+
const registrationWidgetsByType = new Map(registration.widgets.map((widget) => [widget.type, widget]));
|
|
696
|
+
return descriptor.widgets.map((descriptorWidget) => {
|
|
697
|
+
const registeredWidget = registrationWidgetsByType.get(descriptorWidget.type);
|
|
698
|
+
if (!registeredWidget) throw new WidgetRuntimeError({
|
|
699
|
+
code: "INVALID_REGISTRATION",
|
|
700
|
+
message: `Widget package registration is missing widget type: ${descriptorWidget.type}`,
|
|
701
|
+
packageId: descriptor.packageId,
|
|
702
|
+
version: descriptor.version
|
|
703
|
+
});
|
|
704
|
+
return {
|
|
705
|
+
...descriptorWidget,
|
|
706
|
+
...pickRuntimeMetadataOverrides(registeredWidget),
|
|
707
|
+
packageId: descriptor.packageId,
|
|
708
|
+
packageType: descriptor.packageType,
|
|
709
|
+
version: descriptor.version,
|
|
710
|
+
propertySchema: registeredWidget.propertySchema,
|
|
711
|
+
defaultProps: registeredWidget.defaultProps,
|
|
712
|
+
component: registeredWidget.component
|
|
713
|
+
};
|
|
714
|
+
});
|
|
715
|
+
}
|
|
716
|
+
function pickRuntimeMetadataOverrides(widget) {
|
|
717
|
+
return {
|
|
718
|
+
...widget.name !== void 0 ? { name: widget.name } : {},
|
|
719
|
+
...widget.displayName !== void 0 ? { displayName: widget.displayName } : {},
|
|
720
|
+
...widget.description !== void 0 ? { description: widget.description } : {},
|
|
721
|
+
...widget.icon !== void 0 ? { icon: widget.icon } : {},
|
|
722
|
+
...widget.category !== void 0 ? { category: widget.category } : {},
|
|
723
|
+
...widget.container !== void 0 ? { container: widget.container } : {},
|
|
724
|
+
...widget.minSdkVersion !== void 0 ? { minSdkVersion: widget.minSdkVersion } : {},
|
|
725
|
+
...widget.resizable !== void 0 ? { resizable: widget.resizable } : {}
|
|
726
|
+
};
|
|
727
|
+
}
|
|
728
|
+
function loadRemoteEntryScript(descriptor, timeoutMs, cacheBust, assertFreshPackageLoad, isFreshPackageLoad, remoteEntryUrlKey) {
|
|
729
|
+
return enqueueRemoteEntryScriptLoad(async () => {
|
|
730
|
+
assertFreshPackageLoad();
|
|
731
|
+
const registration = ensureFluidWidgetsGlobal().getPackageRegistration(descriptor.packageId, descriptor.version);
|
|
732
|
+
if (registration) return {
|
|
733
|
+
previousRegistration: void 0,
|
|
734
|
+
registration
|
|
735
|
+
};
|
|
736
|
+
return await loadRemoteEntryScriptImmediately(descriptor, timeoutMs, cacheBust, isFreshPackageLoad, remoteEntryUrlKey);
|
|
737
|
+
});
|
|
738
|
+
}
|
|
739
|
+
async function loadRemoteEntryScriptImmediately(descriptor, timeoutMs, cacheBust, isFreshPackageLoad, remoteEntryUrlKey) {
|
|
740
|
+
const fluidWidgets = ensureFluidWidgetsGlobal();
|
|
741
|
+
let previousRegistration;
|
|
742
|
+
let registration;
|
|
743
|
+
const unsubscribe = fluidWidgets.subscribe((event) => {
|
|
744
|
+
if (event.kind !== "register") return;
|
|
745
|
+
if (event.registration.packageId === descriptor.packageId && event.registration.version === descriptor.version) {
|
|
746
|
+
if (isFreshPackageLoad()) {
|
|
747
|
+
previousRegistration = event.previousRegistration;
|
|
748
|
+
registration = event.registration;
|
|
749
|
+
return;
|
|
750
|
+
}
|
|
751
|
+
cleanupUnexpectedFluidWidgetsRegistration(event.registration, event.previousRegistration);
|
|
752
|
+
return;
|
|
753
|
+
}
|
|
754
|
+
if (hasPendingRemoteRegistrationForScript(event.registration, remoteEntryUrlKey)) return;
|
|
755
|
+
cleanupUnexpectedFluidWidgetsRegistration(event.registration, event.previousRegistration);
|
|
756
|
+
});
|
|
757
|
+
const scriptElement = document.createElement("script");
|
|
758
|
+
let timeoutId;
|
|
759
|
+
try {
|
|
760
|
+
await new Promise((resolve, reject) => {
|
|
761
|
+
timeoutId = window.setTimeout(() => {
|
|
762
|
+
reject(new WidgetRuntimeError({
|
|
763
|
+
code: "SCRIPT_TIMEOUT",
|
|
764
|
+
message: `Timed out loading widget package ${descriptor.packageId}@${descriptor.version}`,
|
|
765
|
+
packageId: descriptor.packageId,
|
|
766
|
+
version: descriptor.version
|
|
767
|
+
}));
|
|
768
|
+
}, timeoutMs);
|
|
769
|
+
scriptElement.async = true;
|
|
770
|
+
scriptElement.src = withCacheBust(descriptor.remoteEntryUrl, cacheBust);
|
|
771
|
+
scriptElement.dataset.fluidWidgetRuntimeScript = "true";
|
|
772
|
+
scriptElement.dataset.fluidWidgetRuntimePackageId = descriptor.packageId;
|
|
773
|
+
scriptElement.dataset.fluidWidgetRuntimeVersion = descriptor.version;
|
|
774
|
+
scriptElement.addEventListener("load", () => {
|
|
775
|
+
resolve();
|
|
776
|
+
}, { once: true });
|
|
777
|
+
scriptElement.addEventListener("error", () => {
|
|
778
|
+
reject(new WidgetRuntimeError({
|
|
779
|
+
code: "SCRIPT_LOAD_FAILED",
|
|
780
|
+
message: `Failed to load widget package script ${descriptor.remoteEntryUrl}`,
|
|
781
|
+
packageId: descriptor.packageId,
|
|
782
|
+
version: descriptor.version
|
|
783
|
+
}));
|
|
784
|
+
}, { once: true });
|
|
785
|
+
document.head.appendChild(scriptElement);
|
|
786
|
+
});
|
|
787
|
+
} catch (error) {
|
|
788
|
+
scriptElement.remove();
|
|
789
|
+
throw error;
|
|
790
|
+
} finally {
|
|
791
|
+
unsubscribe();
|
|
792
|
+
if (timeoutId !== void 0) window.clearTimeout(timeoutId);
|
|
793
|
+
}
|
|
794
|
+
return {
|
|
795
|
+
previousRegistration,
|
|
796
|
+
registration,
|
|
797
|
+
scriptElement
|
|
798
|
+
};
|
|
799
|
+
}
|
|
800
|
+
function getDescriptorIdentity(descriptor) {
|
|
801
|
+
if (typeof descriptor !== "object" || descriptor === null) return {};
|
|
802
|
+
return {
|
|
803
|
+
packageId: typeof descriptor.packageId === "string" ? descriptor.packageId : void 0,
|
|
804
|
+
version: typeof descriptor.version === "string" ? descriptor.version : void 0
|
|
805
|
+
};
|
|
806
|
+
}
|
|
807
|
+
function createSuccess(cachedPackage) {
|
|
808
|
+
return {
|
|
809
|
+
ok: true,
|
|
810
|
+
packageId: cachedPackage.packageId,
|
|
811
|
+
version: cachedPackage.version,
|
|
812
|
+
widgets: cachedPackage.widgets
|
|
813
|
+
};
|
|
814
|
+
}
|
|
815
|
+
function createPackageCacheKey(packageId, version) {
|
|
816
|
+
return JSON.stringify([packageId, version]);
|
|
817
|
+
}
|
|
818
|
+
function createCssLoadRef(cacheKey, generation) {
|
|
819
|
+
return JSON.stringify([cacheKey, generation]);
|
|
820
|
+
}
|
|
821
|
+
function createWidgetRegistryKey(packageId, version, type) {
|
|
822
|
+
return JSON.stringify([
|
|
823
|
+
packageId,
|
|
824
|
+
version,
|
|
825
|
+
type
|
|
826
|
+
]);
|
|
827
|
+
}
|
|
828
|
+
function addPendingRemoteRegistration(pendingLoad) {
|
|
829
|
+
const packageKey = createPackageCacheKey(pendingLoad.packageId, pendingLoad.version);
|
|
830
|
+
const pendingLoads = pendingRemoteRegistrationsByPackageKey.get(packageKey);
|
|
831
|
+
if (pendingLoads) {
|
|
832
|
+
pendingLoads.add(pendingLoad);
|
|
833
|
+
return;
|
|
834
|
+
}
|
|
835
|
+
pendingRemoteRegistrationsByPackageKey.set(packageKey, new Set([pendingLoad]));
|
|
836
|
+
}
|
|
837
|
+
function removePendingRemoteRegistration(pendingLoad) {
|
|
838
|
+
const packageKey = createPackageCacheKey(pendingLoad.packageId, pendingLoad.version);
|
|
839
|
+
const pendingLoads = pendingRemoteRegistrationsByPackageKey.get(packageKey);
|
|
840
|
+
if (!pendingLoads) return;
|
|
841
|
+
pendingLoads.delete(pendingLoad);
|
|
842
|
+
if (pendingLoads.size === 0) pendingRemoteRegistrationsByPackageKey.delete(packageKey);
|
|
843
|
+
}
|
|
844
|
+
function hasPendingRemoteRegistrationForScript(registration, remoteEntryUrlKey) {
|
|
845
|
+
const pendingLoads = pendingRemoteRegistrationsByPackageKey.get(createPackageCacheKey(registration.packageId, registration.version));
|
|
846
|
+
if (!pendingLoads) return false;
|
|
847
|
+
for (const pendingLoad of pendingLoads) if (pendingLoad.remoteEntryUrlKey === remoteEntryUrlKey) return true;
|
|
848
|
+
return false;
|
|
849
|
+
}
|
|
850
|
+
function enqueueRemoteEntryScriptLoad(task) {
|
|
851
|
+
const previousLoad = remoteScriptLoadQueue;
|
|
852
|
+
const resultPromise = previousLoad === void 0 ? task() : previousLoad.then(task, task);
|
|
853
|
+
const currentLoad = resultPromise.then(() => void 0, () => void 0);
|
|
854
|
+
remoteScriptLoadQueue = currentLoad;
|
|
855
|
+
currentLoad.then(() => {
|
|
856
|
+
if (remoteScriptLoadQueue === currentLoad) remoteScriptLoadQueue = void 0;
|
|
857
|
+
});
|
|
858
|
+
return resultPromise;
|
|
859
|
+
}
|
|
860
|
+
function normalizeAssetUrl(url, descriptor) {
|
|
861
|
+
try {
|
|
862
|
+
return new URL(url, window.location.href).href;
|
|
863
|
+
} catch {
|
|
864
|
+
throw new WidgetRuntimeError({
|
|
865
|
+
code: "INVALID_DESCRIPTOR",
|
|
866
|
+
message: `Widget package cssUrls contains invalid URL: ${url}`,
|
|
867
|
+
packageId: descriptor.packageId,
|
|
868
|
+
version: descriptor.version
|
|
869
|
+
});
|
|
870
|
+
}
|
|
871
|
+
}
|
|
872
|
+
function withCacheBust(url, cacheBust) {
|
|
873
|
+
if (cacheBust === void 0 || cacheBust === false) return url;
|
|
874
|
+
const cacheBustValue = typeof cacheBust === "function" ? cacheBust() : cacheBust === true ? String(Date.now()) : cacheBust;
|
|
875
|
+
const nextUrl = new URL(url, window.location.href);
|
|
876
|
+
nextUrl.searchParams.set("fluidWidgetRuntimeCacheBust", cacheBustValue);
|
|
877
|
+
return nextUrl.href;
|
|
878
|
+
}
|
|
879
|
+
//#endregion
|
|
880
|
+
//#region ../../platform/widget-runtime/src/globals.ts
|
|
881
|
+
const globalMarker = Symbol.for("fluid.widget-runtime.FluidSharedGlobals");
|
|
882
|
+
function installFluidWidgetRuntimeHostGlobals(shared = {
|
|
883
|
+
React: react,
|
|
884
|
+
ReactDOM: react_dom,
|
|
885
|
+
ReactJsxRuntime: react_jsx_runtime
|
|
886
|
+
}) {
|
|
887
|
+
ensureFluidWidgetsGlobal();
|
|
888
|
+
const existing = window.FluidShared;
|
|
889
|
+
if (isFluidSharedGlobal(existing)) return existing;
|
|
890
|
+
const widgetRuntime = {
|
|
891
|
+
createWidgetRuntimeLoader,
|
|
892
|
+
installFluidWidgetRuntimeHostGlobals,
|
|
893
|
+
manifestVersion: 1,
|
|
894
|
+
...shared.WidgetRuntime
|
|
895
|
+
};
|
|
896
|
+
const fluidShared = {
|
|
897
|
+
[globalMarker]: true,
|
|
898
|
+
React: shared.React,
|
|
899
|
+
ReactDOM: shared.ReactDOM,
|
|
900
|
+
ReactJsxRuntime: shared.ReactJsxRuntime,
|
|
901
|
+
WidgetRuntime: widgetRuntime
|
|
902
|
+
};
|
|
903
|
+
window.FluidShared = fluidShared;
|
|
904
|
+
return fluidShared;
|
|
905
|
+
}
|
|
906
|
+
function isFluidSharedGlobal(value) {
|
|
907
|
+
return value !== void 0 && value[globalMarker] === true;
|
|
908
|
+
}
|
|
909
|
+
//#endregion
|
|
910
|
+
//#region ../../platform/widget-runtime/src/components/WidgetRuntimeErrorBoundary.tsx
|
|
911
|
+
var WidgetRuntimeErrorBoundary = class extends react.Component {
|
|
912
|
+
state = { error: null };
|
|
913
|
+
static getDerivedStateFromError(error) {
|
|
914
|
+
return { error };
|
|
915
|
+
}
|
|
916
|
+
componentDidCatch(error, errorInfo) {
|
|
917
|
+
this.props.onError?.(error, errorInfo);
|
|
918
|
+
}
|
|
919
|
+
render() {
|
|
920
|
+
const { error } = this.state;
|
|
921
|
+
if (!error) return this.props.children;
|
|
922
|
+
const reset = () => {
|
|
923
|
+
this.setState({ error: null });
|
|
924
|
+
};
|
|
925
|
+
if (typeof this.props.fallback === "function") return this.props.fallback({
|
|
926
|
+
error,
|
|
927
|
+
reset
|
|
928
|
+
});
|
|
929
|
+
if (this.props.fallback !== void 0) return this.props.fallback;
|
|
930
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DefaultWidgetRuntimeErrorFallback, {
|
|
931
|
+
error,
|
|
932
|
+
reset
|
|
933
|
+
});
|
|
934
|
+
}
|
|
935
|
+
};
|
|
936
|
+
function DefaultWidgetRuntimeErrorFallback({ error, reset }) {
|
|
937
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
938
|
+
role: "alert",
|
|
939
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", { children: error instanceof WidgetRuntimeError ? "Widget runtime failed" : "Widget failed to render" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
940
|
+
type: "button",
|
|
941
|
+
onClick: reset,
|
|
942
|
+
children: "Try again"
|
|
943
|
+
})]
|
|
944
|
+
});
|
|
945
|
+
}
|
|
946
|
+
//#endregion
|
|
947
|
+
//#region src/utils/build-widget-registry.ts
|
|
948
|
+
function buildWidgetRegistry(manifests) {
|
|
949
|
+
if (manifests.length === 0) return require_FluidProvider.DEFAULT_SDK_WIDGET_REGISTRY;
|
|
950
|
+
const customEntries = Object.fromEntries(manifests.filter((manifest) => {
|
|
951
|
+
const isBuiltIn = isBuiltInWidgetType(manifest.type);
|
|
952
|
+
if (isBuiltIn) warnBuiltInWidgetCollision("manifest", manifest.type);
|
|
953
|
+
return !isBuiltIn;
|
|
954
|
+
}).map((manifest) => [manifest.type, manifest.component]));
|
|
955
|
+
return {
|
|
956
|
+
...require_FluidProvider.DEFAULT_SDK_WIDGET_REGISTRY,
|
|
957
|
+
...customEntries
|
|
958
|
+
};
|
|
959
|
+
}
|
|
960
|
+
function mergeRegisteredWidgetsIntoRegistry(registry, registeredWidgets) {
|
|
961
|
+
if (registeredWidgets.length === 0) return registry;
|
|
962
|
+
const duplicateRuntimeWidgetTypes = getDuplicateWidgetTypes(registeredWidgets);
|
|
963
|
+
const remoteEntries = Object.fromEntries(registeredWidgets.filter((widget) => {
|
|
964
|
+
if (isBuiltInWidgetType(widget.type)) {
|
|
965
|
+
warnBuiltInWidgetCollision("runtime registration", widget.type);
|
|
966
|
+
return false;
|
|
967
|
+
}
|
|
968
|
+
if (duplicateRuntimeWidgetTypes.has(widget.type)) {
|
|
969
|
+
warnDuplicateRuntimeWidgetType(widget.type);
|
|
970
|
+
return false;
|
|
971
|
+
}
|
|
972
|
+
if (isExistingRegistryWidgetType(registry, widget.type)) {
|
|
973
|
+
warnExistingRegistryWidgetCollision(widget.type);
|
|
974
|
+
return false;
|
|
975
|
+
}
|
|
976
|
+
return true;
|
|
977
|
+
}).map((widget) => [widget.type, wrapRuntimeWidgetComponent(widget)]));
|
|
978
|
+
return {
|
|
979
|
+
...registry,
|
|
980
|
+
...remoteEntries
|
|
981
|
+
};
|
|
982
|
+
}
|
|
983
|
+
function getDuplicateWidgetTypes(widgets) {
|
|
984
|
+
const counts = /* @__PURE__ */ new Map();
|
|
985
|
+
for (const widget of widgets) counts.set(widget.type, (counts.get(widget.type) ?? 0) + 1);
|
|
986
|
+
return new Set(Array.from(counts.entries()).filter(([, count]) => count > 1).map(([type]) => type));
|
|
987
|
+
}
|
|
988
|
+
function wrapRuntimeWidgetComponent(widget) {
|
|
989
|
+
const RuntimeWidgetComponent = widget.component;
|
|
990
|
+
function RuntimeWidgetWithBoundary(props) {
|
|
991
|
+
return (0, react.createElement)(WidgetRuntimeErrorBoundary, null, (0, react.createElement)(RuntimeWidgetComponent, props));
|
|
992
|
+
}
|
|
993
|
+
RuntimeWidgetWithBoundary.displayName = `WidgetRuntimeErrorBoundary(${widget.type})`;
|
|
994
|
+
return RuntimeWidgetWithBoundary;
|
|
995
|
+
}
|
|
996
|
+
function isBuiltInWidgetType(widgetType) {
|
|
997
|
+
return Object.prototype.hasOwnProperty.call(require_FluidProvider.DEFAULT_SDK_WIDGET_REGISTRY, widgetType);
|
|
998
|
+
}
|
|
999
|
+
function isExistingRegistryWidgetType(registry, widgetType) {
|
|
1000
|
+
return Object.prototype.hasOwnProperty.call(registry, widgetType);
|
|
1001
|
+
}
|
|
1002
|
+
function warnBuiltInWidgetCollision(source, widgetType) {
|
|
1003
|
+
console.warn(`[portal-sdk] Ignoring ${source} for built-in widget type "${widgetType}". Built-in widgets cannot be overridden.`);
|
|
1004
|
+
}
|
|
1005
|
+
function warnDuplicateRuntimeWidgetType(widgetType) {
|
|
1006
|
+
console.warn(`[portal-sdk] Ignoring runtime widget type "${widgetType}" because multiple packages registered the same SDK-facing type.`);
|
|
1007
|
+
}
|
|
1008
|
+
function warnExistingRegistryWidgetCollision(widgetType) {
|
|
1009
|
+
console.warn(`[portal-sdk] Ignoring runtime widget type "${widgetType}" because the SDK registry already contains that type.`);
|
|
1010
|
+
}
|
|
1011
|
+
//#endregion
|
|
1012
|
+
//#region src/utils/widget-package-manifest-url.ts
|
|
1013
|
+
const DEFAULT_WIDGET_PACKAGE_MANIFEST_URL = "/api/app/widget-packages";
|
|
1014
|
+
const VITE_DEV_WIDGET_PACKAGE_MANIFEST_URL = "/__widget-packages__";
|
|
1015
|
+
const VITE_DEV_MODULE_PATH_SEGMENTS = [
|
|
1016
|
+
"/@fs/",
|
|
1017
|
+
"/src/",
|
|
1018
|
+
"/node_modules/.vite/",
|
|
1019
|
+
"/@id/"
|
|
1020
|
+
];
|
|
1021
|
+
function resolveDefaultWidgetPackageManifestUrl(moduleUrl, options = {}) {
|
|
1022
|
+
const parsedModuleUrl = parseModuleUrl(moduleUrl);
|
|
1023
|
+
if (!parsedModuleUrl) return false;
|
|
1024
|
+
if (options.isViteDev && isViteDevModulePath(parsedModuleUrl.pathname)) return new URL(VITE_DEV_WIDGET_PACKAGE_MANIFEST_URL, parsedModuleUrl.origin).href;
|
|
1025
|
+
return DEFAULT_WIDGET_PACKAGE_MANIFEST_URL;
|
|
1026
|
+
}
|
|
1027
|
+
function parseModuleUrl(moduleUrl) {
|
|
1028
|
+
if (!moduleUrl) return null;
|
|
1029
|
+
try {
|
|
1030
|
+
return new URL(moduleUrl);
|
|
1031
|
+
} catch {
|
|
1032
|
+
return null;
|
|
1033
|
+
}
|
|
1034
|
+
}
|
|
1035
|
+
function isViteDevModulePath(pathname) {
|
|
1036
|
+
return VITE_DEV_MODULE_PATH_SEGMENTS.some((segment) => pathname.includes(segment));
|
|
1037
|
+
}
|
|
1038
|
+
function getDefaultWidgetPackageManifestUrl() {
|
|
1039
|
+
return resolveDefaultWidgetPackageManifestUrl(require("url").pathToFileURL(__filename).href, { isViteDev: isViteDevRuntime() });
|
|
1040
|
+
}
|
|
1041
|
+
function isViteDevRuntime() {
|
|
1042
|
+
return {}.env?.DEV === true;
|
|
1043
|
+
}
|
|
1044
|
+
//#endregion
|
|
1045
|
+
//#region src/utils/load-widget-packages.ts
|
|
1046
|
+
const WIDGET_PACKAGE_DESCRIPTOR_MANIFEST_VERSION = 1;
|
|
1047
|
+
const WIDGET_PACKAGE_DESCRIPTOR_FETCH_TIMEOUT_MS = 5e3;
|
|
1048
|
+
function installAndReadFluidWidgetsRegistry() {
|
|
1049
|
+
if (typeof window === "undefined") return [];
|
|
1050
|
+
installFluidWidgetRuntimeHostGlobals({
|
|
1051
|
+
React: react,
|
|
1052
|
+
ReactDOM: react_dom,
|
|
1053
|
+
ReactJsxRuntime: react_jsx_runtime
|
|
1054
|
+
});
|
|
1055
|
+
return ensureFluidWidgetsGlobal().getRegisteredWidgets();
|
|
1056
|
+
}
|
|
1057
|
+
function subscribeToFluidWidgetsRegistry(listener) {
|
|
1058
|
+
if (typeof window === "undefined") return () => void 0;
|
|
1059
|
+
installFluidWidgetRuntimeHostGlobals({
|
|
1060
|
+
React: react,
|
|
1061
|
+
ReactDOM: react_dom,
|
|
1062
|
+
ReactJsxRuntime: react_jsx_runtime
|
|
1063
|
+
});
|
|
1064
|
+
const fluidWidgets = ensureFluidWidgetsGlobal();
|
|
1065
|
+
return fluidWidgets.subscribe(() => {
|
|
1066
|
+
listener(fluidWidgets.getRegisteredWidgets());
|
|
1067
|
+
});
|
|
1068
|
+
}
|
|
1069
|
+
async function fetchWidgetPackageDescriptors(descriptorEndpointUrl = DEFAULT_WIDGET_PACKAGE_MANIFEST_URL, options = {}) {
|
|
1070
|
+
const abortSignal = createTimeoutAbortSignal(WIDGET_PACKAGE_DESCRIPTOR_FETCH_TIMEOUT_MS);
|
|
1071
|
+
try {
|
|
1072
|
+
const response = await fetch(descriptorEndpointUrl, {
|
|
1073
|
+
credentials: options.credentials ?? "same-origin",
|
|
1074
|
+
signal: abortSignal.signal
|
|
1075
|
+
});
|
|
1076
|
+
if (!response.ok) throw new Error(`[portal] Failed to fetch widget package descriptors from ${descriptorEndpointUrl}: ${response.status} ${response.statusText}`);
|
|
1077
|
+
return parseWidgetPackageDescriptorResponse(await response.json(), descriptorEndpointUrl, options);
|
|
1078
|
+
} finally {
|
|
1079
|
+
abortSignal.cleanup();
|
|
1080
|
+
}
|
|
1081
|
+
}
|
|
1082
|
+
function parseWidgetPackageDescriptorResponse(data, descriptorEndpointUrl = DEFAULT_WIDGET_PACKAGE_MANIFEST_URL, options = {}) {
|
|
1083
|
+
const descriptorEndpointBaseUrl = normalizeDescriptorEndpointUrl(descriptorEndpointUrl);
|
|
1084
|
+
if (!descriptorEndpointBaseUrl) return [];
|
|
1085
|
+
const entries = getWidgetPackageDescriptorEntries(data);
|
|
1086
|
+
if (!entries) return [];
|
|
1087
|
+
const assetOriginPolicy = createRuntimeAssetOriginPolicy(descriptorEndpointBaseUrl, options.allowedOrigins ?? [], options.trustCatalogAssetOrigins === true);
|
|
1088
|
+
const descriptors = [];
|
|
1089
|
+
for (const entry of entries) {
|
|
1090
|
+
const descriptor = normalizeWidgetPackageDescriptor(entry, descriptorEndpointBaseUrl, assetOriginPolicy);
|
|
1091
|
+
if (descriptor) descriptors.push(descriptor);
|
|
1092
|
+
}
|
|
1093
|
+
return descriptors;
|
|
1094
|
+
}
|
|
1095
|
+
async function loadWidgetPackages(widgetPackages) {
|
|
1096
|
+
if (widgetPackages.length === 0) return {
|
|
1097
|
+
registeredWidgets: [],
|
|
1098
|
+
hasFailures: false
|
|
1099
|
+
};
|
|
1100
|
+
installAndReadFluidWidgetsRegistry();
|
|
1101
|
+
const loader = createWidgetRuntimeLoader();
|
|
1102
|
+
const runtimeWidgetPackages = widgetPackages;
|
|
1103
|
+
const results = await loader.loadPackages(runtimeWidgetPackages);
|
|
1104
|
+
let hasFailures = false;
|
|
1105
|
+
for (const result of results) if (!result.ok) {
|
|
1106
|
+
hasFailures = true;
|
|
1107
|
+
console.error(`[portal] Failed to load widget package ${result.packageId}@${result.version}:`, result.error);
|
|
1108
|
+
}
|
|
1109
|
+
return {
|
|
1110
|
+
registeredWidgets: loader.getRegisteredWidgets(),
|
|
1111
|
+
hasFailures
|
|
1112
|
+
};
|
|
1113
|
+
}
|
|
1114
|
+
function createTimeoutAbortSignal(timeoutMs) {
|
|
1115
|
+
if (typeof AbortSignal.timeout === "function") return {
|
|
1116
|
+
signal: AbortSignal.timeout(timeoutMs),
|
|
1117
|
+
cleanup: () => void 0
|
|
1118
|
+
};
|
|
1119
|
+
const controller = new AbortController();
|
|
1120
|
+
const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
|
|
1121
|
+
return {
|
|
1122
|
+
signal: controller.signal,
|
|
1123
|
+
cleanup: () => clearTimeout(timeoutId)
|
|
1124
|
+
};
|
|
1125
|
+
}
|
|
1126
|
+
function getWidgetPackageDescriptorEntries(data) {
|
|
1127
|
+
if (Array.isArray(data)) return data;
|
|
1128
|
+
if (!isRecord(data)) return null;
|
|
1129
|
+
const wrappedEntries = getArrayProperty(data, "packages") ?? getArrayProperty(data, "packageDescriptors") ?? getArrayProperty(data, "widgetPackages");
|
|
1130
|
+
if (wrappedEntries) return wrappedEntries;
|
|
1131
|
+
return looksLikeWidgetPackageEntry(data) ? [data] : null;
|
|
1132
|
+
}
|
|
1133
|
+
function normalizeWidgetPackageDescriptor(entry, descriptorEndpointUrl, assetOriginPolicy) {
|
|
1134
|
+
const candidate = createWidgetPackageDescriptorCandidate(entry);
|
|
1135
|
+
if (candidate.kind === "skipped") return null;
|
|
1136
|
+
if (candidate.kind === "invalid") {
|
|
1137
|
+
warnRejectedMalformedWidgetPackageEntry(entry, candidate.reason, descriptorEndpointUrl);
|
|
1138
|
+
return null;
|
|
1139
|
+
}
|
|
1140
|
+
const remoteEntryUrl = normalizeRuntimeAssetUrl(candidate.descriptor.remoteEntryUrl, descriptorEndpointUrl, assetOriginPolicy);
|
|
1141
|
+
if (!remoteEntryUrl.ok) {
|
|
1142
|
+
warnRejectedWidgetPackageDescriptor(candidate.descriptor, "remoteEntryUrl", remoteEntryUrl.failure, descriptorEndpointUrl);
|
|
1143
|
+
return null;
|
|
1144
|
+
}
|
|
1145
|
+
const cssUrls = [];
|
|
1146
|
+
for (const cssUrl of candidate.descriptor.cssUrls) {
|
|
1147
|
+
const normalizedCssUrl = normalizeRuntimeAssetUrl(cssUrl, descriptorEndpointUrl, assetOriginPolicy);
|
|
1148
|
+
if (!normalizedCssUrl.ok) {
|
|
1149
|
+
warnRejectedWidgetPackageDescriptor(candidate.descriptor, "cssUrls", normalizedCssUrl.failure, descriptorEndpointUrl);
|
|
1150
|
+
return null;
|
|
1151
|
+
}
|
|
1152
|
+
cssUrls.push(normalizedCssUrl.url);
|
|
1153
|
+
}
|
|
1154
|
+
const descriptor = {
|
|
1155
|
+
...candidate.descriptor,
|
|
1156
|
+
remoteEntryUrl: remoteEntryUrl.url,
|
|
1157
|
+
cssUrls
|
|
1158
|
+
};
|
|
1159
|
+
const validationError = validateDescriptorCandidate(descriptor);
|
|
1160
|
+
if (validationError) {
|
|
1161
|
+
warnRejectedMalformedWidgetPackageEntry(entry, validationError, descriptorEndpointUrl);
|
|
1162
|
+
return null;
|
|
1163
|
+
}
|
|
1164
|
+
return descriptor;
|
|
1165
|
+
}
|
|
1166
|
+
function createWidgetPackageDescriptorCandidate(entry) {
|
|
1167
|
+
if (!isRecord(entry)) return {
|
|
1168
|
+
kind: "invalid",
|
|
1169
|
+
reason: "entry must be an object"
|
|
1170
|
+
};
|
|
1171
|
+
const manifest = isRecord(entry.manifest) ? entry.manifest : void 0;
|
|
1172
|
+
if (entry.disabled === true || entry.enabled === false) return { kind: "skipped" };
|
|
1173
|
+
if (isRuntimeWidgetPackageDescriptorAttempt(entry)) return createStrictRuntimeWidgetPackageDescriptorCandidate(entry);
|
|
1174
|
+
if (isCatalogWidgetPackageEntry(entry, manifest)) return createCatalogWidgetPackageDescriptorCandidate(entry, manifest);
|
|
1175
|
+
return createRuntimeWidgetPackageDescriptorCandidate(entry, manifest);
|
|
1176
|
+
}
|
|
1177
|
+
function createStrictRuntimeWidgetPackageDescriptorCandidate(entry) {
|
|
1178
|
+
return createDescriptorCandidate({
|
|
1179
|
+
manifestVersion: normalizeManifestVersion(entry.manifestVersion, { defaultWhenMissing: false }),
|
|
1180
|
+
packageId: readNonEmptyString(entry.packageId),
|
|
1181
|
+
packageType: normalizeWidgetPackageType(entry.packageType),
|
|
1182
|
+
version: readNonEmptyString(entry.version),
|
|
1183
|
+
remoteEntryUrl: readNonEmptyString(entry.remoteEntryUrl),
|
|
1184
|
+
cssUrls: normalizeRuntimeCssUrls(entry.cssUrls),
|
|
1185
|
+
widgets: normalizeRuntimeWidgets(entry.widgets),
|
|
1186
|
+
packageTypeError: "packageType must be one of fluid, company, droplet, partner, or internal",
|
|
1187
|
+
widgetsError: "manifest.widgets/widgets must be a non-empty array"
|
|
1188
|
+
});
|
|
1189
|
+
}
|
|
1190
|
+
function createRuntimeWidgetPackageDescriptorCandidate(entry, manifest) {
|
|
1191
|
+
const packageId = readNonEmptyString(entry.packageId) ?? readNonEmptyString(manifest?.packageId);
|
|
1192
|
+
const version = readNonEmptyString(entry.version) ?? readNonEmptyString(manifest?.version);
|
|
1193
|
+
const remoteEntryUrl = readNonEmptyString(entry.remoteEntryUrl) ?? readNonEmptyString(manifest?.remoteEntryUrl);
|
|
1194
|
+
const packageType = normalizeWidgetPackageType(entry.packageType) ?? normalizeWidgetPackageType(manifest?.packageType);
|
|
1195
|
+
return createDescriptorCandidate({
|
|
1196
|
+
manifestVersion: normalizeManifestVersion(entry.manifestVersion ?? manifest?.manifestVersion, { defaultWhenMissing: false }),
|
|
1197
|
+
packageId,
|
|
1198
|
+
packageType,
|
|
1199
|
+
version,
|
|
1200
|
+
remoteEntryUrl,
|
|
1201
|
+
cssUrls: normalizeRuntimeCssUrls(entry.cssUrls ?? manifest?.cssUrls),
|
|
1202
|
+
widgets: normalizeRuntimeWidgets(manifest?.widgets ?? entry.widgets),
|
|
1203
|
+
packageTypeError: "packageType must be one of fluid, company, droplet, partner, or internal",
|
|
1204
|
+
widgetsError: "manifest.widgets/widgets must be a non-empty array"
|
|
1205
|
+
});
|
|
1206
|
+
}
|
|
1207
|
+
function createCatalogWidgetPackageDescriptorCandidate(entry, manifest) {
|
|
1208
|
+
const packageId = readNonEmptyString(entry.packageId) ?? readNonEmptyString(manifest?.packageId);
|
|
1209
|
+
const version = readNonEmptyString(entry.version) ?? readNonEmptyString(manifest?.version);
|
|
1210
|
+
const remoteEntryUrl = readNonEmptyString(entry.scriptUrl) ?? readNonEmptyString(entry.remoteEntryUrl) ?? readNonEmptyString(manifest?.scriptUrl) ?? readNonEmptyString(manifest?.remoteEntryUrl);
|
|
1211
|
+
const packageType = normalizeWidgetPackageType(entry.source) ?? normalizeWidgetPackageType(entry.packageType) ?? normalizeWidgetPackageType(manifest?.source) ?? normalizeWidgetPackageType(manifest?.packageType) ?? "company";
|
|
1212
|
+
const manifestVersion = normalizeManifestVersion(entry.manifestVersion ?? manifest?.manifestVersion, { defaultWhenMissing: true });
|
|
1213
|
+
const cssUrls = normalizeCssUrls(entry.cssUrls ?? manifest?.cssUrls);
|
|
1214
|
+
const rawWidgets = manifest?.widgets ?? entry.widgets;
|
|
1215
|
+
return createDescriptorCandidate({
|
|
1216
|
+
manifestVersion,
|
|
1217
|
+
packageId,
|
|
1218
|
+
packageType,
|
|
1219
|
+
version,
|
|
1220
|
+
remoteEntryUrl,
|
|
1221
|
+
cssUrls,
|
|
1222
|
+
widgets: Array.isArray(rawWidgets) ? normalizeCatalogWidgets(rawWidgets, packageId) : null,
|
|
1223
|
+
packageTypeError: "packageType/source must be one of fluid, company, droplet, partner, internal, or omitted for company catalog packages",
|
|
1224
|
+
widgetsError: "manifest.widgets/widgets must contain at least one valid widget"
|
|
1225
|
+
});
|
|
1226
|
+
}
|
|
1227
|
+
function createDescriptorCandidate(fields) {
|
|
1228
|
+
if (!fields.manifestVersion) return {
|
|
1229
|
+
kind: "invalid",
|
|
1230
|
+
reason: "unsupported manifestVersion"
|
|
1231
|
+
};
|
|
1232
|
+
if (!fields.packageId) return {
|
|
1233
|
+
kind: "invalid",
|
|
1234
|
+
reason: "packageId must be a non-empty string"
|
|
1235
|
+
};
|
|
1236
|
+
if (!fields.version) return {
|
|
1237
|
+
kind: "invalid",
|
|
1238
|
+
reason: "version must be a non-empty string"
|
|
1239
|
+
};
|
|
1240
|
+
if (!fields.packageType) return {
|
|
1241
|
+
kind: "invalid",
|
|
1242
|
+
reason: fields.packageTypeError
|
|
1243
|
+
};
|
|
1244
|
+
if (!fields.remoteEntryUrl) return {
|
|
1245
|
+
kind: "invalid",
|
|
1246
|
+
reason: "remoteEntryUrl/scriptUrl must be a non-empty string"
|
|
1247
|
+
};
|
|
1248
|
+
if (!fields.cssUrls) return {
|
|
1249
|
+
kind: "invalid",
|
|
1250
|
+
reason: "cssUrls must be an array of strings"
|
|
1251
|
+
};
|
|
1252
|
+
if (!fields.widgets || fields.widgets.length === 0) return {
|
|
1253
|
+
kind: "invalid",
|
|
1254
|
+
reason: fields.widgetsError
|
|
1255
|
+
};
|
|
1256
|
+
return {
|
|
1257
|
+
kind: "valid",
|
|
1258
|
+
descriptor: {
|
|
1259
|
+
manifestVersion: fields.manifestVersion,
|
|
1260
|
+
packageId: fields.packageId,
|
|
1261
|
+
packageType: fields.packageType,
|
|
1262
|
+
version: fields.version,
|
|
1263
|
+
remoteEntryUrl: fields.remoteEntryUrl,
|
|
1264
|
+
cssUrls: fields.cssUrls,
|
|
1265
|
+
widgets: fields.widgets
|
|
1266
|
+
}
|
|
1267
|
+
};
|
|
1268
|
+
}
|
|
1269
|
+
function validateDescriptorCandidate(descriptor) {
|
|
1270
|
+
try {
|
|
1271
|
+
validateWidgetPackageDescriptor(descriptor);
|
|
1272
|
+
return null;
|
|
1273
|
+
} catch (error) {
|
|
1274
|
+
return error instanceof Error ? error.message : String(error);
|
|
1275
|
+
}
|
|
1276
|
+
}
|
|
1277
|
+
function isRuntimeWidgetPackageDescriptorAttempt(entry) {
|
|
1278
|
+
return entry.manifestVersion !== void 0 && entry.packageId !== void 0 && entry.packageType !== void 0 && entry.version !== void 0 && entry.remoteEntryUrl !== void 0 && entry.cssUrls !== void 0 && entry.widgets !== void 0;
|
|
1279
|
+
}
|
|
1280
|
+
function isCatalogWidgetPackageEntry(entry, manifest) {
|
|
1281
|
+
return entry.source !== void 0 || entry.scriptUrl !== void 0 || entry.manifestUrl !== void 0 || manifest?.source !== void 0 || manifest?.scriptUrl !== void 0 || manifest?.manifestUrl !== void 0 || manifest?.widgets !== void 0;
|
|
1282
|
+
}
|
|
1283
|
+
function normalizeManifestVersion(value, options) {
|
|
1284
|
+
if (value === WIDGET_PACKAGE_DESCRIPTOR_MANIFEST_VERSION) return WIDGET_PACKAGE_DESCRIPTOR_MANIFEST_VERSION;
|
|
1285
|
+
if (value === void 0 && options.defaultWhenMissing) return WIDGET_PACKAGE_DESCRIPTOR_MANIFEST_VERSION;
|
|
1286
|
+
return null;
|
|
1287
|
+
}
|
|
1288
|
+
function normalizeCssUrls(value) {
|
|
1289
|
+
return normalizeCssUrlList(value, { undefinedValue: [] });
|
|
1290
|
+
}
|
|
1291
|
+
function normalizeRuntimeCssUrls(value) {
|
|
1292
|
+
return normalizeCssUrlList(value, { undefinedValue: null });
|
|
1293
|
+
}
|
|
1294
|
+
function normalizeCssUrlList(value, options) {
|
|
1295
|
+
if (value === void 0) return options.undefinedValue;
|
|
1296
|
+
if (!Array.isArray(value)) return null;
|
|
1297
|
+
const cssUrls = [];
|
|
1298
|
+
for (const cssUrl of value) {
|
|
1299
|
+
const normalizedCssUrl = readNonEmptyString(cssUrl);
|
|
1300
|
+
if (!normalizedCssUrl) return null;
|
|
1301
|
+
cssUrls.push(normalizedCssUrl);
|
|
1302
|
+
}
|
|
1303
|
+
return cssUrls;
|
|
1304
|
+
}
|
|
1305
|
+
function normalizeRuntimeWidgets(value) {
|
|
1306
|
+
if (!Array.isArray(value)) return null;
|
|
1307
|
+
return value;
|
|
1308
|
+
}
|
|
1309
|
+
function normalizeCatalogWidgets(value, packageId) {
|
|
1310
|
+
const widgets = [];
|
|
1311
|
+
value.forEach((widget, index) => {
|
|
1312
|
+
const normalizedWidget = normalizeWidgetDescriptor(widget, {
|
|
1313
|
+
fallbackType: packageId === void 0 ? void 0 : `${packageId}-widget-${index + 1}`,
|
|
1314
|
+
overwritePropertySchemaWidgetType: true
|
|
1315
|
+
});
|
|
1316
|
+
if (normalizedWidget) widgets.push(normalizedWidget);
|
|
1317
|
+
});
|
|
1318
|
+
return widgets;
|
|
1319
|
+
}
|
|
1320
|
+
function normalizeWidgetDescriptor(widget, options = {}) {
|
|
1321
|
+
if (!isRecord(widget)) return null;
|
|
1322
|
+
const type = readNonEmptyString(widget.type) ?? readNonEmptyString(widget.name) ?? options.fallbackType;
|
|
1323
|
+
if (!type) return null;
|
|
1324
|
+
const name = readNonEmptyString(widget.name) ?? type;
|
|
1325
|
+
const displayName = readNonEmptyString(widget.displayName) ?? name;
|
|
1326
|
+
return {
|
|
1327
|
+
type,
|
|
1328
|
+
name,
|
|
1329
|
+
displayName,
|
|
1330
|
+
description: readNonEmptyString(widget.description) ?? `Custom widget ${displayName}`,
|
|
1331
|
+
icon: readNonEmptyString(widget.icon) ?? "box",
|
|
1332
|
+
category: readNonEmptyString(widget.category) ?? "components",
|
|
1333
|
+
propertySchema: normalizePropertySchema(widget.propertySchema, type, { overwriteWidgetType: options.overwritePropertySchemaWidgetType === true }),
|
|
1334
|
+
defaultProps: isRecord(widget.defaultProps) ? widget.defaultProps : {},
|
|
1335
|
+
container: normalizeContainer(widget.container),
|
|
1336
|
+
minSdkVersion: readNonEmptyString(widget.minSdkVersion) ?? "0.0.0",
|
|
1337
|
+
resizable: normalizeResizable(widget.resizable)
|
|
1338
|
+
};
|
|
1339
|
+
}
|
|
1340
|
+
function normalizePropertySchema(value, widgetType, options = { overwriteWidgetType: false }) {
|
|
1341
|
+
if (!isRecord(value)) return { widgetType };
|
|
1342
|
+
if (options.overwriteWidgetType || value.widgetType === void 0) return {
|
|
1343
|
+
...value,
|
|
1344
|
+
widgetType
|
|
1345
|
+
};
|
|
1346
|
+
return value;
|
|
1347
|
+
}
|
|
1348
|
+
function normalizeContainer(value) {
|
|
1349
|
+
return normalizeWidgetRuntimeContainer(value);
|
|
1350
|
+
}
|
|
1351
|
+
function normalizeResizable(value) {
|
|
1352
|
+
return normalizeWidgetRuntimeResizable(value);
|
|
1353
|
+
}
|
|
1354
|
+
function normalizeRuntimeAssetUrl(url, baseUrl, assetOriginPolicy) {
|
|
1355
|
+
if (hasUnsafeRawRuntimeAssetUrlSyntax(url)) return {
|
|
1356
|
+
ok: false,
|
|
1357
|
+
failure: {
|
|
1358
|
+
inputUrl: url,
|
|
1359
|
+
reason: "invalid-url"
|
|
1360
|
+
}
|
|
1361
|
+
};
|
|
1362
|
+
try {
|
|
1363
|
+
const parsedUrl = new URL(url, baseUrl);
|
|
1364
|
+
if (parsedUrl.protocol !== "http:" && parsedUrl.protocol !== "https:") return {
|
|
1365
|
+
ok: false,
|
|
1366
|
+
failure: {
|
|
1367
|
+
inputUrl: url,
|
|
1368
|
+
resolvedUrl: parsedUrl.href,
|
|
1369
|
+
reason: "unsupported-protocol"
|
|
1370
|
+
}
|
|
1371
|
+
};
|
|
1372
|
+
if (assetOriginPolicy.allowedOrigins.has(parsedUrl.origin)) return {
|
|
1373
|
+
ok: true,
|
|
1374
|
+
url: parsedUrl.href
|
|
1375
|
+
};
|
|
1376
|
+
if (assetOriginPolicy.allowSharedWidgetArtifactBucket && parsedUrl.href.startsWith("https://storage.googleapis.com/portal-widgets/")) return {
|
|
1377
|
+
ok: true,
|
|
1378
|
+
url: parsedUrl.href
|
|
1379
|
+
};
|
|
1380
|
+
return {
|
|
1381
|
+
ok: false,
|
|
1382
|
+
failure: {
|
|
1383
|
+
inputUrl: url,
|
|
1384
|
+
resolvedUrl: parsedUrl.href,
|
|
1385
|
+
reason: "untrusted-origin"
|
|
1386
|
+
}
|
|
1387
|
+
};
|
|
1388
|
+
} catch {
|
|
1389
|
+
return {
|
|
1390
|
+
ok: false,
|
|
1391
|
+
failure: {
|
|
1392
|
+
inputUrl: url,
|
|
1393
|
+
reason: "invalid-url"
|
|
1394
|
+
}
|
|
1395
|
+
};
|
|
1396
|
+
}
|
|
1397
|
+
}
|
|
1398
|
+
function warnRejectedWidgetPackageDescriptor(descriptor, assetField, failure, descriptorEndpointUrl) {
|
|
1399
|
+
console.warn(`[portal] Dropping widget package descriptor ${descriptor.packageId}@${descriptor.version} from ${descriptorEndpointUrl.href}: ${assetField} "${failure.inputUrl}" ${formatRuntimeAssetUrlFailure(failure)}.`);
|
|
1400
|
+
}
|
|
1401
|
+
function warnRejectedMalformedWidgetPackageEntry(entry, reason, descriptorEndpointUrl) {
|
|
1402
|
+
console.warn(`[portal] Dropping widget package catalog entry ${formatWidgetPackageEntryIdentity(entry)} from ${descriptorEndpointUrl.href}: ${reason}.`);
|
|
1403
|
+
}
|
|
1404
|
+
function formatWidgetPackageEntryIdentity(entry) {
|
|
1405
|
+
if (!isRecord(entry)) return "<unknown>";
|
|
1406
|
+
const packageId = readNonEmptyString(entry.packageId);
|
|
1407
|
+
const version = readNonEmptyString(entry.version);
|
|
1408
|
+
if (packageId && version) return `${packageId}@${version}`;
|
|
1409
|
+
if (packageId) return packageId;
|
|
1410
|
+
return "<unknown>";
|
|
1411
|
+
}
|
|
1412
|
+
function formatRuntimeAssetUrlFailure(failure) {
|
|
1413
|
+
const resolvedUrl = failure.resolvedUrl ? ` (resolved as ${failure.resolvedUrl})` : "";
|
|
1414
|
+
switch (failure.reason) {
|
|
1415
|
+
case "invalid-url": return "is not a valid URL";
|
|
1416
|
+
case "unsupported-protocol": return `uses an unsupported protocol${resolvedUrl}`;
|
|
1417
|
+
case "untrusted-origin": return `resolved to an untrusted origin${resolvedUrl}`;
|
|
1418
|
+
}
|
|
1419
|
+
}
|
|
1420
|
+
function createRuntimeAssetOriginPolicy(descriptorEndpointUrl, allowedOrigins, trustCatalogAssetOrigins) {
|
|
1421
|
+
const origins = /* @__PURE__ */ new Set();
|
|
1422
|
+
if (!trustCatalogAssetOrigins) origins.add(descriptorEndpointUrl.origin);
|
|
1423
|
+
for (const origin of allowedOrigins) {
|
|
1424
|
+
const normalizedOrigin = normalizeAllowedOrigin(origin);
|
|
1425
|
+
if (normalizedOrigin) origins.add(normalizedOrigin);
|
|
1426
|
+
else console.warn(`[portal] Ignoring invalid widget package allowed origin "${origin}". Expected an http(s) absolute URL origin.`);
|
|
1427
|
+
}
|
|
1428
|
+
return {
|
|
1429
|
+
allowSharedWidgetArtifactBucket: trustCatalogAssetOrigins,
|
|
1430
|
+
allowedOrigins: origins
|
|
1431
|
+
};
|
|
1432
|
+
}
|
|
1433
|
+
function hasUnsafeRawRuntimeAssetUrlSyntax(url) {
|
|
1434
|
+
return url.trim() !== url || hasControlCharacter(url) || url.includes("\\") || url.startsWith("//") || hasAmbiguousHttpScheme(url);
|
|
1435
|
+
}
|
|
1436
|
+
function hasAmbiguousHttpScheme(url) {
|
|
1437
|
+
return /^https?:(?!\/\/)/i.test(url);
|
|
1438
|
+
}
|
|
1439
|
+
function normalizeAllowedOrigin(origin) {
|
|
1440
|
+
try {
|
|
1441
|
+
const parsedOrigin = new URL(origin);
|
|
1442
|
+
if (parsedOrigin.protocol !== "http:" && parsedOrigin.protocol !== "https:") return null;
|
|
1443
|
+
return parsedOrigin.origin;
|
|
1444
|
+
} catch {
|
|
1445
|
+
return null;
|
|
1446
|
+
}
|
|
1447
|
+
}
|
|
1448
|
+
function normalizeDescriptorEndpointUrl(url) {
|
|
1449
|
+
try {
|
|
1450
|
+
return new URL(url, getWindowLocationHref());
|
|
1451
|
+
} catch {
|
|
1452
|
+
return null;
|
|
1453
|
+
}
|
|
1454
|
+
}
|
|
1455
|
+
function getWindowLocationHref() {
|
|
1456
|
+
return typeof window === "undefined" ? void 0 : window.location.href;
|
|
1457
|
+
}
|
|
1458
|
+
function looksLikeWidgetPackageEntry(value) {
|
|
1459
|
+
return value.packageId !== void 0 || value.remoteEntryUrl !== void 0 || value.scriptUrl !== void 0 || value.manifest !== void 0 || value.widgets !== void 0;
|
|
1460
|
+
}
|
|
1461
|
+
function getArrayProperty(value, key) {
|
|
1462
|
+
const property = value[key];
|
|
1463
|
+
return Array.isArray(property) ? property : void 0;
|
|
1464
|
+
}
|
|
1465
|
+
function isRecord(value) {
|
|
1466
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1467
|
+
}
|
|
1468
|
+
//#endregion
|
|
1469
|
+
//#region src/utils/widget-package-utils.ts
|
|
1470
|
+
function resolveHostedWidgetPackageManifestUrl(descriptorEndpointUrl, baseUrl) {
|
|
1471
|
+
try {
|
|
1472
|
+
return new URL(descriptorEndpointUrl, baseUrl).href;
|
|
1473
|
+
} catch {
|
|
1474
|
+
return descriptorEndpointUrl;
|
|
1475
|
+
}
|
|
1476
|
+
}
|
|
1477
|
+
function dedupeWidgetPackagesByPackageIdAndVersion(widgetPackages) {
|
|
1478
|
+
const widgetPackagesByIdAndVersion = /* @__PURE__ */ new Map();
|
|
1479
|
+
for (const widgetPackage of widgetPackages) {
|
|
1480
|
+
const key = JSON.stringify([widgetPackage.packageId, widgetPackage.version]);
|
|
1481
|
+
if (!widgetPackagesByIdAndVersion.has(key)) widgetPackagesByIdAndVersion.set(key, widgetPackage);
|
|
1482
|
+
}
|
|
1483
|
+
return Array.from(widgetPackagesByIdAndVersion.values());
|
|
1484
|
+
}
|
|
1485
|
+
//#endregion
|
|
1486
|
+
Object.defineProperty(exports, "DEFAULT_WIDGET_PACKAGE_MANIFEST_URL", {
|
|
1487
|
+
enumerable: true,
|
|
1488
|
+
get: function() {
|
|
1489
|
+
return DEFAULT_WIDGET_PACKAGE_MANIFEST_URL;
|
|
1490
|
+
}
|
|
1491
|
+
});
|
|
1492
|
+
Object.defineProperty(exports, "buildWidgetRegistry", {
|
|
1493
|
+
enumerable: true,
|
|
1494
|
+
get: function() {
|
|
1495
|
+
return buildWidgetRegistry;
|
|
1496
|
+
}
|
|
1497
|
+
});
|
|
1498
|
+
Object.defineProperty(exports, "createDefaultFluidConfig", {
|
|
1499
|
+
enumerable: true,
|
|
1500
|
+
get: function() {
|
|
1501
|
+
return createDefaultFluidConfig;
|
|
1502
|
+
}
|
|
1503
|
+
});
|
|
1504
|
+
Object.defineProperty(exports, "dedupeWidgetPackagesByPackageIdAndVersion", {
|
|
1505
|
+
enumerable: true,
|
|
1506
|
+
get: function() {
|
|
1507
|
+
return dedupeWidgetPackagesByPackageIdAndVersion;
|
|
1508
|
+
}
|
|
1509
|
+
});
|
|
1510
|
+
Object.defineProperty(exports, "fetchWidgetPackageDescriptors", {
|
|
1511
|
+
enumerable: true,
|
|
1512
|
+
get: function() {
|
|
1513
|
+
return fetchWidgetPackageDescriptors;
|
|
1514
|
+
}
|
|
1515
|
+
});
|
|
1516
|
+
Object.defineProperty(exports, "getDefaultWidgetPackageManifestUrl", {
|
|
1517
|
+
enumerable: true,
|
|
1518
|
+
get: function() {
|
|
1519
|
+
return getDefaultWidgetPackageManifestUrl;
|
|
1520
|
+
}
|
|
1521
|
+
});
|
|
1522
|
+
Object.defineProperty(exports, "installAndReadFluidWidgetsRegistry", {
|
|
1523
|
+
enumerable: true,
|
|
1524
|
+
get: function() {
|
|
1525
|
+
return installAndReadFluidWidgetsRegistry;
|
|
1526
|
+
}
|
|
1527
|
+
});
|
|
1528
|
+
Object.defineProperty(exports, "loadWidgetPackages", {
|
|
1529
|
+
enumerable: true,
|
|
1530
|
+
get: function() {
|
|
1531
|
+
return loadWidgetPackages;
|
|
1532
|
+
}
|
|
1533
|
+
});
|
|
1534
|
+
Object.defineProperty(exports, "mergeRegisteredWidgetsIntoRegistry", {
|
|
1535
|
+
enumerable: true,
|
|
1536
|
+
get: function() {
|
|
1537
|
+
return mergeRegisteredWidgetsIntoRegistry;
|
|
1538
|
+
}
|
|
1539
|
+
});
|
|
1540
|
+
Object.defineProperty(exports, "resolveHostedWidgetPackageManifestUrl", {
|
|
1541
|
+
enumerable: true,
|
|
1542
|
+
get: function() {
|
|
1543
|
+
return resolveHostedWidgetPackageManifestUrl;
|
|
1544
|
+
}
|
|
1545
|
+
});
|
|
1546
|
+
Object.defineProperty(exports, "subscribeToFluidWidgetsRegistry", {
|
|
1547
|
+
enumerable: true,
|
|
1548
|
+
get: function() {
|
|
1549
|
+
return subscribeToFluidWidgetsRegistry;
|
|
1550
|
+
}
|
|
1551
|
+
});
|
|
1552
|
+
|
|
1553
|
+
//# sourceMappingURL=widget-package-utils-BWn56ZFw.cjs.map
|