@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/.turbo/turbo-build.log +10 -10
- package/CHANGELOG.md +18 -0
- package/README.md +29 -0
- package/dist/index.d.mts +23 -1
- package/dist/index.d.ts +23 -1
- package/dist/index.js +150 -0
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +150 -0
- package/dist/index.mjs.map +1 -1
- package/package.json +4 -4
- package/src/metadata-manager.ts +182 -0
- package/src/metadata-service.test.ts +269 -0
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
> @objectstack/metadata@3.0
|
|
2
|
+
> @objectstack/metadata@3.1.0 build /home/runner/work/spec/spec/packages/metadata
|
|
3
3
|
> tsup --config ../../tsup.config.ts
|
|
4
4
|
|
|
5
5
|
[34mCLI[39m Building entry: src/index.ts
|
|
@@ -10,13 +10,13 @@
|
|
|
10
10
|
[34mCLI[39m Cleaning output folder
|
|
11
11
|
[34mESM[39m Build start
|
|
12
12
|
[34mCJS[39m Build start
|
|
13
|
-
[32mCJS[39m [1mdist/index.js [22m[
|
|
14
|
-
[32mCJS[39m [1mdist/index.js.map [22m[
|
|
15
|
-
[32mCJS[39m ⚡️ Build success in
|
|
16
|
-
[32mESM[39m [1mdist/index.mjs [22m[
|
|
17
|
-
[32mESM[39m [1mdist/index.mjs.map [22m[
|
|
18
|
-
[32mESM[39m ⚡️ Build success in
|
|
13
|
+
[32mCJS[39m [1mdist/index.js [22m[32m63.63 KB[39m
|
|
14
|
+
[32mCJS[39m [1mdist/index.js.map [22m[32m126.48 KB[39m
|
|
15
|
+
[32mCJS[39m ⚡️ Build success in 194ms
|
|
16
|
+
[32mESM[39m [1mdist/index.mjs [22m[32m61.49 KB[39m
|
|
17
|
+
[32mESM[39m [1mdist/index.mjs.map [22m[32m124.30 KB[39m
|
|
18
|
+
[32mESM[39m ⚡️ Build success in 199ms
|
|
19
19
|
[34mDTS[39m Build start
|
|
20
|
-
[32mDTS[39m ⚡️ Build success in
|
|
21
|
-
[32mDTS[39m [1mdist/index.d.mts [22m[
|
|
22
|
-
[32mDTS[39m [1mdist/index.d.ts [22m[
|
|
20
|
+
[32mDTS[39m ⚡️ Build success in 22968ms
|
|
21
|
+
[32mDTS[39m [1mdist/index.d.mts [22m[32m31.26 KB[39m
|
|
22
|
+
[32mDTS[39m [1mdist/index.d.ts [22m[32m31.26 KB[39m
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,23 @@
|
|
|
1
1
|
# @objectstack/metadata
|
|
2
2
|
|
|
3
|
+
## 3.1.0
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Updated dependencies [0088830]
|
|
8
|
+
- @objectstack/spec@3.1.0
|
|
9
|
+
- @objectstack/core@3.1.0
|
|
10
|
+
- @objectstack/types@3.1.0
|
|
11
|
+
|
|
12
|
+
## 3.0.11
|
|
13
|
+
|
|
14
|
+
### Patch Changes
|
|
15
|
+
|
|
16
|
+
- Updated dependencies [92d9d99]
|
|
17
|
+
- @objectstack/spec@3.0.11
|
|
18
|
+
- @objectstack/core@3.0.11
|
|
19
|
+
- @objectstack/types@3.0.11
|
|
20
|
+
|
|
3
21
|
## 3.0.10
|
|
4
22
|
|
|
5
23
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -86,6 +86,7 @@ The `MetadataManager` is the main orchestrator. It provides:
|
|
|
86
86
|
- **Core CRUD**: `register`, `get`, `list`, `unregister`, `exists`, `listNames`
|
|
87
87
|
- **Convenience**: `getObject`, `listObjects`
|
|
88
88
|
- **Package Management**: `unregisterPackage` — unload all metadata from a package
|
|
89
|
+
- **Package Publishing**: `publishPackage`, `revertPackage`, `getPublished` — atomic package-level metadata publishing
|
|
89
90
|
- **Query / Search**: `query` with filtering, pagination, sorting by type/scope/state/tags
|
|
90
91
|
- **Bulk Operations**: `bulkRegister`, `bulkUnregister` with error handling
|
|
91
92
|
- **Import / Export**: `exportMetadata`, `importMetadata` with conflict resolution (skip/overwrite/merge)
|
|
@@ -201,6 +202,34 @@ const plugin = MetadataPlugin({
|
|
|
201
202
|
kernel.use(plugin);
|
|
202
203
|
```
|
|
203
204
|
|
|
205
|
+
## Package Publishing
|
|
206
|
+
|
|
207
|
+
ObjectStack supports **package-level metadata publishing** — all metadata items within a package are published atomically.
|
|
208
|
+
|
|
209
|
+
### Publish a Package
|
|
210
|
+
|
|
211
|
+
```typescript
|
|
212
|
+
const result = await manager.publishPackage('com.acme.crm', {
|
|
213
|
+
publishedBy: 'admin',
|
|
214
|
+
validate: true,
|
|
215
|
+
});
|
|
216
|
+
// result: { success: true, version: 2, itemsPublished: 5, publishedAt: '...' }
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
### Revert to Last Published State
|
|
220
|
+
|
|
221
|
+
```typescript
|
|
222
|
+
await manager.revertPackage('com.acme.crm');
|
|
223
|
+
// All items restored to their publishedDefinition snapshots
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
### Get Published Version (Runtime Serving)
|
|
227
|
+
|
|
228
|
+
```typescript
|
|
229
|
+
const published = await manager.getPublished('object', 'opportunity');
|
|
230
|
+
// Returns publishedDefinition if exists, else current definition
|
|
231
|
+
```
|
|
232
|
+
|
|
204
233
|
## Package Structure
|
|
205
234
|
|
|
206
235
|
```
|
package/dist/index.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { MetadataFormat, MetadataLoaderContract, MetadataLoadOptions, MetadataLoadResult, MetadataStats, MetadataSaveOptions, MetadataSaveResult, MetadataWatchEvent, MetadataManagerConfig } from '@objectstack/spec/system';
|
|
1
|
+
import { MetadataFormat, MetadataLoaderContract, MetadataLoadOptions, MetadataLoadResult, MetadataStats, MetadataSaveOptions, MetadataSaveResult, MetadataWatchEvent, MetadataManagerConfig, PackagePublishResult } from '@objectstack/spec/system';
|
|
2
2
|
export { MetadataCollectionInfo, MetadataExportOptions, MetadataFormat, MetadataImportOptions, MetadataLoadOptions, MetadataLoadResult, MetadataLoaderContract, MetadataManagerConfig, MetadataSaveOptions, MetadataSaveResult, MetadataStats, MetadataWatchEvent } from '@objectstack/spec/system';
|
|
3
3
|
import { IMetadataService, IDataDriver, MetadataWatchCallback, MetadataWatchHandle, MetadataExportOptions, MetadataImportOptions, MetadataImportResult, MetadataTypeInfo, ISchemaDriver } from '@objectstack/spec/contracts';
|
|
4
4
|
export { IMetadataService, MetadataImportResult, MetadataTypeInfo, MetadataWatchCallback, MetadataWatchHandle } from '@objectstack/spec/contracts';
|
|
@@ -225,6 +225,28 @@ declare class MetadataManager implements IMetadataService {
|
|
|
225
225
|
* Unregister all metadata items from a specific package
|
|
226
226
|
*/
|
|
227
227
|
unregisterPackage(packageName: string): Promise<void>;
|
|
228
|
+
/**
|
|
229
|
+
* Publish an entire package:
|
|
230
|
+
* 1. Validate all draft items
|
|
231
|
+
* 2. Snapshot all items in the package (publishedDefinition = clone(metadata))
|
|
232
|
+
* 3. Increment version
|
|
233
|
+
* 4. Set all items state → active
|
|
234
|
+
*/
|
|
235
|
+
publishPackage(packageId: string, options?: {
|
|
236
|
+
changeNote?: string;
|
|
237
|
+
publishedBy?: string;
|
|
238
|
+
validate?: boolean;
|
|
239
|
+
}): Promise<PackagePublishResult>;
|
|
240
|
+
/**
|
|
241
|
+
* Revert entire package to last published state.
|
|
242
|
+
* Restores all metadata definitions from their published snapshots.
|
|
243
|
+
*/
|
|
244
|
+
revertPackage(packageId: string): Promise<void>;
|
|
245
|
+
/**
|
|
246
|
+
* Get the published version of any metadata item (for runtime serving).
|
|
247
|
+
* Returns publishedDefinition if exists, else current definition.
|
|
248
|
+
*/
|
|
249
|
+
getPublished(type: string, name: string): Promise<unknown | undefined>;
|
|
228
250
|
/**
|
|
229
251
|
* Query metadata items with filtering, sorting, and pagination
|
|
230
252
|
*/
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { MetadataFormat, MetadataLoaderContract, MetadataLoadOptions, MetadataLoadResult, MetadataStats, MetadataSaveOptions, MetadataSaveResult, MetadataWatchEvent, MetadataManagerConfig } from '@objectstack/spec/system';
|
|
1
|
+
import { MetadataFormat, MetadataLoaderContract, MetadataLoadOptions, MetadataLoadResult, MetadataStats, MetadataSaveOptions, MetadataSaveResult, MetadataWatchEvent, MetadataManagerConfig, PackagePublishResult } from '@objectstack/spec/system';
|
|
2
2
|
export { MetadataCollectionInfo, MetadataExportOptions, MetadataFormat, MetadataImportOptions, MetadataLoadOptions, MetadataLoadResult, MetadataLoaderContract, MetadataManagerConfig, MetadataSaveOptions, MetadataSaveResult, MetadataStats, MetadataWatchEvent } from '@objectstack/spec/system';
|
|
3
3
|
import { IMetadataService, IDataDriver, MetadataWatchCallback, MetadataWatchHandle, MetadataExportOptions, MetadataImportOptions, MetadataImportResult, MetadataTypeInfo, ISchemaDriver } from '@objectstack/spec/contracts';
|
|
4
4
|
export { IMetadataService, MetadataImportResult, MetadataTypeInfo, MetadataWatchCallback, MetadataWatchHandle } from '@objectstack/spec/contracts';
|
|
@@ -225,6 +225,28 @@ declare class MetadataManager implements IMetadataService {
|
|
|
225
225
|
* Unregister all metadata items from a specific package
|
|
226
226
|
*/
|
|
227
227
|
unregisterPackage(packageName: string): Promise<void>;
|
|
228
|
+
/**
|
|
229
|
+
* Publish an entire package:
|
|
230
|
+
* 1. Validate all draft items
|
|
231
|
+
* 2. Snapshot all items in the package (publishedDefinition = clone(metadata))
|
|
232
|
+
* 3. Increment version
|
|
233
|
+
* 4. Set all items state → active
|
|
234
|
+
*/
|
|
235
|
+
publishPackage(packageId: string, options?: {
|
|
236
|
+
changeNote?: string;
|
|
237
|
+
publishedBy?: string;
|
|
238
|
+
validate?: boolean;
|
|
239
|
+
}): Promise<PackagePublishResult>;
|
|
240
|
+
/**
|
|
241
|
+
* Revert entire package to last published state.
|
|
242
|
+
* Restores all metadata definitions from their published snapshots.
|
|
243
|
+
*/
|
|
244
|
+
revertPackage(packageId: string): Promise<void>;
|
|
245
|
+
/**
|
|
246
|
+
* Get the published version of any metadata item (for runtime serving).
|
|
247
|
+
* Returns publishedDefinition if exists, else current definition.
|
|
248
|
+
*/
|
|
249
|
+
getPublished(type: string, name: string): Promise<unknown | undefined>;
|
|
228
250
|
/**
|
|
229
251
|
* Query metadata items with filtering, sorting, and pagination
|
|
230
252
|
*/
|
package/dist/index.js
CHANGED
|
@@ -825,6 +825,156 @@ var MetadataManager = class {
|
|
|
825
825
|
}
|
|
826
826
|
}
|
|
827
827
|
}
|
|
828
|
+
/**
|
|
829
|
+
* Publish an entire package:
|
|
830
|
+
* 1. Validate all draft items
|
|
831
|
+
* 2. Snapshot all items in the package (publishedDefinition = clone(metadata))
|
|
832
|
+
* 3. Increment version
|
|
833
|
+
* 4. Set all items state → active
|
|
834
|
+
*/
|
|
835
|
+
async publishPackage(packageId, options) {
|
|
836
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
837
|
+
const shouldValidate = options?.validate !== false;
|
|
838
|
+
const publishedBy = options?.publishedBy;
|
|
839
|
+
const packageItems = [];
|
|
840
|
+
for (const [type, typeStore] of this.registry) {
|
|
841
|
+
for (const [name, data] of typeStore) {
|
|
842
|
+
const meta = data;
|
|
843
|
+
if (meta?.packageId === packageId || meta?.package === packageId) {
|
|
844
|
+
packageItems.push({ type, name, data: meta });
|
|
845
|
+
}
|
|
846
|
+
}
|
|
847
|
+
}
|
|
848
|
+
if (packageItems.length === 0) {
|
|
849
|
+
return {
|
|
850
|
+
success: false,
|
|
851
|
+
packageId,
|
|
852
|
+
version: 0,
|
|
853
|
+
publishedAt: now,
|
|
854
|
+
itemsPublished: 0,
|
|
855
|
+
validationErrors: [{ type: "", name: "", message: `No metadata items found for package '${packageId}'` }]
|
|
856
|
+
};
|
|
857
|
+
}
|
|
858
|
+
if (shouldValidate) {
|
|
859
|
+
const validationErrors = [];
|
|
860
|
+
for (const item of packageItems) {
|
|
861
|
+
const result = await this.validate(item.type, item.data);
|
|
862
|
+
if (!result.valid && result.errors) {
|
|
863
|
+
for (const err of result.errors) {
|
|
864
|
+
validationErrors.push({
|
|
865
|
+
type: item.type,
|
|
866
|
+
name: item.name,
|
|
867
|
+
message: err.message
|
|
868
|
+
});
|
|
869
|
+
}
|
|
870
|
+
}
|
|
871
|
+
}
|
|
872
|
+
const packageItemKeys = new Set(packageItems.map((i) => `${i.type}:${i.name}`));
|
|
873
|
+
for (const item of packageItems) {
|
|
874
|
+
const deps = await this.getDependencies(item.type, item.name);
|
|
875
|
+
for (const dep of deps) {
|
|
876
|
+
const depKey = `${dep.targetType}:${dep.targetName}`;
|
|
877
|
+
if (packageItemKeys.has(depKey)) continue;
|
|
878
|
+
const depItem = await this.get(dep.targetType, dep.targetName);
|
|
879
|
+
if (!depItem) {
|
|
880
|
+
validationErrors.push({
|
|
881
|
+
type: item.type,
|
|
882
|
+
name: item.name,
|
|
883
|
+
message: `Dependency '${dep.targetType}:${dep.targetName}' not found`
|
|
884
|
+
});
|
|
885
|
+
} else {
|
|
886
|
+
const depMeta = depItem;
|
|
887
|
+
if (depMeta.publishedDefinition === void 0 && depMeta.state !== "active") {
|
|
888
|
+
validationErrors.push({
|
|
889
|
+
type: item.type,
|
|
890
|
+
name: item.name,
|
|
891
|
+
message: `Dependency '${dep.targetType}:${dep.targetName}' is not published`
|
|
892
|
+
});
|
|
893
|
+
}
|
|
894
|
+
}
|
|
895
|
+
}
|
|
896
|
+
}
|
|
897
|
+
if (validationErrors.length > 0) {
|
|
898
|
+
return {
|
|
899
|
+
success: false,
|
|
900
|
+
packageId,
|
|
901
|
+
version: 0,
|
|
902
|
+
publishedAt: now,
|
|
903
|
+
itemsPublished: 0,
|
|
904
|
+
validationErrors
|
|
905
|
+
};
|
|
906
|
+
}
|
|
907
|
+
}
|
|
908
|
+
let maxVersion = 0;
|
|
909
|
+
for (const item of packageItems) {
|
|
910
|
+
const v = typeof item.data.version === "number" ? item.data.version : 0;
|
|
911
|
+
if (v > maxVersion) maxVersion = v;
|
|
912
|
+
}
|
|
913
|
+
const newVersion = maxVersion + 1;
|
|
914
|
+
for (const item of packageItems) {
|
|
915
|
+
const updated = {
|
|
916
|
+
...item.data,
|
|
917
|
+
publishedDefinition: structuredClone(item.data.metadata ?? item.data),
|
|
918
|
+
publishedAt: now,
|
|
919
|
+
publishedBy: publishedBy ?? item.data.publishedBy,
|
|
920
|
+
version: newVersion,
|
|
921
|
+
state: "active"
|
|
922
|
+
};
|
|
923
|
+
await this.register(item.type, item.name, updated);
|
|
924
|
+
}
|
|
925
|
+
return {
|
|
926
|
+
success: true,
|
|
927
|
+
packageId,
|
|
928
|
+
version: newVersion,
|
|
929
|
+
publishedAt: now,
|
|
930
|
+
itemsPublished: packageItems.length
|
|
931
|
+
};
|
|
932
|
+
}
|
|
933
|
+
/**
|
|
934
|
+
* Revert entire package to last published state.
|
|
935
|
+
* Restores all metadata definitions from their published snapshots.
|
|
936
|
+
*/
|
|
937
|
+
async revertPackage(packageId) {
|
|
938
|
+
const packageItems = [];
|
|
939
|
+
for (const [type, typeStore] of this.registry) {
|
|
940
|
+
for (const [name, data] of typeStore) {
|
|
941
|
+
const meta = data;
|
|
942
|
+
if (meta?.packageId === packageId || meta?.package === packageId) {
|
|
943
|
+
packageItems.push({ type, name, data: meta });
|
|
944
|
+
}
|
|
945
|
+
}
|
|
946
|
+
}
|
|
947
|
+
if (packageItems.length === 0) {
|
|
948
|
+
throw new Error(`No metadata items found for package '${packageId}'`);
|
|
949
|
+
}
|
|
950
|
+
const hasPublished = packageItems.some((item) => item.data.publishedDefinition !== void 0);
|
|
951
|
+
if (!hasPublished) {
|
|
952
|
+
throw new Error(`Package '${packageId}' has never been published`);
|
|
953
|
+
}
|
|
954
|
+
for (const item of packageItems) {
|
|
955
|
+
if (item.data.publishedDefinition !== void 0) {
|
|
956
|
+
const reverted = {
|
|
957
|
+
...item.data,
|
|
958
|
+
metadata: structuredClone(item.data.publishedDefinition),
|
|
959
|
+
state: "active"
|
|
960
|
+
};
|
|
961
|
+
await this.register(item.type, item.name, reverted);
|
|
962
|
+
}
|
|
963
|
+
}
|
|
964
|
+
}
|
|
965
|
+
/**
|
|
966
|
+
* Get the published version of any metadata item (for runtime serving).
|
|
967
|
+
* Returns publishedDefinition if exists, else current definition.
|
|
968
|
+
*/
|
|
969
|
+
async getPublished(type, name) {
|
|
970
|
+
const item = await this.get(type, name);
|
|
971
|
+
if (!item) return void 0;
|
|
972
|
+
const meta = item;
|
|
973
|
+
if (meta.publishedDefinition !== void 0) {
|
|
974
|
+
return meta.publishedDefinition;
|
|
975
|
+
}
|
|
976
|
+
return meta.metadata ?? item;
|
|
977
|
+
}
|
|
828
978
|
// ==========================================
|
|
829
979
|
// Query / Search
|
|
830
980
|
// ==========================================
|