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