@objectstack/objectql 7.6.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 +120 -10
- package/dist/index.d.ts +120 -10
- package/dist/index.js +186 -4
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +191 -4
- package/dist/index.mjs.map +1 -1
- package/package.json +6 -6
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
|
|
|
@@ -81,11 +81,13 @@ type RegistryLogLevel = 'debug' | 'info' | 'warn' | 'error' | 'silent';
|
|
|
81
81
|
*/
|
|
82
82
|
interface SchemaRegistryOptions {
|
|
83
83
|
/**
|
|
84
|
-
* Whether the host kernel runs in multi-tenant mode.
|
|
85
|
-
*
|
|
86
|
-
*
|
|
87
|
-
* isn't `managedBy` an external subsystem
|
|
88
|
-
* `systemFields:
|
|
84
|
+
* Whether the host kernel runs in multi-tenant mode. The `organization_id`
|
|
85
|
+
* column itself is auto-injected regardless of this flag (lookup →
|
|
86
|
+
* sys_organization, on every registered object that doesn't already declare
|
|
87
|
+
* it, isn't `managedBy` an external subsystem, and hasn't opted out via
|
|
88
|
+
* `systemFields`/`tenancy.enabled:false`). When `true` the injected column
|
|
89
|
+
* is additionally INDEXED — single-tenant stacks skip the index since
|
|
90
|
+
* nothing ever filters by organization.
|
|
89
91
|
*
|
|
90
92
|
* Sourced from the `OS_MULTI_TENANT` env var when not explicitly set —
|
|
91
93
|
* matches how the SecurityPlugin and CLI startup banner pick the mode.
|
|
@@ -107,9 +109,12 @@ interface SchemaRegistryOptions {
|
|
|
107
109
|
* via the natural `{ ...sys, ...authored }` merge.
|
|
108
110
|
*
|
|
109
111
|
* Currently injects:
|
|
110
|
-
* - `organization_id` —
|
|
111
|
-
*
|
|
112
|
-
*
|
|
112
|
+
* - `organization_id` — always provisioned (unless the object opts out via
|
|
113
|
+
* `systemFields`/`tenancy.enabled:false` or is `better-auth` managed) so
|
|
114
|
+
* the column never depends on the global multi-tenant flag. Required-false;
|
|
115
|
+
* org-scoping populates it on insert in multi-tenant mode, and it stays
|
|
116
|
+
* NULL on single-tenant stacks. Only the column's INDEX is gated on
|
|
117
|
+
* `multiTenant` (no per-tenant filtering exists single-tenant).
|
|
113
118
|
* - `created_at` / `created_by` / `updated_at` / `updated_by` — audit
|
|
114
119
|
* fields. Marked `system: true, readonly: true` so detail views can
|
|
115
120
|
* surface them in a dedicated "System Information" section while
|
|
@@ -855,7 +860,7 @@ declare class ObjectStackProtocolImplementation implements ObjectStackProtocol {
|
|
|
855
860
|
label: string | undefined;
|
|
856
861
|
required: boolean;
|
|
857
862
|
readonly: boolean;
|
|
858
|
-
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" | "
|
|
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";
|
|
859
864
|
colSpan: number;
|
|
860
865
|
}[];
|
|
861
866
|
}[];
|
|
@@ -1139,6 +1144,17 @@ declare class ObjectStackProtocolImplementation implements ObjectStackProtocol {
|
|
|
1139
1144
|
* stale schema into the registry.
|
|
1140
1145
|
*/
|
|
1141
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;
|
|
1142
1158
|
saveMetaItem(request: {
|
|
1143
1159
|
type: string;
|
|
1144
1160
|
name: string;
|
|
@@ -1198,6 +1214,55 @@ declare class ObjectStackProtocolImplementation implements ObjectStackProtocol {
|
|
|
1198
1214
|
seq: number;
|
|
1199
1215
|
message?: string;
|
|
1200
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
|
+
}>;
|
|
1201
1266
|
/**
|
|
1202
1267
|
* Restore the body recorded at history `toVersion` as the new
|
|
1203
1268
|
* live row. Writes a history event with `op='revert'`. 404
|
|
@@ -1323,6 +1388,24 @@ declare class ObjectStackProtocolImplementation implements ObjectStackProtocol {
|
|
|
1323
1388
|
getChangelog(request: any): Promise<any>;
|
|
1324
1389
|
feedSubscribe(request: any): Promise<any>;
|
|
1325
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>;
|
|
1326
1409
|
}
|
|
1327
1410
|
|
|
1328
1411
|
/**
|
|
@@ -1493,6 +1576,23 @@ declare class SysMetadataRepository implements MetadataRepository {
|
|
|
1493
1576
|
item: MetadataItem;
|
|
1494
1577
|
}>;
|
|
1495
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
|
+
}>>;
|
|
1496
1596
|
/**
|
|
1497
1597
|
* Yield every history event for `(org, type?, name?)` from the
|
|
1498
1598
|
* durable log, ordered by per-(type,name) `version` ascending. When
|
|
@@ -2053,6 +2153,16 @@ declare class ObjectQL implements IDataEngine {
|
|
|
2053
2153
|
* before inserting seed data.
|
|
2054
2154
|
*/
|
|
2055
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>;
|
|
2056
2166
|
/**
|
|
2057
2167
|
* Get a registered driver by datasource name.
|
|
2058
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
|
|
|
@@ -81,11 +81,13 @@ type RegistryLogLevel = 'debug' | 'info' | 'warn' | 'error' | 'silent';
|
|
|
81
81
|
*/
|
|
82
82
|
interface SchemaRegistryOptions {
|
|
83
83
|
/**
|
|
84
|
-
* Whether the host kernel runs in multi-tenant mode.
|
|
85
|
-
*
|
|
86
|
-
*
|
|
87
|
-
* isn't `managedBy` an external subsystem
|
|
88
|
-
* `systemFields:
|
|
84
|
+
* Whether the host kernel runs in multi-tenant mode. The `organization_id`
|
|
85
|
+
* column itself is auto-injected regardless of this flag (lookup →
|
|
86
|
+
* sys_organization, on every registered object that doesn't already declare
|
|
87
|
+
* it, isn't `managedBy` an external subsystem, and hasn't opted out via
|
|
88
|
+
* `systemFields`/`tenancy.enabled:false`). When `true` the injected column
|
|
89
|
+
* is additionally INDEXED — single-tenant stacks skip the index since
|
|
90
|
+
* nothing ever filters by organization.
|
|
89
91
|
*
|
|
90
92
|
* Sourced from the `OS_MULTI_TENANT` env var when not explicitly set —
|
|
91
93
|
* matches how the SecurityPlugin and CLI startup banner pick the mode.
|
|
@@ -107,9 +109,12 @@ interface SchemaRegistryOptions {
|
|
|
107
109
|
* via the natural `{ ...sys, ...authored }` merge.
|
|
108
110
|
*
|
|
109
111
|
* Currently injects:
|
|
110
|
-
* - `organization_id` —
|
|
111
|
-
*
|
|
112
|
-
*
|
|
112
|
+
* - `organization_id` — always provisioned (unless the object opts out via
|
|
113
|
+
* `systemFields`/`tenancy.enabled:false` or is `better-auth` managed) so
|
|
114
|
+
* the column never depends on the global multi-tenant flag. Required-false;
|
|
115
|
+
* org-scoping populates it on insert in multi-tenant mode, and it stays
|
|
116
|
+
* NULL on single-tenant stacks. Only the column's INDEX is gated on
|
|
117
|
+
* `multiTenant` (no per-tenant filtering exists single-tenant).
|
|
113
118
|
* - `created_at` / `created_by` / `updated_at` / `updated_by` — audit
|
|
114
119
|
* fields. Marked `system: true, readonly: true` so detail views can
|
|
115
120
|
* surface them in a dedicated "System Information" section while
|
|
@@ -855,7 +860,7 @@ declare class ObjectStackProtocolImplementation implements ObjectStackProtocol {
|
|
|
855
860
|
label: string | undefined;
|
|
856
861
|
required: boolean;
|
|
857
862
|
readonly: boolean;
|
|
858
|
-
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" | "
|
|
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";
|
|
859
864
|
colSpan: number;
|
|
860
865
|
}[];
|
|
861
866
|
}[];
|
|
@@ -1139,6 +1144,17 @@ declare class ObjectStackProtocolImplementation implements ObjectStackProtocol {
|
|
|
1139
1144
|
* stale schema into the registry.
|
|
1140
1145
|
*/
|
|
1141
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;
|
|
1142
1158
|
saveMetaItem(request: {
|
|
1143
1159
|
type: string;
|
|
1144
1160
|
name: string;
|
|
@@ -1198,6 +1214,55 @@ declare class ObjectStackProtocolImplementation implements ObjectStackProtocol {
|
|
|
1198
1214
|
seq: number;
|
|
1199
1215
|
message?: string;
|
|
1200
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
|
+
}>;
|
|
1201
1266
|
/**
|
|
1202
1267
|
* Restore the body recorded at history `toVersion` as the new
|
|
1203
1268
|
* live row. Writes a history event with `op='revert'`. 404
|
|
@@ -1323,6 +1388,24 @@ declare class ObjectStackProtocolImplementation implements ObjectStackProtocol {
|
|
|
1323
1388
|
getChangelog(request: any): Promise<any>;
|
|
1324
1389
|
feedSubscribe(request: any): Promise<any>;
|
|
1325
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>;
|
|
1326
1409
|
}
|
|
1327
1410
|
|
|
1328
1411
|
/**
|
|
@@ -1493,6 +1576,23 @@ declare class SysMetadataRepository implements MetadataRepository {
|
|
|
1493
1576
|
item: MetadataItem;
|
|
1494
1577
|
}>;
|
|
1495
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
|
+
}>>;
|
|
1496
1596
|
/**
|
|
1497
1597
|
* Yield every history event for `(org, type?, name?)` from the
|
|
1498
1598
|
* durable log, ordered by per-(type,name) `version` ascending. When
|
|
@@ -2053,6 +2153,16 @@ declare class ObjectQL implements IDataEngine {
|
|
|
2053
2153
|
* before inserting seed data.
|
|
2054
2154
|
*/
|
|
2055
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>;
|
|
2056
2166
|
/**
|
|
2057
2167
|
* Get a registered driver by datasource name.
|
|
2058
2168
|
* Alias matching @objectql/core datasource() API.
|
package/dist/index.js
CHANGED
|
@@ -110,7 +110,7 @@ function applySystemFields(schema, opts) {
|
|
|
110
110
|
if (schema.managedBy === "better-auth") return schema;
|
|
111
111
|
const sf = typeof schema.systemFields === "object" && schema.systemFields !== null ? schema.systemFields : void 0;
|
|
112
112
|
const tenancyDisabled = schema.tenancy?.enabled === false;
|
|
113
|
-
const wantTenant =
|
|
113
|
+
const wantTenant = sf?.tenant !== false && !tenancyDisabled;
|
|
114
114
|
const wantAudit = sf?.audit !== false;
|
|
115
115
|
const additions = {};
|
|
116
116
|
if (wantTenant && !schema.fields?.organization_id) {
|
|
@@ -119,11 +119,11 @@ function applySystemFields(schema, opts) {
|
|
|
119
119
|
reference: "sys_organization",
|
|
120
120
|
label: "Organization",
|
|
121
121
|
required: false,
|
|
122
|
-
indexed:
|
|
122
|
+
indexed: opts.multiTenant,
|
|
123
123
|
hidden: true,
|
|
124
124
|
readonly: true,
|
|
125
125
|
system: true,
|
|
126
|
-
description: "Tenant scope (auto-populated by
|
|
126
|
+
description: "Tenant scope (auto-populated by org-scoping on insert; NULL on single-tenant stacks)."
|
|
127
127
|
};
|
|
128
128
|
}
|
|
129
129
|
if (wantAudit) {
|
|
@@ -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}/
|
|
@@ -7078,7 +7223,11 @@ var _ObjectQL = class _ObjectQL {
|
|
|
7078
7223
|
const driver = this.getDriver(object);
|
|
7079
7224
|
let id = data.id;
|
|
7080
7225
|
if (!id && options?.where && typeof options.where === "object" && "id" in options.where) {
|
|
7081
|
-
|
|
7226
|
+
const whereId = options.where.id;
|
|
7227
|
+
const t = typeof whereId;
|
|
7228
|
+
if (whereId !== null && (t === "string" || t === "number" || t === "bigint")) {
|
|
7229
|
+
id = whereId;
|
|
7230
|
+
}
|
|
7082
7231
|
}
|
|
7083
7232
|
const opCtx = {
|
|
7084
7233
|
object,
|
|
@@ -7477,6 +7626,23 @@ var _ObjectQL = class _ObjectQL {
|
|
|
7477
7626
|
}
|
|
7478
7627
|
}
|
|
7479
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
|
+
}
|
|
7480
7646
|
/**
|
|
7481
7647
|
* Get a registered driver by datasource name.
|
|
7482
7648
|
* Alias matching @objectql/core datasource() API.
|
|
@@ -7803,6 +7969,7 @@ var MetadataFacade = class {
|
|
|
7803
7969
|
|
|
7804
7970
|
// src/plugin.ts
|
|
7805
7971
|
var import_system3 = require("@objectstack/spec/system");
|
|
7972
|
+
var import_metadata_core3 = require("@objectstack/metadata-core");
|
|
7806
7973
|
function hasLoadMetaFromDb(service) {
|
|
7807
7974
|
return typeof service === "object" && service !== null && typeof service["loadMetaFromDb"] === "function";
|
|
7808
7975
|
}
|
|
@@ -7839,6 +8006,21 @@ var ObjectQLPlugin = class {
|
|
|
7839
8006
|
ctx.logger.info("ObjectQL engine registered", {
|
|
7840
8007
|
services: ["objectql", "data", "manifest"]
|
|
7841
8008
|
});
|
|
8009
|
+
if (this.environmentId === void 0) {
|
|
8010
|
+
this.ql.registerApp({
|
|
8011
|
+
id: "com.objectstack.metadata-objects",
|
|
8012
|
+
name: "Metadata Platform Objects",
|
|
8013
|
+
version: "1.0.0",
|
|
8014
|
+
type: "plugin",
|
|
8015
|
+
scope: "system",
|
|
8016
|
+
objects: [
|
|
8017
|
+
import_metadata_core3.SysMetadataObject,
|
|
8018
|
+
import_metadata_core3.SysMetadataHistoryObject,
|
|
8019
|
+
import_metadata_core3.SysMetadataAuditObject,
|
|
8020
|
+
import_metadata_core3.SysViewDefinitionObject
|
|
8021
|
+
]
|
|
8022
|
+
});
|
|
8023
|
+
}
|
|
7842
8024
|
const protocolShim = new ObjectStackProtocolImplementation(
|
|
7843
8025
|
this.ql,
|
|
7844
8026
|
() => ctx.getServices ? ctx.getServices() : /* @__PURE__ */ new Map(),
|