@objectstack/objectql 7.7.0 → 7.8.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
@@ -2,7 +2,7 @@ import { ServiceObject, ObjectOwnership, HookContext, QueryAST, EngineQueryOptio
2
2
  import { ObjectStackManifest, InstalledPackage, MetadataValidationResult, MetadataLock, MetadataProvenance, ExecutionContext } from '@objectstack/spec/kernel';
3
3
  import * as _objectstack_metadata_core from '@objectstack/metadata-core';
4
4
  import { MetadataRepository, MetaRef, MetadataItem, PutOptions, PutResult, DeleteOptions, DeleteResult, MetadataWriteIntent, ListFilter, MetadataItemHeader, HistoryOptions, MetadataEvent, WatchFilter } from '@objectstack/metadata-core';
5
- import { ObjectStackProtocol, MetadataCacheRequest, MetadataCacheResponse, BatchUpdateRequest, BatchUpdateResponse, UpdateManyDataRequest, DeleteManyDataRequest } from '@objectstack/spec/api';
5
+ import { ObjectStackProtocol, MetadataCacheRequest, MetadataCacheResponse, BatchUpdateRequest, BatchUpdateResponse, UpdateManyDataRequest, DeleteManyDataRequest, InstallPackageRequest, InstallPackageResponse } from '@objectstack/spec/api';
6
6
  import { IDataEngine, DriverInterface, Logger, Plugin, PluginContext, ObjectKernel } from '@objectstack/core';
7
7
  import { IFeedService, IRealtimeService, ICryptoProvider } from '@objectstack/spec/contracts';
8
8
 
@@ -860,7 +860,7 @@ declare class ObjectStackProtocolImplementation implements ObjectStackProtocol {
860
860
  label: string | undefined;
861
861
  required: boolean;
862
862
  readonly: boolean;
863
- type: "number" | "boolean" | "tags" | "date" | "record" | "file" | "code" | "datetime" | "signature" | "progress" | "url" | "currency" | "percent" | "password" | "secret" | "email" | "time" | "text" | "textarea" | "phone" | "markdown" | "html" | "richtext" | "toggle" | "select" | "multiselect" | "radio" | "checkboxes" | "lookup" | "master_detail" | "tree" | "image" | "avatar" | "video" | "audio" | "formula" | "summary" | "autonumber" | "composite" | "repeater" | "location" | "address" | "json" | "color" | "rating" | "slider" | "qrcode" | "vector";
863
+ type: "number" | "boolean" | "tags" | "date" | "record" | "file" | "code" | "datetime" | "signature" | "progress" | "url" | "lookup" | "master_detail" | "currency" | "percent" | "password" | "secret" | "email" | "time" | "text" | "textarea" | "phone" | "markdown" | "html" | "richtext" | "toggle" | "select" | "multiselect" | "radio" | "checkboxes" | "tree" | "image" | "avatar" | "video" | "audio" | "formula" | "summary" | "autonumber" | "composite" | "repeater" | "location" | "address" | "json" | "color" | "rating" | "slider" | "qrcode" | "vector";
864
864
  colSpan: number;
865
865
  }[];
866
866
  }[];
