scoundrel-remote-eval 1.0.8 → 1.0.9

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.
Files changed (47) hide show
  1. package/build/client/connections/web-socket/index.d.ts +34 -0
  2. package/build/client/connections/web-socket/index.d.ts.map +1 -0
  3. package/build/client/connections/web-socket/index.js +68 -0
  4. package/build/client/index.d.ts +180 -0
  5. package/build/client/index.d.ts.map +1 -0
  6. package/build/client/index.js +413 -0
  7. package/build/client/reference-proxy.d.ts +7 -0
  8. package/build/client/reference-proxy.d.ts.map +1 -0
  9. package/build/client/reference-proxy.js +45 -0
  10. package/build/client/reference.d.ts +50 -0
  11. package/build/client/reference.d.ts.map +1 -0
  12. package/build/client/reference.js +63 -0
  13. package/build/index.d.ts +2 -0
  14. package/build/index.d.ts.map +1 -0
  15. package/build/index.js +1 -0
  16. package/build/logger.d.ts +39 -0
  17. package/build/logger.d.ts.map +1 -0
  18. package/build/logger.js +64 -0
  19. package/build/python-web-socket-runner.d.ts +27 -0
  20. package/build/python-web-socket-runner.d.ts.map +1 -0
  21. package/build/python-web-socket-runner.js +94 -0
  22. package/build/server/connections/web-socket/client.d.ts +26 -0
  23. package/build/server/connections/web-socket/client.d.ts.map +1 -0
  24. package/build/server/connections/web-socket/client.js +39 -0
  25. package/build/server/connections/web-socket/index.d.ts +19 -0
  26. package/build/server/connections/web-socket/index.d.ts.map +1 -0
  27. package/build/server/connections/web-socket/index.js +29 -0
  28. package/build/server/index.d.ts +20 -0
  29. package/build/server/index.d.ts.map +1 -0
  30. package/build/server/index.js +26 -0
  31. package/package.json +8 -3
  32. package/eslint.config.js +0 -18
  33. package/spec/reference-with-proxy-spec.js +0 -101
  34. package/spec/support/jasmine.json +0 -13
  35. package/spec/web-socket-javascript-spec.js +0 -66
  36. package/spec/web-socket-python-spec.js +0 -57
  37. package/src/client/connections/web-socket/index.js +0 -88
  38. package/src/client/index.js +0 -469
  39. package/src/client/reference-proxy.js +0 -53
  40. package/src/client/reference.js +0 -69
  41. package/src/index.js +0 -0
  42. package/src/logger.js +0 -70
  43. package/src/python-web-socket-runner.js +0 -116
  44. package/src/server/connections/web-socket/client.js +0 -46
  45. package/src/server/connections/web-socket/index.js +0 -34
  46. package/src/server/index.js +0 -33
  47. package/tsconfig.json +0 -13
