@objectstack/metadata 3.0.10 → 3.1.0

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/index.mjs CHANGED
@@ -786,6 +786,156 @@ var MetadataManager = class {
786
786
  }
787
787
  }
788
788
  }
789
+ /**
790
+ * Publish an entire package:
791
+ * 1. Validate all draft items
792
+ * 2. Snapshot all items in the package (publishedDefinition = clone(metadata))
793
+ * 3. Increment version
794
+ * 4. Set all items state → active
795
+ */
796
+ async publishPackage(packageId, options) {
797
+ const now = (/* @__PURE__ */ new Date()).toISOString();
798
+ const shouldValidate = options?.validate !== false;
799
+ const publishedBy = options?.publishedBy;
800
+ const packageItems = [];
801
+ for (const [type, typeStore] of this.registry) {
802
+ for (const [name, data] of typeStore) {
803
+ const meta = data;
804
+ if (meta?.packageId === packageId || meta?.package === packageId) {
805
+ packageItems.push({ type, name, data: meta });
806
+ }
807
+ }
808
+ }
809
+ if (packageItems.length === 0) {
810
+ return {
811
+ success: false,
812
+ packageId,
813
+ version: 0,
814
+ publishedAt: now,
815
+ itemsPublished: 0,
816
+ validationErrors: [{ type: "", name: "", message: `No metadata items found for package '${packageId}'` }]
817
+ };
818
+ }
819
+ if (shouldValidate) {
820
+ const validationErrors = [];
821
+ for (const item of packageItems) {
822
+ const result = await this.validate(item.type, item.data);
823
+ if (!result.valid && result.errors) {
824
+ for (const err of result.errors) {
825
+ validationErrors.push({
826
+ type: item.type,
827
+ name: item.name,
828
+ message: err.message
829
+ });
830
+ }
831
+ }
832
+ }
833
+ const packageItemKeys = new Set(packageItems.map((i) => `${i.type}:${i.name}`));
834
+ for (const item of packageItems) {
835
+ const deps = await this.getDependencies(item.type, item.name);
836
+ for (const dep of deps) {
837
+ const depKey = `${dep.targetType}:${dep.targetName}`;
838
+ if (packageItemKeys.has(depKey)) continue;
839
+ const depItem = await this.get(dep.targetType, dep.targetName);
840
+ if (!depItem) {
841
+ validationErrors.push({
842
+ type: item.type,
843
+ name: item.name,
844
+ message: `Dependency '${dep.targetType}:${dep.targetName}' not found`
845
+ });
846
+ } else {
847
+ const depMeta = depItem;
848
+ if (depMeta.publishedDefinition === void 0 && depMeta.state !== "active") {
849
+ validationErrors.push({
850
+ type: item.type,
851
+ name: item.name,
852
+ message: `Dependency '${dep.targetType}:${dep.targetName}' is not published`
853
+ });
854
+ }
855
+ }
856
+ }
857
+ }
858
+ if (validationErrors.length > 0) {
859
+ return {
860
+ success: false,
861
+ packageId,
862
+ version: 0,
863
+ publishedAt: now,
864
+ itemsPublished: 0,
865
+ validationErrors
866
+ };
867
+ }
868
+ }
869
+ let maxVersion = 0;
870
+ for (const item of packageItems) {
871
+ const v = typeof item.data.version === "number" ? item.data.version : 0;
872
+ if (v > maxVersion) maxVersion = v;
873
+ }
874
+ const newVersion = maxVersion + 1;
875
+ for (const item of packageItems) {
876
+ const updated = {
877
+ ...item.data,
878
+ publishedDefinition: structuredClone(item.data.metadata ?? item.data),
879
+ publishedAt: now,
880
+ publishedBy: publishedBy ?? item.data.publishedBy,
881
+ version: newVersion,
882
+ state: "active"
883
+ };
884
+ await this.register(item.type, item.name, updated);
885
+ }
886
+ return {
887
+ success: true,
888
+ packageId,
889
+ version: newVersion,
890
+ publishedAt: now,
891
+ itemsPublished: packageItems.length
892
+ };
893
+ }
894
+ /**
895
+ * Revert entire package to last published state.
896
+ * Restores all metadata definitions from their published snapshots.
897
+ */
898
+ async revertPackage(packageId) {
899
+ const packageItems = [];
900
+ for (const [type, typeStore] of this.registry) {
901
+ for (const [name, data] of typeStore) {
902
+ const meta = data;
903
+ if (meta?.packageId === packageId || meta?.package === packageId) {
904
+ packageItems.push({ type, name, data: meta });
905
+ }
906
+ }
907
+ }
908
+ if (packageItems.length === 0) {
909
+ throw new Error(`No metadata items found for package '${packageId}'`);
910
+ }
911
+ const hasPublished = packageItems.some((item) => item.data.publishedDefinition !== void 0);
912
+ if (!hasPublished) {
913
+ throw new Error(`Package '${packageId}' has never been published`);
914
+ }
915
+ for (const item of packageItems) {
916
+ if (item.data.publishedDefinition !== void 0) {
917
+ const reverted = {
918
+ ...item.data,
919
+ metadata: structuredClone(item.data.publishedDefinition),
920
+ state: "active"
921
+ };
922
+ await this.register(item.type, item.name, reverted);
923
+ }
924
+ }
925
+ }
926
+ /**
927
+ * Get the published version of any metadata item (for runtime serving).
928
+ * Returns publishedDefinition if exists, else current definition.
929
+ */
930
+ async getPublished(type, name) {
931
+ const item = await this.get(type, name);
932
+ if (!item) return void 0;
933
+ const meta = item;
934
+ if (meta.publishedDefinition !== void 0) {
935
+ return meta.publishedDefinition;
936
+ }
937
+ return meta.metadata ?? item;
938
+ }
789
939
  // ==========================================
790
940
  // Query / Search
791
941
  // ==========================================