@@ -1144,6 +1144,17 @@ declare class ObjectStackProtocolImplementation implements ObjectStackProtocol {
1144
1144
  * stale schema into the registry.
1145
1145
  */
1146
1146
  private applyObjectRegistryMutation;
1147
+ /**
1148
+ * Ensure a just-PUBLISHED object's physical table exists so it is usable
1149
+ * for data CRUD immediately — without a server restart. Registering the
1150
+ * object (above) only updates the in-memory registry; the table is created
1151
+ * by the driver's schema sync, which otherwise only runs at boot. Without
1152
+ * this, inserting into a freshly-published object fails with "no such
1153
+ * table" (surfaced as `object_not_found`) until the next restart.
1154
+ * Best-effort + non-fatal: drivers without DDL (or read-only datasources)
1155
+ * simply no-op, and a sync failure must not abort the publish.
1156
+ */
1157
+ private ensureObjectStorage;
1147
1158
  saveMetaItem(request: {
1148
1159
  type: string;
1149
1160
  name: string;
@@ -1203,6 +1214,55 @@ declare class ObjectStackProtocolImplementation implements ObjectStackProtocol {
1203
1214
  seq: number;
1204
1215
  message?: string;
1205
1216
  }>;
1217
+ /**
1218
+ * List pending DRAFT metadata (ADR-0033) for the org, optionally narrowed
1219
+ * by `packageId` and/or `type`. The list reads of `getMetaItems` only see
1220
+ * the ACTIVE registry; this exposes what an AI authored but a human hasn't
1221
+ * published yet, so the console can show a "pending changes" surface and a
1222
+ * just-built app package isn't displayed as empty. No body is returned.
1223
+ */
1224
+ listDrafts(request?: {
1225
+ packageId?: string;
1226
+ type?: string;
1227
+ organizationId?: string;
1228
+ }): Promise<{
1229
+ drafts: Array<{
1230
+ type: string;
1231
+ name: string;
1232
+ packageId: string | null;
1233
+ updatedAt: string | null;
1234
+ updatedBy: string | null;
1235
+ }>;
1236
+ }>;
1237
+ /**
1238
+ * Publish every pending DRAFT bound to a package in one shot (ADR-0033) —
1239
+ * the "publish whole app" action. Promotes each draft→active by reusing the
1240
+ * per-item {@link publishMetaItem} primitive (which runs the overridable /
1241
+ * lock guards and refreshes the runtime registry), so this needs NO
1242
+ * `metadata` service (unlike `MetadataService.publishPackage`, which reads
1243
+ * the in-memory registry and 503s when that service is absent). Per-item
1244
+ * failures are collected and do NOT abort the rest.
1245
+ */
1246
+ publishPackageDrafts(request: {
1247
+ packageId: string;
1248
+ organizationId?: string;
1249
+ actor?: string;
1250
+ }): Promise<{
1251
+ success: boolean;
1252
+ publishedCount: number;
1253
+ failedCount: number;
1254
+ published: Array<{
1255
+ type: string;
1256
+ name: string;
1257
+ version: string;
1258
+ }>;
1259
+ failed: Array<{
1260
+ type: string;
1261
+ name: string;
1262
+ error: string;
1263
+ code?: string;
1264
+ }>;
1265
+ }>;
1206
1266
  /**
1207
1267
  * Restore the body recorded at history `toVersion` as the new
1208
1268
  * live row. Writes a history event with `op='revert'`. 404
@@ -1328,6 +1388,24 @@ declare class ObjectStackProtocolImplementation implements ObjectStackProtocol {
1328
1388
  getChangelog(request: any): Promise<any>;
1329
1389
  feedSubscribe(request: any): Promise<any>;
1330
1390
  feedUnsubscribe(request: any): Promise<any>;
1391
+ /**
1392
+ * Install a package from a manifest — the single canonical write primitive
1393
+ * for the package subsystem (ADR-0033 consolidation).
1394
+ *
1395
+ * It writes BOTH stores that the runtime keeps for packages, so a package
1396
+ * surfaces consistently no matter which read path is used:
1397
+ * 1. the in-memory `SchemaRegistry` (what the dispatcher's
1398
+ * `/api/v1/packages` list/detail and `getMetaItems({type:'package'})`
1399
+ * read — i.e. what Studio's package selector shows), and
1400
+ * 2. the durable `sys_packages` table via the optional `package` service
1401
+ * (so the package survives a restart; that service re-hydrates these
1402
+ * rows back into the registry on boot).
1403
+ *
1404
+ * The DB write is best-effort and non-fatal: when the `package` service is
1405
+ * absent (e.g. the `marketplace` capability is off) the package is still
1406
+ * registered in-memory and visible for the lifetime of the process.
1407
+ */
1408
+ installPackage(request: InstallPackageRequest): Promise<InstallPackageResponse>;
1331
1409
  }
1332
1410
 
1333
1411
  /**
@@ -1498,6 +1576,23 @@ declare class SysMetadataRepository implements MetadataRepository {
1498
1576
  item: MetadataItem;
1499
1577
  }>;
1500
1578
  list(filter: ListFilter): AsyncIterable<MetadataItemHeader>;
1579
+ /**
1580
+ * List pending DRAFT rows (ADR-0033) for this org, optionally narrowed by
1581
+ * `type` and/or `packageId`. Unlike {@link list} (which is hard-scoped to
1582
+ * `state='active'`), this reads `state='draft'` so the console can surface
1583
+ * what an AI authored but a human hasn't published yet. Returns a light
1584
+ * header projection (no body) suitable for a "pending changes" list.
1585
+ */
1586
+ listDrafts(filter?: {
1587
+ type?: string;
1588
+ packageId?: string;
1589
+ }): Promise<Array<{
1590
+ type: string;
1591
+ name: string;
1592
+ packageId: string | null;
1593
+ updatedAt: string | null;
1594
+ updatedBy: string | null;
1595
+ }>>;
1501
1596
  /**
1502
1597
  * Yield every history event for `(org, type?, name?)` from the
1503
1598
  * durable log, ordered by per-(type,name) `version` ascending. When
@@ -2058,6 +2153,16 @@ declare class ObjectQL implements IDataEngine {
2058
2153
  * before inserting seed data.
2059
2154
  */
2060
2155
  syncSchemas(): Promise<void>;
2156
+ /**
2157
+ * Sync a SINGLE object's physical storage (create/alter its table) on
2158
+ * demand. Boot-time {@link syncSchemas} runs once at startup, so an object
2159
+ * that becomes live at runtime (e.g. publishing a drafted object) has a
2160
+ * registry entry but no table — data CRUD then fails with "no such table"
2161
+ * until the next restart. Calling this right after the object is registered
2162
+ * makes it immediately usable. Idempotent: the SQL driver only creates the
2163
+ * table when absent (and alters to add new columns).
2164
+ */
2165
+ syncObjectSchema(objectName: string): Promise<void>;
2061
2166
  /**
2062
2167
  * Get a registered driver by datasource name.
2063
2168
  * Alias matching @objectql/core datasource() API.
package/dist/index.d.ts CHANGED
@@ -2,7 +2,7 @@ import { ServiceObject, ObjectOwnership, HookContext, QueryAST, EngineQueryOptio
2
2
  import { ObjectStackManifest, InstalledPackage, MetadataValidationResult, MetadataLock, MetadataProvenance, ExecutionContext } from '@objectstack/spec/kernel';
3
3
  import * as _objectstack_metadata_core from '@objectstack/metadata-core';
4
4
  import { MetadataRepository, MetaRef, MetadataItem, PutOptions, PutResult, DeleteOptions, DeleteResult, MetadataWriteIntent, ListFilter, MetadataItemHeader, HistoryOptions, MetadataEvent, WatchFilter } from '@objectstack/metadata-core';
5
- import { ObjectStackProtocol, MetadataCacheRequest, MetadataCacheResponse, BatchUpdateRequest, BatchUpdateResponse, UpdateManyDataRequest, DeleteManyDataRequest } from '@objectstack/spec/api';
5
+ import { ObjectStackProtocol, MetadataCacheRequest, MetadataCacheResponse, BatchUpdateRequest, BatchUpdateResponse, UpdateManyDataRequest, DeleteManyDataRequest, InstallPackageRequest, InstallPackageResponse } from '@objectstack/spec/api';
6
6
  import { IDataEngine, DriverInterface, Logger, Plugin, PluginContext, ObjectKernel } from '@objectstack/core';
7
7
  import { IFeedService, IRealtimeService, ICryptoProvider } from '@objectstack/spec/contracts';
8
8
 
@@ -860,7 +860,7 @@ declare class ObjectStackProtocolImplementation implements ObjectStackProtocol {
860
860
  label: string | undefined;
861
861
  required: boolean;
862
862
  readonly: boolean;
863
- type: "number" | "boolean" | "tags" | "date" | "record" | "file" | "code" | "datetime" | "signature" | "progress" | "url" | "currency" | "percent" | "password" | "secret" | "email" | "time" | "text" | "textarea" | "phone" | "markdown" | "html" | "richtext" | "toggle" | "select" | "multiselect" | "radio" | "checkboxes" | "lookup" | "master_detail" | "tree" | "image" | "avatar" | "video" | "audio" | "formula" | "summary" | "autonumber" | "composite" | "repeater" | "location" | "address" | "json" | "color" | "rating" | "slider" | "qrcode" | "vector";
863
+ type: "number" | "boolean" | "tags" | "date" | "record" | "file" | "code" | "datetime" | "signature" | "progress" | "url" | "lookup" | "master_detail" | "currency" | "percent" | "password" | "secret" | "email" | "time" | "text" | "textarea" | "phone" | "markdown" | "html" | "richtext" | "toggle" | "select" | "multiselect" | "radio" | "checkboxes" | "tree" | "image" | "avatar" | "video" | "audio" | "formula" | "summary" | "autonumber" | "composite" | "repeater" | "location" | "address" | "json" | "color" | "rating" | "slider" | "qrcode" | "vector";
864
864
  colSpan: number;
865
865
  }[];
866
866
  }[];
@@ -1144,6 +1144,17 @@ declare class ObjectStackProtocolImplementation implements ObjectStackProtocol {
1144
1144
  * stale schema into the registry.
1145
1145
  */
1146
1146
  private applyObjectRegistryMutation;
1147
+ /**
1148
+ * Ensure a just-PUBLISHED object's physical table exists so it is usable
1149
+ * for data CRUD immediately — without a server restart. Registering the
1150
+ * object (above) only updates the in-memory registry; the table is created
1151
+ * by the driver's schema sync, which otherwise only runs at boot. Without
1152
+ * this, inserting into a freshly-published object fails with "no such
1153
+ * table" (surfaced as `object_not_found`) until the next restart.
1154
+ * Best-effort + non-fatal: drivers without DDL (or read-only datasources)
1155
+ * simply no-op, and a sync failure must not abort the publish.
1156
+ */
1157
+ private ensureObjectStorage;
1147
1158
  saveMetaItem(request: {
1148
1159
  type: string;
1149
1160
  name: string;
@@ -1203,6 +1214,55 @@ declare class ObjectStackProtocolImplementation implements ObjectStackProtocol {
1203
1214
  seq: number;
1204
1215
  message?: string;
1205
1216
  }>;
1217
+ /**
1218
+ * List pending DRAFT metadata (ADR-0033) for the org, optionally narrowed
1219
+ * by `packageId` and/or `type`. The list reads of `getMetaItems` only see
1220
+ * the ACTIVE registry; this exposes what an AI authored but a human hasn't
1221
+ * published yet, so the console can show a "pending changes" surface and a
1222
+ * just-built app package isn't displayed as empty. No body is returned.
1223
+ */
1224
+ listDrafts(request?: {
1225
+ packageId?: string;
1226
+ type?: string;
1227
+ organizationId?: string;
1228
+ }): Promise<{
1229
+ drafts: Array<{
1230
+ type: string;
1231
+ name: string;
1232
+ packageId: string | null;
1233
+ updatedAt: string | null;
1234
+ updatedBy: string | null;
1235
+ }>;
1236
+ }>;
1237
+ /**
1238
+ * Publish every pending DRAFT bound to a package in one shot (ADR-0033) —
1239
+ * the "publish whole app" action. Promotes each draft→active by reusing the
1240
+ * per-item {@link publishMetaItem} primitive (which runs the overridable /
1241
+ * lock guards and refreshes the runtime registry), so this needs NO
1242
+ * `metadata` service (unlike `MetadataService.publishPackage`, which reads
1243
+ * the in-memory registry and 503s when that service is absent). Per-item
1244
+ * failures are collected and do NOT abort the rest.
1245
+ */
1246
+ publishPackageDrafts(request: {
1247
+ packageId: string;
1248
+ organizationId?: string;
1249
+ actor?: string;
1250
+ }): Promise<{
1251
+ success: boolean;
1252
+ publishedCount: number;
1253
+ failedCount: number;
1254
+ published: Array<{
1255
+ type: string;
1256
+ name: string;
1257
+ version: string;
1258
+ }>;
1259
+ failed: Array<{
1260
+ type: string;
1261
+ name: string;
1262
+ error: string;
1263
+ code?: string;
1264
+ }>;
1265
+ }>;
1206
1266
  /**
1207
1267
  * Restore the body recorded at history `toVersion` as the new
1208
1268
  * live row. Writes a history event with `op='revert'`. 404
@@ -1328,6 +1388,24 @@ declare class ObjectStackProtocolImplementation implements ObjectStackProtocol {
1328
1388
  getChangelog(request: any): Promise<any>;
1329
1389
  feedSubscribe(request: any): Promise<any>;
1330
1390
  feedUnsubscribe(request: any): Promise<any>;
1391
+ /**
1392
+ * Install a package from a manifest — the single canonical write primitive
1393
+ * for the package subsystem (ADR-0033 consolidation).
1394
+ *
1395
+ * It writes BOTH stores that the runtime keeps for packages, so a package
1396
+ * surfaces consistently no matter which read path is used:
1397
+ * 1. the in-memory `SchemaRegistry` (what the dispatcher's
1398
+ * `/api/v1/packages` list/detail and `getMetaItems({type:'package'})`
1399
+ * read — i.e. what Studio's package selector shows), and
1400
+ * 2. the durable `sys_packages` table via the optional `package` service
1401
+ * (so the package survives a restart; that service re-hydrates these
1402
+ * rows back into the registry on boot).
1403
+ *
1404
+ * The DB write is best-effort and non-fatal: when the `package` service is
1405
+ * absent (e.g. the `marketplace` capability is off) the package is still
1406
+ * registered in-memory and visible for the lifetime of the process.
1407
+ */
1408
+ installPackage(request: InstallPackageRequest): Promise<InstallPackageResponse>;
1331
1409
  }
1332
1410
 
1333
1411
  /**
@@ -1498,6 +1576,23 @@ declare class SysMetadataRepository implements MetadataRepository {
1498
1576
  item: MetadataItem;
1499
1577
  }>;
1500
1578
  list(filter: ListFilter): AsyncIterable<MetadataItemHeader>;
1579
+ /**
1580
+ * List pending DRAFT rows (ADR-0033) for this org, optionally narrowed by
1581
+ * `type` and/or `packageId`. Unlike {@link list} (which is hard-scoped to
1582
+ * `state='active'`), this reads `state='draft'` so the console can surface
1583
+ * what an AI authored but a human hasn't published yet. Returns a light
1584
+ * header projection (no body) suitable for a "pending changes" list.
1585
+ */
1586
+ listDrafts(filter?: {
1587
+ type?: string;
1588
+ packageId?: string;
1589
+ }): Promise<Array<{
1590
+ type: string;
1591
+ name: string;
1592
+ packageId: string | null;
1593
+ updatedAt: string | null;
1594
+ updatedBy: string | null;
1595
+ }>>;
1501
1596
  /**
1502
1597
  * Yield every history event for `(org, type?, name?)` from the
1503
1598
  * durable log, ordered by per-(type,name) `version` ascending. When
@@ -2058,6 +2153,16 @@ declare class ObjectQL implements IDataEngine {
2058
2153
  * before inserting seed data.
2059
2154
  */
2060
2155
  syncSchemas(): Promise<void>;
2156
+ /**
2157
+ * Sync a SINGLE object's physical storage (create/alter its table) on
2158
+ * demand. Boot-time {@link syncSchemas} runs once at startup, so an object
2159
+ * that becomes live at runtime (e.g. publishing a drafted object) has a
2160
+ * registry entry but no table — data CRUD then fails with "no such table"
2161
+ * until the next restart. Calling this right after the object is registered
2162
+ * makes it immediately usable. Idempotent: the SQL driver only creates the
2163
+ * table when absent (and alters to add new columns).
2164
+ */
2165
+ syncObjectSchema(objectName: string): Promise<void>;
2061
2166
  /**
2062
2167
  * Get a registered driver by datasource name.
2063
2168
  * Alias matching @objectql/core datasource() API.
package/dist/index.js CHANGED
@@ -1288,6 +1288,30 @@ var SysMetadataRepository = class {
1288
1288
  yield header;
1289
1289
  }
1290
1290
  }
1291
+ /**
1292
+ * List pending DRAFT rows (ADR-0033) for this org, optionally narrowed by
1293
+ * `type` and/or `packageId`. Unlike {@link list} (which is hard-scoped to
1294
+ * `state='active'`), this reads `state='draft'` so the console can surface
1295
+ * what an AI authored but a human hasn't published yet. Returns a light
1296
+ * header projection (no body) suitable for a "pending changes" list.
1297
+ */
1298
+ async listDrafts(filter) {
1299
+ this.assertOpen();
1300
+ const where = {
1301
+ organization_id: this.organizationId,
1302
+ state: "draft"
1303
+ };
1304
+ if (filter?.type) where.type = filter.type;
1305
+ if (filter?.packageId) where.package_id = filter.packageId;
1306
+ const rows = await this.engine.find("sys_metadata", { where });
1307
+ return rows.map((row) => ({
1308
+ type: row.type,
1309
+ name: row.name,
1310
+ packageId: row.package_id ?? null,
1311
+ updatedAt: row.updated_at ?? row.created_at ?? null,
1312
+ updatedBy: row.updated_by ?? row.created_by ?? null
1313
+ }));
1314
+ }
1291
1315
  /**
1292
1316
  * Yield every history event for `(org, type?, name?)` from the
1293
1317
  * durable log, ordered by per-(type,name) `version` ascending. When
@@ -1797,6 +1821,13 @@ function resolveOverlaySchema(type, _item) {
1797
1821
  const singular = import_shared4.PLURAL_TO_SINGULAR[type] ?? type;
1798
1822
  return (0, import_kernel4.getMetadataTypeSchema)(singular) ?? null;
1799
1823
  }
1824
+ function normalizeViewMetadata(type, item, saveName) {
1825
+ const singular = import_shared4.PLURAL_TO_SINGULAR[type] ?? type;
1826
+ if (singular !== "view") return item;
1827
+ if (!item || typeof item !== "object" || Array.isArray(item)) return item;
1828
+ const it = item;
1829
+ return it.name ? it : { ...it, name: saveName };
1830
+ }
1800
1831
  function mergeArtifactProtection(item, artifactItem) {
1801
1832
  if (item === void 0 || item === null) return item;
1802
1833
  if (artifactItem === void 0 || artifactItem === null) return item;
@@ -3833,6 +3864,24 @@ var _ObjectStackProtocolImplementation = class _ObjectStackProtocolImplementatio
3833
3864
  );
3834
3865
  }
3835
3866
  }
3867
+ /**
3868
+ * Ensure a just-PUBLISHED object's physical table exists so it is usable
3869
+ * for data CRUD immediately — without a server restart. Registering the
3870
+ * object (above) only updates the in-memory registry; the table is created
3871
+ * by the driver's schema sync, which otherwise only runs at boot. Without
3872
+ * this, inserting into a freshly-published object fails with "no such
3873
+ * table" (surfaced as `object_not_found`) until the next restart.
3874
+ * Best-effort + non-fatal: drivers without DDL (or read-only datasources)
3875
+ * simply no-op, and a sync failure must not abort the publish.
3876
+ */
3877
+ async ensureObjectStorage(type, name) {
3878
+ if (type !== "object" && type !== "objects") return;
3879
+ try {
3880
+ await this.engine.syncObjectSchema(name);
3881
+ } catch (err) {
3882
+ console.warn(`[Protocol] table sync failed for object '${name}': ${err?.message ?? err}`);
3883
+ }
3884
+ }
3836
3885
  async saveMetaItem(request) {
3837
3886
  if (!request.item) {
3838
3887
  throw new Error("Item data is required");
@@ -3906,6 +3955,7 @@ var _ObjectStackProtocolImplementation = class _ObjectStackProtocolImplementatio
3906
3955
  throw err;
3907
3956
  }
3908
3957
  }
3958
+ request.item = normalizeViewMetadata(request.type, request.item, request.name);
3909
3959
  {
3910
3960
  const schema = resolveOverlaySchema(request.type, request.item);
3911
3961
  if (schema) {
@@ -3960,6 +4010,7 @@ var _ObjectStackProtocolImplementation = class _ObjectStackProtocolImplementatio
3960
4010
  });
3961
4011
  if (mode === "publish") {
3962
4012
  this.applyObjectRegistryMutation(request);
4013
+ await this.ensureObjectStorage(request.type, request.name);
3963
4014
  }
3964
4015
  await this.recordMetadataAudit({
3965
4016
  type: request.type,
@@ -4130,6 +4181,7 @@ var _ObjectStackProtocolImplementation = class _ObjectStackProtocolImplementatio
4130
4181
  name: request.name,
4131
4182
  item: result.item.body
4132
4183
  });
4184
+ await this.ensureObjectStorage(request.type, request.name);
4133
4185
  return {
4134
4186
  success: true,
4135
4187
  version: result.version,
@@ -4150,6 +4202,66 @@ var _ObjectStackProtocolImplementation = class _ObjectStackProtocolImplementatio
4150
4202
  throw err;
4151
4203
  }
4152
4204
  }
4205
+ /**
4206
+ * List pending DRAFT metadata (ADR-0033) for the org, optionally narrowed
4207
+ * by `packageId` and/or `type`. The list reads of `getMetaItems` only see
4208
+ * the ACTIVE registry; this exposes what an AI authored but a human hasn't
4209
+ * published yet, so the console can show a "pending changes" surface and a
4210
+ * just-built app package isn't displayed as empty. No body is returned.
4211
+ */
4212
+ async listDrafts(request) {
4213
+ await this.ensureOverlayIndex();
4214
+ const orgId = request?.organizationId ?? null;
4215
+ const repo = this.getOverlayRepo(orgId);
4216
+ const drafts = await repo.listDrafts({
4217
+ ...request?.type ? { type: import_shared4.PLURAL_TO_SINGULAR[request.type] ?? request.type } : {},
4218
+ ...request?.packageId ? { packageId: request.packageId } : {}
4219
+ });
4220
+ return { drafts };
4221
+ }
4222
+ /**
4223
+ * Publish every pending DRAFT bound to a package in one shot (ADR-0033) —
4224
+ * the "publish whole app" action. Promotes each draft→active by reusing the
4225
+ * per-item {@link publishMetaItem} primitive (which runs the overridable /
4226
+ * lock guards and refreshes the runtime registry), so this needs NO
4227
+ * `metadata` service (unlike `MetadataService.publishPackage`, which reads
4228
+ * the in-memory registry and 503s when that service is absent). Per-item
4229
+ * failures are collected and do NOT abort the rest.
4230
+ */
4231
+ async publishPackageDrafts(request) {
4232
+ await this.ensureOverlayIndex();
4233
+ const orgId = request.organizationId ?? null;
4234
+ const repo = this.getOverlayRepo(orgId);
4235
+ const drafts = await repo.listDrafts({ packageId: request.packageId });
4236
+ const published = [];
4237
+ const failed = [];
4238
+ for (const d of drafts) {
4239
+ try {
4240
+ const r = await this.publishMetaItem({
4241
+ type: d.type,
4242
+ name: d.name,
4243
+ ...request.organizationId ? { organizationId: request.organizationId } : {},
4244
+ ...request.actor ? { actor: request.actor } : {},
4245
+ message: `publish app package '${request.packageId}'`
4246
+ });
4247
+ published.push({ type: d.type, name: d.name, version: r.version });
4248
+ } catch (e) {
4249
+ failed.push({
4250
+ type: d.type,
4251
+ name: d.name,
4252
+ error: e?.message ?? "publish failed",
4253
+ ...e?.code ? { code: e.code } : {}
4254
+ });
4255
+ }
4256
+ }
4257
+ return {
4258
+ success: failed.length === 0 && published.length > 0,
4259
+ publishedCount: published.length,
4260
+ failedCount: failed.length,
4261
+ published,
4262
+ failed
4263
+ };
4264
+ }
4153
4265
  /**
4154
4266
  * Restore the body recorded at history `toVersion` as the new
4155
4267
  * live row. Writes a history event with `op='revert'`. 404
@@ -4687,6 +4799,39 @@ var _ObjectStackProtocolImplementation = class _ObjectStackProtocolImplementatio
4687
4799
  const unsubscribed = await svc.unsubscribe(request.object, request.recordId, "current_user");
4688
4800
  return { success: true, data: { object: request.object, recordId: request.recordId, unsubscribed } };
4689
4801
  }
4802
+ /**
4803
+ * Install a package from a manifest — the single canonical write primitive
4804
+ * for the package subsystem (ADR-0033 consolidation).
4805
+ *
4806
+ * It writes BOTH stores that the runtime keeps for packages, so a package
4807
+ * surfaces consistently no matter which read path is used:
4808
+ * 1. the in-memory `SchemaRegistry` (what the dispatcher's
4809
+ * `/api/v1/packages` list/detail and `getMetaItems({type:'package'})`
4810
+ * read — i.e. what Studio's package selector shows), and
4811
+ * 2. the durable `sys_packages` table via the optional `package` service
4812
+ * (so the package survives a restart; that service re-hydrates these
4813
+ * rows back into the registry on boot).
4814
+ *
4815
+ * The DB write is best-effort and non-fatal: when the `package` service is
4816
+ * absent (e.g. the `marketplace` capability is off) the package is still
4817
+ * registered in-memory and visible for the lifetime of the process.
4818
+ */
4819
+ async installPackage(request) {
4820
+ const manifest = request.manifest;
4821
+ const pkg = this.engine.registry.installPackage(manifest, request.settings);
4822
+ try {
4823
+ const services = this.getServicesRegistry?.();
4824
+ const pkgSvc = services?.get("package");
4825
+ if (pkgSvc?.publish && manifest?.version) {
4826
+ await pkgSvc.publish({ manifest, metadata: {} });
4827
+ }
4828
+ } catch (e) {
4829
+ console.warn(
4830
+ `[protocol.installPackage] sys_packages persist skipped for '${manifest?.id}': ${e?.message}`
4831
+ );
4832
+ }
4833
+ return { package: pkg, message: `Installed package: ${manifest?.id}` };
4834
+ }
4690
4835
  };
4691
4836
  /**
4692
4837
  * Metadata types that are customer-overridable via {@link saveMetaItem}/
@@ -7481,6 +7626,23 @@ var _ObjectQL = class _ObjectQL {
7481
7626
  }
7482
7627
  }
7483
7628
  }
7629
+ /**
7630
+ * Sync a SINGLE object's physical storage (create/alter its table) on
7631
+ * demand. Boot-time {@link syncSchemas} runs once at startup, so an object
7632
+ * that becomes live at runtime (e.g. publishing a drafted object) has a
7633
+ * registry entry but no table — data CRUD then fails with "no such table"
7634
+ * until the next restart. Calling this right after the object is registered
7635
+ * makes it immediately usable. Idempotent: the SQL driver only creates the
7636
+ * table when absent (and alters to add new columns).
7637
+ */
7638
+ async syncObjectSchema(objectName) {
7639
+ const obj = this._registry.getObject(objectName);
7640
+ if (!obj) return;
7641
+ const driver = this.getDriverForObject(objectName);
7642
+ if (!driver || typeof driver.syncSchema !== "function") return;
7643
+ const tableName = import_system2.StorageNameMapping.resolveTableName(obj);
7644
+ await driver.syncSchema(tableName, obj);
7645
+ }
7484
7646
  /**
7485
7647
  * Get a registered driver by datasource name.
7486
7648
  * Alias matching @objectql/core datasource() API.