@objectstack/objectql 6.9.0 → 7.1.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
@@ -1,7 +1,7 @@
1
1
  import { ServiceObject, ObjectOwnership, HookContext, QueryAST, EngineQueryOptions, DataEngineInsertOptions, EngineUpdateOptions, EngineDeleteOptions, EngineCountOptions, EngineAggregateOptions, DateGranularityValue, Hook } from '@objectstack/spec/data';
2
- import { ObjectStackManifest, InstalledPackage, ExecutionContext } from '@objectstack/spec/kernel';
2
+ import { ObjectStackManifest, InstalledPackage, MetadataValidationResult, ExecutionContext } from '@objectstack/spec/kernel';
3
3
  import * as _objectstack_metadata_core from '@objectstack/metadata-core';
4
- import { MetadataRepository, MetaRef, MetadataItem, PutOptions, PutResult, DeleteOptions, DeleteResult, ListFilter, MetadataItemHeader, HistoryOptions, MetadataEvent, WatchFilter } from '@objectstack/metadata-core';
4
+ import { MetadataRepository, MetaRef, MetadataItem, PutOptions, PutResult, DeleteOptions, DeleteResult, MetadataWriteIntent, ListFilter, MetadataItemHeader, HistoryOptions, MetadataEvent, WatchFilter } from '@objectstack/metadata-core';
5
5
  import { ObjectStackProtocol, MetadataCacheRequest, MetadataCacheResponse, BatchUpdateRequest, BatchUpdateResponse, UpdateManyDataRequest, DeleteManyDataRequest } from '@objectstack/spec/api';
6
6
  import { IDataEngine, DriverInterface, Logger, Plugin, PluginContext, ObjectKernel } from '@objectstack/core';
7
7
  import { IFeedService, IRealtimeService } from '@objectstack/spec/contracts';
@@ -270,6 +270,12 @@ declare class SchemaRegistry {
270
270
  reset(): void;
271
271
  }
272
272
 
