@feasibleone/blong 1.21.0 → 1.23.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/types.js ADDED
@@ -0,0 +1,68 @@
1
+ import { Type, } from 'typebox';
2
+ import merge from 'ut-function.merge';
3
+ const Kind = Symbol.for('blong:kind');
4
+ export class Internal {
5
+ #log;
6
+ log;
7
+ constructor(api) {
8
+ this.#log = api?.log;
9
+ }
10
+ merge = (...args) => {
11
+ const result = merge(...args);
12
+ if (result.logLevel && this.#log)
13
+ this.log = this.#log.logger(result.logLevel, { name: this.constructor.name });
14
+ return result;
15
+ };
16
+ async stop() {
17
+ return this;
18
+ }
19
+ async start(..._args) {
20
+ return this;
21
+ }
22
+ }
23
+ export const handler = (definition) => Object.defineProperty(definition, Kind, { value: 'handler' });
24
+ export const library = (definition) => Object.defineProperty(definition, Kind, { value: 'lib' });
25
+ export const validation = (validation) => Object.defineProperty(validation, Kind, { value: 'validation' });
26
+ export const schema = (schema) => Object.defineProperty(schema, Kind, { value: 'schema' });
27
+ export const api = (api) => Object.defineProperty(api, Kind, { value: 'api' });
28
+ export const model = (definition) => Object.defineProperty(definition, Kind, { value: 'model' });
29
+ export const fixture = (definition) => Object.defineProperty(definition, Kind, { value: 'fixture' });
30
+ export const validationHandlers = handlers => validation(async () => Object.fromEntries(Object.entries(handlers).map(([name, handler]) => [
31
+ name,
32
+ Object.defineProperty(() => ({
33
+ params: Type.Parameters(handler).items[0],
34
+ result: Type.Awaited(Type.ReturnType(handler)),
35
+ description: 'description' in handler ? handler.description : undefined,
36
+ }), 'name', { value: name }),
37
+ ])));
38
+ export const realm = (definition) => Object.defineProperty(definition, Kind, {
39
+ value: 'solution',
40
+ });
41
+ export const server = (definition) => Object.defineProperty(definition, Kind, {
42
+ value: 'server',
43
+ });
44
+ export const browser = (definition) => Object.defineProperty(definition, Kind, {
45
+ value: 'browser',
46
+ });
47
+ export const layer = (activation) => Object.defineProperty(activation, Kind, { value: 'layer' });
48
+ export const adapter = (definition) => Object.defineProperty(definition, Kind, {
49
+ value: 'adapter',
50
+ });
51
+ export const orchestrator = (definition) => Object.defineProperty(definition, Kind, {
52
+ value: 'orchestrator',
53
+ });
54
+ export const kind = (what) => what[Kind] || '';
55
+ export default {
56
+ handler,
57
+ library,
58
+ validation,
59
+ api,
60
+ realm,
61
+ server,
62
+ browser,
63
+ adapter,
64
+ orchestrator,
65
+ fixture,
66
+ kind,
67
+ };
68
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../types.ts"],"names":[],"mappings":"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"}
package/dist/widget.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=widget.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"widget.js","sourceRoot":"","sources":["../widget.ts"],"names":[],"mappings":""}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@feasibleone/blong",
3
- "version": "1.21.0",
3
+ "version": "1.23.0",
4
4
  "description": "API and DRY focused RAD framework https://feasibleone.github.io/blong-docs",
5
5
  "keywords": [
6
6
  "blong",
@@ -27,7 +27,7 @@
27
27
  },
