libmodulor 0.28.0 → 0.29.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.
Files changed (100) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/README.md +2 -2
  3. package/dist/esm/apps/Helper/src/lib/layers/project.js +3 -3
  4. package/dist/esm/dt/base/TBase.d.ts +2 -0
  5. package/dist/esm/dt/base/TBase.js +5 -0
  6. package/dist/esm/dt/base/TBoolean.d.ts +2 -0
  7. package/dist/esm/dt/base/TBoolean.js +3 -0
  8. package/dist/esm/dt/base/TInt.d.ts +2 -0
  9. package/dist/esm/dt/base/TInt.js +3 -0
  10. package/dist/esm/dt/base/TNumber.d.ts +2 -0
  11. package/dist/esm/dt/base/TNumber.js +3 -0
  12. package/dist/esm/dt/base/TObject.d.ts +2 -0
  13. package/dist/esm/dt/base/TObject.js +29 -0
  14. package/dist/esm/dt/final/TApiKey.d.ts +2 -0
  15. package/dist/esm/dt/final/TApiKey.js +3 -0
  16. package/dist/esm/dt/final/TDateISO8601.d.ts +2 -0
  17. package/dist/esm/dt/final/TDateISO8601.js +3 -0
  18. package/dist/esm/dt/final/TDomainName.d.ts +2 -0
  19. package/dist/esm/dt/final/TDomainName.js +3 -0
  20. package/dist/esm/dt/final/TEmail.d.ts +2 -0
  21. package/dist/esm/dt/final/TEmail.js +3 -0
  22. package/dist/esm/dt/final/TEncryptionKey.d.ts +2 -0
  23. package/dist/esm/dt/final/TEncryptionKey.js +3 -0
  24. package/dist/esm/dt/final/TFile.d.ts +2 -0
  25. package/dist/esm/dt/final/TFile.js +3 -0
  26. package/dist/esm/dt/final/TIPv4.d.ts +2 -0
  27. package/dist/esm/dt/final/TIPv4.js +3 -0
  28. package/dist/esm/dt/final/TIPv6.d.ts +2 -0
  29. package/dist/esm/dt/final/TIPv6.js +3 -0
  30. package/dist/esm/dt/final/TJWT.d.ts +2 -0
  31. package/dist/esm/dt/final/TJWT.js +3 -0
  32. package/dist/esm/dt/final/TPassword.d.ts +2 -0
  33. package/dist/esm/dt/final/TPassword.js +3 -0
  34. package/dist/esm/dt/final/TSSHPrivateKey.d.ts +2 -0
  35. package/dist/esm/dt/final/TSSHPrivateKey.js +3 -0
  36. package/dist/esm/dt/final/TTime.d.ts +2 -0
  37. package/dist/esm/dt/final/TTime.js +3 -0
  38. package/dist/esm/dt/final/TURL.d.ts +2 -0
  39. package/dist/esm/dt/final/TURL.js +3 -0
  40. package/dist/esm/dt/index.d.ts +1 -0
  41. package/dist/esm/dt/targets/json-schema.d.ts +24 -0
  42. package/dist/esm/dt/targets/json-schema.js +1 -0
  43. package/dist/esm/error/funcs.d.ts +3 -0
  44. package/dist/esm/error/funcs.js +1 -1
  45. package/dist/esm/error/index.d.ts +1 -1
  46. package/dist/esm/error/index.js +1 -1
  47. package/dist/esm/product/manifest.d.ts +2 -0
  48. package/dist/esm/std/impl/SimpleMapI18nManager.d.ts +1 -1
  49. package/dist/esm/std/impl/SimpleMapI18nManager.js +4 -2
  50. package/dist/esm/target/edge-worker-hono-server/SyncEdgeWorkerHonoServerManager.d.ts +6 -2
  51. package/dist/esm/target/edge-worker-hono-server/SyncEdgeWorkerHonoServerManager.js +17 -9
  52. package/dist/esm/target/index.d.ts +1 -0
  53. package/dist/esm/target/lib/openapi/OpenAPISpecBuilder.d.ts +25 -0
  54. package/dist/esm/target/lib/openapi/OpenAPISpecBuilder.js +131 -0
  55. package/dist/esm/target/lib/openapi/consts.d.ts +2 -0
  56. package/dist/esm/target/lib/openapi/consts.js +1 -0
  57. package/dist/esm/target/lib/openapi/funcs.d.ts +16 -0
  58. package/dist/esm/target/lib/openapi/funcs.js +249 -0
  59. package/dist/esm/target/lib/openapi/input.d.ts +16 -0
  60. package/dist/esm/target/lib/openapi/input.js +33 -0
  61. package/dist/esm/target/lib/openapi/types.d.ts +109 -0
  62. package/dist/esm/target/lib/openapi/types.js +1 -0
  63. package/dist/esm/target/lib/rn/input.d.ts +3 -0
  64. package/dist/esm/target/lib/server/AuthCookieCreator.d.ts +2 -1
  65. package/dist/esm/target/lib/server/ServerBooter.d.ts +4 -2
  66. package/dist/esm/target/lib/server/ServerBooter.js +34 -11
  67. package/dist/esm/target/lib/server/ServerManager.d.ts +19 -9
  68. package/dist/esm/target/lib/server/ServerRequestHandler.d.ts +0 -1
  69. package/dist/esm/target/lib/server/ServerRequestHandler.js +2 -2
  70. package/dist/esm/target/lib/server/consts.d.ts +4 -0
  71. package/dist/esm/target/lib/server/consts.js +22 -0
  72. package/dist/esm/target/lib/server-express/CORSMiddlewareBuilder.d.ts +15 -0
  73. package/dist/esm/target/lib/server-express/CORSMiddlewareBuilder.js +55 -0
  74. package/dist/esm/target/lib/server-express/funcs.d.ts +2 -1
  75. package/dist/esm/target/lib/server-express/funcs.js +7 -2
  76. package/dist/esm/target/lib/server-hono/CORSMiddlewareBuilder.d.ts +14 -0
  77. package/dist/esm/target/lib/server-hono/CORSMiddlewareBuilder.js +46 -0
  78. package/dist/esm/target/lib/server-hono/funcs.d.ts +2 -1
  79. package/dist/esm/target/lib/server-hono/funcs.js +2 -1
  80. package/dist/esm/target/lib/shared.d.ts +4 -0
  81. package/dist/esm/target/lib/shared.js +2 -1
  82. package/dist/esm/target/nextjs-server/NextJSServerManager.d.ts +3 -1
  83. package/dist/esm/target/nextjs-server/NextJSServerManager.js +3 -0
  84. package/dist/esm/target/node-express-server/NodeExpressServerManager.d.ts +7 -3
  85. package/dist/esm/target/node-express-server/NodeExpressServerManager.js +24 -14
  86. package/dist/esm/target/node-hono-server/NodeHonoServerManager.d.ts +6 -2
  87. package/dist/esm/target/node-hono-server/NodeHonoServerManager.js +21 -11
  88. package/dist/esm/target/node-mcp-server/NodeLocalStdioMCPServerManager.d.ts +3 -1
  89. package/dist/esm/target/node-mcp-server/NodeLocalStdioMCPServerManager.js +19 -14
  90. package/dist/esm/target/node-mcp-server/types.d.ts +0 -4
  91. package/dist/esm/uc/UC.d.ts +2 -0
  92. package/dist/esm/uc/UC.js +16 -1
  93. package/dist/esm/uc/metadata.d.ts +7 -0
  94. package/dist/esm/uc/metadata.js +10 -0
  95. package/dist/esm/uc/output-field.d.ts +1 -0
  96. package/dist/esm/uc/output-field.js +13 -1
  97. package/dist/esm/uc/utils/ucHTTPContract.js +1 -1
  98. package/dist/esm/utils/http/types.d.ts +5 -0
  99. package/dist/esm/utils/index.d.ts +1 -1
  100. package/package.json +8 -8
