@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 CHANGED
@@ -719,6 +719,7 @@ declare class ObjectStackProtocolImplementation implements ObjectStackProtocol {
719
719
  type: string;
720
720
  packageId?: string;
721
721
  organizationId?: string;
722
+ previewDrafts?: boolean;
722
723
  }): Promise<{
723
724
  type: string;
724
725
  items: any[];
@@ -729,10 +730,11 @@ declare class ObjectStackProtocolImplementation implements ObjectStackProtocol {
729
730
  packageId?: string;
730
731
  organizationId?: string;
731
732
  state?: 'active' | 'draft';
733
+ previewDrafts?: boolean;
732
734
  }): Promise<{
733
735
  type: string;
734
736
  name: string;
735
- item: {} | null;
737
+ item: any;
736
738
  } | {
737
739
  editable: boolean;
738
740
  deletable: boolean;
@@ -1155,6 +1157,23 @@ declare class ObjectStackProtocolImplementation implements ObjectStackProtocol {
1155
1157
  * simply no-op, and a sync failure must not abort the publish.
1156
1158
  */
1157
1159
  private ensureObjectStorage;
1160
+ /**
1161
+ * Inverse of {@link ensureObjectStorage}: drop an object's physical table.
1162
+ * DESTRUCTIVE — deletes the table and all its rows. Only invoked when a
1163
+ * delete explicitly opts into storage teardown (see {@link deleteMetaItem}'s
1164
+ * `dropStorage`), so publishing an object solely to preview it can be undone
1165
+ * without leaving an orphan table. Best-effort: a failure is logged, not
1166
+ * thrown — the metadata delete already succeeded, and a stray table is
1167
+ * reclaimed by the next sync/drop rather than blocking the delete.
1168
+ */
1169
+ private dropObjectStorage;
1170
+ /**
1171
+ * Guard for storage teardown on delete. Drops a physical table only when
1172
+ * the caller opted in AND it is safe: object types only (others have no
1173
+ * table), active state only (drafts were never materialised), and never a
1174
+ * `sys_`-prefixed platform table.
1175
+ */
1176
+ private shouldDropStorage;
1158
1177
  saveMetaItem(request: {
1159
1178
  type: string;
1160
1179
  name: string;
@@ -1263,6 +1282,69 @@ declare class ObjectStackProtocolImplementation implements ObjectStackProtocol {
1263
1282
  code?: string;
1264
1283
  }>;
1265
1284
  }>;
1285
+ /**
1286
+ * Discard every pending DRAFT bound to a package — the NON-destructive
1287
+ * inverse of {@link publishPackageDrafts}. Drops only `state='draft'` rows
1288
+ * (via the per-item delete primitive), reverting the package to its last
1289
+ * published baseline; active/published metadata and physical tables are
1290
+ * left untouched.
1291
+ *
1292
+ * Use case: "I edited this app for a while and it turned out worse than
1293
+ * before — abandon all my changes." Routes through the sys_metadata path
1294
+ * (no metadata-service dependency, unlike `POST /packages/:id/revert`).
1295
+ */
1296
+ discardPackageDrafts(request: {
1297
+ packageId: string;
1298
+ organizationId?: string;
1299
+ actor?: string;
1300
+ }): Promise<{
1301
+ success: boolean;
1302
+ discardedCount: number;
1303
+ failedCount: number;
1304
+ discarded: Array<{
1305
+ type: string;
1306
+ name: string;
1307
+ }>;
1308
+ failed: Array<{
1309
+ type: string;
1310
+ name: string;
1311
+ error: string;
1312
+ code?: string;
1313
+ }>;
1314
+ }>;
1315
+ /**
1316
+ * Delete an ENTIRE package: every `sys_metadata` row bound to it (active
1317
+ * AND draft) and — by default — the physical table of each object it
1318
+ * defined. DESTRUCTIVE: removes the app and its data. Use case: "I don't
1319
+ * want this package anymore."
1320
+ *
1321
+ * Set `keepData: true` to remove the metadata but preserve object tables.
1322
+ * The `sys_`-table guard in {@link deleteMetaItem} still applies, so
1323
+ * platform storage is never dropped. Drafts are removed before active rows
1324
+ * so each object's table is torn down once. Per-item failures are collected
1325
+ * without aborting the rest.
1326
+ */
1327
+ deletePackage(request: {
1328
+ packageId: string;
1329
+ organizationId?: string;
1330
+ actor?: string;
1331
+ keepData?: boolean;
1332
+ }): Promise<{
1333
+ success: boolean;
1334
+ deletedCount: number;
1335
+ failedCount: number;
1336
+ deleted: Array<{
1337
+ type: string;
1338
+ name: string;
1339
+ state: string;
1340
+ }>;
1341
+ failed: Array<{
1342
+ type: string;
1343
+ name: string;
1344
+ error: string;
1345
+ code?: string;
1346
+ }>;
1347
+ }>;
1266
1348
  /**
1267
1349
  * Restore the body recorded at history `toVersion` as the new
1268
1350
  * live row. Writes a history event with `op='revert'`. 404
@@ -1331,6 +1413,13 @@ declare class ObjectStackProtocolImplementation implements ObjectStackProtocol {
1331
1413
  parentVersion?: string | null;
1332
1414
  actor?: string;
1333
1415
  state?: 'active' | 'draft';
1416
+ /**
1417
+ * When true, also drop the object's physical table after the metadata
1418
+ * is removed (object + active only; never `sys_`). Default false keeps
1419
+ * delete non-destructive to data. Used by the "discard a previewed
1420
+ * object" flow so a publish-to-preview leaves no orphan table.
1421
+ */
1422
+ dropStorage?: boolean;
1334
1423
  }): Promise<{
1335
1424
  success: boolean;
1336
1425
  message?: string;
@@ -2163,6 +2252,16 @@ declare class ObjectQL implements IDataEngine {
2163
2252
  * table when absent (and alters to add new columns).
2164
2253
  */
2165
2254
  syncObjectSchema(objectName: string): Promise<void>;
2255
+ /**
2256
+ * Drop the physical storage (table/collection) backing an object — the
2257
+ * inverse of {@link syncObjectSchema}. DESTRUCTIVE: deletes all rows in the
2258
+ * table. Used by the protocol delete path when the caller explicitly opts
2259
+ * into storage teardown (e.g. discarding an object that was published only
2260
+ * to preview it). No-op when the object's driver does not expose `dropTable`.
2261
+ * Resolves the physical table name from the registered definition, falling
2262
+ * back to the bare name if the def was already removed.
2263
+ */
2264
+ dropObjectSchema(objectName: string): Promise<void>;
2166
2265
  /**
2167
2266
  * Get a registered driver by datasource name.
2168
2267
  * Alias matching @objectql/core datasource() API.
package/dist/index.d.ts CHANGED
@@ -719,6 +719,7 @@ declare class ObjectStackProtocolImplementation implements ObjectStackProtocol {
719
719
  type: string;
720
720
  packageId?: string;
721
721
  organizationId?: string;
722
+ previewDrafts?: boolean;
722
723
  }): Promise<{
723
724
  type: string;
724
725
  items: any[];
@@ -729,10 +730,11 @@ declare class ObjectStackProtocolImplementation implements ObjectStackProtocol {
729
730
  packageId?: string;
730
731
  organizationId?: string;
731
732
  state?: 'active' | 'draft';
733
+ previewDrafts?: boolean;
732
734
  }): Promise<{
733
735
  type: string;
734
736
  name: string;
735
- item: {} | null;
737
+ item: any;
736
738
  } | {
737
739
  editable: boolean;
738
740
  deletable: boolean;
@@ -1155,6 +1157,23 @@ declare class ObjectStackProtocolImplementation implements ObjectStackProtocol {
1155
1157
  * simply no-op, and a sync failure must not abort the publish.
1156
1158
  */
1157
1159
  private ensureObjectStorage;
1160
+ /**
1161
+ * Inverse of {@link ensureObjectStorage}: drop an object's physical table.
1162
+ * DESTRUCTIVE — deletes the table and all its rows. Only invoked when a
1163
+ * delete explicitly opts into storage teardown (see {@link deleteMetaItem}'s
1164
+ * `dropStorage`), so publishing an object solely to preview it can be undone
1165
+ * without leaving an orphan table. Best-effort: a failure is logged, not
1166
+ * thrown — the metadata delete already succeeded, and a stray table is
1167
+ * reclaimed by the next sync/drop rather than blocking the delete.
1168
+ */
1169
+ private dropObjectStorage;
1170
+ /**
1171
+ * Guard for storage teardown on delete. Drops a physical table only when
1172
+ * the caller opted in AND it is safe: object types only (others have no
1173
+ * table), active state only (drafts were never materialised), and never a
1174
+ * `sys_`-prefixed platform table.
1175
+ */
1176
+ private shouldDropStorage;
1158
1177
  saveMetaItem(request: {
1159
1178
  type: string;
1160
1179
  name: string;
@@ -1263,6 +1282,69 @@ declare class ObjectStackProtocolImplementation implements ObjectStackProtocol {
1263
1282
  code?: string;
1264
1283
  }>;
1265
1284
  }>;
1285
+ /**
1286
+ * Discard every pending DRAFT bound to a package — the NON-destructive
1287
+ * inverse of {@link publishPackageDrafts}. Drops only `state='draft'` rows
1288
+ * (via the per-item delete primitive), reverting the package to its last
1289
+ * published baseline; active/published metadata and physical tables are
1290
+ * left untouched.
1291
+ *
1292
+ * Use case: "I edited this app for a while and it turned out worse than
1293
+ * before — abandon all my changes." Routes through the sys_metadata path
1294
+ * (no metadata-service dependency, unlike `POST /packages/:id/revert`).
1295
+ */
1296
+ discardPackageDrafts(request: {
1297
+ packageId: string;
1298
+ organizationId?: string;
1299
+ actor?: string;
1300
+ }): Promise<{
1301
+ success: boolean;
1302
+ discardedCount: number;
1303
+ failedCount: number;
1304
+ discarded: Array<{
1305
+ type: string;
1306
+ name: string;
1307
+ }>;
1308
+ failed: Array<{
1309
+ type: string;
1310
+ name: string;
1311
+ error: string;
1312
+ code?: string;
1313
+ }>;
1314
+ }>;
1315
+ /**
1316
+ * Delete an ENTIRE package: every `sys_metadata` row bound to it (active
1317
+ * AND draft) and — by default — the physical table of each object it
1318
+ * defined. DESTRUCTIVE: removes the app and its data. Use case: "I don't
1319
+ * want this package anymore."
1320
+ *
1321
+ * Set `keepData: true` to remove the metadata but preserve object tables.
1322
+ * The `sys_`-table guard in {@link deleteMetaItem} still applies, so
1323
+ * platform storage is never dropped. Drafts are removed before active rows
1324
+ * so each object's table is torn down once. Per-item failures are collected
1325
+ * without aborting the rest.
1326
+ */
1327
+ deletePackage(request: {
1328
+ packageId: string;
1329
+ organizationId?: string;
1330
+ actor?: string;
1331
+ keepData?: boolean;
1332
+ }): Promise<{
1333
+ success: boolean;
1334
+ deletedCount: number;
1335
+ failedCount: number;
1336
+ deleted: Array<{
1337
+ type: string;
1338
+ name: string;
1339
+ state: string;
1340
+ }>;
1341
+ failed: Array<{
1342
+ type: string;
1343
+ name: string;
1344
+ error: string;
1345
+ code?: string;
1346
+ }>;
1347
+ }>;
1266
1348
  /**
1267
1349
  * Restore the body recorded at history `toVersion` as the new
1268
1350
  * live row. Writes a history event with `op='revert'`. 404
@@ -1331,6 +1413,13 @@ declare class ObjectStackProtocolImplementation implements ObjectStackProtocol {
1331
1413
  parentVersion?: string | null;
1332
1414
  actor?: string;
1333
1415
  state?: 'active' | 'draft';
1416
+ /**
1417
+ * When true, also drop the object's physical table after the metadata
1418
+ * is removed (object + active only; never `sys_`). Default false keeps
1419
+ * delete non-destructive to data. Used by the "discard a previewed
1420
+ * object" flow so a publish-to-preview leaves no orphan table.
1421
+ */
1422
+ dropStorage?: boolean;
1334
1423
  }): Promise<{
1335
1424
  success: boolean;
1336
1425
  message?: string;
@@ -2163,6 +2252,16 @@ declare class ObjectQL implements IDataEngine {
2163
2252
  * table when absent (and alters to add new columns).
2164
2253
  */
2165
2254
  syncObjectSchema(objectName: string): Promise<void>;
2255
+ /**
2256
+ * Drop the physical storage (table/collection) backing an object — the
2257
+ * inverse of {@link syncObjectSchema}. DESTRUCTIVE: deletes all rows in the
2258
+ * table. Used by the protocol delete path when the caller explicitly opts
2259
+ * into storage teardown (e.g. discarding an object that was published only
2260
+ * to preview it). No-op when the object's driver does not expose `dropTable`.
2261
+ * Resolves the physical table name from the registered definition, falling
2262
+ * back to the bare name if the def was already removed.
2263
+ */
2264
+ dropObjectSchema(objectName: string): Promise<void>;
2166
2265
  /**
2167
2266
  * Get a registered driver by datasource name.
2168
2267
  * Alias matching @objectql/core datasource() API.
package/dist/index.js CHANGED
@@ -2450,6 +2450,44 @@ var _ObjectStackProtocolImplementation = class _ObjectStackProtocolImplementatio
2450
2450
  }
2451
2451
  } catch {
2452
2452
  }
2453
+ if (request.previewDrafts) {
2454
+ try {
2455
+ const orgId = request.organizationId;
2456
+ const queryDrafts = async (oid) => {
2457
+ const whereClause = { type: request.type, state: "draft", organization_id: oid };
2458
+ if (packageId) whereClause.package_id = packageId;
2459
+ let rs = await this.engine.find("sys_metadata", { where: whereClause });
2460
+ if (!rs || rs.length === 0) {
2461
+ const alt = import_shared4.PLURAL_TO_SINGULAR[request.type] ?? import_shared4.SINGULAR_TO_PLURAL[request.type];
2462
+ if (alt) {
2463
+ const altWhere = { type: alt, state: "draft", organization_id: oid };
2464
+ if (packageId) altWhere.package_id = packageId;
2465
+ rs = await this.engine.find("sys_metadata", { where: altWhere });
2466
+ }
2467
+ }
2468
+ return rs ?? [];
2469
+ };
2470
+ const draftRecords = [...await queryDrafts(null), ...orgId ? await queryDrafts(orgId) : []];
2471
+ if (draftRecords.length > 0) {
2472
+ const byName = /* @__PURE__ */ new Map();
2473
+ for (const existing of items) {
2474
+ const entry = existing;
2475
+ if (entry && typeof entry === "object" && "name" in entry) byName.set(entry.name, entry);
2476
+ }
2477
+ for (const record of draftRecords) {
2478
+ const data = typeof record.metadata === "string" ? JSON.parse(record.metadata) : record.metadata;
2479
+ if (data && typeof data === "object" && "name" in data) {
2480
+ const recPkg = record.package_id ?? void 0;
2481
+ if (recPkg && data._packageId === void 0) data._packageId = recPkg;
2482
+ data._draft = true;
2483
+ byName.set(data.name, data);
2484
+ }
2485
+ }
2486
+ items = Array.from(byName.values());
2487
+ }
2488
+ } catch {
2489
+ }
2490
+ }
2453
2491
  try {
2454
2492
  const services = this.getServicesRegistry?.();
2455
2493
  const metadataService = services?.get("metadata");
@@ -2508,6 +2546,34 @@ var _ObjectStackProtocolImplementation = class _ObjectStackProtocolImplementatio
2508
2546
  let item;
2509
2547
  const orgId = request.organizationId;
2510
2548
  const readState = request.state === "draft" ? "draft" : "active";
2549
+ if (request.previewDrafts && readState !== "draft") {
2550
+ try {
2551
+ const findDraft = async (oid) => {
2552
+ const rec = await this.engine.findOne("sys_metadata", {
2553
+ where: { type: request.type, name: request.name, state: "draft", organization_id: oid }
2554
+ });
2555
+ if (rec) return rec;
2556
+ const alt = import_shared4.PLURAL_TO_SINGULAR[request.type] ?? import_shared4.SINGULAR_TO_PLURAL[request.type];
2557
+ if (alt) {
2558
+ return await this.engine.findOne("sys_metadata", {
2559
+ where: { type: alt, name: request.name, state: "draft", organization_id: oid }
2560
+ });
2561
+ }
2562
+ return void 0;
2563
+ };
2564
+ const draftRec = (orgId ? await findDraft(orgId) : void 0) ?? await findDraft(null);
2565
+ if (draftRec) {
2566
+ const draftItem = typeof draftRec.metadata === "string" ? JSON.parse(draftRec.metadata) : draftRec.metadata;
2567
+ if (draftItem && typeof draftItem === "object") {
2568
+ const recPkg = draftRec.package_id ?? void 0;
2569
+ if (recPkg && draftItem._packageId === void 0) draftItem._packageId = recPkg;
2570
+ draftItem._draft = true;
2571
+ }
2572
+ return { type: request.type, name: request.name, item: decorateMetadataItem(request.type, draftItem) };
2573
+ }
2574
+ } catch {
2575
+ }
2576
+ }
2511
2577
  try {
2512
2578
  const findOverlay = async (oid) => {
2513
2579
  const where = {
@@ -3882,6 +3948,37 @@ var _ObjectStackProtocolImplementation = class _ObjectStackProtocolImplementatio
3882
3948
  console.warn(`[Protocol] table sync failed for object '${name}': ${err?.message ?? err}`);
3883
3949
  }
3884
3950
  }
3951
+ /**
3952
+ * Inverse of {@link ensureObjectStorage}: drop an object's physical table.
3953
+ * DESTRUCTIVE — deletes the table and all its rows. Only invoked when a
3954
+ * delete explicitly opts into storage teardown (see {@link deleteMetaItem}'s
3955
+ * `dropStorage`), so publishing an object solely to preview it can be undone
3956
+ * without leaving an orphan table. Best-effort: a failure is logged, not
3957
+ * thrown — the metadata delete already succeeded, and a stray table is
3958
+ * reclaimed by the next sync/drop rather than blocking the delete.
3959
+ */
3960
+ async dropObjectStorage(type, name) {
3961
+ if (type !== "object" && type !== "objects") return;
3962
+ try {
3963
+ await this.engine.dropObjectSchema(name);
3964
+ } catch (err) {
3965
+ console.warn(`[Protocol] table drop failed for object '${name}': ${err?.message ?? err}`);
3966
+ }
3967
+ }
3968
+ /**
3969
+ * Guard for storage teardown on delete. Drops a physical table only when
3970
+ * the caller opted in AND it is safe: object types only (others have no
3971
+ * table), active state only (drafts were never materialised), and never a
3972
+ * `sys_`-prefixed platform table.
3973
+ */
3974
+ shouldDropStorage(type, name, dropStorage, state) {
3975
+ if (!dropStorage) return false;
3976
+ const singular = import_shared4.PLURAL_TO_SINGULAR[type] ?? type;
3977
+ if (singular !== "object") return false;
3978
+ if (state !== "active") return false;
3979
+ if (name.startsWith("sys_")) return false;
3980
+ return true;
3981
+ }
3885
3982
  async saveMetaItem(request) {
3886
3983
  if (!request.item) {
3887
3984
  throw new Error("Item data is required");
@@ -4262,6 +4359,100 @@ var _ObjectStackProtocolImplementation = class _ObjectStackProtocolImplementatio
4262
4359
  failed
4263
4360
  };
4264
4361
  }
4362
+ /**
4363
+ * Discard every pending DRAFT bound to a package — the NON-destructive
4364
+ * inverse of {@link publishPackageDrafts}. Drops only `state='draft'` rows
4365
+ * (via the per-item delete primitive), reverting the package to its last
4366
+ * published baseline; active/published metadata and physical tables are
4367
+ * left untouched.
4368
+ *
4369
+ * Use case: "I edited this app for a while and it turned out worse than
4370
+ * before — abandon all my changes." Routes through the sys_metadata path
4371
+ * (no metadata-service dependency, unlike `POST /packages/:id/revert`).
4372
+ */
4373
+ async discardPackageDrafts(request) {
4374
+ await this.ensureOverlayIndex();
4375
+ const orgId = request.organizationId ?? null;
4376
+ const repo = this.getOverlayRepo(orgId);
4377
+ const drafts = await repo.listDrafts({ packageId: request.packageId });
4378
+ const discarded = [];
4379
+ const failed = [];
4380
+ for (const d of drafts) {
4381
+ try {
4382
+ await this.deleteMetaItem({
4383
+ type: d.type,
4384
+ name: d.name,
4385
+ state: "draft",
4386
+ ...request.organizationId ? { organizationId: request.organizationId } : {},
4387
+ ...request.actor ? { actor: request.actor } : {}
4388
+ });
4389
+ discarded.push({ type: d.type, name: d.name });
4390
+ } catch (e) {
4391
+ failed.push({
4392
+ type: d.type,
4393
+ name: d.name,
4394
+ error: e?.message ?? "discard failed",
4395
+ ...e?.code ? { code: e.code } : {}
4396
+ });
4397
+ }
4398
+ }
4399
+ return {
4400
+ success: failed.length === 0 && discarded.length > 0,
4401
+ discardedCount: discarded.length,
4402
+ failedCount: failed.length,
4403
+ discarded,
4404
+ failed
4405
+ };
4406
+ }
4407
+ /**
4408
+ * Delete an ENTIRE package: every `sys_metadata` row bound to it (active
4409
+ * AND draft) and — by default — the physical table of each object it
4410
+ * defined. DESTRUCTIVE: removes the app and its data. Use case: "I don't
4411
+ * want this package anymore."
4412
+ *
4413
+ * Set `keepData: true` to remove the metadata but preserve object tables.
4414
+ * The `sys_`-table guard in {@link deleteMetaItem} still applies, so
4415
+ * platform storage is never dropped. Drafts are removed before active rows
4416
+ * so each object's table is torn down once. Per-item failures are collected
4417
+ * without aborting the rest.
4418
+ */
4419
+ async deletePackage(request) {
4420
+ const where = { package_id: request.packageId };
4421
+ if (request.organizationId) where.organization_id = request.organizationId;
4422
+ const rows = await this.engine.find("sys_metadata", { where });
4423
+ const dropStorage = request.keepData !== true;
4424
+ const ordered = [...rows].sort((a, b) => (a.state === "draft" ? 0 : 1) - (b.state === "draft" ? 0 : 1));
4425
+ const deleted = [];
4426
+ const failed = [];
4427
+ for (const row of ordered) {
4428
+ const state = row.state === "draft" ? "draft" : "active";
4429
+ try {
4430
+ await this.deleteMetaItem({
4431
+ type: row.type,
4432
+ name: row.name,
4433
+ state,
4434
+ ...row.organization_id ? { organizationId: row.organization_id } : {},
4435
+ ...request.actor ? { actor: request.actor } : {},
4436
+ ...dropStorage ? { dropStorage: true } : {}
4437
+ });
4438
+ deleted.push({ type: row.type, name: row.name, state });
4439
+ } catch (e) {
4440
+ failed.push({
4441
+ type: row.type,
4442
+ name: row.name,
4443
+ error: e?.message ?? "delete failed",
4444
+ ...e?.code ? { code: e.code } : {}
4445
+ });
4446
+ }
4447
+ }
4448
+ return {
4449
+ success: failed.length === 0 && deleted.length > 0,
4450
+ deletedCount: deleted.length,
4451
+ failedCount: failed.length,
4452
+ deleted,
4453
+ failed
4454
+ };
4455
+ }
4265
4456
  /**
4266
4457
  * Restore the body recorded at history `toVersion` as the new
4267
4458
  * live row. Writes a history event with `op='revert'`. 404
@@ -4494,6 +4685,9 @@ var _ObjectStackProtocolImplementation = class _ObjectStackProtocolImplementatio
4494
4685
  } catch {
4495
4686
  }
4496
4687
  }
4688
+ if (this.shouldDropStorage(request.type, request.name, request.dropStorage, targetState)) {
4689
+ await this.dropObjectStorage(singularTypeForRepo, request.name);
4690
+ }
4497
4691
  await this.recordMetadataAudit({
4498
4692
  type: request.type,
4499
4693
  name: request.name,
@@ -4542,6 +4736,12 @@ var _ObjectStackProtocolImplementation = class _ObjectStackProtocolImplementatio
4542
4736
  };
4543
4737
  }
4544
4738
  await this.engine.delete("sys_metadata", { where: { id: existing.id } });
4739
+ {
4740
+ const targetState = request.state === "draft" ? "draft" : "active";
4741
+ if (this.shouldDropStorage(request.type, request.name, request.dropStorage, targetState)) {
4742
+ await this.dropObjectStorage(import_shared4.PLURAL_TO_SINGULAR[request.type] ?? request.type, request.name);
4743
+ }
4744
+ }
4545
4745
  if (this.environmentId === void 0) {
4546
4746
  try {
4547
4747
  const services = this.getServicesRegistry?.();
@@ -7643,6 +7843,22 @@ var _ObjectQL = class _ObjectQL {
7643
7843
  const tableName = import_system2.StorageNameMapping.resolveTableName(obj);
7644
7844
  await driver.syncSchema(tableName, obj);
7645
7845
  }
7846
+ /**
7847
+ * Drop the physical storage (table/collection) backing an object — the
7848
+ * inverse of {@link syncObjectSchema}. DESTRUCTIVE: deletes all rows in the
7849
+ * table. Used by the protocol delete path when the caller explicitly opts
7850
+ * into storage teardown (e.g. discarding an object that was published only
7851
+ * to preview it). No-op when the object's driver does not expose `dropTable`.
7852
+ * Resolves the physical table name from the registered definition, falling
7853
+ * back to the bare name if the def was already removed.
7854
+ */
7855
+ async dropObjectSchema(objectName) {
7856
+ const obj = this._registry.getObject(objectName);
7857
+ const driver = this.getDriverForObject(objectName);
7858
+ if (!driver || typeof driver.dropTable !== "function") return;
7859
+ const tableName = import_system2.StorageNameMapping.resolveTableName(obj ?? { name: objectName });
7860
+ await driver.dropTable(tableName);
7861
+ }
7646
7862
  /**
7647
7863
  * Get a registered driver by datasource name.
7648
7864
  * Alias matching @objectql/core datasource() API.