@@ -1,469 +0,0 @@
1
- // @ts-check
2
-
3
- import Logger from "../logger.js"
4
- import Reference from "./reference.js"
5
-
6
- const logger = new Logger("Scoundrel Client")
7
-
8
- // logger.setDebug(true)
9
-
10
- export default class Client {
11
- /**
12
- * Creates a new Scoundrel Client
13
- *
14
- * @param {any} backend The backend connection (e.g., WebSocket)
15
- */
16
- constructor(backend) {
17
- this.backend = backend
18
- this.backend.onCommand(this.onCommand)
19
-
20
- /** @type {Record<number, any>} */
21
- this.outgoingCommands = {}
22
- this.incomingCommands = {}
23
- this.outgoingCommandsCount = 0
24
-
25
- /** @type {Record<string, any>} */
26
- this._classes = {}
27
-
28
- /** @type {Record<string, any>} */
29
- this._objects = {}
30
-
31
- /** @type {Record<string, Reference>} */
32
- this.references = {}
33
-
34
- /** @type {Record<number, any>} */
35
- this.objects = {}
36
-
37
- this.objectsCount = 0
38
- }
39
-
40
- /**
41
- * Closes the client connection
42
- */
43
- async close() {
44
- this.backend.close()
45
- }
46
-
47
- /**
48
- * Calls a method on a reference and returns the result directly
49
- *
50
- * @param {number} referenceId
51
- * @param {string} methodName
52
- * @param {...any} args
53
- * @returns {Promise<any>}
54
- */
55
- async callMethodOnReference(referenceId, methodName, ...args) {
56
- const result = await this.sendCommand("call_method_on_reference", {
57
- args: this.parseArg(args),
58
- method_name: methodName,
59
- reference_id: referenceId,
60
- with: "result"
61
- })
62
-
63
- return result.response
64
- }
65
-
66
- /**
67
- * Calls a method on a reference and returns a new reference
68
- *
69
- * @param {number} referenceId
70
- * @param {string} methodName
71
- * @param {...any} args
72
- * @returns {Promise<Reference>}
73
- */
74
- async callMethodOnReferenceWithReference(referenceId, methodName, ...args) {
75
- const result = await this.sendCommand("call_method_on_reference", {
76
- args: this.parseArg(args),
77
- method_name: methodName,
78
- reference_id: referenceId,
79
- with: "reference"
80
- })
81
- const id = result.response
82
-
83
- return this.spawnReference(id)
84
- }
85
-
86
- /**
87
- * Evaluates a string and returns a new reference
88
- *
89
- * @param {string} evalString
90
- * @returns {Promise<Reference>}
91
- */
92
- async evalWithReference(evalString) {
93
- const result = await this.sendCommand("eval", {
94
- eval_string: evalString,
95
- with_reference: true
96
- })
97
- const id = result.object_id
98
-
99
- return this.spawnReference(id)
100
- }
101
-
102
- /**
103
- * Imports a module and returns a reference to it
104
- *
105
- * @param {string} importName
106
- * @returns {Promise<Reference>}
107
- */
108
- async import(importName) {
109
- const result = await this.sendCommand("import", {
110
- import_name: importName
111
- })
112
-
113
- logger.log(() => ["import", {result}])
114
-
115
- if (!result) throw new Error("No result given")
116
- if (!result.object_id) throw new Error(`No object ID given in result: ${JSON.stringify(result)}`)
117
-
118
- const id = result.object_id
119
-
120
- return this.spawnReference(id)
121
- }
122
-
123
- /**
124
- * Gets a registered object by name
125
- *
126
- * @param {string} objectName
127
- * @returns {Promise<Reference>}
128
- */
129
- async getObject(objectName) {
130
- const result = await this.sendCommand("get_object", {
131
- object_name: objectName
132
- })
133
-
134
- if (!result) throw new Error("Blank result given")
135
-
136
- const id = result.object_id
137
-
138
- return this.spawnReference(id)
139
- }
140
-
141
- /**
142
- * Spawns a new reference to an object
143
- *
144
- * @param {string} className
145
- * @param {...any} args
146
- * @returns {Promise<Reference>}
147
- */
148
- async newObjectWithReference(className, ...args) {
149
- const result = await this.sendCommand("new_object_with_reference", {
150
- args: this.parseArg(args),
151
- class_name: className
152
- })
153
-
154
- if (!result) throw new Error("Blank result given")
155
-
156
- const id = result.object_id
157
-
158
- if (!id) throw new Error(`No object ID given in result: ${JSON.stringify(result)}`)
159
-
160
- return this.spawnReference(id)
161
- }
162
-
163
- /**
164
- * Checks if the input is a plain object
165
- * @param {any} input
166
- * @returns {boolean}
167
- */
168
- isPlainObject(input) {
169
- if (input && typeof input === "object" && !Array.isArray(input)) {
170
- return true
171
- }
172
-
173
- return false
174
- }
175
-
176
- /**
177
- * Handles an incoming command from the backend
178
- * @param {object} args
179
- * @param {string} args.command
180
- * @param {number} args.command_id
181
- * @param {any} args.data
182
- * @param {string} [args.error]
183
- * @param {string} [args.errorStack]
184
- */
185
- onCommand = ({command, command_id: commandID, data, error, errorStack, ...restArgs}) => {
186
- logger.log(() => ["onCommand", {command, commandID, data, error, errorStack, restArgs}])
187
-
188
- try {
189
- if (!command) {
190
- throw new Error(`No command key given in data: ${Object.keys(restArgs).join(", ")}`)
191
- } else if (command == "get_object") {
192
- const serverObject = this._getRegisteredObject(data.object_name)
193
- let object
194
-
195
- if (serverObject) {
196
- object = serverObject
197
- } else {
198
- object = globalThis[data.object_name]
199
-
200
- if (!object) throw new Error(`No such object: ${data.object_name}`)
201
- }
202
-
203
- const objectId = ++this.objectsCount
204
-
205
- this.objects[objectId] = object
206
- this.respondToCommand(commandID, {object_id: objectId})
207
- } else if (command == "new_object_with_reference") {
208
- const className = data.class_name
209
- let object
210
-
211
- if (typeof className == "string") {
212
- const ClassInstance = this.getClass(className) || globalThis[className]
213
-
214
- if (!ClassInstance) throw new Error(`No such class: ${className}`)
215
-
216
- object = new ClassInstance(...data.args)
217
- } else {
218
- throw new Error(`Don't know how to handle class name: ${typeof className}`)
219
- }
220
-
221
- const objectId = ++this.objectsCount
222
-
223
- this.objects[objectId] = object
224
- this.respondToCommand(commandID, {object_id: objectId})
225
- } else if (command == "call_method_on_reference") {
226
- const referenceId = data.reference_id
227
- const object = this.objects[referenceId]
228
-
229
- if (!object) throw new Error(`No object by that ID: ${referenceId}`)
230
-
231
- const method = object[data.method_name]
232
-
233
- if (!method) throw new Error(`No method called '${data.method_name}' on a '${object.constructor.name}'`)
234
-
235
- const response = method.call(object, ...data.args)
236
-
237
- this.respondToCommand(commandID, {response})
238
- } else if (command == "serialize_reference") {
239
- const referenceId = data.reference_id
240
- const object = this.objects[referenceId]
241
-
242
- if (!object) throw new Error(`No object by that ID: ${referenceId}`)
243
-
244
- this.respondToCommand(commandID, JSON.stringify(object))
245
- } else if (command == "read_attribute") {
246
- const attributeName = data.attribute_name
247
- const referenceId = data.reference_id
248
- const returnWith = data.with
249
- const object = this.objects[referenceId]
250
-
251
- if (!object) throw new Error(`No object by that ID: ${referenceId}`)
252
-
253
- const attribute = object[attributeName]
254
-
255
- if (returnWith == "reference") {
256
- const objectId = ++this.objectsCount
257
-
258
- this.objects[objectId] = attribute
259
- this.respondToCommand(commandID, {response: objectId})
260
- } else {
261
- this.respondToCommand(commandID, {response: attribute})
262
- }
263
- } else if (command == "command_response") {
264
- if (!(commandID in this.outgoingCommands)) {
265
- throw new Error(`Outgoing command ${commandID} not found: ${Object.keys(this.outgoingCommands).join(", ")}`)
266
- }
267
-
268
- const savedCommand = this.outgoingCommands[commandID]
269
-
270
- delete this.outgoingCommands[commandID]
271
-
272
- if (error) {
273
- const errorToThrow = new Error(error)
274
-
275
- if (errorStack) {
276
- errorToThrow.stack = `${errorStack}\n\n${errorToThrow.stack}`
277
- }
278
-
279
- savedCommand.reject(errorToThrow)
280
- } else {
281
- logger.log(() => [`Resolving command ${commandID} with data`, data])
282
- savedCommand.resolve(data.data)
283
- }
284
- } else {
285
- throw new Error(`Unknown command: ${command}`)
286
- }
287
- } catch (error) {
288
- if (error instanceof Error) {
289
- this.send({command: "command_response", command_id: commandID, error: error.message, errorStack: error.stack})
290
- } else {
291
- this.send({command: "command_response", command_id: commandID, error: String(error)})
292
- }
293
-
294
- logger.error(error)
295
- }
296
- }
297
-
298
- /**
299
- * Parases an argument for sending to the server
300
- *
301
- * @param {any} arg
302
- * @returns {any}
303
- */
304
- parseArg(arg) {
305
- if (Array.isArray(arg)) {
306
- return arg.map((argInArray) => this.parseArg(argInArray))
307
- } else if (arg instanceof Reference) {
308
- return {
309
- __scoundrel_object_id: arg.id,
310
- __scoundrel_type: "reference"
311
- }
312
- } else if (this.isPlainObject(arg)) {
313
- /** @type {Record<any, any>} */
314
- const newObject = {}
315
-
316
- for (const key in arg) {
317
- const value = arg[key]
318
-
319
- newObject[key] = this.parseArg(value)
320
- }
321
-
322
- return newObject
323
- }
324
-
325
- return arg
326
- }
327
-
328
- /**
329
- * Reads an attribute on a reference and returns a new reference
330
- *
331
- * @param {number} referenceId
332
- * @param {string} attributeName
333
- * @returns {Promise<Reference>}
334
- */
335
- async readAttributeOnReferenceWithReference(referenceId, attributeName) {
336
- const result = await this.sendCommand("read_attribute", {
337
- attribute_name: attributeName,
338
- reference_id: referenceId,
339
- with: "reference"
340
- })
341
- const id = result.response
342
-
343
- return this.spawnReference(id)
344
- }
345
-
346
- /**
347
- * Reads an attribute on a reference and returns the result directly
348
- *
349
- * @param {number} referenceId
350
- * @param {string} attributeName
351
- * @returns {Promise<any>}
352
- */
353
- async readAttributeOnReference(referenceId, attributeName) {
354
- const result = await this.sendCommand("read_attribute", {
355
- attribute_name: attributeName,
356
- reference_id: referenceId,
357
- with: "result"
358
- })
359
- return result.response
360
- }
361
-
362
- /**
363
- * Registers a class by name
364
- *
365
- * @param {string} className
366
- * @param {any} classInstance
367
- */
368
- registerClass(className, classInstance) {
369
- if (className in this._classes) throw new Error(`Class already exists: ${className}`)
370
-
371
- this._classes[className] = classInstance
372
- }
373
-
374
- /**
375
- * Gets a registered class by name
376
- *
377
- * @param {string} className
378
- * @returns {any}
379
- */
380
- getClass(className) {
381
- return this._classes[className]
382
- }
383
-
384
- /**
385
- * Registers an object by name
386
- *
387
- * @param {string} objectName
388
- * @param {any} objectInstance
389
- */
390
- registerObject(objectName, objectInstance) {
391
- if (objectName in this._objects) throw new Error(`Object already exists: ${objectName}`)
392
-
393
- this._objects[objectName] = objectInstance
394
- }
395
-
396
- /**
397
- * Gets a registered object by name
398
- *
399
- * @param {string} objectName
400
- * @returns {any}
401
- */
402
- _getRegisteredObject(objectName) {
403
- return this._objects[objectName]
404
- }
405
-
406
- /**
407
- * Responds to a command from the backend
408
- * @param {number} commandId
409
- * @param {any} data
410
- */
411
- respondToCommand(commandId, data) {
412
- this.sendCommand("command_response", {command_id: commandId, data})
413
- }
414
-
415
- /**
416
- * Sends a command to the backend and returns a promise that resolves with the response
417
- * @param {string} command
418
- * @param {any} data
419
- * @returns {Promise<any>}
420
- */
421
- sendCommand(command, data) {
422
- return new Promise((resolve, reject) => {
423
- const outgoingCommandCount = ++this.outgoingCommandsCount
424
- const commandData = {
425
- command,
426
- command_id: outgoingCommandCount,
427
- data
428
- }
429
-
430
- this.outgoingCommands[outgoingCommandCount] = {resolve, reject}
431
- logger.log(() => ["Sending", commandData])
432
- this.send(commandData)
433
- })
434
- }
435
-
436
- /**
437
- * Sends data to the backend
438
- * @param {any} data
439
- */
440
- send(data) {
441
- this.backend.send(data)
442
- }
443
-
444
- /**
445
- * Serializes a reference and returns the result directly
446
- *
447
- * @param {number} referenceId
448
- * @returns {Promise<any>}
449
- */
450
- async serializeReference(referenceId) {
451
- const json = await this.sendCommand("serialize_reference", {reference_id: referenceId})
452
-
453
- return JSON.parse(json)
454
- }
455
-
456
- /**
457
- * Spawns a new reference to an object
458
- *
459
- * @param {string} id
460
- * @returns {Reference}
461
- */
462
- spawnReference(id) {
463
- const reference = new Reference(this, id)
464
-
465
- this.references[id] = reference
466
-
467
- return reference
468
- }
469
- }
@@ -1,53 +0,0 @@
1
- // @ts-check
2
-
3
- /**
4
- * @param {import("./reference.js").default} reference
5
- * @param {string} prop
6
- * @returns {(...args: any[]) => Promise<any>}
7
- */
8
- const proxyMethodSpawner = (reference, prop) => (...args) => reference.callMethodWithReference(prop, ...args)
9
-
10
- const proxyObjectHandler = {
11
- /**
12
- * @param {import("./reference.js").default|(() => import("./reference.js").default)} reference
13
- * @param {string} prop
14
- * @returns {any}
15
- */
16
- get(reference, prop) {
17
- if (typeof reference == "function") reference = reference()
18
-
19
- if (prop == "__serialize") {
20
- const method = reference.serialize
21
- const boundMethod = method.bind(reference)
22
-
23
- return boundMethod
24
- }
25
-
26
- return proxyMethodSpawner(reference, prop)
27
- },
28
-
29
- /**
30
- * @param {import("./reference.js").default|(() => import("./reference.js").default)} receiver
31
- * @param {string} prop
32
- * @param {any} newValue
33
- */
34
- set(receiver, prop, newValue) {
35
- throw new Error("set property isn't supported yet")
36
-
37
- // @ts-expect-error
38
- if (typeof receiver == "function") receiver = receiver() // eslint-disable-line no-unreachable
39
-
40
- // @ts-expect-error
41
- if (!(prop in receiver)) throw new PropertyNotFoundError(`Property not found: ${prop}`) // eslint-disable-line no-undef
42
-
43
- return Reflect.set(receiver, prop, newValue)
44
- }
45
- }
46
-
47
- /**
48
- * @param {any} wrappedObject
49
- * @returns {Proxy}
50
- */
51
- const referenceProxy = (wrappedObject) => new Proxy(wrappedObject, proxyObjectHandler)
52
-
53
- export default referenceProxy
@@ -1,69 +0,0 @@
1
- // @ts-check
2
-
3
- export default class Reference {
4
- /**
5
- * Creates a new Reference
6
- *
7
- * @param {any} client The client instance
8
- * @param {string} id The reference ID
9
- */
10
- constructor(client, id) {
11
- this.client = client
12
- this.id = id
13
-
14
- if (!id) throw new Error(`Invalid ID given: ${id}`)
15
- }
16
-
17
- /**
18
- * Calls a method on the reference
19
- *
20
- * @param {string} methodName
21
- * @param {...any} args
22
- * @returns {Promise<any>}
23
- */
24
- async callMethod(methodName, ...args) {
25
- return await this.client.callMethodOnReference(this.id, methodName, ...args)
26
- }
27
-
28
- /**
29
- * Calls a method on the reference using another reference as argument
30
- *
31
- * @param {string} methodName
32
- * @param {...any} args
33
- * @returns {Promise<any>}
34
- */
35
- async callMethodWithReference(methodName, ...args) {
36
- return await this.client.callMethodOnReferenceWithReference(this.id, methodName, ...args)
37
- }
38
-
39
- /**
40
- * Reads an attribute from the reference
41
- *
42
- * @param {string} attributeName
43
- * @param {...any} args
44
- * @returns {Promise<any>}
45
- */
46
- async readAttribute(attributeName, ...args) {
47
- return await this.client.readAttributeOnReference(this.id, attributeName, ...args)
48
- }
49
-
50
- /**
51
- * Reads an attribute from the reference using another reference as argument
52
- *
53
- * @param {string} attributeName
54
- * @param {...any} args
55
- * @returns {Promise<any>}
56
- */
57
- async readAttributeWithReference(attributeName, ...args) {
58
- return await this.client.readAttributeOnReferenceWithReference(this.id, attributeName, ...args)
59
- }
60
-
61
- /**
62
- * Serializes the reference and returns the result directly
63
- *
64
- * @returns {Promise<any>}
65
- */
66
- async serialize() {
67
- return await this.client.serializeReference(this.id)
68
- }
69
- }
package/src/index.js DELETED
File without changes
package/src/logger.js DELETED
@@ -1,70 +0,0 @@
1
- // @ts-check
2
-
3
- export default class Logger {
4
- /**
5
- * Creates a new Logger instance
6
- *
7
- * @param {string} scopeName The name of the scope for the logger
8
- */
9
- constructor(scopeName) {
10
- this.debug = false
11
- this.scopeName = scopeName
12
- }
13
-
14
- /**
15
- * Enables or disables debug logging
16
- *
17
- * @param {boolean} newValue
18
- */
19
- setDebug(newValue) {
20
- this.debug = newValue
21
- }
22
-
23
- /**
24
- * Logs an error message to the console if debug is enabled
25
- *
26
- * @param {...any} args
27
- */
28
- error(...args) {
29
- return this._sendToConsole("error", ...args)
30
- }
31
-
32
- /**
33
- * Logs a message to the console if debug is enabled
34
- * @param {...any} args
35
- */
36
- log(...args) {
37
- return this._sendToConsole("log", ...args)
38
- }
39
-
40
- /**
41
- * Logs a warning message to the console if debug is enabled
42
- * @param {...any} args
43
- */
44
- warn(...args) {
45
- return this._sendToConsole("warn", ...args)
46
- }
47
-
48
- /**
49
- * Sends the log message to the console
50
- * @param {string} logType
51
- * @param {...any} args
52
- */
53
- _sendToConsole(logType, ...args) {
54
- if (!this.debug) {
55
- return
56
- }
57
-
58
- if (args.length == 1 && typeof args[0] == "function") {
59
- const callbackArgs = args[0]()
60
-
61
- if (Array.isArray(callbackArgs)) {
62
- console[logType](this.scopeName, ...callbackArgs)
63
- } else {
64
- console[logType](this.scopeName, callbackArgs)
65
- }
66
- } else {
67
- console[logType](this.scopeName, ...args)
68
- }
69
- }
70
- }