@@ -1,4 +1,4 @@
1
- import type { I18n, I18nLanguageCode, I18nTranslationKey } from '../../i18n/index.js';
1
+ import { type I18n, type I18nLanguageCode, type I18nTranslationKey } from '../../i18n/index.js';
2
2
  import type { I18nManager, I18nManagerTOpts } from '../I18nManager.js';
3
3
  import type { Logger } from '../Logger.js';
4
4
  export declare class SimpleMapI18nManager implements I18nManager {
@@ -12,6 +12,7 @@ var __param = (this && this.__param) || function (paramIndex, decorator) {
12
12
  };
13
13
  var SimpleMapI18nManager_1;
14
14
  import { inject, injectable } from 'inversify';
15
+ import { I18N_DEFAULT_LANG, } from '../../i18n/index.js';
15
16
  let SimpleMapI18nManager = class SimpleMapI18nManager {
16
17
  static { SimpleMapI18nManager_1 = this; }
17
18
  i18n;
@@ -28,8 +29,9 @@ let SimpleMapI18nManager = class SimpleMapI18nManager {
28
29
  throw new Error('I18n must define at least one lang');
29
30
  }
30
31
  this.entries = new Map();
31
- // biome-ignore lint/style/noNonNullAssertion: we want it
32
- this.currentLang = this.langs[0];
32
+ this.currentLang =
33
+ // biome-ignore lint/style/noNonNullAssertion: we want it
34
+ this.langs.find((l) => l === I18N_DEFAULT_LANG) ?? this.langs[0];
33
35
  }
34
36
  async add(key, value) {
35
37
  this.current().set(key, value);
@@ -1,23 +1,26 @@
1
1
  import type { Hono } from 'hono';
2
2
  import type { AppManifest } from '../../app/index.js';
3
- import type { DirPath } from '../../dt/index.js';
3
+ import type { DirPath, URLPath } from '../../dt/index.js';
4
4
  import type { Configurable, SettingsManager } from '../../std/index.js';
5
5
  import type { UCDataStore, UCDef, UCHTTPContract, UCInput, UCManager, UCOPIBase } from '../../uc/index.js';
6
+ import type { OpenAPISpec } from '../lib/openapi/types.js';
6
7
  import { CustomerFacingErrorBuilder } from '../lib/server/CustomerFacingErrorBuilder.js';
7
8
  import type { ServerManager } from '../lib/server/ServerManager.js';
8
9
  import { ServerRequestHandler } from '../lib/server/ServerRequestHandler.js';
10
+ import { CORSMiddlewareBuilder } from '../lib/server-hono/CORSMiddlewareBuilder.js';
9
11
  export interface SyncEdgeWorkerHonoServerManagerSettings {
10
12
  sewhsm_bindings_uc_data_store: string | null;
11
13
  }
12
14
  type S = SyncEdgeWorkerHonoServerManagerSettings;
13
15
  export declare class SyncEdgeWorkerHonoServerManager implements Configurable<S>, ServerManager {
16
+ private corsMiddlewareBuilder;
14
17
  private customerFacingErrorBuilder;
15
18
  private serverRequestHandler;
16
19
  private settingsManager;
17
20
  private ucDataStore;
18
21
  private ucManager;
19
22
  protected runtime: Hono;
20
- constructor(customerFacingErrorBuilder: CustomerFacingErrorBuilder, serverRequestHandler: ServerRequestHandler, settingsManager: SettingsManager<S>, ucDataStore: UCDataStore, ucManager: UCManager);
23
+ constructor(corsMiddlewareBuilder: CORSMiddlewareBuilder, customerFacingErrorBuilder: CustomerFacingErrorBuilder, serverRequestHandler: ServerRequestHandler, settingsManager: SettingsManager<S>, ucDataStore: UCDataStore, ucManager: UCManager);
21
24
  s(): SyncEdgeWorkerHonoServerManagerSettings;
22
25
  getRuntime(): Hono;
23
26
  overrideUCManager(ucManager: UCManager): void;
@@ -25,6 +28,7 @@ export declare class SyncEdgeWorkerHonoServerManager implements Configurable<S>,
25
28
  initSync(): void;
26
29
  mount<I extends UCInput | undefined = undefined, OPI0 extends UCOPIBase | undefined = undefined, OPI1 extends UCOPIBase | undefined = undefined>(_appManifest: AppManifest, _ucd: UCDef<I, OPI0, OPI1>, _contract: UCHTTPContract): Promise<void>;
27
30
  mountSync<I extends UCInput | undefined = undefined, OPI0 extends UCOPIBase | undefined = undefined, OPI1 extends UCOPIBase | undefined = undefined>(appManifest: AppManifest, ucd: UCDef<I, OPI0, OPI1>, contract: UCHTTPContract): void;
31
+ mountOpenAPISpec(_spec: OpenAPISpec, _at: URLPath): Promise<void>;
28
32
  mountStaticDir(_dirPath: DirPath): Promise<void>;
29
33
  start(): Promise<void>;
30
34
  stop(): Promise<void>;
@@ -11,18 +11,21 @@ var __param = (this && this.__param) || function (paramIndex, decorator) {
11
11
  return function (target, key) { decorator(target, key, paramIndex); }
12
12
  };
13
13
  import { inject, injectable } from 'inversify';
14
- import { NotAvailableError, NotCallableError } from '../../error/index.js';
14
+ import { NotAvailableError, NotCallableError, NotImplementedError, } from '../../error/index.js';
15
15
  import { CustomerFacingErrorBuilder } from '../lib/server/CustomerFacingErrorBuilder.js';
16
16
  import { ServerRequestHandler } from '../lib/server/ServerRequestHandler.js';
17
+ import { CORSMiddlewareBuilder } from '../lib/server-hono/CORSMiddlewareBuilder.js';
17
18
  import { buildHandler, init, mountHandler } from '../lib/server-hono/funcs.js';
18
19
  let SyncEdgeWorkerHonoServerManager = class SyncEdgeWorkerHonoServerManager {
20
+ corsMiddlewareBuilder;
19
21
  customerFacingErrorBuilder;
20
22
  serverRequestHandler;
21
23
  settingsManager;
22
24
  ucDataStore;
23
25
  ucManager;
24
26
  runtime;
25
- constructor(customerFacingErrorBuilder, serverRequestHandler, settingsManager, ucDataStore, ucManager) {
27
+ constructor(corsMiddlewareBuilder, customerFacingErrorBuilder, serverRequestHandler, settingsManager, ucDataStore, ucManager) {
28
+ this.corsMiddlewareBuilder = corsMiddlewareBuilder;
26
29
  this.customerFacingErrorBuilder = customerFacingErrorBuilder;
27
30
  this.serverRequestHandler = serverRequestHandler;
28
31
  this.settingsManager = settingsManager;
@@ -44,7 +47,7 @@ let SyncEdgeWorkerHonoServerManager = class SyncEdgeWorkerHonoServerManager {
44
47
  throw new NotCallableError('init', 'initSync', 'sync-only');
45
48
  }
46
49
  initSync() {
47
- this.runtime = init(this.customerFacingErrorBuilder);
50
+ this.runtime = init(this.corsMiddlewareBuilder, this.customerFacingErrorBuilder);
48
51
  }
49
52
  async mount(_appManifest, _ucd, _contract) {
50
53
  throw new NotCallableError('mount', 'mountSync', 'sync-only');
@@ -52,6 +55,9 @@ let SyncEdgeWorkerHonoServerManager = class SyncEdgeWorkerHonoServerManager {
52
55
  mountSync(appManifest, ucd, contract) {
53
56
  mountHandler(contract, this.runtime, buildHandler(appManifest, ucd, contract, this.serverRequestHandler, this.ucManager, (c) => this.beforeExec(c)));
54
57
  }
58
+ async mountOpenAPISpec(_spec, _at) {
59
+ throw new NotImplementedError('mountOpenAPISpec');
60
+ }
55
61
  async mountStaticDir(_dirPath) {
56
62
  throw new NotAvailableError('mountStaticDir');
57
63
  }
@@ -81,12 +87,14 @@ let SyncEdgeWorkerHonoServerManager = class SyncEdgeWorkerHonoServerManager {
81
87
  };
82
88
  SyncEdgeWorkerHonoServerManager = __decorate([
83
89
  injectable(),
84
- __param(0, inject(CustomerFacingErrorBuilder)),
85
- __param(1, inject(ServerRequestHandler)),
86
- __param(2, inject('SettingsManager')),
87
- __param(3, inject('UCDataStore')),
88
- __param(4, inject('UCManager')),
89
- __metadata("design:paramtypes", [CustomerFacingErrorBuilder,
90
+ __param(0, inject(CORSMiddlewareBuilder)),
91
+ __param(1, inject(CustomerFacingErrorBuilder)),
92
+ __param(2, inject(ServerRequestHandler)),
93
+ __param(3, inject('SettingsManager')),
94
+ __param(4, inject('UCDataStore')),
95
+ __param(5, inject('UCManager')),
96
+ __metadata("design:paramtypes", [CORSMiddlewareBuilder,
97
+ CustomerFacingErrorBuilder,
90
98
  ServerRequestHandler, Object, Object, Object])
91
99
  ], SyncEdgeWorkerHonoServerManager);
92
100
  export { SyncEdgeWorkerHonoServerManager };
@@ -1 +1,2 @@
1
1
  export { TARGETS, type TargetName } from './lib/manifest.js';
2
+ export type { OpenAPISpec } from './lib/openapi/types.js';
@@ -0,0 +1,25 @@
1
+ import { WordingManager } from '../../../i18n/index.js';
2
+ import type { ProductManifest, ProductUCsLoaderOutput } from '../../../product/index.js';
3
+ import type { Configurable, I18nManager, SettingsManager, Worker } from '../../../std/index.js';
4
+ import type { ServerManagerSettings } from '../server/ServerManager.js';
5
+ import type { OpenAPISpec } from './types.js';
6
+ type Input = {
7
+ ucs: ProductUCsLoaderOutput;
8
+ };
9
+ interface Output {
10
+ spec: OpenAPISpec;
11
+ }
12
+ type S = Pick<ServerManagerSettings, 'server_cookies_name_auth' | 'server_public_api_key_header_name' | 'server_public_url'>;
13
+ export declare class OpenAPISpecBuilder implements Configurable<S>, Worker<Input, Promise<Output>> {
14
+ private i18nManager;
15
+ private productManifest;
16
+ private settingsManager;
17
+ private wordingManager;
18
+ constructor(i18nManager: I18nManager, productManifest: ProductManifest, settingsManager: SettingsManager<S>, wordingManager: WordingManager);
19
+ s(): S;
20
+ exec({ ucs }: Input): Promise<Output>;
21
+ private initErrors;
22
+ private initOutput;
23
+ private initPath;
24
+ }
25
+ export {};
@@ -0,0 +1,131 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ var __metadata = (this && this.__metadata) || function (k, v) {
8
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
9
+ };
10
+ var __param = (this && this.__param) || function (paramIndex, decorator) {
11
+ return function (target, key) { decorator(target, key, paramIndex); }
12
+ };
13
+ import { inject, injectable } from 'inversify';
14
+ import { WordingManager } from '../../../i18n/index.js';
15
+ import { formatFQUCInputName, formatFQUCName, ucHTTPContract, } from '../../../uc/index.js';
16
+ import { DEFAULT_VERSION } from '../shared.js';
17
+ import { openAPIErrorSchema, openAPIErrors, openAPIInputSchema, openAPIParameters, openAPIRequestBody, openAPISecurity, openAPISecuritySchemes, openAPISuccess, } from './funcs.js';
18
+ let OpenAPISpecBuilder = class OpenAPISpecBuilder {
19
+ i18nManager;
20
+ productManifest;
21
+ settingsManager;
22
+ wordingManager;
23
+ constructor(i18nManager, productManifest, settingsManager, wordingManager) {
24
+ this.i18nManager = i18nManager;
25
+ this.productManifest = productManifest;
26
+ this.settingsManager = settingsManager;
27
+ this.wordingManager = wordingManager;
28
+ }
29
+ s() {
30
+ return {
31
+ server_cookies_name_auth: this.settingsManager.get()('server_cookies_name_auth'),
32
+ server_public_api_key_header_name: this.settingsManager.get()('server_public_api_key_header_name'),
33
+ server_public_url: this.settingsManager.get()('server_public_url'),
34
+ };
35
+ }
36
+ async exec({ ucs }) {
37
+ const output = this.initOutput();
38
+ const errors = this.initErrors();
39
+ const { desc, slogan } = this.wordingManager.p();
40
+ if (desc) {
41
+ output.spec.info.description = desc;
42
+ }
43
+ if (slogan) {
44
+ output.spec.info.summary = slogan;
45
+ }
46
+ for (const uc of ucs) {
47
+ const { method, path, pathAliases, envelope } = ucHTTPContract(uc);
48
+ const httpMethod = method.toLowerCase();
49
+ const fqUCName = formatFQUCName(uc.appManifest.name, uc.def.metadata.name);
50
+ const fqUCInputName = formatFQUCInputName(fqUCName);
51
+ output.spec.components.schemas[fqUCInputName] =
52
+ openAPIInputSchema(uc);
53
+ for (const p of [path, ...pathAliases]) {
54
+ output.spec.paths[p] = {
55
+ ...output.spec.paths[p],
56
+ [httpMethod]: this.initPath(errors, uc, envelope, fqUCInputName),
57
+ };
58
+ }
59
+ }
60
+ return output;
61
+ }
62
+ initErrors() {
63
+ const errors = openAPIErrors();
64
+ for (const error of Object.values(errors)) {
65
+ error.description = this.i18nManager.t(error.description);
66
+ }
67
+ return errors;
68
+ }
69
+ initOutput() {
70
+ return {
71
+ spec: {
72
+ components: {
73
+ schemas: {
74
+ Error: openAPIErrorSchema(),
75
+ },
76
+ securitySchemes: openAPISecuritySchemes(this.s().server_cookies_name_auth, this.s().server_public_api_key_header_name),
77
+ },
78
+ info: {
79
+ title: this.productManifest.name,
80
+ version: this.productManifest.version ?? DEFAULT_VERSION,
81
+ },
82
+ openapi: '3.1.0',
83
+ paths: {},
84
+ servers: [
85
+ {
86
+ url: this.s().server_public_url,
87
+ },
88
+ ],
89
+ },
90
+ };
91
+ }
92
+ initPath(errors,
93
+ // biome-ignore lint/suspicious/noExplicitAny: can be anything
94
+ uc, envelope, fqUCInputName) {
95
+ const { desc, label } = this.wordingManager.uc(uc.def);
96
+ const path = {
97
+ responses: {
98
+ ...openAPISuccess(uc),
99
+ ...errors,
100
+ // TODO : Infer errors that can be sent within ServerMain
101
+ },
102
+ security: openAPISecurity(uc.def.sec),
103
+ summary: label,
104
+ tags: [uc.appManifest.name],
105
+ };
106
+ if (desc) {
107
+ path.description = desc;
108
+ }
109
+ switch (envelope) {
110
+ case 'form-data':
111
+ case 'json':
112
+ path.requestBody = openAPIRequestBody(uc, envelope, fqUCInputName);
113
+ break;
114
+ case 'query-params':
115
+ path.parameters = openAPIParameters(uc, envelope);
116
+ break;
117
+ default:
118
+ envelope;
119
+ }
120
+ return path;
121
+ }
122
+ };
123
+ OpenAPISpecBuilder = __decorate([
124
+ injectable(),
125
+ __param(0, inject('I18nManager')),
126
+ __param(1, inject('ProductManifest')),
127
+ __param(2, inject('SettingsManager')),
128
+ __param(3, inject(WordingManager)),
129
+ __metadata("design:paramtypes", [Object, Object, Object, WordingManager])
130
+ ], OpenAPISpecBuilder);
131
+ export { OpenAPISpecBuilder };
@@ -0,0 +1,2 @@
1
+ import type { OpenAPIDescription } from './types.js';
2
+ export declare const SUCCESS_DESCRIPTION: OpenAPIDescription;
@@ -0,0 +1 @@
1
+ export const SUCCESS_DESCRIPTION = '🕺🏽';
@@ -0,0 +1,16 @@
1
+ import { type ServerError } from '../../../error/index.js';
2
+ import { type FQUCInputName, type UC, type UCInput, type UCInputUnwrapped, type UCOPIBase, type UCOutput, type UCOutputPart, type UCOutputReaderPart, type UCSec } from '../../../uc/index.js';
3
+ import { type HTTPDataEnvelope } from '../../../utils/index.js';
4
+ import { type AuthCookieName, type PublicApiKeyHeaderName } from '../shared.js';
5
+ import type { OpenAPIParameter, OpenAPIRequestBody, OpenAPIResponses, OpenAPISchema, OpenAPISecurity, OpenAPISecuritySchemes } from './types.js';
6
+ export declare function openAPIErrorSchema(): OpenAPISchema<ServerError>;
7
+ export declare function openAPIErrors(): OpenAPIResponses;
8
+ export declare function openAPIInputSchema<I extends UCInput | undefined = undefined, OPI0 extends UCOPIBase | undefined = undefined, OPI1 extends UCOPIBase | undefined = undefined>(uc: UC<I, OPI0, OPI1>): OpenAPISchema<UCInputUnwrapped<I>>;
9
+ export declare function openAPIOPISchema<OPI extends UCOPIBase>(part: UCOutputReaderPart<NonNullable<OPI>>): OpenAPISchema<OPI>;
10
+ export declare function openAPIOutputPartSchema<OPI extends UCOPIBase>(part: UCOutputReaderPart<NonNullable<OPI>>): OpenAPISchema<UCOutputPart<OPI>>;
11
+ export declare function openAPIOutputSchema<I extends UCInput | undefined = undefined, OPI0 extends UCOPIBase | undefined = undefined, OPI1 extends UCOPIBase | undefined = undefined>(uc: UC<I, OPI0, OPI1>): OpenAPISchema<UCOutput<OPI0, OPI1>>;
12
+ export declare function openAPIParameters<I extends UCInput | undefined = undefined, OPI0 extends UCOPIBase | undefined = undefined, OPI1 extends UCOPIBase | undefined = undefined>(uc: UC<I, OPI0, OPI1>, envelope: Extract<HTTPDataEnvelope, 'query-params'>): OpenAPIParameter[];
13
+ export declare function openAPIRequestBody<I extends UCInput | undefined = undefined, OPI0 extends UCOPIBase | undefined = undefined, OPI1 extends UCOPIBase | undefined = undefined>(uc: UC<I, OPI0, OPI1>, envelope: Extract<HTTPDataEnvelope, 'form-data' | 'json'>, fqUCInputName: FQUCInputName): OpenAPIRequestBody;
14
+ export declare function openAPISecuritySchemes(authCookieName: AuthCookieName, publicApiKeyHeaderName: PublicApiKeyHeaderName): OpenAPISecuritySchemes;
15
+ export declare function openAPISecurity(sec: UCSec | undefined): OpenAPISecurity;
16
+ export declare function openAPISuccess<I extends UCInput | undefined = undefined, OPI0 extends UCOPIBase | undefined = undefined, OPI1 extends UCOPIBase | undefined = undefined>(uc: UC<I, OPI0, OPI1>): OpenAPIResponses;
@@ -0,0 +1,249 @@
1
+ import { ERROR_HTTP_STATUS_MAP, IllegalArgumentError, } from '../../../error/index.js';
2
+ import { DEFAULT_UC_SEC_AT, DEFAULT_UC_SEC_PAKCT, UCOutputReader, ucofExamples, } from '../../../uc/index.js';
3
+ import { isBlank } from '../../../utils/index.js';
4
+ import { AUTHORIZATION_HEADER_NAME, } from '../shared.js';
5
+ import { SUCCESS_DESCRIPTION } from './consts.js';
6
+ import { openAPIInputDef } from './input.js';
7
+ export function openAPIErrorSchema() {
8
+ return {
9
+ additionalProperties: false,
10
+ properties: {
11
+ message: {
12
+ examples: [new IllegalArgumentError().message],
13
+ type: 'string',
14
+ },
15
+ },
16
+ type: 'object',
17
+ };
18
+ }
19
+ export function openAPIErrors() {
20
+ return ERROR_HTTP_STATUS_MAP.entries().reduce((acc, cur) => {
21
+ const [status, clazz] = cur;
22
+ const message = new clazz().message;
23
+ acc[status] = {
24
+ content: {
25
+ 'application/json': {
26
+ schema: {
27
+ additionalProperties: false,
28
+ properties: {
29
+ message: {
30
+ examples: [message],
31
+ type: 'string',
32
+ },
33
+ },
34
+ type: 'object',
35
+ },
36
+ },
37
+ },
38
+ description: message,
39
+ };
40
+ return acc;
41
+ }, {});
42
+ }
43
+ export function openAPIInputSchema(uc) {
44
+ const res = {
45
+ additionalProperties: false,
46
+ properties: {},
47
+ type: 'object',
48
+ };
49
+ for (const f of uc.inputFields) {
50
+ const { key } = f;
51
+ const { internal, spec } = openAPIInputDef(f);
52
+ if (!spec) {
53
+ continue;
54
+ }
55
+ const k = key;
56
+ res.properties[k] = spec;
57
+ if (!internal?.required) {
58
+ continue;
59
+ }
60
+ if (!res.required) {
61
+ res.required = [];
62
+ }
63
+ res.required.push(k);
64
+ }
65
+ return res;
66
+ }
67
+ export function openAPIOPISchema(part) {
68
+ const res = {
69
+ additionalProperties: false,
70
+ properties: {},
71
+ type: 'object',
72
+ };
73
+ for (const f of part.fields) {
74
+ const { def, key } = f;
75
+ const { type } = def;
76
+ const k = key;
77
+ res.properties[k] = type.jsonSchemaType();
78
+ const examples = ucofExamples(def);
79
+ if (examples) {
80
+ res.properties[k].examples = examples;
81
+ }
82
+ }
83
+ return res;
84
+ }
85
+ export function openAPIOutputPartSchema(part) {
86
+ return {
87
+ additionalProperties: false,
88
+ properties: {
89
+ items: {
90
+ items: openAPIOPISchema(part),
91
+ type: 'array',
92
+ },
93
+ pagination: {
94
+ properties: {
95
+ id: { format: 'uuid', type: 'string' },
96
+ limit: { type: 'integer' },
97
+ offset: { type: 'integer' },
98
+ q: { type: 'string' },
99
+ },
100
+ type: 'object',
101
+ },
102
+ total: { examples: [1], type: 'integer' },
103
+ },
104
+ required: ['items', 'total'],
105
+ type: 'object',
106
+ };
107
+ }
108
+ export function openAPIOutputSchema(uc) {
109
+ const res = {
110
+ additionalProperties: false,
111
+ properties: {},
112
+ type: 'object',
113
+ };
114
+ if (!uc.hasOutputParts()) {
115
+ return res;
116
+ }
117
+ const ucor = new UCOutputReader(uc.def, undefined);
118
+ const [part0, part1] = ucor.parts();
119
+ res.properties.parts = {
120
+ properties: {
121
+ _0: openAPIOutputPartSchema(part0),
122
+ },
123
+ type: 'object',
124
+ };
125
+ if (part1) {
126
+ res.properties.parts.properties = {
127
+ _1: openAPIOutputPartSchema(part1),
128
+ };
129
+ }
130
+ return res;
131
+ }
132
+ export function openAPIParameters(uc, envelope) {
133
+ const res = [];
134
+ switch (envelope) {
135
+ case 'query-params':
136
+ {
137
+ for (const f of uc.inputFields) {
138
+ const { key } = f;
139
+ const { internal, spec } = openAPIInputDef(f);
140
+ if (!spec) {
141
+ continue;
142
+ }
143
+ res.push({
144
+ in: 'query',
145
+ name: key,
146
+ required: internal?.required ?? false,
147
+ schema: spec,
148
+ });
149
+ }
150
+ }
151
+ break;
152
+ default:
153
+ envelope;
154
+ }
155
+ return res;
156
+ }
157
+ export function openAPIRequestBody(uc, envelope, fqUCInputName) {
158
+ const innerContent = {
159
+ schema: {
160
+ $ref: `#/components/schemas/${fqUCInputName}`,
161
+ },
162
+ };
163
+ switch (envelope) {
164
+ case 'form-data': {
165
+ const repeatableFields = uc.inputFieldsRepeatable();
166
+ const content = {
167
+ 'multipart/form-data': innerContent,
168
+ };
169
+ if (!isBlank(repeatableFields)) {
170
+ content['multipart/form-data'].encoding = {};
171
+ }
172
+ for (const f of repeatableFields) {
173
+ // This is to prevent SwaggerUI from sending the values comma separated
174
+ // biome-ignore lint/style/noNonNullAssertion: we want it
175
+ content['multipart/form-data'].encoding[f.key] = {
176
+ explode: true,
177
+ style: 'form',
178
+ };
179
+ }
180
+ return {
181
+ content,
182
+ required: true,
183
+ };
184
+ }
185
+ case 'json':
186
+ return {
187
+ content: {
188
+ 'application/json': innerContent,
189
+ },
190
+ required: true,
191
+ };
192
+ default:
193
+ envelope;
194
+ throw new Error();
195
+ }
196
+ }
197
+ export function openAPISecuritySchemes(authCookieName, publicApiKeyHeaderName) {
198
+ return {
199
+ apiKey: {
200
+ bearerFormat: 'Bearer',
201
+ in: 'header',
202
+ name: AUTHORIZATION_HEADER_NAME,
203
+ type: 'apiKey',
204
+ },
205
+ basic: {
206
+ scheme: 'basic',
207
+ type: 'http',
208
+ },
209
+ jwt: {
210
+ in: 'cookie',
211
+ name: authCookieName,
212
+ type: 'apiKey',
213
+ },
214
+ publicApiKey: {
215
+ in: 'header',
216
+ name: publicApiKeyHeaderName,
217
+ type: 'apiKey',
218
+ },
219
+ };
220
+ }
221
+ export function openAPISecurity(sec) {
222
+ const item = {};
223
+ const res = [item];
224
+ const publicApiCheckType = sec?.publicApiKeyCheckType ?? DEFAULT_UC_SEC_PAKCT;
225
+ switch (publicApiCheckType) {
226
+ case 'off':
227
+ break;
228
+ case 'on':
229
+ item.publicApiKey = [];
230
+ break;
231
+ default:
232
+ publicApiCheckType;
233
+ }
234
+ const authType = sec?.authType ?? DEFAULT_UC_SEC_AT;
235
+ item[authType] = [];
236
+ return res;
237
+ }
238
+ export function openAPISuccess(uc) {
239
+ return {
240
+ '200': {
241
+ content: {
242
+ 'application/json': {
243
+ schema: openAPIOutputSchema(uc),
244
+ },
245
+ },
246
+ description: SUCCESS_DESCRIPTION,
247
+ },
248
+ };
249
+ }
@@ -0,0 +1,16 @@
1
+ import type { DataType } from '../../../dt/index.js';
2
+ import { type UCInputField } from '../../../uc/index.js';
3
+ import type { OpenAPIProperty } from './types.js';
4
+ export interface OpenAPIInputDef<T extends DataType> {
5
+ /**
6
+ * Internal types that are not part of the spec
7
+ */
8
+ internal?: {
9
+ required?: boolean;
10
+ };
11
+ /**
12
+ * Fields that are part of the spec
13
+ */
14
+ spec?: OpenAPIProperty<T>;
15
+ }
16
+ export declare function openAPIInputDef<T extends DataType>(field: UCInputField<T>): OpenAPIInputDef<T>;
@@ -0,0 +1,33 @@
1
+ import { ucifExamples, ucifIsMandatory, ucifRepeatability, } from '../../../uc/index.js';
2
+ export function openAPIInputDef(field) {
3
+ const def = {
4
+ internal: {},
5
+ spec: { type: 'string' },
6
+ };
7
+ if (!def.internal || !def.spec) {
8
+ // Just a guard to safely type the rest of the function without using !
9
+ return def;
10
+ }
11
+ const { def: fDef } = field;
12
+ const { type: fType } = fDef;
13
+ def.internal.required = ucifIsMandatory(fDef);
14
+ def.spec = fType.jsonSchemaType();
15
+ const examples = ucifExamples(fDef);
16
+ if (examples) {
17
+ def.spec.examples = examples;
18
+ }
19
+ const options = fType.getOptions();
20
+ if (options) {
21
+ def.spec.enum = options.map((o) => o.value);
22
+ }
23
+ const [isRepeatable] = ucifRepeatability(fDef);
24
+ if (isRepeatable) {
25
+ def.spec = {
26
+ items: def.spec,
27
+ maxItems: fDef.cardinality?.max,
28
+ minItems: fDef.cardinality?.min,
29
+ type: 'array',
30
+ };
31
+ }
32
+ return def;
33
+ }