@objectstack/metadata 4.2.0 → 5.0.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.cjs +252 -28
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +77 -4
- package/dist/index.d.ts +77 -4
- package/dist/index.js +252 -28
- package/dist/index.js.map +1 -1
- package/dist/node.cjs +252 -28
- package/dist/node.cjs.map +1 -1
- package/dist/node.d.cts +1 -0
- package/dist/node.d.ts +1 -0
- package/dist/node.js +252 -28
- package/dist/node.js.map +1 -1
- package/package.json +7 -5
package/dist/index.js
CHANGED
|
@@ -42,7 +42,12 @@ function registerMetadataHmrRoutes(app, manager, options = {}) {
|
|
|
42
42
|
metadataType: evt.metadataType ?? type,
|
|
43
43
|
name: evt.name ?? "",
|
|
44
44
|
path: evt.path,
|
|
45
|
-
timestamp: Number.isFinite(ts) ? ts : Date.now()
|
|
45
|
+
timestamp: Number.isFinite(ts) ? ts : Date.now(),
|
|
46
|
+
// Forward the canonical server-side sequence number when the
|
|
47
|
+
// event originated from a MetadataRepository (ADR-0008). Legacy
|
|
48
|
+
// chokidar-driven events have no seq — clients fall back to
|
|
49
|
+
// their local counter in that case.
|
|
50
|
+
...typeof evt.seq === "number" ? { seq: evt.seq } : {}
|
|
46
51
|
});
|
|
47
52
|
});
|
|
48
53
|
}
|
|
@@ -559,7 +564,7 @@ var DatabaseLoader = class {
|
|
|
559
564
|
this.tableName = options.tableName ?? "sys_metadata";
|
|
560
565
|
this.historyTableName = options.historyTableName ?? "sys_metadata_history";
|
|
561
566
|
this.organizationId = options.organizationId;
|
|
562
|
-
|
|
567
|
+
void options.projectId;
|
|
563
568
|
this.trackHistory = options.trackHistory !== false;
|
|
564
569
|
const cacheOpts = options.cache;
|
|
565
570
|
const cacheEnabled = cacheOpts?.enabled !== false;
|
|
@@ -649,6 +654,26 @@ var DatabaseLoader = class {
|
|
|
649
654
|
}
|
|
650
655
|
return this.driver.delete(table, id);
|
|
651
656
|
}
|
|
657
|
+
/**
|
|
658
|
+
* Compute the next per-org `event_seq` for `sys_metadata_history`.
|
|
659
|
+
* Reads `MAX(event_seq) + 1` for the configured `organization_id`.
|
|
660
|
+
* Legacy path — not transactional, so concurrent writes can collide.
|
|
661
|
+
* The canonical (transactional) producer is `SysMetadataRepository`.
|
|
662
|
+
*/
|
|
663
|
+
async nextEventSeq() {
|
|
664
|
+
const where = this.organizationId ? { organization_id: this.organizationId } : {};
|
|
665
|
+
try {
|
|
666
|
+
const rows = await this._find(this.historyTableName, { where });
|
|
667
|
+
let max = 0;
|
|
668
|
+
for (const row of rows) {
|
|
669
|
+
const v = typeof row.event_seq === "number" ? row.event_seq : 0;
|
|
670
|
+
if (v > max) max = v;
|
|
671
|
+
}
|
|
672
|
+
return max + 1;
|
|
673
|
+
} catch {
|
|
674
|
+
return 1;
|
|
675
|
+
}
|
|
676
|
+
}
|
|
652
677
|
/**
|
|
653
678
|
* Ensure the metadata table exists.
|
|
654
679
|
* Uses IDataDriver.syncSchema with the SysMetadataObject definition
|
|
@@ -713,8 +738,9 @@ var DatabaseLoader = class {
|
|
|
713
738
|
}
|
|
714
739
|
/**
|
|
715
740
|
* Build base filter conditions for queries.
|
|
716
|
-
* Filters by organizationId when configured
|
|
717
|
-
*
|
|
741
|
+
* Filters by organizationId when configured. `projectId` is accepted
|
|
742
|
+
* for back-compat but no longer constrains the query — see
|
|
743
|
+
* ADR-0008 §0 (branch/project removal).
|
|
718
744
|
*/
|
|
719
745
|
baseFilter(type, name) {
|
|
720
746
|
const filter = { type };
|
|
@@ -724,7 +750,6 @@ var DatabaseLoader = class {
|
|
|
724
750
|
if (this.organizationId) {
|
|
725
751
|
filter.organization_id = this.organizationId;
|
|
726
752
|
}
|
|
727
|
-
filter.project_id = this.projectId ?? null;
|
|
728
753
|
return filter;
|
|
729
754
|
}
|
|
730
755
|
/**
|
|
@@ -750,6 +775,7 @@ var DatabaseLoader = class {
|
|
|
750
775
|
}
|
|
751
776
|
const historyId = generateId();
|
|
752
777
|
const metadataJson = JSON.stringify(metadata);
|
|
778
|
+
const eventSeq = await this.nextEventSeq();
|
|
753
779
|
const historyRecord = {
|
|
754
780
|
id: historyId,
|
|
755
781
|
metadataId,
|
|
@@ -763,12 +789,12 @@ var DatabaseLoader = class {
|
|
|
763
789
|
changeNote,
|
|
764
790
|
recordedBy,
|
|
765
791
|
recordedAt: now,
|
|
766
|
-
...this.organizationId ? { organizationId: this.organizationId } : {}
|
|
767
|
-
...this.projectId !== void 0 ? { projectId: this.projectId } : {}
|
|
792
|
+
...this.organizationId ? { organizationId: this.organizationId } : {}
|
|
768
793
|
};
|
|
769
794
|
try {
|
|
770
795
|
await this._create(this.historyTableName, {
|
|
771
796
|
id: historyRecord.id,
|
|
797
|
+
event_seq: eventSeq,
|
|
772
798
|
metadata_id: historyRecord.metadataId,
|
|
773
799
|
name: historyRecord.name,
|
|
774
800
|
type: historyRecord.type,
|
|
@@ -780,8 +806,8 @@ var DatabaseLoader = class {
|
|
|
780
806
|
change_note: historyRecord.changeNote,
|
|
781
807
|
recorded_by: historyRecord.recordedBy,
|
|
782
808
|
recorded_at: historyRecord.recordedAt,
|
|
783
|
-
|
|
784
|
-
...this.
|
|
809
|
+
source: "database-loader",
|
|
810
|
+
...this.organizationId ? { organization_id: this.organizationId } : {}
|
|
785
811
|
});
|
|
786
812
|
} catch (error) {
|
|
787
813
|
console.error(`Failed to create history record for ${type}/${name}:`, error);
|
|
@@ -968,7 +994,6 @@ var DatabaseLoader = class {
|
|
|
968
994
|
if (this.organizationId) {
|
|
969
995
|
filter.organization_id = this.organizationId;
|
|
970
996
|
}
|
|
971
|
-
filter.project_id = this.projectId ?? null;
|
|
972
997
|
const row = await this._findOne(this.historyTableName, {
|
|
973
998
|
where: filter
|
|
974
999
|
});
|
|
@@ -985,7 +1010,6 @@ var DatabaseLoader = class {
|
|
|
985
1010
|
previousChecksum: row.previous_checksum,
|
|
986
1011
|
changeNote: row.change_note,
|
|
987
1012
|
organizationId: row.organization_id,
|
|
988
|
-
projectId: row.project_id,
|
|
989
1013
|
recordedBy: row.recorded_by,
|
|
990
1014
|
recordedAt: row.recorded_at
|
|
991
1015
|
};
|
|
@@ -1003,7 +1027,6 @@ var DatabaseLoader = class {
|
|
|
1003
1027
|
await this.ensureHistorySchema();
|
|
1004
1028
|
const filter = { type, name };
|
|
1005
1029
|
if (this.organizationId) filter.organization_id = this.organizationId;
|
|
1006
|
-
filter.project_id = this.projectId ?? null;
|
|
1007
1030
|
const metadataRecord = await this._findOne(this.tableName, { where: filter });
|
|
1008
1031
|
if (!metadataRecord) {
|
|
1009
1032
|
return { records: [], total: 0, hasMore: false };
|
|
@@ -1012,7 +1035,6 @@ var DatabaseLoader = class {
|
|
|
1012
1035
|
metadata_id: metadataRecord.id
|
|
1013
1036
|
};
|
|
1014
1037
|
if (this.organizationId) historyFilter.organization_id = this.organizationId;
|
|
1015
|
-
historyFilter.project_id = this.projectId ?? null;
|
|
1016
1038
|
if (options?.operationType) historyFilter.operation_type = options.operationType;
|
|
1017
1039
|
if (options?.since) historyFilter.recorded_at = { $gte: options.since };
|
|
1018
1040
|
if (options?.until) {
|
|
@@ -1051,7 +1073,6 @@ var DatabaseLoader = class {
|
|
|
1051
1073
|
previousChecksum: row.previous_checksum,
|
|
1052
1074
|
changeNote: row.change_note,
|
|
1053
1075
|
organizationId: row.organization_id,
|
|
1054
|
-
projectId: row.project_id,
|
|
1055
1076
|
recordedBy: row.recorded_by,
|
|
1056
1077
|
recordedAt: row.recorded_at
|
|
1057
1078
|
};
|
|
@@ -1158,7 +1179,6 @@ var DatabaseLoader = class {
|
|
|
1158
1179
|
version: 1,
|
|
1159
1180
|
source: "database",
|
|
1160
1181
|
...this.organizationId ? { organization_id: this.organizationId } : {},
|
|
1161
|
-
...this.projectId !== void 0 ? { project_id: this.projectId } : { project_id: null },
|
|
1162
1182
|
created_at: now,
|
|
1163
1183
|
updated_at: now
|
|
1164
1184
|
});
|
|
@@ -1231,6 +1251,7 @@ var _MetadataManager = class _MetadataManager {
|
|
|
1231
1251
|
// Invalidated on every `register()` / `unregister()` to keep CRUD writes
|
|
1232
1252
|
// visible to subsequent reads.
|
|
1233
1253
|
this.listCache = /* @__PURE__ */ new Map();
|
|
1254
|
+
this.repoWatchClosed = false;
|
|
1234
1255
|
this.config = config;
|
|
1235
1256
|
this.logger = createLogger({ level: "info", format: "pretty" });
|
|
1236
1257
|
this.serializers = /* @__PURE__ */ new Map();
|
|
@@ -2238,6 +2259,110 @@ var _MetadataManager = class _MetadataManager {
|
|
|
2238
2259
|
*/
|
|
2239
2260
|
async stopWatching() {
|
|
2240
2261
|
}
|
|
2262
|
+
// ─── ADR-0008 PR-6: Repository wiring ───────────────────────────────
|
|
2263
|
+
/**
|
|
2264
|
+
* Attach a {@link MetadataRepository} as a supplementary event source.
|
|
2265
|
+
*
|
|
2266
|
+
* The manager subscribes to `repo.watch({})` and re-emits each event
|
|
2267
|
+
* through {@link notifyWatchers} as a legacy `MetadataWatchEvent`.
|
|
2268
|
+
* Each event also invalidates the in-memory registry entry and the
|
|
2269
|
+
* `list()` cache for the affected type so subsequent reads see fresh
|
|
2270
|
+
* data.
|
|
2271
|
+
*
|
|
2272
|
+
* No write-through. `register()` / `unregister()` / `save()` are
|
|
2273
|
+
* untouched in this PR (deferred to ADR-0008 M0 PR-10).
|
|
2274
|
+
*
|
|
2275
|
+
* Call {@link dispose} (or {@link stopRepositoryWatch}) to detach.
|
|
2276
|
+
*/
|
|
2277
|
+
setRepository(repo) {
|
|
2278
|
+
if (this.repository === repo) return;
|
|
2279
|
+
if (this.repository) {
|
|
2280
|
+
void this.stopRepositoryWatch();
|
|
2281
|
+
}
|
|
2282
|
+
this.repository = repo;
|
|
2283
|
+
this.repoWatchClosed = false;
|
|
2284
|
+
void this.startRepositoryWatch();
|
|
2285
|
+
}
|
|
2286
|
+
/** Return the attached repository, if any. */
|
|
2287
|
+
getRepository() {
|
|
2288
|
+
return this.repository;
|
|
2289
|
+
}
|
|
2290
|
+
/** Stop the active repo.watch() loop (best-effort). */
|
|
2291
|
+
async stopRepositoryWatch() {
|
|
2292
|
+
this.repoWatchClosed = true;
|
|
2293
|
+
const iter = this.repoWatchIter;
|
|
2294
|
+
this.repoWatchIter = void 0;
|
|
2295
|
+
if (iter && typeof iter.return === "function") {
|
|
2296
|
+
try {
|
|
2297
|
+
await iter.return(void 0);
|
|
2298
|
+
} catch {
|
|
2299
|
+
}
|
|
2300
|
+
}
|
|
2301
|
+
}
|
|
2302
|
+
/**
|
|
2303
|
+
* Best-effort cleanup. Stops the FS watcher (if any), drains the
|
|
2304
|
+
* repository watch loop, and clears registry caches. Safe to call
|
|
2305
|
+
* multiple times.
|
|
2306
|
+
*/
|
|
2307
|
+
async dispose() {
|
|
2308
|
+
await this.stopWatching().catch(() => void 0);
|
|
2309
|
+
await this.stopRepositoryWatch().catch(() => void 0);
|
|
2310
|
+
this.listCache.clear();
|
|
2311
|
+
}
|
|
2312
|
+
async startRepositoryWatch() {
|
|
2313
|
+
const repo = this.repository;
|
|
2314
|
+
if (!repo) return;
|
|
2315
|
+
const iterable = repo.watch({});
|
|
2316
|
+
const iter = iterable[Symbol.asyncIterator]();
|
|
2317
|
+
this.repoWatchIter = iter;
|
|
2318
|
+
try {
|
|
2319
|
+
while (!this.repoWatchClosed) {
|
|
2320
|
+
const { value, done } = await iter.next();
|
|
2321
|
+
if (done) break;
|
|
2322
|
+
try {
|
|
2323
|
+
this.applyRepoEvent(value);
|
|
2324
|
+
} catch (err) {
|
|
2325
|
+
this.logger.warn("[MetadataManager] repo event handler failed", {
|
|
2326
|
+
error: err instanceof Error ? err.message : String(err)
|
|
2327
|
+
});
|
|
2328
|
+
}
|
|
2329
|
+
}
|
|
2330
|
+
} catch (err) {
|
|
2331
|
+
if (!this.repoWatchClosed) {
|
|
2332
|
+
this.logger.warn("[MetadataManager] repository watch loop exited unexpectedly", {
|
|
2333
|
+
error: err instanceof Error ? err.message : String(err)
|
|
2334
|
+
});
|
|
2335
|
+
}
|
|
2336
|
+
} finally {
|
|
2337
|
+
if (this.repoWatchIter === iter) this.repoWatchIter = void 0;
|
|
2338
|
+
}
|
|
2339
|
+
}
|
|
2340
|
+
/** Translate a repo event to the legacy MetadataWatchEvent + invalidate caches. */
|
|
2341
|
+
applyRepoEvent(evt) {
|
|
2342
|
+
const ref = evt.ref;
|
|
2343
|
+
const type = ref.type;
|
|
2344
|
+
const name = ref.name;
|
|
2345
|
+
const typeStore = this.registry.get(type);
|
|
2346
|
+
if (typeStore) {
|
|
2347
|
+
typeStore.delete(name);
|
|
2348
|
+
if (typeStore.size === 0) this.registry.delete(type);
|
|
2349
|
+
}
|
|
2350
|
+
this.listCache.delete(type);
|
|
2351
|
+
const legacyType = evt.op === "create" ? "added" : evt.op === "delete" ? "deleted" : "changed";
|
|
2352
|
+
const legacyEvent = {
|
|
2353
|
+
type: legacyType,
|
|
2354
|
+
metadataType: type,
|
|
2355
|
+
name,
|
|
2356
|
+
path: "",
|
|
2357
|
+
// Repo events carry the hash only; the body is fetched on demand
|
|
2358
|
+
// via manager.get(type, name). HMR consumers don't read `data` so
|
|
2359
|
+
// this is fine for M0. (See ADR-0008 §12 open question 1.)
|
|
2360
|
+
data: void 0,
|
|
2361
|
+
timestamp: evt.ts
|
|
2362
|
+
};
|
|
2363
|
+
legacyEvent.seq = evt.seq;
|
|
2364
|
+
this.notifyWatchers(type, legacyEvent);
|
|
2365
|
+
}
|
|
2241
2366
|
notifyWatchers(type, event) {
|
|
2242
2367
|
const callbacks = this.watchCallbacks.get(type);
|
|
2243
2368
|
if (!callbacks) return;
|
|
@@ -2713,7 +2838,13 @@ var NodeMetadataManager = class extends MetadataManager {
|
|
|
2713
2838
|
this.watcher = chokidarWatch(rootDir, {
|
|
2714
2839
|
ignored,
|
|
2715
2840
|
persistent,
|
|
2716
|
-
ignoreInitial: true
|
|
2841
|
+
ignoreInitial: true,
|
|
2842
|
+
// Use polling to avoid `fs.watch` EMFILE on macOS / busy dev hosts.
|
|
2843
|
+
// Recursive watch over a project root would otherwise wire native
|
|
2844
|
+
// watches across the entire tree, easily exhausting the FD pool.
|
|
2845
|
+
usePolling: true,
|
|
2846
|
+
interval: 1e3,
|
|
2847
|
+
binaryInterval: 2e3
|
|
2717
2848
|
});
|
|
2718
2849
|
this.watcher.on("add", async (filePath) => {
|
|
2719
2850
|
await this.handleFileEvent("added", filePath);
|
|
@@ -2851,6 +2982,7 @@ var queryableMetadataObjects = [
|
|
|
2851
2982
|
SysMetadataObject2,
|
|
2852
2983
|
SysMetadataHistoryObject2
|
|
2853
2984
|
];
|
|
2985
|
+
var REPO_SUBDIR = ".objectstack/metadata";
|
|
2854
2986
|
var ARTIFACT_FIELD_TO_TYPE = {
|
|
2855
2987
|
objects: "object",
|
|
2856
2988
|
objectExtensions: "object_extension",
|
|
@@ -2948,6 +3080,31 @@ var MetadataPlugin = class {
|
|
|
2948
3080
|
await this._loadFromFileSystem(ctx);
|
|
2949
3081
|
}
|
|
2950
3082
|
}
|
|
3083
|
+
const bootstrapMode = this.options.config?.bootstrap ?? "eager";
|
|
3084
|
+
if (bootstrapMode !== "artifact-only") {
|
|
3085
|
+
try {
|
|
3086
|
+
const path3 = await import("path");
|
|
3087
|
+
const { FileSystemRepository } = await import("@objectstack/metadata-fs");
|
|
3088
|
+
const rootDir = this.options.rootDir || process.cwd();
|
|
3089
|
+
const repoRoot = path3.join(rootDir, REPO_SUBDIR);
|
|
3090
|
+
const repo = new FileSystemRepository({
|
|
3091
|
+
root: repoRoot,
|
|
3092
|
+
org: this.options.organizationId ?? "system",
|
|
3093
|
+
disableWatch: this.options.watch === false
|
|
3094
|
+
});
|
|
3095
|
+
await repo.start();
|
|
3096
|
+
this.repository = repo;
|
|
3097
|
+
this.manager.setRepository(repo);
|
|
3098
|
+
ctx.logger.info("[MetadataPlugin] FileSystemRepository attached", {
|
|
3099
|
+
repoRoot,
|
|
3100
|
+
watch: this.options.watch !== false
|
|
3101
|
+
});
|
|
3102
|
+
} catch (e) {
|
|
3103
|
+
ctx.logger.warn("[MetadataPlugin] Failed to attach FileSystemRepository", {
|
|
3104
|
+
error: e?.message
|
|
3105
|
+
});
|
|
3106
|
+
}
|
|
3107
|
+
}
|
|
2951
3108
|
try {
|
|
2952
3109
|
const realtimeService = ctx.getService("realtime");
|
|
2953
3110
|
if (realtimeService && typeof realtimeService === "object" && "publish" in realtimeService) {
|
|
@@ -2965,12 +3122,12 @@ var MetadataPlugin = class {
|
|
|
2965
3122
|
const { registerMetadataHmrRoutes: registerMetadataHmrRoutes2 } = await Promise.resolve().then(() => (init_hmr_routes(), hmr_routes_exports));
|
|
2966
3123
|
const hub = registerMetadataHmrRoutes2(httpServer.getRawApp(), this.manager);
|
|
2967
3124
|
hub.setOnPostReload(async (body = {}) => {
|
|
2968
|
-
const
|
|
2969
|
-
if (
|
|
3125
|
+
const src3 = this.options.artifactSource;
|
|
3126
|
+
if (src3?.mode === "local-file") {
|
|
2970
3127
|
try {
|
|
2971
|
-
await this._loadFromLocalFile(ctx,
|
|
3128
|
+
await this._loadFromLocalFile(ctx, src3.path, src3.fetchTimeoutMs);
|
|
2972
3129
|
ctx.logger.info("[MetadataPlugin] artifact reloaded via HMR POST", {
|
|
2973
|
-
path:
|
|
3130
|
+
path: src3.path,
|
|
2974
3131
|
reason: body?.reason
|
|
2975
3132
|
});
|
|
2976
3133
|
} catch (e) {
|
|
@@ -2979,6 +3136,53 @@ var MetadataPlugin = class {
|
|
|
2979
3136
|
}
|
|
2980
3137
|
}
|
|
2981
3138
|
});
|
|
3139
|
+
const src2 = this.options.artifactSource;
|
|
3140
|
+
const wantArtifactWatch = this.options.artifactWatch ?? src2?.mode === "local-file";
|
|
3141
|
+
if (src2?.mode === "local-file" && wantArtifactWatch && !/^https?:\/\//i.test(src2.path)) {
|
|
3142
|
+
try {
|
|
3143
|
+
const { watch: chokidarWatch2 } = await import("chokidar");
|
|
3144
|
+
const w = chokidarWatch2(src2.path, {
|
|
3145
|
+
ignoreInitial: true,
|
|
3146
|
+
awaitWriteFinish: { stabilityThreshold: 50, pollInterval: 20 },
|
|
3147
|
+
persistent: true,
|
|
3148
|
+
// Use polling to avoid `fs.watch` exhausting the
|
|
3149
|
+
// process file-descriptor limit on macOS (chokidar
|
|
3150
|
+
// recursively wires watches on the parent
|
|
3151
|
+
// directory tree which can trip EMFILE on busy
|
|
3152
|
+
// dev hosts). 500ms polling is fast enough for
|
|
3153
|
+
// HMR (a recompile takes ~400ms anyway).
|
|
3154
|
+
usePolling: true,
|
|
3155
|
+
interval: 500,
|
|
3156
|
+
binaryInterval: 1e3
|
|
3157
|
+
});
|
|
3158
|
+
let pending = false;
|
|
3159
|
+
const reload = async () => {
|
|
3160
|
+
if (pending) return;
|
|
3161
|
+
pending = true;
|
|
3162
|
+
try {
|
|
3163
|
+
await this._loadFromLocalFile(ctx, src2.path, src2.fetchTimeoutMs);
|
|
3164
|
+
hub.broadcastReload("artifact-file-changed", [src2.path]);
|
|
3165
|
+
ctx.logger.info("[MetadataPlugin] artifact auto-reloaded (file watcher)", {
|
|
3166
|
+
path: src2.path
|
|
3167
|
+
});
|
|
3168
|
+
} catch (e) {
|
|
3169
|
+
ctx.logger.warn("[MetadataPlugin] artifact auto-reload failed", { error: e?.message });
|
|
3170
|
+
} finally {
|
|
3171
|
+
pending = false;
|
|
3172
|
+
}
|
|
3173
|
+
};
|
|
3174
|
+
w.on("change", () => {
|
|
3175
|
+
void reload();
|
|
3176
|
+
});
|
|
3177
|
+
w.on("add", () => {
|
|
3178
|
+
void reload();
|
|
3179
|
+
});
|
|
3180
|
+
this.artifactWatcher = { close: () => w.close() };
|
|
3181
|
+
console.log("[MetadataPlugin] artifact file watcher attached", src2.path);
|
|
3182
|
+
} catch (e) {
|
|
3183
|
+
ctx.logger.warn("[MetadataPlugin] artifact watcher failed to start", { error: e?.message });
|
|
3184
|
+
}
|
|
3185
|
+
}
|
|
2982
3186
|
console.log("[MetadataPlugin] HMR endpoint registered at /api/v1/dev/metadata-events");
|
|
2983
3187
|
} else {
|
|
2984
3188
|
console.log("[MetadataPlugin] HTTP server with getRawApp() not available \u2014 skipping HMR endpoint");
|
|
@@ -2987,6 +3191,28 @@ var MetadataPlugin = class {
|
|
|
2987
3191
|
console.warn("[MetadataPlugin] Failed to register HMR endpoint", e?.message);
|
|
2988
3192
|
}
|
|
2989
3193
|
};
|
|
3194
|
+
this.stop = async (ctx) => {
|
|
3195
|
+
if (this.artifactWatcher) {
|
|
3196
|
+
try {
|
|
3197
|
+
await this.artifactWatcher.close();
|
|
3198
|
+
} catch {
|
|
3199
|
+
}
|
|
3200
|
+
this.artifactWatcher = void 0;
|
|
3201
|
+
}
|
|
3202
|
+
try {
|
|
3203
|
+
await this.manager.dispose();
|
|
3204
|
+
} catch (e) {
|
|
3205
|
+
ctx.logger.warn("[MetadataPlugin] manager.dispose() failed", { error: e?.message });
|
|
3206
|
+
}
|
|
3207
|
+
const repo = this.repository;
|
|
3208
|
+
if (repo && typeof repo.close === "function") {
|
|
3209
|
+
try {
|
|
3210
|
+
await repo.close();
|
|
3211
|
+
} catch {
|
|
3212
|
+
}
|
|
3213
|
+
}
|
|
3214
|
+
this.repository = void 0;
|
|
3215
|
+
};
|
|
2990
3216
|
this.options = {
|
|
2991
3217
|
watch: true,
|
|
2992
3218
|
...options
|
|
@@ -3063,7 +3289,12 @@ var MetadataPlugin = class {
|
|
|
3063
3289
|
const items = metadata[field];
|
|
3064
3290
|
if (!Array.isArray(items) || items.length === 0) continue;
|
|
3065
3291
|
for (const item of items) {
|
|
3066
|
-
|
|
3292
|
+
let name = item?.name;
|
|
3293
|
+
if (!name) {
|
|
3294
|
+
if (metaType === "view") {
|
|
3295
|
+
name = item?.list?.data?.object ?? item?.form?.data?.object;
|
|
3296
|
+
}
|
|
3297
|
+
}
|
|
3067
3298
|
if (!name) continue;
|
|
3068
3299
|
if (manifestPackageId && item._packageId === void 0) {
|
|
3069
3300
|
item._packageId = manifestPackageId;
|
|
@@ -3407,7 +3638,6 @@ var HistoryCleanupManager = class {
|
|
|
3407
3638
|
const driver = this.dbLoader.driver;
|
|
3408
3639
|
const historyTableName = this.dbLoader.historyTableName;
|
|
3409
3640
|
const organizationId = this.dbLoader.organizationId;
|
|
3410
|
-
const projectId = this.dbLoader.projectId;
|
|
3411
3641
|
let deleted = 0;
|
|
3412
3642
|
let errors = 0;
|
|
3413
3643
|
try {
|
|
@@ -3421,9 +3651,6 @@ var HistoryCleanupManager = class {
|
|
|
3421
3651
|
if (organizationId) {
|
|
3422
3652
|
filter.organization_id = organizationId;
|
|
3423
3653
|
}
|
|
3424
|
-
if (projectId !== void 0) {
|
|
3425
|
-
filter.project_id = projectId;
|
|
3426
|
-
}
|
|
3427
3654
|
try {
|
|
3428
3655
|
const result = await this.bulkDeleteByFilter(driver, historyTableName, filter);
|
|
3429
3656
|
deleted += result.deleted;
|
|
@@ -3436,7 +3663,6 @@ var HistoryCleanupManager = class {
|
|
|
3436
3663
|
try {
|
|
3437
3664
|
const baseWhere = {};
|
|
3438
3665
|
if (organizationId) baseWhere.organization_id = organizationId;
|
|
3439
|
-
if (projectId !== void 0) baseWhere.project_id = projectId;
|
|
3440
3666
|
const metadataIds = await driver.find(historyTableName, {
|
|
3441
3667
|
object: historyTableName,
|
|
3442
3668
|
where: baseWhere,
|
|
@@ -3524,13 +3750,11 @@ var HistoryCleanupManager = class {
|
|
|
3524
3750
|
const driver = this.dbLoader.driver;
|
|
3525
3751
|
const historyTableName = this.dbLoader.historyTableName;
|
|
3526
3752
|
const organizationId = this.dbLoader.organizationId;
|
|
3527
|
-
const projectId = this.dbLoader.projectId;
|
|
3528
3753
|
let recordsByAge = 0;
|
|
3529
3754
|
let recordsByCount = 0;
|
|
3530
3755
|
try {
|
|
3531
3756
|
const baseWhere = {};
|
|
3532
3757
|
if (organizationId) baseWhere.organization_id = organizationId;
|
|
3533
|
-
if (projectId !== void 0) baseWhere.project_id = projectId;
|
|
3534
3758
|
if (this.policy.maxAgeDays) {
|
|
3535
3759
|
const cutoffDate = /* @__PURE__ */ new Date();
|
|
3536
3760
|
cutoffDate.setDate(cutoffDate.getDate() - this.policy.maxAgeDays);
|