@vsaas/loopback 10.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +25 -0
- package/README.md +91 -0
- package/common/models/README.md +109 -0
- package/common/models/access-token.json +37 -0
- package/common/models/acl.json +17 -0
- package/common/models/application.json +130 -0
- package/common/models/change.json +25 -0
- package/common/models/checkpoint.json +14 -0
- package/common/models/email.json +11 -0
- package/common/models/key-value-model.json +4 -0
- package/common/models/role-mapping.json +26 -0
- package/common/models/role.json +30 -0
- package/common/models/scope.json +14 -0
- package/common/models/user.json +118 -0
- package/dist/_virtual/_rolldown/runtime.cjs +32 -0
- package/dist/common/models/access-token.cjs +144 -0
- package/dist/common/models/access-token2.cjs +43 -0
- package/dist/common/models/acl.cjs +428 -0
- package/dist/common/models/acl2.cjs +27 -0
- package/dist/common/models/application.cjs +100 -0
- package/dist/common/models/application2.cjs +118 -0
- package/dist/common/models/change.cjs +404 -0
- package/dist/common/models/change2.cjs +25 -0
- package/dist/common/models/checkpoint.cjs +43 -0
- package/dist/common/models/checkpoint2.cjs +18 -0
- package/dist/common/models/email.cjs +18 -0
- package/dist/common/models/email2.cjs +30 -0
- package/dist/common/models/key-value-model.cjs +140 -0
- package/dist/common/models/key-value-model2.cjs +14 -0
- package/dist/common/models/role-mapping.cjs +57 -0
- package/dist/common/models/role-mapping2.cjs +34 -0
- package/dist/common/models/role.cjs +396 -0
- package/dist/common/models/role2.cjs +38 -0
- package/dist/common/models/scope.cjs +30 -0
- package/dist/common/models/scope2.cjs +21 -0
- package/dist/common/models/user.cjs +810 -0
- package/dist/common/models/user2.cjs +118 -0
- package/dist/index.cjs +16 -0
- package/dist/lib/access-context.cjs +228 -0
- package/dist/lib/application.cjs +450 -0
- package/dist/lib/builtin-models.cjs +60 -0
- package/dist/lib/configure-shared-methods.cjs +41 -0
- package/dist/lib/connectors/base-connector.cjs +23 -0
- package/dist/lib/connectors/mail-direct-transport.cjs +375 -0
- package/dist/lib/connectors/mail-stub-transport.cjs +86 -0
- package/dist/lib/connectors/mail.cjs +128 -0
- package/dist/lib/connectors/memory.cjs +19 -0
- package/dist/lib/current-context.cjs +22 -0
- package/dist/lib/globalize.cjs +29 -0
- package/dist/lib/loopback.cjs +313 -0
- package/dist/lib/model.cjs +1009 -0
- package/dist/lib/persisted-model.cjs +1835 -0
- package/dist/lib/registry.cjs +291 -0
- package/dist/lib/runtime.cjs +25 -0
- package/dist/lib/server-app.cjs +231 -0
- package/dist/lib/utils.cjs +154 -0
- package/dist/package.cjs +124 -0
- package/dist/server/middleware/context.cjs +7 -0
- package/dist/server/middleware/error-handler.cjs +6 -0
- package/dist/server/middleware/favicon.cjs +13 -0
- package/dist/server/middleware/rest.cjs +44 -0
- package/dist/server/middleware/static.cjs +14 -0
- package/dist/server/middleware/status.cjs +28 -0
- package/dist/server/middleware/token.cjs +66 -0
- package/dist/server/middleware/url-not-found.cjs +20 -0
- package/favicon.ico +0 -0
- package/package.json +121 -0
- package/templates/reset-form.ejs +3 -0
- package/templates/verify.ejs +9 -0
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
const require_runtime = require("../_virtual/_rolldown/runtime.cjs");
|
|
3
|
+
const require_lib_globalize = require("./globalize.cjs");
|
|
4
|
+
const require_lib_model = require("./model.cjs");
|
|
5
|
+
const require_lib_persisted_model = require("./persisted-model.cjs");
|
|
6
|
+
//#region src/lib/registry.ts
|
|
7
|
+
var require_registry = /* @__PURE__ */ require_runtime.__commonJSMin(((exports, module) => {
|
|
8
|
+
const g = require_lib_globalize;
|
|
9
|
+
const assert = require("assert");
|
|
10
|
+
const juggler = require("@vsaas/loopback-datasource-juggler");
|
|
11
|
+
const debug = require("debug")("loopback:registry");
|
|
12
|
+
const DataSource = juggler.DataSource;
|
|
13
|
+
const ModelBuilder = juggler.ModelBuilder;
|
|
14
|
+
const deprecated = require("depd")("strong-remoting");
|
|
15
|
+
module.exports = Registry;
|
|
16
|
+
/**
|
|
17
|
+
* Define and reference `Models` and `DataSources`.
|
|
18
|
+
*
|
|
19
|
+
* @class
|
|
20
|
+
*/
|
|
21
|
+
function Registry() {
|
|
22
|
+
this.defaultDataSources = {};
|
|
23
|
+
this.modelBuilder = new ModelBuilder();
|
|
24
|
+
require_lib_model(this);
|
|
25
|
+
require_lib_persisted_model(this);
|
|
26
|
+
this.modelBuilder.defaultModelBaseClass = this.getModel("Model");
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Create a named vanilla JavaScript class constructor with an attached
|
|
30
|
+
* set of properties and options.
|
|
31
|
+
*
|
|
32
|
+
* This function comes with two variants:
|
|
33
|
+
* * `loopback.createModel(name, properties, options)`
|
|
34
|
+
* * `loopback.createModel(config)`
|
|
35
|
+
*
|
|
36
|
+
* In the second variant, the parameters `name`, `properties` and `options`
|
|
37
|
+
* are provided in the config object. Any additional config entries are
|
|
38
|
+
* interpreted as `options`, i.e. the following two configs are identical:
|
|
39
|
+
*
|
|
40
|
+
* ```js
|
|
41
|
+
* { name: 'Customer', base: 'User' }
|
|
42
|
+
* { name: 'Customer', options: { base: 'User' } }
|
|
43
|
+
* ```
|
|
44
|
+
*
|
|
45
|
+
* **Example**
|
|
46
|
+
*
|
|
47
|
+
* Create an `Author` model using the three-parameter variant:
|
|
48
|
+
*
|
|
49
|
+
* ```js
|
|
50
|
+
* loopback.createModel(
|
|
51
|
+
* 'Author',
|
|
52
|
+
* {
|
|
53
|
+
* firstName: 'string',
|
|
54
|
+
* lastName: 'string'
|
|
55
|
+
* },
|
|
56
|
+
* {
|
|
57
|
+
* relations: {
|
|
58
|
+
* books: {
|
|
59
|
+
* model: 'Book',
|
|
60
|
+
* type: 'hasAndBelongsToMany'
|
|
61
|
+
* }
|
|
62
|
+
* }
|
|
63
|
+
* }
|
|
64
|
+
* );
|
|
65
|
+
* ```
|
|
66
|
+
*
|
|
67
|
+
* Create the same model using a config object:
|
|
68
|
+
*
|
|
69
|
+
* ```js
|
|
70
|
+
* loopback.createModel({
|
|
71
|
+
* name: 'Author',
|
|
72
|
+
* properties: {
|
|
73
|
+
* firstName: 'string',
|
|
74
|
+
* lastName: 'string'
|
|
75
|
+
* },
|
|
76
|
+
* relations: {
|
|
77
|
+
* books: {
|
|
78
|
+
* model: 'Book',
|
|
79
|
+
* type: 'hasAndBelongsToMany'
|
|
80
|
+
* }
|
|
81
|
+
* }
|
|
82
|
+
* });
|
|
83
|
+
* ```
|
|
84
|
+
*
|
|
85
|
+
* @param {String} name Unique name.
|
|
86
|
+
* @param {Object} properties
|
|
87
|
+
* @param {Object} options (optional)
|
|
88
|
+
*
|
|
89
|
+
* @header loopback.createModel
|
|
90
|
+
*/
|
|
91
|
+
Registry.prototype.createModel = function(name, properties, options) {
|
|
92
|
+
if (arguments.length === 1 && typeof name === "object") {
|
|
93
|
+
const config = name;
|
|
94
|
+
name = config.name;
|
|
95
|
+
properties = config.properties;
|
|
96
|
+
options = buildModelOptionsFromConfig(config);
|
|
97
|
+
assert(typeof name === "string", "The model-config property `name` must be a string");
|
|
98
|
+
}
|
|
99
|
+
options = options || {};
|
|
100
|
+
let BaseModel = options.base || options.super;
|
|
101
|
+
if (typeof BaseModel === "string") {
|
|
102
|
+
const baseName = BaseModel;
|
|
103
|
+
BaseModel = this.findModel(BaseModel);
|
|
104
|
+
if (!BaseModel) throw new Error(g.f("Model not found: model `%s` is extending an unknown model `%s`.", name, baseName));
|
|
105
|
+
}
|
|
106
|
+
BaseModel = BaseModel || this.getModel("PersistedModel");
|
|
107
|
+
const model = BaseModel.extend(name, properties, options);
|
|
108
|
+
model.registry = this;
|
|
109
|
+
this._defineRemoteMethods(model, model.settings.methods);
|
|
110
|
+
return model;
|
|
111
|
+
};
|
|
112
|
+
function buildModelOptionsFromConfig(config) {
|
|
113
|
+
const options = Object.assign({}, config.options);
|
|
114
|
+
for (const key in config) {
|
|
115
|
+
if ([
|
|
116
|
+
"name",
|
|
117
|
+
"properties",
|
|
118
|
+
"options"
|
|
119
|
+
].indexOf(key) !== -1) continue;
|
|
120
|
+
if (options[key] !== void 0) continue;
|
|
121
|
+
options[key] = config[key];
|
|
122
|
+
}
|
|
123
|
+
return options;
|
|
124
|
+
}
|
|
125
|
+
function addACL(acls, acl) {
|
|
126
|
+
for (let i = 0, n = acls.length; i < n; i++) if (acls[i].property === acl.property && acls[i].accessType === acl.accessType && acls[i].principalType === acl.principalType && acls[i].principalId === acl.principalId) {
|
|
127
|
+
acls[i] = acl;
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
acls.push(acl);
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Alter an existing Model class.
|
|
134
|
+
* @param {Model} ModelCtor The model constructor to alter.
|
|
135
|
+
* @options {Object} config Additional configuration to apply
|
|
136
|
+
* @property {DataSource} dataSource Attach the model to a dataSource.
|
|
137
|
+
* @property {Object} [relations] Model relations to add/update.
|
|
138
|
+
*
|
|
139
|
+
* @header loopback.configureModel(ModelCtor, config)
|
|
140
|
+
*/
|
|
141
|
+
Registry.prototype.configureModel = function(ModelCtor, config) {
|
|
142
|
+
const settings = ModelCtor.settings;
|
|
143
|
+
const modelName = ModelCtor.modelName;
|
|
144
|
+
ModelCtor.config = config;
|
|
145
|
+
if (typeof config.relations === "object" && config.relations !== null) {
|
|
146
|
+
const relations = settings.relations = settings.relations || {};
|
|
147
|
+
Object.keys(config.relations).forEach(function(key) {
|
|
148
|
+
relations[key] = Object.assign(relations[key] || {}, config.relations[key]);
|
|
149
|
+
});
|
|
150
|
+
} else if (config.relations != null) g.warn("The relations property of `%s` configuration must be an object", modelName);
|
|
151
|
+
if (Array.isArray(config.acls)) {
|
|
152
|
+
const acls = settings.acls = settings.acls || [];
|
|
153
|
+
config.acls.forEach(function(acl) {
|
|
154
|
+
addACL(acls, acl);
|
|
155
|
+
});
|
|
156
|
+
} else if (config.acls != null) g.warn("The acls property of `%s` configuration must be an array of objects", modelName);
|
|
157
|
+
const excludedProperties = {
|
|
158
|
+
base: true,
|
|
159
|
+
super: true,
|
|
160
|
+
relations: true,
|
|
161
|
+
acls: true,
|
|
162
|
+
dataSource: true
|
|
163
|
+
};
|
|
164
|
+
if (typeof config.options === "object" && config.options !== null) for (const p in config.options) if (!(p in excludedProperties)) settings[p] = config.options[p];
|
|
165
|
+
else g.warn("Property `%s` cannot be reconfigured for `%s`", p, modelName);
|
|
166
|
+
else if (config.options != null) g.warn("The options property of `%s` configuration must be an object", modelName);
|
|
167
|
+
if (config.dataSource) {
|
|
168
|
+
assert(config.dataSource instanceof DataSource, "Cannot configure " + ModelCtor.modelName + ": config.dataSource must be an instance of DataSource");
|
|
169
|
+
ModelCtor.attachTo(config.dataSource);
|
|
170
|
+
debug("Attached model `%s` to dataSource `%s`", modelName, config.dataSource.name);
|
|
171
|
+
} else if (config.dataSource === null || config.dataSource === false) debug("Model `%s` is not attached to any DataSource by configuration.", modelName);
|
|
172
|
+
else {
|
|
173
|
+
debug("Model `%s` is not attached to any DataSource, possibly by a mistake.", modelName);
|
|
174
|
+
g.warn("The configuration of `%s` is missing {{`dataSource`}} property.\nUse `null` or `false` to mark models not attached to any data source.", modelName);
|
|
175
|
+
}
|
|
176
|
+
const newMethodNames = config.methods && Object.keys(config.methods);
|
|
177
|
+
const hasNewMethods = newMethodNames && newMethodNames.length;
|
|
178
|
+
const hasDescendants = this.getModelByType(ModelCtor) !== ModelCtor;
|
|
179
|
+
if (hasNewMethods && hasDescendants) g.warn("Child models of `%s` will not inherit newly defined remote methods %s.", modelName, newMethodNames);
|
|
180
|
+
this._defineRemoteMethods(ModelCtor, config.methods);
|
|
181
|
+
};
|
|
182
|
+
Registry.prototype._defineRemoteMethods = function(ModelCtor, methods) {
|
|
183
|
+
if (!methods) return;
|
|
184
|
+
if (typeof methods !== "object") {
|
|
185
|
+
g.warn("Ignoring non-object \"methods\" setting of \"%s\".", ModelCtor.modelName);
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
Object.keys(methods).forEach(function(key) {
|
|
189
|
+
let meta = methods[key];
|
|
190
|
+
const m = key.match(/^prototype\.(.*)$/);
|
|
191
|
+
const isStatic = !m;
|
|
192
|
+
if (typeof meta.isStatic !== "boolean") {
|
|
193
|
+
key = isStatic ? key : m[1];
|
|
194
|
+
meta = Object.assign({}, meta, { isStatic });
|
|
195
|
+
} else if (meta.isStatic && m) throw new Error(g.f("Remoting metadata for %s.%s {{\"isStatic\"}} does not match new method name-based style.", ModelCtor.modelName, key));
|
|
196
|
+
else {
|
|
197
|
+
key = isStatic ? key : m[1];
|
|
198
|
+
if (!meta.isStatic && isStatic) deprecated(g.f("Remoting metadata {{\"isStatic\"}} is deprecated. Please specify {{\"prototype.name\"}} in method name instead for {{isStatic=false}}."));
|
|
199
|
+
}
|
|
200
|
+
ModelCtor.remoteMethod(key, meta);
|
|
201
|
+
});
|
|
202
|
+
};
|
|
203
|
+
/**
|
|
204
|
+
* Look up a model class by name from all models created by
|
|
205
|
+
* `loopback.createModel()`
|
|
206
|
+
* @param {String|Function} modelOrName The model name or a `Model` constructor.
|
|
207
|
+
* @returns {Model} The model class
|
|
208
|
+
*
|
|
209
|
+
* @header loopback.findModel(modelName)
|
|
210
|
+
*/
|
|
211
|
+
Registry.prototype.findModel = function(modelName) {
|
|
212
|
+
if (typeof modelName === "function") return modelName;
|
|
213
|
+
return this.modelBuilder.models[modelName];
|
|
214
|
+
};
|
|
215
|
+
/**
|
|
216
|
+
* Look up a model class by name from all models created by
|
|
217
|
+
* `loopback.createModel()`. **Throw an error when no such model exists.**
|
|
218
|
+
*
|
|
219
|
+
* @param {String} modelOrName The model name or a `Model` constructor.
|
|
220
|
+
* @returns {Model} The model class
|
|
221
|
+
*
|
|
222
|
+
* @header loopback.getModel(modelName)
|
|
223
|
+
*/
|
|
224
|
+
Registry.prototype.getModel = function(modelName) {
|
|
225
|
+
const model = this.findModel(modelName);
|
|
226
|
+
if (model) return model;
|
|
227
|
+
throw new Error(g.f("Model not found: %s", modelName));
|
|
228
|
+
};
|
|
229
|
+
/**
|
|
230
|
+
* Look up a model class by the base model class.
|
|
231
|
+
* The method can be used by LoopBack
|
|
232
|
+
* to find configured models in models.json over the base model.
|
|
233
|
+
* @param {Model} modelType The base model class
|
|
234
|
+
* @returns {Model} The subclass if found or the base class
|
|
235
|
+
*
|
|
236
|
+
* @header loopback.getModelByType(modelType)
|
|
237
|
+
*/
|
|
238
|
+
Registry.prototype.getModelByType = function(modelType) {
|
|
239
|
+
const type = typeof modelType;
|
|
240
|
+
assert(["function", "string"].indexOf(type) > -1, "The model type must be a constructor or model name");
|
|
241
|
+
if (type === "string") modelType = this.getModel(modelType);
|
|
242
|
+
const models = this.modelBuilder.models;
|
|
243
|
+
for (const m in models) if (models[m].prototype instanceof modelType) return models[m];
|
|
244
|
+
return modelType;
|
|
245
|
+
};
|
|
246
|
+
/**
|
|
247
|
+
* Create a data source with passing the provided options to the connector.
|
|
248
|
+
*
|
|
249
|
+
* @param {String} name Optional name.
|
|
250
|
+
* @options {Object} options Data Source options
|
|
251
|
+
* @property {Object} connector LoopBack connector.
|
|
252
|
+
* @property {*} [*] Other connector properties.
|
|
253
|
+
* See the relevant connector documentation.
|
|
254
|
+
*/
|
|
255
|
+
Registry.prototype.createDataSource = function(name, options) {
|
|
256
|
+
const self = this;
|
|
257
|
+
const ds = new DataSource(name, options, self.modelBuilder);
|
|
258
|
+
ds.createModel = function(name, properties, settings) {
|
|
259
|
+
settings = settings || {};
|
|
260
|
+
let BaseModel = settings.base || settings.super;
|
|
261
|
+
if (!BaseModel) {
|
|
262
|
+
const connectorTypes = ds.getTypes();
|
|
263
|
+
if (Array.isArray(connectorTypes) && connectorTypes.indexOf("db") !== -1) BaseModel = self.PersistedModel;
|
|
264
|
+
else BaseModel = self.Model;
|
|
265
|
+
settings.base = BaseModel;
|
|
266
|
+
}
|
|
267
|
+
const ModelCtor = self.createModel(name, properties, settings);
|
|
268
|
+
ModelCtor.attachTo(ds);
|
|
269
|
+
return ModelCtor;
|
|
270
|
+
};
|
|
271
|
+
if (ds.settings && ds.settings.defaultForType) {
|
|
272
|
+
const msg = g.f("{{DataSource}} option {{\"defaultForType\"}} is no longer supported");
|
|
273
|
+
throw new Error(msg);
|
|
274
|
+
}
|
|
275
|
+
return ds;
|
|
276
|
+
};
|
|
277
|
+
/**
|
|
278
|
+
* Get an in-memory data source. Use one if it already exists.
|
|
279
|
+
*
|
|
280
|
+
* @param {String} [name] The name of the data source.
|
|
281
|
+
* If not provided, the `'default'` is used.
|
|
282
|
+
*/
|
|
283
|
+
Registry.prototype.memory = function(name) {
|
|
284
|
+
name = name || "default";
|
|
285
|
+
let memory = (this._memoryDataSources || (this._memoryDataSources = {}))[name];
|
|
286
|
+
if (!memory) memory = this._memoryDataSources[name] = this.createDataSource({ connector: "memory" });
|
|
287
|
+
return memory;
|
|
288
|
+
};
|
|
289
|
+
}));
|
|
290
|
+
//#endregion
|
|
291
|
+
module.exports = require_registry();
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
//#region src/lib/runtime.ts
|
|
2
|
+
var require_runtime = /* @__PURE__ */ require("../_virtual/_rolldown/runtime.cjs").__commonJSMin(((exports, module) => {
|
|
3
|
+
/**
|
|
4
|
+
* True if running in a browser environment; false otherwise.
|
|
5
|
+
* @header loopback.isBrowser
|
|
6
|
+
*/
|
|
7
|
+
const isBrowser = typeof window !== "undefined";
|
|
8
|
+
/**
|
|
9
|
+
* True if running in a server environment; false otherwise.
|
|
10
|
+
* @header loopback.isServer
|
|
11
|
+
*/
|
|
12
|
+
const runtime = {
|
|
13
|
+
isBrowser,
|
|
14
|
+
isServer: !isBrowser
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(runtime, "loopback", {
|
|
17
|
+
value: null,
|
|
18
|
+
writable: true,
|
|
19
|
+
configurable: true,
|
|
20
|
+
enumerable: false
|
|
21
|
+
});
|
|
22
|
+
module.exports = runtime;
|
|
23
|
+
}));
|
|
24
|
+
//#endregion
|
|
25
|
+
module.exports = require_runtime();
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
const require_runtime = require("../_virtual/_rolldown/runtime.cjs");
|
|
2
|
+
const require_lib_globalize = require("./globalize.cjs");
|
|
3
|
+
//#region src/lib/server-app.ts
|
|
4
|
+
var require_server_app = /* @__PURE__ */ require_runtime.__commonJSMin(((exports, module) => {
|
|
5
|
+
const g = require_lib_globalize;
|
|
6
|
+
const assert = require("assert");
|
|
7
|
+
const express = require("express");
|
|
8
|
+
const mergePhaseNameLists = require("@vsaas/remoting/phases").mergePhaseNameLists;
|
|
9
|
+
const debug = require("debug")("loopback:app");
|
|
10
|
+
const BUILTIN_MIDDLEWARE = { builtin: true };
|
|
11
|
+
const proto = {};
|
|
12
|
+
function loopbackExpress() {
|
|
13
|
+
const app = express();
|
|
14
|
+
app.__expressLazyRouter = app.lazyrouter;
|
|
15
|
+
Object.assign(app, proto);
|
|
16
|
+
return app;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Register a middleware using a factory function and a JSON config.
|
|
20
|
+
*
|
|
21
|
+
* **Example**
|
|
22
|
+
*
|
|
23
|
+
* ```js
|
|
24
|
+
* app.middlewareFromConfig(compression, {
|
|
25
|
+
* enabled: true,
|
|
26
|
+
* phase: 'initial',
|
|
27
|
+
* params: {
|
|
28
|
+
* threshold: 128
|
|
29
|
+
* }
|
|
30
|
+
* });
|
|
31
|
+
* ```
|
|
32
|
+
*
|
|
33
|
+
* @param {function} factory The factory function creating a middleware handler.
|
|
34
|
+
* Typically a result of `require()` call, e.g. `require('compression')`.
|
|
35
|
+
* @options {Object} config The configuration.
|
|
36
|
+
* @property {String} phase The phase to register the middleware in.
|
|
37
|
+
* @property {Boolean} [enabled] Whether the middleware is enabled.
|
|
38
|
+
* Default: `true`.
|
|
39
|
+
* @property {Array|*} [params] The arguments to pass to the factory
|
|
40
|
+
* function. Either an array of arguments,
|
|
41
|
+
* or the value of the first argument when the factory expects
|
|
42
|
+
* a single argument only.
|
|
43
|
+
* @property {Array|string|RegExp} [paths] Optional list of paths limiting
|
|
44
|
+
* the scope of the middleware.
|
|
45
|
+
*
|
|
46
|
+
* @returns {object} this (fluent API)
|
|
47
|
+
*
|
|
48
|
+
* @header app.middlewareFromConfig(factory, config)
|
|
49
|
+
*/
|
|
50
|
+
proto.middlewareFromConfig = function(factory, config) {
|
|
51
|
+
assert(typeof factory === "function", "\"factory\" must be a function");
|
|
52
|
+
assert(typeof config === "object", "\"config\" must be an object");
|
|
53
|
+
assert(typeof config.phase === "string" && config.phase, "\"config.phase\" must be a non-empty string");
|
|
54
|
+
if (config.enabled === false) return;
|
|
55
|
+
let params = config.params;
|
|
56
|
+
if (params === void 0) params = [];
|
|
57
|
+
else if (!Array.isArray(params)) params = [params];
|
|
58
|
+
let handler = factory.apply(null, params);
|
|
59
|
+
let verbs = config.methods || config.verbs;
|
|
60
|
+
if (Array.isArray(verbs)) {
|
|
61
|
+
verbs = verbs.map(function(verb) {
|
|
62
|
+
return verb && verb.toUpperCase();
|
|
63
|
+
});
|
|
64
|
+
if (verbs.indexOf("ALL") === -1) {
|
|
65
|
+
const originalHandler = handler;
|
|
66
|
+
if (handler.length <= 3) handler = function(req, res, next) {
|
|
67
|
+
if (verbs.indexOf(req.method.toUpperCase()) === -1) return next();
|
|
68
|
+
originalHandler(req, res, next);
|
|
69
|
+
};
|
|
70
|
+
else handler = function(err, req, res, next) {
|
|
71
|
+
if (verbs.indexOf(req.method.toUpperCase()) === -1) return next(err);
|
|
72
|
+
originalHandler(err, req, res, next);
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
this.middleware(config.phase, config.paths || [], handler);
|
|
77
|
+
return this;
|
|
78
|
+
};
|
|
79
|
+
/**
|
|
80
|
+
* Register (new) middleware phases.
|
|
81
|
+
*
|
|
82
|
+
* If all names are new, then the phases are added just before "routes" phase.
|
|
83
|
+
* Otherwise the provided list of names is merged with the existing phases
|
|
84
|
+
* in such way that the order of phases is preserved.
|
|
85
|
+
*
|
|
86
|
+
* **Examples**
|
|
87
|
+
*
|
|
88
|
+
* ```js
|
|
89
|
+
* // built-in phases:
|
|
90
|
+
* // initial, session, auth, parse, routes, files, final
|
|
91
|
+
*
|
|
92
|
+
* app.defineMiddlewarePhases('custom');
|
|
93
|
+
* // new list of phases
|
|
94
|
+
* // initial, session, auth, parse, custom, routes, files, final
|
|
95
|
+
*
|
|
96
|
+
* app.defineMiddlewarePhases([
|
|
97
|
+
* 'initial', 'postinit', 'preauth', 'routes', 'subapps'
|
|
98
|
+
* ]);
|
|
99
|
+
* // new list of phases
|
|
100
|
+
* // initial, postinit, preauth, session, auth, parse, custom,
|
|
101
|
+
* // routes, subapps, files, final
|
|
102
|
+
* ```
|
|
103
|
+
*
|
|
104
|
+
* @param {string|Array.<string>} nameOrArray A phase name or a list of phase
|
|
105
|
+
* names to add.
|
|
106
|
+
*
|
|
107
|
+
* @returns {object} this (fluent API)
|
|
108
|
+
*
|
|
109
|
+
* @header app.defineMiddlewarePhases(nameOrArray)
|
|
110
|
+
*/
|
|
111
|
+
proto.defineMiddlewarePhases = function(nameOrArray) {
|
|
112
|
+
this.lazyrouter();
|
|
113
|
+
if (Array.isArray(nameOrArray)) this._requestHandlingPhases = mergePhaseNameLists(this._requestHandlingPhases, nameOrArray);
|
|
114
|
+
else {
|
|
115
|
+
const routesIx = this._requestHandlingPhases.indexOf("routes");
|
|
116
|
+
this._requestHandlingPhases.splice(routesIx - 1, 0, nameOrArray);
|
|
117
|
+
}
|
|
118
|
+
return this;
|
|
119
|
+
};
|
|
120
|
+
/**
|
|
121
|
+
* Register a middleware handler to be executed in a given phase.
|
|
122
|
+
* @param {string} name The phase name, e.g. "init" or "routes".
|
|
123
|
+
* @param {Array|string|RegExp} [paths] Optional list of paths limiting
|
|
124
|
+
* the scope of the middleware.
|
|
125
|
+
* String paths are interpreted as expressjs path patterns,
|
|
126
|
+
* regular expressions are used as-is.
|
|
127
|
+
* @param {function} handler The middleware handler, one of
|
|
128
|
+
* `function(req, res, next)` or
|
|
129
|
+
* `function(err, req, res, next)`
|
|
130
|
+
* @returns {object} this (fluent API)
|
|
131
|
+
*
|
|
132
|
+
* @header app.middleware(name, handler)
|
|
133
|
+
*/
|
|
134
|
+
proto.middleware = function(name, paths, handler) {
|
|
135
|
+
this.lazyrouter();
|
|
136
|
+
if (handler === void 0 && typeof paths === "function") {
|
|
137
|
+
handler = paths;
|
|
138
|
+
paths = void 0;
|
|
139
|
+
}
|
|
140
|
+
assert(typeof name === "string" && name, "\"name\" must be a non-empty string");
|
|
141
|
+
assert(typeof handler === "function", "\"handler\" must be a function");
|
|
142
|
+
if (paths === void 0) paths = "/";
|
|
143
|
+
const fullPhaseName = name;
|
|
144
|
+
const handlerName = handler.name || "<anonymous>";
|
|
145
|
+
const m = name.match(/^(.+):(before|after)$/);
|
|
146
|
+
if (m) name = m[1];
|
|
147
|
+
if (this._requestHandlingPhases.indexOf(name) === -1) throw new Error(g.f("Unknown {{middleware}} phase %s", name));
|
|
148
|
+
debug("use %s %s %s", fullPhaseName, paths, handlerName);
|
|
149
|
+
this._skipLayerSorting = true;
|
|
150
|
+
this.use(paths, handler);
|
|
151
|
+
const layer = this._findLayerByHandler(handler);
|
|
152
|
+
if (layer) layer.phase = fullPhaseName;
|
|
153
|
+
else debug("No matching layer is found for %s %s", fullPhaseName, handlerName);
|
|
154
|
+
this._skipLayerSorting = false;
|
|
155
|
+
this._sortLayersByPhase();
|
|
156
|
+
return this;
|
|
157
|
+
};
|
|
158
|
+
/*!
|
|
159
|
+
* Find the corresponding express layer by handler
|
|
160
|
+
*
|
|
161
|
+
* This is needed because monitoring agents such as NewRelic can add handlers
|
|
162
|
+
* to the stack. For example, NewRelic adds sentinel handler. We need to search
|
|
163
|
+
* the stackto find the correct layer.
|
|
164
|
+
*/
|
|
165
|
+
proto._findLayerByHandler = function(handler) {
|
|
166
|
+
for (let k = this._router.stack.length - 1; k >= 0; k--) {
|
|
167
|
+
const isOriginal = this._router.stack[k].handle === handler;
|
|
168
|
+
const isNewRelic = this._router.stack[k].handle["__NR_original"] === handler;
|
|
169
|
+
const isAppDynamics = this._router.stack[k].handle["__appdynamicsProxyInfo__"] && this._router.stack[k].handle["__appdynamicsProxyInfo__"]["orig"] === handler;
|
|
170
|
+
if (isOriginal || isNewRelic || isAppDynamics) return this._router.stack[k];
|
|
171
|
+
else for (const p in this._router.stack[k].handle) if (this._router.stack[k].handle[p] === handler) return this._router.stack[k];
|
|
172
|
+
}
|
|
173
|
+
return null;
|
|
174
|
+
};
|
|
175
|
+
proto.lazyrouter = function() {
|
|
176
|
+
const self = this;
|
|
177
|
+
if (self._router) return;
|
|
178
|
+
self.__expressLazyRouter();
|
|
179
|
+
const router = self._router;
|
|
180
|
+
router.stack.forEach(function(layer) {
|
|
181
|
+
layer.phase = BUILTIN_MIDDLEWARE;
|
|
182
|
+
});
|
|
183
|
+
router.__expressUse = router.use;
|
|
184
|
+
router.use = function useAndSort() {
|
|
185
|
+
const retval = this.__expressUse.apply(this, arguments);
|
|
186
|
+
self._sortLayersByPhase();
|
|
187
|
+
return retval;
|
|
188
|
+
};
|
|
189
|
+
router.__expressRoute = router.route;
|
|
190
|
+
router.route = function routeAndSort() {
|
|
191
|
+
const retval = this.__expressRoute.apply(this, arguments);
|
|
192
|
+
self._sortLayersByPhase();
|
|
193
|
+
return retval;
|
|
194
|
+
};
|
|
195
|
+
self._requestHandlingPhases = [
|
|
196
|
+
"initial",
|
|
197
|
+
"session",
|
|
198
|
+
"auth",
|
|
199
|
+
"parse",
|
|
200
|
+
"routes",
|
|
201
|
+
"files",
|
|
202
|
+
"final"
|
|
203
|
+
];
|
|
204
|
+
};
|
|
205
|
+
proto._sortLayersByPhase = function() {
|
|
206
|
+
if (this._skipLayerSorting) return;
|
|
207
|
+
const phaseOrder = {};
|
|
208
|
+
this._requestHandlingPhases.forEach(function(name, ix) {
|
|
209
|
+
phaseOrder[name + ":before"] = ix * 3;
|
|
210
|
+
phaseOrder[name] = ix * 3 + 1;
|
|
211
|
+
phaseOrder[name + ":after"] = ix * 3 + 2;
|
|
212
|
+
});
|
|
213
|
+
this._router.stack.sort(compareLayers);
|
|
214
|
+
function compareLayers(left, right) {
|
|
215
|
+
const leftPhase = left.phase;
|
|
216
|
+
const rightPhase = right.phase;
|
|
217
|
+
if (leftPhase === rightPhase) return 0;
|
|
218
|
+
if (leftPhase === BUILTIN_MIDDLEWARE) return -1;
|
|
219
|
+
if (rightPhase === BUILTIN_MIDDLEWARE) return 1;
|
|
220
|
+
if (leftPhase === void 0) {
|
|
221
|
+
if (rightPhase === "routes") return -1;
|
|
222
|
+
return phaseOrder.routes - phaseOrder[rightPhase];
|
|
223
|
+
}
|
|
224
|
+
if (rightPhase === void 0) return -compareLayers(right, left);
|
|
225
|
+
return phaseOrder[leftPhase] - phaseOrder[rightPhase];
|
|
226
|
+
}
|
|
227
|
+
};
|
|
228
|
+
module.exports = loopbackExpress;
|
|
229
|
+
}));
|
|
230
|
+
//#endregion
|
|
231
|
+
module.exports = require_server_app();
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
//#region src/lib/utils.ts
|
|
2
|
+
var require_utils = /* @__PURE__ */ require("../_virtual/_rolldown/runtime.cjs").__commonJSMin(((exports, module) => {
|
|
3
|
+
const hasOwnProperty = Object.prototype.hasOwnProperty;
|
|
4
|
+
function createPromiseCallback() {
|
|
5
|
+
let cb;
|
|
6
|
+
const promise = new Promise(function(resolve, reject) {
|
|
7
|
+
cb = function(err, data) {
|
|
8
|
+
if (err) return reject(err);
|
|
9
|
+
return resolve(data);
|
|
10
|
+
};
|
|
11
|
+
});
|
|
12
|
+
cb.promise = promise;
|
|
13
|
+
return cb;
|
|
14
|
+
}
|
|
15
|
+
function asCallback(promise, cb) {
|
|
16
|
+
if (typeof cb !== "function") return promise;
|
|
17
|
+
promise.then(function(result) {
|
|
18
|
+
cb(null, result);
|
|
19
|
+
}, function(err) {
|
|
20
|
+
cb(err);
|
|
21
|
+
});
|
|
22
|
+
return cb;
|
|
23
|
+
}
|
|
24
|
+
function invokeWithCallback(fn, receiver, args) {
|
|
25
|
+
return new Promise(function(resolve, reject) {
|
|
26
|
+
const argCount = args ? args.length : 0;
|
|
27
|
+
const invokeArgs = new Array(argCount + 1);
|
|
28
|
+
for (let i = 0; i < argCount; i++) invokeArgs[i] = args[i];
|
|
29
|
+
invokeArgs[argCount] = function(err, value) {
|
|
30
|
+
if (err) return reject(err);
|
|
31
|
+
resolve(value);
|
|
32
|
+
};
|
|
33
|
+
fn.apply(receiver, invokeArgs);
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Divide an async call with large array into multiple calls using smaller chunks
|
|
38
|
+
* @param {Array} largeArray - the large array to be chunked
|
|
39
|
+
* @param {Number} chunkSize - size of each chunks
|
|
40
|
+
* @param {Function} processFunction - the function to be called multiple times
|
|
41
|
+
* @param {Function} cb - the callback
|
|
42
|
+
*/
|
|
43
|
+
function uploadInChunks(largeArray, chunkSize, processFunction, cb) {
|
|
44
|
+
cb = cb || createPromiseCallback();
|
|
45
|
+
(async function() {
|
|
46
|
+
if (!chunkSize || chunkSize < 1 || largeArray.length <= chunkSize) return invokeWithCallback(processFunction, null, [largeArray]);
|
|
47
|
+
let previousResults;
|
|
48
|
+
for (let start = 0; start < largeArray.length; start += chunkSize) {
|
|
49
|
+
const results = await invokeWithCallback(processFunction, null, [largeArray.slice(start, start + chunkSize)]);
|
|
50
|
+
previousResults = mergeChunkResults(previousResults, results);
|
|
51
|
+
}
|
|
52
|
+
return previousResults;
|
|
53
|
+
})().then(function(results) {
|
|
54
|
+
cb(null, results);
|
|
55
|
+
}, function(err) {
|
|
56
|
+
cb(err);
|
|
57
|
+
});
|
|
58
|
+
return cb.promise;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Page async download calls
|
|
62
|
+
* @param {Object} filter - filter object used for the async call
|
|
63
|
+
* @param {Number} chunkSize - size of each chunks
|
|
64
|
+
* @param {Function} processFunction - the function to be called multiple times
|
|
65
|
+
* @param {Function} cb - the callback
|
|
66
|
+
*/
|
|
67
|
+
function downloadInChunks(filter, chunkSize, processFunction, cb) {
|
|
68
|
+
cb = cb || createPromiseCallback();
|
|
69
|
+
const baseFilter = filter ? cloneFilter(filter) : {};
|
|
70
|
+
(async function() {
|
|
71
|
+
if (!chunkSize || chunkSize < 1) return invokeWithCallback(processFunction, null, [baseFilter]);
|
|
72
|
+
let results;
|
|
73
|
+
let skip = 0;
|
|
74
|
+
while (true) {
|
|
75
|
+
const currentFilter = cloneFilter(baseFilter);
|
|
76
|
+
currentFilter.skip = skip;
|
|
77
|
+
currentFilter.limit = chunkSize;
|
|
78
|
+
const pagedResults = await invokeWithCallback(processFunction, null, [currentFilter]);
|
|
79
|
+
results = mergeChunkResults(results, pagedResults);
|
|
80
|
+
const pagedResultCount = pagedResults && typeof pagedResults.length === "number" ? pagedResults.length : 0;
|
|
81
|
+
if (pagedResultCount < chunkSize) return results;
|
|
82
|
+
skip += pagedResultCount;
|
|
83
|
+
}
|
|
84
|
+
})().then(function(results) {
|
|
85
|
+
cb(null, results);
|
|
86
|
+
}, function(err) {
|
|
87
|
+
cb(err);
|
|
88
|
+
});
|
|
89
|
+
return cb.promise;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Concat current results into previous results
|
|
93
|
+
* Assumption made here that the previous results and current results are homogeneous
|
|
94
|
+
* @param {Object|Array} previousResults
|
|
95
|
+
* @param {Object|Array} currentResults
|
|
96
|
+
*/
|
|
97
|
+
function concatResults(previousResults, currentResults) {
|
|
98
|
+
if (Array.isArray(currentResults)) previousResults = concatArrays(previousResults, currentResults);
|
|
99
|
+
else if (typeof currentResults === "object") {
|
|
100
|
+
for (const key in currentResults) if (hasOwnProperty.call(currentResults, key)) previousResults[key] = concatResults(previousResults[key], currentResults[key]);
|
|
101
|
+
} else previousResults = currentResults;
|
|
102
|
+
return previousResults;
|
|
103
|
+
}
|
|
104
|
+
function mergeChunkResults(previousResults, currentResults) {
|
|
105
|
+
if (typeof previousResults === "undefined" || previousResults === null) return cloneChunkResult(currentResults);
|
|
106
|
+
if (typeof currentResults === "undefined" || currentResults === null) return previousResults;
|
|
107
|
+
if (Array.isArray(previousResults) && Array.isArray(currentResults)) {
|
|
108
|
+
appendArrayItems(previousResults, currentResults);
|
|
109
|
+
return previousResults;
|
|
110
|
+
}
|
|
111
|
+
if (isPlainObject(previousResults) && isPlainObject(currentResults)) {
|
|
112
|
+
for (const key in currentResults) if (hasOwnProperty.call(currentResults, key)) previousResults[key] = mergeChunkResults(previousResults[key], currentResults[key]);
|
|
113
|
+
return previousResults;
|
|
114
|
+
}
|
|
115
|
+
return currentResults;
|
|
116
|
+
}
|
|
117
|
+
function cloneChunkResult(value) {
|
|
118
|
+
if (Array.isArray(value)) return value.slice();
|
|
119
|
+
if (isPlainObject(value)) {
|
|
120
|
+
const clone = {};
|
|
121
|
+
for (const key in value) if (hasOwnProperty.call(value, key)) clone[key] = cloneChunkResult(value[key]);
|
|
122
|
+
return clone;
|
|
123
|
+
}
|
|
124
|
+
return value;
|
|
125
|
+
}
|
|
126
|
+
function appendArrayItems(target, items) {
|
|
127
|
+
for (let i = 0; i < items.length; i++) target.push(items[i]);
|
|
128
|
+
}
|
|
129
|
+
function concatArrays(left, right) {
|
|
130
|
+
const result = new Array(left.length + right.length);
|
|
131
|
+
let index = 0;
|
|
132
|
+
for (let i = 0; i < left.length; i++) result[index++] = left[i];
|
|
133
|
+
for (let i = 0; i < right.length; i++) result[index++] = right[i];
|
|
134
|
+
return result;
|
|
135
|
+
}
|
|
136
|
+
function isPlainObject(value) {
|
|
137
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return false;
|
|
138
|
+
const prototype = Object.getPrototypeOf(value);
|
|
139
|
+
return prototype === Object.prototype || prototype === null;
|
|
140
|
+
}
|
|
141
|
+
function cloneFilter(filter) {
|
|
142
|
+
return JSON.parse(JSON.stringify(filter));
|
|
143
|
+
}
|
|
144
|
+
module.exports = {
|
|
145
|
+
asCallback,
|
|
146
|
+
concatResults,
|
|
147
|
+
createPromiseCallback,
|
|
148
|
+
downloadInChunks,
|
|
149
|
+
invokeWithCallback,
|
|
150
|
+
uploadInChunks
|
|
151
|
+
};
|
|
152
|
+
}));
|
|
153
|
+
//#endregion
|
|
154
|
+
module.exports = require_utils();
|