@unyt/datex 0.0.5 → 0.0.7

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 (42) hide show
  1. package/README.md +6 -4
  2. package/esm/_dnt.shims.d.ts +1 -1
  3. package/esm/datex-core/datex_core_js.internal.d.ts +290 -210
  4. package/esm/datex-core/datex_core_js.internal.d.ts.map +1 -1
  5. package/esm/datex-core/datex_core_js.internal.js +836 -524
  6. package/esm/datex-core/datex_core_js.wasm +0 -0
  7. package/esm/deno.json +11 -2
  8. package/esm/dif/builders.d.ts +11 -0
  9. package/esm/dif/builders.d.ts.map +1 -0
  10. package/esm/dif/builders.js +23 -0
  11. package/esm/dif/definitions.d.ts +116 -0
  12. package/esm/dif/definitions.d.ts.map +1 -0
  13. package/esm/dif/definitions.js +70 -0
  14. package/esm/dif/dif-handler.d.ts +217 -0
  15. package/esm/dif/dif-handler.d.ts.map +1 -0
  16. package/esm/dif/dif-handler.js +688 -0
  17. package/esm/dif/display.d.ts +8 -0
  18. package/esm/dif/display.d.ts.map +1 -0
  19. package/esm/dif/display.js +74 -0
  20. package/esm/mod.js +8 -6
  21. package/esm/network/com-hub.d.ts +1 -0
  22. package/esm/network/com-hub.d.ts.map +1 -1
  23. package/esm/network/com-hub.js +3 -0
  24. package/esm/network/interface-impls/base.d.ts +11 -0
  25. package/esm/network/interface-impls/base.d.ts.map +1 -0
  26. package/esm/network/interface-impls/base.js +21 -0
  27. package/esm/network/interface-impls/websocket-client.d.ts +6 -0
  28. package/esm/network/interface-impls/websocket-client.d.ts.map +1 -0
  29. package/esm/network/interface-impls/websocket-client.js +6 -0
  30. package/esm/network/interface-impls/websocket-server-deno.d.ts +9 -0
  31. package/esm/network/interface-impls/websocket-server-deno.d.ts.map +1 -0
  32. package/esm/network/interface-impls/websocket-server-deno.js +45 -0
  33. package/esm/refs/ref.d.ts +27 -0
  34. package/esm/refs/ref.d.ts.map +1 -0
  35. package/esm/refs/ref.js +58 -0
  36. package/esm/runtime/runtime.d.ts +97 -5
  37. package/esm/runtime/runtime.d.ts.map +1 -1
  38. package/esm/runtime/runtime.js +69 -13
  39. package/esm/runtime/special-core-types.d.ts +10 -0
  40. package/esm/runtime/special-core-types.d.ts.map +1 -0
  41. package/esm/runtime/special-core-types.js +51 -0
  42. package/package.json +10 -1
