@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/node.cjs
CHANGED
|
@@ -64,7 +64,12 @@ function registerMetadataHmrRoutes(app, manager, options = {}) {
|
|
|
64
64
|
metadataType: evt.metadataType ?? type,
|
|
65
65
|
name: evt.name ?? "",
|
|
66
66
|
path: evt.path,
|
|
67
|
-
timestamp: Number.isFinite(ts) ? ts : Date.now()
|
|
67
|
+
timestamp: Number.isFinite(ts) ? ts : Date.now(),
|
|
68
|
+
// Forward the canonical server-side sequence number when the
|
|
69
|
+
// event originated from a MetadataRepository (ADR-0008). Legacy
|
|
70
|
+
// chokidar-driven events have no seq — clients fall back to
|
|
71
|
+
// their local counter in that case.
|
|
72
|
+
...typeof evt.seq === "number" ? { seq: evt.seq } : {}
|
|
68
73
|
});
|
|
69
74
|
});
|
|
70
75
|
}
|
|
@@ -605,7 +610,7 @@ var DatabaseLoader = class {
|
|
|
605
610
|
this.tableName = options.tableName ?? "sys_metadata";
|
|
606
611
|
this.historyTableName = options.historyTableName ?? "sys_metadata_history";
|
|
607
612
|
this.organizationId = options.organizationId;
|
|
608
|
-
|
|
613
|
+
void options.projectId;
|
|
609
614
|
this.trackHistory = options.trackHistory !== false;
|
|
610
615
|
const cacheOpts = options.cache;
|
|
611
616
|
const cacheEnabled = cacheOpts?.enabled !== false;
|
|
@@ -695,6 +700,26 @@ var DatabaseLoader = class {
|
|
|
695
700
|
}
|
|
696
701
|
return this.driver.delete(table, id);
|
|
697
702
|
}
|
|
703
|
+
/**
|
|
704
|
+
* Compute the next per-org `event_seq` for `sys_metadata_history`.
|
|
705
|
+
* Reads `MAX(event_seq) + 1` for the configured `organization_id`.
|
|
706
|
+
* Legacy path — not transactional, so concurrent writes can collide.
|
|
707
|
+
* The canonical (transactional) producer is `SysMetadataRepository`.
|
|
708
|
+
*/
|
|
709
|
+
async nextEventSeq() {
|
|
710
|
+
const where = this.organizationId ? { organization_id: this.organizationId } : {};
|
|
711
|
+
try {
|
|
712
|
+
const rows = await this._find(this.historyTableName, { where });
|
|
713
|
+
let max = 0;
|
|
714
|
+
for (const row of rows) {
|
|
715
|
+
const v = typeof row.event_seq === "number" ? row.event_seq : 0;
|
|
716
|
+
if (v > max) max = v;
|
|
717
|
+
}
|
|
718
|
+
return max + 1;
|
|
719
|
+
} catch {
|
|
720
|
+
return 1;
|
|
721
|
+
}
|
|
722
|
+
}
|
|
698
723
|
/**
|
|
699
724
|
* Ensure the metadata table exists.
|
|
700
725
|
* Uses IDataDriver.syncSchema with the SysMetadataObject definition
|
|
@@ -759,8 +784,9 @@ var DatabaseLoader = class {
|
|
|
759
784
|
}
|
|
760
785
|
/**
|
|
761
786
|
* Build base filter conditions for queries.
|
|
762
|
-
* Filters by organizationId when configured
|
|
763
|
-
*
|
|
787
|
+
* Filters by organizationId when configured. `projectId` is accepted
|
|
788
|
+
* for back-compat but no longer constrains the query — see
|
|
789
|
+
* ADR-0008 §0 (branch/project removal).
|
|
764
790
|
*/
|
|
765
791
|
baseFilter(type, name) {
|
|
766
792
|
const filter = { type };
|
|
@@ -770,7 +796,6 @@ var DatabaseLoader = class {
|
|
|
770
796
|
if (this.organizationId) {
|
|
771
797
|
filter.organization_id = this.organizationId;
|
|
772
798
|
}
|
|
773
|
-
filter.project_id = this.projectId ?? null;
|
|
774
799
|
return filter;
|
|
775
800
|
}
|
|
776
801
|
/**
|
|
@@ -796,6 +821,7 @@ var DatabaseLoader = class {
|
|
|
796
821
|
}
|
|
797
822
|
const historyId = generateId();
|
|
798
823
|
const metadataJson = JSON.stringify(metadata);
|
|
824
|
+
const eventSeq = await this.nextEventSeq();
|
|
799
825
|
const historyRecord = {
|
|
800
826
|
id: historyId,
|
|
801
827
|
metadataId,
|
|
@@ -809,12 +835,12 @@ var DatabaseLoader = class {
|
|
|
809
835
|
changeNote,
|
|
810
836
|
recordedBy,
|
|
811
837
|
recordedAt: now,
|
|
812
|
-
...this.organizationId ? { organizationId: this.organizationId } : {}
|
|
813
|
-
...this.projectId !== void 0 ? { projectId: this.projectId } : {}
|
|
838
|
+
...this.organizationId ? { organizationId: this.organizationId } : {}
|
|
814
839
|
};
|
|
815
840
|
try {
|
|
816
841
|
await this._create(this.historyTableName, {
|
|
817
842
|
id: historyRecord.id,
|
|
843
|
+
event_seq: eventSeq,
|
|
818
844
|
metadata_id: historyRecord.metadataId,
|
|
819
845
|
name: historyRecord.name,
|
|
820
846
|
type: historyRecord.type,
|
|
@@ -826,8 +852,8 @@ var DatabaseLoader = class {
|
|
|
826
852
|
change_note: historyRecord.changeNote,
|
|
827
853
|
recorded_by: historyRecord.recordedBy,
|
|
828
854
|
recorded_at: historyRecord.recordedAt,
|
|
829
|
-
|
|
830
|
-
...this.
|
|
855
|
+
source: "database-loader",
|
|
856
|
+
...this.organizationId ? { organization_id: this.organizationId } : {}
|
|
831
857
|
});
|
|
832
858
|
} catch (error) {
|
|
833
859
|
console.error(`Failed to create history record for ${type}/${name}:`, error);
|
|
@@ -1014,7 +1040,6 @@ var DatabaseLoader = class {
|
|
|
1014
1040
|
if (this.organizationId) {
|
|
1015
1041
|
filter.organization_id = this.organizationId;
|
|
1016
1042
|
}
|
|
1017
|
-
filter.project_id = this.projectId ?? null;
|
|
1018
1043
|
const row = await this._findOne(this.historyTableName, {
|
|
1019
1044
|
where: filter
|
|
1020
1045
|
});
|
|
@@ -1031,7 +1056,6 @@ var DatabaseLoader = class {
|
|
|
1031
1056
|
previousChecksum: row.previous_checksum,
|
|
1032
1057
|
changeNote: row.change_note,
|
|
1033
1058
|
organizationId: row.organization_id,
|
|
1034
|
-
projectId: row.project_id,
|
|
1035
1059
|
recordedBy: row.recorded_by,
|
|
1036
1060
|
recordedAt: row.recorded_at
|
|
1037
1061
|
};
|
|
@@ -1049,7 +1073,6 @@ var DatabaseLoader = class {
|
|
|
1049
1073
|
await this.ensureHistorySchema();
|
|
1050
1074
|
const filter = { type, name };
|
|
1051
1075
|
if (this.organizationId) filter.organization_id = this.organizationId;
|
|
1052
|
-
filter.project_id = this.projectId ?? null;
|
|
1053
1076
|
const metadataRecord = await this._findOne(this.tableName, { where: filter });
|
|
1054
1077
|
if (!metadataRecord) {
|
|
1055
1078
|
return { records: [], total: 0, hasMore: false };
|
|
@@ -1058,7 +1081,6 @@ var DatabaseLoader = class {
|
|
|
1058
1081
|
metadata_id: metadataRecord.id
|
|
1059
1082
|
};
|
|
1060
1083
|
if (this.organizationId) historyFilter.organization_id = this.organizationId;
|
|
1061
|
-
historyFilter.project_id = this.projectId ?? null;
|
|
1062
1084
|
if (options?.operationType) historyFilter.operation_type = options.operationType;
|
|
1063
1085
|
if (options?.since) historyFilter.recorded_at = { $gte: options.since };
|
|
1064
1086
|
if (options?.until) {
|
|
@@ -1097,7 +1119,6 @@ var DatabaseLoader = class {
|
|
|
1097
1119
|
previousChecksum: row.previous_checksum,
|
|
1098
1120
|
changeNote: row.change_note,
|
|
1099
1121
|
organizationId: row.organization_id,
|
|
1100
|
-
projectId: row.project_id,
|
|
1101
1122
|
recordedBy: row.recorded_by,
|
|
1102
1123
|
recordedAt: row.recorded_at
|
|
1103
1124
|
};
|
|
@@ -1204,7 +1225,6 @@ var DatabaseLoader = class {
|
|
|
1204
1225
|
version: 1,
|
|
1205
1226
|
source: "database",
|
|
1206
1227
|
...this.organizationId ? { organization_id: this.organizationId } : {},
|
|
1207
|
-
...this.projectId !== void 0 ? { project_id: this.projectId } : { project_id: null },
|
|
1208
1228
|
created_at: now,
|
|
1209
1229
|
updated_at: now
|
|
1210
1230
|
});
|
|
@@ -1277,6 +1297,7 @@ var _MetadataManager = class _MetadataManager {
|
|
|
1277
1297
|
// Invalidated on every `register()` / `unregister()` to keep CRUD writes
|
|
1278
1298
|
// visible to subsequent reads.
|
|
1279
1299
|
this.listCache = /* @__PURE__ */ new Map();
|
|
1300
|
+
this.repoWatchClosed = false;
|
|
1280
1301
|
this.config = config;
|
|
1281
1302
|
this.logger = (0, import_core.createLogger)({ level: "info", format: "pretty" });
|
|
1282
1303
|
this.serializers = /* @__PURE__ */ new Map();
|
|
@@ -2284,6 +2305,110 @@ var _MetadataManager = class _MetadataManager {
|
|
|
2284
2305
|
*/
|
|
2285
2306
|
async stopWatching() {
|
|
2286
2307
|
}
|
|
2308
|
+
// ─── ADR-0008 PR-6: Repository wiring ───────────────────────────────
|
|
2309
|
+
/**
|
|
2310
|
+
* Attach a {@link MetadataRepository} as a supplementary event source.
|
|
2311
|
+
*
|
|
2312
|
+
* The manager subscribes to `repo.watch({})` and re-emits each event
|
|
2313
|
+
* through {@link notifyWatchers} as a legacy `MetadataWatchEvent`.
|
|
2314
|
+
* Each event also invalidates the in-memory registry entry and the
|
|
2315
|
+
* `list()` cache for the affected type so subsequent reads see fresh
|
|
2316
|
+
* data.
|
|
2317
|
+
*
|
|
2318
|
+
* No write-through. `register()` / `unregister()` / `save()` are
|
|
2319
|
+
* untouched in this PR (deferred to ADR-0008 M0 PR-10).
|
|
2320
|
+
*
|
|
2321
|
+
* Call {@link dispose} (or {@link stopRepositoryWatch}) to detach.
|
|
2322
|
+
*/
|
|
2323
|
+
setRepository(repo) {
|
|
2324
|
+
if (this.repository === repo) return;
|
|
2325
|
+
if (this.repository) {
|
|
2326
|
+
void this.stopRepositoryWatch();
|
|
2327
|
+
}
|
|
2328
|
+
this.repository = repo;
|
|
2329
|
+
this.repoWatchClosed = false;
|
|
2330
|
+
void this.startRepositoryWatch();
|
|
2331
|
+
}
|
|
2332
|
+
/** Return the attached repository, if any. */
|
|
2333
|
+
getRepository() {
|
|
2334
|
+
return this.repository;
|
|
2335
|
+
}
|
|
2336
|
+
/** Stop the active repo.watch() loop (best-effort). */
|
|
2337
|
+
async stopRepositoryWatch() {
|
|
2338
|
+
this.repoWatchClosed = true;
|
|
2339
|
+
const iter = this.repoWatchIter;
|
|
2340
|
+
this.repoWatchIter = void 0;
|
|
2341
|
+
if (iter && typeof iter.return === "function") {
|
|
2342
|
+
try {
|
|
2343
|
+
await iter.return(void 0);
|
|
2344
|
+
} catch {
|
|
2345
|
+
}
|
|
2346
|
+
}
|
|
2347
|
+
}
|
|
2348
|
+
/**
|
|
2349
|
+
* Best-effort cleanup. Stops the FS watcher (if any), drains the
|
|
2350
|
+
* repository watch loop, and clears registry caches. Safe to call
|
|
2351
|
+
* multiple times.
|
|
2352
|
+
*/
|
|
2353
|
+
async dispose() {
|
|
2354
|
+
await this.stopWatching().catch(() => void 0);
|
|
2355
|
+
await this.stopRepositoryWatch().catch(() => void 0);
|
|
2356
|
+
this.listCache.clear();
|
|
2357
|
+
}
|
|
2358
|
+
async startRepositoryWatch() {
|
|
2359
|
+
const repo = this.repository;
|
|
2360
|
+
if (!repo) return;
|
|
2361
|
+
const iterable = repo.watch({});
|
|
2362
|
+
const iter = iterable[Symbol.asyncIterator]();
|
|
2363
|
+
this.repoWatchIter = iter;
|
|
2364
|
+
try {
|
|
2365
|
+
while (!this.repoWatchClosed) {
|
|
2366
|
+
const { value, done } = await iter.next();
|
|
2367
|
+
if (done) break;
|
|
2368
|
+
try {
|
|
2369
|
+
this.applyRepoEvent(value);
|
|
2370
|
+
} catch (err) {
|
|
2371
|
+
this.logger.warn("[MetadataManager] repo event handler failed", {
|
|
2372
|
+
error: err instanceof Error ? err.message : String(err)
|
|
2373
|
+
});
|
|
2374
|
+
}
|
|
2375
|
+
}
|
|
2376
|
+
} catch (err) {
|
|
2377
|
+
if (!this.repoWatchClosed) {
|
|
2378
|
+
this.logger.warn("[MetadataManager] repository watch loop exited unexpectedly", {
|
|
2379
|
+
error: err instanceof Error ? err.message : String(err)
|
|
2380
|
+
});
|
|
2381
|
+
}
|
|
2382
|
+
} finally {
|
|
2383
|
+
if (this.repoWatchIter === iter) this.repoWatchIter = void 0;
|
|
2384
|
+
}
|
|
2385
|
+
}
|
|
2386
|
+
/** Translate a repo event to the legacy MetadataWatchEvent + invalidate caches. */
|
|
2387
|
+
applyRepoEvent(evt) {
|
|
2388
|
+
const ref = evt.ref;
|
|
2389
|
+
const type = ref.type;
|
|
2390
|
+
const name = ref.name;
|
|
2391
|
+
const typeStore = this.registry.get(type);
|
|
2392
|
+
if (typeStore) {
|
|
2393
|
+
typeStore.delete(name);
|
|
2394
|
+
if (typeStore.size === 0) this.registry.delete(type);
|
|
2395
|
+
}
|
|
2396
|
+
this.listCache.delete(type);
|
|
2397
|
+
const legacyType = evt.op === "create" ? "added" : evt.op === "delete" ? "deleted" : "changed";
|
|
2398
|
+
const legacyEvent = {
|
|
2399
|
+
type: legacyType,
|
|
2400
|
+
metadataType: type,
|
|
2401
|
+
name,
|
|
2402
|
+
path: "",
|
|
2403
|
+
// Repo events carry the hash only; the body is fetched on demand
|
|
2404
|
+
// via manager.get(type, name). HMR consumers don't read `data` so
|
|
2405
|
+
// this is fine for M0. (See ADR-0008 §12 open question 1.)
|
|
2406
|
+
data: void 0,
|
|
2407
|
+
timestamp: evt.ts
|
|
2408
|
+
};
|
|
2409
|
+
legacyEvent.seq = evt.seq;
|
|
2410
|
+
this.notifyWatchers(type, legacyEvent);
|
|
2411
|
+
}
|
|
2287
2412
|
notifyWatchers(type, event) {
|
|
2288
2413
|
const callbacks = this.watchCallbacks.get(type);
|
|
2289
2414
|
if (!callbacks) return;
|
|
@@ -2759,7 +2884,13 @@ var NodeMetadataManager = class extends MetadataManager {
|
|
|
2759
2884
|
this.watcher = (0, import_chokidar.watch)(rootDir, {
|
|
2760
2885
|
ignored,
|
|
2761
2886
|
persistent,
|
|
2762
|
-
ignoreInitial: true
|
|
2887
|
+
ignoreInitial: true,
|
|
2888
|
+
// Use polling to avoid `fs.watch` EMFILE on macOS / busy dev hosts.
|
|
2889
|
+
// Recursive watch over a project root would otherwise wire native
|
|
2890
|
+
// watches across the entire tree, easily exhausting the FD pool.
|
|
2891
|
+
usePolling: true,
|
|
2892
|
+
interval: 1e3,
|
|
2893
|
+
binaryInterval: 2e3
|
|
2763
2894
|
});
|
|
2764
2895
|
this.watcher.on("add", async (filePath) => {
|
|
2765
2896
|
await this.handleFileEvent("added", filePath);
|
|
@@ -2894,6 +3025,7 @@ var queryableMetadataObjects = [
|
|
|
2894
3025
|
import_metadata2.SysMetadataObject,
|
|
2895
3026
|
import_metadata2.SysMetadataHistoryObject
|
|
2896
3027
|
];
|
|
3028
|
+
var REPO_SUBDIR = ".objectstack/metadata";
|
|
2897
3029
|
var ARTIFACT_FIELD_TO_TYPE = {
|
|
2898
3030
|
objects: "object",
|
|
2899
3031
|
objectExtensions: "object_extension",
|
|
@@ -2991,6 +3123,31 @@ var MetadataPlugin = class {
|
|
|
2991
3123
|
await this._loadFromFileSystem(ctx);
|
|
2992
3124
|
}
|
|
2993
3125
|
}
|
|
3126
|
+
const bootstrapMode = this.options.config?.bootstrap ?? "eager";
|
|
3127
|
+
if (bootstrapMode !== "artifact-only") {
|
|
3128
|
+
try {
|
|
3129
|
+
const path3 = await import("path");
|
|
3130
|
+
const { FileSystemRepository } = await import("@objectstack/metadata-fs");
|
|
3131
|
+
const rootDir = this.options.rootDir || process.cwd();
|
|
3132
|
+
const repoRoot = path3.join(rootDir, REPO_SUBDIR);
|
|
3133
|
+
const repo = new FileSystemRepository({
|
|
3134
|
+
root: repoRoot,
|
|
3135
|
+
org: this.options.organizationId ?? "system",
|
|
3136
|
+
disableWatch: this.options.watch === false
|
|
3137
|
+
});
|
|
3138
|
+
await repo.start();
|
|
3139
|
+
this.repository = repo;
|
|
3140
|
+
this.manager.setRepository(repo);
|
|
3141
|
+
ctx.logger.info("[MetadataPlugin] FileSystemRepository attached", {
|
|
3142
|
+
repoRoot,
|
|
3143
|
+
watch: this.options.watch !== false
|
|
3144
|
+
});
|
|
3145
|
+
} catch (e) {
|
|
3146
|
+
ctx.logger.warn("[MetadataPlugin] Failed to attach FileSystemRepository", {
|
|
3147
|
+
error: e?.message
|
|
3148
|
+
});
|
|
3149
|
+
}
|
|
3150
|
+
}
|
|
2994
3151
|
try {
|
|
2995
3152
|
const realtimeService = ctx.getService("realtime");
|
|
2996
3153
|
if (realtimeService && typeof realtimeService === "object" && "publish" in realtimeService) {
|
|
@@ -3008,12 +3165,12 @@ var MetadataPlugin = class {
|
|
|
3008
3165
|
const { registerMetadataHmrRoutes: registerMetadataHmrRoutes2 } = await Promise.resolve().then(() => (init_hmr_routes(), hmr_routes_exports));
|
|
3009
3166
|
const hub = registerMetadataHmrRoutes2(httpServer.getRawApp(), this.manager);
|
|
3010
3167
|
hub.setOnPostReload(async (body = {}) => {
|
|
3011
|
-
const
|
|
3012
|
-
if (
|
|
3168
|
+
const src3 = this.options.artifactSource;
|
|
3169
|
+
if (src3?.mode === "local-file") {
|
|
3013
3170
|
try {
|
|
3014
|
-
await this._loadFromLocalFile(ctx,
|
|
3171
|
+
await this._loadFromLocalFile(ctx, src3.path, src3.fetchTimeoutMs);
|
|
3015
3172
|
ctx.logger.info("[MetadataPlugin] artifact reloaded via HMR POST", {
|
|
3016
|
-
path:
|
|
3173
|
+
path: src3.path,
|
|
3017
3174
|
reason: body?.reason
|
|
3018
3175
|
});
|
|
3019
3176
|
} catch (e) {
|
|
@@ -3022,6 +3179,53 @@ var MetadataPlugin = class {
|
|
|
3022
3179
|
}
|
|
3023
3180
|
}
|
|
3024
3181
|
});
|
|
3182
|
+
const src2 = this.options.artifactSource;
|
|
3183
|
+
const wantArtifactWatch = this.options.artifactWatch ?? src2?.mode === "local-file";
|
|
3184
|
+
if (src2?.mode === "local-file" && wantArtifactWatch && !/^https?:\/\//i.test(src2.path)) {
|
|
3185
|
+
try {
|
|
3186
|
+
const { watch: chokidarWatch2 } = await import("chokidar");
|
|
3187
|
+
const w = chokidarWatch2(src2.path, {
|
|
3188
|
+
ignoreInitial: true,
|
|
3189
|
+
awaitWriteFinish: { stabilityThreshold: 50, pollInterval: 20 },
|
|
3190
|
+
persistent: true,
|
|
3191
|
+
// Use polling to avoid `fs.watch` exhausting the
|
|
3192
|
+
// process file-descriptor limit on macOS (chokidar
|
|
3193
|
+
// recursively wires watches on the parent
|
|
3194
|
+
// directory tree which can trip EMFILE on busy
|
|
3195
|
+
// dev hosts). 500ms polling is fast enough for
|
|
3196
|
+
// HMR (a recompile takes ~400ms anyway).
|
|
3197
|
+
usePolling: true,
|
|
3198
|
+
interval: 500,
|
|
3199
|
+
binaryInterval: 1e3
|
|
3200
|
+
});
|
|
3201
|
+
let pending = false;
|
|
3202
|
+
const reload = async () => {
|
|
3203
|
+
if (pending) return;
|
|
3204
|
+
pending = true;
|
|
3205
|
+
try {
|
|
3206
|
+
await this._loadFromLocalFile(ctx, src2.path, src2.fetchTimeoutMs);
|
|
3207
|
+
hub.broadcastReload("artifact-file-changed", [src2.path]);
|
|
3208
|
+
ctx.logger.info("[MetadataPlugin] artifact auto-reloaded (file watcher)", {
|
|
3209
|
+
path: src2.path
|
|
3210
|
+
});
|
|
3211
|
+
} catch (e) {
|
|
3212
|
+
ctx.logger.warn("[MetadataPlugin] artifact auto-reload failed", { error: e?.message });
|
|
3213
|
+
} finally {
|
|
3214
|
+
pending = false;
|
|
3215
|
+
}
|
|
3216
|
+
};
|
|
3217
|
+
w.on("change", () => {
|
|
3218
|
+
void reload();
|
|
3219
|
+
});
|
|
3220
|
+
w.on("add", () => {
|
|
3221
|
+
void reload();
|
|
3222
|
+
});
|
|
3223
|
+
this.artifactWatcher = { close: () => w.close() };
|
|
3224
|
+
console.log("[MetadataPlugin] artifact file watcher attached", src2.path);
|
|
3225
|
+
} catch (e) {
|
|
3226
|
+
ctx.logger.warn("[MetadataPlugin] artifact watcher failed to start", { error: e?.message });
|
|
3227
|
+
}
|
|
3228
|
+
}
|
|
3025
3229
|
console.log("[MetadataPlugin] HMR endpoint registered at /api/v1/dev/metadata-events");
|
|
3026
3230
|
} else {
|
|
3027
3231
|
console.log("[MetadataPlugin] HTTP server with getRawApp() not available \u2014 skipping HMR endpoint");
|
|
@@ -3030,6 +3234,28 @@ var MetadataPlugin = class {
|
|
|
3030
3234
|
console.warn("[MetadataPlugin] Failed to register HMR endpoint", e?.message);
|
|
3031
3235
|
}
|
|
3032
3236
|
};
|
|
3237
|
+
this.stop = async (ctx) => {
|
|
3238
|
+
if (this.artifactWatcher) {
|
|
3239
|
+
try {
|
|
3240
|
+
await this.artifactWatcher.close();
|
|
3241
|
+
} catch {
|
|
3242
|
+
}
|
|
3243
|
+
this.artifactWatcher = void 0;
|
|
3244
|
+
}
|
|
3245
|
+
try {
|
|
3246
|
+
await this.manager.dispose();
|
|
3247
|
+
} catch (e) {
|
|
3248
|
+
ctx.logger.warn("[MetadataPlugin] manager.dispose() failed", { error: e?.message });
|
|
3249
|
+
}
|
|
3250
|
+
const repo = this.repository;
|
|
3251
|
+
if (repo && typeof repo.close === "function") {
|
|
3252
|
+
try {
|
|
3253
|
+
await repo.close();
|
|
3254
|
+
} catch {
|
|
3255
|
+
}
|
|
3256
|
+
}
|
|
3257
|
+
this.repository = void 0;
|
|
3258
|
+
};
|
|
3033
3259
|
this.options = {
|
|
3034
3260
|
watch: true,
|
|
3035
3261
|
...options
|
|
@@ -3106,7 +3332,12 @@ var MetadataPlugin = class {
|
|
|
3106
3332
|
const items = metadata[field];
|
|
3107
3333
|
if (!Array.isArray(items) || items.length === 0) continue;
|
|
3108
3334
|
for (const item of items) {
|
|
3109
|
-
|
|
3335
|
+
let name = item?.name;
|
|
3336
|
+
if (!name) {
|
|
3337
|
+
if (metaType === "view") {
|
|
3338
|
+
name = item?.list?.data?.object ?? item?.form?.data?.object;
|
|
3339
|
+
}
|
|
3340
|
+
}
|
|
3110
3341
|
if (!name) continue;
|
|
3111
3342
|
if (manifestPackageId && item._packageId === void 0) {
|
|
3112
3343
|
item._packageId = manifestPackageId;
|
|
@@ -3450,7 +3681,6 @@ var HistoryCleanupManager = class {
|
|
|
3450
3681
|
const driver = this.dbLoader.driver;
|
|
3451
3682
|
const historyTableName = this.dbLoader.historyTableName;
|
|
3452
3683
|
const organizationId = this.dbLoader.organizationId;
|
|
3453
|
-
const projectId = this.dbLoader.projectId;
|
|
3454
3684
|
let deleted = 0;
|
|
3455
3685
|
let errors = 0;
|
|
3456
3686
|
try {
|
|
@@ -3464,9 +3694,6 @@ var HistoryCleanupManager = class {
|
|
|
3464
3694
|
if (organizationId) {
|
|
3465
3695
|
filter.organization_id = organizationId;
|
|
3466
3696
|
}
|
|
3467
|
-
if (projectId !== void 0) {
|
|
3468
|
-
filter.project_id = projectId;
|
|
3469
|
-
}
|
|
3470
3697
|
try {
|
|
3471
3698
|
const result = await this.bulkDeleteByFilter(driver, historyTableName, filter);
|
|
3472
3699
|
deleted += result.deleted;
|
|
@@ -3479,7 +3706,6 @@ var HistoryCleanupManager = class {
|
|
|
3479
3706
|
try {
|
|
3480
3707
|
const baseWhere = {};
|
|
3481
3708
|
if (organizationId) baseWhere.organization_id = organizationId;
|
|
3482
|
-
if (projectId !== void 0) baseWhere.project_id = projectId;
|
|
3483
3709
|
const metadataIds = await driver.find(historyTableName, {
|
|
3484
3710
|
object: historyTableName,
|
|
3485
3711
|
where: baseWhere,
|
|
@@ -3567,13 +3793,11 @@ var HistoryCleanupManager = class {
|
|
|
3567
3793
|
const driver = this.dbLoader.driver;
|
|
3568
3794
|
const historyTableName = this.dbLoader.historyTableName;
|
|
3569
3795
|
const organizationId = this.dbLoader.organizationId;
|
|
3570
|
-
const projectId = this.dbLoader.projectId;
|
|
3571
3796
|
let recordsByAge = 0;
|
|
3572
3797
|
let recordsByCount = 0;
|
|
3573
3798
|
try {
|
|
3574
3799
|
const baseWhere = {};
|
|
3575
3800
|
if (organizationId) baseWhere.organization_id = organizationId;
|
|
3576
|
-
if (projectId !== void 0) baseWhere.project_id = projectId;
|
|
3577
3801
|
if (this.policy.maxAgeDays) {
|
|
3578
3802
|
const cutoffDate = /* @__PURE__ */ new Date();
|
|
3579
3803
|
cutoffDate.setDate(cutoffDate.getDate() - this.policy.maxAgeDays);
|