javonet-nodejs-sdk 2.6.13 → 2.6.14
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/dist/core/handler/ArraySetItemHandler.cjs +9 -8
- package/dist/core/handler/AsDtoHandler.cjs +36 -0
- package/dist/core/handler/AsKwargsHandler.cjs +1 -1
- package/dist/core/handler/DtoPropertyHandler.cjs +36 -0
- package/dist/core/handler/Handler.cjs +14 -9
- package/dist/core/handler/PassDelegateHandler.cjs +1 -1
- package/dist/core/handler/ProjectResultAsDtoHandler.cjs +66 -0
- package/dist/core/handler/SetInstanceFieldHandler.cjs +1 -1
- package/dist/core/handler/SetStaticFieldHandler.cjs +6 -6
- package/dist/core/interpreter/Interpreter.cjs +14 -2
- package/dist/core/protocol/CommandDeserializer.cjs +8 -0
- package/dist/core/protocol/TypeDeserializer.cjs +4 -0
- package/dist/core/protocol/TypeSerializer.cjs +10 -5
- package/dist/core/webSocketClient/WebSocketClient.cjs +23 -5
- package/dist/core/webSocketClient/WebSocketClientBrowser.cjs +23 -5
- package/dist/plugins/PluginImplementationRegistry.cjs +214 -0
- package/dist/plugins/PluginPayloadBuilder.cjs +76 -0
- package/dist/plugins/PluginRegistry.cjs +255 -0
- package/dist/plugins/index.cjs +51 -0
- package/dist/plugins/interfaces/ICommunityPlugin.cjs +44 -0
- package/dist/plugins/interfaces/ICommunityReceivingPlugin.cjs +62 -0
- package/dist/plugins/interfaces/ICommunitySendingPlugin.cjs +59 -0
- package/dist/plugins/settings/BasePluginSettings.cjs +67 -0
- package/dist/plugins/settings/JwtGraftocodePluginSettings.cjs +40 -0
- package/dist/sdk/InvocationContext.cjs +133 -12
- package/dist/sdk/RuntimeContext.cjs +27 -9
- package/dist/sdk/configuration/configResolvers/ConfigResolver.cjs +7 -6
- package/dist/sdk/tools/DtoHelper.cjs +100 -0
- package/dist/types/core/handler/ArraySetItemHandler.d.ts +1 -1
- package/dist/types/core/handler/AsDtoHandler.d.ts +7 -0
- package/dist/types/core/handler/AsKwargsHandler.d.ts +1 -1
- package/dist/types/core/handler/DtoPropertyHandler.d.ts +7 -0
- package/dist/types/core/handler/ProjectResultAsDtoHandler.d.ts +9 -0
- package/dist/types/core/handler/SetInstanceFieldHandler.d.ts +1 -1
- package/dist/types/core/handler/SetStaticFieldHandler.d.ts +1 -1
- package/dist/types/core/interpreter/Interpreter.d.ts +3 -3
- package/dist/types/core/protocol/CommandDeserializer.d.ts +1 -0
- package/dist/types/core/protocol/TypeDeserializer.d.ts +1 -0
- package/dist/types/core/protocol/TypeSerializer.d.ts +1 -0
- package/dist/types/plugins/PluginImplementationRegistry.d.ts +121 -0
- package/dist/types/plugins/PluginPayloadBuilder.d.ts +32 -0
- package/dist/types/plugins/PluginRegistry.d.ts +157 -0
- package/dist/types/plugins/index.d.ts +8 -0
- package/dist/types/plugins/interfaces/ICommunityPlugin.d.ts +14 -0
- package/dist/types/plugins/interfaces/ICommunityReceivingPlugin.d.ts +50 -0
- package/dist/types/plugins/interfaces/ICommunitySendingPlugin.d.ts +27 -0
- package/dist/types/plugins/settings/BasePluginSettings.d.ts +45 -0
- package/dist/types/plugins/settings/JwtGraftocodePluginSettings.d.ts +32 -0
- package/dist/types/sdk/InvocationContext.d.ts +20 -2
- package/dist/types/sdk/RuntimeContext.d.ts +6 -0
- package/dist/types/sdk/configuration/configResolvers/ConfigResolver.d.ts +3 -6
- package/dist/types/sdk/tools/DtoHelper.d.ts +35 -0
- package/dist/types/utils/Command.d.ts +5 -0
- package/dist/types/utils/CommandType.d.ts +3 -0
- package/dist/types/utils/Type.d.ts +2 -1
- package/dist/utils/Command.cjs +40 -0
- package/dist/utils/CommandType.cjs +4 -1
- package/dist/utils/Type.cjs +2 -1
- package/lib/core/handler/ArraySetItemHandler.js +11 -10
- package/lib/core/handler/AsDtoHandler.js +11 -0
- package/lib/core/handler/AsKwargsHandler.js +1 -1
- package/lib/core/handler/DtoPropertyHandler.js +11 -0
- package/lib/core/handler/Handler.js +16 -7
- package/lib/core/handler/PassDelegateHandler.js +2 -1
- package/lib/core/handler/ProjectResultAsDtoHandler.js +47 -0
- package/lib/core/handler/SetInstanceFieldHandler.js +1 -1
- package/lib/core/handler/SetStaticFieldHandler.js +6 -6
- package/lib/core/interpreter/Interpreter.js +18 -4
- package/lib/core/protocol/CommandDeserializer.js +9 -0
- package/lib/core/protocol/TypeDeserializer.js +5 -0
- package/lib/core/protocol/TypeSerializer.js +11 -8
- package/lib/core/webSocketClient/WebSocketClient.js +30 -5
- package/lib/core/webSocketClient/WebSocketClientBrowser.js +29 -5
- package/lib/plugins/PluginImplementationRegistry.js +231 -0
- package/lib/plugins/PluginPayloadBuilder.js +60 -0
- package/lib/plugins/PluginRegistry.js +295 -0
- package/lib/plugins/index.js +29 -0
- package/lib/plugins/interfaces/ICommunityPlugin.js +25 -0
- package/lib/plugins/interfaces/ICommunityReceivingPlugin.js +57 -0
- package/lib/plugins/interfaces/ICommunitySendingPlugin.js +42 -0
- package/lib/plugins/settings/BasePluginSettings.js +79 -0
- package/lib/plugins/settings/JwtGraftocodePluginSettings.js +43 -0
- package/lib/sdk/InvocationContext.js +149 -14
- package/lib/sdk/RuntimeContext.js +33 -9
- package/lib/sdk/configuration/configResolvers/ConfigResolver.js +14 -8
- package/lib/sdk/tools/DtoHelper.js +90 -0
- package/lib/utils/Command.js +47 -0
- package/lib/utils/CommandType.js +3 -0
- package/lib/utils/Type.js +2 -1
- package/package.json +5 -1
|
@@ -6,6 +6,7 @@ import { CommandType } from '../utils/CommandType.js'
|
|
|
6
6
|
import { ExceptionThrower } from '../utils/exception/ExceptionThrower.js'
|
|
7
7
|
import { RuntimeName } from '../utils/RuntimeName.js'
|
|
8
8
|
import { TypesHandler } from '../utils/TypesHandler.js'
|
|
9
|
+
import { DtoHelper } from './tools/DtoHelper.js'
|
|
9
10
|
import { v4 as uuidv4 } from 'uuid' // add lightweight uuid generation
|
|
10
11
|
|
|
11
12
|
/**
|
|
@@ -40,6 +41,8 @@ class AsyncLock {
|
|
|
40
41
|
* @class
|
|
41
42
|
*/
|
|
42
43
|
class InvocationContext {
|
|
44
|
+
/** @type {string} */
|
|
45
|
+
#runtimeContextId
|
|
43
46
|
/** @type {RuntimeNameType} */
|
|
44
47
|
#runtimeName
|
|
45
48
|
/** @type {IConnectionData} */
|
|
@@ -50,6 +53,8 @@ class InvocationContext {
|
|
|
50
53
|
#responseCommand = null
|
|
51
54
|
/** @type {boolean} */
|
|
52
55
|
#isExecuted = false
|
|
56
|
+
/** @type {boolean} */
|
|
57
|
+
#isDto = false
|
|
53
58
|
/** @type {string | null} */
|
|
54
59
|
#guid = null
|
|
55
60
|
/** @type {AsyncLock} */
|
|
@@ -62,18 +67,22 @@ class InvocationContext {
|
|
|
62
67
|
|
|
63
68
|
/**
|
|
64
69
|
*
|
|
70
|
+
* @param {string} runtimeContextId
|
|
65
71
|
* @param {RuntimeNameType} runtimeName
|
|
66
72
|
* @param {IConnectionData} connectionData
|
|
67
|
-
* @param {Command} command
|
|
73
|
+
* @param {Command | null} command
|
|
68
74
|
* @param {boolean} isExecuted
|
|
75
|
+
* @param {boolean} isDto
|
|
69
76
|
*/
|
|
70
|
-
constructor(runtimeName, connectionData, command, isExecuted = false) {
|
|
77
|
+
constructor(runtimeContextId, runtimeName, connectionData, command, isExecuted = false, isDto = false) {
|
|
78
|
+
this.#runtimeContextId = runtimeContextId
|
|
71
79
|
this.#runtimeName = runtimeName
|
|
72
80
|
this.#connectionData = connectionData
|
|
73
81
|
this.#currentCommand = command
|
|
74
82
|
this.#responseCommand = null
|
|
75
83
|
this.#isExecuted = isExecuted
|
|
76
84
|
this.#guid = uuidv4()
|
|
85
|
+
this.#isDto = isDto
|
|
77
86
|
}
|
|
78
87
|
|
|
79
88
|
/**
|
|
@@ -90,9 +99,12 @@ class InvocationContext {
|
|
|
90
99
|
*/
|
|
91
100
|
#createInstanceContext(localCommand) {
|
|
92
101
|
return new InvocationContext(
|
|
102
|
+
this.#runtimeContextId,
|
|
93
103
|
this.#runtimeName,
|
|
94
104
|
this.#connectionData,
|
|
95
|
-
this.#buildCommand(localCommand)
|
|
105
|
+
this.#buildCommand(localCommand),
|
|
106
|
+
this.#isExecuted,
|
|
107
|
+
this.#isDto
|
|
96
108
|
)
|
|
97
109
|
}
|
|
98
110
|
|
|
@@ -142,6 +154,10 @@ class InvocationContext {
|
|
|
142
154
|
throw new Error('currentCommand is undefined in Invocation Context execute method')
|
|
143
155
|
}
|
|
144
156
|
|
|
157
|
+
if (this.#isDto) {
|
|
158
|
+
return this;
|
|
159
|
+
}
|
|
160
|
+
|
|
145
161
|
const entries = Array.from(InvocationContext._invocationContexts.entries())
|
|
146
162
|
entries.sort((a, b) => String(a[0]).localeCompare(String(b[0])))
|
|
147
163
|
const releases = []
|
|
@@ -154,11 +170,11 @@ class InvocationContext {
|
|
|
154
170
|
try {
|
|
155
171
|
// Execute command on interpreter
|
|
156
172
|
this.#responseCommand = await Interpreter.execute(
|
|
173
|
+
this.#runtimeContextId,
|
|
157
174
|
this.#currentCommand,
|
|
158
175
|
this.#connectionData
|
|
159
176
|
)
|
|
160
177
|
|
|
161
|
-
|
|
162
178
|
if (!this.#responseCommand) {
|
|
163
179
|
throw new Error('responseCommand is undefined in Invocation Context execute method')
|
|
164
180
|
}
|
|
@@ -169,16 +185,26 @@ class InvocationContext {
|
|
|
169
185
|
// Process ValueForUpdate commands in response payload
|
|
170
186
|
this.#responseCommand = this.#processUpdateInvocationContextCommands(this.#responseCommand)
|
|
171
187
|
|
|
172
|
-
if (this.#
|
|
173
|
-
|
|
174
|
-
this.#isExecuted = true
|
|
175
|
-
return this
|
|
188
|
+
if (this.#currentCommand.commandType === CommandType.ProjectResultAsDto) {
|
|
189
|
+
return this.#convertResponseToDto()
|
|
176
190
|
}
|
|
177
|
-
|
|
191
|
+
|
|
192
|
+
return new InvocationContext(
|
|
193
|
+
this.#runtimeContextId,
|
|
194
|
+
this.#runtimeName,
|
|
195
|
+
this.#connectionData,
|
|
196
|
+
this.#responseCommand,
|
|
197
|
+
true,
|
|
198
|
+
this.#isDto
|
|
199
|
+
)
|
|
178
200
|
} finally {
|
|
179
201
|
// Release all locks in reverse order
|
|
180
202
|
for (let i = releases.length - 1; i >= 0; i--) {
|
|
181
|
-
try {
|
|
203
|
+
try {
|
|
204
|
+
releases[i]()
|
|
205
|
+
} catch {
|
|
206
|
+
/* ignore */
|
|
207
|
+
}
|
|
182
208
|
}
|
|
183
209
|
}
|
|
184
210
|
}
|
|
@@ -217,7 +243,9 @@ class InvocationContext {
|
|
|
217
243
|
const instanceGuid = String(cmdPayload[1])
|
|
218
244
|
const invCtx = InvocationContext._invocationContexts.get(contextGuid)
|
|
219
245
|
if (invCtx) {
|
|
220
|
-
invCtx.#currentCommand = new Command(invCtx.#runtimeName, CommandType.Reference, [
|
|
246
|
+
invCtx.#currentCommand = new Command(invCtx.#runtimeName, CommandType.Reference, [
|
|
247
|
+
instanceGuid,
|
|
248
|
+
])
|
|
221
249
|
InvocationContext._invocationContexts.delete(contextGuid)
|
|
222
250
|
}
|
|
223
251
|
}
|
|
@@ -281,6 +309,9 @@ class InvocationContext {
|
|
|
281
309
|
createInstance(...args) {
|
|
282
310
|
const localCommand = new Command(this.#runtimeName, CommandType.CreateClassInstance, [...args])
|
|
283
311
|
const createInstanceInvCtx = this.#createInstanceContext(localCommand)
|
|
312
|
+
if (this.#isDto) {
|
|
313
|
+
return createInstanceInvCtx;
|
|
314
|
+
}
|
|
284
315
|
return createInstanceInvCtx.#registerForUpdate()
|
|
285
316
|
}
|
|
286
317
|
|
|
@@ -289,7 +320,9 @@ class InvocationContext {
|
|
|
289
320
|
* @returns {InvocationContext}
|
|
290
321
|
*/
|
|
291
322
|
#registerForUpdate() {
|
|
292
|
-
this.#currentCommand = this.#buildCommand(
|
|
323
|
+
this.#currentCommand = this.#buildCommand(
|
|
324
|
+
new Command(this.#runtimeName, CommandType.RegisterForUpdate, [this.getGuid()])
|
|
325
|
+
)
|
|
293
326
|
InvocationContext._invocationContexts.set(this.getGuid(), this)
|
|
294
327
|
return this
|
|
295
328
|
}
|
|
@@ -302,6 +335,19 @@ class InvocationContext {
|
|
|
302
335
|
* @method
|
|
303
336
|
*/
|
|
304
337
|
getInstanceField(fieldName) {
|
|
338
|
+
if (this.#isDto) {
|
|
339
|
+
// @ts-ignore
|
|
340
|
+
const value = DtoHelper.tryGetDtoFieldValue(this.#currentCommand, fieldName)
|
|
341
|
+
const valueCommand = new Command(this.#runtimeName, CommandType.Value, [value])
|
|
342
|
+
return new InvocationContext(
|
|
343
|
+
this.#runtimeContextId,
|
|
344
|
+
this.#runtimeName,
|
|
345
|
+
this.#connectionData,
|
|
346
|
+
valueCommand,
|
|
347
|
+
false,
|
|
348
|
+
this.#isDto
|
|
349
|
+
)
|
|
350
|
+
}
|
|
305
351
|
let localCommand = new Command(this.#runtimeName, CommandType.GetInstanceField, [fieldName])
|
|
306
352
|
return this.#createInstanceContext(localCommand)
|
|
307
353
|
}
|
|
@@ -316,7 +362,19 @@ class InvocationContext {
|
|
|
316
362
|
*/
|
|
317
363
|
setInstanceField(fieldName, value) {
|
|
318
364
|
let localCommand = new Command(this.#runtimeName, CommandType.SetInstanceField, [fieldName, value])
|
|
319
|
-
|
|
365
|
+
const newCommand = this.#buildCommand(localCommand)
|
|
366
|
+
if (this.#isDto) {
|
|
367
|
+
this.#currentCommand = newCommand
|
|
368
|
+
return this
|
|
369
|
+
}
|
|
370
|
+
return new InvocationContext(
|
|
371
|
+
this.#runtimeContextId,
|
|
372
|
+
this.#runtimeName,
|
|
373
|
+
this.#connectionData,
|
|
374
|
+
newCommand,
|
|
375
|
+
this.#isExecuted,
|
|
376
|
+
this.#isDto
|
|
377
|
+
)
|
|
320
378
|
}
|
|
321
379
|
|
|
322
380
|
/**
|
|
@@ -493,6 +551,46 @@ class InvocationContext {
|
|
|
493
551
|
return this.#createInstanceContext(localCommand)
|
|
494
552
|
}
|
|
495
553
|
|
|
554
|
+
/**
|
|
555
|
+
* Returns a new InvocationContext that acts as a DTO (Data Transfer Object).
|
|
556
|
+
* When actAsDto is true, field get/set operate on local state without remote calls.
|
|
557
|
+
* @param {boolean} actAsDto - Whether to treat this context as a DTO.
|
|
558
|
+
* @returns {InvocationContext} A new InvocationContext with the DTO flag set.
|
|
559
|
+
* @method
|
|
560
|
+
*/
|
|
561
|
+
asDto(actAsDto = true) {
|
|
562
|
+
return new InvocationContext(
|
|
563
|
+
this.#runtimeContextId,
|
|
564
|
+
this.#runtimeName,
|
|
565
|
+
this.#connectionData,
|
|
566
|
+
this.#currentCommand,
|
|
567
|
+
false,
|
|
568
|
+
actAsDto
|
|
569
|
+
)
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
/**
|
|
573
|
+
* Projects the result as a DTO with the specified property names.
|
|
574
|
+
* When propertiesNames is a single empty string, returns this context unchanged.
|
|
575
|
+
* @param {...string} propertiesNames - Names of properties to include in the DTO.
|
|
576
|
+
* @returns {InvocationContext} A new InvocationContext that will materialize as a DTO.
|
|
577
|
+
* @method
|
|
578
|
+
*/
|
|
579
|
+
projectResultAsDto(...propertiesNames) {
|
|
580
|
+
if (propertiesNames.length === 1 && (propertiesNames[0] === null || propertiesNames[0] === '')) {
|
|
581
|
+
return this
|
|
582
|
+
}
|
|
583
|
+
let localCommand = new Command(this.#runtimeName, CommandType.ProjectResultAsDto, propertiesNames)
|
|
584
|
+
return new InvocationContext(
|
|
585
|
+
this.#runtimeContextId,
|
|
586
|
+
this.#runtimeName,
|
|
587
|
+
this.#connectionData,
|
|
588
|
+
this.#buildCommand(localCommand),
|
|
589
|
+
false,
|
|
590
|
+
false
|
|
591
|
+
)
|
|
592
|
+
}
|
|
593
|
+
|
|
496
594
|
/**
|
|
497
595
|
* Retrieves the type of the object from the target runtime.
|
|
498
596
|
* @returns {Promise<string>} The type of the object.
|
|
@@ -502,6 +600,7 @@ class InvocationContext {
|
|
|
502
600
|
async getResultType() {
|
|
503
601
|
const localCommand = new Command(this.#runtimeName, CommandType.GetResultType, [])
|
|
504
602
|
const invocationContext = new InvocationContext(
|
|
603
|
+
this.#runtimeContextId,
|
|
505
604
|
this.#runtimeName,
|
|
506
605
|
this.#connectionData,
|
|
507
606
|
this.#buildCommand(localCommand)
|
|
@@ -529,6 +628,7 @@ class InvocationContext {
|
|
|
529
628
|
async retrieveArray() {
|
|
530
629
|
const localCommand = new Command(this.#runtimeName, CommandType.RetrieveArray, [])
|
|
531
630
|
const localInvCtx = new InvocationContext(
|
|
631
|
+
this.#runtimeContextId,
|
|
532
632
|
this.#runtimeName,
|
|
533
633
|
this.#connectionData,
|
|
534
634
|
this.#buildCommand(localCommand)
|
|
@@ -558,9 +658,12 @@ class InvocationContext {
|
|
|
558
658
|
|
|
559
659
|
/**
|
|
560
660
|
* @param {Command} command
|
|
561
|
-
* @returns {Command}
|
|
661
|
+
* @returns {Command | null}
|
|
562
662
|
*/
|
|
563
663
|
#buildCommand(command) {
|
|
664
|
+
if (!command) {
|
|
665
|
+
return this.#currentCommand
|
|
666
|
+
}
|
|
564
667
|
for (let i = 0; i < command.payload.length; i++) {
|
|
565
668
|
command.payload[i] = this.#encapsulatePayloadItem(command.payload[i])
|
|
566
669
|
}
|
|
@@ -603,6 +706,38 @@ class InvocationContext {
|
|
|
603
706
|
)
|
|
604
707
|
}
|
|
605
708
|
}
|
|
709
|
+
|
|
710
|
+
#convertResponseToDto() {
|
|
711
|
+
/** @type {Command} */
|
|
712
|
+
// @ts-ignore
|
|
713
|
+
const responseCommand = this.#responseCommand
|
|
714
|
+
// const instanceReferenceCommand = responseCommand.payload[0]
|
|
715
|
+
const getTypeCommand = responseCommand.payload[1]
|
|
716
|
+
|
|
717
|
+
let projectResultAsDtoInvCtx = new InvocationContext(
|
|
718
|
+
this.#runtimeContextId,
|
|
719
|
+
this.#runtimeName,
|
|
720
|
+
this.#connectionData,
|
|
721
|
+
new Command(this.#runtimeName, CommandType.CreateClassInstance, [getTypeCommand]),
|
|
722
|
+
true,
|
|
723
|
+
true
|
|
724
|
+
)
|
|
725
|
+
|
|
726
|
+
if (responseCommand.payload.length >= 3) {
|
|
727
|
+
for (let i = 2; i < responseCommand.payload.length; i++) {
|
|
728
|
+
const item = responseCommand.payload[i]
|
|
729
|
+
if (item instanceof Command && item.commandType === CommandType.DtoProperty) {
|
|
730
|
+
const propertyName = item.payload[0] ? String(item.payload[0]) : ''
|
|
731
|
+
const propertyValue = item.payload.length > 1 ? item.payload[1] : ''
|
|
732
|
+
projectResultAsDtoInvCtx = projectResultAsDtoInvCtx.setInstanceField(
|
|
733
|
+
propertyName,
|
|
734
|
+
propertyValue
|
|
735
|
+
)
|
|
736
|
+
}
|
|
737
|
+
}
|
|
738
|
+
}
|
|
739
|
+
return projectResultAsDtoInvCtx
|
|
740
|
+
}
|
|
606
741
|
}
|
|
607
742
|
|
|
608
743
|
export { InvocationContext }
|
|
@@ -11,6 +11,7 @@ import { TypesHandler } from '../utils/TypesHandler.js'
|
|
|
11
11
|
import { UtilsConst } from '../utils/UtilsConst.js'
|
|
12
12
|
import { Config } from "./configuration/Config.js"
|
|
13
13
|
import { getRequire, isNodejsRuntime } from '../utils/Runtime.js'
|
|
14
|
+
import { generateGUID } from '../utils/guid/generateGuid.js'
|
|
14
15
|
|
|
15
16
|
|
|
16
17
|
/**
|
|
@@ -47,6 +48,8 @@ class RuntimeContext {
|
|
|
47
48
|
#currentCommand = null
|
|
48
49
|
/** @type {Command | null} */
|
|
49
50
|
#responseCommand = null
|
|
51
|
+
/** @type {string} Unique identifier for this runtime context instance */
|
|
52
|
+
#runtimeContextId = ''
|
|
50
53
|
|
|
51
54
|
/**
|
|
52
55
|
* @param {RuntimeNameType} runtimeName
|
|
@@ -56,6 +59,8 @@ class RuntimeContext {
|
|
|
56
59
|
this._isExecuted = false
|
|
57
60
|
this.runtimeName = runtimeName
|
|
58
61
|
this.connectionData = connectionData
|
|
62
|
+
// Generate unique runtime context ID (GUID/UUID)
|
|
63
|
+
this.#runtimeContextId = generateGUID()
|
|
59
64
|
|
|
60
65
|
if (this.connectionData.connectionType === ConnectionType.WEB_SOCKET) {
|
|
61
66
|
return
|
|
@@ -125,6 +130,8 @@ class RuntimeContext {
|
|
|
125
130
|
const runtimeCtx = RuntimeContext.memoryRuntimeContexts.get(key)
|
|
126
131
|
if (!runtimeCtx) throw new Error('Runtime context not found')
|
|
127
132
|
runtimeCtx.#currentCommand = null
|
|
133
|
+
// Regenerate runtime context ID for each getInstance call (matches .NET behavior)
|
|
134
|
+
runtimeCtx.#runtimeContextId = generateGUID()
|
|
128
135
|
return runtimeCtx
|
|
129
136
|
} else {
|
|
130
137
|
if (!_Transmitter) {
|
|
@@ -141,6 +148,8 @@ class RuntimeContext {
|
|
|
141
148
|
const runtimeCtx = RuntimeContext.networkRuntimeContexts.get(key1)
|
|
142
149
|
if (!runtimeCtx) throw new Error('Runtime context not found')
|
|
143
150
|
runtimeCtx.#currentCommand = null
|
|
151
|
+
// Regenerate runtime context ID for each getInstance call (matches .NET behavior)
|
|
152
|
+
runtimeCtx.#runtimeContextId = generateGUID()
|
|
144
153
|
return runtimeCtx
|
|
145
154
|
} else {
|
|
146
155
|
if (!_Transmitter) {
|
|
@@ -158,6 +167,8 @@ class RuntimeContext {
|
|
|
158
167
|
const runtimeCtx = RuntimeContext.webSocketRuntimeContexts.get(key2)
|
|
159
168
|
if (!runtimeCtx) throw new Error('Runtime context not found')
|
|
160
169
|
runtimeCtx.#currentCommand = null
|
|
170
|
+
// Regenerate runtime context ID for each getInstance call (matches .NET behavior)
|
|
171
|
+
runtimeCtx.#runtimeContextId = generateGUID()
|
|
161
172
|
return runtimeCtx
|
|
162
173
|
} else {
|
|
163
174
|
const runtimeCtx = new RuntimeContext(runtimeName, connectionData)
|
|
@@ -170,6 +181,15 @@ class RuntimeContext {
|
|
|
170
181
|
}
|
|
171
182
|
}
|
|
172
183
|
|
|
184
|
+
/**
|
|
185
|
+
* Gets the unique runtime context ID for this instance.
|
|
186
|
+
* This ID is used to associate plugins with specific runtime contexts.
|
|
187
|
+
* @returns {string} The runtime context ID (GUID/UUID string)
|
|
188
|
+
*/
|
|
189
|
+
get runtimeContextId() {
|
|
190
|
+
return this.#runtimeContextId
|
|
191
|
+
}
|
|
192
|
+
|
|
173
193
|
/**
|
|
174
194
|
* Executes the current command. The initial state of RuntimeContext is non-materialized,
|
|
175
195
|
* wrapping either a single command or a chain of recursively nested commands.
|
|
@@ -184,7 +204,8 @@ class RuntimeContext {
|
|
|
184
204
|
if (!this.#currentCommand) {
|
|
185
205
|
throw new Error('currentCommand is undefined in Runtime Context execute method')
|
|
186
206
|
}
|
|
187
|
-
|
|
207
|
+
// Pass the runtime context ID to the interpreter for plugin resolution
|
|
208
|
+
this.#responseCommand = await Interpreter.execute(this.#runtimeContextId, this.#currentCommand, this.connectionData)
|
|
188
209
|
this.#currentCommand = null
|
|
189
210
|
if (this.#responseCommand === undefined) {
|
|
190
211
|
throw new Error('responseCommand is undefined in Runtime Context execute method')
|
|
@@ -221,7 +242,7 @@ class RuntimeContext {
|
|
|
221
242
|
getType(typeName, ...args) {
|
|
222
243
|
let localCommand = new Command(this.runtimeName, CommandType.GetType, [typeName, ...args])
|
|
223
244
|
this.#currentCommand = null
|
|
224
|
-
return new InvocationContext(this.runtimeName, this.connectionData, this.#buildCommand(localCommand))
|
|
245
|
+
return new InvocationContext(this.#runtimeContextId, this.runtimeName, this.connectionData, this.#buildCommand(localCommand))
|
|
225
246
|
}
|
|
226
247
|
|
|
227
248
|
/**
|
|
@@ -236,7 +257,7 @@ class RuntimeContext {
|
|
|
236
257
|
cast(...args) {
|
|
237
258
|
let localCommand = new Command(this.runtimeName, CommandType.Cast, args)
|
|
238
259
|
this.#currentCommand = null
|
|
239
|
-
return new InvocationContext(this.runtimeName, this.connectionData, this.#buildCommand(localCommand))
|
|
260
|
+
return new InvocationContext(this.#runtimeContextId, this.runtimeName, this.connectionData, this.#buildCommand(localCommand))
|
|
240
261
|
}
|
|
241
262
|
|
|
242
263
|
/**
|
|
@@ -251,7 +272,7 @@ class RuntimeContext {
|
|
|
251
272
|
getEnumItem(...args) {
|
|
252
273
|
let localCommand = new Command(this.runtimeName, CommandType.GetEnumItem, args)
|
|
253
274
|
this.#currentCommand = null
|
|
254
|
-
return new InvocationContext(this.runtimeName, this.connectionData, this.#buildCommand(localCommand))
|
|
275
|
+
return new InvocationContext(this.#runtimeContextId, this.runtimeName, this.connectionData, this.#buildCommand(localCommand))
|
|
255
276
|
}
|
|
256
277
|
|
|
257
278
|
/**
|
|
@@ -266,7 +287,7 @@ class RuntimeContext {
|
|
|
266
287
|
asRef(...args) {
|
|
267
288
|
let localCommand = new Command(this.runtimeName, CommandType.AsRef, args)
|
|
268
289
|
this.#currentCommand = null
|
|
269
|
-
return new InvocationContext(this.runtimeName, this.connectionData, this.#buildCommand(localCommand))
|
|
290
|
+
return new InvocationContext(this.#runtimeContextId, this.runtimeName, this.connectionData, this.#buildCommand(localCommand))
|
|
270
291
|
}
|
|
271
292
|
|
|
272
293
|
/**
|
|
@@ -281,7 +302,7 @@ class RuntimeContext {
|
|
|
281
302
|
asOut(...args) {
|
|
282
303
|
let localCommand = new Command(this.runtimeName, CommandType.AsOut, args)
|
|
283
304
|
this.#currentCommand = null
|
|
284
|
-
return new InvocationContext(this.runtimeName, this.connectionData, this.#buildCommand(localCommand))
|
|
305
|
+
return new InvocationContext(this.#runtimeContextId, this.runtimeName, this.connectionData, this.#buildCommand(localCommand))
|
|
285
306
|
}
|
|
286
307
|
|
|
287
308
|
/**
|
|
@@ -294,7 +315,7 @@ class RuntimeContext {
|
|
|
294
315
|
getGlobalField(fieldName) {
|
|
295
316
|
let localCommand = new Command(this.runtimeName, CommandType.GetGlobalField, [fieldName])
|
|
296
317
|
this.#currentCommand = null
|
|
297
|
-
return new InvocationContext(this.runtimeName, this.connectionData, this.#buildCommand(localCommand))
|
|
318
|
+
return new InvocationContext(this.#runtimeContextId, this.runtimeName, this.connectionData, this.#buildCommand(localCommand))
|
|
298
319
|
}
|
|
299
320
|
|
|
300
321
|
/**
|
|
@@ -313,14 +334,17 @@ class RuntimeContext {
|
|
|
313
334
|
...args,
|
|
314
335
|
])
|
|
315
336
|
this.#currentCommand = null
|
|
316
|
-
return new InvocationContext(this.runtimeName, this.connectionData, this.#buildCommand(localCommand))
|
|
337
|
+
return new InvocationContext(this.#runtimeContextId, this.runtimeName, this.connectionData, this.#buildCommand(localCommand))
|
|
317
338
|
}
|
|
318
339
|
|
|
319
340
|
/**
|
|
320
341
|
* @param {Command} command
|
|
321
|
-
* @returns {Command}
|
|
342
|
+
* @returns {Command | null}
|
|
322
343
|
*/
|
|
323
344
|
#buildCommand(command) {
|
|
345
|
+
if (!command) {
|
|
346
|
+
return this.#currentCommand
|
|
347
|
+
}
|
|
324
348
|
for (let i = 0; i < command.payload.length; i++) {
|
|
325
349
|
command.payload[i] = this.#encapsulatePayloadItem(command.payload[i])
|
|
326
350
|
}
|
|
@@ -20,40 +20,43 @@ class ConfigResolver {
|
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
/**
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
* - ws:// or wss:// => WsConnectionData(fullAddress)
|
|
27
|
-
* - tcp://... => parsed by parseTcp
|
|
28
|
-
* - host:port or host:port/... => TcpConnectionData(host, port) if valid, otherwise InMemoryConnectionData
|
|
23
|
+
* Builds connection data from the host string from config (JSON, YAML, or connection string).
|
|
24
|
+
* Recognized formats: empty (in-memory), "inmemory"/"in-memory", ws://..., wss://..., tcp://host:port, host:port.
|
|
25
|
+
* When the value is missing, invalid, or unparseable, falls back to InMemoryConnectionData and logs the reason.
|
|
29
26
|
* @param {string} hostValue
|
|
30
27
|
* @returns {InMemoryConnectionData|WsConnectionData|TcpConnectionData}
|
|
31
28
|
*/
|
|
32
29
|
static buildConnectionData(hostValue) {
|
|
30
|
+
// No host specified: use in-memory (local) connection; no remote server.
|
|
33
31
|
if (!hostValue || String(hostValue).trim() === '') {
|
|
32
|
+
console.warn('Host not specified; using in-memory.')
|
|
34
33
|
return new InMemoryConnectionData()
|
|
35
34
|
}
|
|
36
35
|
|
|
37
36
|
const hv = String(hostValue).trim()
|
|
38
37
|
const lower = hv.toLowerCase()
|
|
39
38
|
|
|
39
|
+
// Explicit in-memory choice from config; no console message (intended by user).
|
|
40
40
|
if (lower === 'inmemory' || lower === 'in-memory') {
|
|
41
41
|
return new InMemoryConnectionData()
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
+
// WebSocket URL: use as-is for WsConnectionData.
|
|
44
45
|
if (lower.startsWith('ws://') || lower.startsWith('wss://')) {
|
|
45
46
|
return new WsConnectionData(hv)
|
|
46
47
|
}
|
|
47
48
|
|
|
49
|
+
// tcp://host:port — parse and create TcpConnectionData; on parse failure, fall back to in-memory.
|
|
48
50
|
if (lower.startsWith('tcp://')) {
|
|
49
51
|
try {
|
|
50
|
-
// slice off 'tcp://'
|
|
51
52
|
return ConfigResolver.parseTcp(hv.slice(6))
|
|
52
53
|
} catch (e) {
|
|
54
|
+
console.warn("Invalid or unparseable tcp:// address '" + hv + "'; falling back to in-memory.")
|
|
53
55
|
return new InMemoryConnectionData()
|
|
54
56
|
}
|
|
55
57
|
}
|
|
56
58
|
|
|
59
|
+
// host:port (or host:port/path) — try to create TcpConnectionData; on failure, fall back to in-memory.
|
|
57
60
|
const colon = hv.indexOf(':')
|
|
58
61
|
if (colon > 0 && colon < hv.length - 1) {
|
|
59
62
|
let portPart = hv.substring(colon + 1)
|
|
@@ -71,14 +74,17 @@ class ConfigResolver {
|
|
|
71
74
|
try {
|
|
72
75
|
return new TcpConnectionData(hostOnly, port)
|
|
73
76
|
} catch (e) {
|
|
77
|
+
console.warn("Could not create TCP connection for '" + hv + "'; falling back to in-memory.")
|
|
74
78
|
return new InMemoryConnectionData()
|
|
75
79
|
}
|
|
76
80
|
}
|
|
77
81
|
} catch (e) {
|
|
78
|
-
// fall through to
|
|
82
|
+
// Port not a valid number; fall through to final fallback below.
|
|
79
83
|
}
|
|
80
84
|
}
|
|
81
85
|
|
|
86
|
+
// Unrecognized format: expected empty, "inmemory", "in-memory", ws://..., wss://..., tcp://host:port, or host:port.
|
|
87
|
+
console.warn("Host value '" + hv + "' is not a recognized connection format (expected: empty, 'inmemory', 'in-memory', 'ws://...', 'wss://...', 'tcp://host:port', or 'host:port'). Falling back to in-memory.")
|
|
82
88
|
return new InMemoryConnectionData()
|
|
83
89
|
}
|
|
84
90
|
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
3
|
+
import { Command } from '../../utils/Command.js'
|
|
4
|
+
import { CommandType } from '../../utils/CommandType.js'
|
|
5
|
+
|
|
6
|
+
export class DtoHelper {
|
|
7
|
+
/**
|
|
8
|
+
* Attempts to retrieve a DTO field value by field name from a command chain.
|
|
9
|
+
*
|
|
10
|
+
* @param {Command | null} command - The command to search through.
|
|
11
|
+
* @param {string} fieldName - The name of the field to retrieve.
|
|
12
|
+
* @returns {any}
|
|
13
|
+
*/
|
|
14
|
+
static tryGetDtoFieldValue(command, fieldName) {
|
|
15
|
+
let value = null
|
|
16
|
+
let currentCommand = command
|
|
17
|
+
|
|
18
|
+
while (currentCommand !== undefined && currentCommand !== null) {
|
|
19
|
+
if (
|
|
20
|
+
currentCommand.commandType === CommandType.SetInstanceField &&
|
|
21
|
+
DtoHelper._tryGetDtoFieldName(currentCommand) &&
|
|
22
|
+
DtoHelper._getDtoFieldName(currentCommand) === fieldName
|
|
23
|
+
) {
|
|
24
|
+
value = DtoHelper._tryGetDtoFieldValueFromCommand(currentCommand)
|
|
25
|
+
return value
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if (!currentCommand.payload || currentCommand.payload.length === 0) {
|
|
29
|
+
break
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const firstPayload = currentCommand.payload[0]
|
|
33
|
+
currentCommand = (firstPayload instanceof Command) ? firstPayload : null
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return null
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Attempts to extract the field name from a SetInstanceField command.
|
|
41
|
+
* @param {Command} command
|
|
42
|
+
* @returns {boolean}
|
|
43
|
+
*/
|
|
44
|
+
static _tryGetDtoFieldName(command) {
|
|
45
|
+
if (command.payload.length < 2) {
|
|
46
|
+
return false
|
|
47
|
+
}
|
|
48
|
+
const nameValue = DtoHelper._tryGetPayloadValue(command.payload[1])
|
|
49
|
+
return typeof nameValue === 'string'
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Extracts the field name from a SetInstanceField command.
|
|
54
|
+
* @param {Command} command
|
|
55
|
+
* @returns {string}
|
|
56
|
+
*/
|
|
57
|
+
static _getDtoFieldName(command) {
|
|
58
|
+
if (command.payload.length < 2) {
|
|
59
|
+
return ''
|
|
60
|
+
}
|
|
61
|
+
const nameValue = DtoHelper._tryGetPayloadValue(command.payload[1])
|
|
62
|
+
return (typeof nameValue === 'string') ? nameValue : ""
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Attempts to extract the field value from a SetInstanceField command.
|
|
67
|
+
* @param {Command} command
|
|
68
|
+
* @returns {any}
|
|
69
|
+
*/
|
|
70
|
+
static _tryGetDtoFieldValueFromCommand(command) {
|
|
71
|
+
if (command.payload.length < 3) {
|
|
72
|
+
return null
|
|
73
|
+
}
|
|
74
|
+
return DtoHelper._tryGetPayloadValue(command.payload[2])
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Attempts to extract a value from a payload item, handling Value command types.
|
|
79
|
+
* @param {any} payloadItem
|
|
80
|
+
* @returns {any}
|
|
81
|
+
*/
|
|
82
|
+
static _tryGetPayloadValue(payloadItem) {
|
|
83
|
+
if ((payloadItem instanceof Command) &&
|
|
84
|
+
payloadItem.commandType === CommandType.Value &&
|
|
85
|
+
payloadItem.payload.length > 0) {
|
|
86
|
+
return payloadItem.payload[0]
|
|
87
|
+
}
|
|
88
|
+
return payloadItem
|
|
89
|
+
}
|
|
90
|
+
}
|
package/lib/utils/Command.js
CHANGED
|
@@ -69,4 +69,51 @@ export class Command {
|
|
|
69
69
|
return new Command(this.runtimeName, this.commandType, [current_command].concat(this.payload))
|
|
70
70
|
}
|
|
71
71
|
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Returns string representation of the Command instance for debugging purposes.
|
|
75
|
+
* @returns {string}
|
|
76
|
+
*/
|
|
77
|
+
toString() {
|
|
78
|
+
try {
|
|
79
|
+
let result = ' { '
|
|
80
|
+
result += `RuntimeName: ${this.runtimeName}, `
|
|
81
|
+
result += `CommandType: ${this.commandType}, `
|
|
82
|
+
result += 'Payload: \n'
|
|
83
|
+
result += ' ['
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* @type {string | any[]}
|
|
87
|
+
*/
|
|
88
|
+
const payload = this.payload || []
|
|
89
|
+
const len = payload.length
|
|
90
|
+
|
|
91
|
+
if (len > 0) {
|
|
92
|
+
result += '\n'
|
|
93
|
+
for (let i = 0; i < len; i++) {
|
|
94
|
+
const item = payload[i]
|
|
95
|
+
let itemStr
|
|
96
|
+
if (item === null || item === undefined) {
|
|
97
|
+
itemStr = 'null'
|
|
98
|
+
} else if (typeof item === 'string') {
|
|
99
|
+
itemStr = ` "${item}"`
|
|
100
|
+
} else if (item instanceof Command) {
|
|
101
|
+
itemStr = item.toString().replace(/\n/g, '\n ')
|
|
102
|
+
} else {
|
|
103
|
+
itemStr = ' ' + String(item)
|
|
104
|
+
}
|
|
105
|
+
result += ' ' + itemStr
|
|
106
|
+
result += i < len - 1 ? ',\n' : '\n'
|
|
107
|
+
}
|
|
108
|
+
result += ' ]\n'
|
|
109
|
+
} else {
|
|
110
|
+
result += ' ]\n'
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
result += ' }'
|
|
114
|
+
return result
|
|
115
|
+
} catch (ex) {
|
|
116
|
+
return 'Error while converting command to string:' + (ex);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
72
119
|
}
|
package/lib/utils/CommandType.js
CHANGED