@objectstack/objectql 7.8.0 → 7.9.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.d.mts +100 -1
- package/dist/index.d.ts +100 -1
- package/dist/index.js +216 -0
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +216 -0
- package/dist/index.mjs.map +1 -1
- package/package.json +6 -6
package/dist/index.mjs
CHANGED
|
@@ -2386,6 +2386,44 @@ var _ObjectStackProtocolImplementation = class _ObjectStackProtocolImplementatio
|
|
|
2386
2386
|
}
|
|
2387
2387
|
} catch {
|
|
2388
2388
|
}
|
|
2389
|
+
if (request.previewDrafts) {
|
|
2390
|
+
try {
|
|
2391
|
+
const orgId = request.organizationId;
|
|
2392
|
+
const queryDrafts = async (oid) => {
|
|
2393
|
+
const whereClause = { type: request.type, state: "draft", organization_id: oid };
|
|
2394
|
+
if (packageId) whereClause.package_id = packageId;
|
|
2395
|
+
let rs = await this.engine.find("sys_metadata", { where: whereClause });
|
|
2396
|
+
if (!rs || rs.length === 0) {
|
|
2397
|
+
const alt = PLURAL_TO_SINGULAR3[request.type] ?? SINGULAR_TO_PLURAL2[request.type];
|
|
2398
|
+
if (alt) {
|
|
2399
|
+
const altWhere = { type: alt, state: "draft", organization_id: oid };
|
|
2400
|
+
if (packageId) altWhere.package_id = packageId;
|
|
2401
|
+
rs = await this.engine.find("sys_metadata", { where: altWhere });
|
|
2402
|
+
}
|
|
2403
|
+
}
|
|
2404
|
+
return rs ?? [];
|
|
2405
|
+
};
|
|
2406
|
+
const draftRecords = [...await queryDrafts(null), ...orgId ? await queryDrafts(orgId) : []];
|
|
2407
|
+
if (draftRecords.length > 0) {
|
|
2408
|
+
const byName = /* @__PURE__ */ new Map();
|
|
2409
|
+
for (const existing of items) {
|
|
2410
|
+
const entry = existing;
|
|
2411
|
+
if (entry && typeof entry === "object" && "name" in entry) byName.set(entry.name, entry);
|
|
2412
|
+
}
|
|
2413
|
+
for (const record of draftRecords) {
|
|
2414
|
+
const data = typeof record.metadata === "string" ? JSON.parse(record.metadata) : record.metadata;
|
|
2415
|
+
if (data && typeof data === "object" && "name" in data) {
|
|
2416
|
+
const recPkg = record.package_id ?? void 0;
|
|
2417
|
+
if (recPkg && data._packageId === void 0) data._packageId = recPkg;
|
|
2418
|
+
data._draft = true;
|
|
2419
|
+
byName.set(data.name, data);
|
|
2420
|
+
}
|
|
2421
|
+
}
|
|
2422
|
+
items = Array.from(byName.values());
|
|
2423
|
+
}
|
|
2424
|
+
} catch {
|
|
2425
|
+
}
|
|
2426
|
+
}
|
|
2389
2427
|
try {
|
|
2390
2428
|
const services = this.getServicesRegistry?.();
|
|
2391
2429
|
const metadataService = services?.get("metadata");
|
|
@@ -2444,6 +2482,34 @@ var _ObjectStackProtocolImplementation = class _ObjectStackProtocolImplementatio
|
|
|
2444
2482
|
let item;
|
|
2445
2483
|
const orgId = request.organizationId;
|
|
2446
2484
|
const readState = request.state === "draft" ? "draft" : "active";
|
|
2485
|
+
if (request.previewDrafts && readState !== "draft") {
|
|
2486
|
+
try {
|
|
2487
|
+
const findDraft = async (oid) => {
|
|
2488
|
+
const rec = await this.engine.findOne("sys_metadata", {
|
|
2489
|
+
where: { type: request.type, name: request.name, state: "draft", organization_id: oid }
|
|
2490
|
+
});
|
|
2491
|
+
if (rec) return rec;
|
|
2492
|
+
const alt = PLURAL_TO_SINGULAR3[request.type] ?? SINGULAR_TO_PLURAL2[request.type];
|
|
2493
|
+
if (alt) {
|
|
2494
|
+
return await this.engine.findOne("sys_metadata", {
|
|
2495
|
+
where: { type: alt, name: request.name, state: "draft", organization_id: oid }
|
|
2496
|
+
});
|
|
2497
|
+
}
|
|
2498
|
+
return void 0;
|
|
2499
|
+
};
|
|
2500
|
+
const draftRec = (orgId ? await findDraft(orgId) : void 0) ?? await findDraft(null);
|
|
2501
|
+
if (draftRec) {
|
|
2502
|
+
const draftItem = typeof draftRec.metadata === "string" ? JSON.parse(draftRec.metadata) : draftRec.metadata;
|
|
2503
|
+
if (draftItem && typeof draftItem === "object") {
|
|
2504
|
+
const recPkg = draftRec.package_id ?? void 0;
|
|
2505
|
+
if (recPkg && draftItem._packageId === void 0) draftItem._packageId = recPkg;
|
|
2506
|
+
draftItem._draft = true;
|
|
2507
|
+
}
|
|
2508
|
+
return { type: request.type, name: request.name, item: decorateMetadataItem(request.type, draftItem) };
|
|
2509
|
+
}
|
|
2510
|
+
} catch {
|
|
2511
|
+
}
|
|
2512
|
+
}
|
|
2447
2513
|
try {
|
|
2448
2514
|
const findOverlay = async (oid) => {
|
|
2449
2515
|
const where = {
|
|
@@ -3818,6 +3884,37 @@ var _ObjectStackProtocolImplementation = class _ObjectStackProtocolImplementatio
|
|
|
3818
3884
|
console.warn(`[Protocol] table sync failed for object '${name}': ${err?.message ?? err}`);
|
|
3819
3885
|
}
|
|
3820
3886
|
}
|
|
3887
|
+
/**
|
|
3888
|
+
* Inverse of {@link ensureObjectStorage}: drop an object's physical table.
|
|
3889
|
+
* DESTRUCTIVE — deletes the table and all its rows. Only invoked when a
|
|
3890
|
+
* delete explicitly opts into storage teardown (see {@link deleteMetaItem}'s
|
|
3891
|
+
* `dropStorage`), so publishing an object solely to preview it can be undone
|
|
3892
|
+
* without leaving an orphan table. Best-effort: a failure is logged, not
|
|
3893
|
+
* thrown — the metadata delete already succeeded, and a stray table is
|
|
3894
|
+
* reclaimed by the next sync/drop rather than blocking the delete.
|
|
3895
|
+
*/
|
|
3896
|
+
async dropObjectStorage(type, name) {
|
|
3897
|
+
if (type !== "object" && type !== "objects") return;
|
|
3898
|
+
try {
|
|
3899
|
+
await this.engine.dropObjectSchema(name);
|
|
3900
|
+
} catch (err) {
|
|
3901
|
+
console.warn(`[Protocol] table drop failed for object '${name}': ${err?.message ?? err}`);
|
|
3902
|
+
}
|
|
3903
|
+
}
|
|
3904
|
+
/**
|
|
3905
|
+
* Guard for storage teardown on delete. Drops a physical table only when
|
|
3906
|
+
* the caller opted in AND it is safe: object types only (others have no
|
|
3907
|
+
* table), active state only (drafts were never materialised), and never a
|
|
3908
|
+
* `sys_`-prefixed platform table.
|
|
3909
|
+
*/
|
|
3910
|
+
shouldDropStorage(type, name, dropStorage, state) {
|
|
3911
|
+
if (!dropStorage) return false;
|
|
3912
|
+
const singular = PLURAL_TO_SINGULAR3[type] ?? type;
|
|
3913
|
+
if (singular !== "object") return false;
|
|
3914
|
+
if (state !== "active") return false;
|
|
3915
|
+
if (name.startsWith("sys_")) return false;
|
|
3916
|
+
return true;
|
|
3917
|
+
}
|
|
3821
3918
|
async saveMetaItem(request) {
|
|
3822
3919
|
if (!request.item) {
|
|
3823
3920
|
throw new Error("Item data is required");
|
|
@@ -4198,6 +4295,100 @@ var _ObjectStackProtocolImplementation = class _ObjectStackProtocolImplementatio
|
|
|
4198
4295
|
failed
|
|
4199
4296
|
};
|
|
4200
4297
|
}
|
|
4298
|
+
/**
|
|
4299
|
+
* Discard every pending DRAFT bound to a package — the NON-destructive
|
|
4300
|
+
* inverse of {@link publishPackageDrafts}. Drops only `state='draft'` rows
|
|
4301
|
+
* (via the per-item delete primitive), reverting the package to its last
|
|
4302
|
+
* published baseline; active/published metadata and physical tables are
|
|
4303
|
+
* left untouched.
|
|
4304
|
+
*
|
|
4305
|
+
* Use case: "I edited this app for a while and it turned out worse than
|
|
4306
|
+
* before — abandon all my changes." Routes through the sys_metadata path
|
|
4307
|
+
* (no metadata-service dependency, unlike `POST /packages/:id/revert`).
|
|
4308
|
+
*/
|
|
4309
|
+
async discardPackageDrafts(request) {
|
|
4310
|
+
await this.ensureOverlayIndex();
|
|
4311
|
+
const orgId = request.organizationId ?? null;
|
|
4312
|
+
const repo = this.getOverlayRepo(orgId);
|
|
4313
|
+
const drafts = await repo.listDrafts({ packageId: request.packageId });
|
|
4314
|
+
const discarded = [];
|
|
4315
|
+
const failed = [];
|
|
4316
|
+
for (const d of drafts) {
|
|
4317
|
+
try {
|
|
4318
|
+
await this.deleteMetaItem({
|
|
4319
|
+
type: d.type,
|
|
4320
|
+
name: d.name,
|
|
4321
|
+
state: "draft",
|
|
4322
|
+
...request.organizationId ? { organizationId: request.organizationId } : {},
|
|
4323
|
+
...request.actor ? { actor: request.actor } : {}
|
|
4324
|
+
});
|
|
4325
|
+
discarded.push({ type: d.type, name: d.name });
|
|
4326
|
+
} catch (e) {
|
|
4327
|
+
failed.push({
|
|
4328
|
+
type: d.type,
|
|
4329
|
+
name: d.name,
|
|
4330
|
+
error: e?.message ?? "discard failed",
|
|
4331
|
+
...e?.code ? { code: e.code } : {}
|
|
4332
|
+
});
|
|
4333
|
+
}
|
|
4334
|
+
}
|
|
4335
|
+
return {
|
|
4336
|
+
success: failed.length === 0 && discarded.length > 0,
|
|
4337
|
+
discardedCount: discarded.length,
|
|
4338
|
+
failedCount: failed.length,
|
|
4339
|
+
discarded,
|
|
4340
|
+
failed
|
|
4341
|
+
};
|
|
4342
|
+
}
|
|
4343
|
+
/**
|
|
4344
|
+
* Delete an ENTIRE package: every `sys_metadata` row bound to it (active
|
|
4345
|
+
* AND draft) and — by default — the physical table of each object it
|
|
4346
|
+
* defined. DESTRUCTIVE: removes the app and its data. Use case: "I don't
|
|
4347
|
+
* want this package anymore."
|
|
4348
|
+
*
|
|
4349
|
+
* Set `keepData: true` to remove the metadata but preserve object tables.
|
|
4350
|
+
* The `sys_`-table guard in {@link deleteMetaItem} still applies, so
|
|
4351
|
+
* platform storage is never dropped. Drafts are removed before active rows
|
|
4352
|
+
* so each object's table is torn down once. Per-item failures are collected
|
|
4353
|
+
* without aborting the rest.
|
|
4354
|
+
*/
|
|
4355
|
+
async deletePackage(request) {
|
|
4356
|
+
const where = { package_id: request.packageId };
|
|
4357
|
+
if (request.organizationId) where.organization_id = request.organizationId;
|
|
4358
|
+
const rows = await this.engine.find("sys_metadata", { where });
|
|
4359
|
+
const dropStorage = request.keepData !== true;
|
|
4360
|
+
const ordered = [...rows].sort((a, b) => (a.state === "draft" ? 0 : 1) - (b.state === "draft" ? 0 : 1));
|
|
4361
|
+
const deleted = [];
|
|
4362
|
+
const failed = [];
|
|
4363
|
+
for (const row of ordered) {
|
|
4364
|
+
const state = row.state === "draft" ? "draft" : "active";
|
|
4365
|
+
try {
|
|
4366
|
+
await this.deleteMetaItem({
|
|
4367
|
+
type: row.type,
|
|
4368
|
+
name: row.name,
|
|
4369
|
+
state,
|
|
4370
|
+
...row.organization_id ? { organizationId: row.organization_id } : {},
|
|
4371
|
+
...request.actor ? { actor: request.actor } : {},
|
|
4372
|
+
...dropStorage ? { dropStorage: true } : {}
|
|
4373
|
+
});
|
|
4374
|
+
deleted.push({ type: row.type, name: row.name, state });
|
|
4375
|
+
} catch (e) {
|
|
4376
|
+
failed.push({
|
|
4377
|
+
type: row.type,
|
|
4378
|
+
name: row.name,
|
|
4379
|
+
error: e?.message ?? "delete failed",
|
|
4380
|
+
...e?.code ? { code: e.code } : {}
|
|
4381
|
+
});
|
|
4382
|
+
}
|
|
4383
|
+
}
|
|
4384
|
+
return {
|
|
4385
|
+
success: failed.length === 0 && deleted.length > 0,
|
|
4386
|
+
deletedCount: deleted.length,
|
|
4387
|
+
failedCount: failed.length,
|
|
4388
|
+
deleted,
|
|
4389
|
+
failed
|
|
4390
|
+
};
|
|
4391
|
+
}
|
|
4201
4392
|
/**
|
|
4202
4393
|
* Restore the body recorded at history `toVersion` as the new
|
|
4203
4394
|
* live row. Writes a history event with `op='revert'`. 404
|
|
@@ -4430,6 +4621,9 @@ var _ObjectStackProtocolImplementation = class _ObjectStackProtocolImplementatio
|
|
|
4430
4621
|
} catch {
|
|
4431
4622
|
}
|
|
4432
4623
|
}
|
|
4624
|
+
if (this.shouldDropStorage(request.type, request.name, request.dropStorage, targetState)) {
|
|
4625
|
+
await this.dropObjectStorage(singularTypeForRepo, request.name);
|
|
4626
|
+
}
|
|
4433
4627
|
await this.recordMetadataAudit({
|
|
4434
4628
|
type: request.type,
|
|
4435
4629
|
name: request.name,
|
|
@@ -4478,6 +4672,12 @@ var _ObjectStackProtocolImplementation = class _ObjectStackProtocolImplementatio
|
|
|
4478
4672
|
};
|
|
4479
4673
|
}
|
|
4480
4674
|
await this.engine.delete("sys_metadata", { where: { id: existing.id } });
|
|
4675
|
+
{
|
|
4676
|
+
const targetState = request.state === "draft" ? "draft" : "active";
|
|
4677
|
+
if (this.shouldDropStorage(request.type, request.name, request.dropStorage, targetState)) {
|
|
4678
|
+
await this.dropObjectStorage(PLURAL_TO_SINGULAR3[request.type] ?? request.type, request.name);
|
|
4679
|
+
}
|
|
4680
|
+
}
|
|
4481
4681
|
if (this.environmentId === void 0) {
|
|
4482
4682
|
try {
|
|
4483
4683
|
const services = this.getServicesRegistry?.();
|
|
@@ -7579,6 +7779,22 @@ var _ObjectQL = class _ObjectQL {
|
|
|
7579
7779
|
const tableName = StorageNameMapping.resolveTableName(obj);
|
|
7580
7780
|
await driver.syncSchema(tableName, obj);
|
|
7581
7781
|
}
|
|
7782
|
+
/**
|
|
7783
|
+
* Drop the physical storage (table/collection) backing an object — the
|
|
7784
|
+
* inverse of {@link syncObjectSchema}. DESTRUCTIVE: deletes all rows in the
|
|
7785
|
+
* table. Used by the protocol delete path when the caller explicitly opts
|
|
7786
|
+
* into storage teardown (e.g. discarding an object that was published only
|
|
7787
|
+
* to preview it). No-op when the object's driver does not expose `dropTable`.
|
|
7788
|
+
* Resolves the physical table name from the registered definition, falling
|
|
7789
|
+
* back to the bare name if the def was already removed.
|
|
7790
|
+
*/
|
|
7791
|
+
async dropObjectSchema(objectName) {
|
|
7792
|
+
const obj = this._registry.getObject(objectName);
|
|
7793
|
+
const driver = this.getDriverForObject(objectName);
|
|
7794
|
+
if (!driver || typeof driver.dropTable !== "function") return;
|
|
7795
|
+
const tableName = StorageNameMapping.resolveTableName(obj ?? { name: objectName });
|
|
7796
|
+
await driver.dropTable(tableName);
|
|
7797
|
+
}
|
|
7582
7798
|
/**
|
|
7583
7799
|
* Get a registered driver by datasource name.
|
|
7584
7800
|
* Alias matching @objectql/core datasource() API.
|