28
28
  "devDependencies": {
29
29
  "@aws-sdk/client-s3": "^3.1037.0",
30
- "@keycloak/keycloak-admin-client": "^26.5.4",
30
+ "@keycloak/keycloak-admin-client": "^26.6.2",
31
31
  "@kubernetes/client-node": "^1.4.0",
32
32
  "@rushstack/heft": "^1.2.6",
33
33
  "@rushstack/heft-lint-plugin": "^1.2.6",
@@ -40,14 +40,14 @@
40
40
  "bson": "^7.2.0",
41
41
  "chokidar": "^5.0.0",
42
42
  "dts-bundle-generator": "^9.5.1",
43
- "knex": "^3.1.0",
43
+ "knex": "^3.2.10",
44
44
  "mongodb": "^7.1.0",
45
45
  "node-vault": "^0.10.10",
46
46
  "openapi-types": "^12.1.3",
47
47
  "react": "^19.1.0",
48
48
  "tarn": "^3.0.2",
49
49
  "typescript": "^6.0.3",
50
- "@feasibleone/blong-dev": "1.0.1"
50
+ "@feasibleone/blong-dev": "1.1.0"
51
51
  },
52
52
  "scripts": {
53
53
  "build": "heft build --clean;dts-bundle-generator --config dts-gen.config.json",
package/types.ts CHANGED
@@ -19,9 +19,12 @@ import {
19
19
  type TIntersect,
20
20
  type TNever,
21
21
  type TNumber,
22
+ type TNumberOptions,
22
23
  type TObject,
23
24
  type TSchema,
25
+ type TSchemaOptions,
24
26
  type TString,
27
+ type TStringOptions,
25
28
  type TUnknown,
26
29
  } from 'typebox';
27
30
  // import type {client} from 'node-vault';
@@ -132,11 +135,38 @@ export interface IWatcher extends EventEmitter<FSWatcherEventMap> {
132
135
 
133
136
  export type HRTime = [number, number];
134
137
 
138
+ type BaseConfig = {
139
+ name: string;
140
+ pkg: {name: string; version: string};
141
+ children: unknown[];
142
+ url: string;
143
+ base: string;
144
+ server: {
145
+ load: {logLevel: Parameters<ILog['logger']>[0]};
146
+ realm: {logLevel: Parameters<ILog['logger']>[0]};
147
+ };
148
+ browser: {
149
+ load: {logLevel: Parameters<ILog['logger']>[0]};
150
+ realm: {logLevel: Parameters<ILog['logger']>[0]};
151
+ };
152
+ kopi?: {realm?: unknown};
153
+ watch?: {configs?: object};
154
+ configs?: object;
155
+ configNames: string[];
156
+ };
157
+
135
158
  export interface IPlatformApi {
136
159
  platform: 'server' | 'browser';
137
160
  loadConfig: (
138
- config: string | object,
139
- ) => Promise<{loadedConfig?: object; configRuntime?: IConfigRuntime}>;
161
+ baseConfig: BaseConfig,
162
+ parentConfig: string | object,
163
+ loadedConfigs: object[],
164
+ ) => Promise<{
165
+ loadedConfig: BaseConfig & {
166
+ [key: string]: unknown;
167
+ };
168
+ configRuntime?: IConfigRuntime;
169
+ }>;
140
170
  readdir: (path: string) => Promise<Dirent[]>;
141
171
  scan: (...path: string[]) => Promise<Dirent[]>;
142
172
  existsSync: (path: string) => boolean;
@@ -163,6 +193,7 @@ export interface IPlatformApi {
163
193
  spare: (time: HRTime, latency?: number) => number;
164
194
  };
165
195
  configs: string[];
196
+ context: Record<string, unknown>;
166
197
  }
167
198
 
168
199
  export interface IErrorFactory {
@@ -263,6 +294,12 @@ export interface IApiSchema {
263
294
  ): unknown;
264
295
  }
265
296
 
297
+ export interface IObjectSchema {
298
+ [subject: string]: {
299
+ [object: string]: TObject;
300
+ };
301
+ }
302
+
266
303
  export interface IGateway {
267
304
  route: (
268
305
  validations: Record<string, GatewaySchema>,
@@ -291,6 +328,7 @@ export interface IRegistry {
291
328
  ports: Map<string, IAdapterRegistry>;
292
329
  methods: Map<string, Handlers>;
293
330
  modules: Map<string | symbol, IRegistry[]>;
331
+ objectSchema: IObjectSchema;
294
332
  createPort: (id: string) => Promise<Adapter | undefined>;
295
333
  getPort: (id: string) => Adapter | undefined;
296
334
  replaceHandlers: (id: string, handlers: Handlers) => Promise<void>;
@@ -304,9 +342,31 @@ export interface IRegistry {
304
342
  connected: () => Promise<boolean>;
305
343
  }
306
344
 
345
+ type BlongType = typeof Type & {
346
+ increment: () => TSchema;
347
+ integerNull: (options?: TNumberOptions) => TSchema;
348
+ integerNotNull: (options?: TNumberOptions) => TSchema;
349
+ bigIntNull: (options?: TNumberOptions) => TSchema;
350
+ bigIntNotNull: (options?: TNumberOptions) => TSchema;
351
+ stringNull: (options?: TStringOptions) => TSchema;
352
+ stringNotNull: (options?: TStringOptions) => TSchema;
353
+ numberNull: (options?: TNumberOptions) => TSchema;
354
+ numberNotNull: (options?: TNumberOptions) => TSchema;
355
+ booleanNull: (options?: TSchemaOptions) => TSchema;
356
+ booleanNotNull: (options?: TSchemaOptions) => TSchema;
357
+ dateNull: () => TSchema;
358
+ dateNotNull: () => TSchema;
359
+ dateTimeNull: () => TSchema;
360
+ dateTimeNotNull: () => TSchema;
361
+ ulid: () => TSchema;
362
+ uuid: () => TSchema;
363
+ uidNull: () => TSchema;
364
+ uidNotNull: () => TSchema;
365
+ };
366
+
307
367
  export interface IApi {
308
368
  id?: string;
309
- type: typeof Type;
369
+ type: BlongType;
310
370
  adapter: (id: string) => IAdapterRegistry | undefined;
311
371
  utError: IError;
312
372
  errors: IErrorFactory;
@@ -315,6 +375,7 @@ export interface IApi {
315
375
  rpc: IRpcServer;
316
376
  local: ILocal;
317
377
  registry: IRegistry;
378
+ schema: IObjectSchema;
318
379
  register: (
319
380
  methods:
320
381
  | Record<string, (...params: unknown[]) => Promise<unknown>>
@@ -349,9 +410,16 @@ export interface IApi {
349
410
  patterns: (string | RegExp)[] | string | RegExp,
350
411
  adapter?: boolean,
351
412
  ) => unknown;
413
+ attach: (target: object, patterns: (string | RegExp)[] | string | RegExp) => Promise<object>;
352
414
  createLog: ILog['logger'];
353
415
  attachCheckpoint?: (meta: IMeta) => void;
354
- handlers?: (api: {utError: IError; remote: IRemote; type: typeof Type}) => {
416
+ handlers?: (api: {
417
+ utError: IError;
418
+ remote: IRemote;
419
+ type: BlongType;
420
+ schema: IObjectSchema;
421
+ manifest?: IManifest;
422
+ }) => {
355
423
  extends?:
356
424
  | string
357
425
  | ((api: {
@@ -360,8 +428,13 @@ export interface IApi {
360
428
  rpc: IRpcServer;
361
429
  local: ILocal;
362
430
  registry: IRegistry;
431
+ schema: IObjectSchema;
432
+ manifest?: IManifest;
363
433
  }) => object);
364
434
  };
435
+ render: (what: object[] | object) => object;
436
+ platform: IPlatformApi;
437
+ manifest?: IManifest;
365
438
  }
366
439
 
367
440
  export interface IErrorMap {
@@ -388,6 +461,7 @@ export type Adapter<T = Record<string, unknown>, C = Record<string, unknown>> =
388
461
  | 'findValidation'
389
462
  | 'getConversion'
390
463
  | 'dispatch'
464
+ | 'platform'
391
465
  >;
392
466
  export interface IAdapter<T, C> {
393
467
  validation?: TSchema;
@@ -399,20 +473,17 @@ export interface IAdapter<T, C> {
399
473
  imported?: Record<string, PortHandlerBound>;
400
474
  importedMap?: Map<string, IRemoteHandler>;
401
475
  extends?: object | `adapter.${string}` | `orchestrator.${string}`;
476
+ platform?: IPlatformApi;
402
477
  activeConfig?(this: Adapter<T, C>): Partial<Config<T, C>>;
403
478
  init?(this: Adapter<T, C>, ...config: unknown[]): Promise<unknown>;
404
479
  start?(this: Adapter<T, C>, ...params: unknown[]): Promise<unknown>;
405
480
  ready?(this: Adapter<T, C>): Promise<unknown>;
406
481
  stop?(this: Adapter<T, C>, ...params: unknown[]): Promise<unknown>;
407
- link?(
482
+ attach?<R extends object>(
408
483
  this: Adapter<T, C>,
409
484
  patterns: (string | RegExp)[] | string | RegExp,
410
- target: object,
411
- ): Promise<{
412
- importedMap?: Map<string, object>;
413
- imported?: object;
414
- config?: {namespace?: string | string[]};
415
- }>;
485
+ target?: R,
486
+ ): Promise<R>;
416
487
  connected?(this: Adapter<T, C>): Promise<boolean>;
417
488
  error?(error: unknown, $meta: unknown): void;
418
489
  pack?(this: Adapter<T, C>, ...params: unknown[]): unknown;
@@ -487,6 +558,8 @@ export interface IAdapterRegistry {
487
558
  rpc: IRpcServer;
488
559
  local: ILocal;
489
560
  registry: IRegistry;
561
+ schema: IObjectSchema;
562
+ manifest?: IManifest;
490
563
  }): Promise<Adapter>;
491
564
  }
492
565
 
@@ -605,18 +678,27 @@ export type Errors<T> = {
605
678
 
606
679
  export interface IBaseConfig extends TObject<{
607
680
  watch: TObject<{
608
- test: TArray<TString>;
681
+ test?: TArray<TString>;
609
682
  }>;
610
683
  remote: TObject<{
611
- canSkipSocket: TBoolean;
684
+ canSkipSocket?: TBoolean;
612
685
  }>;
613
- adapter: TBoolean;
614
- orchestrator: TBoolean;
615
- test: TBoolean;
616
- error: TBoolean;
686
+ adapter: TBoolean | TObject;
687
+ orchestrator: TBoolean | TObject;
688
+ test: TBoolean | TObject;
689
+ error: TBoolean | TObject;
617
690
  gateway: TBoolean | TObject;
618
- sim: TBoolean;
619
- resolution: TBoolean;
691
+ sim: TBoolean | TObject;
692
+ resolution: TBoolean | TObject;
693
+ log: TBoolean | TObject;
694
+ apiSchema: TBoolean | TObject;
695
+ registry: TBoolean | TObject;
696
+ port: TBoolean | TObject;
697
+ codec: TBoolean | TObject;
698
+ local: TBoolean | TObject;
699
+ rpcServer: TBoolean | TObject;
700
+ restFs: TBoolean | TObject;
701
+ systemDebug: TBoolean | TObject;
620
702
  }> {
621
703
  additionalProperties: false;
622
704
  }
@@ -725,8 +807,25 @@ export type ChainStep =
725
807
 
726
808
  export type CheckpointFn = (this: IMeta, name: string, data?: unknown) => void;
727
809
 
810
+ /**
811
+ * Manifest — a shared mutable object passed to the `load` function that allows
812
+ * platforms to share information such as effective ports, URLs, or other
813
+ * runtime-resolved values across components.
814
+ *
815
+ * Properties are typically Promises (created via `Promise.withResolvers()`) that
816
+ * are resolved when one platform finishes a startup step (e.g. listening on a
817
+ * random port), and awaited by another platform or adapter during its own
818
+ * initialisation (e.g. constructing a backend URL from the effective port).
819
+ *
820
+ * Manifest properties can also be provided via CLI args using the
821
+ * `--manifest.<key>=<value>` syntax.
822
+ */
823
+ export interface IManifest {
824
+ [key: string]: unknown;
825
+ }
826
+
728
827
  export interface ILib {
729
- type: typeof Type;
828
+ type: BlongType;
730
829
  error: <T>(errors: T) => Record<keyof T, (params?: unknown, $meta?: IMeta) => ITypedError>;
731
830
  rename: <T extends object>(object: T, name: string) => T & {name: string};
732
831
  /**
@@ -773,26 +872,33 @@ export interface ILib {
773
872
  merge<T, S1, S2>(target: T, source1: S1, source2: S2): T & S1 & S2;
774
873
  merge<T, S1, S2, S3>(target: T, source1: S1, source2: S2, source3: S3): T & S1 & S2 & S3;
775
874
  merge<T>(...args: unknown[]): T;
875
+ mergeWithSymbols<T, S1>(target: T, source: S1): T & S1;
876
+ render: (what: object[] | object) => object;
877
+ crockfordEncode: (data: Uint8Array) => string;
878
+ crockfordDecode: (data: string) => Uint8Array;
776
879
  }
777
880
 
778
881
  export type ValidationFn = () => GatewaySchema;
779
- export interface IValidationProxy {
882
+ export interface IValidationProxy<T> {
780
883
  type: typeof Type;
781
884
  handler: {
782
885
  [name: string]: ValidationFn;
783
- };
886
+ } & IRemoteHandler;
784
887
  lib: ILib & {
785
888
  [name: string]: TSchema;
786
889
  };
787
890
  error: {
788
891
  [name: string]: (...params: unknown[]) => ITypedError;
789
892
  };
893
+ /** Collected object schemas accumulated so far; later `schema()` exports can reference earlier ones. */
894
+ schema: IObjectSchema;
895
+ config: T;
790
896
  }
791
- export type ValidationDefinition = (
792
- blong: IValidationProxy,
793
- ) => Record<string, ValidationFn | TSchema> | ValidationFn | ValidationFn[];
897
+ export type ValidationDefinition<T> = (
898
+ blong: IValidationProxy<T>,
899
+ ) => Promise<Record<string, ValidationFn | TSchema> | ValidationFn | ValidationFn[]>;
794
900
 
795
- export type ApiDefinition = (blong: IValidationProxy) =>
901
+ export type ApiDefinition<T> = (blong: IValidationProxy<T>) =>
796
902
  | {
797
903
  namespace:
798
904
  | string[]
@@ -838,6 +944,8 @@ export interface IHandlerProxy<T> {
838
944
  errors: {
839
945
  [name: string]: (...params: unknown[]) => ITypedError;
840
946
  };
947
+ /** Collected object schemas from all registered `schema()` exports. */
948
+ schema: IObjectSchema;
841
949
  utBus: {
842
950
  info: () => {encrypt: object; sign: object};
843
951
  };
@@ -859,8 +967,8 @@ export type ModuleApi = {
859
967
  config: Record<string, unknown>;
860
968
  parent: IAdapterFactory;
861
969
  error: (errors: object) => ModuleApi;
862
- validation: (
863
- method: ValidationDefinition | ValidationDefinition[],
970
+ validation: <T>(
971
+ method: ValidationDefinition<T> | ValidationDefinition<T>[],
864
972
  namespace?: string,
865
973
  ) => ModuleApi;
866
974
  sequence: (fn: () => Sequence) => ModuleApi;
@@ -873,7 +981,10 @@ export type ModuleApi = {
873
981
  };
874
982
 
875
983
  export interface SolutionFactory<T extends TSchema = TNever> {
876
- (definition: {type: typeof Type}): IModuleConfig<T> | Promise<IModuleConfig<T>>;
984
+ (definition: {
985
+ type: typeof Type;
986
+ manifest?: IManifest;
987
+ }): IModuleConfig<T> | Promise<IModuleConfig<T>>;
877
988
  }
878
989
 
879
990
  const Kind: symbol = Symbol.for('blong:kind');
@@ -919,58 +1030,15 @@ export interface IComponent {
919
1030
  component: (params?: Record<string, unknown>) => Promise<unknown>;
920
1031
  }
921
1032
 
922
- /** Action definition for use with `defineActions`. */
923
- export interface IActionDef {
924
- title?: string;
925
- permission?: string;
926
- icon?: string;
927
- /** Lazy-load a page component (page action). */
928
- component?: () => Promise<unknown>;
929
- /** Bus method name to invoke (query or mutation action). */
930
- method?: string;
931
- /** When true the action mutates data and should invalidate related caches. */
932
- mutates?: boolean;
933
- /** Action names whose query caches should be invalidated on success. */
934
- invalidates?: string[];
935
- /** Static params merged into every invocation. */
936
- params?:
937
- | Record<string, unknown>
938
- | ((params: Record<string, unknown>) => Record<string, unknown>);
939
- }
940
-
941
- /**
942
- * Register action metadata for a realm's browser layer.
943
- *
944
- * Returns a handler-compatible function that the blong framework loads from
945
- * the realm's `actions/` or `action/` folder. Each entry in `actions` is
946
- * wrapped in a no-argument function so the framework can call it as a method.
947
- *
948
- * @example
949
- * ```ts
950
- * // marine/actions/index.ts
951
- * export default defineActions({
952
- * 'marine.coral.browse': {
953
- * title: 'Browse Corals',
954
- * permission: 'marine.coral.browse',
955
- * component: () => import('./components/CoralBrowse.js'),
956
- * },
957
- * });
958
- * ```
959
- */
960
- export const defineActions = (
961
- actions: Record<string, IActionDef>,
962
- ): ((_blong: unknown) => Record<string, () => IActionDef>) =>
963
- Object.defineProperty(
964
- () => Object.fromEntries(Object.entries(actions).map(([key, value]) => [key, () => value])),
965
- Kind,
966
- {value: 'handler'},
967
- );
968
-
969
1033
  export const library = <T = Record<string, unknown>>(definition: Lib<T>): Lib<T> =>
970
1034
  Object.defineProperty(definition, Kind, {value: 'lib'});
971
- export const validation = (validation: ValidationDefinition): ValidationDefinition =>
972
- Object.defineProperty(validation, Kind, {value: 'validation'});
973
- export const api = (api: ApiDefinition): ApiDefinition =>
1035
+ export const validation = <T = Record<string, unknown>>(
1036
+ validation: ValidationDefinition<T>,
1037
+ ): ValidationDefinition<T> => Object.defineProperty(validation, Kind, {value: 'validation'});
1038
+ export const schema = <T = Record<string, unknown>>(
1039
+ schema: ValidationDefinition<T>,
1040
+ ): ValidationDefinition<T> => Object.defineProperty(schema, Kind, {value: 'schema'});
1041
+ export const api = <T = Record<string, unknown>>(api: ApiDefinition<T>): ApiDefinition<T> =>
974
1042
  Object.defineProperty(api, Kind, {value: 'api'});
975
1043
  export const model = <T extends IModelSpec>(
976
1044
  definition: () => () => Promise<T>,
@@ -978,10 +1046,10 @@ export const model = <T extends IModelSpec>(
978
1046
  export const fixture = <T extends IMock>(definition: () => T): (() => T) =>
979
1047
  Object.defineProperty(definition, Kind, {value: 'fixture'});
980
1048
 
981
- export const validationHandlers: (
1049
+ export const validationHandlers: <T>(
982
1050
  handlers: Record<string, TFunction<[ApiSchema]>>,
983
- ) => ValidationDefinition = handlers =>
984
- validation(() =>
1051
+ ) => ValidationDefinition<T> = handlers =>
1052
+ validation(async () =>
985
1053
  Object.fromEntries(
986
1054
  Object.entries(handlers).map(([name, handler]) => [
987
1055
  name,
@@ -1036,6 +1104,7 @@ export const orchestrator = <T, C = AdapterContext>(
1036
1104
  export type Kinds =
1037
1105
  | 'lib'
1038
1106
  | 'validation'
1107
+ | 'schema'
1039
1108
  | 'api'
1040
1109
  | 'solution'
1041
1110
  | 'server'
@@ -1050,7 +1119,6 @@ export const kind = (what: {[Kind]: Kinds | undefined}): Kinds => what[Kind] ||
1050
1119
 
1051
1120
  export default {
1052
1121
  handler,
1053
- defineActions,
1054
1122
  library,
1055
1123
  validation,
1056
1124
  api,