vovk 3.0.0-draft.46 → 3.0.0-draft.461
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/LICENSE +1 -1
- package/README.md +8 -96
- package/bin/index.mjs +8 -0
- package/cjs/JSONLinesResponse.d.ts +19 -0
- package/cjs/JSONLinesResponse.js +95 -0
- package/{VovkApp.d.ts → cjs/VovkApp.d.ts} +14 -8
- package/cjs/VovkApp.js +304 -0
- package/cjs/client/createRPC.d.ts +5 -0
- package/cjs/client/createRPC.js +116 -0
- package/cjs/client/defaultHandler.d.ts +6 -0
- package/{client → cjs/client}/defaultHandler.js +9 -2
- package/cjs/client/defaultStreamHandler.d.ts +9 -0
- package/{client → cjs/client}/defaultStreamHandler.js +49 -26
- package/cjs/client/fetcher.d.ts +18 -0
- package/cjs/client/fetcher.js +97 -0
- package/cjs/client/index.d.ts +4 -0
- package/cjs/client/index.js +10 -0
- package/cjs/client/progressive.d.ts +9 -0
- package/cjs/client/progressive.js +54 -0
- package/cjs/client/types.d.ts +120 -0
- package/{createVovkApp.d.ts → cjs/createVovkApp.d.ts} +19 -16
- package/cjs/createVovkApp.js +146 -0
- package/cjs/index.d.ts +69 -0
- package/cjs/index.js +42 -0
- package/cjs/openapi/error.d.ts +2 -0
- package/cjs/openapi/error.js +100 -0
- package/cjs/openapi/index.d.ts +8 -0
- package/cjs/openapi/index.js +21 -0
- package/cjs/openapi/openAPIToVovkSchema/applyComponentsSchemas.d.ts +3 -0
- package/cjs/openapi/openAPIToVovkSchema/applyComponentsSchemas.js +67 -0
- package/cjs/openapi/openAPIToVovkSchema/index.d.ts +4 -0
- package/cjs/openapi/openAPIToVovkSchema/index.js +141 -0
- package/cjs/openapi/openAPIToVovkSchema/inlineRefs.d.ts +10 -0
- package/cjs/openapi/openAPIToVovkSchema/inlineRefs.js +102 -0
- package/cjs/openapi/vovkSchemaToOpenAPI.d.ts +8 -0
- package/cjs/openapi/vovkSchemaToOpenAPI.js +238 -0
- package/cjs/types.d.ts +466 -0
- package/{types.js → cjs/types.js} +14 -2
- package/cjs/utils/camelCase.d.ts +6 -0
- package/cjs/utils/camelCase.js +37 -0
- package/cjs/utils/createCodeSamples.d.ts +20 -0
- package/cjs/utils/createCodeSamples.js +279 -0
- package/cjs/utils/createDecorator.d.ts +6 -0
- package/{createDecorator.js → cjs/utils/createDecorator.js} +24 -14
- package/cjs/utils/createLLMTools.d.ts +50 -0
- package/cjs/utils/createLLMTools.js +168 -0
- package/cjs/utils/createStandardValidation.d.ts +83 -0
- package/cjs/utils/createStandardValidation.js +35 -0
- package/cjs/utils/createValidateOnClient.d.ts +7 -0
- package/cjs/utils/createValidateOnClient.js +19 -0
- package/cjs/utils/deepExtend.d.ts +54 -0
- package/cjs/utils/deepExtend.js +134 -0
- package/{utils → cjs/utils}/generateStaticAPI.d.ts +2 -2
- package/cjs/utils/generateStaticAPI.js +30 -0
- package/cjs/utils/getJSONSchemaExample.d.ts +11 -0
- package/cjs/utils/getJSONSchemaExample.js +264 -0
- package/cjs/utils/getJSONSchemaSample.d.ts +2 -0
- package/cjs/utils/getJSONSchemaSample.js +167 -0
- package/cjs/utils/getSampleFromObject.d.ts +9 -0
- package/cjs/utils/getSampleFromObject.js +41 -0
- package/cjs/utils/getSchema.d.ts +21 -0
- package/cjs/utils/getSchema.js +38 -0
- package/cjs/utils/multitenant.d.ts +24 -0
- package/cjs/utils/multitenant.js +131 -0
- package/cjs/utils/parseQuery.d.ts +25 -0
- package/cjs/utils/parseQuery.js +156 -0
- package/cjs/utils/reqForm.d.ts +2 -0
- package/cjs/utils/reqForm.js +33 -0
- package/cjs/utils/reqMeta.d.ts +2 -0
- package/cjs/utils/reqQuery.d.ts +2 -0
- package/cjs/utils/reqQuery.js +10 -0
- package/cjs/utils/resolveGeneratorConfigValues.d.ts +18 -0
- package/cjs/utils/resolveGeneratorConfigValues.js +82 -0
- package/cjs/utils/serializeQuery.d.ts +13 -0
- package/cjs/utils/serializeQuery.js +65 -0
- package/cjs/utils/setHandlerSchema.d.ts +4 -0
- package/cjs/utils/setHandlerSchema.js +15 -0
- package/cjs/utils/upperFirst.d.ts +1 -0
- package/cjs/utils/upperFirst.js +6 -0
- package/cjs/utils/withValidationLibrary.d.ts +78 -0
- package/cjs/utils/withValidationLibrary.js +133 -0
- package/mjs/HttpException.d.ts +7 -0
- package/mjs/HttpException.js +15 -0
- package/mjs/JSONLinesResponse.d.ts +19 -0
- package/mjs/JSONLinesResponse.js +95 -0
- package/mjs/VovkApp.d.ts +34 -0
- package/mjs/VovkApp.js +304 -0
- package/mjs/client/createRPC.d.ts +5 -0
- package/mjs/client/createRPC.js +116 -0
- package/mjs/client/defaultHandler.d.ts +6 -0
- package/mjs/client/defaultHandler.js +29 -0
- package/mjs/client/defaultStreamHandler.d.ts +9 -0
- package/mjs/client/defaultStreamHandler.js +105 -0
- package/mjs/client/fetcher.d.ts +18 -0
- package/mjs/client/fetcher.js +97 -0
- package/mjs/client/index.d.ts +4 -0
- package/mjs/client/index.js +10 -0
- package/mjs/client/progressive.d.ts +9 -0
- package/mjs/client/progressive.js +54 -0
- package/mjs/client/types.d.ts +120 -0
- package/mjs/createVovkApp.d.ts +65 -0
- package/mjs/createVovkApp.js +146 -0
- package/mjs/index.d.ts +69 -0
- package/mjs/index.js +42 -0
- package/mjs/openapi/error.d.ts +2 -0
- package/mjs/openapi/error.js +100 -0
- package/mjs/openapi/index.d.ts +8 -0
- package/mjs/openapi/index.js +21 -0
- package/mjs/openapi/openAPIToVovkSchema/applyComponentsSchemas.d.ts +3 -0
- package/mjs/openapi/openAPIToVovkSchema/applyComponentsSchemas.js +67 -0
- package/mjs/openapi/openAPIToVovkSchema/index.d.ts +4 -0
- package/mjs/openapi/openAPIToVovkSchema/index.js +141 -0
- package/mjs/openapi/openAPIToVovkSchema/inlineRefs.d.ts +10 -0
- package/mjs/openapi/openAPIToVovkSchema/inlineRefs.js +102 -0
- package/mjs/openapi/vovkSchemaToOpenAPI.d.ts +8 -0
- package/mjs/openapi/vovkSchemaToOpenAPI.js +238 -0
- package/mjs/types.d.ts +466 -0
- package/mjs/types.js +77 -0
- package/mjs/utils/camelCase.d.ts +6 -0
- package/mjs/utils/camelCase.js +37 -0
- package/mjs/utils/createCodeSamples.d.ts +20 -0
- package/mjs/utils/createCodeSamples.js +279 -0
- package/mjs/utils/createDecorator.d.ts +6 -0
- package/mjs/utils/createDecorator.js +48 -0
- package/mjs/utils/createLLMTools.d.ts +50 -0
- package/mjs/utils/createLLMTools.js +168 -0
- package/mjs/utils/createStandardValidation.d.ts +83 -0
- package/mjs/utils/createStandardValidation.js +35 -0
- package/mjs/utils/createValidateOnClient.d.ts +7 -0
- package/mjs/utils/createValidateOnClient.js +19 -0
- package/mjs/utils/deepExtend.d.ts +54 -0
- package/mjs/utils/deepExtend.js +134 -0
- package/mjs/utils/generateStaticAPI.d.ts +4 -0
- package/mjs/utils/generateStaticAPI.js +30 -0
- package/mjs/utils/getJSONSchemaExample.d.ts +11 -0
- package/mjs/utils/getJSONSchemaExample.js +264 -0
- package/mjs/utils/getJSONSchemaSample.d.ts +2 -0
- package/mjs/utils/getJSONSchemaSample.js +167 -0
- package/mjs/utils/getSampleFromObject.d.ts +9 -0
- package/mjs/utils/getSampleFromObject.js +41 -0
- package/mjs/utils/getSchema.d.ts +21 -0
- package/mjs/utils/getSchema.js +38 -0
- package/mjs/utils/multitenant.d.ts +24 -0
- package/mjs/utils/multitenant.js +131 -0
- package/mjs/utils/parseQuery.d.ts +25 -0
- package/mjs/utils/parseQuery.js +156 -0
- package/mjs/utils/reqForm.d.ts +2 -0
- package/mjs/utils/reqForm.js +33 -0
- package/mjs/utils/reqMeta.d.ts +2 -0
- package/mjs/utils/reqMeta.js +13 -0
- package/mjs/utils/reqQuery.d.ts +2 -0
- package/mjs/utils/reqQuery.js +10 -0
- package/mjs/utils/resolveGeneratorConfigValues.d.ts +18 -0
- package/mjs/utils/resolveGeneratorConfigValues.js +82 -0
- package/mjs/utils/serializeQuery.d.ts +13 -0
- package/mjs/utils/serializeQuery.js +65 -0
- package/mjs/utils/setHandlerSchema.d.ts +4 -0
- package/mjs/utils/setHandlerSchema.js +15 -0
- package/mjs/utils/shim.d.ts +1 -0
- package/mjs/utils/shim.js +18 -0
- package/mjs/utils/upperFirst.d.ts +1 -0
- package/mjs/utils/upperFirst.js +6 -0
- package/mjs/utils/withValidationLibrary.d.ts +78 -0
- package/mjs/utils/withValidationLibrary.js +133 -0
- package/package.json +28 -6
- package/.npmignore +0 -2
- package/StreamJSONResponse.d.ts +0 -17
- package/StreamJSONResponse.js +0 -54
- package/VovkApp.js +0 -185
- package/client/clientizeController.d.ts +0 -4
- package/client/clientizeController.js +0 -93
- package/client/defaultFetcher.d.ts +0 -4
- package/client/defaultFetcher.js +0 -49
- package/client/defaultHandler.d.ts +0 -2
- package/client/defaultStreamHandler.d.ts +0 -4
- package/client/index.d.ts +0 -4
- package/client/index.js +0 -5
- package/client/types.d.ts +0 -100
- package/createDecorator.d.ts +0 -4
- package/createVovkApp.js +0 -118
- package/index.d.ts +0 -60
- package/index.js +0 -20
- package/types.d.ts +0 -157
- package/utils/generateStaticAPI.js +0 -18
- package/utils/getSchema.d.ts +0 -8
- package/utils/getSchema.js +0 -38
- package/utils/reqForm.d.ts +0 -3
- package/utils/reqForm.js +0 -13
- package/utils/reqMeta.d.ts +0 -3
- package/utils/reqQuery.d.ts +0 -3
- package/utils/reqQuery.js +0 -25
- package/utils/setClientValidatorsForHandler.d.ts +0 -5
- package/utils/setClientValidatorsForHandler.js +0 -25
- package/worker/index.d.ts +0 -3
- package/worker/index.js +0 -7
- package/worker/promisifyWorker.d.ts +0 -2
- package/worker/promisifyWorker.js +0 -141
- package/worker/types.d.ts +0 -31
- package/worker/worker.d.ts +0 -1
- package/worker/worker.js +0 -43
- /package/{HttpException.d.ts → cjs/HttpException.d.ts} +0 -0
- /package/{HttpException.js → cjs/HttpException.js} +0 -0
- /package/{client → cjs/client}/types.js +0 -0
- /package/{utils → cjs/utils}/reqMeta.js +0 -0
- /package/{utils → cjs/utils}/shim.d.ts +0 -0
- /package/{utils → cjs/utils}/shim.js +0 -0
- /package/{worker → mjs/client}/types.js +0 -0
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getJSONSchemaSample = getJSONSchemaSample;
|
|
4
|
+
function getJSONSchemaSample(schema, rootSchema) {
|
|
5
|
+
if (!schema || typeof schema !== 'object')
|
|
6
|
+
return null;
|
|
7
|
+
// Use the input schema as the root if not provided
|
|
8
|
+
rootSchema = rootSchema || schema;
|
|
9
|
+
// If there's an example, use it
|
|
10
|
+
if (schema.example !== undefined) {
|
|
11
|
+
return schema.example;
|
|
12
|
+
}
|
|
13
|
+
// If there are examples, use one of them
|
|
14
|
+
if (schema.examples && schema.examples.length > 0) {
|
|
15
|
+
return schema.examples[0];
|
|
16
|
+
}
|
|
17
|
+
// Handle const if present
|
|
18
|
+
if (schema.const !== undefined) {
|
|
19
|
+
return schema.const;
|
|
20
|
+
}
|
|
21
|
+
// Handle $ref if present
|
|
22
|
+
if (schema.$ref) {
|
|
23
|
+
return handleRef(schema.$ref, rootSchema);
|
|
24
|
+
}
|
|
25
|
+
// Handle enum if present
|
|
26
|
+
if (schema.enum && schema.enum.length > 0) {
|
|
27
|
+
return schema.enum[0];
|
|
28
|
+
}
|
|
29
|
+
// Handle oneOf, anyOf, allOf
|
|
30
|
+
if (schema.oneOf && schema.oneOf.length > 0) {
|
|
31
|
+
return getJSONSchemaSample(schema.oneOf[0], rootSchema);
|
|
32
|
+
}
|
|
33
|
+
if (schema.anyOf && schema.anyOf.length > 0) {
|
|
34
|
+
return getJSONSchemaSample(schema.anyOf[0], rootSchema);
|
|
35
|
+
}
|
|
36
|
+
if (schema.allOf && schema.allOf.length > 0) {
|
|
37
|
+
// Merge all schemas in allOf
|
|
38
|
+
const mergedSchema = schema.allOf.reduce((acc, s) => ({ ...acc, ...s }), {});
|
|
39
|
+
return getJSONSchemaSample(mergedSchema, rootSchema);
|
|
40
|
+
}
|
|
41
|
+
// Handle different types
|
|
42
|
+
if (schema.type) {
|
|
43
|
+
switch (schema.type) {
|
|
44
|
+
case 'string':
|
|
45
|
+
return handleString(schema);
|
|
46
|
+
case 'number':
|
|
47
|
+
case 'integer':
|
|
48
|
+
return handleNumber(schema);
|
|
49
|
+
case 'boolean':
|
|
50
|
+
return handleBoolean();
|
|
51
|
+
case 'object':
|
|
52
|
+
return handleObject(schema, rootSchema);
|
|
53
|
+
case 'array':
|
|
54
|
+
return handleArray(schema, rootSchema);
|
|
55
|
+
case 'null':
|
|
56
|
+
return null;
|
|
57
|
+
default:
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
// If type is not specified but properties are, treat it as an object
|
|
62
|
+
if (schema.properties) {
|
|
63
|
+
return handleObject(schema, rootSchema);
|
|
64
|
+
}
|
|
65
|
+
// Default fallback
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
function handleRef(ref, rootSchema) {
|
|
69
|
+
// Parse the reference path
|
|
70
|
+
const path = ref.split('/').slice(1); // Remove the initial '#'
|
|
71
|
+
// Navigate through the schema to find the referenced definition
|
|
72
|
+
let current = rootSchema;
|
|
73
|
+
for (const segment of path) {
|
|
74
|
+
current = current[segment];
|
|
75
|
+
if (current === undefined) {
|
|
76
|
+
return null; // Reference not found
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
// Process the referenced schema
|
|
80
|
+
return getJSONSchemaSample(current, rootSchema);
|
|
81
|
+
}
|
|
82
|
+
function handleString(schema) {
|
|
83
|
+
if (schema.format) {
|
|
84
|
+
switch (schema.format) {
|
|
85
|
+
case 'email':
|
|
86
|
+
case 'idn-email':
|
|
87
|
+
return 'user@example.com';
|
|
88
|
+
case 'uri':
|
|
89
|
+
case 'url':
|
|
90
|
+
case 'iri':
|
|
91
|
+
return 'https://example.com';
|
|
92
|
+
case 'date':
|
|
93
|
+
return '2023-01-01';
|
|
94
|
+
case 'date-time':
|
|
95
|
+
return '2023-01-01T00:00:00Z';
|
|
96
|
+
case 'time':
|
|
97
|
+
return '12:00:00Z';
|
|
98
|
+
case 'duration':
|
|
99
|
+
return 'PT1H';
|
|
100
|
+
case 'uuid':
|
|
101
|
+
return '00000000-0000-0000-0000-000000000000';
|
|
102
|
+
case 'regex':
|
|
103
|
+
return '^[a-zA-Z0-9]+$';
|
|
104
|
+
case 'relative-json-pointer':
|
|
105
|
+
return '/some/relative/path';
|
|
106
|
+
case 'color':
|
|
107
|
+
return '#000000';
|
|
108
|
+
case 'hostname':
|
|
109
|
+
return 'example.com';
|
|
110
|
+
case 'zipcode':
|
|
111
|
+
return '12345';
|
|
112
|
+
case 'phone':
|
|
113
|
+
return '+123-456-7890';
|
|
114
|
+
case 'password':
|
|
115
|
+
return '******';
|
|
116
|
+
default:
|
|
117
|
+
return 'string';
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
if (schema.pattern) {
|
|
121
|
+
// For simplicity, return a basic string for patterns
|
|
122
|
+
return 'pattern-string';
|
|
123
|
+
}
|
|
124
|
+
return 'string';
|
|
125
|
+
}
|
|
126
|
+
function handleNumber(schema) {
|
|
127
|
+
if (schema.minimum !== undefined && schema.maximum !== undefined) {
|
|
128
|
+
return schema.minimum;
|
|
129
|
+
}
|
|
130
|
+
else if (schema.minimum !== undefined) {
|
|
131
|
+
return schema.minimum;
|
|
132
|
+
}
|
|
133
|
+
else if (schema.maximum !== undefined) {
|
|
134
|
+
return schema.maximum;
|
|
135
|
+
}
|
|
136
|
+
return 0;
|
|
137
|
+
}
|
|
138
|
+
function handleBoolean() {
|
|
139
|
+
return true;
|
|
140
|
+
}
|
|
141
|
+
function handleObject(schema, rootSchema) {
|
|
142
|
+
const result = {};
|
|
143
|
+
if (schema.properties) {
|
|
144
|
+
const required = schema.required || [];
|
|
145
|
+
for (const [key, propSchema] of Object.entries(schema.properties)) {
|
|
146
|
+
// Only include required properties or as a basic example
|
|
147
|
+
if (required.includes(key) || required.length === 0) {
|
|
148
|
+
result[key] = getJSONSchemaSample(propSchema, rootSchema);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
// Handle additionalProperties
|
|
153
|
+
if (schema.additionalProperties && typeof schema.additionalProperties === 'object') {
|
|
154
|
+
result['additionalProp'] = getJSONSchemaSample(schema.additionalProperties, rootSchema);
|
|
155
|
+
}
|
|
156
|
+
return result;
|
|
157
|
+
}
|
|
158
|
+
function handleArray(schema, rootSchema) {
|
|
159
|
+
if (schema.items) {
|
|
160
|
+
const itemSchema = schema.items;
|
|
161
|
+
const minItems = schema.minItems || 1;
|
|
162
|
+
// Create minimum number of items (capped at a reasonable max for examples)
|
|
163
|
+
const numItems = Math.min(minItems, 3);
|
|
164
|
+
return Array.from({ length: numItems }, () => getJSONSchemaSample(itemSchema, rootSchema));
|
|
165
|
+
}
|
|
166
|
+
return [];
|
|
167
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { KnownAny } from '../types';
|
|
2
|
+
interface SamplerOptions {
|
|
3
|
+
stripQuotes?: boolean;
|
|
4
|
+
indent?: number;
|
|
5
|
+
nestingIndent?: number;
|
|
6
|
+
quote?: '"' | "'";
|
|
7
|
+
}
|
|
8
|
+
export declare function getSampleFromObject(obj: KnownAny, options?: SamplerOptions): string;
|
|
9
|
+
export {};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getSampleFromObject = getSampleFromObject;
|
|
4
|
+
function getSampleFromObject(obj, options) {
|
|
5
|
+
const { stripQuotes = false, indent = 0, nestingIndent = 2, quote = '"' } = options || {};
|
|
6
|
+
// Use JSON.stringify with the nesting indent
|
|
7
|
+
let result = JSON.stringify(obj, null, nestingIndent);
|
|
8
|
+
// Replace double quotes with single quotes for string values if requested
|
|
9
|
+
if (quote === "'") {
|
|
10
|
+
// First, escape any existing single quotes in string values
|
|
11
|
+
result = result.replace(/"([^"]*)"/g, (match, content) => {
|
|
12
|
+
// Check if this is a key (followed by colon) or a value
|
|
13
|
+
const matchIndex = result.indexOf(match);
|
|
14
|
+
const afterMatch = result.substring(matchIndex + match.length);
|
|
15
|
+
if (afterMatch.startsWith(':')) {
|
|
16
|
+
// This is a key, keep it for now
|
|
17
|
+
return match;
|
|
18
|
+
}
|
|
19
|
+
// This is a value, replace quotes and escape single quotes
|
|
20
|
+
const escaped = content.replace(/'/g, "\\'");
|
|
21
|
+
return `'${escaped}'`;
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
// Strip quotes from keys if requested
|
|
25
|
+
if (stripQuotes) {
|
|
26
|
+
// Remove quotes from keys that are valid JavaScript identifiers
|
|
27
|
+
// Keep quotes for keys with special characters (like 'x-foo', spaces, etc.)
|
|
28
|
+
const keyQuote = quote === "'" ? "'" : '"';
|
|
29
|
+
const pattern = new RegExp(`${keyQuote}([a-zA-Z_$][a-zA-Z0-9_$]*)${keyQuote}:`, 'g');
|
|
30
|
+
result = result.replace(pattern, '$1:');
|
|
31
|
+
}
|
|
32
|
+
// Apply base indentation if specified
|
|
33
|
+
if (indent > 0) {
|
|
34
|
+
const indentStr = ' '.repeat(indent);
|
|
35
|
+
result = result
|
|
36
|
+
.split('\n')
|
|
37
|
+
.map((line, i) => (i === 0 ? line : indentStr + line))
|
|
38
|
+
.join('\n');
|
|
39
|
+
}
|
|
40
|
+
return result;
|
|
41
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { type VovkSegmentSchema, type VovkController, type StaticClass } from '../types';
|
|
2
|
+
export declare function getControllerSchema(controller: VovkController, rpcModuleName: string, exposeValidation: boolean): Promise<{
|
|
3
|
+
rpcModuleName: string;
|
|
4
|
+
originalControllerName: string;
|
|
5
|
+
prefix: string;
|
|
6
|
+
handlers: {
|
|
7
|
+
[k: string]: {
|
|
8
|
+
path: string;
|
|
9
|
+
httpMethod: string;
|
|
10
|
+
operationObject?: import("../types").VovkOperationObject;
|
|
11
|
+
misc?: Record<string, import("../types").KnownAny>;
|
|
12
|
+
};
|
|
13
|
+
};
|
|
14
|
+
}>;
|
|
15
|
+
export default function getSchema(options: {
|
|
16
|
+
emitSchema?: boolean;
|
|
17
|
+
segmentName?: string;
|
|
18
|
+
controllers: Record<string, StaticClass>;
|
|
19
|
+
exposeValidation?: boolean;
|
|
20
|
+
forceApiRoot?: string;
|
|
21
|
+
}): Promise<VovkSegmentSchema>;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getControllerSchema = getControllerSchema;
|
|
4
|
+
exports.default = getSchema;
|
|
5
|
+
const types_1 = require("../types");
|
|
6
|
+
async function getControllerSchema(controller, rpcModuleName, exposeValidation) {
|
|
7
|
+
const handlers = exposeValidation
|
|
8
|
+
? (controller._handlers ?? {})
|
|
9
|
+
: Object.fromEntries(
|
|
10
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
11
|
+
Object.entries(controller._handlers ?? {}).map(([key, { validation: _v, ...value }]) => [key, value]));
|
|
12
|
+
return {
|
|
13
|
+
rpcModuleName,
|
|
14
|
+
originalControllerName: controller.name,
|
|
15
|
+
prefix: controller._prefix ?? '',
|
|
16
|
+
handlers,
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
async function getSchema(options) {
|
|
20
|
+
const exposeValidation = options?.exposeValidation ?? true;
|
|
21
|
+
const emitSchema = options.emitSchema ?? true;
|
|
22
|
+
const schema = {
|
|
23
|
+
$schema: types_1.VovkSchemaIdEnum.SEGMENT,
|
|
24
|
+
emitSchema,
|
|
25
|
+
segmentName: options.segmentName ?? '',
|
|
26
|
+
segmentType: 'segment',
|
|
27
|
+
controllers: {},
|
|
28
|
+
};
|
|
29
|
+
if (options.forceApiRoot) {
|
|
30
|
+
schema.forceApiRoot = options.forceApiRoot;
|
|
31
|
+
}
|
|
32
|
+
if (!emitSchema)
|
|
33
|
+
return schema;
|
|
34
|
+
for (const [rpcModuleName, controller] of Object.entries(options.controllers ?? {})) {
|
|
35
|
+
schema.controllers[rpcModuleName] = await getControllerSchema(controller, rpcModuleName, exposeValidation);
|
|
36
|
+
}
|
|
37
|
+
return schema;
|
|
38
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
type Override = {
|
|
2
|
+
from: string;
|
|
3
|
+
to: string;
|
|
4
|
+
};
|
|
5
|
+
type Config = {
|
|
6
|
+
requestUrl: string;
|
|
7
|
+
requestHost: string;
|
|
8
|
+
targetHost: string;
|
|
9
|
+
overrides: {
|
|
10
|
+
[key: string]: Override[];
|
|
11
|
+
};
|
|
12
|
+
};
|
|
13
|
+
export declare function multitenant(config: Config): {
|
|
14
|
+
action: null;
|
|
15
|
+
destination: null;
|
|
16
|
+
message: string;
|
|
17
|
+
subdomains: null;
|
|
18
|
+
} | {
|
|
19
|
+
action: string;
|
|
20
|
+
destination: string;
|
|
21
|
+
message: string;
|
|
22
|
+
subdomains: Record<string, string> | null;
|
|
23
|
+
};
|
|
24
|
+
export {};
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.multitenant = multitenant;
|
|
4
|
+
// Get the reserved paths from the overrides configuration
|
|
5
|
+
const getReservedPaths = (overrides) => {
|
|
6
|
+
return Object.keys(overrides).filter((key) => !key.includes('[') && !key.includes(']')); // Filter out dynamic paths
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* Convert a pattern with [placeholders] to a regex pattern and extract placeholder names
|
|
10
|
+
*/
|
|
11
|
+
const patternToRegex = (pattern) => {
|
|
12
|
+
const paramNames = [];
|
|
13
|
+
const regexPattern = pattern
|
|
14
|
+
.replace(/\[([^\]]+)\]/g, (_, name) => {
|
|
15
|
+
paramNames.push(name);
|
|
16
|
+
return '([^.]+)';
|
|
17
|
+
})
|
|
18
|
+
.replace(/\./g, '\\.'); // Escape dots in the pattern
|
|
19
|
+
return {
|
|
20
|
+
regex: new RegExp(`^${regexPattern}$`),
|
|
21
|
+
paramNames,
|
|
22
|
+
};
|
|
23
|
+
};
|
|
24
|
+
function multitenant(config) {
|
|
25
|
+
const { requestUrl, requestHost, targetHost, overrides } = config;
|
|
26
|
+
// Parse the URL
|
|
27
|
+
const urlObj = new URL(requestUrl);
|
|
28
|
+
const pathname = urlObj.pathname.slice(1); // Remove leading slash
|
|
29
|
+
// Skip processing for paths ending with "_schema_"
|
|
30
|
+
if (pathname.endsWith('_schema_')) {
|
|
31
|
+
return {
|
|
32
|
+
action: null,
|
|
33
|
+
destination: null,
|
|
34
|
+
message: 'Schema endpoint, bypassing overrides',
|
|
35
|
+
subdomains: null,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
const pathSegments = pathname.split('/').filter(Boolean);
|
|
39
|
+
// Get reserved paths
|
|
40
|
+
const reservedPaths = getReservedPaths(overrides);
|
|
41
|
+
// Check if any path segment matches a reserved path (e.g., "admin")
|
|
42
|
+
for (let i = 0; i < pathSegments.length; i++) {
|
|
43
|
+
const segment = pathSegments[i];
|
|
44
|
+
if (reservedPaths.includes(segment)) {
|
|
45
|
+
// Create the destination URL with the reserved path as subdomain
|
|
46
|
+
const destinationHost = `${segment}.${targetHost}`;
|
|
47
|
+
// Keep path segments before the reserved path
|
|
48
|
+
const beforeSegments = pathSegments.slice(0, i);
|
|
49
|
+
// Keep path segments after the reserved path
|
|
50
|
+
const afterSegments = pathSegments.slice(i + 1);
|
|
51
|
+
// Construct the new path
|
|
52
|
+
const newPath = [...beforeSegments, ...afterSegments].join('/');
|
|
53
|
+
const destinationUrl = new URL(`${urlObj.protocol}//${destinationHost}`);
|
|
54
|
+
if (newPath) {
|
|
55
|
+
destinationUrl.pathname = `/${newPath}`;
|
|
56
|
+
}
|
|
57
|
+
// Keep any query parameters
|
|
58
|
+
destinationUrl.search = urlObj.search;
|
|
59
|
+
return {
|
|
60
|
+
action: 'redirect',
|
|
61
|
+
destination: destinationUrl.toString(),
|
|
62
|
+
message: `Redirecting to ${segment} subdomain`,
|
|
63
|
+
subdomains: null, // No wildcards used
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
// Process based on host and subdomains
|
|
68
|
+
for (const pattern in overrides) {
|
|
69
|
+
const fullPattern = `${pattern}.${targetHost}`;
|
|
70
|
+
const { regex, paramNames } = patternToRegex(fullPattern);
|
|
71
|
+
const match = requestHost.match(regex);
|
|
72
|
+
if (match) {
|
|
73
|
+
const overrideRules = overrides[pattern];
|
|
74
|
+
// Extract parameters from the match
|
|
75
|
+
const params = {};
|
|
76
|
+
if (match.length > 1) {
|
|
77
|
+
for (let i = 0; i < paramNames.length; i++) {
|
|
78
|
+
params[paramNames[i]] = match[i + 1];
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
// Find the appropriate rule based on the path
|
|
82
|
+
for (const rule of overrideRules) {
|
|
83
|
+
if (pathname === rule.from || pathname.startsWith(`${rule.from}/`)) {
|
|
84
|
+
// Replace path with the destination
|
|
85
|
+
let destination = pathname.replace(rule.from, rule.to);
|
|
86
|
+
// Replace any dynamic parameters in destination
|
|
87
|
+
if (Object.keys(params).length > 0) {
|
|
88
|
+
Object.entries(params).forEach(([key, value]) => {
|
|
89
|
+
destination = destination.replace(`[${key}]`, value);
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
// Only return non-null subdomains if we have wildcard parameters
|
|
93
|
+
const wildcardSubdomains = paramNames.length > 0 ? params : null;
|
|
94
|
+
return {
|
|
95
|
+
action: 'rewrite',
|
|
96
|
+
destination: `${urlObj.protocol}//${urlObj.host}/${destination}${urlObj.search}`,
|
|
97
|
+
message: `Rewriting to ${destination}`,
|
|
98
|
+
subdomains: wildcardSubdomains,
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
// Handle cases where a customer subdomain tries to access reserved paths
|
|
105
|
+
if (pathSegments.length > 0 && reservedPaths.includes(pathSegments[0])) {
|
|
106
|
+
const reservedPath = pathSegments[0];
|
|
107
|
+
const restPath = pathSegments.slice(1).join('/');
|
|
108
|
+
// Create the destination URL with the reserved path as subdomain
|
|
109
|
+
const destinationHost = `${reservedPath}.${targetHost}`;
|
|
110
|
+
const destinationUrl = new URL(`${urlObj.protocol}//${destinationHost}`);
|
|
111
|
+
// Only add remaining path segments if they exist
|
|
112
|
+
if (restPath) {
|
|
113
|
+
destinationUrl.pathname = `/${restPath}`;
|
|
114
|
+
}
|
|
115
|
+
// Keep any query parameters
|
|
116
|
+
destinationUrl.search = urlObj.search;
|
|
117
|
+
return {
|
|
118
|
+
action: 'redirect',
|
|
119
|
+
destination: destinationUrl.toString(),
|
|
120
|
+
message: `Redirecting to ${reservedPath} subdomain`,
|
|
121
|
+
subdomains: null, // No wildcards used for reserved paths
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
// Default case - pass through
|
|
125
|
+
return {
|
|
126
|
+
action: null,
|
|
127
|
+
destination: null,
|
|
128
|
+
message: 'No action',
|
|
129
|
+
subdomains: null, // No wildcards matched
|
|
130
|
+
};
|
|
131
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { KnownAny } from '../types';
|
|
2
|
+
/**
|
|
3
|
+
* Deserialize a bracket-based query string into an object.
|
|
4
|
+
*
|
|
5
|
+
* Supports:
|
|
6
|
+
* - Key/value pairs with nested brackets (e.g. "a[b][0]=value")
|
|
7
|
+
* - Arrays with empty bracket (e.g. "arr[]=1&arr[]=2")
|
|
8
|
+
* - Mixed arrays of objects, etc.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* parseQuery("x=xx&y[0]=yy&y[1]=uu&z[f]=x&z[u][0]=uu&z[u][1]=xx&z[d][x]=ee")
|
|
12
|
+
* => {
|
|
13
|
+
* x: "xx",
|
|
14
|
+
* y: ["yy", "uu"],
|
|
15
|
+
* z: {
|
|
16
|
+
* f: "x",
|
|
17
|
+
* u: ["uu", "xx"],
|
|
18
|
+
* d: { x: "ee" }
|
|
19
|
+
* }
|
|
20
|
+
* }
|
|
21
|
+
*
|
|
22
|
+
* @param queryString - The raw query string (e.g. location.search.slice(1))
|
|
23
|
+
* @returns - A nested object representing the query params
|
|
24
|
+
*/
|
|
25
|
+
export default function parseQuery(queryString: string): Record<string, KnownAny>;
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.default = parseQuery;
|
|
4
|
+
/**
|
|
5
|
+
* Parse a bracket-based key (e.g. "z[d][0][x]" or "arr[]")
|
|
6
|
+
* into an array of path segments (strings or special push-markers).
|
|
7
|
+
*
|
|
8
|
+
* Example: "z[d][0][x]" => ["z", "d", "0", "x"]
|
|
9
|
+
* Example: "arr[]" => ["arr", "" ] // "" indicates "push" onto array
|
|
10
|
+
*/
|
|
11
|
+
function parseKey(key) {
|
|
12
|
+
// The first segment is everything up to the first '[' (or the entire key if no '[')
|
|
13
|
+
const segments = [];
|
|
14
|
+
const topKeyMatch = key.match(/^([^[\]]+)/);
|
|
15
|
+
if (topKeyMatch) {
|
|
16
|
+
segments.push(topKeyMatch[1]);
|
|
17
|
+
}
|
|
18
|
+
else {
|
|
19
|
+
// If it starts with brackets, treat it as empty? (edge case)
|
|
20
|
+
segments.push('');
|
|
21
|
+
}
|
|
22
|
+
// Now capture all bracket parts: [something], [0], []
|
|
23
|
+
const bracketRegex = /\[([^[\]]*)\]/g;
|
|
24
|
+
let match;
|
|
25
|
+
while ((match = bracketRegex.exec(key)) !== null) {
|
|
26
|
+
// match[1] is the content inside the brackets
|
|
27
|
+
segments.push(match[1]);
|
|
28
|
+
}
|
|
29
|
+
return segments;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Recursively set a value in a nested object/array, given a path of segments.
|
|
33
|
+
* - If segment is numeric => treat as array index
|
|
34
|
+
* - If segment is empty "" => push to array
|
|
35
|
+
* - Else => object property
|
|
36
|
+
*/
|
|
37
|
+
function setValue(obj, path, value) {
|
|
38
|
+
let current = obj;
|
|
39
|
+
for (let i = 0; i < path.length; i++) {
|
|
40
|
+
const segment = path[i];
|
|
41
|
+
// If we're at the last segment, set the value
|
|
42
|
+
if (i === path.length - 1) {
|
|
43
|
+
if (segment === '') {
|
|
44
|
+
// Empty bracket => push
|
|
45
|
+
if (!Array.isArray(current)) {
|
|
46
|
+
current = [];
|
|
47
|
+
}
|
|
48
|
+
current.push(value);
|
|
49
|
+
}
|
|
50
|
+
else if (!isNaN(Number(segment))) {
|
|
51
|
+
// Numeric segment => array index
|
|
52
|
+
const idx = Number(segment);
|
|
53
|
+
if (!Array.isArray(current)) {
|
|
54
|
+
current = [];
|
|
55
|
+
}
|
|
56
|
+
current[idx] = value;
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
// Object property
|
|
60
|
+
current[segment] = value;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
// Not the last segment: descend into existing structure or create it
|
|
65
|
+
const nextSegment = path[i + 1];
|
|
66
|
+
if (segment === '') {
|
|
67
|
+
// Empty bracket => push
|
|
68
|
+
if (!Array.isArray(current)) {
|
|
69
|
+
// Convert the current node into an array, if not one
|
|
70
|
+
current = [];
|
|
71
|
+
}
|
|
72
|
+
// If we are not at the last path, we need a placeholder object or array
|
|
73
|
+
// for the next segment. We'll push something and move current to that.
|
|
74
|
+
if (current.length === 0) {
|
|
75
|
+
// nothing in array yet
|
|
76
|
+
current.push(typeof nextSegment === 'string' && !isNaN(Number(nextSegment)) ? [] : {});
|
|
77
|
+
}
|
|
78
|
+
else if (typeof nextSegment === 'string' && !isNaN(Number(nextSegment))) {
|
|
79
|
+
// next is numeric => we want an array
|
|
80
|
+
if (!Array.isArray(current[current.length - 1])) {
|
|
81
|
+
current[current.length - 1] = [];
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
// next is not numeric => we want an object
|
|
86
|
+
if (typeof current[current.length - 1] !== 'object') {
|
|
87
|
+
current[current.length - 1] = {};
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
current = current[current.length - 1];
|
|
91
|
+
}
|
|
92
|
+
else if (!isNaN(Number(segment))) {
|
|
93
|
+
// segment is numeric => array index
|
|
94
|
+
const idx = Number(segment);
|
|
95
|
+
if (!Array.isArray(current)) {
|
|
96
|
+
current = [];
|
|
97
|
+
}
|
|
98
|
+
if (current[idx] === undefined) {
|
|
99
|
+
// Create placeholder for next segment
|
|
100
|
+
current[idx] = typeof nextSegment === 'string' && !isNaN(Number(nextSegment)) ? [] : {};
|
|
101
|
+
}
|
|
102
|
+
current = current[idx];
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
// segment is an object key
|
|
106
|
+
if (current[segment] === undefined) {
|
|
107
|
+
// Create placeholder
|
|
108
|
+
current[segment] = typeof nextSegment === 'string' && !isNaN(Number(nextSegment)) ? [] : {};
|
|
109
|
+
}
|
|
110
|
+
current = current[segment];
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Deserialize a bracket-based query string into an object.
|
|
117
|
+
*
|
|
118
|
+
* Supports:
|
|
119
|
+
* - Key/value pairs with nested brackets (e.g. "a[b][0]=value")
|
|
120
|
+
* - Arrays with empty bracket (e.g. "arr[]=1&arr[]=2")
|
|
121
|
+
* - Mixed arrays of objects, etc.
|
|
122
|
+
*
|
|
123
|
+
* @example
|
|
124
|
+
* parseQuery("x=xx&y[0]=yy&y[1]=uu&z[f]=x&z[u][0]=uu&z[u][1]=xx&z[d][x]=ee")
|
|
125
|
+
* => {
|
|
126
|
+
* x: "xx",
|
|
127
|
+
* y: ["yy", "uu"],
|
|
128
|
+
* z: {
|
|
129
|
+
* f: "x",
|
|
130
|
+
* u: ["uu", "xx"],
|
|
131
|
+
* d: { x: "ee" }
|
|
132
|
+
* }
|
|
133
|
+
* }
|
|
134
|
+
*
|
|
135
|
+
* @param queryString - The raw query string (e.g. location.search.slice(1))
|
|
136
|
+
* @returns - A nested object representing the query params
|
|
137
|
+
*/
|
|
138
|
+
function parseQuery(queryString) {
|
|
139
|
+
const result = {};
|
|
140
|
+
if (!queryString)
|
|
141
|
+
return result;
|
|
142
|
+
// Split into key=value pairs
|
|
143
|
+
const pairs = queryString
|
|
144
|
+
.replace(/^\?/, '') // Remove leading "?" if present
|
|
145
|
+
.split('&');
|
|
146
|
+
for (const pair of pairs) {
|
|
147
|
+
const [rawKey, rawVal = ''] = pair.split('=');
|
|
148
|
+
const decodedKey = decodeURIComponent(rawKey);
|
|
149
|
+
const decodedVal = decodeURIComponent(rawVal);
|
|
150
|
+
// Parse bracket notation
|
|
151
|
+
const pathSegments = parseKey(decodedKey);
|
|
152
|
+
// Insert into the result object
|
|
153
|
+
setValue(result, pathSegments, decodedVal);
|
|
154
|
+
}
|
|
155
|
+
return result;
|
|
156
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.default = reqForm;
|
|
4
|
+
const formMap = new WeakMap();
|
|
5
|
+
async function reqForm(req) {
|
|
6
|
+
if (formMap.has(req)) {
|
|
7
|
+
return formMap.get(req);
|
|
8
|
+
}
|
|
9
|
+
const body = await req.formData();
|
|
10
|
+
req.formData = () => Promise.resolve(body);
|
|
11
|
+
const formData = {};
|
|
12
|
+
for (const [key, value] of body.entries()) {
|
|
13
|
+
if (value instanceof File) {
|
|
14
|
+
// If this key already exists, convert to array or append to existing array
|
|
15
|
+
if (formData[key]) {
|
|
16
|
+
if (Array.isArray(formData[key])) {
|
|
17
|
+
formData[key].push(value);
|
|
18
|
+
}
|
|
19
|
+
else {
|
|
20
|
+
formData[key] = [formData[key], value];
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
formData[key] = value;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
formData[key] = value.toString();
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
formMap.set(req, formData);
|
|
32
|
+
return formData;
|
|
33
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.default = reqQuery;
|
|
7
|
+
const parseQuery_1 = __importDefault(require("./parseQuery"));
|
|
8
|
+
function reqQuery(req) {
|
|
9
|
+
return (0, parseQuery_1.default)(req.nextUrl.search);
|
|
10
|
+
}
|