@skipruntime/helpers 0.0.1 → 0.0.2
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/external.d.ts +18 -18
- package/dist/external.d.ts.map +1 -1
- package/dist/external.js +18 -19
- package/dist/external.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/remote.d.ts +8 -14
- package/dist/remote.d.ts.map +1 -1
- package/dist/remote.js +24 -60
- package/dist/remote.js.map +1 -1
- package/dist/rest.d.ts +8 -13
- package/dist/rest.d.ts.map +1 -1
- package/dist/rest.js +8 -50
- package/dist/rest.js.map +1 -1
- package/dist/utils.d.ts +12 -12
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +8 -15
- package/dist/utils.js.map +1 -1
- package/package.json +2 -3
- package/src/external.ts +27 -51
- package/src/index.ts +1 -0
- package/src/remote.ts +31 -120
- package/src/rest.ts +14 -77
- package/src/utils.ts +16 -24
package/dist/utils.js
CHANGED
|
@@ -3,10 +3,10 @@ export class Sum {
|
|
|
3
3
|
constructor() {
|
|
4
4
|
this.default = 0;
|
|
5
5
|
}
|
|
6
|
-
|
|
6
|
+
add(acc, value) {
|
|
7
7
|
return acc + value;
|
|
8
8
|
}
|
|
9
|
-
|
|
9
|
+
remove(acc, value) {
|
|
10
10
|
return acc - value;
|
|
11
11
|
}
|
|
12
12
|
}
|
|
@@ -14,10 +14,10 @@ export class Min {
|
|
|
14
14
|
constructor() {
|
|
15
15
|
this.default = null;
|
|
16
16
|
}
|
|
17
|
-
|
|
17
|
+
add(acc, value) {
|
|
18
18
|
return acc === null ? value : Math.min(acc, value);
|
|
19
19
|
}
|
|
20
|
-
|
|
20
|
+
remove(acc, value) {
|
|
21
21
|
return value > acc ? acc : null;
|
|
22
22
|
}
|
|
23
23
|
}
|
|
@@ -25,10 +25,10 @@ export class Max {
|
|
|
25
25
|
constructor() {
|
|
26
26
|
this.default = null;
|
|
27
27
|
}
|
|
28
|
-
|
|
28
|
+
add(acc, value) {
|
|
29
29
|
return acc === null ? value : Math.max(acc, value);
|
|
30
30
|
}
|
|
31
|
-
|
|
31
|
+
remove(acc, value) {
|
|
32
32
|
return value < acc ? acc : null;
|
|
33
33
|
}
|
|
34
34
|
}
|
|
@@ -43,16 +43,9 @@ export function parseReactiveResponse(header) {
|
|
|
43
43
|
: header.get("Skip-Reactive-Response-Token");
|
|
44
44
|
if (!strReactiveResponse)
|
|
45
45
|
return undefined;
|
|
46
|
-
return JSON.parse(strReactiveResponse
|
|
47
|
-
if (key == "watermark")
|
|
48
|
-
return BigInt(value);
|
|
49
|
-
return value;
|
|
50
|
-
});
|
|
46
|
+
return JSON.parse(strReactiveResponse);
|
|
51
47
|
}
|
|
52
48
|
export function reactiveResponseHeader(reactiveResponse) {
|
|
53
|
-
return [
|
|
54
|
-
"Skip-Reactive-Response-Token",
|
|
55
|
-
JSON.stringify(reactiveResponse, (_key, value) => typeof value === "bigint" ? value.toString() : value),
|
|
56
|
-
];
|
|
49
|
+
return ["Skip-Reactive-Response-Token", JSON.stringify(reactiveResponse)];
|
|
57
50
|
}
|
|
58
51
|
//# sourceMappingURL=utils.js.map
|
package/dist/utils.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAQnD,MAAM,OAAO,GAAG;IAAhB;QACE,YAAO,GAAG,CAAC,CAAC;IASd,CAAC;IAPC,
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAQnD,MAAM,OAAO,GAAG;IAAhB;QACE,YAAO,GAAG,CAAC,CAAC;IASd,CAAC;IAPC,GAAG,CAAC,GAAW,EAAE,KAAa;QAC5B,OAAO,GAAG,GAAG,KAAK,CAAC;IACrB,CAAC;IAED,MAAM,CAAC,GAAW,EAAE,KAAa;QAC/B,OAAO,GAAG,GAAG,KAAK,CAAC;IACrB,CAAC;CACF;AAED,MAAM,OAAO,GAAG;IAAhB;QACE,YAAO,GAAG,IAAI,CAAC;IASjB,CAAC;IAPC,GAAG,CAAC,GAAqB,EAAE,KAAa;QACtC,OAAO,GAAG,KAAK,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IACrD,CAAC;IAED,MAAM,CAAC,GAAW,EAAE,KAAa;QAC/B,OAAO,KAAK,GAAG,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC;IAClC,CAAC;CACF;AAED,MAAM,OAAO,GAAG;IAAhB;QACE,YAAO,GAAG,IAAI,CAAC;IASjB,CAAC;IAPC,GAAG,CAAC,GAAqB,EAAE,KAAa;QACtC,OAAO,GAAG,KAAK,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IACrD,CAAC;IAED,MAAM,CAAC,GAAW,EAAE,KAAa;QAC/B,OAAO,KAAK,GAAG,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC;IAClC,CAAC;CACF;AAED,MAAM,OAAO,WAGX,SAAQ,eAA6B;IACrC,SAAS,CAAC,MAA2B;QACnC,OAAO,MAAM,CAAC,OAAO,EAAE,CAAC,MAAM,CAAC;IACjC,CAAC;CACF;AAED,MAAM,UAAU,qBAAqB,CACnC,MAAwB;IAExB,MAAM,mBAAmB,GACvB,OAAO,MAAM,IAAI,QAAQ;QACvB,CAAC,CAAC,MAAM;QACR,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,8BAA8B,CAAC,CAAC;IACjD,IAAI,CAAC,mBAAmB;QAAE,OAAO,SAAS,CAAC;IAC3C,OAAO,IAAI,CAAC,KAAK,CAAC,mBAAmB,CAAqB,CAAC;AAC7D,CAAC;AAED,MAAM,UAAU,sBAAsB,CACpC,gBAAkC;IAElC,OAAO,CAAC,8BAA8B,EAAE,IAAI,CAAC,SAAS,CAAC,gBAAgB,CAAC,CAAC,CAAC;AAC5E,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@skipruntime/helpers",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": "./dist/index.js",
|
|
@@ -21,7 +21,6 @@
|
|
|
21
21
|
},
|
|
22
22
|
"dependencies": {
|
|
23
23
|
"express": "^4.21.0",
|
|
24
|
-
"@skipruntime/
|
|
25
|
-
"@skipruntime/api": "^0.0.1"
|
|
24
|
+
"@skipruntime/api": "^0.0.2"
|
|
26
25
|
}
|
|
27
26
|
}
|
package/src/external.ts
CHANGED
|
@@ -1,21 +1,17 @@
|
|
|
1
|
-
import type { Entry, ExternalService,
|
|
1
|
+
import type { Entry, ExternalService, Json } from "@skipruntime/api";
|
|
2
2
|
import { fetchJSON } from "./rest.js";
|
|
3
3
|
|
|
4
4
|
export interface ExternalResource {
|
|
5
5
|
open(
|
|
6
6
|
params: Record<string, string | number>,
|
|
7
7
|
callbacks: {
|
|
8
|
-
update: (updates: Entry<
|
|
9
|
-
error: (error:
|
|
8
|
+
update: (updates: Entry<Json, Json>[], isInit: boolean) => void;
|
|
9
|
+
error: (error: Json) => void;
|
|
10
10
|
loading: () => void;
|
|
11
11
|
},
|
|
12
|
-
reactiveAuth?: Uint8Array,
|
|
13
12
|
): void;
|
|
14
13
|
|
|
15
|
-
close(
|
|
16
|
-
params: Record<string, string | number>,
|
|
17
|
-
reactiveAuth?: Uint8Array,
|
|
18
|
-
): void;
|
|
14
|
+
close(params: Record<string, string | number>): void;
|
|
19
15
|
}
|
|
20
16
|
|
|
21
17
|
export class GenericExternalService implements ExternalService {
|
|
@@ -25,11 +21,10 @@ export class GenericExternalService implements ExternalService {
|
|
|
25
21
|
resourceName: string,
|
|
26
22
|
params: Record<string, string | number>,
|
|
27
23
|
callbacks: {
|
|
28
|
-
update: (updates: Entry<
|
|
29
|
-
error: (error:
|
|
24
|
+
update: (updates: Entry<Json, Json>[], isInit: boolean) => void;
|
|
25
|
+
error: (error: Json) => void;
|
|
30
26
|
loading: () => void;
|
|
31
27
|
},
|
|
32
|
-
reactiveAuth?: Uint8Array,
|
|
33
28
|
): void {
|
|
34
29
|
const resource = this.resources[resourceName] as
|
|
35
30
|
| ExternalResource
|
|
@@ -37,21 +32,17 @@ export class GenericExternalService implements ExternalService {
|
|
|
37
32
|
if (!resource) {
|
|
38
33
|
throw new Error(`Unkonwn resource named '${resourceName}'`);
|
|
39
34
|
}
|
|
40
|
-
resource.open(params, callbacks
|
|
35
|
+
resource.open(params, callbacks);
|
|
41
36
|
}
|
|
42
37
|
|
|
43
|
-
unsubscribe(
|
|
44
|
-
resourceName: string,
|
|
45
|
-
params: Record<string, string>,
|
|
46
|
-
reactiveAuth?: Uint8Array,
|
|
47
|
-
) {
|
|
38
|
+
unsubscribe(resourceName: string, params: Record<string, string>) {
|
|
48
39
|
const resource = this.resources[resourceName] as
|
|
49
40
|
| ExternalResource
|
|
50
41
|
| undefined;
|
|
51
42
|
if (!resource) {
|
|
52
43
|
throw new Error(`Unkonwn resource named '${resourceName}'`);
|
|
53
44
|
}
|
|
54
|
-
resource.close(params
|
|
45
|
+
resource.close(params);
|
|
55
46
|
}
|
|
56
47
|
|
|
57
48
|
shutdown(): void {
|
|
@@ -67,11 +58,10 @@ export class TimerResource implements ExternalResource {
|
|
|
67
58
|
open(
|
|
68
59
|
params: Record<string, string | number>,
|
|
69
60
|
callbacks: {
|
|
70
|
-
update: (updates: Entry<
|
|
71
|
-
error: (error:
|
|
61
|
+
update: (updates: Entry<Json, Json>[], isInit: boolean) => void;
|
|
62
|
+
error: (error: Json) => void;
|
|
72
63
|
loading: () => void;
|
|
73
64
|
},
|
|
74
|
-
reactiveAuth?: Uint8Array,
|
|
75
65
|
) {
|
|
76
66
|
const time = new Date().getTime();
|
|
77
67
|
const values: Entry<string, number>[] = [];
|
|
@@ -79,13 +69,13 @@ export class TimerResource implements ExternalResource {
|
|
|
79
69
|
values.push([name, [time]]);
|
|
80
70
|
}
|
|
81
71
|
callbacks.update(values, true);
|
|
82
|
-
const id = toId(params
|
|
72
|
+
const id = toId(params);
|
|
83
73
|
const intervals: Record<string, Timeout> = {};
|
|
84
74
|
for (const [name, duration] of Object.entries(params)) {
|
|
85
75
|
const ms = Number(duration);
|
|
86
76
|
if (ms > 0) {
|
|
87
77
|
intervals[name] = setInterval(() => {
|
|
88
|
-
const newvalue: Entry<
|
|
78
|
+
const newvalue: Entry<Json, Json> = [name, [new Date().getTime()]];
|
|
89
79
|
callbacks.update([newvalue], true);
|
|
90
80
|
}, ms);
|
|
91
81
|
}
|
|
@@ -93,11 +83,8 @@ export class TimerResource implements ExternalResource {
|
|
|
93
83
|
this.intervals.set(id, intervals);
|
|
94
84
|
}
|
|
95
85
|
|
|
96
|
-
close(
|
|
97
|
-
|
|
98
|
-
reactiveAuth?: Uint8Array,
|
|
99
|
-
): void {
|
|
100
|
-
const intervals = this.intervals.get(toId(params, reactiveAuth));
|
|
86
|
+
close(params: Record<string, string | number>): void {
|
|
87
|
+
const intervals = this.intervals.get(toId(params));
|
|
101
88
|
if (intervals != null) {
|
|
102
89
|
for (const interval of Object.values(intervals)) {
|
|
103
90
|
clearInterval(interval);
|
|
@@ -106,7 +93,7 @@ export class TimerResource implements ExternalResource {
|
|
|
106
93
|
}
|
|
107
94
|
}
|
|
108
95
|
|
|
109
|
-
export class Polled<S extends
|
|
96
|
+
export class Polled<S extends Json, K extends Json, V extends Json>
|
|
110
97
|
implements ExternalResource
|
|
111
98
|
{
|
|
112
99
|
private intervals = new Map<string, Timeout>();
|
|
@@ -120,18 +107,17 @@ export class Polled<S extends TJSON, K extends TJSON, V extends TJSON>
|
|
|
120
107
|
open(
|
|
121
108
|
params: Record<string, string | number>,
|
|
122
109
|
callbacks: {
|
|
123
|
-
update: (updates: Entry<
|
|
124
|
-
error: (error:
|
|
110
|
+
update: (updates: Entry<Json, Json>[], isInit: boolean) => void;
|
|
111
|
+
error: (error: Json) => void;
|
|
125
112
|
loading: () => void;
|
|
126
113
|
},
|
|
127
|
-
reactiveAuth?: Uint8Array,
|
|
128
114
|
): void {
|
|
129
|
-
this.close(params
|
|
130
|
-
const
|
|
115
|
+
this.close(params);
|
|
116
|
+
const queryParams: Record<string, string> = {};
|
|
131
117
|
for (const [key, value] of Object.entries(params)) {
|
|
132
|
-
|
|
118
|
+
queryParams[key] = value.toString();
|
|
133
119
|
}
|
|
134
|
-
const strParams = new URLSearchParams(
|
|
120
|
+
const strParams = new URLSearchParams(queryParams).toString();
|
|
135
121
|
const url = `${this.url}?${strParams}`;
|
|
136
122
|
const call = () => {
|
|
137
123
|
callbacks.loading();
|
|
@@ -145,30 +131,20 @@ export class Polled<S extends TJSON, K extends TJSON, V extends TJSON>
|
|
|
145
131
|
});
|
|
146
132
|
};
|
|
147
133
|
call();
|
|
148
|
-
this.intervals.set(
|
|
149
|
-
toId(params, reactiveAuth),
|
|
150
|
-
setInterval(call, this.duration),
|
|
151
|
-
);
|
|
134
|
+
this.intervals.set(toId(params), setInterval(call, this.duration));
|
|
152
135
|
}
|
|
153
136
|
|
|
154
|
-
close(
|
|
155
|
-
|
|
156
|
-
reactiveAuth?: Uint8Array,
|
|
157
|
-
): void {
|
|
158
|
-
const interval = this.intervals.get(toId(params, reactiveAuth));
|
|
137
|
+
close(params: Record<string, string | number>): void {
|
|
138
|
+
const interval = this.intervals.get(toId(params));
|
|
159
139
|
if (interval) {
|
|
160
140
|
clearInterval(interval);
|
|
161
141
|
}
|
|
162
142
|
}
|
|
163
143
|
}
|
|
164
144
|
|
|
165
|
-
function toId(
|
|
166
|
-
params: Record<string, string | number>,
|
|
167
|
-
reactiveAuth?: Uint8Array,
|
|
168
|
-
): string {
|
|
145
|
+
function toId(params: Record<string, string | number>): string {
|
|
169
146
|
const strparams = Object.entries(params)
|
|
170
147
|
.map(([key, value]) => `${key}:${value.toString()}`)
|
|
171
148
|
.sort();
|
|
172
|
-
|
|
173
|
-
return `[${strparams.join(",")}]${hex}`;
|
|
149
|
+
return `[${strparams.join(",")}]`;
|
|
174
150
|
}
|
package/src/index.ts
CHANGED
package/src/remote.ts
CHANGED
|
@@ -1,158 +1,69 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
Entry,
|
|
3
|
-
ExternalService,
|
|
4
|
-
ReactiveResponse,
|
|
5
|
-
TJSON,
|
|
6
|
-
} from "@skipruntime/api";
|
|
7
|
-
import { parseReactiveResponse } from "./utils.js";
|
|
1
|
+
import type { Entry, ExternalService, Json } from "@skipruntime/api";
|
|
8
2
|
|
|
9
|
-
import {
|
|
10
|
-
import { fetchJSON, type Entrypoint } from "./rest.js";
|
|
3
|
+
import type { Entrypoint } from "./rest.js";
|
|
11
4
|
|
|
12
5
|
interface Closable {
|
|
13
6
|
close(): void;
|
|
14
7
|
}
|
|
15
8
|
|
|
16
9
|
export class SkipExternalService implements ExternalService {
|
|
17
|
-
private client?: Promise<[Client, Protocol.Creds]>;
|
|
18
10
|
private resources = new Map<string, Closable>();
|
|
19
11
|
|
|
20
|
-
constructor(
|
|
21
|
-
private url: string,
|
|
22
|
-
private auth: (
|
|
23
|
-
resource: string,
|
|
24
|
-
params: Record<string, string>,
|
|
25
|
-
reactiveAuth: Uint8Array,
|
|
26
|
-
) => Promise<ReactiveResponse>,
|
|
27
|
-
private creds?: Protocol.Creds,
|
|
28
|
-
) {}
|
|
12
|
+
constructor(private url: string) {}
|
|
29
13
|
|
|
30
|
-
static
|
|
31
|
-
entrypoint: Entrypoint,
|
|
32
|
-
auth: (
|
|
33
|
-
resource: string,
|
|
34
|
-
params: Record<string, string>,
|
|
35
|
-
reactiveAuth: Uint8Array,
|
|
36
|
-
) => Promise<ReactiveResponse>,
|
|
37
|
-
creds?: Protocol.Creds,
|
|
38
|
-
): SkipExternalService {
|
|
39
|
-
let url = `ws://${entrypoint.host}:${entrypoint.port.toString()}`;
|
|
40
|
-
if (entrypoint.secured)
|
|
41
|
-
url = `wss://${entrypoint.host}:${entrypoint.port.toString()}`;
|
|
42
|
-
return new SkipExternalService(url, auth, creds);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
static direct(
|
|
46
|
-
entrypoint: Entrypoint,
|
|
47
|
-
creds?: Protocol.Creds,
|
|
48
|
-
): SkipExternalService {
|
|
14
|
+
static direct(entrypoint: Entrypoint): SkipExternalService {
|
|
49
15
|
let url = `http://${entrypoint.host}:${entrypoint.port.toString()}`;
|
|
50
16
|
if (entrypoint.secured)
|
|
51
17
|
url = `https://${entrypoint.host}:${entrypoint.port.toString()}`;
|
|
52
|
-
|
|
53
|
-
resource: string,
|
|
54
|
-
params: Record<string, string>,
|
|
55
|
-
reactiveAuth: Uint8Array,
|
|
56
|
-
) => {
|
|
57
|
-
const qParams = new URLSearchParams(params).toString();
|
|
58
|
-
const header = {
|
|
59
|
-
"X-Reactive-Auth": Buffer.from(reactiveAuth).toString("base64"),
|
|
60
|
-
};
|
|
61
|
-
const [_data, headers] = await fetchJSON(
|
|
62
|
-
`${url}/v1/${resource}?${qParams}`,
|
|
63
|
-
"HEAD",
|
|
64
|
-
header,
|
|
65
|
-
);
|
|
66
|
-
const reactiveResponse = parseReactiveResponse(headers);
|
|
67
|
-
if (!reactiveResponse)
|
|
68
|
-
throw new Error("Reactive response must be suplied.");
|
|
69
|
-
return reactiveResponse;
|
|
70
|
-
};
|
|
71
|
-
return new SkipExternalService(url, auth, creds);
|
|
18
|
+
return new SkipExternalService(url);
|
|
72
19
|
}
|
|
73
20
|
|
|
74
21
|
subscribe(
|
|
75
22
|
resource: string,
|
|
76
23
|
params: Record<string, string>,
|
|
77
24
|
callbacks: {
|
|
78
|
-
update: (updates: Entry<
|
|
79
|
-
|
|
25
|
+
update: (updates: Entry<Json, Json>[], isInit: boolean) => void;
|
|
26
|
+
// FIXME: What is `error()` used for?
|
|
27
|
+
error: (error: Json) => void;
|
|
28
|
+
// FIXME: What is `loading()` used for?
|
|
80
29
|
loading: () => void;
|
|
81
30
|
},
|
|
82
|
-
reactiveAuth?: Uint8Array,
|
|
83
31
|
): void {
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
this.creds = creds;
|
|
88
|
-
return connect(this.url, this.creds).then((c) => [c, creds]);
|
|
89
|
-
});
|
|
90
|
-
} else {
|
|
91
|
-
this.client = connect(this.url, this.creds).then((c) => {
|
|
92
|
-
return [c, this.creds!];
|
|
93
|
-
});
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
this.subscribe_(resource, params, callbacks, reactiveAuth).catch(
|
|
97
|
-
(e: unknown) => {
|
|
98
|
-
console.error(e);
|
|
99
|
-
},
|
|
32
|
+
// TODO Manage Status
|
|
33
|
+
const evSource = new EventSource(
|
|
34
|
+
`${this.url}?${new URLSearchParams(params)}`,
|
|
100
35
|
);
|
|
36
|
+
evSource.addEventListener("init", (e: MessageEvent<string>) => {
|
|
37
|
+
const updates = JSON.parse(e.data) as Entry<Json, Json>[];
|
|
38
|
+
callbacks.update(updates, true);
|
|
39
|
+
});
|
|
40
|
+
evSource.addEventListener("update", (e: MessageEvent<string>) => {
|
|
41
|
+
const updates = JSON.parse(e.data) as Entry<Json, Json>[];
|
|
42
|
+
callbacks.update(updates, false);
|
|
43
|
+
});
|
|
44
|
+
evSource.onerror = (e) => {
|
|
45
|
+
console.log(e);
|
|
46
|
+
};
|
|
47
|
+
this.resources.set(this.toId(resource, params), evSource);
|
|
101
48
|
}
|
|
102
49
|
|
|
103
|
-
unsubscribe(
|
|
104
|
-
resource
|
|
105
|
-
params: Record<string, string>,
|
|
106
|
-
reactiveAuth?: Uint8Array,
|
|
107
|
-
) {
|
|
108
|
-
const closable = this.resources.get(
|
|
109
|
-
this.toId(resource, params, reactiveAuth),
|
|
110
|
-
);
|
|
50
|
+
unsubscribe(resource: string, params: Record<string, string>) {
|
|
51
|
+
const closable = this.resources.get(this.toId(resource, params));
|
|
111
52
|
if (closable) closable.close();
|
|
112
53
|
}
|
|
113
54
|
|
|
114
55
|
shutdown(): void {
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
.then((client) => {
|
|
118
|
-
client[0].close();
|
|
119
|
-
})
|
|
120
|
-
.catch((e: unknown) => console.error(e));
|
|
56
|
+
for (const res of this.resources.values()) {
|
|
57
|
+
res.close();
|
|
121
58
|
}
|
|
122
59
|
}
|
|
123
60
|
|
|
124
|
-
private
|
|
125
|
-
|
|
126
|
-
params: Record<string, string>,
|
|
127
|
-
callbacks: {
|
|
128
|
-
update: (updates: Entry<TJSON, TJSON>[], isInit: boolean) => void;
|
|
129
|
-
error: (error: TJSON) => void;
|
|
130
|
-
loading: () => void;
|
|
131
|
-
},
|
|
132
|
-
reactiveAuth?: Uint8Array,
|
|
133
|
-
): Promise<void> {
|
|
134
|
-
const [client, creds] = await this.client!;
|
|
135
|
-
const publicKey = new Uint8Array(await Protocol.exportKey(creds.publicKey));
|
|
136
|
-
const reactive = await this.auth(resource, params, publicKey);
|
|
137
|
-
// TODO Manage Status
|
|
138
|
-
const close = client.subscribe(
|
|
139
|
-
reactive.collection,
|
|
140
|
-
BigInt(reactive.watermark),
|
|
141
|
-
callbacks.update,
|
|
142
|
-
);
|
|
143
|
-
this.resources.set(this.toId(resource, params, reactiveAuth), close);
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
private toId(
|
|
147
|
-
resource: string,
|
|
148
|
-
params: Record<string, string>,
|
|
149
|
-
reactiveAuth?: Uint8Array,
|
|
150
|
-
): string {
|
|
61
|
+
private toId(resource: string, params: Record<string, string>): string {
|
|
62
|
+
// TODO: This is equivalent to `querystring.encode(params, ',', ':')`.
|
|
151
63
|
const strparams: string[] = [];
|
|
152
64
|
for (const key of Object.keys(params).sort()) {
|
|
153
65
|
strparams.push(`${key}:${params[key]}`);
|
|
154
66
|
}
|
|
155
|
-
|
|
156
|
-
return `${resource}[${strparams.join(",")}]${hex}`;
|
|
67
|
+
return `${resource}[${strparams.join(",")}]`;
|
|
157
68
|
}
|
|
158
69
|
}
|
package/src/rest.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import { parseReactiveResponse } from "./utils.js";
|
|
1
|
+
import type { Json, Entry } from "@skipruntime/api";
|
|
3
2
|
|
|
4
3
|
export type Entrypoint = {
|
|
5
4
|
host: string;
|
|
@@ -17,7 +16,7 @@ export async function fetchJSON<V>(
|
|
|
17
16
|
url: string,
|
|
18
17
|
method: "POST" | "GET" | "PUT" | "PATCH" | "HEAD" | "DELETE" = "GET",
|
|
19
18
|
headers: Record<string, string> = {},
|
|
20
|
-
data?:
|
|
19
|
+
data?: Json,
|
|
21
20
|
): Promise<[V | null, Headers]> {
|
|
22
21
|
const body = data ? JSON.stringify(data) : undefined;
|
|
23
22
|
const response = await fetch(url, {
|
|
@@ -41,7 +40,7 @@ export async function fetchJSON<V>(
|
|
|
41
40
|
return [responseJSON, response.headers];
|
|
42
41
|
}
|
|
43
42
|
|
|
44
|
-
export class
|
|
43
|
+
export class RESTWrapperOfSkipService {
|
|
45
44
|
private entrypoint: string;
|
|
46
45
|
|
|
47
46
|
constructor(
|
|
@@ -53,110 +52,48 @@ export class SkipRESTService {
|
|
|
53
52
|
this.entrypoint = toHttp(entrypoint);
|
|
54
53
|
}
|
|
55
54
|
|
|
56
|
-
async getAll<K extends
|
|
55
|
+
async getAll<K extends Json, V extends Json>(
|
|
57
56
|
resource: string,
|
|
58
57
|
params: Record<string, string>,
|
|
59
|
-
|
|
60
|
-
): Promise<{ values: Entry<K, V>[]; reactive?: ReactiveResponse }> {
|
|
58
|
+
): Promise<Entry<K, V>[]> {
|
|
61
59
|
const qParams = new URLSearchParams(params).toString();
|
|
62
|
-
|
|
63
|
-
if (reactiveAuth) {
|
|
64
|
-
if (typeof reactiveAuth == "string") {
|
|
65
|
-
header = {
|
|
66
|
-
"X-Reactive-Auth": reactiveAuth,
|
|
67
|
-
};
|
|
68
|
-
} else {
|
|
69
|
-
header = {
|
|
70
|
-
"X-Reactive-Auth": Buffer.from(reactiveAuth.buffer).toString(
|
|
71
|
-
"base64",
|
|
72
|
-
),
|
|
73
|
-
};
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
const [optValues, headers] = await fetchJSON<Entry<K, V>[]>(
|
|
60
|
+
const [optValues, _headers] = await fetchJSON<Entry<K, V>[]>(
|
|
77
61
|
`${this.entrypoint}/v1/${resource}?${qParams}`,
|
|
78
62
|
"GET",
|
|
79
|
-
header,
|
|
80
63
|
);
|
|
81
|
-
const reactive = parseReactiveResponse(headers);
|
|
82
64
|
const values = optValues ?? [];
|
|
83
|
-
return
|
|
65
|
+
return values;
|
|
84
66
|
}
|
|
85
67
|
|
|
86
|
-
async
|
|
87
|
-
resource: string,
|
|
88
|
-
params: Record<string, string>,
|
|
89
|
-
reactiveAuth: Uint8Array | string,
|
|
90
|
-
): Promise<ReactiveResponse> {
|
|
91
|
-
const qParams = new URLSearchParams(params).toString();
|
|
92
|
-
const header = this.header(reactiveAuth);
|
|
93
|
-
const [_data, headers] = await fetchJSON(
|
|
94
|
-
`${this.entrypoint}/v1/${resource}?${qParams}`,
|
|
95
|
-
"HEAD",
|
|
96
|
-
header,
|
|
97
|
-
);
|
|
98
|
-
const reactiveResponse = parseReactiveResponse(headers);
|
|
99
|
-
if (!reactiveResponse)
|
|
100
|
-
throw new Error("Reactive response must be suplied.");
|
|
101
|
-
else {
|
|
102
|
-
return reactiveResponse;
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
async getArray<V extends TJSON>(
|
|
68
|
+
async getArray<V extends Json>(
|
|
107
69
|
resource: string,
|
|
108
70
|
params: Record<string, string>,
|
|
109
71
|
key: string,
|
|
110
|
-
reactiveAuth?: Uint8Array | string,
|
|
111
72
|
): Promise<V[]> {
|
|
112
73
|
const qParams = new URLSearchParams(params).toString();
|
|
113
|
-
const header = this.header(reactiveAuth);
|
|
114
74
|
const [data, _headers] = await fetchJSON<V[]>(
|
|
115
75
|
`${this.entrypoint}/v1/${resource}/${key}?${qParams}`,
|
|
116
76
|
"GET",
|
|
117
|
-
header,
|
|
118
77
|
);
|
|
119
78
|
return data ?? [];
|
|
120
79
|
}
|
|
121
80
|
|
|
122
|
-
async put<V extends
|
|
81
|
+
async put<K extends Json, V extends Json>(
|
|
123
82
|
collection: string,
|
|
124
|
-
key:
|
|
83
|
+
key: K,
|
|
125
84
|
value: V[],
|
|
126
85
|
): Promise<void> {
|
|
127
|
-
await
|
|
128
|
-
`${this.entrypoint}/v1/${collection}/${key}`,
|
|
129
|
-
"PUT",
|
|
130
|
-
{},
|
|
131
|
-
value,
|
|
132
|
-
);
|
|
86
|
+
return await this.patch(collection, [[key, value]]);
|
|
133
87
|
}
|
|
134
88
|
|
|
135
|
-
async patch<K extends
|
|
89
|
+
async patch<K extends Json, V extends Json>(
|
|
136
90
|
collection: string,
|
|
137
91
|
values: Entry<K, V>[],
|
|
138
92
|
): Promise<void> {
|
|
139
93
|
await fetchJSON(`${this.entrypoint}/v1/${collection}`, "PATCH", {}, values);
|
|
140
94
|
}
|
|
141
95
|
|
|
142
|
-
async deleteKey(collection: string, key:
|
|
143
|
-
await
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
private header(reactiveAuth?: Uint8Array | string): Record<string, string> {
|
|
147
|
-
if (reactiveAuth) {
|
|
148
|
-
if (typeof reactiveAuth == "string") {
|
|
149
|
-
return {
|
|
150
|
-
"X-Reactive-Auth": reactiveAuth,
|
|
151
|
-
};
|
|
152
|
-
} else {
|
|
153
|
-
return {
|
|
154
|
-
"X-Reactive-Auth": Buffer.from(reactiveAuth.buffer).toString(
|
|
155
|
-
"base64",
|
|
156
|
-
),
|
|
157
|
-
};
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
return {};
|
|
96
|
+
async deleteKey<K extends Json>(collection: string, key: K): Promise<void> {
|
|
97
|
+
return await this.patch(collection, [[key, []]]);
|
|
161
98
|
}
|
|
162
99
|
}
|