@@ -0,0 +1,688 @@
1
+ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
2
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
3
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
4
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
5
+ };
6
+ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
7
+ if (kind === "m") throw new TypeError("Private method is not writable");
8
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
9
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
10
+ return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
11
+ };
12
+ var _DIFHandler_runtime, _DIFHandler_handle, _DIFHandler_transceiver_id, _DIFHandler_cache, _DIFHandler_observers;
13
+ import * as dntShim from "../_dnt.shims.js";
14
+ import { Ref } from "../refs/ref.js";
15
+ import { Endpoint } from "../runtime/special-core-types.js";
16
+ import { CoreTypeAddress, CoreTypeAddressRanges, DIFReferenceMutability, DIFUpdateKind, } from "./definitions.js";
17
+ import { difValueContainerToDisplayString } from "./display.js";
18
+ export class DIFHandler {
19
+ get _observers() {
20
+ return __classPrivateFieldGet(this, _DIFHandler_observers, "f");
21
+ }
22
+ get _handle() {
23
+ return __classPrivateFieldGet(this, _DIFHandler_handle, "f");
24
+ }
25
+ get _transceiver_id() {
26
+ return __classPrivateFieldGet(this, _DIFHandler_transceiver_id, "f");
27
+ }
28
+ /**
29
+ * Creates a new DIFHandler instance.
30
+ * @param runtime - The JSRuntime instance for executing Datex scripts.
31
+ * @param pointerCache - The PointerCache instance for managing object pointers. If not provided, a new PointerCache will be created.
32
+ */
33
+ constructor(runtime) {
34
+ /** The JSRuntime interface for the underlying Datex Core runtime */
35
+ _DIFHandler_runtime.set(this, void 0);
36
+ _DIFHandler_handle.set(this, void 0);
37
+ // always 0 for now - potentially used for multi DIF transceivers using the same underlying runtime
38
+ _DIFHandler_transceiver_id.set(this, 0);
39
+ /** The pointer cache for storing and reusing object instances on the JS side
40
+ * The observerId is only set if the pointer is being observed (if not final).
41
+ */
42
+ _DIFHandler_cache.set(this, new Map());
43
+ _DIFHandler_observers.set(this, new Map());
44
+ __classPrivateFieldSet(this, _DIFHandler_runtime, runtime, "f");
45
+ __classPrivateFieldSet(this, _DIFHandler_handle, runtime.dif(), "f");
46
+ }
47
+ /**
48
+ * Executes a Datex script asynchronously and returns a Promise that resolves to a DIFContainer.
49
+ * @param datexScript - The Datex script source code to execute.
50
+ * @param values - An optional array of values to inject into the script.
51
+ * @returns A Promise that resolves to the execution result as a DIFContainer.
52
+ * @throws If an error occurs during execution.
53
+ */
54
+ executeDIF(datexScript, values = []) {
55
+ return __classPrivateFieldGet(this, _DIFHandler_runtime, "f").execute(datexScript, this.convertToDIFValues(values));
56
+ }
57
+ /**
58
+ * Executes a Datex script synchronously and returns the result as a DIFContainer.
59
+ * @param datexScript - The Datex script source code to execute.
60
+ * @param values - An optional array of values to inject into the script.
61
+ * @returns The execution result as a DIFContainer.
62
+ * @throws If an error occurs during execution.
63
+ */
64
+ executeSyncDIF(datexScript, values = []) {
65
+ return __classPrivateFieldGet(this, _DIFHandler_runtime, "f").execute_sync(datexScript, this.convertToDIFValues(values));
66
+ }
67
+ /**
68
+ * Creates a new pointer for the specified value.
69
+ * @param difValue - The DIFValue value to create a pointer for.
70
+ * @param allowedType - The allowed type for the pointer.
71
+ * @param mutability - The mutability of the pointer.
72
+ * @returns The created pointer address.
73
+ */
74
+ createPointer(difValue, allowedType = null, mutability) {
75
+ return __classPrivateFieldGet(this, _DIFHandler_handle, "f").create_pointer(difValue, allowedType, mutability);
76
+ }
77
+ /**
78
+ * Creates a new pointer that points to an existing address.
79
+ * @param address - The address to create a reference pointer for.
80
+ * @param allowedType - The allowed type for the pointer.
81
+ * @param mutability - The mutability of the pointer.
82
+ * @returns A Promise that resolves to the created pointer address.
83
+ */
84
+ createRefPointer(address, allowedType = null, mutability) {
85
+ return __classPrivateFieldGet(this, _DIFHandler_handle, "f").create_pointer(address, allowedType, mutability);
86
+ }
87
+ /**
88
+ * Updates the DIF value at the specified address.
89
+ * @param address - The address of the DIF value to update.
90
+ * @param dif - The DIFUpdate object containing the update information.
91
+ */
92
+ updatePointer(address, dif) {
93
+ __classPrivateFieldGet(this, _DIFHandler_handle, "f").update(__classPrivateFieldGet(this, _DIFHandler_transceiver_id, "f"), address, dif);
94
+ }
95
+ /**
96
+ * Registers an observer callback for changes to the DIF value at the specified address
97
+ * directly on the DATEX core runtime.
98
+ * This method should only be used internally, since it comes with additional overhead.
99
+ * For normal use cases, use the observePointer method instead.
100
+ * The callback will be invoked whenever the value at the address is updated.
101
+ * @param address - The address of the DIF value to observe.
102
+ * @param callback - The callback function to invoke on updates.
103
+ * @returns An observer ID that can be used to unregister the observer.
104
+ * @throws If the pointer is final.
105
+ */
106
+ observePointerBindDirect(address, callback, options = { relay_own_updates: false }) {
107
+ return __classPrivateFieldGet(this, _DIFHandler_runtime, "f").dif().observe_pointer(__classPrivateFieldGet(this, _DIFHandler_transceiver_id, "f"), address, options, callback);
108
+ }
109
+ /**
110
+ * Updates the observe options for a registered observer.
111
+ * @param address - The address of the DIF value being observed.
112
+ * @param observerId - The observer ID returned by the observePointer method.
113
+ * @param options - The new observe options to apply.
114
+ */
115
+ updateObserverOptions(address, observerId, options) {
116
+ __classPrivateFieldGet(this, _DIFHandler_runtime, "f").dif().update_observer_options(address, observerId, options);
117
+ }
118
+ /**
119
+ * Enables propagation of own updates for a registered observer.
120
+ * @param address - The address of the DIF value being observed.
121
+ * @param observerId - The observer ID returned by the observePointer method.
122
+ */
123
+ enableOwnUpdatesPropagation(address, observerId) {
124
+ this.updateObserverOptions(address, observerId, {
125
+ relay_own_updates: true,
126
+ });
127
+ }
128
+ /**
129
+ * Disables propagation of own updates for a registered observer.
130
+ * @param address - The address of the DIF value being observed.
131
+ * @param observerId - The observer ID returned by the observePointer method.
132
+ */
133
+ disableOwnUpdatesPropagation(address, observerId) {
134
+ this.updateObserverOptions(address, observerId, {
135
+ relay_own_updates: false,
136
+ });
137
+ }
138
+ /**
139
+ * Unregisters an observer that was registered directly on the DATEX core runtime
140
+ * with the observePointerBindDirect method.
141
+ * For internal use only.
142
+ * @param address - The address of the DIF value being observed.
143
+ * @param observerId - The observer ID returned by the observePointer method.
144
+ */
145
+ unobservePointerBindDirect(address, observerId) {
146
+ __classPrivateFieldGet(this, _DIFHandler_runtime, "f").dif().unobserve_pointer(address, observerId);
147
+ }
148
+ /**
149
+ * Registers a local observer callback for changes to the DIF value at the specified address.
150
+ * The callback will be invoked whenever the value at the address is updated.
151
+ * In contrast to observePointerBindDirect, this method does not register the observer
152
+ * directly on the DATEX core runtime, but keeps it local in the JS side, which prevents
153
+ * unnecessary overhead from additional cross-language calls.
154
+ * @param address - The address of the DIF value to observe.
155
+ * @param callback - The callback function to invoke on updates.
156
+ * @returns An observer ID that can be used to unregister the observer.
157
+ * @throws If the pointer is final.
158
+ */
159
+ observePointer(address, callback) {
160
+ let cached = __classPrivateFieldGet(this, _DIFHandler_cache, "f").get(address);
161
+ if (!cached) {
162
+ // first resolve the pointer to make sure it's loaded in the cache
163
+ this.resolvePointerAddressSync(address);
164
+ cached = __classPrivateFieldGet(this, _DIFHandler_cache, "f").get(address);
165
+ }
166
+ // make sure the pointer is not final (no observer)
167
+ if (cached.observerId === null) {
168
+ throw new Error(`Cannot observe final reference $${address}`);
169
+ }
170
+ // directly add to observers map
171
+ let observers = __classPrivateFieldGet(this, _DIFHandler_observers, "f").get(address);
172
+ if (!observers) {
173
+ observers = new Map();
174
+ __classPrivateFieldGet(this, _DIFHandler_observers, "f").set(address, observers);
175
+ // first local observer for this address - enable own updates propagation
176
+ this.enableOwnUpdatesPropagation(address, cached.observerId);
177
+ }
178
+ // FIXME make this more robust for delete/re-add cases
179
+ const observerId = observers.size + 1;
180
+ observers.set(observerId, callback);
181
+ return observerId;
182
+ }
183
+ /**
184
+ * Unregisters an observer that was registered with the observePointer method.
185
+ * @param address - The address of the DIF value being observed.
186
+ * @param observerId - The observer ID returned by the observePointer method.
187
+ * @returns True if the observer was successfully unregistered, false otherwise.
188
+ */
189
+ unobservePointer(address, observerId) {
190
+ const observers = __classPrivateFieldGet(this, _DIFHandler_observers, "f").get(address);
191
+ if (observers) {
192
+ observers.delete(observerId);
193
+ if (observers.size === 0) {
194
+ // no local observers left - disable own updates propagation and remove from map
195
+ const cached = __classPrivateFieldGet(this, _DIFHandler_cache, "f").get(address);
196
+ if (cached?.observerId) {
197
+ this.disableOwnUpdatesPropagation(address, cached.observerId);
198
+ }
199
+ else {
200
+ console.error(`No observer found for address ${address}`);
201
+ }
202
+ return __classPrivateFieldGet(this, _DIFHandler_observers, "f").delete(address);
203
+ }
204
+ }
205
+ return false;
206
+ }
207
+ /**
208
+ * Resolves a DIFValue to its corresponding JS value.
209
+ * This function handles core types and custom types (not yet implemented).
210
+ * It returns the resolved value as the specified type T.
211
+ * @param value
212
+ */
213
+ resolveDIFValue(value) {
214
+ console.log("RESOLVE", value);
215
+ let type = value.type;
216
+ if (type === undefined) {
217
+ if (Array.isArray(value.value)) {
218
+ if (Array.isArray(value.value[0])) {
219
+ type = CoreTypeAddress.map;
220
+ }
221
+ else {
222
+ type = CoreTypeAddress.list;
223
+ }
224
+ }
225
+ else {
226
+ return value.value;
227
+ }
228
+ }
229
+ console.log(type, value);
230
+ // null, boolean and text types values are just returned as is
231
+ if (type === CoreTypeAddress.boolean ||
232
+ type == CoreTypeAddress.text ||
233
+ type === CoreTypeAddress.null) {
234
+ return value.value;
235
+ } // small integers are interpreted as JS numbers
236
+ else if (typeof type === "string" && (type == CoreTypeAddress.integer ||
237
+ this.isPointerAddressInAdresses(type, CoreTypeAddressRanges.small_signed_integers) ||
238
+ this.isPointerAddressInAdresses(type, CoreTypeAddressRanges.small_unsigned_integers))) {
239
+ return Number(value.value);
240
+ } // big integers are interpreted as JS BigInt
241
+ else if (typeof type === "string" && (this.isPointerAddressInAdresses(type, CoreTypeAddressRanges.big_signed_integers) ||
242
+ this.isPointerAddressInAdresses(type, CoreTypeAddressRanges.big_unsigned_integers))) {
243
+ return BigInt(value.value);
244
+ } // decimal types are interpreted as JS numbers
245
+ else if (typeof type === "string" &&
246
+ this.isPointerAddressInAdresses(type, CoreTypeAddressRanges.decimals)) {
247
+ return Number(value.value);
248
+ } // endpoint types are resolved to Endpoint instances
249
+ else if (type === CoreTypeAddress.endpoint) {
250
+ return Endpoint.get(value.value);
251
+ }
252
+ else if (type === CoreTypeAddress.list) {
253
+ return this.promiseAllOrSync(value.value.map((v) => this.resolveDIFValueContainer(v)));
254
+ } // map types are resolved from a DIFObject (aka JS Map) or Array of key-value pairs to a JS object
255
+ else if (type === CoreTypeAddress.map) {
256
+ if (Array.isArray(value.value)) {
257
+ const resolvedMap = new Map();
258
+ for (const [key, val] of value.value) {
259
+ // TODO: currently always converting to an object here, but this should be a Map per default
260
+ resolvedMap.set(this.resolveDIFValueContainer(key), this.resolveDIFValueContainer(val));
261
+ }
262
+ // TODO: map promises
263
+ return resolvedMap;
264
+ }
265
+ else {
266
+ const resolvedObj = {};
267
+ for (const [key, val] of Object.entries(value.value)) {
268
+ // TODO: currently always converting to an object here, but this should be a Map per default
269
+ resolvedObj[key] = this.resolveDIFValueContainer(val);
270
+ }
271
+ return this.promiseFromObjectOrSync(resolvedObj);
272
+ }
273
+ }
274
+ else {
275
+ // custom types not implemented yet
276
+ throw new Error("Custom type resolution not implemented yet");
277
+ }
278
+ }
279
+ /**
280
+ * Converts an array of Promises or resolved values to either a Promise of an array of resolved values,
281
+ * or an array of resolved values if all values are already resolved.
282
+ */
283
+ promiseAllOrSync(values) {
284
+ if (values.some((v) => v instanceof Promise)) {
285
+ return Promise.all(values);
286
+ }
287
+ else {
288
+ return values;
289
+ }
290
+ }
291
+ /**
292
+ * Converts an object with values that may be Promises to either a Promise of an object with resolved values,
293
+ * or an object with resolved values if all values are already resolved.
294
+ */
295
+ promiseFromObjectOrSync(values) {
296
+ const valueArray = Object.values(values);
297
+ if (valueArray.some((v) => v instanceof Promise)) {
298
+ return Promise.all(valueArray).then((resolvedValues) => {
299
+ const resolvedObj = {};
300
+ let i = 0;
301
+ for (const key of Object.keys(values)) {
302
+ resolvedObj[key] = resolvedValues[i++];
303
+ }
304
+ return resolvedObj;
305
+ });
306
+ }
307
+ else {
308
+ return values;
309
+ }
310
+ }
311
+ /**
312
+ * Maps a value or Promise of a value to another value or Promise of a value using the provided onfulfilled function.
313
+ */
314
+ mapPromise(value, onfulfilled) {
315
+ if (value instanceof Promise) {
316
+ return value.then(onfulfilled);
317
+ }
318
+ else {
319
+ return onfulfilled(value);
320
+ }
321
+ }
322
+ /**
323
+ * Resolves a DIFValueContainer (either a DIFValue or a pointer address) to its corresponding JS value.
324
+ * If the container contains pointers that are not yet loaded in memory, it returns a Promise that resolves to the value.
325
+ * Otherwise, it returns the resolved value directly.
326
+ * @param value - The DIFValueContainer to resolve.
327
+ * @returns The resolved value as type T, or a Promise that resolves to type T.
328
+ */
329
+ resolveDIFValueContainer(value) {
330
+ if (typeof value !== "string") {
331
+ return this.resolveDIFValue(value);
332
+ }
333
+ else {
334
+ return this.resolvePointerAddress(value);
335
+ }
336
+ }
337
+ /**
338
+ * Synchronous version of resolveDIFValueContainer.
339
+ * This method can only be used if the value only contains pointer addresses that are already loaded in memory -
340
+ * otherwise, use the asynchronous `resolveDIFValueContainer` method instead.
341
+ * @param value - The DIFValueContainer to resolve.
342
+ * @returns The resolved value as type T.
343
+ * @throws If the resolution would require asynchronous operations.
344
+ */
345
+ resolveDIFValueContainerSync(value) {
346
+ const result = this.resolveDIFValueContainer(value);
347
+ if (result instanceof Promise) {
348
+ throw new Error("resolveDIFValueContainerSync cannot return a Promise. Use resolveDIFValueContainer() instead.");
349
+ }
350
+ return result;
351
+ }
352
+ /**
353
+ * Resolves a pointer address to its corresponding JS value.
354
+ * If the pointer address is not yet loaded in memory, it returns a Promise that resolves to the value.
355
+ * Otherwise, it returns the resolved value directly.
356
+ * @param address - The pointer address to resolve.
357
+ * @returns The resolved value as type T, or a Promise that resolves to type T.
358
+ */
359
+ resolvePointerAddress(address) {
360
+ // check cache first
361
+ const cached = this.getCachedPointer(address);
362
+ if (cached) {
363
+ return cached;
364
+ }
365
+ // if not in cache, resolve from runtime
366
+ const reference = __classPrivateFieldGet(this, _DIFHandler_handle, "f").resolve_pointer_address(address);
367
+ return this.mapPromise(reference, (reference) => {
368
+ const value = this.resolveDIFValueContainer(reference.value);
369
+ return this.mapPromise(value, (v) => {
370
+ // init pointer
371
+ this.initPointer(address, v, reference.mut, reference.allowed_type);
372
+ return v;
373
+ });
374
+ });
375
+ }
376
+ /**
377
+ * Resolves a pointer address to its corresponding JS value synchronously.
378
+ * If the pointer address is not yet loaded in memory, it returns a Promise that resolves to the value.
379
+ * Otherwise, it returns the resolved value directly.
380
+ * @param address - The pointer address to resolve.
381
+ * @returns The resolved value as type T, or a Promise that resolves to type T.
382
+ * @throws If the resolution would require asynchronous operations.
383
+ */
384
+ resolvePointerAddressSync(address) {
385
+ // check cache first
386
+ const cached = this.getCachedPointer(address);
387
+ if (cached) {
388
+ return cached;
389
+ }
390
+ // if not in cache, resolve from runtime
391
+ const entry = __classPrivateFieldGet(this, _DIFHandler_handle, "f")
392
+ .resolve_pointer_address_sync(address);
393
+ const value = this.resolveDIFValueContainerSync(entry.value);
394
+ this.initPointer(address, value, entry.mut, entry.allowed_type);
395
+ return value;
396
+ }
397
+ /**
398
+ * Converts an array of JS values to an array of DIFValues.
399
+ * If the input is null, it returns null.
400
+ * @param values
401
+ */
402
+ convertToDIFValues(values) {
403
+ return values?.map((value) => this.convertJSValueToDIFValue(value)) ||
404
+ null;
405
+ }
406
+ /**
407
+ * Returns true if the given address is within the specified address range.
408
+ */
409
+ isPointerAddressInAdresses(address, range) {
410
+ return range.has(address);
411
+ }
412
+ /**
413
+ * Initializes a pointer with the given value and mutability, by
414
+ * adding a proxy wrapper if necessary, and setting up observation and caching on the JS side.
415
+ */
416
+ initPointer(ptrAddress, value, mutability, allowedType = null) {
417
+ const refValue = this.wrapJSValueInProxy(value, ptrAddress, allowedType);
418
+ // if not final, observe to keep the pointer 'live' and receive updates
419
+ let observerId = null;
420
+ if (mutability !== DIFReferenceMutability.Final) {
421
+ observerId = this.observePointerBindDirect(ptrAddress, (update) => {
422
+ // if source_id is not own transceiver id, handle pointer update
423
+ if (update.source_id !== __classPrivateFieldGet(this, _DIFHandler_transceiver_id, "f")) {
424
+ this.handlePointerUpdate(ptrAddress, update.data);
425
+ }
426
+ // call all local observers
427
+ const observers = __classPrivateFieldGet(this, _DIFHandler_observers, "f").get(ptrAddress);
428
+ if (observers) {
429
+ for (const cb of observers.values()) {
430
+ try {
431
+ cb(update.data);
432
+ }
433
+ catch (e) {
434
+ console.error("Error in pointer observer callback", e);
435
+ }
436
+ }
437
+ }
438
+ console.debug("Pointer update received", update);
439
+ });
440
+ }
441
+ this.cacheWrappedPointerValue(ptrAddress, refValue, observerId);
442
+ return refValue;
443
+ }
444
+ /**
445
+ * Handles a pointer update received from the DATEX core runtime.
446
+ * If the pointer is cached and has a dereferenceable value, it updates the value.
447
+ * @param address - The address of the pointer being updated.
448
+ * @param update - The DIFUpdateData containing the update information.
449
+ * @returns True if the pointer was found and updated, false otherwise.
450
+ */
451
+ handlePointerUpdate(address, update) {
452
+ const cached = __classPrivateFieldGet(this, _DIFHandler_cache, "f").get(address);
453
+ if (!cached)
454
+ return false;
455
+ const deref = cached.val.deref();
456
+ if (!deref)
457
+ return false;
458
+ if (deref instanceof Ref && update.kind === DIFUpdateKind.Replace) {
459
+ deref.updateValueSilently(this.resolveDIFValueContainerSync(update.value));
460
+ }
461
+ // TODO: handle generic updates for values (depending on type interface definition)
462
+ return true;
463
+ }
464
+ /**
465
+ * Caches the given pointer value with the given address in the JS side cache.
466
+ * The pointer must already be wrapped if necessary.
467
+ */
468
+ cacheWrappedPointerValue(address, value, observerId) {
469
+ __classPrivateFieldGet(this, _DIFHandler_cache, "f").set(address, {
470
+ val: new dntShim.WeakRef(value),
471
+ observerId,
472
+ });
473
+ // register finalizer to clean up the cache and free the pointer in the runtime
474
+ // when the object is garbage collected
475
+ const finalizationRegistry = new FinalizationRegistry((address) => {
476
+ __classPrivateFieldGet(this, _DIFHandler_cache, "f").delete(address);
477
+ // remove local observers
478
+ __classPrivateFieldGet(this, _DIFHandler_observers, "f").delete(address);
479
+ // if observer is active, unregister it
480
+ if (observerId !== null) {
481
+ this.unobservePointerBindDirect(address, observerId);
482
+ }
483
+ });
484
+ finalizationRegistry.register(value, address);
485
+ }
486
+ getCachedPointer(address) {
487
+ const cached = __classPrivateFieldGet(this, _DIFHandler_cache, "f").get(address);
488
+ if (cached) {
489
+ const deref = cached.val.deref();
490
+ if (deref) {
491
+ return deref;
492
+ }
493
+ }
494
+ return undefined;
495
+ }
496
+ /**
497
+ * Creates a new pointer containg the given JS value.
498
+ * The returned value is a proxy object that behaves like the original object,
499
+ * but also propagates changes between JS and the DATEX runtime.
500
+ */
501
+ createPointerFromJSValue(value, allowedType = null, mutability = DIFReferenceMutability.Mutable) {
502
+ const difValue = this.convertJSValueToDIFValue(value);
503
+ console.log("DIF", difValueContainerToDisplayString(difValue));
504
+ const ptrAddress = this.createPointer(difValue, allowedType, mutability);
505
+ // get inferred allowed type from pointer if not explicitly set
506
+ if (!allowedType) {
507
+ allowedType = __classPrivateFieldGet(this, _DIFHandler_handle, "f").resolve_pointer_address_sync(ptrAddress).allowed_type;
508
+ }
509
+ return this.initPointer(ptrAddress, value, mutability, allowedType); // TODO: map to correct pointer wrapper type
510
+ }
511
+ wrapJSValueInProxy(value, pointerAddress, _type = null) {
512
+ // primitive values are always wrapped in a Ref proxy
513
+ if (value === null || value === undefined ||
514
+ typeof value === "boolean" ||
515
+ typeof value === "number" || typeof value === "bigint" ||
516
+ typeof value === "string") {
517
+ return new Ref(value, pointerAddress, this);
518
+ }
519
+ else if (value instanceof Map) {
520
+ return this.proxifyJSMap(value, pointerAddress);
521
+ }
522
+ else if (typeof value === "object") {
523
+ return this.wrapJSObjectInProxy(value);
524
+ }
525
+ else {
526
+ return value;
527
+ }
528
+ }
529
+ isRef(value) {
530
+ return value instanceof Ref;
531
+ }
532
+ proxifyJSMap(map, pointerAddress) {
533
+ const originalSet = map.set;
534
+ const originalDelete = map.delete;
535
+ const originalClear = map.clear;
536
+ // deno-lint-ignore no-this-alias
537
+ const self = this;
538
+ Object.defineProperties(map, {
539
+ set: {
540
+ value: function (key, value) {
541
+ self.updatePointer(pointerAddress, {
542
+ kind: DIFUpdateKind.Set,
543
+ key: {
544
+ kind: "value",
545
+ value: self.convertJSValueToDIFValue(key),
546
+ },
547
+ value: self.convertJSValueToDIFValue(value),
548
+ });
549
+ return originalSet.call(this, key, value);
550
+ },
551
+ configurable: true,
552
+ writable: true,
553
+ },
554
+ delete: {
555
+ value: function (key) {
556
+ self.updatePointer(pointerAddress, {
557
+ kind: DIFUpdateKind.Remove,
558
+ key: {
559
+ kind: "value",
560
+ value: self.convertJSValueToDIFValue(key),
561
+ },
562
+ });
563
+ const result = originalDelete.call(this, key);
564
+ return result;
565
+ },
566
+ configurable: true,
567
+ writable: true,
568
+ },
569
+ clear: {
570
+ value: function () {
571
+ self.updatePointer(pointerAddress, {
572
+ kind: DIFUpdateKind.Clear,
573
+ });
574
+ const result = originalClear.call(this);
575
+ return result;
576
+ },
577
+ configurable: true,
578
+ writable: true,
579
+ },
580
+ });
581
+ return map;
582
+ }
583
+ wrapJSObjectInProxy(value) {
584
+ // deno-lint-ignore no-this-alias
585
+ const self = this;
586
+ return new Proxy(value, {
587
+ get(target, prop, receiver) {
588
+ const val = Reflect.get(target, prop, receiver);
589
+ if (val && typeof val === "object" && !self.isRef(val)) {
590
+ return self.wrapJSObjectInProxy(val);
591
+ }
592
+ return val;
593
+ },
594
+ set(target, prop, newValue, receiver) {
595
+ const oldValue = Reflect.get(target, prop, receiver);
596
+ if (!self.isRef(oldValue)) {
597
+ throw new Error(`Cannot modify non-Ref property "${String(prop)}"`);
598
+ }
599
+ oldValue.value = newValue;
600
+ return true;
601
+ },
602
+ deleteProperty() {
603
+ throw new Error("Cannot delete properties from a Refs-only object");
604
+ },
605
+ defineProperty() {
606
+ throw new Error("Cannot define new properties on a Refs-only object");
607
+ },
608
+ });
609
+ }
610
+ /// Returns the pointer address for the given value if it is already cached, or null otherwise.
611
+ /// TODO: optimize by using a reverse map or direct Symbols on the objects
612
+ /// But this is probably not important for normal use cases
613
+ getPointerAddressForValue(value) {
614
+ for (const [address, entry] of __classPrivateFieldGet(this, _DIFHandler_cache, "f")) {
615
+ const deref = entry.val.deref();
616
+ if (deref === value) {
617
+ return address;
618
+ }
619
+ }
620
+ return null;
621
+ }
622
+ /**
623
+ * Converts a given JS value to its DIFValue representation.
624
+ */
625
+ convertJSValueToDIFValue(value) {
626
+ // assuming core values
627
+ // TODO: handle custom types
628
+ if (value === null) {
629
+ return {
630
+ value: null,
631
+ };
632
+ }
633
+ else if (typeof value === "boolean") {
634
+ return {
635
+ value,
636
+ };
637
+ }
638
+ else if (typeof value === "number") {
639
+ return {
640
+ value,
641
+ };
642
+ }
643
+ else if (typeof value === "bigint") {
644
+ return {
645
+ type: CoreTypeAddress.integer_big,
646
+ value: value.toString(), // convert bigint to string for DIFValue
647
+ };
648
+ }
649
+ else if (typeof value === "string") {
650
+ return {
651
+ value,
652
+ };
653
+ }
654
+ else if (value instanceof Endpoint) {
655
+ return {
656
+ type: CoreTypeAddress.endpoint,
657
+ value: value.toString(),
658
+ };
659
+ }
660
+ else if (Array.isArray(value)) {
661
+ return {
662
+ value: value.map((v) => this.convertJSValueToDIFValue(v)),
663
+ };
664
+ }
665
+ else if (value instanceof Map) {
666
+ const map = value.entries().map(([k, v]) => [
667
+ this.convertJSValueToDIFValue(k),
668
+ this.convertJSValueToDIFValue(v),
669
+ ]).toArray();
670
+ return {
671
+ type: CoreTypeAddress.map,
672
+ value: map,
673
+ };
674
+ }
675
+ else if (typeof value === "object") {
676
+ const map = {};
677
+ for (const [key, val] of Object.entries(value)) {
678
+ map[key] = this.convertJSValueToDIFValue(val);
679
+ }
680
+ return {
681
+ type: CoreTypeAddress.map,
682
+ value: map,
683
+ };
684
+ }
685
+ throw new Error("Unsupported type for conversion to DIFValue");
686
+ }
687
+ }
688
+ _DIFHandler_runtime = new WeakMap(), _DIFHandler_handle = new WeakMap(), _DIFHandler_transceiver_id = new WeakMap(), _DIFHandler_cache = new WeakMap(), _DIFHandler_observers = new WeakMap();