oc 0.50.60 → 0.50.62
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/.turbo/turbo-build.log +5 -5
- package/.turbo/turbo-lint.log +2 -2
- package/.turbo/turbo-test-silent.log +12 -11
- package/.turbo/turbo-test.log +1806 -1750
- package/CHANGELOG.md +13 -0
- package/README.md +16 -0
- package/dist/cli/domain/local.js +7 -4
- package/dist/components/oc-client/_package/package.json +4 -4
- package/dist/components/oc-client/_package/server.js +1 -1
- package/dist/components/oc-client/package.json +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/registry/domain/events-handler.d.ts +2 -5
- package/dist/registry/domain/http-server/express-adapter.d.ts +2 -2
- package/dist/registry/domain/http-server/express-adapter.js +47 -2
- package/dist/registry/domain/http-server/types.d.ts +21 -7
- package/dist/registry/domain/options-sanitiser.d.ts +8 -2
- package/dist/registry/domain/options-sanitiser.js +2 -0
- package/dist/registry/domain/plugins-initialiser.js +41 -5
- package/dist/registry/domain/repository.js +100 -19
- package/dist/registry/domain/validators/registry-configuration.d.ts +5 -2
- package/dist/registry/domain/validators/registry-configuration.js +5 -0
- package/dist/registry/index.d.ts +11 -6
- package/dist/registry/index.js +107 -28
- package/dist/registry/middleware/cors.d.ts +4 -0
- package/dist/registry/middleware/cors.js +62 -4
- package/dist/registry/router.js +4 -2
- package/dist/registry/routes/component-info.js +3 -2
- package/dist/registry/routes/component-preview.js +3 -2
- package/dist/registry/routes/component.d.ts +2 -1
- package/dist/registry/routes/component.js +1 -2
- package/dist/registry/routes/components.d.ts +2 -1
- package/dist/registry/routes/components.js +1 -2
- package/dist/registry/routes/helpers/get-component.d.ts +2 -1
- package/dist/registry/routes/helpers/get-component.js +7 -8
- package/dist/registry/routes/index.js +11 -7
- package/dist/resources/index.d.ts +5 -1
- package/dist/resources/index.js +5 -1
- package/dist/types.d.ts +34 -5
- package/dist/utils/bounded-cache.d.ts +10 -0
- package/dist/utils/bounded-cache.js +31 -0
- package/js-library-optimization-playbook.md +1379 -0
- package/package.json +4 -3
- package/tsconfig.types.json +10 -0
package/dist/registry/index.js
CHANGED
|
@@ -38,6 +38,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
38
38
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
39
|
exports.default = registry;
|
|
40
40
|
const colors_1 = __importDefault(require("../utils/colors"));
|
|
41
|
+
const deprecate_1 = __importDefault(require("../utils/deprecate"));
|
|
41
42
|
const app_start_1 = __importDefault(require("./app-start"));
|
|
42
43
|
const events_handler_1 = __importDefault(require("./domain/events-handler"));
|
|
43
44
|
const options_sanitiser_1 = __importDefault(require("./domain/options-sanitiser"));
|
|
@@ -47,6 +48,20 @@ const server_adapter_1 = __importDefault(require("./domain/server-adapter"));
|
|
|
47
48
|
const validator = __importStar(require("./domain/validators"));
|
|
48
49
|
const middleware = __importStar(require("./middleware"));
|
|
49
50
|
const router_1 = require("./router");
|
|
51
|
+
const SERVER_ERROR_CODE = 'SERVER_ERROR';
|
|
52
|
+
const warnAboutCallback = () => (0, deprecate_1.default)({
|
|
53
|
+
id: 'registry-lifecycle-callbacks',
|
|
54
|
+
subject: 'Registry lifecycle callbacks',
|
|
55
|
+
replacement: 'the returned promises'
|
|
56
|
+
});
|
|
57
|
+
const toError = (error) => {
|
|
58
|
+
if (error instanceof Error) {
|
|
59
|
+
return error;
|
|
60
|
+
}
|
|
61
|
+
const errorLike = error;
|
|
62
|
+
const message = errorLike?.message ?? errorLike?.msg ?? error;
|
|
63
|
+
return new Error(String(message));
|
|
64
|
+
};
|
|
50
65
|
function registry(inputOptions) {
|
|
51
66
|
const validationResult = validator.validateRegistryConfiguration(inputOptions);
|
|
52
67
|
if (!validationResult.isValid) {
|
|
@@ -57,56 +72,120 @@ function registry(inputOptions) {
|
|
|
57
72
|
const adapter = middleware.bind((0, server_adapter_1.default)(options.server.adapter, options.server.options), options);
|
|
58
73
|
const app = adapter.native();
|
|
59
74
|
const repository = (0, repository_1.default)(options);
|
|
60
|
-
const
|
|
61
|
-
|
|
62
|
-
|
|
75
|
+
const listenAdapter = (serverOptions) => {
|
|
76
|
+
if (adapter.supportsPromiseLifecycle) {
|
|
77
|
+
return adapter.listen(serverOptions);
|
|
78
|
+
}
|
|
79
|
+
return new Promise((resolve, reject) => {
|
|
80
|
+
adapter.listen(serverOptions, (err) => {
|
|
81
|
+
if (err) {
|
|
82
|
+
reject(err);
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
resolve();
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
};
|
|
90
|
+
const closeAdapter = () => {
|
|
91
|
+
if (adapter.supportsPromiseLifecycle) {
|
|
92
|
+
return adapter.close();
|
|
93
|
+
}
|
|
94
|
+
return new Promise((resolve, reject) => {
|
|
63
95
|
adapter.close((err) => {
|
|
64
|
-
|
|
96
|
+
if (err) {
|
|
97
|
+
reject(err);
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
resolve();
|
|
101
|
+
}
|
|
65
102
|
});
|
|
66
|
-
|
|
103
|
+
});
|
|
104
|
+
};
|
|
105
|
+
const closePromise = () => {
|
|
106
|
+
const closeMetadataStore = () => Promise.resolve(repository.close?.()).catch(() => undefined);
|
|
107
|
+
const closeServer = new Promise((resolve, reject) => {
|
|
108
|
+
if (!adapter.isListening()) {
|
|
109
|
+
reject('not opened');
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
closeAdapter().then(resolve, reject);
|
|
113
|
+
});
|
|
114
|
+
return closeServer.finally(closeMetadataStore);
|
|
115
|
+
};
|
|
116
|
+
const close = (callback) => {
|
|
117
|
+
const promise = closePromise();
|
|
118
|
+
if (!callback) {
|
|
119
|
+
return promise;
|
|
67
120
|
}
|
|
68
|
-
|
|
121
|
+
warnAboutCallback();
|
|
122
|
+
const callbackPromise = promise.then(() => callback(), (error) => {
|
|
123
|
+
callback(error);
|
|
124
|
+
throw error;
|
|
125
|
+
});
|
|
126
|
+
void callbackPromise.catch(() => undefined);
|
|
127
|
+
return callbackPromise;
|
|
69
128
|
};
|
|
70
129
|
const register = (plugin, callback) => {
|
|
130
|
+
if (callback) {
|
|
131
|
+
warnAboutCallback();
|
|
132
|
+
}
|
|
71
133
|
plugins.push(Object.assign(plugin, { callback }));
|
|
134
|
+
return Promise.resolve();
|
|
72
135
|
};
|
|
73
|
-
const
|
|
136
|
+
const startPromise = async () => {
|
|
74
137
|
const ok = (msg) => console.log(colors_1.default.green(msg));
|
|
75
138
|
try {
|
|
76
139
|
options.plugins = await pluginsInitialiser.init(plugins);
|
|
77
140
|
(0, router_1.create)(adapter, options, repository);
|
|
78
141
|
const componentsInfo = await repository.init();
|
|
79
142
|
await (0, app_start_1.default)(repository, options);
|
|
80
|
-
|
|
143
|
+
const listenPromise = listenAdapter({
|
|
81
144
|
port: options.port,
|
|
82
145
|
timeout: options.timeout,
|
|
83
146
|
keepAliveTimeout: options.keepAliveTimeout
|
|
84
|
-
}, (err) => {
|
|
85
|
-
if (err) {
|
|
86
|
-
return callback(err);
|
|
87
|
-
}
|
|
88
|
-
events_handler_1.default.fire('start', {});
|
|
89
|
-
if (options.verbosity) {
|
|
90
|
-
ok(`Registry started at port http://localhost:${options.port}${options.prefix}`);
|
|
91
|
-
if (componentsInfo) {
|
|
92
|
-
const componentsNumber = Object.keys(componentsInfo.components).length;
|
|
93
|
-
const componentsReleases = Object.values(componentsInfo.components).reduce((acc, component) => acc + Object.keys(component).length, 0);
|
|
94
|
-
ok(`Registry serving ${componentsNumber} components for a total of ${componentsReleases} releases.`);
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
callback(null, { app, server: adapter.httpServer() });
|
|
98
147
|
});
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
148
|
+
const serverError = new Promise((_resolve, reject) => {
|
|
149
|
+
adapter.onServerError((error) => {
|
|
150
|
+
events_handler_1.default.fire('error', {
|
|
151
|
+
code: SERVER_ERROR_CODE,
|
|
152
|
+
message: error?.message ?? String(error)
|
|
153
|
+
});
|
|
154
|
+
reject(toError(error));
|
|
103
155
|
});
|
|
104
|
-
callback(error);
|
|
105
156
|
});
|
|
157
|
+
void serverError.catch(() => undefined);
|
|
158
|
+
await Promise.race([listenPromise, serverError]);
|
|
159
|
+
events_handler_1.default.fire('start', {});
|
|
160
|
+
if (options.verbosity) {
|
|
161
|
+
ok(`Registry started at port http://localhost:${options.port}${options.prefix}`);
|
|
162
|
+
if (componentsInfo) {
|
|
163
|
+
const componentsNumber = Object.keys(componentsInfo.components).length;
|
|
164
|
+
const componentsReleases = Object.values(componentsInfo.components).reduce((acc, component) => acc + Object.keys(component).length, 0);
|
|
165
|
+
ok(`Registry serving ${componentsNumber} components for a total of ${componentsReleases} releases.`);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
return { app, server: adapter.httpServer() };
|
|
106
169
|
}
|
|
107
170
|
catch (err) {
|
|
108
|
-
|
|
171
|
+
throw toError(err);
|
|
172
|
+
}
|
|
173
|
+
};
|
|
174
|
+
const start = (callback) => {
|
|
175
|
+
const promise = startPromise();
|
|
176
|
+
if (!callback) {
|
|
177
|
+
return promise;
|
|
109
178
|
}
|
|
179
|
+
warnAboutCallback();
|
|
180
|
+
const callbackPromise = promise.then((result) => {
|
|
181
|
+
callback(null, result);
|
|
182
|
+
return result;
|
|
183
|
+
}, (error) => {
|
|
184
|
+
callback(error);
|
|
185
|
+
throw error;
|
|
186
|
+
});
|
|
187
|
+
void callbackPromise.catch(() => undefined);
|
|
188
|
+
return callbackPromise;
|
|
110
189
|
};
|
|
111
190
|
return {
|
|
112
191
|
close,
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
import type { CorsConfig, CorsOptions } from '../../types';
|
|
1
2
|
import type { OcHandler } from '../domain/http-server/types';
|
|
3
|
+
export declare const DEFAULT_CORS_CONFIG: CorsConfig;
|
|
4
|
+
export declare const normaliseCorsConfig: (options?: CorsOptions | null) => CorsConfig;
|
|
5
|
+
export declare const validateCorsConfig: (options: unknown) => string | undefined;
|
|
2
6
|
declare const cors: OcHandler;
|
|
3
7
|
export default cors;
|
|
@@ -1,10 +1,68 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
2
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.validateCorsConfig = exports.normaliseCorsConfig = exports.DEFAULT_CORS_CONFIG = void 0;
|
|
7
|
+
const resources_1 = __importDefault(require("../../resources"));
|
|
8
|
+
exports.DEFAULT_CORS_CONFIG = {
|
|
9
|
+
origin: '*',
|
|
10
|
+
credentials: true,
|
|
11
|
+
allowedHeaders: 'Origin, X-Requested-With, Content-Type, Accept, traceparent',
|
|
12
|
+
methods: 'GET, OPTIONS, PUT, POST'
|
|
13
|
+
};
|
|
14
|
+
const asHeaderValue = (value, fallback) => (Array.isArray(value) ? value.join(', ') : (value ?? fallback));
|
|
15
|
+
const normaliseCorsConfig = (options) => ({
|
|
16
|
+
origin: options?.origin ?? exports.DEFAULT_CORS_CONFIG.origin,
|
|
17
|
+
credentials: options?.credentials ?? exports.DEFAULT_CORS_CONFIG.credentials,
|
|
18
|
+
allowedHeaders: asHeaderValue(options?.allowedHeaders, exports.DEFAULT_CORS_CONFIG.allowedHeaders),
|
|
19
|
+
methods: asHeaderValue(options?.methods, exports.DEFAULT_CORS_CONFIG.methods)
|
|
20
|
+
});
|
|
21
|
+
exports.normaliseCorsConfig = normaliseCorsConfig;
|
|
22
|
+
const isStringArray = (value) => Array.isArray(value) && value.every((item) => typeof item === 'string');
|
|
23
|
+
const validateCorsConfig = (options) => {
|
|
24
|
+
if (typeof options === 'undefined') {
|
|
25
|
+
return undefined;
|
|
26
|
+
}
|
|
27
|
+
if (options === null ||
|
|
28
|
+
typeof options !== 'object' ||
|
|
29
|
+
Array.isArray(options)) {
|
|
30
|
+
return resources_1.default.errors.registry.CONFIGURATION_CORS_MUST_BE_OBJECT;
|
|
31
|
+
}
|
|
32
|
+
const config = options;
|
|
33
|
+
if (typeof config.origin !== 'undefined' &&
|
|
34
|
+
(typeof config.origin !== 'string' || config.origin.length === 0)) {
|
|
35
|
+
return resources_1.default.errors.registry.CONFIGURATION_CORS_ORIGIN_MUST_BE_STRING;
|
|
36
|
+
}
|
|
37
|
+
if (typeof config.credentials !== 'undefined' &&
|
|
38
|
+
typeof config.credentials !== 'boolean') {
|
|
39
|
+
return resources_1.default.errors.registry
|
|
40
|
+
.CONFIGURATION_CORS_CREDENTIALS_MUST_BE_BOOLEAN;
|
|
41
|
+
}
|
|
42
|
+
if (typeof config.allowedHeaders !== 'undefined' &&
|
|
43
|
+
typeof config.allowedHeaders !== 'string' &&
|
|
44
|
+
!isStringArray(config.allowedHeaders)) {
|
|
45
|
+
return resources_1.default.errors.registry
|
|
46
|
+
.CONFIGURATION_CORS_ALLOWED_HEADERS_MUST_BE_STRING_ARRAY;
|
|
47
|
+
}
|
|
48
|
+
if (typeof config.methods !== 'undefined' &&
|
|
49
|
+
typeof config.methods !== 'string' &&
|
|
50
|
+
!isStringArray(config.methods)) {
|
|
51
|
+
return resources_1.default.errors.registry
|
|
52
|
+
.CONFIGURATION_CORS_METHODS_MUST_BE_STRING_ARRAY;
|
|
53
|
+
}
|
|
54
|
+
return undefined;
|
|
55
|
+
};
|
|
56
|
+
exports.validateCorsConfig = validateCorsConfig;
|
|
3
57
|
const cors = (_req, res) => {
|
|
58
|
+
const options = (0, exports.normaliseCorsConfig)(res.conf?.cors);
|
|
4
59
|
res.removeHeader('X-Powered-By');
|
|
5
|
-
res.
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
60
|
+
res.removeHeader('Access-Control-Allow-Credentials');
|
|
61
|
+
if (options.credentials) {
|
|
62
|
+
res.set('Access-Control-Allow-Credentials', 'true');
|
|
63
|
+
}
|
|
64
|
+
res.set('Access-Control-Allow-Origin', options.origin);
|
|
65
|
+
res.set('Access-Control-Allow-Headers', options.allowedHeaders);
|
|
66
|
+
res.set('Access-Control-Allow-Methods', options.methods);
|
|
9
67
|
};
|
|
10
68
|
exports.default = cors;
|
package/dist/registry/router.js
CHANGED
|
@@ -11,6 +11,7 @@ const component_info_1 = __importDefault(require("./routes/component-info"));
|
|
|
11
11
|
const component_preview_1 = __importDefault(require("./routes/component-preview"));
|
|
12
12
|
const components_1 = __importDefault(require("./routes/components"));
|
|
13
13
|
const dependencies_1 = __importDefault(require("./routes/dependencies"));
|
|
14
|
+
const get_component_1 = __importDefault(require("./routes/helpers/get-component"));
|
|
14
15
|
const history_1 = __importDefault(require("./routes/history"));
|
|
15
16
|
const plugins_1 = __importDefault(require("./routes/plugins"));
|
|
16
17
|
const publish_1 = __importDefault(require("./routes/publish"));
|
|
@@ -18,9 +19,10 @@ const static_redirector_1 = __importDefault(require("./routes/static-redirector"
|
|
|
18
19
|
const validate_1 = __importDefault(require("./routes/validate"));
|
|
19
20
|
function create(adapter, conf, repository) {
|
|
20
21
|
const route = (method, path, id, ...handlers) => adapter.route(method, path, id, handlers);
|
|
22
|
+
const renderComponent = (0, get_component_1.default)(conf, repository);
|
|
21
23
|
const routes = {
|
|
22
|
-
component: (0, component_1.default)(conf, repository),
|
|
23
|
-
components: (0, components_1.default)(conf, repository),
|
|
24
|
+
component: (0, component_1.default)(conf, repository, renderComponent),
|
|
25
|
+
components: (0, components_1.default)(conf, repository, renderComponent),
|
|
24
26
|
componentInfo: (0, component_info_1.default)(conf, repository),
|
|
25
27
|
componentPreview: (0, component_preview_1.default)(conf, repository),
|
|
26
28
|
index: (0, routes_1.default)(repository),
|
|
@@ -100,9 +100,10 @@ function componentInfo(err, req, res, component, componentDetail) {
|
|
|
100
100
|
});
|
|
101
101
|
}
|
|
102
102
|
else if (res.conf.discovery.api) {
|
|
103
|
-
res.status(200).json(
|
|
103
|
+
res.status(200).json({
|
|
104
|
+
...component,
|
|
104
105
|
requestVersion: req.params['componentVersion'] || ''
|
|
105
|
-
})
|
|
106
|
+
});
|
|
106
107
|
}
|
|
107
108
|
else {
|
|
108
109
|
res.status(401);
|
|
@@ -71,9 +71,10 @@ function componentPreview(err, req, res, component, templates) {
|
|
|
71
71
|
}));
|
|
72
72
|
}
|
|
73
73
|
else {
|
|
74
|
-
res.status(200).json(
|
|
74
|
+
res.status(200).json({
|
|
75
|
+
...component,
|
|
75
76
|
requestVersion: req.params['componentVersion'] || ''
|
|
76
|
-
})
|
|
77
|
+
});
|
|
77
78
|
}
|
|
78
79
|
}
|
|
79
80
|
function componentPreviewRoute(conf, repository) {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { Config } from '../../types';
|
|
2
2
|
import type { OcHandler } from '../domain/http-server/types';
|
|
3
3
|
import type { Repository } from '../domain/repository';
|
|
4
|
-
|
|
4
|
+
import { type RenderComponent } from './helpers/get-component';
|
|
5
|
+
export default function component(conf: Config, repository: Repository, getComponent?: RenderComponent): OcHandler;
|
|
@@ -42,8 +42,7 @@ const turbo_stream_1 = require("@rdevis/turbo-stream");
|
|
|
42
42
|
const serialize_error_1 = require("serialize-error");
|
|
43
43
|
const resources_1 = __importDefault(require("../../resources"));
|
|
44
44
|
const get_component_1 = __importStar(require("./helpers/get-component"));
|
|
45
|
-
function component(conf, repository) {
|
|
46
|
-
const getComponent = (0, get_component_1.default)(conf, repository);
|
|
45
|
+
function component(conf, repository, getComponent = (0, get_component_1.default)(conf, repository)) {
|
|
47
46
|
return (req, res) => {
|
|
48
47
|
let parameters = req.query;
|
|
49
48
|
if (req.method === 'POST') {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { Config } from '../../types';
|
|
2
2
|
import type { OcHandler } from '../domain/http-server/types';
|
|
3
3
|
import type { Repository } from '../domain/repository';
|
|
4
|
-
|
|
4
|
+
import { type RenderComponent } from './helpers/get-component';
|
|
5
|
+
export default function components(conf: Config, repository: Repository, getComponent?: RenderComponent): OcHandler;
|
|
@@ -7,8 +7,7 @@ exports.default = components;
|
|
|
7
7
|
const resources_1 = __importDefault(require("../../resources"));
|
|
8
8
|
const pLimit_1 = __importDefault(require("../../utils/pLimit"));
|
|
9
9
|
const get_component_1 = __importDefault(require("./helpers/get-component"));
|
|
10
|
-
function components(conf, repository) {
|
|
11
|
-
const getComponent = (0, get_component_1.default)(conf, repository);
|
|
10
|
+
function components(conf, repository, getComponent = (0, get_component_1.default)(conf, repository)) {
|
|
12
11
|
const setHeaders = (results, res) => {
|
|
13
12
|
if (results?.length !== 1 || !results[0] || !res.set) {
|
|
14
13
|
return;
|
|
@@ -39,5 +39,6 @@ export interface GetComponentResult {
|
|
|
39
39
|
missingDependencies?: string[];
|
|
40
40
|
};
|
|
41
41
|
}
|
|
42
|
+
export type RenderComponent = (options: RendererOptions, cb: (result: GetComponentResult) => void) => void;
|
|
42
43
|
export declare const stream: unique symbol;
|
|
43
|
-
export default function getComponent(conf: Config, repository: Repository):
|
|
44
|
+
export default function getComponent(conf: Config, repository: Repository): RenderComponent;
|
|
@@ -42,12 +42,12 @@ const node_crypto_1 = require("node:crypto");
|
|
|
42
42
|
const node_domain_1 = __importDefault(require("node:domain"));
|
|
43
43
|
const node_vm_1 = __importDefault(require("node:vm"));
|
|
44
44
|
const accept_language_parser_1 = __importDefault(require("accept-language-parser"));
|
|
45
|
-
const nice_cache_1 = __importDefault(require("nice-cache"));
|
|
46
45
|
const oc_client_1 = __importDefault(require("oc-client"));
|
|
47
46
|
const oc_empty_response_handler_1 = __importDefault(require("oc-empty-response-handler"));
|
|
48
47
|
const universalify_1 = require("universalify");
|
|
49
48
|
const resources_1 = __importDefault(require("../../../resources"));
|
|
50
49
|
const settings_1 = __importDefault(require("../../../resources/settings"));
|
|
50
|
+
const bounded_cache_1 = __importDefault(require("../../../utils/bounded-cache"));
|
|
51
51
|
const is_template_legacy_1 = __importDefault(require("../../../utils/is-template-legacy"));
|
|
52
52
|
const events_handler_1 = __importDefault(require("../../domain/events-handler"));
|
|
53
53
|
const nested_renderer_1 = __importDefault(require("../../domain/nested-renderer"));
|
|
@@ -61,6 +61,7 @@ const format_error_stack_1 = require("./format-error-stack");
|
|
|
61
61
|
const getComponentFallback = __importStar(require("./get-component-fallback"));
|
|
62
62
|
const get_component_retrieving_info_1 = __importDefault(require("./get-component-retrieving-info"));
|
|
63
63
|
exports.stream = Symbol('stream');
|
|
64
|
+
const MAX_ARTIFACT_CACHE_ENTRIES = 1000;
|
|
64
65
|
const noop = () => { };
|
|
65
66
|
const noopConsole = Object.fromEntries(Object.keys(console).map((key) => [key, noop]));
|
|
66
67
|
const parseTemplatesHeader = (templates) => {
|
|
@@ -118,10 +119,7 @@ function pluginConverter(plugins = {}) {
|
|
|
118
119
|
}
|
|
119
120
|
function getComponent(conf, repository) {
|
|
120
121
|
const client = (0, oc_client_1.default)({ templates: conf.templates });
|
|
121
|
-
const cache = new
|
|
122
|
-
verbose: !!conf.verbosity,
|
|
123
|
-
refreshInterval: conf.refreshInterval
|
|
124
|
-
});
|
|
122
|
+
const cache = new bounded_cache_1.default(MAX_ARTIFACT_CACHE_ENTRIES);
|
|
125
123
|
const convertPlugins = pluginConverter(conf.plugins);
|
|
126
124
|
const customHeadersByConfig = new WeakMap();
|
|
127
125
|
const pluginNamesByConfig = new WeakMap();
|
|
@@ -156,7 +154,7 @@ function getComponent(conf, repository) {
|
|
|
156
154
|
const getEnv = async (component) => {
|
|
157
155
|
const cacheKey = `${component.name}/${component.version}/.env`;
|
|
158
156
|
const cached = cache.get('file-contents', cacheKey);
|
|
159
|
-
if (cached)
|
|
157
|
+
if (cached !== undefined)
|
|
160
158
|
return cached;
|
|
161
159
|
return singleFlight(cacheKey, async () => {
|
|
162
160
|
const env = component.oc.files.env
|
|
@@ -437,7 +435,7 @@ function getComponent(conf, repository) {
|
|
|
437
435
|
});
|
|
438
436
|
});
|
|
439
437
|
};
|
|
440
|
-
if (cached && !conf.hotReloading) {
|
|
438
|
+
if (cached !== undefined && !conf.hotReloading) {
|
|
441
439
|
returnResult(cached);
|
|
442
440
|
}
|
|
443
441
|
else {
|
|
@@ -538,7 +536,7 @@ function getComponent(conf, repository) {
|
|
|
538
536
|
}, executionTimeout * 1000);
|
|
539
537
|
}
|
|
540
538
|
};
|
|
541
|
-
if (cached && !conf.hotReloading) {
|
|
539
|
+
if (cached !== undefined && !conf.hotReloading) {
|
|
542
540
|
domain.on('error', returnComponent);
|
|
543
541
|
try {
|
|
544
542
|
domain.run(() => {
|
|
@@ -589,6 +587,7 @@ function getComponent(conf, repository) {
|
|
|
589
587
|
exports: {},
|
|
590
588
|
console: conf.local ? console : noopConsole,
|
|
591
589
|
setTimeout,
|
|
590
|
+
clearTimeout,
|
|
592
591
|
Buffer,
|
|
593
592
|
Error,
|
|
594
593
|
AbortController: globalThis?.AbortController,
|
|
@@ -16,7 +16,16 @@ const getParsedAuthor = (author) => {
|
|
|
16
16
|
author = author || {};
|
|
17
17
|
return typeof author === 'string' ? (0, parse_author_1.default)(author) : author;
|
|
18
18
|
};
|
|
19
|
-
const mapComponentDetails = (component) =>
|
|
19
|
+
const mapComponentDetails = (component) => ({
|
|
20
|
+
...component,
|
|
21
|
+
author: getParsedAuthor(component.author),
|
|
22
|
+
oc: component.oc.date
|
|
23
|
+
? {
|
|
24
|
+
...component.oc,
|
|
25
|
+
stringifiedDate: (0, date_stringify_1.default)(new Date(component.oc.date))
|
|
26
|
+
}
|
|
27
|
+
: component.oc
|
|
28
|
+
});
|
|
20
29
|
const isHtmlRequest = (headers) => !!headers.accept && headers.accept.indexOf('text/html') >= 0;
|
|
21
30
|
const excludedMeta = ['dependencies', 'devDependencies'];
|
|
22
31
|
function default_1(repository) {
|
|
@@ -37,12 +46,7 @@ function default_1(repository) {
|
|
|
37
46
|
};
|
|
38
47
|
const componentDetails = await Promise.all(componentNames.map((componentName) => repository.getComponent(componentName, undefined)));
|
|
39
48
|
if (isHtmlRequest(req.headers) && res.conf.discovery.ui) {
|
|
40
|
-
const processedComponents = componentDetails.map(
|
|
41
|
-
if (component.oc?.date) {
|
|
42
|
-
component.oc.stringifiedDate = (0, date_stringify_1.default)(new Date(component.oc.date));
|
|
43
|
-
}
|
|
44
|
-
return mapComponentDetails(component);
|
|
45
|
-
});
|
|
49
|
+
const processedComponents = componentDetails.map(mapComponentDetails);
|
|
46
50
|
const totalReleases = componentDetails.reduce((sum, component) => sum + component.allVersions.length, 0);
|
|
47
51
|
const stateCounts = {};
|
|
48
52
|
const componentsList = processedComponents.map((component) => {
|
|
@@ -27,6 +27,11 @@ declare const _default: {
|
|
|
27
27
|
COMPONENT_SET_HEADER_PARAMETERS_NOT_VALID: string;
|
|
28
28
|
COMPONENT_SET_COOKIE_PARAMETERS_NOT_VALID: string;
|
|
29
29
|
CONFIGURATION_DEPENDENCIES_MUST_BE_ARRAY: string;
|
|
30
|
+
CONFIGURATION_CORS_MUST_BE_OBJECT: string;
|
|
31
|
+
CONFIGURATION_CORS_ORIGIN_MUST_BE_STRING: string;
|
|
32
|
+
CONFIGURATION_CORS_CREDENTIALS_MUST_BE_BOOLEAN: string;
|
|
33
|
+
CONFIGURATION_CORS_ALLOWED_HEADERS_MUST_BE_STRING_ARRAY: string;
|
|
34
|
+
CONFIGURATION_CORS_METHODS_MUST_BE_STRING_ARRAY: string;
|
|
30
35
|
CONFIGURATION_EMPTY: string;
|
|
31
36
|
CONFIGURATION_METADATA_NOT_VALID: (adapterType: string) => string;
|
|
32
37
|
CONFIGURATION_METADATA_EXPORT_INTERVAL_NOT_VALID: string;
|
|
@@ -108,7 +113,6 @@ declare const _default: {
|
|
|
108
113
|
initSuccess: (componentName: string, componentPath: string) => string;
|
|
109
114
|
installCompiler: (compiler: string) => string;
|
|
110
115
|
installCompilerSuccess: (template: string, compiler: string, version: string) => string;
|
|
111
|
-
legacyTemplateDeprecationWarning: (legacyType: string, newType: string) => string;
|
|
112
116
|
CHANGES_DETECTED: (file: string) => string;
|
|
113
117
|
CHECKING_DEPENDENCIES: string;
|
|
114
118
|
COMPRESSING: (path: string) => string;
|
package/dist/resources/index.js
CHANGED
|
@@ -76,6 +76,11 @@ exports.default = {
|
|
|
76
76
|
COMPONENT_SET_HEADER_PARAMETERS_NOT_VALID: 'context.setHeader parameters must be strings',
|
|
77
77
|
COMPONENT_SET_COOKIE_PARAMETERS_NOT_VALID: 'context.setCookie parameters are not valid',
|
|
78
78
|
CONFIGURATION_DEPENDENCIES_MUST_BE_ARRAY: 'Registry configuration is not valid: dependencies must be an array',
|
|
79
|
+
CONFIGURATION_CORS_MUST_BE_OBJECT: 'Registry configuration is not valid: cors must be an object',
|
|
80
|
+
CONFIGURATION_CORS_ORIGIN_MUST_BE_STRING: 'Registry configuration is not valid: cors.origin must be a non-empty string',
|
|
81
|
+
CONFIGURATION_CORS_CREDENTIALS_MUST_BE_BOOLEAN: 'Registry configuration is not valid: cors.credentials must be a boolean',
|
|
82
|
+
CONFIGURATION_CORS_ALLOWED_HEADERS_MUST_BE_STRING_ARRAY: 'Registry configuration is not valid: cors.allowedHeaders must be a string or an array of strings',
|
|
83
|
+
CONFIGURATION_CORS_METHODS_MUST_BE_STRING_ARRAY: 'Registry configuration is not valid: cors.methods must be a string or an array of strings',
|
|
79
84
|
CONFIGURATION_EMPTY: 'Registry configuration is empty',
|
|
80
85
|
CONFIGURATION_METADATA_NOT_VALID: (adapterType) => `Registry configuration is not valid: ${adapterType} is not a valid metadata adapter`,
|
|
81
86
|
CONFIGURATION_METADATA_EXPORT_INTERVAL_NOT_VALID: 'Registry configuration is not valid: metadata.exportLegacyFilesInterval must be a positive number',
|
|
@@ -157,7 +162,6 @@ exports.default = {
|
|
|
157
162
|
initSuccess,
|
|
158
163
|
installCompiler: (compiler) => `Installing ${compiler} from npm...`,
|
|
159
164
|
installCompilerSuccess: (template, compiler, version) => `${(0, colors_1.green)('✔')} Installed ${compiler} [${template} v${version}]`,
|
|
160
|
-
legacyTemplateDeprecationWarning: (legacyType, newType) => `Template-type "${legacyType}" has been deprecated and is now replaced by "${newType}"`,
|
|
161
165
|
CHANGES_DETECTED: (file) => `Changes detected on file: ${file}`,
|
|
162
166
|
CHECKING_DEPENDENCIES: 'Ensuring dependencies are loaded...',
|
|
163
167
|
COMPRESSING: (path) => `Compressing -> ${path}`,
|
package/dist/types.d.ts
CHANGED
|
@@ -5,6 +5,27 @@ import type { PackageJson } from 'type-fest';
|
|
|
5
5
|
import type { HttpServerAdapterFactory, HttpServerAdapterOptions } from './registry/domain/http-server/types';
|
|
6
6
|
export type { ComponentRow, MetadataStore } from 'oc-metadata-adapters-utils';
|
|
7
7
|
type Middleware = (req: Request, res: Response, next: NextFunction) => void;
|
|
8
|
+
export interface RegistryErrorEvent {
|
|
9
|
+
/**
|
|
10
|
+
* Stable registry error category. Server adapter failures use
|
|
11
|
+
* `SERVER_ERROR`, regardless of the configured adapter.
|
|
12
|
+
*/
|
|
13
|
+
code: string;
|
|
14
|
+
/** The original error message reported by the failing registry operation. */
|
|
15
|
+
message: string;
|
|
16
|
+
}
|
|
17
|
+
export interface CorsConfig {
|
|
18
|
+
origin: string;
|
|
19
|
+
credentials: boolean;
|
|
20
|
+
allowedHeaders: string;
|
|
21
|
+
methods: string;
|
|
22
|
+
}
|
|
23
|
+
export interface CorsOptions {
|
|
24
|
+
origin?: string;
|
|
25
|
+
credentials?: boolean;
|
|
26
|
+
allowedHeaders?: string | string[];
|
|
27
|
+
methods?: string | string[];
|
|
28
|
+
}
|
|
8
29
|
export interface Author {
|
|
9
30
|
email?: string;
|
|
10
31
|
name?: string;
|
|
@@ -192,6 +213,12 @@ export interface Config<T = any, TServerAdapter extends HttpServerAdapterFactory
|
|
|
192
213
|
* @example "https://components.mycompany.com/"
|
|
193
214
|
*/
|
|
194
215
|
baseUrl: string;
|
|
216
|
+
/**
|
|
217
|
+
* CORS response headers sent by the registry.
|
|
218
|
+
*
|
|
219
|
+
* @default Existing registry CORS headers
|
|
220
|
+
*/
|
|
221
|
+
cors?: CorsConfig;
|
|
195
222
|
/**
|
|
196
223
|
* Pre-compiled version of the `oc-client` library generated automatically
|
|
197
224
|
* at runtime when `compileClient` is enabled (default).
|
|
@@ -296,11 +323,12 @@ export interface Config<T = any, TServerAdapter extends HttpServerAdapterFactory
|
|
|
296
323
|
secure: boolean;
|
|
297
324
|
}) => boolean;
|
|
298
325
|
/**
|
|
299
|
-
* Environment
|
|
326
|
+
* Environment values passed to components in `context.env` and the data
|
|
327
|
+
* provider's `process.env` shim.
|
|
300
328
|
*
|
|
301
329
|
* @default {}
|
|
302
330
|
*/
|
|
303
|
-
env: Record<string,
|
|
331
|
+
env: Record<string, any>;
|
|
304
332
|
/**
|
|
305
333
|
* Maximum execution time of a component’s server-side logic, expressed in
|
|
306
334
|
* seconds. When the timeout elapses the registry returns a 500 error.
|
|
@@ -485,12 +513,13 @@ export interface Template {
|
|
|
485
513
|
getInfo: () => TemplateInfo;
|
|
486
514
|
render: (options: any, cb: (err: Error | null, data: string) => void) => void;
|
|
487
515
|
}
|
|
516
|
+
export type PluginRegistration<T = any> = (options: T, dependencies: any, next: (error?: Error) => void) => void | Promise<void>;
|
|
488
517
|
interface BasePLugin<T = any> {
|
|
489
518
|
description?: string;
|
|
490
519
|
name: string;
|
|
491
520
|
options?: T;
|
|
492
521
|
register: {
|
|
493
|
-
register:
|
|
522
|
+
register: PluginRegistration<T>;
|
|
494
523
|
dependencies?: string[];
|
|
495
524
|
};
|
|
496
525
|
}
|
|
@@ -514,7 +543,7 @@ export type Plugin<T = any> = BasePLugin<T> & ({
|
|
|
514
543
|
*/
|
|
515
544
|
context?: false | undefined;
|
|
516
545
|
register: {
|
|
517
|
-
register:
|
|
546
|
+
register: PluginRegistration<T>;
|
|
518
547
|
execute: (...args: any[]) => any;
|
|
519
548
|
dependencies?: string[];
|
|
520
549
|
};
|
|
@@ -533,7 +562,7 @@ export type Plugin<T = any> = BasePLugin<T> & ({
|
|
|
533
562
|
*/
|
|
534
563
|
context: true;
|
|
535
564
|
register: {
|
|
536
|
-
register:
|
|
565
|
+
register: PluginRegistration<T>;
|
|
537
566
|
execute: (context: PluginContext) => (params: any) => any;
|
|
538
567
|
dependencies?: string[];
|
|
539
568
|
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export default class BoundedCache {
|
|
2
|
+
private readonly cache;
|
|
3
|
+
constructor(maxEntries: number);
|
|
4
|
+
get<T>(namespace: string, key: string): T | undefined;
|
|
5
|
+
set<T>(namespace: string, key: string, value: T): void;
|
|
6
|
+
delete(namespace: string, key: string): boolean;
|
|
7
|
+
clear(): void;
|
|
8
|
+
get size(): number;
|
|
9
|
+
private toKey;
|
|
10
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const lru_cache_1 = require("lru-cache");
|
|
4
|
+
class BoundedCache {
|
|
5
|
+
cache;
|
|
6
|
+
constructor(maxEntries) {
|
|
7
|
+
if (!Number.isInteger(maxEntries) || maxEntries <= 0) {
|
|
8
|
+
throw new Error('Cache capacity must be a positive integer');
|
|
9
|
+
}
|
|
10
|
+
this.cache = new lru_cache_1.LRUCache({ max: maxEntries });
|
|
11
|
+
}
|
|
12
|
+
get(namespace, key) {
|
|
13
|
+
return this.cache.get(this.toKey(namespace, key));
|
|
14
|
+
}
|
|
15
|
+
set(namespace, key, value) {
|
|
16
|
+
this.cache.set(this.toKey(namespace, key), value);
|
|
17
|
+
}
|
|
18
|
+
delete(namespace, key) {
|
|
19
|
+
return this.cache.delete(this.toKey(namespace, key));
|
|
20
|
+
}
|
|
21
|
+
clear() {
|
|
22
|
+
this.cache.clear();
|
|
23
|
+
}
|
|
24
|
+
get size() {
|
|
25
|
+
return this.cache.size;
|
|
26
|
+
}
|
|
27
|
+
toKey(namespace, key) {
|
|
28
|
+
return JSON.stringify([namespace, key]);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
exports.default = BoundedCache;
|