@vsaas/remoting 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.md +202 -0
- package/README.md +78 -0
- package/dist/_virtual/_rolldown/runtime.js +32 -0
- package/dist/ext/meta.d.ts +1 -0
- package/dist/ext/meta.js +39 -0
- package/dist/ext/meta.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +20 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/context-base.d.ts +1 -0
- package/dist/lib/context-base.js +30 -0
- package/dist/lib/context-base.js.map +1 -0
- package/dist/lib/deprecate.d.ts +1 -0
- package/dist/lib/deprecate.js +34 -0
- package/dist/lib/deprecate.js.map +1 -0
- package/dist/lib/escape-regexp.d.ts +1 -0
- package/dist/lib/escape-regexp.js +12 -0
- package/dist/lib/escape-regexp.js.map +1 -0
- package/dist/lib/exports-helper.d.ts +1 -0
- package/dist/lib/exports-helper.js +101 -0
- package/dist/lib/exports-helper.js.map +1 -0
- package/dist/lib/http-context.d.ts +1 -0
- package/dist/lib/http-context.js +484 -0
- package/dist/lib/http-context.js.map +1 -0
- package/dist/lib/http-invocation.d.ts +1 -0
- package/dist/lib/http-invocation.js +254 -0
- package/dist/lib/http-invocation.js.map +1 -0
- package/dist/lib/jsonrpc-adapter.d.ts +1 -0
- package/dist/lib/jsonrpc-adapter.js +187 -0
- package/dist/lib/jsonrpc-adapter.js.map +1 -0
- package/dist/lib/looks-like-json.d.ts +1 -0
- package/dist/lib/looks-like-json.js +22 -0
- package/dist/lib/looks-like-json.js.map +1 -0
- package/dist/lib/messages.d.ts +1 -0
- package/dist/lib/messages.js +24 -0
- package/dist/lib/messages.js.map +1 -0
- package/dist/lib/number-checks.d.ts +1 -0
- package/dist/lib/number-checks.js +18 -0
- package/dist/lib/number-checks.js.map +1 -0
- package/dist/lib/phases/merge-phase-name-lists.d.ts +5 -0
- package/dist/lib/phases/merge-phase-name-lists.d.ts.map +1 -0
- package/dist/lib/phases/merge-phase-name-lists.js +39 -0
- package/dist/lib/phases/merge-phase-name-lists.js.map +1 -0
- package/dist/lib/phases/phase-list.d.ts +27 -0
- package/dist/lib/phases/phase-list.d.ts.map +1 -0
- package/dist/lib/phases/phase-list.js +154 -0
- package/dist/lib/phases/phase-list.js.map +1 -0
- package/dist/lib/phases/phase.d.ts +24 -0
- package/dist/lib/phases/phase.d.ts.map +1 -0
- package/dist/lib/phases/phase.js +144 -0
- package/dist/lib/phases/phase.js.map +1 -0
- package/dist/lib/remote-objects.d.ts +1 -0
- package/dist/lib/remote-objects.js +642 -0
- package/dist/lib/remote-objects.js.map +1 -0
- package/dist/lib/rest-adapter-browser.d.ts +1 -0
- package/dist/lib/rest-adapter-browser.js +302 -0
- package/dist/lib/rest-adapter-browser.js.map +1 -0
- package/dist/lib/rest-adapter.d.ts +1 -0
- package/dist/lib/rest-adapter.js +519 -0
- package/dist/lib/rest-adapter.js.map +1 -0
- package/dist/lib/server-sent-events.d.ts +1 -0
- package/dist/lib/server-sent-events.js +61 -0
- package/dist/lib/server-sent-events.js.map +1 -0
- package/dist/lib/shared-class.d.ts +1 -0
- package/dist/lib/shared-class.js +207 -0
- package/dist/lib/shared-class.js.map +1 -0
- package/dist/lib/shared-method.d.ts +1 -0
- package/dist/lib/shared-method.js +469 -0
- package/dist/lib/shared-method.js.map +1 -0
- package/dist/lib/socket-io-adapter.d.ts +1 -0
- package/dist/lib/socket-io-adapter.js +93 -0
- package/dist/lib/socket-io-adapter.js.map +1 -0
- package/dist/lib/socket-io-context.d.ts +1 -0
- package/dist/lib/socket-io-context.js +94 -0
- package/dist/lib/socket-io-context.js.map +1 -0
- package/dist/lib/type-registry.d.ts +1 -0
- package/dist/lib/type-registry.js +99 -0
- package/dist/lib/type-registry.js.map +1 -0
- package/dist/lib/types/any.d.ts +1 -0
- package/dist/lib/types/any.js +44 -0
- package/dist/lib/types/any.js.map +1 -0
- package/dist/lib/types/array.d.ts +1 -0
- package/dist/lib/types/array.js +99 -0
- package/dist/lib/types/array.js.map +1 -0
- package/dist/lib/types/boolean.d.ts +1 -0
- package/dist/lib/types/boolean.js +37 -0
- package/dist/lib/types/boolean.js.map +1 -0
- package/dist/lib/types/date.d.ts +1 -0
- package/dist/lib/types/date.js +37 -0
- package/dist/lib/types/date.js.map +1 -0
- package/dist/lib/types/geopoint.d.ts +1 -0
- package/dist/lib/types/geopoint.js +68 -0
- package/dist/lib/types/geopoint.js.map +1 -0
- package/dist/lib/types/integer.d.ts +1 -0
- package/dist/lib/types/integer.js +36 -0
- package/dist/lib/types/integer.js.map +1 -0
- package/dist/lib/types/number.d.ts +1 -0
- package/dist/lib/types/number.js +30 -0
- package/dist/lib/types/number.js.map +1 -0
- package/dist/lib/types/object.d.ts +1 -0
- package/dist/lib/types/object.js +57 -0
- package/dist/lib/types/object.js.map +1 -0
- package/dist/lib/types/string.d.ts +1 -0
- package/dist/lib/types/string.js +29 -0
- package/dist/lib/types/string.js.map +1 -0
- package/dist/phases.d.ts +4 -0
- package/dist/phases.js +35 -0
- package/dist/phases.js.map +1 -0
- package/package.json +96 -0
|
@@ -0,0 +1,642 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
const require_runtime = require("../_virtual/_rolldown/runtime.js");
|
|
3
|
+
const require_lib_messages = require("./messages.js");
|
|
4
|
+
const require_lib_deprecate = require("./deprecate.js");
|
|
5
|
+
const require_lib_type_registry = require("./type-registry.js");
|
|
6
|
+
require("./shared-method.js");
|
|
7
|
+
const require_lib_shared_class = require("./shared-class.js");
|
|
8
|
+
const require_lib_exports_helper = require("./exports-helper.js");
|
|
9
|
+
const require_phases = require("../phases.js");
|
|
10
|
+
require("./rest-adapter.js");
|
|
11
|
+
//#region src/lib/remote-objects.ts
|
|
12
|
+
var require_remote_objects = /* @__PURE__ */ require_runtime.__commonJSMin(((exports, module) => {
|
|
13
|
+
const g = require_lib_messages;
|
|
14
|
+
/*!
|
|
15
|
+
* Expose `RemoteObjects`.
|
|
16
|
+
*/
|
|
17
|
+
module.exports = RemoteObjects;
|
|
18
|
+
/*!
|
|
19
|
+
* Module dependencies.
|
|
20
|
+
*/
|
|
21
|
+
const EventEmitter = require("eventemitter2").EventEmitter2;
|
|
22
|
+
const debug = require("debug")("strong-remoting:remotes");
|
|
23
|
+
const deprecated = require_lib_deprecate("strong-remoting");
|
|
24
|
+
const inherits = require("util").inherits;
|
|
25
|
+
const assert = require("assert");
|
|
26
|
+
const SharedClass = require_lib_shared_class;
|
|
27
|
+
const ExportsHelper = require_lib_exports_helper;
|
|
28
|
+
const PhaseList = (require_phases.init_phases(), require_runtime.__toCommonJS(require_phases.phases_exports)).PhaseList;
|
|
29
|
+
const TypeRegistry = require_lib_type_registry;
|
|
30
|
+
/**
|
|
31
|
+
* Create a new `RemoteObjects` with the given `options`.
|
|
32
|
+
*
|
|
33
|
+
* ```js
|
|
34
|
+
* var remoteObjects = require('strong-remoting').create();
|
|
35
|
+
* ```
|
|
36
|
+
*
|
|
37
|
+
* @param {Object} options
|
|
38
|
+
* @return {RemoteObjects}
|
|
39
|
+
* @class
|
|
40
|
+
* @property {Object} auth Authentication options used by underlying adapters
|
|
41
|
+
* to set authorization metadata. **The `rest` adapter supports:**
|
|
42
|
+
*
|
|
43
|
+
* - **basic** - `username` and `password` are required.
|
|
44
|
+
* - **digest** - `username` and `password` required and `sendImmediately` must
|
|
45
|
+
* be false.
|
|
46
|
+
* - **bearer** - `bearer` must be set as the bearer token
|
|
47
|
+
*
|
|
48
|
+
* @property {String} auth.username
|
|
49
|
+
* @property {String} auth.password
|
|
50
|
+
* @property {String} auth.bearer The **bearer token**.
|
|
51
|
+
* @property {Boolean} auth.sendImmediately Defaults to `false`.
|
|
52
|
+
*/
|
|
53
|
+
function RemoteObjects(options) {
|
|
54
|
+
EventEmitter.call(this, { wildcard: true });
|
|
55
|
+
this.setMaxListeners(16);
|
|
56
|
+
this.options = options || {};
|
|
57
|
+
this.exports = this.options.exports || {};
|
|
58
|
+
this._typeRegistry = new TypeRegistry(this.options.types);
|
|
59
|
+
this._classes = {};
|
|
60
|
+
this._setupPhases();
|
|
61
|
+
}
|
|
62
|
+
/*!
|
|
63
|
+
* Inherit from `EventEmitter`.
|
|
64
|
+
*/
|
|
65
|
+
inherits(RemoteObjects, EventEmitter);
|
|
66
|
+
/*!
|
|
67
|
+
* Simplified APIs
|
|
68
|
+
*/
|
|
69
|
+
RemoteObjects.create = function(options) {
|
|
70
|
+
return new RemoteObjects(options);
|
|
71
|
+
};
|
|
72
|
+
RemoteObjects.extend = function(exports$1) {
|
|
73
|
+
return new ExportsHelper(exports$1);
|
|
74
|
+
};
|
|
75
|
+
/**
|
|
76
|
+
* Create a handler from the given adapter.
|
|
77
|
+
*
|
|
78
|
+
* @param {String} nameOrClass Adapter name or provided adapter class
|
|
79
|
+
* @param {Object} options Adapter options
|
|
80
|
+
* @return {Function}
|
|
81
|
+
*/
|
|
82
|
+
RemoteObjects.prototype.handler = function(nameOrClass, options) {
|
|
83
|
+
const adapter = new (this.adapter(nameOrClass))(this, options);
|
|
84
|
+
const handler = adapter.createHandler();
|
|
85
|
+
if (handler) handler.adapter = adapter;
|
|
86
|
+
return handler;
|
|
87
|
+
};
|
|
88
|
+
/**
|
|
89
|
+
* Create a connection to a remoting server.
|
|
90
|
+
*
|
|
91
|
+
* @param {String} url Server root
|
|
92
|
+
* @param {String} name Name of the adapter (eg. "rest")
|
|
93
|
+
*/
|
|
94
|
+
RemoteObjects.prototype.connect = function(url, name) {
|
|
95
|
+
let urlWithoutAuth = url;
|
|
96
|
+
let auth;
|
|
97
|
+
const parsedUrl = URL.canParse(url) ? new URL(url) : null;
|
|
98
|
+
if (parsedUrl && (parsedUrl.username || parsedUrl.password)) {
|
|
99
|
+
auth = this.auth = {};
|
|
100
|
+
auth.username = parsedUrl.username;
|
|
101
|
+
auth.password = parsedUrl.password;
|
|
102
|
+
parsedUrl.username = "";
|
|
103
|
+
parsedUrl.password = "";
|
|
104
|
+
urlWithoutAuth = parsedUrl.toString();
|
|
105
|
+
if (url[url.length - 1] !== urlWithoutAuth[urlWithoutAuth.length - 1]) urlWithoutAuth = urlWithoutAuth.slice(0, -1);
|
|
106
|
+
}
|
|
107
|
+
const adapter = new (this.adapter(name))(this);
|
|
108
|
+
this.serverAdapter = adapter;
|
|
109
|
+
return adapter.connect(urlWithoutAuth);
|
|
110
|
+
};
|
|
111
|
+
/**
|
|
112
|
+
* Invoke a method on a remote server using the connected adapter.
|
|
113
|
+
*
|
|
114
|
+
* @param {String} method The remote method string
|
|
115
|
+
* @param {String} [ctorArgs] Constructor arguments (for prototype methods)
|
|
116
|
+
* @param {String} [args] Method arguments
|
|
117
|
+
* @callback {Function} [callback] callback
|
|
118
|
+
* @param {Error} err
|
|
119
|
+
* @param {Any} arg...
|
|
120
|
+
* @end
|
|
121
|
+
*/
|
|
122
|
+
RemoteObjects.prototype.invoke = function(method, ctorArgs, args, callback) {
|
|
123
|
+
assert(this.serverAdapter, g.f("Cannot invoke method without an adapter. See {{RemoteObjects#connect().}}"));
|
|
124
|
+
return this.serverAdapter.invoke.apply(this.serverAdapter, arguments, callback);
|
|
125
|
+
};
|
|
126
|
+
/**
|
|
127
|
+
* Get an adapter by name.
|
|
128
|
+
* @param {String} nameOrClass The adapter name or provided class
|
|
129
|
+
* @return {Adapter}
|
|
130
|
+
*/
|
|
131
|
+
RemoteObjects.prototype.adapter = function(nameOrClass) {
|
|
132
|
+
if (typeof nameOrClass === "function") {
|
|
133
|
+
this.validateAdapter(nameOrClass);
|
|
134
|
+
return nameOrClass;
|
|
135
|
+
} else {
|
|
136
|
+
const adapterModulePath = "./" + nameOrClass + "-adapter.js";
|
|
137
|
+
try {
|
|
138
|
+
return require(adapterModulePath);
|
|
139
|
+
} catch (error) {
|
|
140
|
+
if (!error || error.code !== "MODULE_NOT_FOUND" || !String(error.message || "").includes(adapterModulePath)) throw error;
|
|
141
|
+
return require("./" + nameOrClass + "-adapter");
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
};
|
|
145
|
+
RemoteObjects.prototype.getRequiredAdapterMethods = () => ["createHandler"];
|
|
146
|
+
RemoteObjects.prototype.validateAdapter = function(Adapter) {
|
|
147
|
+
const notImplementedMethods = this.getRequiredAdapterMethods().filter((methodString) => typeof Adapter.prototype[methodString] !== "function");
|
|
148
|
+
if (notImplementedMethods.length > 0) throw new Error(g.f("Invalid adapter class. The provided adapter class does not implement the following required methods: %s", notImplementedMethods.join(", ")));
|
|
149
|
+
return Adapter;
|
|
150
|
+
};
|
|
151
|
+
/**
|
|
152
|
+
* Get all classes.
|
|
153
|
+
*/
|
|
154
|
+
RemoteObjects.prototype.classes = function(options) {
|
|
155
|
+
options = options || {};
|
|
156
|
+
const exports$2 = this.exports;
|
|
157
|
+
const result = [];
|
|
158
|
+
const sharedClasses = this._classes;
|
|
159
|
+
const exportNames = Object.keys(exports$2);
|
|
160
|
+
const sharedClassNames = Object.keys(sharedClasses);
|
|
161
|
+
for (let i = 0; i < exportNames.length; i++) {
|
|
162
|
+
const name = exportNames[i];
|
|
163
|
+
result.push(new SharedClass(name, exports$2[name], options));
|
|
164
|
+
}
|
|
165
|
+
for (let i = 0; i < sharedClassNames.length; i++) result.push(sharedClasses[sharedClassNames[i]]);
|
|
166
|
+
return result;
|
|
167
|
+
};
|
|
168
|
+
/**
|
|
169
|
+
* Add a shared class.
|
|
170
|
+
*
|
|
171
|
+
* @param {SharedClass} sharedClass
|
|
172
|
+
*/
|
|
173
|
+
RemoteObjects.prototype.addClass = function(sharedClass) {
|
|
174
|
+
assert(sharedClass && sharedClass.constructor.name === "SharedClass", g.f("must provide a valid {{SharedClass}}"));
|
|
175
|
+
this._classes[sharedClass.name] = sharedClass;
|
|
176
|
+
};
|
|
177
|
+
/**
|
|
178
|
+
* Remove a previously-registered shared class.
|
|
179
|
+
*
|
|
180
|
+
* @param {string} className The name of the shared class to remove.
|
|
181
|
+
*/
|
|
182
|
+
RemoteObjects.prototype.deleteClassByName = function(className) {
|
|
183
|
+
delete this._classes[className];
|
|
184
|
+
Object.keys(this.listenerTree).forEach((hooktype) => {
|
|
185
|
+
delete this.listenerTree[hooktype][className];
|
|
186
|
+
});
|
|
187
|
+
};
|
|
188
|
+
/**
|
|
189
|
+
* Find a method by its string name.
|
|
190
|
+
*
|
|
191
|
+
* @param {String} methodString String specifying the method. For example:
|
|
192
|
+
*
|
|
193
|
+
* - `MyClass.prototype.myMethod`
|
|
194
|
+
* - `MyClass.staticMethod`
|
|
195
|
+
* - `obj.method`
|
|
196
|
+
*/
|
|
197
|
+
RemoteObjects.prototype.findMethod = function(methodString) {
|
|
198
|
+
const classes = this.classes();
|
|
199
|
+
for (let i = 0; i < classes.length; i++) {
|
|
200
|
+
const methods = classes[i].methods();
|
|
201
|
+
for (let j = 0; j < methods.length; j++) if (methods[j].stringName === methodString) return methods[j];
|
|
202
|
+
}
|
|
203
|
+
};
|
|
204
|
+
/**
|
|
205
|
+
* List all methods.
|
|
206
|
+
*/
|
|
207
|
+
RemoteObjects.prototype.methods = function() {
|
|
208
|
+
const methods = [];
|
|
209
|
+
const classes = this.classes();
|
|
210
|
+
for (let i = 0; i < classes.length; i++) {
|
|
211
|
+
const classMethods = classes[i].methods();
|
|
212
|
+
for (let j = 0; j < classMethods.length; j++) methods.push(classMethods[j]);
|
|
213
|
+
}
|
|
214
|
+
return methods;
|
|
215
|
+
};
|
|
216
|
+
/**
|
|
217
|
+
* Get as JSON.
|
|
218
|
+
*/
|
|
219
|
+
RemoteObjects.prototype.toJSON = function() {
|
|
220
|
+
const result = {};
|
|
221
|
+
const methods = this.methods();
|
|
222
|
+
for (let i = 0; i < methods.length; i++) {
|
|
223
|
+
const sharedMethod = methods[i];
|
|
224
|
+
result[sharedMethod.stringName] = {
|
|
225
|
+
http: sharedMethod.fn && sharedMethod.fn.http,
|
|
226
|
+
accepts: sharedMethod.accepts,
|
|
227
|
+
returns: sharedMethod.returns,
|
|
228
|
+
errors: sharedMethod.errors
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
return result;
|
|
232
|
+
};
|
|
233
|
+
/**
|
|
234
|
+
* Execute the given function before the matched method string.
|
|
235
|
+
*
|
|
236
|
+
* @example
|
|
237
|
+
*
|
|
238
|
+
* Do something before the `user.greet` method is called:
|
|
239
|
+
* ```js
|
|
240
|
+
* remotes.before('user.greet', function(ctx, next) {
|
|
241
|
+
* if ((ctx.req.param('password') || '').toString() !== '1234') {
|
|
242
|
+
* next(new Error('Bad password!'));
|
|
243
|
+
* } else {
|
|
244
|
+
* next();
|
|
245
|
+
* }
|
|
246
|
+
* });
|
|
247
|
+
* ```
|
|
248
|
+
*
|
|
249
|
+
* Do something before any `user` method:
|
|
250
|
+
* ```js
|
|
251
|
+
* remotes.before('user.*', function(ctx, next) {
|
|
252
|
+
* console.log('Calling a user method.');
|
|
253
|
+
* next();
|
|
254
|
+
* });
|
|
255
|
+
* ```
|
|
256
|
+
*
|
|
257
|
+
* Do something before a `dog` instance method:
|
|
258
|
+
* ```js
|
|
259
|
+
* remotes.before('dog.prototype.*', function(ctx, next) {
|
|
260
|
+
* var dog = this;
|
|
261
|
+
* console.log('Calling a method on "%s".', dog.name);
|
|
262
|
+
* next();
|
|
263
|
+
* });
|
|
264
|
+
* ```
|
|
265
|
+
*
|
|
266
|
+
* @param {String} methodMatch The glob to match a method string
|
|
267
|
+
* @callback {Function} hook
|
|
268
|
+
* @param {Context} ctx The adapter specific context
|
|
269
|
+
* @param {Function} next Call with an optional error object
|
|
270
|
+
* @param {SharedMethod} method The SharedMethod object
|
|
271
|
+
*/
|
|
272
|
+
RemoteObjects.prototype.before = function(methodMatch, fn) {
|
|
273
|
+
this.on("before." + methodMatch, fn);
|
|
274
|
+
};
|
|
275
|
+
/**
|
|
276
|
+
* Execute the given `hook` function after the matched method string.
|
|
277
|
+
*
|
|
278
|
+
* @example
|
|
279
|
+
*
|
|
280
|
+
* Do something after the `speak` instance method.
|
|
281
|
+
* NOTE: you cannot cancel a method after it has been called.
|
|
282
|
+
* ```js
|
|
283
|
+
* remotes.after('dog.prototype.speak', function(ctx, next) {
|
|
284
|
+
* console.log('After speak!');
|
|
285
|
+
* next();
|
|
286
|
+
* });
|
|
287
|
+
*```
|
|
288
|
+
*
|
|
289
|
+
* Do something before all methods.
|
|
290
|
+
```js
|
|
291
|
+
* remotes.before('**', function(ctx, next, method) {
|
|
292
|
+
* console.log('Calling:', method.name);
|
|
293
|
+
* next();
|
|
294
|
+
* });
|
|
295
|
+
* ```
|
|
296
|
+
*
|
|
297
|
+
* Modify all returned values named `result`.
|
|
298
|
+
* ```js
|
|
299
|
+
* remotes.after('**', function(ctx, next) {
|
|
300
|
+
* ctx.result += '!!!';
|
|
301
|
+
* next();
|
|
302
|
+
* });
|
|
303
|
+
* ```
|
|
304
|
+
*
|
|
305
|
+
* @param {String} methodMatch The glob to match a method string
|
|
306
|
+
* @callback {Function} hook
|
|
307
|
+
* @param {Context} ctx The adapter specific context
|
|
308
|
+
* @param {Function} next Call with an optional error object
|
|
309
|
+
* @param {SharedMethod} method The SharedMethod object
|
|
310
|
+
*/
|
|
311
|
+
RemoteObjects.prototype.after = function(methodMatch, fn) {
|
|
312
|
+
this.on("after." + methodMatch, fn);
|
|
313
|
+
};
|
|
314
|
+
/**
|
|
315
|
+
* Execute the given `hook` function after the method matched by the method
|
|
316
|
+
* string failed.
|
|
317
|
+
*
|
|
318
|
+
* @example
|
|
319
|
+
* Do something after the `speak` instance method failed.
|
|
320
|
+
*
|
|
321
|
+
* ```js
|
|
322
|
+
* remotes.afterError('dog.prototype.speak', function(ctx, next) {
|
|
323
|
+
* console.log('Cannot speak!', ctx.error);
|
|
324
|
+
* next();
|
|
325
|
+
* });
|
|
326
|
+
* ```
|
|
327
|
+
*
|
|
328
|
+
* Do something before all methods:
|
|
329
|
+
* ```js
|
|
330
|
+
* remotes.afterError('**', function(ctx, next, method) {
|
|
331
|
+
* console.log('Failed', method.name, ctx.error);
|
|
332
|
+
* next();
|
|
333
|
+
* });
|
|
334
|
+
* ```
|
|
335
|
+
*
|
|
336
|
+
* Modify all returned errors:
|
|
337
|
+
* ```js
|
|
338
|
+
* remotes.after('**', function(ctx, next) {
|
|
339
|
+
* if (!ctx.error.details) ctx.result.details = {};
|
|
340
|
+
* ctx.error.details.info = 'intercepted by a hook';
|
|
341
|
+
* next();
|
|
342
|
+
* });
|
|
343
|
+
* ```
|
|
344
|
+
*
|
|
345
|
+
* Report a different error:
|
|
346
|
+
* ```js
|
|
347
|
+
* remotes.after('dog.prototype.speak', function(ctx, next) {
|
|
348
|
+
* console.error(ctx.error);
|
|
349
|
+
* next(new Error('See server console log for details.'));
|
|
350
|
+
* });
|
|
351
|
+
* ```
|
|
352
|
+
*
|
|
353
|
+
* @param {String} methodMatch The glob to match a method string
|
|
354
|
+
* @callback {Function} hook
|
|
355
|
+
* @param {Context} ctx The adapter specific context
|
|
356
|
+
* @param {Function} next Call with an optional error object
|
|
357
|
+
* @param {SharedMethod} method The SharedMethod object
|
|
358
|
+
*/
|
|
359
|
+
RemoteObjects.prototype.afterError = function(methodMatch, fn) {
|
|
360
|
+
this.on("afterError." + methodMatch, fn);
|
|
361
|
+
};
|
|
362
|
+
RemoteObjects.prototype.registerPhaseHandler = function(phaseName, methodNameWildcard, handler) {
|
|
363
|
+
const pattern = methodNameWildcard.replace(/[.+?^${}()|[\]\\]/g, "\\$&").replace(/(^|\.)\*($|\.)/g, "$1[^.]*$2").replace(/(^|\.)\*\*($|\.)/g, "$1.*$2");
|
|
364
|
+
const matcher = new RegExp("^" + pattern + "$");
|
|
365
|
+
debug("registerPhaseHandler(%j) -> pattern %j", methodNameWildcard, pattern);
|
|
366
|
+
this.phases.registerHandler(phaseName, function matchHandler(ctx, next) {
|
|
367
|
+
if (matcher.test(ctx.method.stringName)) handler(ctx, next);
|
|
368
|
+
else next();
|
|
369
|
+
});
|
|
370
|
+
};
|
|
371
|
+
/*!
|
|
372
|
+
* Create a middleware style emit that supports wildcards.
|
|
373
|
+
*/
|
|
374
|
+
RemoteObjects.prototype.execHooks = function(when, method, scope, ctx, next) {
|
|
375
|
+
let stack;
|
|
376
|
+
let stackIndex = 0;
|
|
377
|
+
let stackLength = 0;
|
|
378
|
+
const isStatic = method.isStatic || method.sharedMethod && method.sharedMethod.isStatic;
|
|
379
|
+
let type, handler;
|
|
380
|
+
this.objectName = method.sharedClass && method.sharedClass.name || method.restClass && method.restClass.name;
|
|
381
|
+
this.methodName = method.name;
|
|
382
|
+
if (method.fullName) type = when + "." + method.fullName;
|
|
383
|
+
else type = when + "." + this.objectName + (isStatic ? "." : ".prototype.") + this.methodName;
|
|
384
|
+
if (this.wildcard) {
|
|
385
|
+
stack = [];
|
|
386
|
+
const ns = typeof type === "string" ? type.split(this.delimiter) : type.slice();
|
|
387
|
+
searchListenerTree.call(this, stack, ns, this.listenerTree, 0);
|
|
388
|
+
} else {
|
|
389
|
+
handler = this._events[type];
|
|
390
|
+
if (typeof handler === "function") {
|
|
391
|
+
this.event = type;
|
|
392
|
+
stack = [handler];
|
|
393
|
+
} else if (handler) stack = handler;
|
|
394
|
+
else return next();
|
|
395
|
+
}
|
|
396
|
+
stackLength = stack.length;
|
|
397
|
+
if (stackLength === 0) return next();
|
|
398
|
+
function execStack(err) {
|
|
399
|
+
if (err) return next(err);
|
|
400
|
+
if (stackIndex >= stackLength) {
|
|
401
|
+
next();
|
|
402
|
+
return;
|
|
403
|
+
}
|
|
404
|
+
const cur = stack[stackIndex++];
|
|
405
|
+
if (!cur) {
|
|
406
|
+
execStack();
|
|
407
|
+
return;
|
|
408
|
+
}
|
|
409
|
+
let hookCompleted = false;
|
|
410
|
+
try {
|
|
411
|
+
const advance = function(advanceErr) {
|
|
412
|
+
if (hookCompleted) return;
|
|
413
|
+
hookCompleted = true;
|
|
414
|
+
execStack(advanceErr);
|
|
415
|
+
};
|
|
416
|
+
const result = cur.call(scope, ctx, advance, method);
|
|
417
|
+
if (result && typeof result.then === "function") result.then(function() {
|
|
418
|
+
advance();
|
|
419
|
+
}, function(promiseErr) {
|
|
420
|
+
advance(promiseErr);
|
|
421
|
+
});
|
|
422
|
+
} catch (err) {
|
|
423
|
+
if (!hookCompleted) next(err);
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
return execStack();
|
|
427
|
+
};
|
|
428
|
+
function searchListenerTree(handlers, type, tree, i) {
|
|
429
|
+
if (!tree) return;
|
|
430
|
+
let leaf, len, branch, isolatedBranch, endReached;
|
|
431
|
+
const typeLength = type.length;
|
|
432
|
+
const currentType = type[i];
|
|
433
|
+
const nextType = type[i + 1];
|
|
434
|
+
if (i === typeLength && tree._listeners) if (typeof tree._listeners === "function") {
|
|
435
|
+
if (handlers) handlers.push(tree._listeners);
|
|
436
|
+
return;
|
|
437
|
+
} else {
|
|
438
|
+
for (leaf = 0, len = tree._listeners.length; leaf < len; leaf++) if (handlers) handlers.push(tree._listeners[leaf]);
|
|
439
|
+
return;
|
|
440
|
+
}
|
|
441
|
+
if (currentType === "*" || currentType === "**" || tree[currentType]) {
|
|
442
|
+
if (currentType === "*") {
|
|
443
|
+
for (branch in tree) if (branch !== "_listeners" && Object.prototype.hasOwnProperty.call(tree, branch)) searchListenerTree(handlers, type, tree[branch], i + 1);
|
|
444
|
+
return;
|
|
445
|
+
} else if (currentType === "**") {
|
|
446
|
+
endReached = i + 1 === typeLength || i + 2 === typeLength && nextType === "*";
|
|
447
|
+
if (endReached && tree._listeners) searchListenerTree(handlers, type, tree, typeLength);
|
|
448
|
+
for (branch in tree) if (branch !== "_listeners" && Object.prototype.hasOwnProperty.call(tree, branch)) if (branch === "*" || branch === "**") {
|
|
449
|
+
if (tree[branch]._listeners && !endReached) searchListenerTree(handlers, type, tree[branch], typeLength);
|
|
450
|
+
searchListenerTree(handlers, type, tree[branch], i);
|
|
451
|
+
} else if (branch === nextType) searchListenerTree(handlers, type, tree[branch], i + 2);
|
|
452
|
+
else searchListenerTree(handlers, type, tree[branch], i);
|
|
453
|
+
return;
|
|
454
|
+
}
|
|
455
|
+
searchListenerTree(handlers, type, tree[currentType], i + 1);
|
|
456
|
+
}
|
|
457
|
+
const xTree = tree["*"];
|
|
458
|
+
if (xTree) searchListenerTree(handlers, type, xTree, i + 1);
|
|
459
|
+
const xxTree = tree["**"];
|
|
460
|
+
if (xxTree) {
|
|
461
|
+
if (i < typeLength) {
|
|
462
|
+
if (xxTree._listeners) searchListenerTree(handlers, type, xxTree, typeLength);
|
|
463
|
+
for (branch in xxTree) if (branch !== "_listeners" && Object.prototype.hasOwnProperty.call(xxTree, branch)) if (branch === nextType) searchListenerTree(handlers, type, xxTree[branch], i + 2);
|
|
464
|
+
else if (branch === currentType) searchListenerTree(handlers, type, xxTree[branch], i + 1);
|
|
465
|
+
else {
|
|
466
|
+
isolatedBranch = {};
|
|
467
|
+
isolatedBranch[branch] = xxTree[branch];
|
|
468
|
+
searchListenerTree(handlers, type, { "**": isolatedBranch }, i + 1);
|
|
469
|
+
}
|
|
470
|
+
} else if (xxTree._listeners) searchListenerTree(handlers, type, xxTree, typeLength);
|
|
471
|
+
else if (xxTree["*"] && xxTree["*"]._listeners) searchListenerTree(handlers, type, xxTree["*"], typeLength);
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
RemoteObjects.prototype._executeAuthorizationHook = function(ctx, cb) {
|
|
475
|
+
if (typeof this.authorization === "function") this.authorization(ctx, cb);
|
|
476
|
+
else process.nextTick(function() {
|
|
477
|
+
cb();
|
|
478
|
+
});
|
|
479
|
+
};
|
|
480
|
+
RemoteObjects.prototype._setupPhases = function() {
|
|
481
|
+
const self = this;
|
|
482
|
+
self.phases = new PhaseList();
|
|
483
|
+
const auth = self.phases.add("auth");
|
|
484
|
+
const invoke = self.phases.add("invoke");
|
|
485
|
+
auth.use(function phaseAuthorization(ctx, next) {
|
|
486
|
+
self._executeAuthorizationHook(ctx, next);
|
|
487
|
+
});
|
|
488
|
+
invoke.before(function reportSharedCtorError(ctx, next) {
|
|
489
|
+
next(ctx.sharedCtorError);
|
|
490
|
+
});
|
|
491
|
+
invoke.before(function phaseBeforeInvoke(ctx, next) {
|
|
492
|
+
self.execHooks("before", ctx.method, ctx.getScope(), ctx, next);
|
|
493
|
+
});
|
|
494
|
+
invoke.use(function phaseInvoke(ctx, next) {
|
|
495
|
+
ctx.invoke(ctx.getScope(), ctx.method, function(err, result) {
|
|
496
|
+
if (!err) ctx.result = result;
|
|
497
|
+
next(err);
|
|
498
|
+
});
|
|
499
|
+
});
|
|
500
|
+
invoke.after(function phaseAfterInvoke(ctx, next) {
|
|
501
|
+
self.execHooks("after", ctx.method, ctx.getScope(), ctx, next);
|
|
502
|
+
});
|
|
503
|
+
};
|
|
504
|
+
/**
|
|
505
|
+
* Invoke the given shared method using the supplied context.
|
|
506
|
+
* Execute registered before/after hooks.
|
|
507
|
+
*
|
|
508
|
+
* @param {Object} ctx
|
|
509
|
+
* @param {Object} method
|
|
510
|
+
* @param {function(Error=)} cb
|
|
511
|
+
*/
|
|
512
|
+
RemoteObjects.prototype.invokeMethodInContext = function(ctx, method, cb) {
|
|
513
|
+
const self = this;
|
|
514
|
+
const scope = ctx.getScope();
|
|
515
|
+
if (cb === void 0 && typeof method === "function") {
|
|
516
|
+
cb = method;
|
|
517
|
+
method = ctx.method;
|
|
518
|
+
} else {
|
|
519
|
+
assert.equal(method, ctx.method);
|
|
520
|
+
deprecated("invokeMethodInContext(ctx, method, cb) is deprecated.Pass the method as ctx.method instead.");
|
|
521
|
+
}
|
|
522
|
+
self.phases.run(ctx, function interceptInvocationErrors(err) {
|
|
523
|
+
if (!err) return cb();
|
|
524
|
+
ctx.error = err;
|
|
525
|
+
self.execHooks("afterError", method, scope, ctx, function(hookErr) {
|
|
526
|
+
cb(hookErr || err);
|
|
527
|
+
});
|
|
528
|
+
});
|
|
529
|
+
};
|
|
530
|
+
/**
|
|
531
|
+
* Determine what scope object to use when invoking the given remote method in
|
|
532
|
+
* the given context.
|
|
533
|
+
* @private
|
|
534
|
+
*/
|
|
535
|
+
RemoteObjects.prototype.getScope = function(ctx, method) {
|
|
536
|
+
deprecated("remoteObjects.getScope(ctx, method) is deprecated, use ctx.getScope() instead");
|
|
537
|
+
assert.equal(ctx.method, method);
|
|
538
|
+
return ctx.getScope();
|
|
539
|
+
};
|
|
540
|
+
/**
|
|
541
|
+
* Define a named type conversion. The conversion is used when a
|
|
542
|
+
* `SharedMethod` argument defines a type with the given `name`.
|
|
543
|
+
*
|
|
544
|
+
* See also `remotes.defineObjectType`.
|
|
545
|
+
*
|
|
546
|
+
* @example
|
|
547
|
+
*
|
|
548
|
+
* ```js
|
|
549
|
+
* remotes.defineType('MyType', {
|
|
550
|
+
* // Convert the raw "value" coming typically from JSON.
|
|
551
|
+
* // Use the remoting context in "ctx" to access the type registry and
|
|
552
|
+
* // other request-related information.
|
|
553
|
+
* fromTypedValue: function(ctx, value) {
|
|
554
|
+
* if (value === undefined || value === null)
|
|
555
|
+
* return { value: value };
|
|
556
|
+
*
|
|
557
|
+
* value = new MyType(value);
|
|
558
|
+
* var error = this.validate(ctx, value);
|
|
559
|
+
* return error ? { error: error } : { value: value };
|
|
560
|
+
* },
|
|
561
|
+
*
|
|
562
|
+
* // Apply any coercion needed to convert values coming from
|
|
563
|
+
* // string-only sources like HTTP headers and query string.
|
|
564
|
+
* //
|
|
565
|
+
* // A sloppy value is one of:
|
|
566
|
+
* // - a string
|
|
567
|
+
* // - an array containing sloppy values
|
|
568
|
+
* // - an object where property values are sloppy
|
|
569
|
+
* fromSloppyValue: function(ctx, value) {
|
|
570
|
+
* var objectConverter = ctx.typeRegistry.getConverter('object');
|
|
571
|
+
* var result = objectConverter.fromSloppyString(ctx, value);
|
|
572
|
+
* return result.error ? result : this.fromTypedValue(ctx, result.value);
|
|
573
|
+
* },
|
|
574
|
+
*
|
|
575
|
+
* // Perform basic validation of the value. Validations are required to be
|
|
576
|
+
* // synchronous.
|
|
577
|
+
* validate: function(ctx, value) {
|
|
578
|
+
* if (value === undefined || value === null)
|
|
579
|
+
* return null;
|
|
580
|
+
* if (typeof value !== 'object' || !(value instanceof MyType) {
|
|
581
|
+
* return new Error('Value is not an instance of MyType.');
|
|
582
|
+
* }
|
|
583
|
+
* return null;
|
|
584
|
+
* },
|
|
585
|
+
* });
|
|
586
|
+
* ```
|
|
587
|
+
*
|
|
588
|
+
* @param {String} name The type name
|
|
589
|
+
* @param {Object} converter A converter implementing the following methods:
|
|
590
|
+
*
|
|
591
|
+
* - `fromTypedValue(ctx, value) -> { value } or { error }`
|
|
592
|
+
* - `fromSloppyValue(ctx, value) -> { value } or { error }`
|
|
593
|
+
* - `validate(ctx, value) -> error or undefined/null`
|
|
594
|
+
*/
|
|
595
|
+
RemoteObjects.prototype.defineType = function(name, converter) {
|
|
596
|
+
if (typeof converter === "function") throw new Error(g.f("%s is no longer supported. Use one of the new APIs instead: %s or %s", "remoteObjects.defineType(name, fn)", "remoteObjects.defineObjectType(name, factoryFn)", "remoteObjects.defineType(name, converter)"));
|
|
597
|
+
this._typeRegistry.defineType(name, converter);
|
|
598
|
+
};
|
|
599
|
+
/**
|
|
600
|
+
* Define a named type conversion for an object-like type.
|
|
601
|
+
* The conversion is used when a `SharedMethod` argument
|
|
602
|
+
* defines a type with the given `name`.
|
|
603
|
+
*
|
|
604
|
+
* Under the hood, a converter is created that ensures the input data
|
|
605
|
+
* is an object (or sloppy value is coerced to an object) and calls
|
|
606
|
+
* the provided factory function to convert plain data object to
|
|
607
|
+
* a class instance.
|
|
608
|
+
*
|
|
609
|
+
* @example
|
|
610
|
+
*
|
|
611
|
+
* ```js
|
|
612
|
+
* remotes.defineObjectType('MyClass', function(data) {
|
|
613
|
+
* return new MyClass(data);
|
|
614
|
+
* });
|
|
615
|
+
* ```
|
|
616
|
+
*
|
|
617
|
+
* @param {String} name The type name
|
|
618
|
+
* @param {Function(Object)} factoryFn Factory function creating object
|
|
619
|
+
* instance from a plain-data object.
|
|
620
|
+
*/
|
|
621
|
+
RemoteObjects.prototype.defineObjectType = function(name, factoryFn) {
|
|
622
|
+
this._typeRegistry.registerObjectType(name, factoryFn);
|
|
623
|
+
};
|
|
624
|
+
/**
|
|
625
|
+
* Remove a type registered via `defineType` or `defineObjectType`.
|
|
626
|
+
*
|
|
627
|
+
* @param {String} name The type name.
|
|
628
|
+
*/
|
|
629
|
+
RemoteObjects.prototype.deleteTypeByName = function(name) {
|
|
630
|
+
delete this._typeRegistry._types[name.toLowerCase()];
|
|
631
|
+
};
|
|
632
|
+
RemoteObjects.convert = RemoteObjects.prototype.convert = function(name, fn) {
|
|
633
|
+
throw new Error(g.f("RemoteObjects.convert(name, fn) is no longer supported. Use remoteObjects.defineType(name, converter) instead."));
|
|
634
|
+
};
|
|
635
|
+
RemoteObjects.defineType = function(name, fn) {
|
|
636
|
+
throw new Error(g.f("RemoteObjects.defineType(name, fn) is no longer supported. Use remoteObjects.defineType(name, converter) instead."));
|
|
637
|
+
};
|
|
638
|
+
}));
|
|
639
|
+
//#endregion
|
|
640
|
+
module.exports = require_remote_objects();
|
|
641
|
+
|
|
642
|
+
//# sourceMappingURL=remote-objects.js.map
|