@servlyadmin/runtime-core 0.1.0 → 0.1.2
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/chunk-CIUQK4GA.js +182 -0
- package/dist/index.cjs +637 -149
- package/dist/index.d.cts +198 -5
- package/dist/index.d.ts +198 -5
- package/dist/index.js +441 -149
- package/dist/registry-GCCVK65D.js +16 -0
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -1,3 +1,12 @@
|
|
|
1
|
+
import {
|
|
2
|
+
buildRegistryFromBundle,
|
|
3
|
+
collectAllDependencies,
|
|
4
|
+
createRegistry,
|
|
5
|
+
detectCircularDependencies,
|
|
6
|
+
extractDependencies,
|
|
7
|
+
extractDependenciesFromCode
|
|
8
|
+
} from "./chunk-CIUQK4GA.js";
|
|
9
|
+
|
|
1
10
|
// src/bindings.ts
|
|
2
11
|
var BINDING_SOURCES = [
|
|
3
12
|
"props",
|
|
@@ -294,17 +303,39 @@ function applyStyles(element, styles) {
|
|
|
294
303
|
}
|
|
295
304
|
}
|
|
296
305
|
}
|
|
306
|
+
var CANVAS_ONLY_STYLES = /* @__PURE__ */ new Set([
|
|
307
|
+
"transform",
|
|
308
|
+
"--translate-x",
|
|
309
|
+
"--translate-y",
|
|
310
|
+
"--width",
|
|
311
|
+
"--height",
|
|
312
|
+
"z-index",
|
|
313
|
+
"zIndex"
|
|
314
|
+
]);
|
|
315
|
+
function filterCanvasStyles(style) {
|
|
316
|
+
const filtered = {};
|
|
317
|
+
for (const [key, value] of Object.entries(style)) {
|
|
318
|
+
if (CANVAS_ONLY_STYLES.has(key)) {
|
|
319
|
+
continue;
|
|
320
|
+
}
|
|
321
|
+
if (key === "transform" && typeof value === "string" && value.includes("translate(")) {
|
|
322
|
+
continue;
|
|
323
|
+
}
|
|
324
|
+
filtered[key] = value;
|
|
325
|
+
}
|
|
326
|
+
return filtered;
|
|
327
|
+
}
|
|
297
328
|
function buildElementStyles(element, context) {
|
|
298
329
|
const config = element.configuration || {};
|
|
299
330
|
const combined = {};
|
|
300
331
|
if (element.style) {
|
|
301
|
-
Object.assign(combined, element.style);
|
|
332
|
+
Object.assign(combined, filterCanvasStyles(element.style));
|
|
302
333
|
}
|
|
303
334
|
if (config.style) {
|
|
304
|
-
Object.assign(combined, config.style);
|
|
335
|
+
Object.assign(combined, filterCanvasStyles(config.style));
|
|
305
336
|
}
|
|
306
337
|
if (config.cssVariables) {
|
|
307
|
-
Object.assign(combined, config.cssVariables);
|
|
338
|
+
Object.assign(combined, filterCanvasStyles(config.cssVariables));
|
|
308
339
|
}
|
|
309
340
|
return processStyles(combined, context);
|
|
310
341
|
}
|
|
@@ -527,18 +558,84 @@ function createElement(element, context, eventHandlers) {
|
|
|
527
558
|
attachEventHandlers(domElement, element.i, eventHandlers, elementState);
|
|
528
559
|
return elementState;
|
|
529
560
|
}
|
|
530
|
-
|
|
561
|
+
var globalRenderingStack = /* @__PURE__ */ new Set();
|
|
562
|
+
function renderComponentRef(element, container, context, state) {
|
|
563
|
+
const config = element.configuration;
|
|
564
|
+
if (!config?.componentViewRef) return void 0;
|
|
565
|
+
const refId = config.componentViewRef;
|
|
566
|
+
const refVersion = config.componentViewVersion;
|
|
567
|
+
if (globalRenderingStack.has(refId)) {
|
|
568
|
+
console.warn(`Circular dependency detected: ${refId} is already being rendered`);
|
|
569
|
+
const placeholder = document.createElement("div");
|
|
570
|
+
placeholder.setAttribute("data-servly-circular", refId);
|
|
571
|
+
placeholder.textContent = `[Circular: ${refId}]`;
|
|
572
|
+
container.appendChild(placeholder);
|
|
573
|
+
return void 0;
|
|
574
|
+
}
|
|
575
|
+
let component;
|
|
576
|
+
if (state.componentRegistry) {
|
|
577
|
+
component = state.componentRegistry.get(refId, refVersion);
|
|
578
|
+
}
|
|
579
|
+
if (!component) {
|
|
580
|
+
const placeholder = document.createElement("div");
|
|
581
|
+
placeholder.setAttribute("data-servly-loading", refId);
|
|
582
|
+
placeholder.className = "servly-loading";
|
|
583
|
+
container.appendChild(placeholder);
|
|
584
|
+
if (state.onDependencyNeeded) {
|
|
585
|
+
state.onDependencyNeeded(refId, refVersion).then((loaded) => {
|
|
586
|
+
if (loaded && state.componentRegistry) {
|
|
587
|
+
state.componentRegistry.set(refId, refVersion || "latest", loaded);
|
|
588
|
+
container.innerHTML = "";
|
|
589
|
+
renderComponentRef(element, container, context, state);
|
|
590
|
+
}
|
|
591
|
+
}).catch((err) => {
|
|
592
|
+
console.error(`Failed to load dependency ${refId}:`, err);
|
|
593
|
+
placeholder.textContent = `[Failed to load: ${refId}]`;
|
|
594
|
+
placeholder.className = "servly-error";
|
|
595
|
+
});
|
|
596
|
+
}
|
|
597
|
+
return void 0;
|
|
598
|
+
}
|
|
599
|
+
const refProps = config.componentViewProps ? resolveTemplatesDeep(config.componentViewProps, context) : {};
|
|
600
|
+
globalRenderingStack.add(refId);
|
|
601
|
+
const refContext = {
|
|
602
|
+
props: refProps,
|
|
603
|
+
state: context.state,
|
|
604
|
+
context: context.context
|
|
605
|
+
};
|
|
606
|
+
try {
|
|
607
|
+
const result = render({
|
|
608
|
+
container,
|
|
609
|
+
elements: component.layout,
|
|
610
|
+
context: refContext,
|
|
611
|
+
componentRegistry: state.componentRegistry,
|
|
612
|
+
onDependencyNeeded: state.onDependencyNeeded
|
|
613
|
+
});
|
|
614
|
+
return result;
|
|
615
|
+
} finally {
|
|
616
|
+
globalRenderingStack.delete(refId);
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
function renderElement(element, tree, context, eventHandlers, elementStates, state) {
|
|
531
620
|
const elementState = createElement(element, context, eventHandlers);
|
|
532
621
|
elementStates.set(element.i, elementState);
|
|
622
|
+
const config = element.configuration;
|
|
623
|
+
if (config?.componentViewRef) {
|
|
624
|
+
const nestedResult = renderComponentRef(element, elementState.domElement, context, state);
|
|
625
|
+
if (nestedResult) {
|
|
626
|
+
elementState.nestedRender = nestedResult;
|
|
627
|
+
}
|
|
628
|
+
return elementState.domElement;
|
|
629
|
+
}
|
|
533
630
|
const children = tree.get(element.i) || [];
|
|
534
631
|
for (const child of children) {
|
|
535
|
-
const childElement = renderElement(child, tree, context, eventHandlers, elementStates);
|
|
632
|
+
const childElement = renderElement(child, tree, context, eventHandlers, elementStates, state);
|
|
536
633
|
elementState.domElement.appendChild(childElement);
|
|
537
634
|
}
|
|
538
635
|
return elementState.domElement;
|
|
539
636
|
}
|
|
540
637
|
function render(options) {
|
|
541
|
-
const { container, elements, context, eventHandlers } = options;
|
|
638
|
+
const { container, elements, context, eventHandlers, componentRegistry, onDependencyNeeded } = options;
|
|
542
639
|
const tree = buildTree(elements);
|
|
543
640
|
const rootElements = elements.filter((el) => !el.parent || el.parent === null);
|
|
544
641
|
const state = {
|
|
@@ -547,7 +644,10 @@ function render(options) {
|
|
|
547
644
|
context,
|
|
548
645
|
eventHandlers,
|
|
549
646
|
elementStates: /* @__PURE__ */ new Map(),
|
|
550
|
-
rootElement: null
|
|
647
|
+
rootElement: null,
|
|
648
|
+
componentRegistry,
|
|
649
|
+
onDependencyNeeded,
|
|
650
|
+
renderingStack: /* @__PURE__ */ new Set()
|
|
551
651
|
};
|
|
552
652
|
container.innerHTML = "";
|
|
553
653
|
if (rootElements.length === 0) {
|
|
@@ -563,14 +663,15 @@ function render(options) {
|
|
|
563
663
|
tree,
|
|
564
664
|
context,
|
|
565
665
|
eventHandlers,
|
|
566
|
-
state.elementStates
|
|
666
|
+
state.elementStates,
|
|
667
|
+
state
|
|
567
668
|
);
|
|
568
669
|
container.appendChild(state.rootElement);
|
|
569
670
|
} else {
|
|
570
671
|
const wrapper = document.createElement("div");
|
|
571
672
|
wrapper.setAttribute("data-servly-wrapper", "true");
|
|
572
673
|
for (const root of rootElements) {
|
|
573
|
-
const rootElement = renderElement(root, tree, context, eventHandlers, state.elementStates);
|
|
674
|
+
const rootElement = renderElement(root, tree, context, eventHandlers, state.elementStates, state);
|
|
574
675
|
wrapper.appendChild(rootElement);
|
|
575
676
|
}
|
|
576
677
|
state.rootElement = wrapper;
|
|
@@ -608,6 +709,9 @@ function update(state, newContext) {
|
|
|
608
709
|
function destroy(state) {
|
|
609
710
|
for (const elementState of state.elementStates.values()) {
|
|
610
711
|
detachEventHandlers(elementState);
|
|
712
|
+
if (elementState.nestedRender) {
|
|
713
|
+
elementState.nestedRender.destroy();
|
|
714
|
+
}
|
|
611
715
|
}
|
|
612
716
|
state.elementStates.clear();
|
|
613
717
|
if (state.rootElement && state.rootElement.parentNode) {
|
|
@@ -615,6 +719,66 @@ function destroy(state) {
|
|
|
615
719
|
}
|
|
616
720
|
state.rootElement = null;
|
|
617
721
|
}
|
|
722
|
+
function renderDynamicList(options) {
|
|
723
|
+
const {
|
|
724
|
+
targetContainer,
|
|
725
|
+
blueprint,
|
|
726
|
+
blueprintVersion,
|
|
727
|
+
data,
|
|
728
|
+
renderType = "renderInto",
|
|
729
|
+
itemKey = "item",
|
|
730
|
+
indexKey = "index",
|
|
731
|
+
componentRegistry,
|
|
732
|
+
context = { props: {} }
|
|
733
|
+
} = options;
|
|
734
|
+
let container;
|
|
735
|
+
if (typeof targetContainer === "string") {
|
|
736
|
+
container = document.querySelector(targetContainer);
|
|
737
|
+
} else {
|
|
738
|
+
container = targetContainer;
|
|
739
|
+
}
|
|
740
|
+
if (!container) {
|
|
741
|
+
console.error(`renderDynamicList: Container not found: ${targetContainer}`);
|
|
742
|
+
return [];
|
|
743
|
+
}
|
|
744
|
+
const blueprintComponent = componentRegistry.get(blueprint, blueprintVersion);
|
|
745
|
+
if (!blueprintComponent) {
|
|
746
|
+
console.error(`renderDynamicList: Blueprint not found: ${blueprint}`);
|
|
747
|
+
return [];
|
|
748
|
+
}
|
|
749
|
+
if (renderType === "renderInto") {
|
|
750
|
+
container.innerHTML = "";
|
|
751
|
+
}
|
|
752
|
+
const results = [];
|
|
753
|
+
const fragment = document.createDocumentFragment();
|
|
754
|
+
data.forEach((item, index) => {
|
|
755
|
+
const itemContainer = document.createElement("div");
|
|
756
|
+
itemContainer.setAttribute("data-servly-list-item", String(index));
|
|
757
|
+
const itemContext = {
|
|
758
|
+
props: {
|
|
759
|
+
...context.props,
|
|
760
|
+
[itemKey]: item,
|
|
761
|
+
[indexKey]: index
|
|
762
|
+
},
|
|
763
|
+
state: context.state,
|
|
764
|
+
context: context.context
|
|
765
|
+
};
|
|
766
|
+
const result = render({
|
|
767
|
+
container: itemContainer,
|
|
768
|
+
elements: blueprintComponent.layout,
|
|
769
|
+
context: itemContext,
|
|
770
|
+
componentRegistry
|
|
771
|
+
});
|
|
772
|
+
results.push(result);
|
|
773
|
+
fragment.appendChild(itemContainer);
|
|
774
|
+
});
|
|
775
|
+
if (renderType === "prepend") {
|
|
776
|
+
container.insertBefore(fragment, container.firstChild);
|
|
777
|
+
} else {
|
|
778
|
+
container.appendChild(fragment);
|
|
779
|
+
}
|
|
780
|
+
return results;
|
|
781
|
+
}
|
|
618
782
|
|
|
619
783
|
// src/cache.ts
|
|
620
784
|
var DEFAULT_CACHE_CONFIG = {
|
|
@@ -860,118 +1024,6 @@ function invalidateCache(id, version, config = DEFAULT_CACHE_CONFIG) {
|
|
|
860
1024
|
}
|
|
861
1025
|
}
|
|
862
1026
|
|
|
863
|
-
// src/version.ts
|
|
864
|
-
function parseVersion(version) {
|
|
865
|
-
const match = version.match(/^(\d+)\.(\d+)\.(\d+)$/);
|
|
866
|
-
if (!match) return null;
|
|
867
|
-
return {
|
|
868
|
-
major: parseInt(match[1], 10),
|
|
869
|
-
minor: parseInt(match[2], 10),
|
|
870
|
-
patch: parseInt(match[3], 10)
|
|
871
|
-
};
|
|
872
|
-
}
|
|
873
|
-
function compareVersions(a, b) {
|
|
874
|
-
const parsedA = parseVersion(a);
|
|
875
|
-
const parsedB = parseVersion(b);
|
|
876
|
-
if (!parsedA || !parsedB) return 0;
|
|
877
|
-
if (parsedA.major !== parsedB.major) {
|
|
878
|
-
return parsedA.major > parsedB.major ? 1 : -1;
|
|
879
|
-
}
|
|
880
|
-
if (parsedA.minor !== parsedB.minor) {
|
|
881
|
-
return parsedA.minor > parsedB.minor ? 1 : -1;
|
|
882
|
-
}
|
|
883
|
-
if (parsedA.patch !== parsedB.patch) {
|
|
884
|
-
return parsedA.patch > parsedB.patch ? 1 : -1;
|
|
885
|
-
}
|
|
886
|
-
return 0;
|
|
887
|
-
}
|
|
888
|
-
function satisfiesVersion(version, specifier) {
|
|
889
|
-
if (specifier === "latest" || specifier === "*") {
|
|
890
|
-
return true;
|
|
891
|
-
}
|
|
892
|
-
const parsed = parseVersion(version);
|
|
893
|
-
if (!parsed) return false;
|
|
894
|
-
if (/^\d+\.\d+\.\d+$/.test(specifier)) {
|
|
895
|
-
return version === specifier;
|
|
896
|
-
}
|
|
897
|
-
if (specifier.startsWith("^")) {
|
|
898
|
-
const specParsed = parseVersion(specifier.slice(1));
|
|
899
|
-
if (!specParsed) return false;
|
|
900
|
-
if (parsed.major !== specParsed.major) return false;
|
|
901
|
-
if (parsed.major === 0) {
|
|
902
|
-
return parsed.minor === specParsed.minor && parsed.patch >= specParsed.patch;
|
|
903
|
-
}
|
|
904
|
-
return compareVersions(version, specifier.slice(1)) >= 0;
|
|
905
|
-
}
|
|
906
|
-
if (specifier.startsWith("~")) {
|
|
907
|
-
const specParsed = parseVersion(specifier.slice(1));
|
|
908
|
-
if (!specParsed) return false;
|
|
909
|
-
return parsed.major === specParsed.major && parsed.minor === specParsed.minor && parsed.patch >= specParsed.patch;
|
|
910
|
-
}
|
|
911
|
-
if (specifier.startsWith(">=")) {
|
|
912
|
-
return compareVersions(version, specifier.slice(2)) >= 0;
|
|
913
|
-
}
|
|
914
|
-
if (specifier.startsWith(">")) {
|
|
915
|
-
return compareVersions(version, specifier.slice(1)) > 0;
|
|
916
|
-
}
|
|
917
|
-
if (specifier.startsWith("<=")) {
|
|
918
|
-
return compareVersions(version, specifier.slice(2)) <= 0;
|
|
919
|
-
}
|
|
920
|
-
if (specifier.startsWith("<")) {
|
|
921
|
-
return compareVersions(version, specifier.slice(1)) < 0;
|
|
922
|
-
}
|
|
923
|
-
return false;
|
|
924
|
-
}
|
|
925
|
-
function resolveVersion(versions, specifier = "latest") {
|
|
926
|
-
if (versions.length === 0) {
|
|
927
|
-
return null;
|
|
928
|
-
}
|
|
929
|
-
const sorted = [...versions].sort((a, b) => compareVersions(b, a));
|
|
930
|
-
if (specifier === "latest" || specifier === "*") {
|
|
931
|
-
return sorted[0];
|
|
932
|
-
}
|
|
933
|
-
if (/^\d+\.\d+\.\d+$/.test(specifier)) {
|
|
934
|
-
return versions.includes(specifier) ? specifier : null;
|
|
935
|
-
}
|
|
936
|
-
for (const version of sorted) {
|
|
937
|
-
if (satisfiesVersion(version, specifier)) {
|
|
938
|
-
return version;
|
|
939
|
-
}
|
|
940
|
-
}
|
|
941
|
-
return null;
|
|
942
|
-
}
|
|
943
|
-
function bumpVersion(currentVersion, bumpType) {
|
|
944
|
-
const parsed = parseVersion(currentVersion);
|
|
945
|
-
if (!parsed) return "1.0.0";
|
|
946
|
-
switch (bumpType) {
|
|
947
|
-
case "major":
|
|
948
|
-
return `${parsed.major + 1}.0.0`;
|
|
949
|
-
case "minor":
|
|
950
|
-
return `${parsed.major}.${parsed.minor + 1}.0`;
|
|
951
|
-
case "patch":
|
|
952
|
-
return `${parsed.major}.${parsed.minor}.${parsed.patch + 1}`;
|
|
953
|
-
default:
|
|
954
|
-
return currentVersion;
|
|
955
|
-
}
|
|
956
|
-
}
|
|
957
|
-
function isValidSpecifier(specifier) {
|
|
958
|
-
if (specifier === "latest" || specifier === "*") {
|
|
959
|
-
return true;
|
|
960
|
-
}
|
|
961
|
-
if (/^\d+\.\d+\.\d+$/.test(specifier)) {
|
|
962
|
-
return true;
|
|
963
|
-
}
|
|
964
|
-
if (/^[\^~><]=?\d+\.\d+\.\d+$/.test(specifier)) {
|
|
965
|
-
return true;
|
|
966
|
-
}
|
|
967
|
-
return false;
|
|
968
|
-
}
|
|
969
|
-
function formatVersion(version) {
|
|
970
|
-
const parsed = parseVersion(version);
|
|
971
|
-
if (!parsed) return version;
|
|
972
|
-
return `v${parsed.major}.${parsed.minor}.${parsed.patch}`;
|
|
973
|
-
}
|
|
974
|
-
|
|
975
1027
|
// src/fetcher.ts
|
|
976
1028
|
var DEFAULT_RETRY_CONFIG = {
|
|
977
1029
|
maxRetries: 3,
|
|
@@ -979,7 +1031,7 @@ var DEFAULT_RETRY_CONFIG = {
|
|
|
979
1031
|
maxDelay: 1e4,
|
|
980
1032
|
backoffMultiplier: 2
|
|
981
1033
|
};
|
|
982
|
-
var registryBaseUrl = "/api/
|
|
1034
|
+
var registryBaseUrl = "/api/views/registry";
|
|
983
1035
|
function setRegistryUrl(url) {
|
|
984
1036
|
registryBaseUrl = url;
|
|
985
1037
|
}
|
|
@@ -1013,19 +1065,15 @@ async function resolveVersionFromApi(id, specifier, apiKey) {
|
|
|
1013
1065
|
}
|
|
1014
1066
|
try {
|
|
1015
1067
|
const response = await fetch(
|
|
1016
|
-
`${baseUrl}/${id}/
|
|
1068
|
+
`${baseUrl}/${id}/resolve?specifier=${encodeURIComponent(specifier)}`,
|
|
1017
1069
|
{ headers }
|
|
1018
1070
|
);
|
|
1019
1071
|
if (!response.ok) {
|
|
1020
1072
|
throw new Error(`Failed to resolve version: ${response.statusText}`);
|
|
1021
1073
|
}
|
|
1022
1074
|
const data = await response.json();
|
|
1023
|
-
if (data.success && data.data?.
|
|
1024
|
-
return data.data.
|
|
1025
|
-
}
|
|
1026
|
-
if (data.data?.versions) {
|
|
1027
|
-
const resolved = resolveVersion(data.data.versions, specifier);
|
|
1028
|
-
if (resolved) return resolved;
|
|
1075
|
+
if (data.success && data.data?.resolved) {
|
|
1076
|
+
return data.data.resolved;
|
|
1029
1077
|
}
|
|
1030
1078
|
throw new Error(data.error || "Failed to resolve version");
|
|
1031
1079
|
} catch (error) {
|
|
@@ -1033,7 +1081,7 @@ async function resolveVersionFromApi(id, specifier, apiKey) {
|
|
|
1033
1081
|
return "latest";
|
|
1034
1082
|
}
|
|
1035
1083
|
}
|
|
1036
|
-
async function fetchFromRegistry(id, version, apiKey) {
|
|
1084
|
+
async function fetchFromRegistry(id, version, apiKey, includeBundle) {
|
|
1037
1085
|
const baseUrl = getRegistryUrl();
|
|
1038
1086
|
const headers = {
|
|
1039
1087
|
"Content-Type": "application/json"
|
|
@@ -1041,25 +1089,39 @@ async function fetchFromRegistry(id, version, apiKey) {
|
|
|
1041
1089
|
if (apiKey) {
|
|
1042
1090
|
headers["Authorization"] = `Bearer ${apiKey}`;
|
|
1043
1091
|
}
|
|
1044
|
-
|
|
1092
|
+
let url;
|
|
1093
|
+
if (version && version !== "latest" && /^\d+\.\d+\.\d+/.test(version)) {
|
|
1094
|
+
url = `${baseUrl}/${id}/versions/${version}`;
|
|
1095
|
+
} else if (version && version !== "latest") {
|
|
1096
|
+
url = `${baseUrl}/${id}?version=${encodeURIComponent(version)}`;
|
|
1097
|
+
} else {
|
|
1098
|
+
url = `${baseUrl}/${id}`;
|
|
1099
|
+
}
|
|
1100
|
+
if (includeBundle) {
|
|
1101
|
+
url += (url.includes("?") ? "&" : "?") + "bundle=true";
|
|
1102
|
+
}
|
|
1045
1103
|
const response = await fetch(url, { headers });
|
|
1046
1104
|
if (!response.ok) {
|
|
1047
1105
|
if (response.status === 404) {
|
|
1048
|
-
throw new Error(`
|
|
1106
|
+
throw new Error(`View not found: ${id}@${version}`);
|
|
1049
1107
|
}
|
|
1050
1108
|
if (response.status === 401) {
|
|
1051
1109
|
throw new Error("Unauthorized: Invalid or missing API key");
|
|
1052
1110
|
}
|
|
1053
1111
|
if (response.status === 403) {
|
|
1054
|
-
throw new Error("Forbidden: Access denied to this
|
|
1112
|
+
throw new Error("Forbidden: Access denied to this view");
|
|
1055
1113
|
}
|
|
1056
|
-
throw new Error(`Failed to fetch
|
|
1114
|
+
throw new Error(`Failed to fetch view: ${response.statusText}`);
|
|
1057
1115
|
}
|
|
1058
1116
|
const data = await response.json();
|
|
1059
1117
|
if (!data.success || !data.data) {
|
|
1060
|
-
throw new Error(data.error || "Failed to fetch
|
|
1118
|
+
throw new Error(data.error || "Failed to fetch view data");
|
|
1061
1119
|
}
|
|
1062
|
-
|
|
1120
|
+
const result = data.data;
|
|
1121
|
+
if (result.viewId && !result.id) {
|
|
1122
|
+
result.id = result.viewId;
|
|
1123
|
+
}
|
|
1124
|
+
return result;
|
|
1063
1125
|
}
|
|
1064
1126
|
async function fetchComponent(id, options = {}) {
|
|
1065
1127
|
const {
|
|
@@ -1069,7 +1131,9 @@ async function fetchComponent(id, options = {}) {
|
|
|
1069
1131
|
cacheConfig = DEFAULT_CACHE_CONFIG,
|
|
1070
1132
|
retryConfig = {},
|
|
1071
1133
|
forceRefresh = false,
|
|
1072
|
-
signal
|
|
1134
|
+
signal,
|
|
1135
|
+
bundleStrategy = "eager",
|
|
1136
|
+
includeBundle = true
|
|
1073
1137
|
} = options;
|
|
1074
1138
|
const fullRetryConfig = {
|
|
1075
1139
|
...DEFAULT_RETRY_CONFIG,
|
|
@@ -1078,10 +1142,15 @@ async function fetchComponent(id, options = {}) {
|
|
|
1078
1142
|
if (!forceRefresh) {
|
|
1079
1143
|
const cached = getFromCache(id, version, cacheStrategy, cacheConfig);
|
|
1080
1144
|
if (cached) {
|
|
1145
|
+
let registry;
|
|
1146
|
+
if (cached.bundle) {
|
|
1147
|
+
registry = buildRegistryFromBundle(cached);
|
|
1148
|
+
}
|
|
1081
1149
|
return {
|
|
1082
1150
|
data: cached,
|
|
1083
1151
|
fromCache: true,
|
|
1084
|
-
version: cached.version
|
|
1152
|
+
version: cached.version,
|
|
1153
|
+
registry
|
|
1085
1154
|
};
|
|
1086
1155
|
}
|
|
1087
1156
|
}
|
|
@@ -1089,28 +1158,46 @@ async function fetchComponent(id, options = {}) {
|
|
|
1089
1158
|
if (!forceRefresh && resolvedVersion !== version) {
|
|
1090
1159
|
const cached = getFromCache(id, resolvedVersion, cacheStrategy, cacheConfig);
|
|
1091
1160
|
if (cached) {
|
|
1161
|
+
let registry;
|
|
1162
|
+
if (cached.bundle) {
|
|
1163
|
+
registry = buildRegistryFromBundle(cached);
|
|
1164
|
+
}
|
|
1092
1165
|
return {
|
|
1093
1166
|
data: cached,
|
|
1094
1167
|
fromCache: true,
|
|
1095
|
-
version: resolvedVersion
|
|
1168
|
+
version: resolvedVersion,
|
|
1169
|
+
registry
|
|
1096
1170
|
};
|
|
1097
1171
|
}
|
|
1098
1172
|
}
|
|
1099
1173
|
let lastError = null;
|
|
1174
|
+
const shouldIncludeBundle = bundleStrategy !== "none" && includeBundle;
|
|
1100
1175
|
for (let attempt = 0; attempt <= fullRetryConfig.maxRetries; attempt++) {
|
|
1101
1176
|
if (signal?.aborted) {
|
|
1102
1177
|
throw new Error("Fetch aborted");
|
|
1103
1178
|
}
|
|
1104
1179
|
try {
|
|
1105
|
-
const data = await fetchFromRegistry(id, resolvedVersion, apiKey);
|
|
1180
|
+
const data = await fetchFromRegistry(id, resolvedVersion, apiKey, shouldIncludeBundle);
|
|
1106
1181
|
setInCache(id, resolvedVersion, data, cacheStrategy, cacheConfig);
|
|
1107
1182
|
if (version !== resolvedVersion) {
|
|
1108
1183
|
setInCache(id, version, data, cacheStrategy, cacheConfig);
|
|
1109
1184
|
}
|
|
1185
|
+
let registry;
|
|
1186
|
+
let pendingDependencies;
|
|
1187
|
+
if (data.bundle) {
|
|
1188
|
+
registry = buildRegistryFromBundle(data);
|
|
1189
|
+
} else if (data.dependencies && bundleStrategy === "lazy") {
|
|
1190
|
+
pendingDependencies = Object.entries(data.dependencies).map(([depId, entry]) => ({
|
|
1191
|
+
id: depId,
|
|
1192
|
+
version: entry.resolved || entry.version
|
|
1193
|
+
}));
|
|
1194
|
+
}
|
|
1110
1195
|
return {
|
|
1111
1196
|
data,
|
|
1112
1197
|
fromCache: false,
|
|
1113
|
-
version: resolvedVersion
|
|
1198
|
+
version: resolvedVersion,
|
|
1199
|
+
registry,
|
|
1200
|
+
pendingDependencies
|
|
1114
1201
|
};
|
|
1115
1202
|
} catch (error) {
|
|
1116
1203
|
lastError = error instanceof Error ? error : new Error(String(error));
|
|
@@ -1125,10 +1212,60 @@ async function fetchComponent(id, options = {}) {
|
|
|
1125
1212
|
}
|
|
1126
1213
|
throw lastError || new Error("Failed to fetch component");
|
|
1127
1214
|
}
|
|
1215
|
+
async function fetchComponentWithDependencies(id, options = {}) {
|
|
1216
|
+
const result = await fetchComponent(id, { ...options, includeBundle: true });
|
|
1217
|
+
if (result.pendingDependencies && result.pendingDependencies.length > 0) {
|
|
1218
|
+
const { createRegistry: createRegistry2 } = await import("./registry-GCCVK65D.js");
|
|
1219
|
+
const registry = result.registry || createRegistry2();
|
|
1220
|
+
await Promise.all(
|
|
1221
|
+
result.pendingDependencies.map(async (dep) => {
|
|
1222
|
+
try {
|
|
1223
|
+
const depResult = await fetchComponent(dep.id, {
|
|
1224
|
+
...options,
|
|
1225
|
+
version: dep.version,
|
|
1226
|
+
bundleStrategy: "none"
|
|
1227
|
+
// Don't recursively bundle
|
|
1228
|
+
});
|
|
1229
|
+
registry.set(dep.id, depResult.version, {
|
|
1230
|
+
layout: depResult.data.layout,
|
|
1231
|
+
propsInterface: depResult.data.propsInterface
|
|
1232
|
+
});
|
|
1233
|
+
} catch (err) {
|
|
1234
|
+
console.warn(`Failed to fetch dependency ${dep.id}:`, err);
|
|
1235
|
+
}
|
|
1236
|
+
})
|
|
1237
|
+
);
|
|
1238
|
+
result.registry = registry;
|
|
1239
|
+
result.pendingDependencies = void 0;
|
|
1240
|
+
}
|
|
1241
|
+
return result;
|
|
1242
|
+
}
|
|
1243
|
+
async function batchFetchComponents(components, options = {}) {
|
|
1244
|
+
const baseUrl = getRegistryUrl();
|
|
1245
|
+
const headers = {
|
|
1246
|
+
"Content-Type": "application/json"
|
|
1247
|
+
};
|
|
1248
|
+
if (options.apiKey) {
|
|
1249
|
+
headers["Authorization"] = `Bearer ${options.apiKey}`;
|
|
1250
|
+
}
|
|
1251
|
+
const response = await fetch(`${baseUrl}/batch`, {
|
|
1252
|
+
method: "POST",
|
|
1253
|
+
headers,
|
|
1254
|
+
body: JSON.stringify({ components })
|
|
1255
|
+
});
|
|
1256
|
+
if (!response.ok) {
|
|
1257
|
+
throw new Error(`Batch fetch failed: ${response.statusText}`);
|
|
1258
|
+
}
|
|
1259
|
+
const data = await response.json();
|
|
1260
|
+
if (!data.success || !data.data) {
|
|
1261
|
+
throw new Error(data.error || "Batch fetch failed");
|
|
1262
|
+
}
|
|
1263
|
+
return data.data;
|
|
1264
|
+
}
|
|
1128
1265
|
async function prefetchComponents(ids, options = {}) {
|
|
1129
1266
|
const promises = ids.map(
|
|
1130
1267
|
({ id, version }) => fetchComponent(id, { ...options, version }).catch((error) => {
|
|
1131
|
-
console.warn(`Failed to prefetch
|
|
1268
|
+
console.warn(`Failed to prefetch view ${id}:`, error);
|
|
1132
1269
|
})
|
|
1133
1270
|
);
|
|
1134
1271
|
await Promise.all(promises);
|
|
@@ -1137,19 +1274,164 @@ async function isComponentAvailable(id, version = "latest", options = {}) {
|
|
|
1137
1274
|
const { cacheStrategy = "memory", cacheConfig = DEFAULT_CACHE_CONFIG } = options;
|
|
1138
1275
|
const cached = getFromCache(id, version, cacheStrategy, cacheConfig);
|
|
1139
1276
|
if (cached) {
|
|
1140
|
-
return { available: true, cached: true };
|
|
1277
|
+
return { available: true, cached: true, version: cached.version };
|
|
1278
|
+
}
|
|
1279
|
+
const baseUrl = getRegistryUrl();
|
|
1280
|
+
const headers = {
|
|
1281
|
+
"Content-Type": "application/json"
|
|
1282
|
+
};
|
|
1283
|
+
if (options.apiKey) {
|
|
1284
|
+
headers["Authorization"] = `Bearer ${options.apiKey}`;
|
|
1141
1285
|
}
|
|
1142
1286
|
try {
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
}
|
|
1148
|
-
|
|
1287
|
+
const url = version && version !== "latest" ? `${baseUrl}/${id}/available?version=${encodeURIComponent(version)}` : `${baseUrl}/${id}/available`;
|
|
1288
|
+
const response = await fetch(url, { headers });
|
|
1289
|
+
if (!response.ok) {
|
|
1290
|
+
return { available: false, cached: false };
|
|
1291
|
+
}
|
|
1292
|
+
const data = await response.json();
|
|
1293
|
+
if (data.success && data.data) {
|
|
1294
|
+
return data.data;
|
|
1295
|
+
}
|
|
1296
|
+
return { available: false, cached: false };
|
|
1149
1297
|
} catch {
|
|
1150
1298
|
return { available: false, cached: false };
|
|
1151
1299
|
}
|
|
1152
1300
|
}
|
|
1301
|
+
async function getDependencyTree(id, options = {}) {
|
|
1302
|
+
const baseUrl = getRegistryUrl();
|
|
1303
|
+
const headers = {
|
|
1304
|
+
"Content-Type": "application/json"
|
|
1305
|
+
};
|
|
1306
|
+
if (options.apiKey) {
|
|
1307
|
+
headers["Authorization"] = `Bearer ${options.apiKey}`;
|
|
1308
|
+
}
|
|
1309
|
+
const params = new URLSearchParams();
|
|
1310
|
+
if (options.version) params.set("version", options.version);
|
|
1311
|
+
if (options.depth) params.set("depth", String(options.depth));
|
|
1312
|
+
const url = `${baseUrl}/${id}/dependencies${params.toString() ? "?" + params.toString() : ""}`;
|
|
1313
|
+
const response = await fetch(url, { headers });
|
|
1314
|
+
if (!response.ok) {
|
|
1315
|
+
throw new Error(`Failed to get dependency tree: ${response.statusText}`);
|
|
1316
|
+
}
|
|
1317
|
+
const data = await response.json();
|
|
1318
|
+
if (!data.success || !data.data) {
|
|
1319
|
+
throw new Error(data.error || "Failed to get dependency tree");
|
|
1320
|
+
}
|
|
1321
|
+
return data.data;
|
|
1322
|
+
}
|
|
1323
|
+
|
|
1324
|
+
// src/version.ts
|
|
1325
|
+
function parseVersion(version) {
|
|
1326
|
+
const match = version.match(/^(\d+)\.(\d+)\.(\d+)$/);
|
|
1327
|
+
if (!match) return null;
|
|
1328
|
+
return {
|
|
1329
|
+
major: parseInt(match[1], 10),
|
|
1330
|
+
minor: parseInt(match[2], 10),
|
|
1331
|
+
patch: parseInt(match[3], 10)
|
|
1332
|
+
};
|
|
1333
|
+
}
|
|
1334
|
+
function compareVersions(a, b) {
|
|
1335
|
+
const parsedA = parseVersion(a);
|
|
1336
|
+
const parsedB = parseVersion(b);
|
|
1337
|
+
if (!parsedA || !parsedB) return 0;
|
|
1338
|
+
if (parsedA.major !== parsedB.major) {
|
|
1339
|
+
return parsedA.major > parsedB.major ? 1 : -1;
|
|
1340
|
+
}
|
|
1341
|
+
if (parsedA.minor !== parsedB.minor) {
|
|
1342
|
+
return parsedA.minor > parsedB.minor ? 1 : -1;
|
|
1343
|
+
}
|
|
1344
|
+
if (parsedA.patch !== parsedB.patch) {
|
|
1345
|
+
return parsedA.patch > parsedB.patch ? 1 : -1;
|
|
1346
|
+
}
|
|
1347
|
+
return 0;
|
|
1348
|
+
}
|
|
1349
|
+
function satisfiesVersion(version, specifier) {
|
|
1350
|
+
if (specifier === "latest" || specifier === "*") {
|
|
1351
|
+
return true;
|
|
1352
|
+
}
|
|
1353
|
+
const parsed = parseVersion(version);
|
|
1354
|
+
if (!parsed) return false;
|
|
1355
|
+
if (/^\d+\.\d+\.\d+$/.test(specifier)) {
|
|
1356
|
+
return version === specifier;
|
|
1357
|
+
}
|
|
1358
|
+
if (specifier.startsWith("^")) {
|
|
1359
|
+
const specParsed = parseVersion(specifier.slice(1));
|
|
1360
|
+
if (!specParsed) return false;
|
|
1361
|
+
if (parsed.major !== specParsed.major) return false;
|
|
1362
|
+
if (parsed.major === 0) {
|
|
1363
|
+
return parsed.minor === specParsed.minor && parsed.patch >= specParsed.patch;
|
|
1364
|
+
}
|
|
1365
|
+
return compareVersions(version, specifier.slice(1)) >= 0;
|
|
1366
|
+
}
|
|
1367
|
+
if (specifier.startsWith("~")) {
|
|
1368
|
+
const specParsed = parseVersion(specifier.slice(1));
|
|
1369
|
+
if (!specParsed) return false;
|
|
1370
|
+
return parsed.major === specParsed.major && parsed.minor === specParsed.minor && parsed.patch >= specParsed.patch;
|
|
1371
|
+
}
|
|
1372
|
+
if (specifier.startsWith(">=")) {
|
|
1373
|
+
return compareVersions(version, specifier.slice(2)) >= 0;
|
|
1374
|
+
}
|
|
1375
|
+
if (specifier.startsWith(">")) {
|
|
1376
|
+
return compareVersions(version, specifier.slice(1)) > 0;
|
|
1377
|
+
}
|
|
1378
|
+
if (specifier.startsWith("<=")) {
|
|
1379
|
+
return compareVersions(version, specifier.slice(2)) <= 0;
|
|
1380
|
+
}
|
|
1381
|
+
if (specifier.startsWith("<")) {
|
|
1382
|
+
return compareVersions(version, specifier.slice(1)) < 0;
|
|
1383
|
+
}
|
|
1384
|
+
return false;
|
|
1385
|
+
}
|
|
1386
|
+
function resolveVersion(versions, specifier = "latest") {
|
|
1387
|
+
if (versions.length === 0) {
|
|
1388
|
+
return null;
|
|
1389
|
+
}
|
|
1390
|
+
const sorted = [...versions].sort((a, b) => compareVersions(b, a));
|
|
1391
|
+
if (specifier === "latest" || specifier === "*") {
|
|
1392
|
+
return sorted[0];
|
|
1393
|
+
}
|
|
1394
|
+
if (/^\d+\.\d+\.\d+$/.test(specifier)) {
|
|
1395
|
+
return versions.includes(specifier) ? specifier : null;
|
|
1396
|
+
}
|
|
1397
|
+
for (const version of sorted) {
|
|
1398
|
+
if (satisfiesVersion(version, specifier)) {
|
|
1399
|
+
return version;
|
|
1400
|
+
}
|
|
1401
|
+
}
|
|
1402
|
+
return null;
|
|
1403
|
+
}
|
|
1404
|
+
function bumpVersion(currentVersion, bumpType) {
|
|
1405
|
+
const parsed = parseVersion(currentVersion);
|
|
1406
|
+
if (!parsed) return "1.0.0";
|
|
1407
|
+
switch (bumpType) {
|
|
1408
|
+
case "major":
|
|
1409
|
+
return `${parsed.major + 1}.0.0`;
|
|
1410
|
+
case "minor":
|
|
1411
|
+
return `${parsed.major}.${parsed.minor + 1}.0`;
|
|
1412
|
+
case "patch":
|
|
1413
|
+
return `${parsed.major}.${parsed.minor}.${parsed.patch + 1}`;
|
|
1414
|
+
default:
|
|
1415
|
+
return currentVersion;
|
|
1416
|
+
}
|
|
1417
|
+
}
|
|
1418
|
+
function isValidSpecifier(specifier) {
|
|
1419
|
+
if (specifier === "latest" || specifier === "*") {
|
|
1420
|
+
return true;
|
|
1421
|
+
}
|
|
1422
|
+
if (/^\d+\.\d+\.\d+$/.test(specifier)) {
|
|
1423
|
+
return true;
|
|
1424
|
+
}
|
|
1425
|
+
if (/^[\^~><]=?\d+\.\d+\.\d+$/.test(specifier)) {
|
|
1426
|
+
return true;
|
|
1427
|
+
}
|
|
1428
|
+
return false;
|
|
1429
|
+
}
|
|
1430
|
+
function formatVersion(version) {
|
|
1431
|
+
const parsed = parseVersion(version);
|
|
1432
|
+
if (!parsed) return version;
|
|
1433
|
+
return `v${parsed.major}.${parsed.minor}.${parsed.patch}`;
|
|
1434
|
+
}
|
|
1153
1435
|
|
|
1154
1436
|
// src/testRunner.ts
|
|
1155
1437
|
function runTestCase(elements, testCase, container) {
|
|
@@ -1409,21 +1691,30 @@ export {
|
|
|
1409
1691
|
DEFAULT_CACHE_CONFIG,
|
|
1410
1692
|
DEFAULT_RETRY_CONFIG,
|
|
1411
1693
|
applyStyles,
|
|
1694
|
+
batchFetchComponents,
|
|
1412
1695
|
buildClassName,
|
|
1413
1696
|
buildElementStyles,
|
|
1697
|
+
buildRegistryFromBundle,
|
|
1414
1698
|
bumpVersion,
|
|
1415
1699
|
camelToKebab,
|
|
1416
1700
|
clearAllCaches,
|
|
1417
1701
|
clearLocalStorageCache,
|
|
1418
1702
|
clearMemoryCache,
|
|
1419
1703
|
clearStyles,
|
|
1704
|
+
collectAllDependencies,
|
|
1420
1705
|
compareVersions,
|
|
1706
|
+
createRegistry,
|
|
1707
|
+
detectCircularDependencies,
|
|
1421
1708
|
extractBindingKeys,
|
|
1709
|
+
extractDependencies,
|
|
1710
|
+
extractDependenciesFromCode,
|
|
1422
1711
|
fetchComponent,
|
|
1712
|
+
fetchComponentWithDependencies,
|
|
1423
1713
|
formatStyleValue,
|
|
1424
1714
|
formatVersion,
|
|
1425
1715
|
generateTestCases,
|
|
1426
1716
|
getCacheKey,
|
|
1717
|
+
getDependencyTree,
|
|
1427
1718
|
getFromCache,
|
|
1428
1719
|
getMemoryCacheSize,
|
|
1429
1720
|
getRegistryUrl,
|
|
@@ -1435,6 +1726,7 @@ export {
|
|
|
1435
1726
|
prefetchComponents,
|
|
1436
1727
|
processStyles,
|
|
1437
1728
|
render,
|
|
1729
|
+
renderDynamicList,
|
|
1438
1730
|
resolveBindingPath,
|
|
1439
1731
|
resolveTemplate,
|
|
1440
1732
|
resolveTemplateValue,
|