@uns-kit/api 3.0.22 → 3.0.24

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uns-kit/api",
3
- "version": "3.0.22",
3
+ "version": "3.0.24",
4
4
  "description": "Express-powered API gateway plugin for UnsProxyProcess with JWT/JWKS support.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -37,7 +37,7 @@
37
37
  "multer": "^2.2.0",
38
38
  "hyparquet-writer": "^0.16.5",
39
39
  "uuid": "^14.0.1",
40
- "@uns-kit/core": "3.0.22"
40
+ "@uns-kit/core": "3.0.24"
41
41
  },
42
42
  "devDependencies": {
43
43
  "@types/cookie-parser": "^1.4.10",
@@ -1,185 +0,0 @@
1
- export type { IApiProxyOptions, IGetEndpointOptions, IPostEndpointOptions, QueryParamDef, } from "@uns-kit/core/uns/uns-interfaces.js";
2
- import type { IGetEndpointOptions, IPostEndpointOptions } from "@uns-kit/core/uns/uns-interfaces.js";
3
- export type ApiInteractionMethod = "GET" | "POST" | "PUT" | "PATCH" | "DELETE";
4
- export type DataCatalogParameterRegistration = {
5
- name: string;
6
- in: "path" | "query" | "header" | "cookie";
7
- required?: boolean;
8
- description?: string | null;
9
- type?: string | null;
10
- format?: string | null;
11
- nullable?: boolean;
12
- example?: unknown;
13
- enumValues?: string[];
14
- schema?: unknown;
15
- };
16
- export type DataCatalogSchemaFieldRegistration = {
17
- name: string;
18
- path?: string;
19
- sourceKey?: string | null;
20
- type?: string | null;
21
- format?: string | null;
22
- nullable?: boolean;
23
- required?: boolean;
24
- description?: string | null;
25
- enumValues?: string[];
26
- example?: unknown;
27
- };
28
- export type DataCatalogSchemaRegistration = {
29
- id: string;
30
- title: string;
31
- kind?: string | null;
32
- source?: string | null;
33
- contentType?: string | null;
34
- rootType?: string | null;
35
- fieldPathPrefix?: string | null;
36
- nullable?: boolean;
37
- description?: string | null;
38
- fields?: DataCatalogSchemaFieldRegistration[];
39
- examplePayloads?: unknown[];
40
- };
41
- export type DataCatalogRequestBodyRegistration = {
42
- required?: boolean;
43
- description?: string | null;
44
- contentType?: string | null;
45
- schemas?: DataCatalogSchemaRegistration[];
46
- schemaIds?: string[];
47
- };
48
- export type DataCatalogResponseRegistration = {
49
- statusCode: string;
50
- description?: string | null;
51
- contentType?: string | null;
52
- schemas?: DataCatalogSchemaRegistration[];
53
- schemaIds?: string[];
54
- examplePayloads?: unknown[];
55
- headers?: DataCatalogParameterRegistration[];
56
- };
57
- export type DataCatalogOperationRegistration = {
58
- id?: string;
59
- method: ApiInteractionMethod | "HEAD" | "OPTIONS";
60
- path: string;
61
- summary?: string | null;
62
- description?: string | null;
63
- tags?: string[];
64
- deprecated?: boolean;
65
- parameters?: DataCatalogParameterRegistration[];
66
- headers?: DataCatalogParameterRegistration[];
67
- requestBody?: DataCatalogRequestBodyRegistration | null;
68
- responses?: DataCatalogResponseRegistration[];
69
- };
70
- export type DataCatalogOfferRegistration = {
71
- offerId: string;
72
- displayName: string;
73
- description?: string | null;
74
- owner?: string | null;
75
- status?: string | null;
76
- tags?: string[];
77
- categories?: string[];
78
- microserviceName?: string | null;
79
- version?: string | null;
80
- basePaths?: string[];
81
- operations: DataCatalogOperationRegistration[];
82
- schemas?: DataCatalogSchemaRegistration[];
83
- swaggerPath?: string | null;
84
- metadata?: Record<string, unknown> | null;
85
- };
86
- type ApiRouteIdentity<Handler = unknown> = {
87
- topic: string;
88
- asset: string;
89
- objectType: string;
90
- objectId: string;
91
- attribute: string;
92
- handler: Handler;
93
- };
94
- export type DataCatalogOfferSourceRegistration<Handler = unknown> = ApiRouteIdentity<Handler> & {
95
- offerId: string;
96
- displayName: string;
97
- description: string;
98
- owner?: string;
99
- status?: string;
100
- tags?: string[];
101
- categories?: string[];
102
- method?: ApiInteractionMethod;
103
- queryParams?: DataCatalogParameterRegistration[];
104
- headers?: DataCatalogParameterRegistration[];
105
- requestBody?: DataCatalogRequestBodyRegistration | null;
106
- response?: {
107
- statusCode?: string;
108
- description?: string | null;
109
- contentType?: string | null;
110
- headers?: DataCatalogParameterRegistration[];
111
- examplePayloads?: unknown[];
112
- };
113
- schema: DataCatalogSchemaRegistration;
114
- apiDescription?: string;
115
- };
116
- export type ServiceApiRegistration<Handler = unknown> = {
117
- attribute: string;
118
- handler: Handler;
119
- method?: ApiInteractionMethod;
120
- description: string;
121
- publishInUnsTree?: boolean;
122
- tags?: string[];
123
- queryParams?: DataCatalogParameterRegistration[];
124
- requestBody?: DataCatalogRequestBodyRegistration | null;
125
- response?: DataCatalogResponseRegistration;
126
- schema?: DataCatalogSchemaRegistration;
127
- topic?: string;
128
- asset?: string;
129
- objectType?: string;
130
- objectId?: string;
131
- };
132
- export type ApiInteractionDefinition<Handler = unknown> = {
133
- id: string;
134
- topic: string;
135
- asset: string;
136
- objectType: string;
137
- objectId: string;
138
- attribute: string;
139
- method: ApiInteractionMethod;
140
- routeOnly?: boolean;
141
- registryTopic?: "api-endpoints" | "service-endpoints" | "data-offer-endpoints";
142
- options: IGetEndpointOptions | IPostEndpointOptions;
143
- handler: Handler;
144
- };
145
- export declare function defineApiInteraction<Handler>(input: ApiInteractionDefinition<Handler>): ApiInteractionDefinition<Handler>;
146
- export declare function defineServiceApi<Handler>(input: ServiceApiRegistration<Handler>): ServiceApiRegistration<Handler>;
147
- export declare function buildApiInteractionPath(route: Pick<ApiInteractionDefinition, "topic" | "asset" | "objectType" | "objectId" | "attribute">, apiBasePrefix?: string): string;
148
- export declare function buildApiInteractionTopicPath(route: Pick<ApiInteractionDefinition, "topic" | "asset" | "objectType" | "objectId" | "attribute">): string;
149
- export declare function defineDataCatalogQueryParam(name: string, description: string, options?: {
150
- required?: boolean;
151
- type?: string;
152
- format?: string;
153
- example?: unknown;
154
- }): DataCatalogParameterRegistration;
155
- export declare function defineDataCatalogField(name: string, type: string, description: string, options?: {
156
- path?: string;
157
- sourceKey?: string;
158
- required?: boolean;
159
- format?: string;
160
- nullable?: boolean;
161
- example?: unknown;
162
- enumValues?: string[];
163
- }): DataCatalogSchemaFieldRegistration;
164
- export declare function defineDataCatalogSchema(input: {
165
- id: string;
166
- title: string;
167
- contentType: string;
168
- description?: string;
169
- kind?: string;
170
- source?: string;
171
- rootType?: string;
172
- fieldPathPrefix?: string;
173
- fields: DataCatalogSchemaFieldRegistration[];
174
- examplePayloads?: unknown[];
175
- }): DataCatalogSchemaRegistration;
176
- export declare function buildDataCatalogOfferOperation(route: Pick<ApiInteractionDefinition, "topic" | "asset" | "objectType" | "objectId" | "attribute">, operation: Omit<DataCatalogOperationRegistration, "path">, apiBasePrefix?: string): DataCatalogOperationRegistration;
177
- export declare function defineDataCatalogOfferSource<Handler>(input: DataCatalogOfferSourceRegistration<Handler>): DataCatalogOfferSourceRegistration<Handler>;
178
- export declare function buildServiceApiInteractions<Handler, T extends Record<string, ServiceApiRegistration<Handler>>>(processName: string, definitions: T): Record<keyof T, ApiInteractionDefinition<Handler>>;
179
- export declare function buildApiInteractionsFromDataOfferSources<Handler, T extends Record<string, DataCatalogOfferSourceRegistration<Handler>>>(sources: T): Record<keyof T, ApiInteractionDefinition<Handler>>;
180
- export declare function buildDataCatalogOffersFromSources<T extends Record<string, DataCatalogOfferSourceRegistration<any>>>(sources: T): DataCatalogOfferRegistration[];
181
- export declare function projectRowsForDataCatalogSchema(rows: Array<Record<string, unknown>>, schema: DataCatalogSchemaRegistration): Array<Record<string, unknown>>;
182
- export declare function buildSchemaFieldPathIndex(schema: DataCatalogSchemaRegistration): Array<{
183
- path: string;
184
- name: string;
185
- }>;
@@ -1,311 +0,0 @@
1
- import { buildUnsRoutePath } from "@uns-kit/core/uns/uns-path.js";
2
- export function defineApiInteraction(input) {
3
- return input;
4
- }
5
- export function defineServiceApi(input) {
6
- return input;
7
- }
8
- export function buildApiInteractionPath(route, apiBasePrefix = "/api") {
9
- return `${apiBasePrefix}${buildUnsRoutePath(route.topic, route.asset, route.objectType, route.objectId, route.attribute)}`.replace(/\/{2,}/g, "/");
10
- }
11
- export function buildApiInteractionTopicPath(route) {
12
- return buildUnsRoutePath(route.topic, route.asset, route.objectType, route.objectId, route.attribute).slice(1);
13
- }
14
- export function defineDataCatalogQueryParam(name, description, options = {}) {
15
- return {
16
- name,
17
- in: "query",
18
- type: options.type ?? "string",
19
- required: options.required === true,
20
- description,
21
- ...(options.format ? { format: options.format } : {}),
22
- ...(options.example !== undefined ? { example: options.example } : {}),
23
- };
24
- }
25
- export function defineDataCatalogField(name, type, description, options = {}) {
26
- return {
27
- name,
28
- path: options.path ?? name,
29
- type,
30
- description,
31
- required: options.required === true,
32
- nullable: options.nullable === true,
33
- ...(options.format ? { format: options.format } : {}),
34
- ...(options.example !== undefined ? { example: options.example } : {}),
35
- ...(Array.isArray(options.enumValues) ? { enumValues: options.enumValues } : {}),
36
- ...(options.sourceKey ? { sourceKey: options.sourceKey } : {}),
37
- };
38
- }
39
- export function defineDataCatalogSchema(input) {
40
- const fieldPathPrefix = input.fieldPathPrefix?.trim();
41
- const fields = input.fields.map((field) => ({
42
- ...field,
43
- path: field.path ?? buildSchemaFieldPath(field.name, field.type ?? "string", fieldPathPrefix),
44
- }));
45
- const shouldAutogenerateExamples = !isBinaryCatalogContentType(input.contentType);
46
- const examplePayloads = Array.isArray(input.examplePayloads) && input.examplePayloads.length
47
- ? input.examplePayloads
48
- : shouldAutogenerateExamples
49
- ? buildExamplePayloadsFromFields(fields)
50
- : [];
51
- return {
52
- id: input.id,
53
- title: input.title,
54
- kind: input.kind ?? "response",
55
- source: input.source ?? "registered",
56
- contentType: input.contentType,
57
- rootType: input.rootType ?? inferSchemaRootType(input.contentType, input.fields),
58
- ...(fieldPathPrefix ? { fieldPathPrefix } : {}),
59
- ...(input.description ? { description: input.description } : {}),
60
- fields,
61
- ...(examplePayloads?.length ? { examplePayloads } : {}),
62
- };
63
- }
64
- function isBinaryCatalogContentType(contentType) {
65
- const normalized = String(contentType ?? "").toLowerCase();
66
- return normalized.includes("parquet") || normalized.includes("octet-stream");
67
- }
68
- export function buildDataCatalogOfferOperation(route, operation, apiBasePrefix = "/api") {
69
- return {
70
- ...operation,
71
- path: buildApiInteractionPath(route, apiBasePrefix),
72
- };
73
- }
74
- export function defineDataCatalogOfferSource(input) {
75
- return input;
76
- }
77
- export function buildServiceApiInteractions(processName, definitions) {
78
- return Object.fromEntries(Object.entries(definitions).map(([key, definition]) => [
79
- key,
80
- defineApiInteraction({
81
- id: String(key),
82
- topic: definition.topic ?? "system",
83
- asset: definition.asset ?? "service",
84
- objectType: definition.objectType ?? "runtime",
85
- objectId: definition.objectId ?? processName,
86
- attribute: definition.attribute,
87
- method: definition.method ?? "GET",
88
- routeOnly: definition.publishInUnsTree !== true,
89
- registryTopic: "service-endpoints",
90
- options: buildApiInteractionOptions(definition.method ?? "GET", definition.description, definition.tags, definition.queryParams, definition.requestBody, definition.publishInUnsTree !== true, "service-endpoints", buildServiceApiPayload(String(key), definition)),
91
- handler: definition.handler,
92
- }),
93
- ]));
94
- }
95
- export function buildApiInteractionsFromDataOfferSources(sources) {
96
- return Object.fromEntries(Object.entries(sources).map(([key, source]) => [
97
- key,
98
- defineApiInteraction({
99
- id: source.offerId,
100
- topic: source.topic,
101
- asset: source.asset,
102
- objectType: source.objectType,
103
- objectId: source.objectId,
104
- attribute: source.attribute,
105
- method: source.method ?? "GET",
106
- routeOnly: true,
107
- registryTopic: "data-offer-endpoints",
108
- options: buildApiInteractionOptions(source.method ?? "GET", source.apiDescription ?? source.description, source.tags, source.queryParams, source.requestBody, true, "data-offer-endpoints"),
109
- handler: source.handler,
110
- }),
111
- ]));
112
- }
113
- export function buildDataCatalogOffersFromSources(sources) {
114
- return Object.values(sources).map((source) => ({
115
- offerId: source.offerId,
116
- displayName: source.displayName,
117
- description: source.description,
118
- ...(source.owner ? { owner: source.owner } : {}),
119
- status: source.status ?? "available",
120
- ...(source.tags ? { tags: source.tags } : {}),
121
- ...(source.categories ? { categories: source.categories } : {}),
122
- schemas: [source.schema],
123
- operations: [
124
- buildDataCatalogOfferOperation(source, {
125
- id: `${source.offerId}-${(source.method ?? "GET").toLowerCase()}`,
126
- method: source.method ?? "GET",
127
- summary: source.displayName,
128
- description: source.description,
129
- ...(source.tags ? { tags: source.tags } : {}),
130
- ...(source.queryParams ? { parameters: source.queryParams } : {}),
131
- ...(source.headers ? { headers: source.headers } : {}),
132
- ...(source.requestBody !== undefined ? { requestBody: source.requestBody } : {}),
133
- responses: [
134
- {
135
- statusCode: source.response?.statusCode ?? "200",
136
- ...(source.response?.description ? { description: source.response.description } : { description: source.description }),
137
- contentType: source.response?.contentType ?? source.schema.contentType ?? null,
138
- schemas: [source.schema],
139
- ...(source.response?.examplePayloads ? { examplePayloads: source.response.examplePayloads } : {}),
140
- ...(source.response?.headers ? { headers: source.response.headers } : { headers: [] }),
141
- },
142
- ],
143
- }),
144
- ],
145
- }));
146
- }
147
- export function projectRowsForDataCatalogSchema(rows, schema) {
148
- const leafFields = (schema.fields ?? []).filter((field) => field.type !== "array");
149
- return rows.map((row) => {
150
- const projected = {};
151
- for (const field of leafFields) {
152
- const outputKey = field.name;
153
- const sourceKey = field.sourceKey?.trim() || field.name;
154
- projected[outputKey] = getRowValue(row, sourceKey);
155
- }
156
- return projected;
157
- });
158
- }
159
- export function buildSchemaFieldPathIndex(schema) {
160
- return (schema.fields ?? []).map((field) => ({
161
- path: field.path ?? field.name,
162
- name: field.name,
163
- }));
164
- }
165
- function inferSchemaRootType(contentType, fields) {
166
- if (contentType.includes("parquet") || contentType.includes("octet-stream")) {
167
- return "table";
168
- }
169
- if (fields.some((field) => (field.path ?? field.name).includes("[]"))) {
170
- return "object";
171
- }
172
- return "object";
173
- }
174
- function buildSchemaFieldPath(name, type, fieldPathPrefix) {
175
- if (fieldPathPrefix && type !== "array") {
176
- return `${fieldPathPrefix}.${name}`;
177
- }
178
- return name;
179
- }
180
- function buildApiInteractionOptions(method, description, tags, queryParams, requestBody, routeOnly = true, registryTopic = "api-endpoints", serviceApi) {
181
- if (method === "GET") {
182
- return {
183
- apiDescription: description,
184
- ...(routeOnly ? { routeOnly: true } : {}),
185
- ...(registryTopic ? { registryTopic } : {}),
186
- ...(serviceApi ? { serviceApi } : {}),
187
- ...(tags ? { tags } : {}),
188
- ...(queryParams
189
- ? {
190
- queryParams: queryParams
191
- .filter((parameter) => parameter.in === "query")
192
- .map((parameter) => ({
193
- name: parameter.name,
194
- type: parameter.type === "number" || parameter.type === "boolean"
195
- ? parameter.type
196
- : "string",
197
- required: parameter.required,
198
- ...(parameter.description ? { description: parameter.description } : {}),
199
- })),
200
- }
201
- : {}),
202
- };
203
- }
204
- const requestSchema = requestBody?.schemas?.[0]
205
- ? buildJsonSchemaFromCatalogSchema(requestBody.schemas[0])
206
- : null;
207
- return {
208
- apiDescription: description,
209
- ...(routeOnly ? { routeOnly: true } : {}),
210
- ...(registryTopic ? { registryTopic } : {}),
211
- ...(serviceApi ? { serviceApi } : {}),
212
- ...(tags ? { tags } : {}),
213
- ...(requestBody
214
- ? {
215
- requestBody: {
216
- required: requestBody.required ?? true,
217
- ...(requestBody.description ? { description: requestBody.description } : {}),
218
- ...(requestSchema && typeof requestSchema === "object" ? { schema: requestSchema } : {}),
219
- },
220
- }
221
- : {}),
222
- };
223
- }
224
- function buildServiceApiPayload(id, definition) {
225
- const schemas = definition.schema ? [definition.schema] : [];
226
- const response = definition.response ?? {
227
- statusCode: "200",
228
- description: definition.description,
229
- ...(definition.schema?.contentType ? { contentType: definition.schema.contentType } : {}),
230
- ...(definition.schema ? { schemas: [definition.schema] } : {}),
231
- };
232
- return {
233
- id,
234
- summary: definition.description,
235
- description: definition.description,
236
- tags: definition.tags ?? [],
237
- parameters: definition.queryParams ?? [],
238
- headers: [],
239
- requestBody: definition.requestBody ?? null,
240
- responses: [response],
241
- schemas,
242
- };
243
- }
244
- function getRowValue(row, key) {
245
- if (Object.prototype.hasOwnProperty.call(row, key)) {
246
- return row[key];
247
- }
248
- const normalizedKey = key.toLowerCase();
249
- const match = Object.keys(row).find((candidate) => candidate.toLowerCase() === normalizedKey);
250
- return match ? row[match] : null;
251
- }
252
- function buildJsonSchemaFromCatalogSchema(schema) {
253
- const leafFields = (schema.fields ?? []).filter((field) => field.type !== "array");
254
- const properties = Object.fromEntries(leafFields.map((field) => [
255
- field.name,
256
- {
257
- type: toJsonSchemaType(field.type ?? "string"),
258
- ...(field.description ? { description: field.description } : {}),
259
- ...(field.format ? { format: field.format } : {}),
260
- ...(field.example !== undefined ? { example: field.example } : {}),
261
- ...(Array.isArray(field.enumValues) && field.enumValues.length ? { enum: field.enumValues } : {}),
262
- },
263
- ]));
264
- const required = leafFields.filter((field) => field.required === true).map((field) => field.name);
265
- return {
266
- type: "object",
267
- ...(required.length ? { required } : {}),
268
- properties,
269
- };
270
- }
271
- function toJsonSchemaType(type) {
272
- switch (type) {
273
- case "number":
274
- case "integer":
275
- case "boolean":
276
- case "array":
277
- case "object":
278
- return type;
279
- default:
280
- return "string";
281
- }
282
- }
283
- function buildExamplePayloadsFromFields(fields) {
284
- const arrayFields = fields.filter((field) => field.type === "array");
285
- const scalarFields = fields.filter((field) => field.type !== "array");
286
- if (!scalarFields.length) {
287
- return undefined;
288
- }
289
- if (arrayFields.length === 1 && isGenericListField(arrayFields[0].name)) {
290
- const listField = arrayFields[0];
291
- const rowFields = scalarFields.filter((field) => field.name !== "count");
292
- if (!rowFields.length || rowFields.some((field) => field.example === undefined)) {
293
- return undefined;
294
- }
295
- const payload = {
296
- [listField.name]: [Object.fromEntries(rowFields.map((field) => [field.name, field.example]))],
297
- };
298
- const countField = scalarFields.find((field) => field.name === "count");
299
- if (countField) {
300
- payload[countField.name] = countField.example ?? 1;
301
- }
302
- return [payload];
303
- }
304
- if (scalarFields.some((field) => field.example === undefined)) {
305
- return undefined;
306
- }
307
- return [Object.fromEntries(scalarFields.map((field) => [field.name, field.example]))];
308
- }
309
- function isGenericListField(name) {
310
- return name === "data" || name === "rows";
311
- }
package/dist/app.d.ts DELETED
@@ -1,48 +0,0 @@
1
- /**
2
- * Module dependencies.
3
- */
4
- import { type Router } from "express";
5
- import * as http from "http";
6
- type MountConfig = {
7
- apiBasePrefix?: string;
8
- swaggerBasePrefix?: string;
9
- disableDefaultApiMount?: boolean;
10
- };
11
- export default class App {
12
- private expressApplication;
13
- server: http.Server<typeof http.IncomingMessage, typeof http.ServerResponse>;
14
- private port;
15
- router: Router;
16
- private processName;
17
- private instanceName;
18
- private apiBasePrefix;
19
- private swaggerBasePrefix;
20
- swaggerSpec: {
21
- openapi: string;
22
- info: {
23
- title: string;
24
- version: string;
25
- };
26
- paths: Record<string, any>;
27
- servers?: Array<{
28
- url: string;
29
- }>;
30
- };
31
- private swaggerDocs;
32
- constructor(port: number, processName: string, instanceName: string, appContext?: any, mountConfig?: MountConfig);
33
- static getExternalIPv4(): string | null;
34
- getSwaggerSpec(): {
35
- openapi: string;
36
- info: {
37
- title: string;
38
- version: string;
39
- };
40
- paths: Record<string, any>;
41
- servers?: Array<{
42
- url: string;
43
- }>;
44
- };
45
- registerSwaggerDoc(path: string, doc: Record<string, unknown>): void;
46
- start(): Promise<void>;
47
- }
48
- export {};