@skipruntime/helpers 0.0.1
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/errors.d.ts +3 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +3 -0
- package/dist/errors.js.map +1 -0
- package/dist/external.d.ts +43 -0
- package/dist/external.d.ts.map +1 -0
- package/dist/external.js +100 -0
- package/dist/external.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -0
- package/dist/remote.d.ts +23 -0
- package/dist/remote.d.ts.map +1 -0
- package/dist/remote.js +83 -0
- package/dist/remote.js.map +1 -0
- package/dist/rest.d.ts +22 -0
- package/dist/rest.d.ts.map +1 -0
- package/dist/rest.js +97 -0
- package/dist/rest.js.map +1 -0
- package/dist/utils.d.ts +24 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +58 -0
- package/dist/utils.js.map +1 -0
- package/eslint.config.js +3 -0
- package/package.json +27 -0
- package/src/errors.ts +1 -0
- package/src/external.ts +174 -0
- package/src/index.ts +14 -0
- package/src/remote.ts +158 -0
- package/src/rest.ts +162 -0
- package/src/utils.ts +78 -0
- package/tsconfig.json +3 -0
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,qBAAa,sBAAuB,SAAQ,KAAK;CAAG"}
|
package/dist/errors.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,sBAAuB,SAAQ,KAAK;CAAG"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { Entry, ExternalService, TJSON } from "@skipruntime/api";
|
|
2
|
+
export interface ExternalResource {
|
|
3
|
+
open(params: Record<string, string | number>, callbacks: {
|
|
4
|
+
update: (updates: Entry<TJSON, TJSON>[], isInit: boolean) => void;
|
|
5
|
+
error: (error: TJSON) => void;
|
|
6
|
+
loading: () => void;
|
|
7
|
+
}, reactiveAuth?: Uint8Array): void;
|
|
8
|
+
close(params: Record<string, string | number>, reactiveAuth?: Uint8Array): void;
|
|
9
|
+
}
|
|
10
|
+
export declare class GenericExternalService implements ExternalService {
|
|
11
|
+
private resources;
|
|
12
|
+
constructor(resources: Record<string, ExternalResource>);
|
|
13
|
+
subscribe(resourceName: string, params: Record<string, string | number>, callbacks: {
|
|
14
|
+
update: (updates: Entry<TJSON, TJSON>[], isInit: boolean) => void;
|
|
15
|
+
error: (error: TJSON) => void;
|
|
16
|
+
loading: () => void;
|
|
17
|
+
}, reactiveAuth?: Uint8Array): void;
|
|
18
|
+
unsubscribe(resourceName: string, params: Record<string, string>, reactiveAuth?: Uint8Array): void;
|
|
19
|
+
shutdown(): void;
|
|
20
|
+
}
|
|
21
|
+
export declare class TimerResource implements ExternalResource {
|
|
22
|
+
private intervals;
|
|
23
|
+
open(params: Record<string, string | number>, callbacks: {
|
|
24
|
+
update: (updates: Entry<TJSON, TJSON>[], isInit: boolean) => void;
|
|
25
|
+
error: (error: TJSON) => void;
|
|
26
|
+
loading: () => void;
|
|
27
|
+
}, reactiveAuth?: Uint8Array): void;
|
|
28
|
+
close(params: Record<string, string | number>, reactiveAuth?: Uint8Array): void;
|
|
29
|
+
}
|
|
30
|
+
export declare class Polled<S extends TJSON, K extends TJSON, V extends TJSON> implements ExternalResource {
|
|
31
|
+
private url;
|
|
32
|
+
private duration;
|
|
33
|
+
private conv;
|
|
34
|
+
private intervals;
|
|
35
|
+
constructor(url: string, duration: number, conv: (data: S) => Entry<K, V>[]);
|
|
36
|
+
open(params: Record<string, string | number>, callbacks: {
|
|
37
|
+
update: (updates: Entry<TJSON, TJSON>[], isInit: boolean) => void;
|
|
38
|
+
error: (error: TJSON) => void;
|
|
39
|
+
loading: () => void;
|
|
40
|
+
}, reactiveAuth?: Uint8Array): void;
|
|
41
|
+
close(params: Record<string, string | number>, reactiveAuth?: Uint8Array): void;
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=external.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"external.d.ts","sourceRoot":"","sources":["../src/external.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,eAAe,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAGtE,MAAM,WAAW,gBAAgB;IAC/B,IAAI,CACF,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,EACvC,SAAS,EAAE;QACT,MAAM,EAAE,CAAC,OAAO,EAAE,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,KAAK,IAAI,CAAC;QAClE,KAAK,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;QAC9B,OAAO,EAAE,MAAM,IAAI,CAAC;KACrB,EACD,YAAY,CAAC,EAAE,UAAU,GACxB,IAAI,CAAC;IAER,KAAK,CACH,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,EACvC,YAAY,CAAC,EAAE,UAAU,GACxB,IAAI,CAAC;CACT;AAED,qBAAa,sBAAuB,YAAW,eAAe;IAChD,OAAO,CAAC,SAAS;gBAAT,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC;IAE/D,SAAS,CACP,YAAY,EAAE,MAAM,EACpB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,EACvC,SAAS,EAAE;QACT,MAAM,EAAE,CAAC,OAAO,EAAE,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,KAAK,IAAI,CAAC;QAClE,KAAK,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;QAC9B,OAAO,EAAE,MAAM,IAAI,CAAC;KACrB,EACD,YAAY,CAAC,EAAE,UAAU,GACxB,IAAI;IAUP,WAAW,CACT,YAAY,EAAE,MAAM,EACpB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC9B,YAAY,CAAC,EAAE,UAAU;IAW3B,QAAQ,IAAI,IAAI;CAGjB;AAID,qBAAa,aAAc,YAAW,gBAAgB;IACpD,OAAO,CAAC,SAAS,CAA8C;IAE/D,IAAI,CACF,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,EACvC,SAAS,EAAE;QACT,MAAM,EAAE,CAAC,OAAO,EAAE,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,KAAK,IAAI,CAAC;QAClE,KAAK,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;QAC9B,OAAO,EAAE,MAAM,IAAI,CAAC;KACrB,EACD,YAAY,CAAC,EAAE,UAAU;IAsB3B,KAAK,CACH,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,EACvC,YAAY,CAAC,EAAE,UAAU,GACxB,IAAI;CAQR;AAED,qBAAa,MAAM,CAAC,CAAC,SAAS,KAAK,EAAE,CAAC,SAAS,KAAK,EAAE,CAAC,SAAS,KAAK,CACnE,YAAW,gBAAgB;IAKzB,OAAO,CAAC,GAAG;IACX,OAAO,CAAC,QAAQ;IAChB,OAAO,CAAC,IAAI;IALd,OAAO,CAAC,SAAS,CAA8B;gBAGrC,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE;IAG1C,IAAI,CACF,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,EACvC,SAAS,EAAE;QACT,MAAM,EAAE,CAAC,OAAO,EAAE,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,KAAK,IAAI,CAAC;QAClE,KAAK,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;QAC9B,OAAO,EAAE,MAAM,IAAI,CAAC;KACrB,EACD,YAAY,CAAC,EAAE,UAAU,GACxB,IAAI;IA0BP,KAAK,CACH,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,EACvC,YAAY,CAAC,EAAE,UAAU,GACxB,IAAI;CAMR"}
|
package/dist/external.js
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { fetchJSON } from "./rest.js";
|
|
2
|
+
export class GenericExternalService {
|
|
3
|
+
constructor(resources) {
|
|
4
|
+
this.resources = resources;
|
|
5
|
+
}
|
|
6
|
+
subscribe(resourceName, params, callbacks, reactiveAuth) {
|
|
7
|
+
const resource = this.resources[resourceName];
|
|
8
|
+
if (!resource) {
|
|
9
|
+
throw new Error(`Unkonwn resource named '${resourceName}'`);
|
|
10
|
+
}
|
|
11
|
+
resource.open(params, callbacks, reactiveAuth);
|
|
12
|
+
}
|
|
13
|
+
unsubscribe(resourceName, params, reactiveAuth) {
|
|
14
|
+
const resource = this.resources[resourceName];
|
|
15
|
+
if (!resource) {
|
|
16
|
+
throw new Error(`Unkonwn resource named '${resourceName}'`);
|
|
17
|
+
}
|
|
18
|
+
resource.close(params, reactiveAuth);
|
|
19
|
+
}
|
|
20
|
+
shutdown() {
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
export class TimerResource {
|
|
25
|
+
constructor() {
|
|
26
|
+
this.intervals = new Map();
|
|
27
|
+
}
|
|
28
|
+
open(params, callbacks, reactiveAuth) {
|
|
29
|
+
const time = new Date().getTime();
|
|
30
|
+
const values = [];
|
|
31
|
+
for (const name of Object.keys(params)) {
|
|
32
|
+
values.push([name, [time]]);
|
|
33
|
+
}
|
|
34
|
+
callbacks.update(values, true);
|
|
35
|
+
const id = toId(params, reactiveAuth);
|
|
36
|
+
const intervals = {};
|
|
37
|
+
for (const [name, duration] of Object.entries(params)) {
|
|
38
|
+
const ms = Number(duration);
|
|
39
|
+
if (ms > 0) {
|
|
40
|
+
intervals[name] = setInterval(() => {
|
|
41
|
+
const newvalue = [name, [new Date().getTime()]];
|
|
42
|
+
callbacks.update([newvalue], true);
|
|
43
|
+
}, ms);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
this.intervals.set(id, intervals);
|
|
47
|
+
}
|
|
48
|
+
close(params, reactiveAuth) {
|
|
49
|
+
const intervals = this.intervals.get(toId(params, reactiveAuth));
|
|
50
|
+
if (intervals != null) {
|
|
51
|
+
for (const interval of Object.values(intervals)) {
|
|
52
|
+
clearInterval(interval);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
export class Polled {
|
|
58
|
+
constructor(url, duration, conv) {
|
|
59
|
+
this.url = url;
|
|
60
|
+
this.duration = duration;
|
|
61
|
+
this.conv = conv;
|
|
62
|
+
this.intervals = new Map();
|
|
63
|
+
}
|
|
64
|
+
open(params, callbacks, reactiveAuth) {
|
|
65
|
+
this.close(params, reactiveAuth);
|
|
66
|
+
const querieParams = {};
|
|
67
|
+
for (const [key, value] of Object.entries(params)) {
|
|
68
|
+
querieParams[key] = value.toString();
|
|
69
|
+
}
|
|
70
|
+
const strParams = new URLSearchParams(querieParams).toString();
|
|
71
|
+
const url = `${this.url}?${strParams}`;
|
|
72
|
+
const call = () => {
|
|
73
|
+
callbacks.loading();
|
|
74
|
+
fetchJSON(url, "GET", {})
|
|
75
|
+
.then((r) => {
|
|
76
|
+
callbacks.update(this.conv(r[0]), true);
|
|
77
|
+
})
|
|
78
|
+
.catch((e) => {
|
|
79
|
+
callbacks.error(e instanceof Error ? e.message : JSON.stringify(e));
|
|
80
|
+
console.error(e);
|
|
81
|
+
});
|
|
82
|
+
};
|
|
83
|
+
call();
|
|
84
|
+
this.intervals.set(toId(params, reactiveAuth), setInterval(call, this.duration));
|
|
85
|
+
}
|
|
86
|
+
close(params, reactiveAuth) {
|
|
87
|
+
const interval = this.intervals.get(toId(params, reactiveAuth));
|
|
88
|
+
if (interval) {
|
|
89
|
+
clearInterval(interval);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
function toId(params, reactiveAuth) {
|
|
94
|
+
const strparams = Object.entries(params)
|
|
95
|
+
.map(([key, value]) => `${key}:${value.toString()}`)
|
|
96
|
+
.sort();
|
|
97
|
+
const hex = reactiveAuth ? Buffer.from(reactiveAuth).toString("hex") : "";
|
|
98
|
+
return `[${strparams.join(",")}]${hex}`;
|
|
99
|
+
}
|
|
100
|
+
//# sourceMappingURL=external.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"external.js","sourceRoot":"","sources":["../src/external.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { SkipExternalService } from "./remote.js";
|
|
2
|
+
export { type ExternalResource, GenericExternalService, Polled, } from "./external.js";
|
|
3
|
+
export { Sum, Min, Max, CountMapper, parseReactiveResponse, reactiveResponseHeader, } from "./utils.js";
|
|
4
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,EACL,KAAK,gBAAgB,EACrB,sBAAsB,EACtB,MAAM,GACP,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,GAAG,EACH,GAAG,EACH,GAAG,EACH,WAAW,EACX,qBAAqB,EACrB,sBAAsB,GACvB,MAAM,YAAY,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,EAEL,sBAAsB,EACtB,MAAM,GACP,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,GAAG,EACH,GAAG,EACH,GAAG,EACH,WAAW,EACX,qBAAqB,EACrB,sBAAsB,GACvB,MAAM,YAAY,CAAC"}
|
package/dist/remote.d.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { Entry, ExternalService, ReactiveResponse, TJSON } from "@skipruntime/api";
|
|
2
|
+
import { Protocol } from "@skipruntime/client";
|
|
3
|
+
import { type Entrypoint } from "./rest.js";
|
|
4
|
+
export declare class SkipExternalService implements ExternalService {
|
|
5
|
+
private url;
|
|
6
|
+
private auth;
|
|
7
|
+
private creds?;
|
|
8
|
+
private client?;
|
|
9
|
+
private resources;
|
|
10
|
+
constructor(url: string, auth: (resource: string, params: Record<string, string>, reactiveAuth: Uint8Array) => Promise<ReactiveResponse>, creds?: Protocol.Creds | undefined);
|
|
11
|
+
static fromEntrypoint(entrypoint: Entrypoint, auth: (resource: string, params: Record<string, string>, reactiveAuth: Uint8Array) => Promise<ReactiveResponse>, creds?: Protocol.Creds): SkipExternalService;
|
|
12
|
+
static direct(entrypoint: Entrypoint, creds?: Protocol.Creds): SkipExternalService;
|
|
13
|
+
subscribe(resource: string, params: Record<string, string>, callbacks: {
|
|
14
|
+
update: (updates: Entry<TJSON, TJSON>[], isInit: boolean) => void;
|
|
15
|
+
error: (error: TJSON) => void;
|
|
16
|
+
loading: () => void;
|
|
17
|
+
}, reactiveAuth?: Uint8Array): void;
|
|
18
|
+
unsubscribe(resource: string, params: Record<string, string>, reactiveAuth?: Uint8Array): void;
|
|
19
|
+
shutdown(): void;
|
|
20
|
+
private subscribe_;
|
|
21
|
+
private toId;
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=remote.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"remote.d.ts","sourceRoot":"","sources":["../src/remote.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,KAAK,EACL,eAAe,EACf,gBAAgB,EAChB,KAAK,EACN,MAAM,kBAAkB,CAAC;AAG1B,OAAO,EAAW,QAAQ,EAAU,MAAM,qBAAqB,CAAC;AAChE,OAAO,EAAa,KAAK,UAAU,EAAE,MAAM,WAAW,CAAC;AAMvD,qBAAa,mBAAoB,YAAW,eAAe;IAKvD,OAAO,CAAC,GAAG;IACX,OAAO,CAAC,IAAI;IAKZ,OAAO,CAAC,KAAK,CAAC;IAVhB,OAAO,CAAC,MAAM,CAAC,CAAoC;IACnD,OAAO,CAAC,SAAS,CAA+B;gBAGtC,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,CACZ,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC9B,YAAY,EAAE,UAAU,KACrB,OAAO,CAAC,gBAAgB,CAAC,EACtB,KAAK,CAAC,EAAE,QAAQ,CAAC,KAAK,YAAA;IAGhC,MAAM,CAAC,cAAc,CACnB,UAAU,EAAE,UAAU,EACtB,IAAI,EAAE,CACJ,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC9B,YAAY,EAAE,UAAU,KACrB,OAAO,CAAC,gBAAgB,CAAC,EAC9B,KAAK,CAAC,EAAE,QAAQ,CAAC,KAAK,GACrB,mBAAmB;IAOtB,MAAM,CAAC,MAAM,CACX,UAAU,EAAE,UAAU,EACtB,KAAK,CAAC,EAAE,QAAQ,CAAC,KAAK,GACrB,mBAAmB;IA0BtB,SAAS,CACP,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC9B,SAAS,EAAE;QACT,MAAM,EAAE,CAAC,OAAO,EAAE,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,KAAK,IAAI,CAAC;QAClE,KAAK,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;QAC9B,OAAO,EAAE,MAAM,IAAI,CAAC;KACrB,EACD,YAAY,CAAC,EAAE,UAAU,GACxB,IAAI;IAoBP,WAAW,CACT,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC9B,YAAY,CAAC,EAAE,UAAU;IAQ3B,QAAQ,IAAI,IAAI;YAUF,UAAU;IAsBxB,OAAO,CAAC,IAAI;CAYb"}
|
package/dist/remote.js
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { parseReactiveResponse } from "./utils.js";
|
|
2
|
+
import { connect, Protocol, Client } from "@skipruntime/client";
|
|
3
|
+
import { fetchJSON } from "./rest.js";
|
|
4
|
+
export class SkipExternalService {
|
|
5
|
+
constructor(url, auth, creds) {
|
|
6
|
+
this.url = url;
|
|
7
|
+
this.auth = auth;
|
|
8
|
+
this.creds = creds;
|
|
9
|
+
this.resources = new Map();
|
|
10
|
+
}
|
|
11
|
+
static fromEntrypoint(entrypoint, auth, creds) {
|
|
12
|
+
let url = `ws://${entrypoint.host}:${entrypoint.port.toString()}`;
|
|
13
|
+
if (entrypoint.secured)
|
|
14
|
+
url = `wss://${entrypoint.host}:${entrypoint.port.toString()}`;
|
|
15
|
+
return new SkipExternalService(url, auth, creds);
|
|
16
|
+
}
|
|
17
|
+
static direct(entrypoint, creds) {
|
|
18
|
+
let url = `http://${entrypoint.host}:${entrypoint.port.toString()}`;
|
|
19
|
+
if (entrypoint.secured)
|
|
20
|
+
url = `https://${entrypoint.host}:${entrypoint.port.toString()}`;
|
|
21
|
+
const auth = async (resource, params, reactiveAuth) => {
|
|
22
|
+
const qParams = new URLSearchParams(params).toString();
|
|
23
|
+
const header = {
|
|
24
|
+
"X-Reactive-Auth": Buffer.from(reactiveAuth).toString("base64"),
|
|
25
|
+
};
|
|
26
|
+
const [_data, headers] = await fetchJSON(`${url}/v1/${resource}?${qParams}`, "HEAD", header);
|
|
27
|
+
const reactiveResponse = parseReactiveResponse(headers);
|
|
28
|
+
if (!reactiveResponse)
|
|
29
|
+
throw new Error("Reactive response must be suplied.");
|
|
30
|
+
return reactiveResponse;
|
|
31
|
+
};
|
|
32
|
+
return new SkipExternalService(url, auth, creds);
|
|
33
|
+
}
|
|
34
|
+
subscribe(resource, params, callbacks, reactiveAuth) {
|
|
35
|
+
if (!this.client) {
|
|
36
|
+
if (!this.creds) {
|
|
37
|
+
this.client = Protocol.generateCredentials().then((creds) => {
|
|
38
|
+
this.creds = creds;
|
|
39
|
+
return connect(this.url, this.creds).then((c) => [c, creds]);
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
this.client = connect(this.url, this.creds).then((c) => {
|
|
44
|
+
return [c, this.creds];
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
this.subscribe_(resource, params, callbacks, reactiveAuth).catch((e) => {
|
|
49
|
+
console.error(e);
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
unsubscribe(resource, params, reactiveAuth) {
|
|
53
|
+
const closable = this.resources.get(this.toId(resource, params, reactiveAuth));
|
|
54
|
+
if (closable)
|
|
55
|
+
closable.close();
|
|
56
|
+
}
|
|
57
|
+
shutdown() {
|
|
58
|
+
if (this.client) {
|
|
59
|
+
this.client
|
|
60
|
+
.then((client) => {
|
|
61
|
+
client[0].close();
|
|
62
|
+
})
|
|
63
|
+
.catch((e) => console.error(e));
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
async subscribe_(resource, params, callbacks, reactiveAuth) {
|
|
67
|
+
const [client, creds] = await this.client;
|
|
68
|
+
const publicKey = new Uint8Array(await Protocol.exportKey(creds.publicKey));
|
|
69
|
+
const reactive = await this.auth(resource, params, publicKey);
|
|
70
|
+
// TODO Manage Status
|
|
71
|
+
const close = client.subscribe(reactive.collection, BigInt(reactive.watermark), callbacks.update);
|
|
72
|
+
this.resources.set(this.toId(resource, params, reactiveAuth), close);
|
|
73
|
+
}
|
|
74
|
+
toId(resource, params, reactiveAuth) {
|
|
75
|
+
const strparams = [];
|
|
76
|
+
for (const key of Object.keys(params).sort()) {
|
|
77
|
+
strparams.push(`${key}:${params[key]}`);
|
|
78
|
+
}
|
|
79
|
+
const hex = reactiveAuth ? Buffer.from(reactiveAuth).toString("hex") : "";
|
|
80
|
+
return `${resource}[${strparams.join(",")}]${hex}`;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
//# sourceMappingURL=remote.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"remote.js","sourceRoot":"","sources":["../src/remote.ts"],"names":[],"mappings":"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"}
|
package/dist/rest.d.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { TJSON, Entry, ReactiveResponse } from "@skipruntime/api";
|
|
2
|
+
export type Entrypoint = {
|
|
3
|
+
host: string;
|
|
4
|
+
port: number;
|
|
5
|
+
secured?: boolean;
|
|
6
|
+
};
|
|
7
|
+
export declare function fetchJSON<V>(url: string, method?: "POST" | "GET" | "PUT" | "PATCH" | "HEAD" | "DELETE", headers?: Record<string, string>, data?: TJSON): Promise<[V | null, Headers]>;
|
|
8
|
+
export declare class SkipRESTService {
|
|
9
|
+
private entrypoint;
|
|
10
|
+
constructor(entrypoint?: Entrypoint);
|
|
11
|
+
getAll<K extends TJSON, V extends TJSON>(resource: string, params: Record<string, string>, reactiveAuth?: Uint8Array | string): Promise<{
|
|
12
|
+
values: Entry<K, V>[];
|
|
13
|
+
reactive?: ReactiveResponse;
|
|
14
|
+
}>;
|
|
15
|
+
head(resource: string, params: Record<string, string>, reactiveAuth: Uint8Array | string): Promise<ReactiveResponse>;
|
|
16
|
+
getArray<V extends TJSON>(resource: string, params: Record<string, string>, key: string, reactiveAuth?: Uint8Array | string): Promise<V[]>;
|
|
17
|
+
put<V extends TJSON>(collection: string, key: string, value: V[]): Promise<void>;
|
|
18
|
+
patch<K extends TJSON, V extends TJSON>(collection: string, values: Entry<K, V>[]): Promise<void>;
|
|
19
|
+
deleteKey(collection: string, key: string): Promise<void>;
|
|
20
|
+
private header;
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=rest.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rest.d.ts","sourceRoot":"","sources":["../src/rest.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAGvE,MAAM,MAAM,UAAU,GAAG;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,CAAC;AAQF,wBAAsB,SAAS,CAAC,CAAC,EAC/B,GAAG,EAAE,MAAM,EACX,MAAM,GAAE,MAAM,GAAG,KAAK,GAAG,KAAK,GAAG,OAAO,GAAG,MAAM,GAAG,QAAgB,EACpE,OAAO,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAM,EACpC,IAAI,CAAC,EAAE,KAAK,GACX,OAAO,CAAC,CAAC,CAAC,GAAG,IAAI,EAAE,OAAO,CAAC,CAAC,CAqB9B;AAED,qBAAa,eAAe;IAC1B,OAAO,CAAC,UAAU,CAAS;gBAGzB,UAAU,GAAE,UAGX;IAKG,MAAM,CAAC,CAAC,SAAS,KAAK,EAAE,CAAC,SAAS,KAAK,EAC3C,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC9B,YAAY,CAAC,EAAE,UAAU,GAAG,MAAM,GACjC,OAAO,CAAC;QAAE,MAAM,EAAE,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;QAAC,QAAQ,CAAC,EAAE,gBAAgB,CAAA;KAAE,CAAC;IA0B5D,IAAI,CACR,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC9B,YAAY,EAAE,UAAU,GAAG,MAAM,GAChC,OAAO,CAAC,gBAAgB,CAAC;IAgBtB,QAAQ,CAAC,CAAC,SAAS,KAAK,EAC5B,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC9B,GAAG,EAAE,MAAM,EACX,YAAY,CAAC,EAAE,UAAU,GAAG,MAAM,GACjC,OAAO,CAAC,CAAC,EAAE,CAAC;IAWT,GAAG,CAAC,CAAC,SAAS,KAAK,EACvB,UAAU,EAAE,MAAM,EAClB,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,CAAC,EAAE,GACT,OAAO,CAAC,IAAI,CAAC;IASV,KAAK,CAAC,CAAC,SAAS,KAAK,EAAE,CAAC,SAAS,KAAK,EAC1C,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,GACpB,OAAO,CAAC,IAAI,CAAC;IAIV,SAAS,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAI/D,OAAO,CAAC,MAAM;CAgBf"}
|
package/dist/rest.js
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { parseReactiveResponse } from "./utils.js";
|
|
2
|
+
function toHttp(entrypoint) {
|
|
3
|
+
if (entrypoint.secured)
|
|
4
|
+
return `https://${entrypoint.host}:${entrypoint.port}`;
|
|
5
|
+
return `http://${entrypoint.host}:${entrypoint.port}`;
|
|
6
|
+
}
|
|
7
|
+
export async function fetchJSON(url, method = "GET", headers = {}, data) {
|
|
8
|
+
const body = data ? JSON.stringify(data) : undefined;
|
|
9
|
+
const response = await fetch(url, {
|
|
10
|
+
method,
|
|
11
|
+
body,
|
|
12
|
+
headers: {
|
|
13
|
+
"Content-Type": "application/json",
|
|
14
|
+
Accept: "application/json",
|
|
15
|
+
...headers,
|
|
16
|
+
},
|
|
17
|
+
signal: AbortSignal.timeout(1000),
|
|
18
|
+
});
|
|
19
|
+
if (!response.ok) {
|
|
20
|
+
throw new Error(`${response.status}: ${response.statusText}`);
|
|
21
|
+
}
|
|
22
|
+
const responseText = await response.text();
|
|
23
|
+
const responseJSON = responseText.length > 0 && responseText != response.statusText
|
|
24
|
+
? JSON.parse(responseText)
|
|
25
|
+
: null;
|
|
26
|
+
return [responseJSON, response.headers];
|
|
27
|
+
}
|
|
28
|
+
export class SkipRESTService {
|
|
29
|
+
constructor(entrypoint = {
|
|
30
|
+
host: "localhost",
|
|
31
|
+
port: 3587,
|
|
32
|
+
}) {
|
|
33
|
+
this.entrypoint = toHttp(entrypoint);
|
|
34
|
+
}
|
|
35
|
+
async getAll(resource, params, reactiveAuth) {
|
|
36
|
+
const qParams = new URLSearchParams(params).toString();
|
|
37
|
+
let header = {};
|
|
38
|
+
if (reactiveAuth) {
|
|
39
|
+
if (typeof reactiveAuth == "string") {
|
|
40
|
+
header = {
|
|
41
|
+
"X-Reactive-Auth": reactiveAuth,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
header = {
|
|
46
|
+
"X-Reactive-Auth": Buffer.from(reactiveAuth.buffer).toString("base64"),
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
const [optValues, headers] = await fetchJSON(`${this.entrypoint}/v1/${resource}?${qParams}`, "GET", header);
|
|
51
|
+
const reactive = parseReactiveResponse(headers);
|
|
52
|
+
const values = optValues ?? [];
|
|
53
|
+
return reactive ? { values, reactive } : { values };
|
|
54
|
+
}
|
|
55
|
+
async head(resource, params, reactiveAuth) {
|
|
56
|
+
const qParams = new URLSearchParams(params).toString();
|
|
57
|
+
const header = this.header(reactiveAuth);
|
|
58
|
+
const [_data, headers] = await fetchJSON(`${this.entrypoint}/v1/${resource}?${qParams}`, "HEAD", header);
|
|
59
|
+
const reactiveResponse = parseReactiveResponse(headers);
|
|
60
|
+
if (!reactiveResponse)
|
|
61
|
+
throw new Error("Reactive response must be suplied.");
|
|
62
|
+
else {
|
|
63
|
+
return reactiveResponse;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
async getArray(resource, params, key, reactiveAuth) {
|
|
67
|
+
const qParams = new URLSearchParams(params).toString();
|
|
68
|
+
const header = this.header(reactiveAuth);
|
|
69
|
+
const [data, _headers] = await fetchJSON(`${this.entrypoint}/v1/${resource}/${key}?${qParams}`, "GET", header);
|
|
70
|
+
return data ?? [];
|
|
71
|
+
}
|
|
72
|
+
async put(collection, key, value) {
|
|
73
|
+
await fetchJSON(`${this.entrypoint}/v1/${collection}/${key}`, "PUT", {}, value);
|
|
74
|
+
}
|
|
75
|
+
async patch(collection, values) {
|
|
76
|
+
await fetchJSON(`${this.entrypoint}/v1/${collection}`, "PATCH", {}, values);
|
|
77
|
+
}
|
|
78
|
+
async deleteKey(collection, key) {
|
|
79
|
+
await fetchJSON(`${this.entrypoint}/v1/${collection}/${key}`, "DELETE", {});
|
|
80
|
+
}
|
|
81
|
+
header(reactiveAuth) {
|
|
82
|
+
if (reactiveAuth) {
|
|
83
|
+
if (typeof reactiveAuth == "string") {
|
|
84
|
+
return {
|
|
85
|
+
"X-Reactive-Auth": reactiveAuth,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
return {
|
|
90
|
+
"X-Reactive-Auth": Buffer.from(reactiveAuth.buffer).toString("base64"),
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return {};
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
//# sourceMappingURL=rest.js.map
|
package/dist/rest.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rest.js","sourceRoot":"","sources":["../src/rest.ts"],"names":[],"mappings":"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"}
|
package/dist/utils.d.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { Opt } from "@skip-wasm/std";
|
|
2
|
+
import { ManyToOneMapper } from "@skipruntime/api";
|
|
3
|
+
import type { Accumulator, NonEmptyIterator, ReactiveResponse, TJSON } from "@skipruntime/api";
|
|
4
|
+
export declare class Sum implements Accumulator<number, number> {
|
|
5
|
+
default: number;
|
|
6
|
+
accumulate(acc: number, value: number): number;
|
|
7
|
+
dismiss(acc: number, value: number): Opt<number>;
|
|
8
|
+
}
|
|
9
|
+
export declare class Min implements Accumulator<number, number> {
|
|
10
|
+
default: null;
|
|
11
|
+
accumulate(acc: Opt<number>, value: number): number;
|
|
12
|
+
dismiss(acc: number, value: number): Opt<number>;
|
|
13
|
+
}
|
|
14
|
+
export declare class Max implements Accumulator<number, number> {
|
|
15
|
+
default: null;
|
|
16
|
+
accumulate(acc: Opt<number>, value: number): number;
|
|
17
|
+
dismiss(acc: number, value: number): Opt<number>;
|
|
18
|
+
}
|
|
19
|
+
export declare class CountMapper<K extends TJSON, V extends TJSON> extends ManyToOneMapper<K, V, number> {
|
|
20
|
+
mapValues(values: NonEmptyIterator<V>): number;
|
|
21
|
+
}
|
|
22
|
+
export declare function parseReactiveResponse(header: Headers | string): ReactiveResponse | undefined;
|
|
23
|
+
export declare function reactiveResponseHeader(reactiveResponse: ReactiveResponse): [string, string];
|
|
24
|
+
//# sourceMappingURL=utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,KAAK,EACV,WAAW,EACX,gBAAgB,EAChB,gBAAgB,EAChB,KAAK,EACN,MAAM,kBAAkB,CAAC;AAE1B,qBAAa,GAAI,YAAW,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC;IACrD,OAAO,SAAK;IAEZ,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM;IAI9C,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC;CAGjD;AAED,qBAAa,GAAI,YAAW,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC;IACrD,OAAO,OAAQ;IAEf,UAAU,CAAC,GAAG,EAAE,GAAG,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM;IAInD,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC;CAGjD;AAED,qBAAa,GAAI,YAAW,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC;IACrD,OAAO,OAAQ;IAEf,UAAU,CAAC,GAAG,EAAE,GAAG,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM;IAInD,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC;CAGjD;AAED,qBAAa,WAAW,CACtB,CAAC,SAAS,KAAK,EACf,CAAC,SAAS,KAAK,CACf,SAAQ,eAAe,CAAC,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC;IACrC,SAAS,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC,CAAC,GAAG,MAAM;CAG/C;AAED,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,OAAO,GAAG,MAAM,GACvB,gBAAgB,GAAG,SAAS,CAU9B;AAED,wBAAgB,sBAAsB,CACpC,gBAAgB,EAAE,gBAAgB,GACjC,CAAC,MAAM,EAAE,MAAM,CAAC,CAOlB"}
|
package/dist/utils.js
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { ManyToOneMapper } from "@skipruntime/api";
|
|
2
|
+
export class Sum {
|
|
3
|
+
constructor() {
|
|
4
|
+
this.default = 0;
|
|
5
|
+
}
|
|
6
|
+
accumulate(acc, value) {
|
|
7
|
+
return acc + value;
|
|
8
|
+
}
|
|
9
|
+
dismiss(acc, value) {
|
|
10
|
+
return acc - value;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
export class Min {
|
|
14
|
+
constructor() {
|
|
15
|
+
this.default = null;
|
|
16
|
+
}
|
|
17
|
+
accumulate(acc, value) {
|
|
18
|
+
return acc === null ? value : Math.min(acc, value);
|
|
19
|
+
}
|
|
20
|
+
dismiss(acc, value) {
|
|
21
|
+
return value > acc ? acc : null;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
export class Max {
|
|
25
|
+
constructor() {
|
|
26
|
+
this.default = null;
|
|
27
|
+
}
|
|
28
|
+
accumulate(acc, value) {
|
|
29
|
+
return acc === null ? value : Math.max(acc, value);
|
|
30
|
+
}
|
|
31
|
+
dismiss(acc, value) {
|
|
32
|
+
return value < acc ? acc : null;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
export class CountMapper extends ManyToOneMapper {
|
|
36
|
+
mapValues(values) {
|
|
37
|
+
return values.toArray().length;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
export function parseReactiveResponse(header) {
|
|
41
|
+
const strReactiveResponse = typeof header == "string"
|
|
42
|
+
? header
|
|
43
|
+
: header.get("Skip-Reactive-Response-Token");
|
|
44
|
+
if (!strReactiveResponse)
|
|
45
|
+
return undefined;
|
|
46
|
+
return JSON.parse(strReactiveResponse, (key, value) => {
|
|
47
|
+
if (key == "watermark")
|
|
48
|
+
return BigInt(value);
|
|
49
|
+
return value;
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
export function reactiveResponseHeader(reactiveResponse) {
|
|
53
|
+
return [
|
|
54
|
+
"Skip-Reactive-Response-Token",
|
|
55
|
+
JSON.stringify(reactiveResponse, (_key, value) => typeof value === "bigint" ? value.toString() : value),
|
|
56
|
+
];
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=utils.js.map
|
|
@@ -0,0 +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,UAAU,CAAC,GAAW,EAAE,KAAa;QACnC,OAAO,GAAG,GAAG,KAAK,CAAC;IACrB,CAAC;IAED,OAAO,CAAC,GAAW,EAAE,KAAa;QAChC,OAAO,GAAG,GAAG,KAAK,CAAC;IACrB,CAAC;CACF;AAED,MAAM,OAAO,GAAG;IAAhB;QACE,YAAO,GAAG,IAAI,CAAC;IASjB,CAAC;IAPC,UAAU,CAAC,GAAgB,EAAE,KAAa;QACxC,OAAO,GAAG,KAAK,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IACrD,CAAC;IAED,OAAO,CAAC,GAAW,EAAE,KAAa;QAChC,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,UAAU,CAAC,GAAgB,EAAE,KAAa;QACxC,OAAO,GAAG,KAAK,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IACrD,CAAC;IAED,OAAO,CAAC,GAAW,EAAE,KAAa;QAChC,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,EAAE,CAAC,GAAW,EAAE,KAAa,EAAE,EAAE;QACpE,IAAI,GAAG,IAAI,WAAW;YAAE,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC;QAC7C,OAAO,KAAK,CAAC;IACf,CAAC,CAAqB,CAAC;AACzB,CAAC;AAED,MAAM,UAAU,sBAAsB,CACpC,gBAAkC;IAElC,OAAO;QACL,8BAA8B;QAC9B,IAAI,CAAC,SAAS,CAAC,gBAAgB,EAAE,CAAC,IAAY,EAAE,KAAc,EAAE,EAAE,CAChE,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,KAAK,CACrD;KACF,CAAC;AACJ,CAAC"}
|
package/eslint.config.js
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@skipruntime/helpers",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"exports": {
|
|
6
|
+
".": "./dist/index.js",
|
|
7
|
+
"./errors.js": "./dist/errors.js",
|
|
8
|
+
"./rest.js": "./dist/rest.js",
|
|
9
|
+
"./external.js": "./dist/external.js"
|
|
10
|
+
},
|
|
11
|
+
"scripts": {
|
|
12
|
+
"build": "tsc",
|
|
13
|
+
"clean": "rm -rf dist",
|
|
14
|
+
"lint": "eslint"
|
|
15
|
+
},
|
|
16
|
+
"author": "SkipLabs",
|
|
17
|
+
"license": "MIT",
|
|
18
|
+
"description": "",
|
|
19
|
+
"engines": {
|
|
20
|
+
"node": ">=22.6.0 <23.0.0"
|
|
21
|
+
},
|
|
22
|
+
"dependencies": {
|
|
23
|
+
"express": "^4.21.0",
|
|
24
|
+
"@skipruntime/client": "^0.0.1",
|
|
25
|
+
"@skipruntime/api": "^0.0.1"
|
|
26
|
+
}
|
|
27
|
+
}
|
package/src/errors.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export class UnknownCollectionError extends Error {}
|
package/src/external.ts
ADDED
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
import type { Entry, ExternalService, TJSON } from "@skipruntime/api";
|
|
2
|
+
import { fetchJSON } from "./rest.js";
|
|
3
|
+
|
|
4
|
+
export interface ExternalResource {
|
|
5
|
+
open(
|
|
6
|
+
params: Record<string, string | number>,
|
|
7
|
+
callbacks: {
|
|
8
|
+
update: (updates: Entry<TJSON, TJSON>[], isInit: boolean) => void;
|
|
9
|
+
error: (error: TJSON) => void;
|
|
10
|
+
loading: () => void;
|
|
11
|
+
},
|
|
12
|
+
reactiveAuth?: Uint8Array,
|
|
13
|
+
): void;
|
|
14
|
+
|
|
15
|
+
close(
|
|
16
|
+
params: Record<string, string | number>,
|
|
17
|
+
reactiveAuth?: Uint8Array,
|
|
18
|
+
): void;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export class GenericExternalService implements ExternalService {
|
|
22
|
+
constructor(private resources: Record<string, ExternalResource>) {}
|
|
23
|
+
|
|
24
|
+
subscribe(
|
|
25
|
+
resourceName: string,
|
|
26
|
+
params: Record<string, string | number>,
|
|
27
|
+
callbacks: {
|
|
28
|
+
update: (updates: Entry<TJSON, TJSON>[], isInit: boolean) => void;
|
|
29
|
+
error: (error: TJSON) => void;
|
|
30
|
+
loading: () => void;
|
|
31
|
+
},
|
|
32
|
+
reactiveAuth?: Uint8Array,
|
|
33
|
+
): void {
|
|
34
|
+
const resource = this.resources[resourceName] as
|
|
35
|
+
| ExternalResource
|
|
36
|
+
| undefined;
|
|
37
|
+
if (!resource) {
|
|
38
|
+
throw new Error(`Unkonwn resource named '${resourceName}'`);
|
|
39
|
+
}
|
|
40
|
+
resource.open(params, callbacks, reactiveAuth);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
unsubscribe(
|
|
44
|
+
resourceName: string,
|
|
45
|
+
params: Record<string, string>,
|
|
46
|
+
reactiveAuth?: Uint8Array,
|
|
47
|
+
) {
|
|
48
|
+
const resource = this.resources[resourceName] as
|
|
49
|
+
| ExternalResource
|
|
50
|
+
| undefined;
|
|
51
|
+
if (!resource) {
|
|
52
|
+
throw new Error(`Unkonwn resource named '${resourceName}'`);
|
|
53
|
+
}
|
|
54
|
+
resource.close(params, reactiveAuth);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
shutdown(): void {
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
type Timeout = ReturnType<typeof setInterval>;
|
|
63
|
+
|
|
64
|
+
export class TimerResource implements ExternalResource {
|
|
65
|
+
private intervals = new Map<string, Record<string, Timeout>>();
|
|
66
|
+
|
|
67
|
+
open(
|
|
68
|
+
params: Record<string, string | number>,
|
|
69
|
+
callbacks: {
|
|
70
|
+
update: (updates: Entry<TJSON, TJSON>[], isInit: boolean) => void;
|
|
71
|
+
error: (error: TJSON) => void;
|
|
72
|
+
loading: () => void;
|
|
73
|
+
},
|
|
74
|
+
reactiveAuth?: Uint8Array,
|
|
75
|
+
) {
|
|
76
|
+
const time = new Date().getTime();
|
|
77
|
+
const values: Entry<string, number>[] = [];
|
|
78
|
+
for (const name of Object.keys(params)) {
|
|
79
|
+
values.push([name, [time]]);
|
|
80
|
+
}
|
|
81
|
+
callbacks.update(values, true);
|
|
82
|
+
const id = toId(params, reactiveAuth);
|
|
83
|
+
const intervals: Record<string, Timeout> = {};
|
|
84
|
+
for (const [name, duration] of Object.entries(params)) {
|
|
85
|
+
const ms = Number(duration);
|
|
86
|
+
if (ms > 0) {
|
|
87
|
+
intervals[name] = setInterval(() => {
|
|
88
|
+
const newvalue: Entry<TJSON, TJSON> = [name, [new Date().getTime()]];
|
|
89
|
+
callbacks.update([newvalue], true);
|
|
90
|
+
}, ms);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
this.intervals.set(id, intervals);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
close(
|
|
97
|
+
params: Record<string, string | number>,
|
|
98
|
+
reactiveAuth?: Uint8Array,
|
|
99
|
+
): void {
|
|
100
|
+
const intervals = this.intervals.get(toId(params, reactiveAuth));
|
|
101
|
+
if (intervals != null) {
|
|
102
|
+
for (const interval of Object.values(intervals)) {
|
|
103
|
+
clearInterval(interval);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export class Polled<S extends TJSON, K extends TJSON, V extends TJSON>
|
|
110
|
+
implements ExternalResource
|
|
111
|
+
{
|
|
112
|
+
private intervals = new Map<string, Timeout>();
|
|
113
|
+
|
|
114
|
+
constructor(
|
|
115
|
+
private url: string,
|
|
116
|
+
private duration: number,
|
|
117
|
+
private conv: (data: S) => Entry<K, V>[],
|
|
118
|
+
) {}
|
|
119
|
+
|
|
120
|
+
open(
|
|
121
|
+
params: Record<string, string | number>,
|
|
122
|
+
callbacks: {
|
|
123
|
+
update: (updates: Entry<TJSON, TJSON>[], isInit: boolean) => void;
|
|
124
|
+
error: (error: TJSON) => void;
|
|
125
|
+
loading: () => void;
|
|
126
|
+
},
|
|
127
|
+
reactiveAuth?: Uint8Array,
|
|
128
|
+
): void {
|
|
129
|
+
this.close(params, reactiveAuth);
|
|
130
|
+
const querieParams: Record<string, string> = {};
|
|
131
|
+
for (const [key, value] of Object.entries(params)) {
|
|
132
|
+
querieParams[key] = value.toString();
|
|
133
|
+
}
|
|
134
|
+
const strParams = new URLSearchParams(querieParams).toString();
|
|
135
|
+
const url = `${this.url}?${strParams}`;
|
|
136
|
+
const call = () => {
|
|
137
|
+
callbacks.loading();
|
|
138
|
+
fetchJSON(url, "GET", {})
|
|
139
|
+
.then((r) => {
|
|
140
|
+
callbacks.update(this.conv(r[0] as S), true);
|
|
141
|
+
})
|
|
142
|
+
.catch((e: unknown) => {
|
|
143
|
+
callbacks.error(e instanceof Error ? e.message : JSON.stringify(e));
|
|
144
|
+
console.error(e);
|
|
145
|
+
});
|
|
146
|
+
};
|
|
147
|
+
call();
|
|
148
|
+
this.intervals.set(
|
|
149
|
+
toId(params, reactiveAuth),
|
|
150
|
+
setInterval(call, this.duration),
|
|
151
|
+
);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
close(
|
|
155
|
+
params: Record<string, string | number>,
|
|
156
|
+
reactiveAuth?: Uint8Array,
|
|
157
|
+
): void {
|
|
158
|
+
const interval = this.intervals.get(toId(params, reactiveAuth));
|
|
159
|
+
if (interval) {
|
|
160
|
+
clearInterval(interval);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
function toId(
|
|
166
|
+
params: Record<string, string | number>,
|
|
167
|
+
reactiveAuth?: Uint8Array,
|
|
168
|
+
): string {
|
|
169
|
+
const strparams = Object.entries(params)
|
|
170
|
+
.map(([key, value]) => `${key}:${value.toString()}`)
|
|
171
|
+
.sort();
|
|
172
|
+
const hex = reactiveAuth ? Buffer.from(reactiveAuth).toString("hex") : "";
|
|
173
|
+
return `[${strparams.join(",")}]${hex}`;
|
|
174
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export { SkipExternalService } from "./remote.js";
|
|
2
|
+
export {
|
|
3
|
+
type ExternalResource,
|
|
4
|
+
GenericExternalService,
|
|
5
|
+
Polled,
|
|
6
|
+
} from "./external.js";
|
|
7
|
+
export {
|
|
8
|
+
Sum,
|
|
9
|
+
Min,
|
|
10
|
+
Max,
|
|
11
|
+
CountMapper,
|
|
12
|
+
parseReactiveResponse,
|
|
13
|
+
reactiveResponseHeader,
|
|
14
|
+
} from "./utils.js";
|
package/src/remote.ts
ADDED
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
Entry,
|
|
3
|
+
ExternalService,
|
|
4
|
+
ReactiveResponse,
|
|
5
|
+
TJSON,
|
|
6
|
+
} from "@skipruntime/api";
|
|
7
|
+
import { parseReactiveResponse } from "./utils.js";
|
|
8
|
+
|
|
9
|
+
import { connect, Protocol, Client } from "@skipruntime/client";
|
|
10
|
+
import { fetchJSON, type Entrypoint } from "./rest.js";
|
|
11
|
+
|
|
12
|
+
interface Closable {
|
|
13
|
+
close(): void;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export class SkipExternalService implements ExternalService {
|
|
17
|
+
private client?: Promise<[Client, Protocol.Creds]>;
|
|
18
|
+
private resources = new Map<string, Closable>();
|
|
19
|
+
|
|
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
|
+
) {}
|
|
29
|
+
|
|
30
|
+
static fromEntrypoint(
|
|
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 {
|
|
49
|
+
let url = `http://${entrypoint.host}:${entrypoint.port.toString()}`;
|
|
50
|
+
if (entrypoint.secured)
|
|
51
|
+
url = `https://${entrypoint.host}:${entrypoint.port.toString()}`;
|
|
52
|
+
const auth = async (
|
|
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);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
subscribe(
|
|
75
|
+
resource: string,
|
|
76
|
+
params: Record<string, string>,
|
|
77
|
+
callbacks: {
|
|
78
|
+
update: (updates: Entry<TJSON, TJSON>[], isInit: boolean) => void;
|
|
79
|
+
error: (error: TJSON) => void;
|
|
80
|
+
loading: () => void;
|
|
81
|
+
},
|
|
82
|
+
reactiveAuth?: Uint8Array,
|
|
83
|
+
): void {
|
|
84
|
+
if (!this.client) {
|
|
85
|
+
if (!this.creds) {
|
|
86
|
+
this.client = Protocol.generateCredentials().then((creds) => {
|
|
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
|
+
},
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
unsubscribe(
|
|
104
|
+
resource: string,
|
|
105
|
+
params: Record<string, string>,
|
|
106
|
+
reactiveAuth?: Uint8Array,
|
|
107
|
+
) {
|
|
108
|
+
const closable = this.resources.get(
|
|
109
|
+
this.toId(resource, params, reactiveAuth),
|
|
110
|
+
);
|
|
111
|
+
if (closable) closable.close();
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
shutdown(): void {
|
|
115
|
+
if (this.client) {
|
|
116
|
+
this.client
|
|
117
|
+
.then((client) => {
|
|
118
|
+
client[0].close();
|
|
119
|
+
})
|
|
120
|
+
.catch((e: unknown) => console.error(e));
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
private async subscribe_(
|
|
125
|
+
resource: string,
|
|
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 {
|
|
151
|
+
const strparams: string[] = [];
|
|
152
|
+
for (const key of Object.keys(params).sort()) {
|
|
153
|
+
strparams.push(`${key}:${params[key]}`);
|
|
154
|
+
}
|
|
155
|
+
const hex = reactiveAuth ? Buffer.from(reactiveAuth).toString("hex") : "";
|
|
156
|
+
return `${resource}[${strparams.join(",")}]${hex}`;
|
|
157
|
+
}
|
|
158
|
+
}
|
package/src/rest.ts
ADDED
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import type { TJSON, Entry, ReactiveResponse } from "@skipruntime/api";
|
|
2
|
+
import { parseReactiveResponse } from "./utils.js";
|
|
3
|
+
|
|
4
|
+
export type Entrypoint = {
|
|
5
|
+
host: string;
|
|
6
|
+
port: number;
|
|
7
|
+
secured?: boolean;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
function toHttp(entrypoint: Entrypoint) {
|
|
11
|
+
if (entrypoint.secured)
|
|
12
|
+
return `https://${entrypoint.host}:${entrypoint.port}`;
|
|
13
|
+
return `http://${entrypoint.host}:${entrypoint.port}`;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export async function fetchJSON<V>(
|
|
17
|
+
url: string,
|
|
18
|
+
method: "POST" | "GET" | "PUT" | "PATCH" | "HEAD" | "DELETE" = "GET",
|
|
19
|
+
headers: Record<string, string> = {},
|
|
20
|
+
data?: TJSON,
|
|
21
|
+
): Promise<[V | null, Headers]> {
|
|
22
|
+
const body = data ? JSON.stringify(data) : undefined;
|
|
23
|
+
const response = await fetch(url, {
|
|
24
|
+
method,
|
|
25
|
+
body,
|
|
26
|
+
headers: {
|
|
27
|
+
"Content-Type": "application/json",
|
|
28
|
+
Accept: "application/json",
|
|
29
|
+
...headers,
|
|
30
|
+
},
|
|
31
|
+
signal: AbortSignal.timeout(1000),
|
|
32
|
+
});
|
|
33
|
+
if (!response.ok) {
|
|
34
|
+
throw new Error(`${response.status}: ${response.statusText}`);
|
|
35
|
+
}
|
|
36
|
+
const responseText = await response.text();
|
|
37
|
+
const responseJSON =
|
|
38
|
+
responseText.length > 0 && responseText != response.statusText
|
|
39
|
+
? JSON.parse(responseText)
|
|
40
|
+
: null;
|
|
41
|
+
return [responseJSON, response.headers];
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export class SkipRESTService {
|
|
45
|
+
private entrypoint: string;
|
|
46
|
+
|
|
47
|
+
constructor(
|
|
48
|
+
entrypoint: Entrypoint = {
|
|
49
|
+
host: "localhost",
|
|
50
|
+
port: 3587,
|
|
51
|
+
},
|
|
52
|
+
) {
|
|
53
|
+
this.entrypoint = toHttp(entrypoint);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
async getAll<K extends TJSON, V extends TJSON>(
|
|
57
|
+
resource: string,
|
|
58
|
+
params: Record<string, string>,
|
|
59
|
+
reactiveAuth?: Uint8Array | string,
|
|
60
|
+
): Promise<{ values: Entry<K, V>[]; reactive?: ReactiveResponse }> {
|
|
61
|
+
const qParams = new URLSearchParams(params).toString();
|
|
62
|
+
let header = {};
|
|
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>[]>(
|
|
77
|
+
`${this.entrypoint}/v1/${resource}?${qParams}`,
|
|
78
|
+
"GET",
|
|
79
|
+
header,
|
|
80
|
+
);
|
|
81
|
+
const reactive = parseReactiveResponse(headers);
|
|
82
|
+
const values = optValues ?? [];
|
|
83
|
+
return reactive ? { values, reactive } : { values };
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
async head(
|
|
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>(
|
|
107
|
+
resource: string,
|
|
108
|
+
params: Record<string, string>,
|
|
109
|
+
key: string,
|
|
110
|
+
reactiveAuth?: Uint8Array | string,
|
|
111
|
+
): Promise<V[]> {
|
|
112
|
+
const qParams = new URLSearchParams(params).toString();
|
|
113
|
+
const header = this.header(reactiveAuth);
|
|
114
|
+
const [data, _headers] = await fetchJSON<V[]>(
|
|
115
|
+
`${this.entrypoint}/v1/${resource}/${key}?${qParams}`,
|
|
116
|
+
"GET",
|
|
117
|
+
header,
|
|
118
|
+
);
|
|
119
|
+
return data ?? [];
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
async put<V extends TJSON>(
|
|
123
|
+
collection: string,
|
|
124
|
+
key: string,
|
|
125
|
+
value: V[],
|
|
126
|
+
): Promise<void> {
|
|
127
|
+
await fetchJSON(
|
|
128
|
+
`${this.entrypoint}/v1/${collection}/${key}`,
|
|
129
|
+
"PUT",
|
|
130
|
+
{},
|
|
131
|
+
value,
|
|
132
|
+
);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
async patch<K extends TJSON, V extends TJSON>(
|
|
136
|
+
collection: string,
|
|
137
|
+
values: Entry<K, V>[],
|
|
138
|
+
): Promise<void> {
|
|
139
|
+
await fetchJSON(`${this.entrypoint}/v1/${collection}`, "PATCH", {}, values);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
async deleteKey(collection: string, key: string): Promise<void> {
|
|
143
|
+
await fetchJSON(`${this.entrypoint}/v1/${collection}/${key}`, "DELETE", {});
|
|
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 {};
|
|
161
|
+
}
|
|
162
|
+
}
|
package/src/utils.ts
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import type { Opt } from "@skip-wasm/std";
|
|
2
|
+
import { ManyToOneMapper } from "@skipruntime/api";
|
|
3
|
+
import type {
|
|
4
|
+
Accumulator,
|
|
5
|
+
NonEmptyIterator,
|
|
6
|
+
ReactiveResponse,
|
|
7
|
+
TJSON,
|
|
8
|
+
} from "@skipruntime/api";
|
|
9
|
+
|
|
10
|
+
export class Sum implements Accumulator<number, number> {
|
|
11
|
+
default = 0;
|
|
12
|
+
|
|
13
|
+
accumulate(acc: number, value: number): number {
|
|
14
|
+
return acc + value;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
dismiss(acc: number, value: number): Opt<number> {
|
|
18
|
+
return acc - value;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export class Min implements Accumulator<number, number> {
|
|
23
|
+
default = null;
|
|
24
|
+
|
|
25
|
+
accumulate(acc: Opt<number>, value: number): number {
|
|
26
|
+
return acc === null ? value : Math.min(acc, value);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
dismiss(acc: number, value: number): Opt<number> {
|
|
30
|
+
return value > acc ? acc : null;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export class Max implements Accumulator<number, number> {
|
|
35
|
+
default = null;
|
|
36
|
+
|
|
37
|
+
accumulate(acc: Opt<number>, value: number): number {
|
|
38
|
+
return acc === null ? value : Math.max(acc, value);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
dismiss(acc: number, value: number): Opt<number> {
|
|
42
|
+
return value < acc ? acc : null;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export class CountMapper<
|
|
47
|
+
K extends TJSON,
|
|
48
|
+
V extends TJSON,
|
|
49
|
+
> extends ManyToOneMapper<K, V, number> {
|
|
50
|
+
mapValues(values: NonEmptyIterator<V>): number {
|
|
51
|
+
return values.toArray().length;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function parseReactiveResponse(
|
|
56
|
+
header: Headers | string,
|
|
57
|
+
): ReactiveResponse | undefined {
|
|
58
|
+
const strReactiveResponse =
|
|
59
|
+
typeof header == "string"
|
|
60
|
+
? header
|
|
61
|
+
: header.get("Skip-Reactive-Response-Token");
|
|
62
|
+
if (!strReactiveResponse) return undefined;
|
|
63
|
+
return JSON.parse(strReactiveResponse, (key: string, value: string) => {
|
|
64
|
+
if (key == "watermark") return BigInt(value);
|
|
65
|
+
return value;
|
|
66
|
+
}) as ReactiveResponse;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export function reactiveResponseHeader(
|
|
70
|
+
reactiveResponse: ReactiveResponse,
|
|
71
|
+
): [string, string] {
|
|
72
|
+
return [
|
|
73
|
+
"Skip-Reactive-Response-Token",
|
|
74
|
+
JSON.stringify(reactiveResponse, (_key: string, value: unknown) =>
|
|
75
|
+
typeof value === "bigint" ? value.toString() : value,
|
|
76
|
+
),
|
|
77
|
+
];
|
|
78
|
+
}
|
package/tsconfig.json
ADDED