273
+ /**
274
+ * Re-export the canonical validation-result type so callers in this
275
+ * package don't need to dual-import from `@objectstack/spec/kernel`.
276
+ */
277
+ type MetadataDiagnostics = MetadataValidationResult;
278
+
273
279
  declare class ObjectStackProtocolImplementation implements ObjectStackProtocol {
274
280
  private engine;
275
281
  private getServicesRegistry?;
@@ -399,6 +405,7 @@ declare class ObjectStackProtocolImplementation implements ObjectStackProtocol {
399
405
  collapsed: boolean;
400
406
  columns: 1 | 2 | 3 | 4;
401
407
  fields: any[];
408
+ name?: string | undefined;
402
409
  label?: string | undefined;
403
410
  description?: string | undefined;
404
411
  visibleOn?: {
@@ -424,6 +431,7 @@ declare class ObjectStackProtocolImplementation implements ObjectStackProtocol {
424
431
  collapsed: boolean;
425
432
  columns: 1 | 2 | 3 | 4;
426
433
  fields: any[];
434
+ name?: string | undefined;
427
435
  label?: string | undefined;
428
436
  description?: string | undefined;
429
437
  visibleOn?: {
@@ -486,19 +494,55 @@ declare class ObjectStackProtocolImplementation implements ObjectStackProtocol {
486
494
  description?: string | undefined;
487
495
  }[];
488
496
  }>;
497
+ /**
498
+ * Sweep all (or filtered) metadata types and report entries that
499
+ * fail spec validation. Powers the Studio governance view
500
+ * (`GET /api/v1/meta/diagnostics`) and `os doctor`-style CLI
501
+ * checks.
502
+ *
503
+ * `severity` defaults to `'error'` — only entries with at least
504
+ * one Zod error issue are returned. `'warning'` includes
505
+ * everything we surface (warnings are reserved for a future lint
506
+ * layer on top of spec validation).
507
+ *
508
+ * `type` may be either a singular (`'view'`) or plural (`'views'`)
509
+ * identifier; the underlying `getMetaItems` already normalises.
510
+ *
511
+ * Implementation note: leverages the `_diagnostics` already
512
+ * decorated onto items by `getMetaItems()` to avoid running
513
+ * `safeParse()` twice. For types whose schema is unregistered we
514
+ * skip silently (they cannot be validated and should not appear
515
+ * as "valid" either — they are simply opaque to this report).
516
+ */
517
+ getMetaDiagnostics(request?: {
518
+ type?: string;
519
+ severity?: 'error' | 'warning';
520
+ organizationId?: string;
521
+ packageId?: string;
522
+ }): Promise<{
523
+ entries: Array<{
524
+ type: string;
525
+ name: string;
526
+ diagnostics: MetadataDiagnostics;
527
+ }>;
528
+ total: number;
529
+ scannedTypes: number;
530
+ scannedItems: number;
531
+ }>;
489
532
  getMetaItems(request: {
490
533
  type: string;
491
534
  packageId?: string;
492
535
  organizationId?: string;
493
536
  }): Promise<{
494
537
  type: string;
495
- items: unknown[];
538
+ items: any[];
496
539
  }>;
497
540
  getMetaItem(request: {
498
541
  type: string;
499
542
  name: string;
500
543
  packageId?: string;
501
544
  organizationId?: string;
545
+ state?: 'active' | 'draft';
502
546
  }): Promise<{
503
547
  type: string;
504
548
  name: string;
@@ -530,6 +574,15 @@ declare class ObjectStackProtocolImplementation implements ObjectStackProtocol {
530
574
  overlay: unknown | null;
531
575
  overlayScope: 'org' | 'env' | null;
532
576
  effective: unknown | null;
577
+ /**
578
+ * Load-time validation result for the effective payload — same
579
+ * shape attached to getMetaItems/getMetaItem by
580
+ * decorateMetadataItem. Undefined for types without a registered
581
+ * Zod schema (function/service/router). Lets the Studio edit
582
+ * page surface invalid-metadata banners + inline field errors
583
+ * without a second round-trip.
584
+ */
585
+ _diagnostics?: MetadataDiagnostics;
533
586
  }>;
534
587
  getUiView(request: {
535
588
  object: string;
@@ -563,7 +616,7 @@ declare class ObjectStackProtocolImplementation implements ObjectStackProtocol {
563
616
  label: string | undefined;
564
617
  required: boolean;
565
618
  readonly: boolean;
566
- type: "number" | "boolean" | "tags" | "date" | "file" | "code" | "datetime" | "signature" | "progress" | "url" | "text" | "textarea" | "email" | "phone" | "password" | "markdown" | "html" | "richtext" | "currency" | "percent" | "time" | "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";
619
+ type: "number" | "boolean" | "tags" | "date" | "record" | "file" | "code" | "datetime" | "signature" | "progress" | "url" | "text" | "textarea" | "email" | "phone" | "password" | "markdown" | "html" | "richtext" | "currency" | "percent" | "time" | "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";
567
620
  colSpan: number;
568
621
  }[];
569
622
  }[];
@@ -760,8 +813,44 @@ declare class ObjectStackProtocolImplementation implements ObjectStackProtocol {
760
813
  private static envWritableTypes;
761
814
  /** Test hook — clear the memoised env-writable cache. */
762
815
  static resetEnvWritableCache(): void;
816
+ /**
817
+ * Types that opt into runtime creation of brand-new items (ADR-0005
818
+ * extension — two-tier model). A type may have
819
+ * `allowOrgOverride: false` (cannot overlay artifact-shipped items)
820
+ * yet still set `allowRuntimeCreate: true` (users can author new
821
+ * items in `sys_metadata`). The two flags are orthogonal; see
822
+ * {@link isArtifactBacked} for how the protocol decides which gate
823
+ * applies to a given save/delete.
824
+ */
825
+ /**
826
+ * Set of type names that have a static entry in
827
+ * `DEFAULT_METADATA_TYPE_REGISTRY`. Anything outside this set is
828
+ * runtime-registered (plugin-provided types like `theme`, `api`,
829
+ * `connector`) — the listing endpoint at `getMetaTypes()` synthesises
830
+ * those with `allowRuntimeCreate: true`, so this gate must agree.
831
+ */
832
+ private static readonly STATIC_REGISTRY_TYPES;
833
+ private static readonly RUNTIME_CREATE_ALLOWED_TYPES;
763
834
  /** Normalize plural→singular before consulting the allow-list. */
764
835
  private static isOverlayAllowed;
836
+ /** Does this type permit creating brand-new (artifact-free) items? */
837
+ private static isRuntimeCreateAllowed;
838
+ /**
839
+ * Does an artifact (npm-package-loaded) item exist at `(type, name)`?
840
+ *
841
+ * The schema registry's `_packageId` tag is set only when
842
+ * `registerItem(..., packageId)` is called with a truthy packageId
843
+ * — and only artifact loaders do that. DB-rehydrated items
844
+ * (sys_metadata rows registered back into the registry by
845
+ * `getMetaItems` / `loadMetaFromDb`) call `registerItem` without a
846
+ * packageId, so they carry no `_packageId` and are correctly
847
+ * excluded here.
848
+ *
849
+ * Used by the two-tier authorization model to distinguish
850
+ * "overlaying a packaged item" (requires `allowOrgOverride`) from
851
+ * "authoring a DB-only item" (requires only `allowRuntimeCreate`).
852
+ */
853
+ private isArtifactBacked;
765
854
  /**
766
855
  * Mirror an object-type overlay write into the in-memory engine
767
856
  * registry so subsequent CRUD finds the new schema. Idempotent and
@@ -781,16 +870,19 @@ declare class ObjectStackProtocolImplementation implements ObjectStackProtocol {
781
870
  parentVersion?: string | null;
782
871
  actor?: string;
783
872
  force?: boolean;
873
+ mode?: 'draft' | 'publish';
784
874
  }): Promise<{
785
875
  success: boolean;
786
876
  version: string;
787
877
  seq: number;
878
+ state: string;
788
879
  message: string;
789
880
  } | {
790
881
  success: boolean;
791
882
  message: string;
792
883
  version?: undefined;
793
884
  seq?: undefined;
885
+ state?: undefined;
794
886
  }>;
795
887
  /**
796
888
  * Yield the durable change-log for a single metadata item — every
@@ -811,6 +903,78 @@ declare class ObjectStackProtocolImplementation implements ObjectStackProtocol {
811
903
  }): Promise<{
812
904
  events: _objectstack_metadata_core.MetadataEvent[];
813
905
  }>;
906
+ /**
907
+ * Promote the pending draft overlay to the live (`active`) row.
908
+ * Records a history event with `op='publish'`. 404 (`[no_draft]`)
909
+ * when there is nothing to publish.
910
+ */
911
+ publishMetaItem(request: {
912
+ type: string;
913
+ name: string;
914
+ organizationId?: string;
915
+ actor?: string;
916
+ message?: string;
917
+ }): Promise<{
918
+ success: boolean;
919
+ version: string;
920
+ seq: number;
921
+ message?: string;
922
+ }>;
923
+ /**
924
+ * Restore the body recorded at history `toVersion` as the new
925
+ * live row. Writes a history event with `op='revert'`. 404
926
+ * (`[version_not_found]`) when the target version doesn't exist;
927
+ * 409 (`[version_not_restorable]`) when the target is a delete
928
+ * tombstone (no body to bring back).
929
+ */
930
+ rollbackMetaItem(request: {
931
+ type: string;
932
+ name: string;
933
+ toVersion: number;
934
+ organizationId?: string;
935
+ actor?: string;
936
+ message?: string;
937
+ }): Promise<{
938
+ success: boolean;
939
+ version: string;
940
+ seq: number;
941
+ restoredFromVersion: number;
942
+ message?: string;
943
+ }>;
944
+ /**
945
+ * Compute a shallow structural diff between two historical
946
+ * versions of a metadata item. Either side may be omitted: when
947
+ * `toVersion` is undefined the current active body is used; when
948
+ * `fromVersion` is undefined the immediately previous history row
949
+ * is used. Returns `{ added, removed, changed }` keyed by JSON
950
+ * pointer-style paths for primitive leaves; nested objects/arrays
951
+ * are reported as a single change record.
952
+ */
953
+ diffMetaItem(request: {
954
+ type: string;
955
+ name: string;
956
+ fromVersion?: number;
957
+ toVersion?: number;
958
+ organizationId?: string;
959
+ }): Promise<{
960
+ type: string;
961
+ name: string;
962
+ fromVersion: number | null;
963
+ toVersion: number | null;
964
+ added: Array<{
965
+ path: string;
966
+ value: unknown;
967
+ }>;
968
+ removed: Array<{
969
+ path: string;
970
+ value: unknown;
971
+ }>;
972
+ changed: Array<{
973
+ path: string;
974
+ from: unknown;
975
+ to: unknown;
976
+ }>;
977
+ }>;
814
978
  /**
815
979
  * Remove a customization overlay row for the given metadata item, so the
816
980
  * next read falls through to the artifact-loaded default. Implements the
@@ -823,6 +987,7 @@ declare class ObjectStackProtocolImplementation implements ObjectStackProtocol {
823
987
  organizationId?: string;
824
988
  parentVersion?: string | null;
825
989
  actor?: string;
990
+ state?: 'active' | 'draft';
826
991
  }): Promise<{
827
992
  success: boolean;
828
993
  message?: string;
@@ -882,6 +1047,28 @@ declare class ObjectStackProtocolImplementation implements ObjectStackProtocol {
882
1047
  feedUnsubscribe(request: any): Promise<any>;
883
1048
  }
884
1049
 
1050
+ /**
1051
+ * Overlay-row lifecycle state.
1052
+ *
1053
+ * - `'active'` → the published, live overlay. `getMetaItem` (the
1054
+ * default read path) and runtime loaders observe this row.
1055
+ * - `'draft'` → an unpublished pending change. Lives alongside the
1056
+ * active row (one of each per `(org,type,name)`). Promoted to
1057
+ * `active` via {@link SysMetadataRepository.promoteDraft}.
1058
+ *
1059
+ * Other lifecycle values defined on `sys_metadata.state` (`'archived'`,
1060
+ * `'deprecated'`) are not yet plumbed through the overlay write path;
1061
+ * they remain reserved for future flows (item retirement, freeze).
1062
+ */
1063
+ type OverlayState = 'active' | 'draft';
1064
+ /**
1065
+ * Extended history operation tag. The base `'create' | 'update' |
1066
+ * 'delete'` operations are emitted by the canonical put/delete paths.
1067
+ * `'publish'` is recorded when a draft is promoted, `'revert'` when a
1068
+ * historical version is restored. Both are surfaced as MetadataEvent
1069
+ * `.op` values via `history()`.
1070
+ */
1071
+ type ExtendedOperation = 'create' | 'update' | 'publish' | 'revert' | 'delete';
885
1072
  /**
886
1073
  * Sub-set of the ObjectQL engine shape we depend on. Kept narrow so
887
1074
  * tests can stub it with a plain mock. Mirrors the real engine's
@@ -961,8 +1148,14 @@ declare class SysMetadataRepository implements MetadataRepository {
961
1148
  /**
962
1149
  * Read the current overlay row. Returns null if no row exists —
963
1150
  * callers (e.g. LayeredRepository) fall through to lower layers.
1151
+ *
1152
+ * `opts.state` selects which lifecycle row to read: defaults to the
1153
+ * live published row (`'active'`). Pass `'draft'` to read the pending
1154
+ * unpublished revision (if any).
964
1155
  */
965
- get(ref: MetaRef): Promise<MetadataItem | null>;
1156
+ get(ref: MetaRef, opts?: {
1157
+ state?: OverlayState;
1158
+ }): Promise<MetadataItem | null>;
966
1159
  /**
967
1160
  * Resolve a historical version by content hash (ADR-0009).
968
1161
  *
@@ -972,8 +1165,55 @@ declare class SysMetadataRepository implements MetadataRepository {
972
1165
  * them.
973
1166
  */
974
1167
  getByHash(ref: MetaRef, hash: string): Promise<MetadataItem | null>;
975
- put(ref: MetaRef, spec: unknown, opts: PutOptions): Promise<PutResult>;
976
- delete(ref: MetaRef, opts: DeleteOptions): Promise<DeleteResult>;
1168
+ put(ref: MetaRef, spec: unknown, opts: PutOptions & {
1169
+ state?: OverlayState;
1170
+ opType?: ExtendedOperation;
1171
+ }): Promise<PutResult>;
1172
+ delete(ref: MetaRef, opts: DeleteOptions & {
1173
+ state?: OverlayState;
1174
+ }): Promise<DeleteResult>;
1175
+ /**
1176
+ * Promote the pending draft row for `ref` into the live (`active`)
1177
+ * overlay. Atomic: reads the draft inside the same transaction, runs
1178
+ * the canonical `put` to upsert the active row (which appends a
1179
+ * history event with `operation_type='publish'`), then deletes the
1180
+ * draft row.
1181
+ *
1182
+ * Errors if no draft exists (callers should 404). The active row's
1183
+ * `parentVersion` is computed from the current active hash so this
1184
+ * also surfaces optimistic-lock conflicts when something else has
1185
+ * published in between (e.g. another admin reverted to an older
1186
+ * version since the draft was authored).
1187
+ */
1188
+ promoteDraft(ref: MetaRef, opts: {
1189
+ actor: string;
1190
+ source?: string;
1191
+ message?: string;
1192
+ intent?: MetadataWriteIntent;
1193
+ }): Promise<{
1194
+ version: string;
1195
+ seq: number;
1196
+ item: MetadataItem;
1197
+ }>;
1198
+ /**
1199
+ * Restore the body recorded in history at `targetVersion` (per-org
1200
+ * lineage counter) as the new active row. Writes a history event
1201
+ * with `operation_type='revert'` so the audit trail captures the
1202
+ * intent. Does NOT touch any draft row.
1203
+ *
1204
+ * Throws `[version_not_found]` (404) if the target version row is
1205
+ * missing or is a delete tombstone (no body to restore).
1206
+ */
1207
+ restoreVersion(ref: MetaRef, targetVersion: number, opts: {
1208
+ actor: string;
1209
+ source?: string;
1210
+ message?: string;
1211
+ intent?: MetadataWriteIntent;
1212
+ }): Promise<{
1213
+ version: string;
1214
+ seq: number;
1215
+ item: MetadataItem;
1216
+ }>;
977
1217
  list(filter: ListFilter): AsyncIterable<MetadataItemHeader>;
978
1218
  /**
979
1219
  * Yield every history event for `(org, type?, name?)` from the
@@ -994,6 +1234,19 @@ declare class SysMetadataRepository implements MetadataRepository {
994
1234
  /** Shut down all watch iterators. */
995
1235
  close(): void;
996
1236
  private assertOpen;
1237
+ /**
1238
+ * Defense-in-depth authorization gate.
1239
+ *
1240
+ * `intent` defaults to `'override-artifact'` (the historical strict
1241
+ * behavior). The protocol layer passes `'runtime-only'` after it has
1242
+ * verified — via the schema registry — that no artifact item exists
1243
+ * at `(type, name)`. In that case we accept types with
1244
+ * `allowRuntimeCreate: true`, even when `allowOrgOverride` is false.
1245
+ *
1246
+ * The env-var escape hatch (`OBJECTSTACK_METADATA_WRITABLE`) still
1247
+ * applies to BOTH intents, so operators can opt into artifact
1248
+ * overrides at runtime for emergency fixes.
1249
+ */
997
1250
  private assertAllowed;
998
1251
  private whereFor;
999
1252
  private fullRef;