@skipruntime/core 0.0.1 → 0.0.3
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/binding.d.ts +2 -6
- package/dist/binding.d.ts.map +1 -1
- package/dist/binding.js.map +1 -1
- package/dist/index.d.ts +31 -49
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +18 -95
- package/dist/index.js.map +1 -1
- package/dist/remote.d.ts +17 -6
- package/dist/remote.d.ts.map +1 -1
- package/dist/remote.js +22 -5
- package/dist/remote.js.map +1 -1
- package/dist/utils.d.ts +44 -11
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +54 -15
- package/dist/utils.js.map +1 -1
- package/package.json +2 -2
- package/src/binding.ts +2 -6
- package/src/index.ts +85 -134
- package/src/remote.ts +24 -9
- package/src/utils.ts +57 -17
package/src/index.ts
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The @skipruntime/core package contains internal implementation detail for the Skip Framework and should not need to be used directly. See the public API exposed by the @skipruntime/helpers package.
|
|
3
|
+
*
|
|
4
|
+
* @packageDocumentation
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type { Opaque } from "@skiplang/std";
|
|
1
8
|
import type {
|
|
2
9
|
Pointer,
|
|
3
10
|
Nullable,
|
|
@@ -5,7 +12,12 @@ import type {
|
|
|
5
12
|
JsonConverter,
|
|
6
13
|
JsonObject,
|
|
7
14
|
} from "@skiplang/json";
|
|
8
|
-
import {
|
|
15
|
+
import {
|
|
16
|
+
sk_freeze,
|
|
17
|
+
isSkManaged,
|
|
18
|
+
SkManaged,
|
|
19
|
+
checkOrCloneParam,
|
|
20
|
+
} from "@skiplang/json";
|
|
9
21
|
import type * as Internal from "./internal.js";
|
|
10
22
|
import {
|
|
11
23
|
NonUniqueValueException,
|
|
@@ -18,16 +30,14 @@ import {
|
|
|
18
30
|
type LazyCompute,
|
|
19
31
|
type Mapper,
|
|
20
32
|
type NamedCollections,
|
|
21
|
-
type
|
|
22
|
-
type
|
|
33
|
+
type Values,
|
|
34
|
+
type DepSafe,
|
|
23
35
|
type Reducer,
|
|
24
36
|
type Resource,
|
|
25
37
|
type SkipService,
|
|
26
|
-
type SubscriptionID,
|
|
27
38
|
type Watermark,
|
|
28
39
|
} from "@skipruntime/api";
|
|
29
40
|
|
|
30
|
-
import { Frozen } from "@skipruntime/api/internals.js";
|
|
31
41
|
import { UnknownCollectionError } from "./errors.js";
|
|
32
42
|
import {
|
|
33
43
|
ResourceBuilder,
|
|
@@ -37,99 +47,40 @@ import {
|
|
|
37
47
|
type FromBinding,
|
|
38
48
|
} from "./binding.js";
|
|
39
49
|
|
|
40
|
-
export { UnknownCollectionError, sk_freeze,
|
|
50
|
+
export { UnknownCollectionError, sk_freeze, isSkManaged };
|
|
41
51
|
export { SkipExternalService } from "./remote.js";
|
|
42
|
-
export { Sum, Min, Max, CountMapper } from "./utils.js";
|
|
52
|
+
export { Sum, Min, Max, Count, CountMapper } from "./utils.js";
|
|
43
53
|
|
|
44
54
|
export type JSONMapper = Mapper<Json, Json, Json, Json>;
|
|
45
55
|
export type JSONLazyCompute = LazyCompute<Json, Json>;
|
|
46
56
|
|
|
57
|
+
/**
|
|
58
|
+
* An entry point of a Skip reactive service.
|
|
59
|
+
*
|
|
60
|
+
* URLs for the service's control and streaming APIs can be constructed from an `Entrypoint`.
|
|
61
|
+
*/
|
|
47
62
|
export type Entrypoint = {
|
|
63
|
+
/**
|
|
64
|
+
* Hostname of the service.
|
|
65
|
+
*/
|
|
48
66
|
host: string;
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Port to use for the service's streaming interface.
|
|
70
|
+
*/
|
|
49
71
|
streaming_port: number;
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Port to use for the service's control interface.
|
|
75
|
+
*/
|
|
50
76
|
control_port: number;
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Flag that when set indicates that https should be used instead of http.
|
|
80
|
+
*/
|
|
51
81
|
secured?: boolean;
|
|
52
82
|
};
|
|
53
83
|
|
|
54
|
-
abstract class SkFrozen extends Frozen {
|
|
55
|
-
protected freeze() {
|
|
56
|
-
sk_freeze(this);
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
function checkOrCloneParam<T>(value: T): T {
|
|
61
|
-
if (
|
|
62
|
-
typeof value == "string" ||
|
|
63
|
-
typeof value == "number" ||
|
|
64
|
-
typeof value == "boolean"
|
|
65
|
-
)
|
|
66
|
-
return value;
|
|
67
|
-
if (typeof value == "object") {
|
|
68
|
-
if (value === null) return value;
|
|
69
|
-
if (isObjectProxy(value)) return value.clone() as T;
|
|
70
|
-
if (isSkFrozen(value)) return value;
|
|
71
|
-
throw new Error("Invalid object: must be deep-frozen.");
|
|
72
|
-
}
|
|
73
|
-
throw new Error(`'${typeof value}' cannot be deep-frozen.`);
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
/**
|
|
77
|
-
* _Deep-freeze_ an object, returning the same object that was passed in.
|
|
78
|
-
*
|
|
79
|
-
* This function is similar to
|
|
80
|
-
* {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze | `Object.freeze()`}
|
|
81
|
-
* but freezes the object and deep-freezes all its properties,
|
|
82
|
-
* recursively. The object is then not only _immutable_ but also
|
|
83
|
-
* _constant_. Note that as a result all objects reachable from the
|
|
84
|
-
* parameter will be frozen and no longer mutable or extensible, even from
|
|
85
|
-
* other references.
|
|
86
|
-
*
|
|
87
|
-
* The argument object and all its properties, recursively, must not already
|
|
88
|
-
* be frozen by `Object.freeze` (or else `deepFreeze` cannot mark them
|
|
89
|
-
* deep-frozen). Undefined, function (and hence class) values cannot be
|
|
90
|
-
* deep-frozen.
|
|
91
|
-
*
|
|
92
|
-
* The primary use for this function is to satisfy the requirement that all
|
|
93
|
-
* parameters to Skip `Mapper` constructors must be deep-frozen: objects
|
|
94
|
-
* that have not been constructed by Skip can be passed to `deepFreeze()`
|
|
95
|
-
* before passing them to a `Mapper` constructor.
|
|
96
|
-
*
|
|
97
|
-
* @param value - The object to deep-freeze.
|
|
98
|
-
* @returns The same object that was passed in.
|
|
99
|
-
*/
|
|
100
|
-
export function deepFreeze<T>(value: T): T & Param {
|
|
101
|
-
if (
|
|
102
|
-
typeof value == "bigint" ||
|
|
103
|
-
typeof value == "boolean" ||
|
|
104
|
-
typeof value == "number" ||
|
|
105
|
-
typeof value == "string" ||
|
|
106
|
-
typeof value == "symbol"
|
|
107
|
-
) {
|
|
108
|
-
return value;
|
|
109
|
-
} else if (typeof value == "object") {
|
|
110
|
-
if (value === null) {
|
|
111
|
-
return value;
|
|
112
|
-
} else if (isSkFrozen(value)) {
|
|
113
|
-
return value;
|
|
114
|
-
} else if (Object.isFrozen(value)) {
|
|
115
|
-
throw new Error(`Cannot deep-freeze an Object.frozen value.`);
|
|
116
|
-
} else if (Array.isArray(value)) {
|
|
117
|
-
for (const elt of value) {
|
|
118
|
-
deepFreeze(elt);
|
|
119
|
-
}
|
|
120
|
-
return Object.freeze(sk_freeze(value));
|
|
121
|
-
} else {
|
|
122
|
-
for (const val of Object.values(value)) {
|
|
123
|
-
deepFreeze(val);
|
|
124
|
-
}
|
|
125
|
-
return Object.freeze(sk_freeze(value));
|
|
126
|
-
}
|
|
127
|
-
} else {
|
|
128
|
-
// typeof value == "function" || typeof value == "undefined"
|
|
129
|
-
throw new Error(`'${typeof value}' values cannot be deep-frozen.`);
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
|
|
133
84
|
class Handles {
|
|
134
85
|
private nextID: number = 1;
|
|
135
86
|
private readonly objects: any[] = [];
|
|
@@ -187,7 +138,7 @@ export class Refs {
|
|
|
187
138
|
}
|
|
188
139
|
|
|
189
140
|
class LazyCollectionImpl<K extends Json, V extends Json>
|
|
190
|
-
extends
|
|
141
|
+
extends SkManaged
|
|
191
142
|
implements LazyCollection<K, V>
|
|
192
143
|
{
|
|
193
144
|
constructor(
|
|
@@ -198,29 +149,29 @@ class LazyCollectionImpl<K extends Json, V extends Json>
|
|
|
198
149
|
Object.freeze(this);
|
|
199
150
|
}
|
|
200
151
|
|
|
201
|
-
getArray(key: K): (V &
|
|
152
|
+
getArray(key: K): (V & DepSafe)[] {
|
|
202
153
|
return this.refs.skjson.importJSON(
|
|
203
154
|
this.refs.binding.SkipRuntime_LazyCollection__getArray(
|
|
204
155
|
this.lazyCollection,
|
|
205
156
|
this.refs.skjson.exportJSON(key),
|
|
206
157
|
),
|
|
207
|
-
) as (V &
|
|
158
|
+
) as (V & DepSafe)[];
|
|
208
159
|
}
|
|
209
160
|
|
|
210
|
-
getUnique(key: K): V &
|
|
161
|
+
getUnique(key: K): V & DepSafe {
|
|
211
162
|
const v = this.refs.skjson.importOptJSON(
|
|
212
163
|
this.refs.binding.SkipRuntime_LazyCollection__getUnique(
|
|
213
164
|
this.lazyCollection,
|
|
214
165
|
this.refs.skjson.exportJSON(key),
|
|
215
166
|
),
|
|
216
|
-
) as Nullable<V &
|
|
167
|
+
) as Nullable<V & DepSafe>;
|
|
217
168
|
if (v == null) throw new NonUniqueValueException();
|
|
218
169
|
return v;
|
|
219
170
|
}
|
|
220
171
|
}
|
|
221
172
|
|
|
222
173
|
class EagerCollectionImpl<K extends Json, V extends Json>
|
|
223
|
-
extends
|
|
174
|
+
extends SkManaged
|
|
224
175
|
implements EagerCollection<K, V>
|
|
225
176
|
{
|
|
226
177
|
constructor(
|
|
@@ -231,22 +182,22 @@ class EagerCollectionImpl<K extends Json, V extends Json>
|
|
|
231
182
|
Object.freeze(this);
|
|
232
183
|
}
|
|
233
184
|
|
|
234
|
-
getArray(key: K): (V &
|
|
185
|
+
getArray(key: K): (V & DepSafe)[] {
|
|
235
186
|
return this.refs.skjson.importJSON(
|
|
236
187
|
this.refs.binding.SkipRuntime_Collection__getArray(
|
|
237
188
|
this.collection,
|
|
238
189
|
this.refs.skjson.exportJSON(key),
|
|
239
190
|
),
|
|
240
|
-
) as (V &
|
|
191
|
+
) as (V & DepSafe)[];
|
|
241
192
|
}
|
|
242
193
|
|
|
243
|
-
getUnique(key: K): V &
|
|
194
|
+
getUnique(key: K): V & DepSafe {
|
|
244
195
|
const v = this.refs.skjson.importOptJSON(
|
|
245
196
|
this.refs.binding.SkipRuntime_Collection__getUnique(
|
|
246
197
|
this.collection,
|
|
247
198
|
this.refs.skjson.exportJSON(key),
|
|
248
199
|
),
|
|
249
|
-
) as Nullable<V &
|
|
200
|
+
) as Nullable<V & DepSafe>;
|
|
250
201
|
if (v == null) throw new NonUniqueValueException();
|
|
251
202
|
return v;
|
|
252
203
|
}
|
|
@@ -277,7 +228,7 @@ class EagerCollectionImpl<K extends Json, V extends Json>
|
|
|
277
228
|
return this.derive<K, V>(skcollection);
|
|
278
229
|
}
|
|
279
230
|
|
|
280
|
-
map<K2 extends Json, V2 extends Json, Params extends
|
|
231
|
+
map<K2 extends Json, V2 extends Json, Params extends DepSafe[]>(
|
|
281
232
|
mapper: new (...params: Params) => Mapper<K, V, K2, V2>,
|
|
282
233
|
...params: Params
|
|
283
234
|
): EagerCollection<K2, V2> {
|
|
@@ -297,11 +248,11 @@ class EagerCollectionImpl<K extends Json, V extends Json>
|
|
|
297
248
|
return this.derive<K2, V2>(mapped);
|
|
298
249
|
}
|
|
299
250
|
|
|
300
|
-
mapReduce<K2 extends Json, V2 extends Json, MapperParams extends
|
|
251
|
+
mapReduce<K2 extends Json, V2 extends Json, MapperParams extends DepSafe[]>(
|
|
301
252
|
mapper: new (...params: MapperParams) => Mapper<K, V, K2, V2>,
|
|
302
253
|
...mapperParams: MapperParams
|
|
303
254
|
) {
|
|
304
|
-
return <Accum extends Json, ReducerParams extends
|
|
255
|
+
return <Accum extends Json, ReducerParams extends DepSafe[]>(
|
|
305
256
|
reducer: new (...params: ReducerParams) => Reducer<V2, Accum>,
|
|
306
257
|
...reducerParams: ReducerParams
|
|
307
258
|
) => {
|
|
@@ -326,7 +277,7 @@ class EagerCollectionImpl<K extends Json, V extends Json>
|
|
|
326
277
|
);
|
|
327
278
|
const skreducer = this.refs.binding.SkipRuntime_createReducer(
|
|
328
279
|
this.refs.handles.register(reducerObj),
|
|
329
|
-
this.refs.skjson.exportJSON(reducerObj.
|
|
280
|
+
this.refs.skjson.exportJSON(reducerObj.initial),
|
|
330
281
|
);
|
|
331
282
|
const mapped = this.refs.binding.SkipRuntime_Collection__mapReduce(
|
|
332
283
|
this.collection,
|
|
@@ -337,7 +288,7 @@ class EagerCollectionImpl<K extends Json, V extends Json>
|
|
|
337
288
|
};
|
|
338
289
|
}
|
|
339
290
|
|
|
340
|
-
reduce<Accum extends Json, Params extends
|
|
291
|
+
reduce<Accum extends Json, Params extends DepSafe[]>(
|
|
341
292
|
reducer: new (...params: Params) => Reducer<V, Accum>,
|
|
342
293
|
...params: Params
|
|
343
294
|
): EagerCollection<K, Accum> {
|
|
@@ -349,7 +300,7 @@ class EagerCollectionImpl<K extends Json, V extends Json>
|
|
|
349
300
|
}
|
|
350
301
|
const skreducer = this.refs.binding.SkipRuntime_createReducer(
|
|
351
302
|
this.refs.handles.register(reducerObj),
|
|
352
|
-
this.refs.skjson.exportJSON(reducerObj.
|
|
303
|
+
this.refs.skjson.exportJSON(reducerObj.initial),
|
|
353
304
|
);
|
|
354
305
|
return this.derive<K, Accum>(
|
|
355
306
|
this.refs.binding.SkipRuntime_Collection__reduce(
|
|
@@ -420,13 +371,17 @@ class CollectionWriter<K extends Json, V extends Json> {
|
|
|
420
371
|
}
|
|
421
372
|
}
|
|
422
373
|
|
|
423
|
-
class ContextImpl extends
|
|
374
|
+
class ContextImpl extends SkManaged implements Context {
|
|
424
375
|
constructor(private readonly refs: Refs) {
|
|
425
376
|
super();
|
|
426
377
|
Object.freeze(this);
|
|
427
378
|
}
|
|
428
379
|
|
|
429
|
-
createLazyCollection<
|
|
380
|
+
createLazyCollection<
|
|
381
|
+
K extends Json,
|
|
382
|
+
V extends Json,
|
|
383
|
+
Params extends DepSafe[],
|
|
384
|
+
>(
|
|
430
385
|
compute: new (...params: Params) => LazyCompute<K, V>,
|
|
431
386
|
...params: Params
|
|
432
387
|
): LazyCollection<K, V> {
|
|
@@ -447,7 +402,7 @@ class ContextImpl extends SkFrozen implements Context {
|
|
|
447
402
|
useExternalResource<K extends Json, V extends Json>(resource: {
|
|
448
403
|
service: string;
|
|
449
404
|
identifier: string;
|
|
450
|
-
params?:
|
|
405
|
+
params?: Json;
|
|
451
406
|
}): EagerCollection<K, V> {
|
|
452
407
|
const collection =
|
|
453
408
|
this.refs.binding.SkipRuntime_Context__useExternalResource(
|
|
@@ -492,7 +447,7 @@ class AllChecker<K extends Json, V extends Json> implements Checker {
|
|
|
492
447
|
private readonly service: ServiceInstance,
|
|
493
448
|
private readonly executor: Executor<Entry<K, V>[]>,
|
|
494
449
|
private readonly resource: string,
|
|
495
|
-
private readonly params:
|
|
450
|
+
private readonly params: Json,
|
|
496
451
|
) {}
|
|
497
452
|
|
|
498
453
|
check(request: string): void {
|
|
@@ -514,7 +469,7 @@ class OneChecker<K extends Json, V extends Json> implements Checker {
|
|
|
514
469
|
private readonly service: ServiceInstance,
|
|
515
470
|
private readonly executor: Executor<V[]>,
|
|
516
471
|
private readonly resource: string,
|
|
517
|
-
private readonly params:
|
|
472
|
+
private readonly params: Json,
|
|
518
473
|
private readonly key: K,
|
|
519
474
|
) {}
|
|
520
475
|
|
|
@@ -533,6 +488,8 @@ class OneChecker<K extends Json, V extends Json> implements Checker {
|
|
|
533
488
|
}
|
|
534
489
|
}
|
|
535
490
|
|
|
491
|
+
export type SubscriptionID = Opaque<bigint, "subscription">;
|
|
492
|
+
|
|
536
493
|
/**
|
|
537
494
|
* A `ServiceInstance` is a running instance of a `SkipService`, providing access to its resources
|
|
538
495
|
* and operations to manage susbscriptions and the service itself.
|
|
@@ -549,7 +506,7 @@ export class ServiceInstance {
|
|
|
549
506
|
instantiateResource(
|
|
550
507
|
identifier: string,
|
|
551
508
|
resource: string,
|
|
552
|
-
params:
|
|
509
|
+
params: Json,
|
|
553
510
|
): void {
|
|
554
511
|
const errorHdl = this.refs.runWithGC(() => {
|
|
555
512
|
return this.refs.binding.SkipRuntime_Runtime__createResource(
|
|
@@ -569,7 +526,7 @@ export class ServiceInstance {
|
|
|
569
526
|
*/
|
|
570
527
|
getAll<K extends Json, V extends Json>(
|
|
571
528
|
resource: string,
|
|
572
|
-
params:
|
|
529
|
+
params: Json = {},
|
|
573
530
|
request?: string | Executor<Entry<K, V>[]>,
|
|
574
531
|
): GetResult<Entry<K, V>[]> {
|
|
575
532
|
const get_ = () => {
|
|
@@ -606,7 +563,7 @@ export class ServiceInstance {
|
|
|
606
563
|
getArray<K extends Json, V extends Json>(
|
|
607
564
|
resource: string,
|
|
608
565
|
key: K,
|
|
609
|
-
params:
|
|
566
|
+
params: Json = {},
|
|
610
567
|
request?: string | Executor<V[]>,
|
|
611
568
|
): GetResult<V[]> {
|
|
612
569
|
const get_ = () => {
|
|
@@ -734,7 +691,7 @@ export class ServiceInstance {
|
|
|
734
691
|
}
|
|
735
692
|
}
|
|
736
693
|
|
|
737
|
-
|
|
694
|
+
class ValuesImpl<T> implements Values<T> {
|
|
738
695
|
constructor(
|
|
739
696
|
private readonly skjson: JsonConverter,
|
|
740
697
|
private readonly binding: FromBinding,
|
|
@@ -745,26 +702,26 @@ export class NonEmptyIteratorImpl<T> implements NonEmptyIterator<T> {
|
|
|
745
702
|
this.pointer = pointer;
|
|
746
703
|
}
|
|
747
704
|
|
|
748
|
-
next(): Nullable<T &
|
|
705
|
+
next(): Nullable<T & DepSafe> {
|
|
749
706
|
return this.skjson.importOptJSON(
|
|
750
707
|
this.binding.SkipRuntime_NonEmptyIterator__next(this.pointer),
|
|
751
|
-
) as Nullable<T &
|
|
708
|
+
) as Nullable<T & DepSafe>;
|
|
752
709
|
}
|
|
753
710
|
|
|
754
|
-
getUnique(): T &
|
|
711
|
+
getUnique(): T & DepSafe {
|
|
755
712
|
const value = this.skjson.importOptJSON(
|
|
756
713
|
this.binding.SkipRuntime_NonEmptyIterator__uniqueValue(this.pointer),
|
|
757
|
-
) as Nullable<T &
|
|
714
|
+
) as Nullable<T & DepSafe>;
|
|
758
715
|
if (value == null) throw new NonUniqueValueException();
|
|
759
716
|
return value;
|
|
760
717
|
}
|
|
761
718
|
|
|
762
|
-
toArray: () => (T &
|
|
719
|
+
toArray: () => (T & DepSafe)[] = () => {
|
|
763
720
|
return Array.from(this);
|
|
764
721
|
};
|
|
765
722
|
|
|
766
|
-
[Symbol.iterator](): Iterator<T &
|
|
767
|
-
const cloned_iter = new
|
|
723
|
+
[Symbol.iterator](): Iterator<T & DepSafe> {
|
|
724
|
+
const cloned_iter = new ValuesImpl<T & DepSafe>(
|
|
768
725
|
this.skjson,
|
|
769
726
|
this.binding,
|
|
770
727
|
this.binding.SkipRuntime_NonEmptyIterator__clone(this.pointer),
|
|
@@ -773,12 +730,12 @@ export class NonEmptyIteratorImpl<T> implements NonEmptyIterator<T> {
|
|
|
773
730
|
return {
|
|
774
731
|
next() {
|
|
775
732
|
const value = cloned_iter.next();
|
|
776
|
-
return { value, done: value == null } as IteratorResult<T &
|
|
733
|
+
return { value, done: value == null } as IteratorResult<T & DepSafe>;
|
|
777
734
|
},
|
|
778
735
|
};
|
|
779
736
|
}
|
|
780
737
|
|
|
781
|
-
map<U>(f: (value: T &
|
|
738
|
+
map<U>(f: (value: T & DepSafe, index: number) => U, thisObj?: any): U[] {
|
|
782
739
|
return this.toArray().map(f, thisObj);
|
|
783
740
|
}
|
|
784
741
|
}
|
|
@@ -833,7 +790,7 @@ export class ToBinding {
|
|
|
833
790
|
const mapper = this.handles.get(skmapper);
|
|
834
791
|
const result = mapper.mapEntry(
|
|
835
792
|
skjson.importJSON(key) as Json,
|
|
836
|
-
new
|
|
793
|
+
new ValuesImpl<Json>(skjson, this.binding, values),
|
|
837
794
|
);
|
|
838
795
|
return skjson.exportJSON(Array.from(result) as [[Json, Json]]);
|
|
839
796
|
}
|
|
@@ -851,11 +808,11 @@ export class ToBinding {
|
|
|
851
808
|
): Pointer<Internal.CJArray> {
|
|
852
809
|
const skjson = this.getJsonConverter();
|
|
853
810
|
const lazyCompute = this.handles.get(sklazyCompute);
|
|
854
|
-
const
|
|
811
|
+
const result = lazyCompute.compute(
|
|
855
812
|
new LazyCollectionImpl<Json, Json>(self, this.refs()),
|
|
856
813
|
skjson.importJSON(skkey) as Json,
|
|
857
814
|
);
|
|
858
|
-
return skjson.exportJSON(
|
|
815
|
+
return skjson.exportJSON(Array.from(result));
|
|
859
816
|
}
|
|
860
817
|
|
|
861
818
|
SkipRuntime_deleteLazyCompute(lazyCompute: Handle<JSONLazyCompute>): void {
|
|
@@ -894,9 +851,7 @@ export class ToBinding {
|
|
|
894
851
|
): Pointer<Internal.Resource> {
|
|
895
852
|
const skjson = this.getJsonConverter();
|
|
896
853
|
const builder = this.handles.get(skbuilder);
|
|
897
|
-
const resource = builder.build(
|
|
898
|
-
skjson.importJSON(skparams) as { [param: string]: string },
|
|
899
|
-
);
|
|
854
|
+
const resource = builder.build(skjson.importJSON(skparams) as Json);
|
|
900
855
|
return this.binding.SkipRuntime_createResource(
|
|
901
856
|
this.handles.register(resource),
|
|
902
857
|
);
|
|
@@ -987,7 +942,7 @@ export class ToBinding {
|
|
|
987
942
|
return skjson.exportJSON(
|
|
988
943
|
reducer.add(
|
|
989
944
|
skacc ? (skjson.importJSON(skacc) as Json) : null,
|
|
990
|
-
skjson.importJSON(skvalue) as Json &
|
|
945
|
+
skjson.importJSON(skvalue) as Json & DepSafe,
|
|
991
946
|
),
|
|
992
947
|
);
|
|
993
948
|
}
|
|
@@ -1002,7 +957,7 @@ export class ToBinding {
|
|
|
1002
957
|
return skjson.exportJSON(
|
|
1003
958
|
reducer.remove(
|
|
1004
959
|
skjson.importJSON(skacc) as Json,
|
|
1005
|
-
skjson.importJSON(skvalue) as Json &
|
|
960
|
+
skjson.importJSON(skvalue) as Json & DepSafe,
|
|
1006
961
|
),
|
|
1007
962
|
);
|
|
1008
963
|
}
|
|
@@ -1022,9 +977,7 @@ export class ToBinding {
|
|
|
1022
977
|
const skjson = this.getJsonConverter();
|
|
1023
978
|
const supplier = this.handles.get(sksupplier);
|
|
1024
979
|
const writer = new CollectionWriter(writerId, this.refs());
|
|
1025
|
-
const params = skjson.importJSON(skparams, true) as
|
|
1026
|
-
[param: string]: string;
|
|
1027
|
-
};
|
|
980
|
+
const params = skjson.importJSON(skparams, true) as Json;
|
|
1028
981
|
supplier.subscribe(resource, params, {
|
|
1029
982
|
update: writer.update.bind(writer),
|
|
1030
983
|
error: writer.error.bind(writer),
|
|
@@ -1039,9 +992,7 @@ export class ToBinding {
|
|
|
1039
992
|
): void {
|
|
1040
993
|
const skjson = this.getJsonConverter();
|
|
1041
994
|
const supplier = this.handles.get(sksupplier);
|
|
1042
|
-
const params = skjson.importJSON(skparams, true) as
|
|
1043
|
-
[param: string]: string;
|
|
1044
|
-
};
|
|
995
|
+
const params = skjson.importJSON(skparams, true) as Json;
|
|
1045
996
|
supplier.unsubscribe(resource, params);
|
|
1046
997
|
}
|
|
1047
998
|
|
package/src/remote.ts
CHANGED
|
@@ -10,14 +10,29 @@ interface Closable {
|
|
|
10
10
|
close(): void;
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
+
/**
|
|
14
|
+
* An external Skip reactive service.
|
|
15
|
+
*
|
|
16
|
+
* `SkipExternalService` provides an implementation of `ExternalService` for an external Skip service.
|
|
17
|
+
*/
|
|
13
18
|
export class SkipExternalService implements ExternalService {
|
|
14
19
|
private readonly resources = new Map<string, Closable>();
|
|
15
20
|
|
|
21
|
+
/**
|
|
22
|
+
* @param url - URL to use for the service's streaming interface.
|
|
23
|
+
* @param control_url - URL to use for the service's control interface.
|
|
24
|
+
*/
|
|
16
25
|
constructor(
|
|
17
26
|
private readonly url: string,
|
|
18
27
|
private readonly control_url: string,
|
|
19
28
|
) {}
|
|
20
29
|
|
|
30
|
+
/**
|
|
31
|
+
* Constructor accepting an `Entrypoint`.
|
|
32
|
+
*
|
|
33
|
+
* @param entrypoint - The entry point for the external Skip service.
|
|
34
|
+
* @returns An `ExternalService` to interact with the service running at `entrypoint`.
|
|
35
|
+
*/
|
|
21
36
|
// TODO: Support Skip external services going through a gateway.
|
|
22
37
|
static direct(entrypoint: Entrypoint): SkipExternalService {
|
|
23
38
|
let url = `http://${entrypoint.host}:${entrypoint.streaming_port.toString()}`;
|
|
@@ -31,7 +46,7 @@ export class SkipExternalService implements ExternalService {
|
|
|
31
46
|
|
|
32
47
|
subscribe(
|
|
33
48
|
resource: string,
|
|
34
|
-
params:
|
|
49
|
+
params: Json,
|
|
35
50
|
callbacks: {
|
|
36
51
|
update: (updates: Entry<Json, Json>[], isInitial: boolean) => void;
|
|
37
52
|
// FIXME: What is `error()` used for?
|
|
@@ -72,7 +87,7 @@ export class SkipExternalService implements ExternalService {
|
|
|
72
87
|
});
|
|
73
88
|
}
|
|
74
89
|
|
|
75
|
-
unsubscribe(resource: string, params:
|
|
90
|
+
unsubscribe(resource: string, params: Json) {
|
|
76
91
|
const closable = this.resources.get(this.toId(resource, params));
|
|
77
92
|
if (closable) closable.close();
|
|
78
93
|
}
|
|
@@ -83,12 +98,12 @@ export class SkipExternalService implements ExternalService {
|
|
|
83
98
|
}
|
|
84
99
|
}
|
|
85
100
|
|
|
86
|
-
private toId(resource: string, params:
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
return `${resource}[${
|
|
101
|
+
private toId(resource: string, params: Json): string {
|
|
102
|
+
if (typeof params == "object") {
|
|
103
|
+
const strparams = Object.entries(params)
|
|
104
|
+
.map(([key, value]) => `${key}:${btoa(JSON.stringify(value))}`)
|
|
105
|
+
.sort();
|
|
106
|
+
return `${resource}[${strparams.join(",")}]`;
|
|
107
|
+
} else return `${resource}[${btoa(JSON.stringify(params))}]`;
|
|
93
108
|
}
|
|
94
109
|
}
|
package/src/utils.ts
CHANGED
|
@@ -1,48 +1,88 @@
|
|
|
1
1
|
import type { Nullable } from "@skip-wasm/std";
|
|
2
2
|
import { ManyToOneMapper } from "@skipruntime/api";
|
|
3
|
-
import type { Reducer,
|
|
3
|
+
import type { Reducer, Values, Json } from "@skipruntime/api";
|
|
4
4
|
|
|
5
|
+
/**
|
|
6
|
+
* `Reducer` to maintain the sum of input values.
|
|
7
|
+
*
|
|
8
|
+
* A `Reducer` that maintains the sum of values as they are added and removed from a collection.
|
|
9
|
+
*/
|
|
5
10
|
export class Sum implements Reducer<number, number> {
|
|
6
|
-
|
|
11
|
+
initial = 0;
|
|
7
12
|
|
|
8
|
-
add(
|
|
9
|
-
return
|
|
13
|
+
add(accum: number, value: number): number {
|
|
14
|
+
return accum + value;
|
|
10
15
|
}
|
|
11
16
|
|
|
12
|
-
remove(
|
|
13
|
-
return
|
|
17
|
+
remove(accum: number, value: number): Nullable<number> {
|
|
18
|
+
return accum - value;
|
|
14
19
|
}
|
|
15
20
|
}
|
|
16
21
|
|
|
22
|
+
/**
|
|
23
|
+
* `Reducer` to maintain the minimum of input values.
|
|
24
|
+
*
|
|
25
|
+
* A `Reducer` that maintains the minimum of values as they are added and removed from a collection.
|
|
26
|
+
*/
|
|
17
27
|
export class Min implements Reducer<number, number> {
|
|
18
|
-
|
|
28
|
+
initial = null;
|
|
19
29
|
|
|
20
|
-
add(
|
|
21
|
-
return
|
|
30
|
+
add(accum: Nullable<number>, value: number): number {
|
|
31
|
+
return accum === null ? value : Math.min(accum, value);
|
|
22
32
|
}
|
|
23
33
|
|
|
24
|
-
remove(
|
|
25
|
-
return value >
|
|
34
|
+
remove(accum: number, value: number): Nullable<number> {
|
|
35
|
+
return value > accum ? accum : null;
|
|
26
36
|
}
|
|
27
37
|
}
|
|
28
38
|
|
|
39
|
+
/**
|
|
40
|
+
* `Reducer` to maintain the maximum of input values.
|
|
41
|
+
*
|
|
42
|
+
* A `Reducer` that maintains the maximum of values as they are added and removed from a collection.
|
|
43
|
+
*/
|
|
29
44
|
export class Max implements Reducer<number, number> {
|
|
30
|
-
|
|
45
|
+
initial = null;
|
|
31
46
|
|
|
32
|
-
add(
|
|
33
|
-
return
|
|
47
|
+
add(accum: Nullable<number>, value: number): number {
|
|
48
|
+
return accum === null ? value : Math.max(accum, value);
|
|
34
49
|
}
|
|
35
50
|
|
|
36
|
-
remove(
|
|
37
|
-
return value <
|
|
51
|
+
remove(accum: number, value: number): Nullable<number> {
|
|
52
|
+
return value < accum ? accum : null;
|
|
38
53
|
}
|
|
39
54
|
}
|
|
40
55
|
|
|
56
|
+
/**
|
|
57
|
+
* `Reducer` to maintain the count of input values.
|
|
58
|
+
*
|
|
59
|
+
* A `Reducer` that maintains the number of values as they are added and removed from a collection.
|
|
60
|
+
*/
|
|
61
|
+
export class Count<T extends Json> implements Reducer<T, number> {
|
|
62
|
+
initial = 0;
|
|
63
|
+
|
|
64
|
+
add(accum: number): number {
|
|
65
|
+
return accum + 1;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
remove(accum: number): Nullable<number> {
|
|
69
|
+
return accum - 1;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* `Mapper` to count input values.
|
|
75
|
+
*
|
|
76
|
+
* A `Mapper` that associates each key in the output with the number of values it is associated with in the input.
|
|
77
|
+
*
|
|
78
|
+
* @remarks
|
|
79
|
+
* If there are many values associated to keys in a collection, and they are updated frequently, using the `Count` `Reducer` instead could be more efficient.
|
|
80
|
+
*/
|
|
41
81
|
export class CountMapper<
|
|
42
82
|
K extends Json,
|
|
43
83
|
V extends Json,
|
|
44
84
|
> extends ManyToOneMapper<K, V, number> {
|
|
45
|
-
mapValues(values:
|
|
85
|
+
mapValues(values: Values<V>): number {
|
|
46
86
|
return values.toArray().length;
|
|
47
87
|
}
|
|
48
88
|
}
|