@feasibleone/blong 1.16.0 → 1.17.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/CHANGELOG.md CHANGED
@@ -1,5 +1,34 @@
1
1
  # Changelog
2
2
 
3
+ ## [1.17.0](https://github.com/feasibleone/blong/compare/blong-v1.16.1...blong-v1.17.0) (2026-04-26)
4
+
5
+
6
+ ### Features
7
+
8
+ * add support for the browser platform ([f483e14](https://github.com/feasibleone/blong/commit/f483e149711acdeebcf9ee5afa3bf7ac7a6b669c))
9
+ * implement wiring pipeline simplifications ([0a3dc01](https://github.com/feasibleone/blong/commit/0a3dc01e97c158d30491e8b76bef7d6bb4987529))
10
+ * model handling ([168e77e](https://github.com/feasibleone/blong/commit/168e77ec3284bbcebf5d7d6bb07cc624d0d1a56e))
11
+ * model init ([7e18e00](https://github.com/feasibleone/blong/commit/7e18e002e3d9d9d2e996762d3ce7dd70d6a7d0be))
12
+ * model mocks ([118a142](https://github.com/feasibleone/blong/commit/118a14254f87b8d1cf0b4d217939a9d49942f93e))
13
+
14
+
15
+ ### Bug Fixes
16
+
17
+ * dependencies ([dd785c4](https://github.com/feasibleone/blong/commit/dd785c49c20045a804df0527638191f5d7d32a49))
18
+ * dependencies ([a21d8eb](https://github.com/feasibleone/blong/commit/a21d8ebe4ce9b476060dec8eeb9017a5eb7f07b5))
19
+ * dependencies ([705b2f7](https://github.com/feasibleone/blong/commit/705b2f7a72ac2dc93aea0f586394dde71192c1b6))
20
+ * eslint ([a3b9f2b](https://github.com/feasibleone/blong/commit/a3b9f2bed4f958abfb378d97d372b3e7a6cd5a21))
21
+ * optimize browser loading ([0aac985](https://github.com/feasibleone/blong/commit/0aac985a24520810dc05eb34d314ed7dec4f1962))
22
+ * remove heft lint ([c4d0eaa](https://github.com/feasibleone/blong/commit/c4d0eaa81714c04e9f9adec01c6ae7fa068f1948))
23
+ * types ([b7f0b57](https://github.com/feasibleone/blong/commit/b7f0b57159019dbeb80b9021b04e04eee57468ba))
24
+
25
+ ## [1.16.1](https://github.com/feasibleone/blong/compare/blong-v1.16.0...blong-v1.16.1) (2026-04-10)
26
+
27
+
28
+ ### Bug Fixes
29
+
30
+ * build ([32951e4](https://github.com/feasibleone/blong/commit/32951e46561648651ee4e032545655007c05e274))
31
+
3
32
  ## [1.16.0](https://github.com/feasibleone/blong/compare/blong-v1.15.0...blong-v1.16.0) (2026-04-10)
4
33
 
5
34
 
package/dist/model.js ADDED
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Model system types.
3
+ *
4
+ * A ModelSpec describes one "subject.object" domain entity and drives:
5
+ * - automatic Browse / New / Open / Report page generation
6
+ * - schema enrichment (server OpenAPI merged with browser overlay)
7
+ * - dropdown dependency tracking and caching
8
+ */
9
+ export {};
10
+ //# sourceMappingURL=model.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"model.js","sourceRoot":"","sources":["../model.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG"}
package/dist/types.d.ts CHANGED
@@ -1,10 +1,11 @@
1
1
  // Generated by dts-bundle-generator v9.5.1
2
2
 
3
+ import { ChokidarOptions, FSWatcherEventMap } from 'chokidar';
3
4
  import { SrvRecord } from 'dns';
4
5
  import { EventEmitter } from 'events';
5
6
  import { Socket, TcpNetConnectOpts } from 'net';
6
7
  import Assert from 'node:assert';
7
- import { Dirent } from 'node:fs';
8
+ import { Dirent, StatSyncFn } from 'node:fs';
8
9
  import { Agent } from 'node:http';
9
10
  import { Duplex } from 'node:stream';
10
11
  import { Level, LogFn, Logger as PinoLogger } from 'pino';
@@ -17573,6 +17574,207 @@ declare namespace DeferredKeySelection {
17573
17574
  }
17574
17575
  export type AggregationQueryResult<TResult, TIntersectProps2 extends {}> = ArrayIfAlready<TResult, UnwrapArrayMember<TResult> extends DeferredKeySelection<infer TBase, infer TKeys, infer THasSelect, infer TAliasMapping, infer TSingle, infer TIntersectProps, infer TUnionProps> ? true extends THasSelect ? DeferredKeySelection<TBase, TKeys, THasSelect, TAliasMapping, TSingle, TIntersectProps & TIntersectProps2, TUnionProps> : DeferredKeySelection<{}, never, true, {}, false, TIntersectProps2> : TIntersectProps2>;
17575
17576
  export type ResolveResult<S> = DeferredKeySelection.Resolve<S>;
17577
+ /**
17578
+ * Model system types.
17579
+ *
17580
+ * A ModelSpec describes one "subject.object" domain entity and drives:
17581
+ * - automatic Browse / New / Open / Report page generation
17582
+ * - schema enrichment (server OpenAPI merged with browser overlay)
17583
+ * - dropdown dependency tracking and caching
17584
+ */
17585
+ /** {value, label} pair used in all dropdown and select widgets */
17586
+ export interface IDropdownOption {
17587
+ value: unknown;
17588
+ label: string;
17589
+ [key: string]: unknown;
17590
+ }
17591
+ /** Widget metadata overlay */
17592
+ export interface IWidgetOverride {
17593
+ type?: string;
17594
+ /** Named dropdown: 'rule.country', 'marine.species', etc. */
17595
+ dropdown?: string;
17596
+ options?: Array<{
17597
+ value: unknown;
17598
+ label: string;
17599
+ }>;
17600
+ keyValue?: boolean;
17601
+ fieldClass?: string;
17602
+ itemClassName?: string;
17603
+ label?: string;
17604
+ master?: Record<string, string>;
17605
+ parent?: string;
17606
+ autoSelect?: boolean;
17607
+ selectionMode?: "single" | "multiple";
17608
+ hidden?: string[];
17609
+ widgets?: string[];
17610
+ params?: Record<string, unknown>;
17611
+ [key: string]: unknown;
17612
+ }
17613
+ /** JSON Schema property overlay — the browser model adds/overrides field metadata */
17614
+ export interface IPropertyOverride {
17615
+ title?: string;
17616
+ type?: string;
17617
+ filter?: boolean;
17618
+ sort?: boolean;
17619
+ required?: boolean;
17620
+ default?: unknown;
17621
+ widget?: IWidgetOverride;
17622
+ validation?: unknown;
17623
+ properties?: Record<string, IPropertyOverride>;
17624
+ items?: {
17625
+ properties?: Record<string, IPropertyOverride>;
17626
+ };
17627
+ [key: string]: unknown;
17628
+ }
17629
+ /** Schema overlay — top-level properties map per subject.object */
17630
+ export interface ISchemaOverlay {
17631
+ properties?: Record<string, IPropertyOverride>;
17632
+ [key: string]: unknown;
17633
+ }
17634
+ /** Named card layout — a group of fields rendered as one collapsible card */
17635
+ export interface ICardOverride {
17636
+ className?: string;
17637
+ label?: string;
17638
+ title?: string;
17639
+ hidden?: boolean;
17640
+ widgets: Array<string | IInlineWidget>;
17641
+ }
17642
+ /** Inline widget descriptor (used inside card.widgets arrays) */
17643
+ export interface IInlineWidget {
17644
+ name: string;
17645
+ type: string;
17646
+ page?: string;
17647
+ params?: Record<string, unknown>;
17648
+ }
17649
+ /** Tab in the editor layout */
17650
+ export interface ILayoutTab {
17651
+ id: string;
17652
+ label?: string;
17653
+ icon?: string;
17654
+ widgets: Array<string | string[]>;
17655
+ }
17656
+ /** Permission names for each CRUD action */
17657
+ export interface IBrowserPermissions {
17658
+ browse: string;
17659
+ add: string;
17660
+ edit: string;
17661
+ delete: string;
17662
+ }
17663
+ /** Browse page configuration */
17664
+ export interface IBrowserConfig {
17665
+ title?: string;
17666
+ icon?: string;
17667
+ permission?: IBrowserPermissions;
17668
+ /** Column transformation applied to server fetch params */
17669
+ fetch?: (params: Record<string, unknown>) => Record<string, unknown>;
17670
+ /** Default filter applied on page open */
17671
+ filter?: Record<string, unknown>;
17672
+ /** Result set key to use from server response */
17673
+ resultSet?: string;
17674
+ /** Whether to show "Create" button */
17675
+ create?: Array<{
17676
+ title?: string;
17677
+ type?: string;
17678
+ permission?: string;
17679
+ }>;
17680
+ /** Extra toolbar buttons */
17681
+ toolbar?: unknown[];
17682
+ }
17683
+ /** Editor page configuration */
17684
+ export interface IEditorConfig {
17685
+ resultSet?: string;
17686
+ }
17687
+ /** Report page configuration */
17688
+ export interface IReportConfig {
17689
+ title?: string;
17690
+ permission?: string;
17691
+ }
17692
+ /** Method name overrides — defaults to semantic triple naming */
17693
+ export interface IMethodsConfig {
17694
+ find?: string;
17695
+ get?: string;
17696
+ add?: string;
17697
+ edit?: string;
17698
+ remove?: string;
17699
+ report?: string;
17700
+ }
17701
+ /**
17702
+ * ModelSpec — the browser-side description of one "subject.object" domain entity.
17703
+ *
17704
+ * Used by modelFactory() to auto-generate Browse/New/Open/Report pages.
17705
+ */
17706
+ export interface IModelSpec {
17707
+ /** Namespace / subject, e.g. 'marine', 'rule' */
17708
+ subject: string;
17709
+ /** Entity name, e.g. 'coral', 'condition' */
17710
+ object: string;
17711
+ /** Human-readable title, e.g. 'Coral'. Defaults to capitalized object. */
17712
+ objectTitle?: string;
17713
+ /** Primary key field path, e.g. 'coralId'. Defaults to `${object}Id`. */
17714
+ keyField?: string;
17715
+ /** Name field path (dotted), e.g. 'coral.coralName'. Defaults to `${object}.${object}Name`. */
17716
+ nameField?: string;
17717
+ /** JSON Schema overlay merged on top of server OpenAPI schema */
17718
+ schema?: ISchemaOverlay;
17719
+ /** Named card layout definitions */
17720
+ cards?: Record<string, ICardOverride>;
17721
+ /** Browse page configuration */
17722
+ browser?: IBrowserConfig;
17723
+ /** Editor page configuration */
17724
+ editor?: IEditorConfig;
17725
+ /** Report page configuration */
17726
+ report?: IReportConfig;
17727
+ /** Tab layouts for editor */
17728
+ layouts?: {
17729
+ edit?: ILayoutTab[] | string[];
17730
+ [key: string]: unknown;
17731
+ };
17732
+ /** Method name overrides */
17733
+ methods?: IMethodsConfig;
17734
+ }
17735
+ /** Model spec as accepted by modelFactory — objectTitle/keyField/nameField are optional */
17736
+ export type IPartialModelSpec = IModelSpec;
17737
+ /** Fully resolved model spec — all defaults filled in */
17738
+ export interface IResolvedModelSpec extends Required<IModelSpec> {
17739
+ objectTitle: string;
17740
+ keyField: string;
17741
+ nameField: string;
17742
+ browser: Required<IBrowserConfig> & {
17743
+ permission: IBrowserPermissions;
17744
+ };
17745
+ editor: Required<IEditorConfig>;
17746
+ report: Required<IReportConfig>;
17747
+ methods: Required<IMethodsConfig>;
17748
+ }
17749
+ /** Mock OpenAPI document (minimal shape used by schemaFetcher) */
17750
+ export interface IMockOpenApiDoc {
17751
+ paths?: Record<string, Record<string, {
17752
+ operationId?: string;
17753
+ requestBody?: {
17754
+ content?: {
17755
+ "application/json"?: {
17756
+ schema?: Record<string, unknown>;
17757
+ };
17758
+ };
17759
+ };
17760
+ responses?: {
17761
+ "200"?: {
17762
+ content?: {
17763
+ "application/json"?: {
17764
+ schema?: Record<string, unknown>;
17765
+ };
17766
+ };
17767
+ };
17768
+ };
17769
+ }>>;
17770
+ "x-ui-customizations"?: Record<string, Record<string, unknown>>;
17771
+ }
17772
+ export interface IMock {
17773
+ /** Mock OpenAPI documents keyed by subject name */
17774
+ subjects?: Record<string, object[]>;
17775
+ /** Pre-populated dropdown data keyed by dropdown name */
17776
+ dropdowns?: Record<string, IDropdownOption[]>;
17777
+ }
17576
17778
  export type ServerContext = {
17577
17779
  queryBuilder?: Knex;
17578
17780
  kcAdminClient?: KeycloakAdminClient;
@@ -17591,6 +17793,82 @@ export interface ILog {
17591
17793
  logger: (level: Level, bindings: object) => ILogger;
17592
17794
  child: PinoLogger["child"];
17593
17795
  }
17796
+ /** A flat map of dotted-path → [prev, next] pairs that represent changed keys */
17797
+ export type ConfigDiff = Map<string, {
17798
+ prev: unknown;
17799
+ next: unknown;
17800
+ }>;
17801
+ /** Subscriber callback invoked after a successful reload */
17802
+ export type ConfigSubscriber = (diff: ConfigDiff, next: object, prev: object) => void | Promise<void>;
17803
+ /**
17804
+ * Mode used when the config proxy is queried during handler factory initialisation.
17805
+ *
17806
+ * - `'throw'` — throw immediately (default; keeps misuse from going unnoticed)
17807
+ * - `'collect'` — accumulate errors and return them from exitConfigFactoryPhase()
17808
+ * (useful in tests that explicitly verify the anti-pattern is caught)
17809
+ */
17810
+ export type FactoryPhaseMode = "throw" | "collect";
17811
+ export interface IConfigRuntime {
17812
+ /** Current effective config, exposed as a live proxy */
17813
+ readonly snapshot: object;
17814
+ /** Raw (non-proxy) snapshot of the current effective config */
17815
+ readonly rawSnapshot: object;
17816
+ /** Load (or reload) config from all sources; returns the updated snapshot */
17817
+ load(params?: object): Promise<object>;
17818
+ /**
17819
+ * Reload config in-place. The backing store of the proxy is updated so all
17820
+ * existing proxy references automatically reflect the new values.
17821
+ * Returns the computed diff.
17822
+ */
17823
+ reload(): Promise<ConfigDiff>;
17824
+ /** Compute the diff between two plain config objects without modifying state */
17825
+ diff(prev: object, next: object): ConfigDiff;
17826
+ /** Register a subscriber to be called after every successful reload */
17827
+ subscribe(fn: ConfigSubscriber): () => void;
17828
+ /** Enter the config factory phase */
17829
+ enterConfig(mode?: FactoryPhaseMode): void;
17830
+ /** Exit the config factory phase */
17831
+ exitConfig(): Error[];
17832
+ }
17833
+ export interface IWatcher extends EventEmitter<FSWatcherEventMap> {
17834
+ close(): Promise<void>;
17835
+ }
17836
+ export type HRTime = [
17837
+ number,
17838
+ number
17839
+ ];
17840
+ export interface IPlatformApi {
17841
+ platform: "server" | "browser";
17842
+ loadConfig: (config: string | object) => Promise<{
17843
+ loadedConfig?: object;
17844
+ configRuntime?: IConfigRuntime;
17845
+ }>;
17846
+ readdir: (path: string) => Promise<Dirent[]>;
17847
+ scan: (...path: string[]) => Promise<Dirent[]>;
17848
+ existsSync: (path: string) => boolean;
17849
+ createRequire?: (path: string | URL) => NodeJS.Require;
17850
+ join: (...paths: string[]) => string;
17851
+ dirname: (path: string) => string;
17852
+ basename: (path: string, ext?: string) => string;
17853
+ relative: (from: string, to: string) => string;
17854
+ extname: (path: string) => string;
17855
+ resolve: (...paths: string[]) => string;
17856
+ readFileSync: (path: string, options?: {
17857
+ encoding: BufferEncoding;
17858
+ }) => string | Buffer;
17859
+ writeFileSync: (path: string, data: string | Buffer, options?: {
17860
+ encoding: BufferEncoding;
17861
+ }) => void;
17862
+ statSync: StatSyncFn;
17863
+ watch?: (path: string | string[], options?: ChokidarOptions) => IWatcher;
17864
+ timing: {
17865
+ diff: (time: HRTime, newTime: HRTime) => number;
17866
+ after: (milliseconds: number) => HRTime;
17867
+ now: (previous?: HRTime) => HRTime;
17868
+ isAfter: (time: HRTime, timeout: HRTime) => boolean;
17869
+ spare: (time: HRTime, latency?: number) => number;
17870
+ };
17871
+ }
17594
17872
  export interface IErrorFactory {
17595
17873
  get(type?: string): unknown;
17596
17874
  fetch(type: string): object;
@@ -17674,6 +17952,9 @@ export interface IApiSchema {
17674
17952
  }, source: string): Promise<Record<string, GatewaySchema>>;
17675
17953
  generateFile(file: string): Promise<boolean>;
17676
17954
  generateDir(dir: string, files: Dirent[]): Promise<boolean>;
17955
+ loadApi(locations: string | string[] | object | object[] | {
17956
+ assets: object;
17957
+ }, source: string): unknown;
17677
17958
  }
17678
17959
  export interface IGateway {
17679
17960
  route: (validations: Record<string, GatewaySchema>, pkg: {
@@ -17691,6 +17972,7 @@ export type Handlers = ((params: {
17691
17972
  local: object;
17692
17973
  literals: object[];
17693
17974
  gateway: IGateway;
17975
+ apiSchema: IApiSchema;
17694
17976
  }) => void)[];
17695
17977
  export interface IRegistry {
17696
17978
  start: (configOverride?: object) => Promise<IRegistry>;
@@ -17724,25 +18006,20 @@ export interface IApi {
17724
18006
  rpc: IRpcServer;
17725
18007
  local: ILocal;
17726
18008
  registry: IRegistry;
17727
- utBus: {
17728
- config: object;
17729
- register: (methods: object, namespace: string, id: string, pkg: {
17730
- version: string;
17731
- }) => void;
17732
- unregister: (methods: string[], namespace: string) => void;
17733
- subscribe: (methods: object, namespace: string, id: string, pkg: {
17734
- version: string;
17735
- }) => void;
17736
- unsubscribe: (methods: string[], namespace: string) => void;
17737
- dispatch: (...params: unknown[]) => boolean | Promise<unknown>;
17738
- methodId: (name: string) => string;
17739
- getPath: (name: string) => string;
17740
- importMethod: (methodName: string, options?: object) => (...params: unknown[]) => Promise<unknown>;
17741
- attachHandlers: (target: object, patterns: unknown, adapter?: boolean) => unknown;
17742
- };
17743
- utLog: {
17744
- createLog: ILog["logger"];
17745
- };
18009
+ register: (methods: object, namespace: string, id: string, pkg: {
18010
+ version: string;
18011
+ }) => void;
18012
+ unregister: (methods: string[], namespace: string) => void;
18013
+ subscribe: (methods: object, namespace: string, id: string, pkg: {
18014
+ version: string;
18015
+ }) => void;
18016
+ unsubscribe: (methods: string[], namespace: string) => void;
18017
+ dispatch: (...params: unknown[]) => boolean | Promise<unknown>;
18018
+ methodId: (name: string) => string;
18019
+ getPath: (name: string) => string;
18020
+ importMethod: (methodName: string, options?: object) => (...params: unknown[]) => Promise<unknown>;
18021
+ attachHandlers: (target: object, patterns: unknown, adapter?: boolean) => unknown;
18022
+ createLog: ILog["logger"];
17746
18023
  attachCheckpoint?: (meta: IMeta) => void;
17747
18024
  handlers?: (api: {
17748
18025
  utError: IError;
@@ -17773,6 +18050,7 @@ export interface IAdapter<T, C> {
17773
18050
  log?: ILogger;
17774
18051
  errors?: Errors<IErrorMap>;
17775
18052
  imported?: ReturnType<IAdapterFactory<T, C>>;
18053
+ importedMap?: Map<string, IRemoteHandler>;
17776
18054
  extends?: object | `adapter.${string}` | `orchestrator.${string}`;
17777
18055
  activeConfig?: (this: ReturnType<IAdapterFactory<T, C>>) => Partial<Config<T, C>>;
17778
18056
  init?: (this: ReturnType<IAdapterFactory<T, C>>, ...config: Partial<Config<T, C>>[]) => Promise<void>;
@@ -17794,7 +18072,7 @@ export interface IAdapter<T, C> {
17794
18072
  }) => Buffer;
17795
18073
  encode?: (data: unknown, $meta: IMeta, context: object, log: ILogger) => string | Buffer;
17796
18074
  decode?: (buff: string | Buffer, $meta: IMeta, context: object, log: ILogger) => object[];
17797
- request?: () => Promise<unknown>;
18075
+ request?: (...params: unknown[]) => Promise<unknown>;
17798
18076
  publish?: () => Promise<unknown>;
17799
18077
  drain?: () => void;
17800
18078
  findValidation?: (this: ReturnType<IAdapterFactory<T, C>>, $meta: IMeta) => () => object;
@@ -17920,10 +18198,6 @@ export interface IMeta {
17920
18198
  timestamp: number;
17921
18199
  }>;
17922
18200
  }
17923
- export type HRTime = [
17924
- number,
17925
- number
17926
- ];
17927
18201
  export interface IContext {
17928
18202
  trace: number;
17929
18203
  session?: {
@@ -17992,6 +18266,7 @@ export interface IModuleConfig<T extends TSchema = TNever> {
17992
18266
  config?: IActivationConfig<Partial<Static<T>> & Partial<Static<IBaseConfig>>>;
17993
18267
  validation?: T;
17994
18268
  children?: (string | (() => Promise<object>))[] | ((layer: ModuleApi) => unknown)[];
18269
+ glob?: Record<string, () => Promise<object>>;
17995
18270
  }
17996
18271
  export interface ILogger {
17997
18272
  trace?: LogFn;
@@ -18054,9 +18329,16 @@ export interface ILib {
18054
18329
  name: string;
18055
18330
  };
18056
18331
  assert: typeof Assert | undefined;
18332
+ yaml: {
18333
+ parse: <T>(source: string, options?: unknown) => T;
18334
+ parseAllDocuments: <T>(source: string, options?: unknown) => T;
18335
+ parseDocument: <T>(source: string, options?: unknown) => T;
18336
+ stringify: (value: unknown, options?: unknown) => string;
18337
+ };
18057
18338
  ulid: () => string;
18058
18339
  uuid4: () => string;
18059
18340
  uuid7: () => string;
18341
+ timing: IPlatformApi["timing"];
18060
18342
  setProperty: (obj: Record<string, unknown>, path: string, value: unknown) => void;
18061
18343
  merge<T, S1>(target: T, source: S1): T & S1;
18062
18344
  merge<T, S1, S2>(target: T, source1: S1, source2: S2): T & S1 & S2;
@@ -18120,6 +18402,7 @@ export interface IHandlerProxy<T> {
18120
18402
  };
18121
18403
  };
18122
18404
  };
18405
+ apiSchema: IApiSchema;
18123
18406
  }
18124
18407
  export type ImportProxyCallback<T, C> = (blong: IHandlerProxy<T>) => PortHandler<T, C> | IAdapterFactory<T, C> | Record<string, PortHandler<T, C>>;
18125
18408
  export type Definition<T, C> = object | ImportProxyCallback<T, C> | ImportProxyCallback<T, C>[];
@@ -18162,21 +18445,13 @@ export declare const handler: <T = Record<string, unknown>, C = AdapterContext>(
18162
18445
  * The inner function should return a map whose keys are dot-notation method names
18163
18446
  * (e.g. `'coral.browse'`) and values are async functions that return component
18164
18447
  * metadata `{title, permission, icon, component: async () => ReactComponent}`.
18165
- *
18166
- * @example
18167
- * ```ts
18168
- * export default componentHandler(blong => function coralBrowse() {
18169
- * return {
18170
- * 'coral.browse': async () => ({
18171
- * title: 'Browse Corals',
18172
- * permission: 'marine.coral.browse',
18173
- * component: async () => (await import('./CoralBrowse.js')).default,
18174
- * }),
18175
- * };
18176
- * });
18177
- * ```
18178
18448
  */
18179
- export declare const componentHandler: <T = Record<string, unknown>, C = AdapterContext>(definition: Definition<T, C>) => Definition<T, C>;
18449
+ export interface IComponent {
18450
+ title?: string;
18451
+ permission?: string;
18452
+ icon?: string;
18453
+ component: (params?: Record<string, unknown>) => Promise<unknown>;
18454
+ }
18180
18455
  /** Action definition for use with `defineActions`. */
18181
18456
  export interface IActionDef {
18182
18457
  title?: string;
@@ -18216,6 +18491,8 @@ export declare const defineActions: (actions: Record<string, IActionDef>) => ((_
18216
18491
  export declare const library: <T = Record<string, unknown>>(definition: Lib<T>) => Lib<T>;
18217
18492
  export declare const validation: (validation: ValidationDefinition) => ValidationDefinition;
18218
18493
  export declare const api: (api: ApiDefinition) => ApiDefinition;
18494
+ export declare const model: <T extends IModelSpec>(definition: () => () => Promise<T>) => (() => () => Promise<T>);
18495
+ export declare const fixture: <T extends IMock>(definition: () => T) => (() => T);
18219
18496
  export declare const validationHandlers: (handlers: Record<string, TFunction<[
18220
18497
  ApiSchema
18221
18498
  ]>>) => ValidationDefinition;
@@ -18225,11 +18502,10 @@ export declare const browser: <T extends TObject>(definition: SolutionFactory<T>
18225
18502
  export declare const layer: (activation: Record<string, boolean | object>) => Record<string, boolean | object>;
18226
18503
  export declare const adapter: <T, C = AdapterContext>(definition: IAdapterFactory<T, C>) => IAdapterFactory<T, C>;
18227
18504
  export declare const orchestrator: <T, C = AdapterContext>(definition: IAdapterFactory<T, C>) => IAdapterFactory<T, C>;
18228
- export type Kinds = "lib" | "validation" | "api" | "solution" | "server" | "browser" | "adapter" | "orchestrator" | "handler";
18229
- export declare const kind: (what: {}) => Kinds | undefined;
18505
+ export type Kinds = "lib" | "validation" | "api" | "solution" | "server" | "browser" | "adapter" | "orchestrator" | "handler" | "model" | "fixture" | "";
18506
+ export declare const kind: (what: {}) => Kinds;
18230
18507
  declare const _default: {
18231
18508
  handler: <T = Record<string, unknown>, C = AdapterContext>(definition: Definition<T, C>) => Definition<T, C>;
18232
- componentHandler: <T = Record<string, unknown>, C = AdapterContext>(definition: Definition<T, C>) => Definition<T, C>;
18233
18509
  defineActions: (actions: Record<string, IActionDef>) => ((_blong: unknown) => Record<string, () => IActionDef>);
18234
18510
  library: <T = Record<string, unknown>>(definition: Lib<T>) => Lib<T>;
18235
18511
  validation: (validation: ValidationDefinition) => ValidationDefinition;
@@ -18239,7 +18515,8 @@ declare const _default: {
18239
18515
  browser: <T extends TObject>(definition: SolutionFactory<T>) => SolutionFactory<T>;
18240
18516
  adapter: <T, C = AdapterContext>(definition: IAdapterFactory<T, C>) => IAdapterFactory<T, C>;
18241
18517
  orchestrator: <T, C = AdapterContext>(definition: IAdapterFactory<T, C>) => IAdapterFactory<T, C>;
18242
- kind: (what: {}) => Kinds | undefined;
18518
+ fixture: <T extends IMock>(definition: () => T) => (() => T);
18519
+ kind: (what: {}) => Kinds;
18243
18520
  };
18244
18521
 
18245
18522
  export {
package/dist/types.js CHANGED
@@ -21,29 +21,6 @@ export class Internal {
21
21
  }
22
22
  }
23
23
  export const handler = (definition) => Object.defineProperty(definition, Kind, { value: 'handler' });
24
- /**
25
- * Browser-side equivalent of `handler`. Use this to define a component handler
26
- * in a realm's `component/` layer. Functionally identical to `handler` — the
27
- * distinction is semantic and makes intent clear in code review.
28
- *
29
- * The inner function should return a map whose keys are dot-notation method names
30
- * (e.g. `'coral.browse'`) and values are async functions that return component
31
- * metadata `{title, permission, icon, component: async () => ReactComponent}`.
32
- *
33
- * @example
34
- * ```ts
35
- * export default componentHandler(blong => function coralBrowse() {
36
- * return {
37
- * 'coral.browse': async () => ({
38
- * title: 'Browse Corals',
39
- * permission: 'marine.coral.browse',
40
- * component: async () => (await import('./CoralBrowse.js')).default,
41
- * }),
42
- * };
43
- * });
44
- * ```
45
- */
46
- export const componentHandler = (definition) => Object.defineProperty(definition, Kind, { value: 'handler' });
47
24
  /**
48
25
  * Register action metadata for a realm's browser layer.
49
26
  *
@@ -67,6 +44,8 @@ export const defineActions = (actions) => Object.defineProperty((_blong) => Obje
67
44
  export const library = (definition) => Object.defineProperty(definition, Kind, { value: 'lib' });
68
45
  export const validation = (validation) => Object.defineProperty(validation, Kind, { value: 'validation' });
69
46
  export const api = (api) => Object.defineProperty(api, Kind, { value: 'api' });
47
+ export const model = (definition) => Object.defineProperty(definition, Kind, { value: 'model' });
48
+ export const fixture = (definition) => Object.defineProperty(definition, Kind, { value: 'fixture' });
70
49
  export const validationHandlers = handlers => validation(() => Object.fromEntries(Object.entries(handlers).map(([name, handler]) => [
71
50
  name,
72
51
  Object.defineProperty(() => ({
@@ -81,10 +60,9 @@ export const browser = (definition) => Object.defineProperty(definition, Kind, {
81
60
  export const layer = (activation) => Object.defineProperty(activation, Kind, { value: 'layer' });
82
61
  export const adapter = (definition) => Object.defineProperty(definition, Kind, { value: 'adapter' });
83
62
  export const orchestrator = (definition) => Object.defineProperty(definition, Kind, { value: 'orchestrator' });
84
- export const kind = (what) => what[Kind];
63
+ export const kind = (what) => what[Kind] || '';
85
64
  export default {
86
65
  handler,
87
- componentHandler,
88
66
  defineActions,
89
67
  library,
90
68
  validation,
@@ -94,6 +72,7 @@ export default {
94
72
  browser,
95
73
  adapter,
96
74
  orchestrator,
75
+ fixture,
97
76
  kind,
98
77
  };
99
78
  //# sourceMappingURL=types.js.map
package/dist/types.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../types.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@feasibleone/blong",
3
- "version": "1.16.0",
3
+ "version": "1.17.0",
4
4
  "description": "API and DRY focused RAD framework https://feasibleone.github.io/blong-docs",
5
5
  "keywords": [
6
6
  "blong",
@@ -12,8 +12,11 @@
12
12
  },
13
13
  "type": "module",
14
14
  "exports": {
15
- ".": "./dist/types.js",
16
- "./dev": "./types.ts",
15
+ ".": {
16
+ "blong-dev": "./types.ts",
17
+ "types": "./types.ts",
18
+ "default": "./dist/types.js"
19
+ },
17
20
  "./types": "./types.ts"
18
21
  },
19
22
  "dependencies": {
@@ -23,10 +26,9 @@
23
26
  "ut-function.merge": "^1.5.6"
24
27
  },
25
28
  "devDependencies": {
26
- "@aws-sdk/client-s3": "^3.1003.0",
29
+ "@aws-sdk/client-s3": "^3.1037.0",
27
30
  "@keycloak/keycloak-admin-client": "^26.5.4",
28
31
  "@kubernetes/client-node": "^1.4.0",
29
- "@rushstack/eslint-config": "^4.6.4",
30
32
  "@rushstack/heft": "^1.2.6",
31
33
  "@rushstack/heft-lint-plugin": "^1.2.6",
32
34
  "@rushstack/heft-typescript-plugin": "^1.3.1",
@@ -35,8 +37,8 @@
35
37
  "@types/request": "^2.48.13",
36
38
  "@types/ut-function.merge": "file:./types/ut-function.merge",
37
39
  "bson": "^7.2.0",
40
+ "chokidar": "^5.0.0",
38
41
  "dts-bundle-generator": "^9.5.1",
39
- "eslint": "~9.39.2",
40
42
  "knex": "^3.1.0",
41
43
  "mongodb": "^7.1.0",
42
44
  "node-vault": "^0.10.10",
package/types.ts CHANGED
@@ -24,12 +24,15 @@ import {
24
24
  type TUnknown,
25
25
  } from 'typebox';
26
26
  // import type {client} from 'node-vault';
27
- import type {Dirent} from 'node:fs';
27
+ import type {ChokidarOptions, FSWatcherEventMap} from 'chokidar';
28
+ import type {EventEmitter} from 'events';
29
+ import type {Dirent, StatSyncFn} from 'node:fs';
28
30
  import type {Duplex} from 'node:stream';
29
31
  import type {OpenAPI, OpenAPIV2, OpenAPIV3_1} from 'openapi-types';
30
32
  import type {Level, LogFn, Logger as PinoLogger} from 'pino';
31
33
  import merge from 'ut-function.merge';
32
34
  import type {Knex} from './knex.js';
35
+ import type {IMock, IModelSpec} from './model.ts';
33
36
 
34
37
  // export {
35
38
  // AppsV1Api,
@@ -45,6 +48,7 @@ export type * from 'mongodb';
45
48
  export type {IJsonSchema, OpenAPI, OpenAPIV2, OpenAPIV3, OpenAPIV3_1} from 'openapi-types';
46
49
  // export type {Level, LogFn, Logger as PinoLogger} from 'pino';
47
50
  export type {Knex} from './knex.js';
51
+ export type * from './model.ts';
48
52
 
49
53
  export type ServerContext = {
50
54
  queryBuilder?: Knex;
@@ -75,6 +79,89 @@ export interface ILog {
75
79
  child: PinoLogger['child'];
76
80
  }
77
81
 
82
+ // ---------------------------------------------------------------------------
83
+ // Types
84
+ // ---------------------------------------------------------------------------
85
+
86
+ /** A flat map of dotted-path → [prev, next] pairs that represent changed keys */
87
+ export type ConfigDiff = Map<string, {prev: unknown; next: unknown}>;
88
+
89
+ /** Subscriber callback invoked after a successful reload */
90
+ export type ConfigSubscriber = (
91
+ diff: ConfigDiff,
92
+ next: object,
93
+ prev: object,
94
+ ) => void | Promise<void>;
95
+
96
+ /**
97
+ * Mode used when the config proxy is queried during handler factory initialisation.
98
+ *
99
+ * - `'throw'` — throw immediately (default; keeps misuse from going unnoticed)
100
+ * - `'collect'` — accumulate errors and return them from exitConfigFactoryPhase()
101
+ * (useful in tests that explicitly verify the anti-pattern is caught)
102
+ */
103
+ export type FactoryPhaseMode = 'throw' | 'collect';
104
+ export interface IConfigRuntime {
105
+ /** Current effective config, exposed as a live proxy */
106
+ readonly snapshot: object;
107
+ /** Raw (non-proxy) snapshot of the current effective config */
108
+ readonly rawSnapshot: object;
109
+ /** Load (or reload) config from all sources; returns the updated snapshot */
110
+ load(params?: object): Promise<object>;
111
+ /**
112
+ * Reload config in-place. The backing store of the proxy is updated so all
113
+ * existing proxy references automatically reflect the new values.
114
+ * Returns the computed diff.
115
+ */
116
+ reload(): Promise<ConfigDiff>;
117
+ /** Compute the diff between two plain config objects without modifying state */
118
+ diff(prev: object, next: object): ConfigDiff;
119
+ /** Register a subscriber to be called after every successful reload */
120
+ subscribe(fn: ConfigSubscriber): () => void;
121
+ /** Enter the config factory phase */
122
+ enterConfig(mode?: FactoryPhaseMode): void;
123
+ /** Exit the config factory phase */
124
+ exitConfig(): Error[];
125
+ }
126
+
127
+ export interface IWatcher extends EventEmitter<FSWatcherEventMap> {
128
+ close(): Promise<void>;
129
+ }
130
+
131
+ export type HRTime = [number, number];
132
+
133
+ export interface IPlatformApi {
134
+ platform: 'server' | 'browser';
135
+ loadConfig: (
136
+ config: string | object,
137
+ ) => Promise<{loadedConfig?: object; configRuntime?: IConfigRuntime}>;
138
+ readdir: (path: string) => Promise<Dirent[]>;
139
+ scan: (...path: string[]) => Promise<Dirent[]>;
140
+ existsSync: (path: string) => boolean;
141
+ createRequire?: (path: string | URL) => NodeJS.Require;
142
+ join: (...paths: string[]) => string;
143
+ dirname: (path: string) => string;
144
+ basename: (path: string, ext?: string) => string;
145
+ relative: (from: string, to: string) => string;
146
+ extname: (path: string) => string;
147
+ resolve: (...paths: string[]) => string;
148
+ readFileSync: (path: string, options?: {encoding: BufferEncoding}) => string | Buffer;
149
+ writeFileSync: (
150
+ path: string,
151
+ data: string | Buffer,
152
+ options?: {encoding: BufferEncoding},
153
+ ) => void;
154
+ statSync: StatSyncFn;
155
+ watch?: (path: string | string[], options?: ChokidarOptions) => IWatcher;
156
+ timing: {
157
+ diff: (time: HRTime, newTime: HRTime) => number;
158
+ after: (milliseconds: number) => HRTime;
159
+ now: (previous?: HRTime) => HRTime;
160
+ isAfter: (time: HRTime, timeout: HRTime) => boolean;
161
+ spare: (time: HRTime, latency?: number) => number;
162
+ };
163
+ }
164
+
78
165
  export interface IErrorFactory {
79
166
  get(type?: string): unknown;
80
167
  fetch(type: string): object;
@@ -160,6 +247,10 @@ export interface IApiSchema {
160
247
  ): Promise<Record<string, GatewaySchema>>;
161
248
  generateFile(file: string): Promise<boolean>;
162
249
  generateDir(dir: string, files: Dirent[]): Promise<boolean>;
250
+ loadApi(
251
+ locations: string | string[] | object | object[] | {assets: object},
252
+ source: string,
253
+ ): unknown;
163
254
  }
164
255
 
165
256
  export interface IGateway {
@@ -179,6 +270,7 @@ export type Handlers = ((params: {
179
270
  local: object;
180
271
  literals: object[];
181
272
  gateway: IGateway;
273
+ apiSchema: IApiSchema;
182
274
  }) => void)[];
183
275
 
184
276
  export interface IRegistry {
@@ -220,24 +312,19 @@ export interface IApi {
220
312
  rpc: IRpcServer;
221
313
  local: ILocal;
222
314
  registry: IRegistry;
223
- utBus: {
224
- config: object;
225
- register: (methods: object, namespace: string, id: string, pkg: {version: string}) => void;
226
- unregister: (methods: string[], namespace: string) => void;
227
- subscribe: (methods: object, namespace: string, id: string, pkg: {version: string}) => void;
228
- unsubscribe: (methods: string[], namespace: string) => void;
229
- dispatch: (...params: unknown[]) => boolean | Promise<unknown>;
230
- methodId: (name: string) => string;
231
- getPath: (name: string) => string;
232
- importMethod: (
233
- methodName: string,
234
- options?: object,
235
- ) => (...params: unknown[]) => Promise<unknown>;
236
- attachHandlers: (target: object, patterns: unknown, adapter?: boolean) => unknown;
237
- };
238
- utLog: {
239
- createLog: ILog['logger'];
240
- };
315
+ register: (methods: object, namespace: string, id: string, pkg: {version: string}) => void;
316
+ unregister: (methods: string[], namespace: string) => void;
317
+ subscribe: (methods: object, namespace: string, id: string, pkg: {version: string}) => void;
318
+ unsubscribe: (methods: string[], namespace: string) => void;
319
+ dispatch: (...params: unknown[]) => boolean | Promise<unknown>;
320
+ methodId: (name: string) => string;
321
+ getPath: (name: string) => string;
322
+ importMethod: (
323
+ methodName: string,
324
+ options?: object,
325
+ ) => (...params: unknown[]) => Promise<unknown>;
326
+ attachHandlers: (target: object, patterns: unknown, adapter?: boolean) => unknown;
327
+ createLog: ILog['logger'];
241
328
  attachCheckpoint?: (meta: IMeta) => void;
242
329
  handlers?: (api: {utError: IError; remote: IRemote; type: typeof Type}) => {
243
330
  extends?:
@@ -270,6 +357,7 @@ export interface IAdapter<T, C> {
270
357
  log?: ILogger;
271
358
  errors?: Errors<IErrorMap>;
272
359
  imported?: ReturnType<IAdapterFactory<T, C>>;
360
+ importedMap?: Map<string, IRemoteHandler>;
273
361
  extends?: object | `adapter.${string}` | `orchestrator.${string}`;
274
362
  activeConfig?: (this: ReturnType<IAdapterFactory<T, C>>) => Partial<Config<T, C>>;
275
363
  init?: (
@@ -296,7 +384,7 @@ export interface IAdapter<T, C> {
296
384
  ) => Buffer;
297
385
  encode?: (data: unknown, $meta: IMeta, context: object, log: ILogger) => string | Buffer;
298
386
  decode?: (buff: string | Buffer, $meta: IMeta, context: object, log: ILogger) => object[];
299
- request?: () => Promise<unknown>;
387
+ request?: (...params: unknown[]) => Promise<unknown>;
300
388
  publish?: () => Promise<unknown>;
301
389
  drain?: () => void;
302
390
  findValidation?: (this: ReturnType<IAdapterFactory<T, C>>, $meta: IMeta) => () => object;
@@ -422,8 +510,6 @@ export interface IMeta {
422
510
  checkpoints?: Array<{name: string; data?: unknown; timestamp: number}>;
423
511
  }
424
512
 
425
- export type HRTime = [number, number];
426
-
427
513
  export interface IContext {
428
514
  trace: number;
429
515
  session?: {
@@ -493,6 +579,7 @@ export interface IModuleConfig<T extends TSchema = TNever> {
493
579
  config?: IActivationConfig<Partial<Static<T>> & Partial<Static<IBaseConfig>>>;
494
580
  validation?: T;
495
581
  children?: (string | (() => Promise<object>))[] | ((layer: ModuleApi) => unknown)[];
582
+ glob?: Record<string, () => Promise<object>>;
496
583
  }
497
584
 
498
585
  export interface ILogger {
@@ -567,9 +654,16 @@ export interface ILib {
567
654
  /** @deprecated The framework now auto-names step arrays from handler names. */
568
655
  group: (name: string) => (handlers: ChainStep[]) => ChainStep[] & {name: string};
569
656
  assert: typeof Assert | undefined;
657
+ yaml: {
658
+ parse: <T>(source: string, options?: unknown) => T;
659
+ parseAllDocuments: <T>(source: string, options?: unknown) => T;
660
+ parseDocument: <T>(source: string, options?: unknown) => T;
661
+ stringify: (value: unknown, options?: unknown) => string;
662
+ };
570
663
  ulid: () => string;
571
664
  uuid4: () => string;
572
665
  uuid7: () => string;
666
+ timing: IPlatformApi['timing'];
573
667
  setProperty: (obj: Record<string, unknown>, path: string, value: unknown) => void;
574
668
  merge<T, S1>(target: T, source: S1): T & S1;
575
669
  merge<T, S1, S2>(target: T, source1: S1, source2: S2): T & S1 & S2;
@@ -639,6 +733,7 @@ export interface IHandlerProxy<T> {
639
733
  gateway: {
640
734
  config: () => {public: {sign: object; encrypt: object}};
641
735
  };
736
+ apiSchema: IApiSchema;
642
737
  }
643
738
 
644
739
  export type ImportProxyCallback<T, C> = (
@@ -705,23 +800,13 @@ export const handler = <T = Record<string, unknown>, C = AdapterContext>(
705
800
  * The inner function should return a map whose keys are dot-notation method names
706
801
  * (e.g. `'coral.browse'`) and values are async functions that return component
707
802
  * metadata `{title, permission, icon, component: async () => ReactComponent}`.
708
- *
709
- * @example
710
- * ```ts
711
- * export default componentHandler(blong => function coralBrowse() {
712
- * return {
713
- * 'coral.browse': async () => ({
714
- * title: 'Browse Corals',
715
- * permission: 'marine.coral.browse',
716
- * component: async () => (await import('./CoralBrowse.js')).default,
717
- * }),
718
- * };
719
- * });
720
- * ```
721
803
  */
722
- export const componentHandler = <T = Record<string, unknown>, C = AdapterContext>(
723
- definition: Definition<T, C>,
724
- ): Definition<T, C> => Object.defineProperty(definition, Kind, {value: 'handler'});
804
+ export interface IComponent {
805
+ title?: string;
806
+ permission?: string;
807
+ icon?: string;
808
+ component: (params?: Record<string, unknown>) => Promise<unknown>;
809
+ }
725
810
 
726
811
  /** Action definition for use with `defineActions`. */
727
812
  export interface IActionDef {
@@ -737,7 +822,9 @@ export interface IActionDef {
737
822
  /** Action names whose query caches should be invalidated on success. */
738
823
  invalidates?: string[];
739
824
  /** Static params merged into every invocation. */
740
- params?: Record<string, unknown> | ((params: Record<string, unknown>) => Record<string, unknown>);
825
+ params?:
826
+ | Record<string, unknown>
827
+ | ((params: Record<string, unknown>) => Record<string, unknown>);
741
828
  }
742
829
 
743
830
  /**
@@ -764,9 +851,7 @@ export const defineActions = (
764
851
  ): ((_blong: unknown) => Record<string, () => IActionDef>) =>
765
852
  Object.defineProperty(
766
853
  (_blong: unknown) =>
767
- Object.fromEntries(
768
- Object.entries(actions).map(([key, value]) => [key, () => value]),
769
- ),
854
+ Object.fromEntries(Object.entries(actions).map(([key, value]) => [key, () => value])),
770
855
  Kind,
771
856
  {value: 'handler'},
772
857
  );
@@ -777,6 +862,11 @@ export const validation = (validation: ValidationDefinition): ValidationDefiniti
777
862
  Object.defineProperty(validation, Kind, {value: 'validation'});
778
863
  export const api = (api: ApiDefinition): ApiDefinition =>
779
864
  Object.defineProperty(api, Kind, {value: 'api'});
865
+ export const model = <T extends IModelSpec>(
866
+ definition: () => () => Promise<T>,
867
+ ): (() => () => Promise<T>) => Object.defineProperty(definition, Kind, {value: 'model'});
868
+ export const fixture = <T extends IMock>(definition: () => T): (() => T) =>
869
+ Object.defineProperty(definition, Kind, {value: 'fixture'});
780
870
 
781
871
  export const validationHandlers: (
782
872
  handlers: Record<string, TFunction<[ApiSchema]>>,
@@ -813,6 +903,7 @@ export const adapter = <T, C = AdapterContext>(
813
903
  export const orchestrator = <T, C = AdapterContext>(
814
904
  definition: IAdapterFactory<T, C>,
815
905
  ): IAdapterFactory<T, C> => Object.defineProperty(definition, Kind, {value: 'orchestrator'});
906
+
816
907
  export type Kinds =
817
908
  | 'lib'
818
909
  | 'validation'
@@ -822,12 +913,14 @@ export type Kinds =
822
913
  | 'browser'
823
914
  | 'adapter'
824
915
  | 'orchestrator'
825
- | 'handler';
826
- export const kind = (what: {[Kind]: Kinds | undefined}): Kinds | undefined => what[Kind];
916
+ | 'handler'
917
+ | 'model'
918
+ | 'fixture'
919
+ | '';
920
+ export const kind = (what: {[Kind]: Kinds | undefined}): Kinds => what[Kind] || '';
827
921
 
828
922
  export default {
829
923
  handler,
830
- componentHandler,
831
924
  defineActions,
832
925
  library,
833
926
  validation,
@@ -837,5 +930,6 @@ export default {
837
930
  browser,
838
931
  adapter,
839
932
  orchestrator,
933
+ fixture,
840
934
  kind,
841
935
  };