@aloma.io/integration-sdk 3.3.64 → 3.3.66
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/build/builder/runtime-context.mjs +2 -2
- package/build/builder/transform/index.mjs +7 -10
- package/build/controller/index.d.mts +1 -1
- package/build/controller/index.mjs +1 -1
- package/build/internal/dispatcher/index.mjs +3 -3
- package/build/internal/index.mjs +33 -18
- package/build/internal/websocket/config.d.mts +1 -1
- package/build/internal/websocket/config.mjs +1 -1
- package/build/internal/websocket/connection/registration.mjs +1 -1
- package/build/internal/websocket/transport/index.mjs +10 -0
- package/package.json +1 -1
- package/src/builder/index.mts +4 -4
- package/src/builder/runtime-context.mts +13 -13
- package/src/builder/transform/index.mts +23 -20
- package/src/controller/index.mts +7 -1
- package/src/internal/dispatcher/index.mjs +5 -5
- package/src/internal/index.mjs +91 -69
- package/src/internal/websocket/config.mjs +2 -2
- package/src/internal/websocket/connection/registration.mjs +2 -2
- package/src/internal/websocket/transport/index.mjs +11 -0
@@ -16,7 +16,7 @@ export default class RuntimeContext {
|
|
16
16
|
let icon;
|
17
17
|
try {
|
18
18
|
if (data.icon) {
|
19
|
-
icon = fs.readFileSync(data.icon).toString(
|
19
|
+
icon = fs.readFileSync(data.icon).toString("base64");
|
20
20
|
}
|
21
21
|
}
|
22
22
|
catch (e) {
|
@@ -26,7 +26,7 @@ export default class RuntimeContext {
|
|
26
26
|
id: data.id,
|
27
27
|
version: data.version,
|
28
28
|
name: `${data.id}/${data.version}`,
|
29
|
-
icon
|
29
|
+
icon,
|
30
30
|
});
|
31
31
|
const configuration = connector.configure().config(data.config || {});
|
32
32
|
const resolvers = {};
|
@@ -29,11 +29,10 @@ const transform = (meta) => {
|
|
29
29
|
let eg;
|
30
30
|
if (example) {
|
31
31
|
const parts = example.split(/```/);
|
32
|
-
const backticks =
|
33
|
-
eg = `@example ${parts[0] ||
|
32
|
+
const backticks = "```";
|
33
|
+
eg = `@example ${parts[0] || "usage"}\n${backticks}${parts[1]}${backticks}`;
|
34
34
|
}
|
35
|
-
const paramDocs = docs
|
36
|
-
.filter((what) => what.kind === "param");
|
35
|
+
const paramDocs = docs.filter((what) => what.kind === "param");
|
37
36
|
const params = sig
|
38
37
|
.getParameters()
|
39
38
|
.filter((param) => param.isNamed())
|
@@ -46,12 +45,10 @@ const transform = (meta) => {
|
|
46
45
|
return `${p.getName()}${defaultVal}`;
|
47
46
|
})
|
48
47
|
.join("; ");
|
49
|
-
const suffix = serialized
|
50
|
-
.type
|
51
|
-
.properties
|
48
|
+
const suffix = serialized.type.properties
|
52
49
|
.map((p) => {
|
53
50
|
const comment = paramDocs.find((what) => what.value.name === p.name);
|
54
|
-
const desc = (comment?.value.description ||
|
51
|
+
const desc = (comment?.value.description || "").replace(/\\@/gi, "@");
|
55
52
|
return `\n/**\n${desc}\n */\n ${p.name}: ${p.type.text}`;
|
56
53
|
})
|
57
54
|
.join("; ");
|
@@ -66,7 +63,7 @@ const transform = (meta) => {
|
|
66
63
|
/**
|
67
64
|
* ${desc || ""}
|
68
65
|
*
|
69
|
-
* ${eg ||
|
66
|
+
* ${eg || ""}
|
70
67
|
**/
|
71
68
|
declare function ${member.getName()}(${params}): ${retVal};
|
72
69
|
`;
|
@@ -79,6 +76,6 @@ declare function ${member.getName()}(${params}): ${retVal};
|
|
79
76
|
export default async (path) => {
|
80
77
|
const parsed = await parseFromFiles([path]);
|
81
78
|
if (parsed.errors?.length)
|
82
|
-
throw new Error(path +
|
79
|
+
throw new Error(path + " " + JSON.stringify(parsed.errors));
|
83
80
|
return transform(parsed.project?.getModules() || []);
|
84
81
|
};
|
@@ -7,7 +7,7 @@ export declare abstract class AbstractController {
|
|
7
7
|
protected fallback(arg: any): Promise<any>;
|
8
8
|
protected endpoint(arg: any): Promise<any>;
|
9
9
|
protected newTask(name: string, data: any): Promise<string>;
|
10
|
-
protected getClient({ baseUrl, onResponse }: {
|
10
|
+
protected getClient({ baseUrl, onResponse, }: {
|
11
11
|
baseUrl: string;
|
12
12
|
onResponse?: (response: any) => void;
|
13
13
|
}): Promise<any>;
|
@@ -15,7 +15,7 @@ export class AbstractController {
|
|
15
15
|
async newTask(name, data) {
|
16
16
|
throw new Error("not implemented");
|
17
17
|
}
|
18
|
-
getClient({ baseUrl, onResponse }) {
|
18
|
+
getClient({ baseUrl, onResponse, }) {
|
19
19
|
throw new Error("not implemented");
|
20
20
|
}
|
21
21
|
async updateTask(name, data) {
|
@@ -44,7 +44,7 @@ class Dispatcher {
|
|
44
44
|
placeholder: "e.g. 1234",
|
45
45
|
type: "line",
|
46
46
|
optional: !!arg.configurableClientOptional,
|
47
|
-
plain: true
|
47
|
+
plain: true,
|
48
48
|
},
|
49
49
|
clientSecret: {
|
50
50
|
name: "OAuth Client Secret",
|
@@ -67,8 +67,8 @@ class Dispatcher {
|
|
67
67
|
${arg.configurableClientScope}
|
68
68
|
`,
|
69
69
|
optional: true,
|
70
|
-
plain: true
|
71
|
-
}
|
70
|
+
plain: true,
|
71
|
+
},
|
72
72
|
},
|
73
73
|
});
|
74
74
|
}
|
package/build/internal/index.mjs
CHANGED
@@ -38,7 +38,7 @@ const unwrap = async (ret, options) => {
|
|
38
38
|
return JSON.parse(text);
|
39
39
|
}
|
40
40
|
catch (e) {
|
41
|
-
throw
|
41
|
+
throw e + " " + text;
|
42
42
|
}
|
43
43
|
};
|
44
44
|
class Fetcher {
|
@@ -48,7 +48,7 @@ class Fetcher {
|
|
48
48
|
this.onResponse = onResponse;
|
49
49
|
}
|
50
50
|
async customize(options, args = {}) { }
|
51
|
-
async onError(e, url, options, retries, args) {
|
51
|
+
async onError(e, url, options, retries, args, rateLimit) {
|
52
52
|
var local = this;
|
53
53
|
return new Promise((resolve, reject) => {
|
54
54
|
setTimeout(async () => {
|
@@ -58,7 +58,7 @@ class Fetcher {
|
|
58
58
|
catch (e) {
|
59
59
|
reject(e);
|
60
60
|
}
|
61
|
-
}, 500);
|
61
|
+
}, rateLimit ? 10000 : 500);
|
62
62
|
});
|
63
63
|
}
|
64
64
|
async fetch(url, options = {}, retries, args = {}) {
|
@@ -125,15 +125,22 @@ class OAuthFetcher extends Fetcher {
|
|
125
125
|
if (!force && oauth.accessToken())
|
126
126
|
return oauth.accessToken();
|
127
127
|
const refreshToken = oauth.refreshToken();
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
oauth.
|
133
|
-
|
128
|
+
try {
|
129
|
+
if (!refreshToken) {
|
130
|
+
throw new Error("have no access_token and no refresh_token");
|
131
|
+
}
|
132
|
+
const ret = await oauth.obtainViaRefreshToken(oauth.refreshToken());
|
133
|
+
if (ret.access_token) {
|
134
|
+
oauth.update(ret.access_token, ret.refresh_token);
|
135
|
+
return ret.access_token;
|
136
|
+
}
|
137
|
+
else {
|
138
|
+
throw new Error("could not obtain access token via refresh token");
|
139
|
+
}
|
134
140
|
}
|
135
|
-
|
136
|
-
|
141
|
+
catch (e) {
|
142
|
+
oauth.invalidate(e);
|
143
|
+
throw (e);
|
137
144
|
}
|
138
145
|
}
|
139
146
|
async onError(e, url, options, retries, args, rateLimit) {
|
@@ -192,12 +199,16 @@ class OAuth {
|
|
192
199
|
}
|
193
200
|
async periodicRefresh() {
|
194
201
|
const clients = this.clients;
|
195
|
-
console.log(
|
202
|
+
console.log("refreshing oauth clients", clients.length);
|
196
203
|
for (let i = 0; i < clients.length; ++i) {
|
197
204
|
const client = clients[0];
|
198
205
|
await client.periodicRefresh();
|
199
206
|
}
|
200
207
|
}
|
208
|
+
async invalidate(err) {
|
209
|
+
console.log('could not obtain access token, marking connector as disconnected', err);
|
210
|
+
await this.upate(null, null);
|
211
|
+
}
|
201
212
|
getClient(arg = {}) {
|
202
213
|
const client = new OAuthFetcher({ ...arg, oauth: this });
|
203
214
|
this.clients.push(client);
|
@@ -251,7 +262,7 @@ class Connector {
|
|
251
262
|
publicKey: process.env.PUBLIC_KEY,
|
252
263
|
introspect,
|
253
264
|
configSchema,
|
254
|
-
icon: this.icon
|
265
|
+
icon: this.icon,
|
255
266
|
});
|
256
267
|
if (Object.keys(configSchema().fields).length) {
|
257
268
|
try {
|
@@ -293,7 +304,7 @@ ${text}
|
|
293
304
|
const value = secrets[key];
|
294
305
|
if (!value)
|
295
306
|
continue;
|
296
|
-
if (fields[key]?.plain || [
|
307
|
+
if (fields[key]?.plain || ["endpointUrl"].includes(key)) {
|
297
308
|
decrypted[key] = value;
|
298
309
|
}
|
299
310
|
else {
|
@@ -338,7 +349,6 @@ ${text}
|
|
338
349
|
const clientId = process.env.OAUTH_CLIENT_ID ||
|
339
350
|
decrypted.clientId ||
|
340
351
|
that._oauth.clientId;
|
341
|
-
;
|
342
352
|
if (!clientId)
|
343
353
|
throw new Error("clientId not configured");
|
344
354
|
const clientSecret = process.env.OAUTH_CLIENT_SECRET ||
|
@@ -411,11 +421,16 @@ ${text}
|
|
411
421
|
return { value: await jwe.encrypt(data, "none", config.id()) };
|
412
422
|
};
|
413
423
|
const saveOAuthResult = async (what) => {
|
414
|
-
|
424
|
+
let value = null;
|
425
|
+
if (what) {
|
426
|
+
const jwe = await config.validateKeys("RSA-OAEP-256");
|
427
|
+
value = await jwe.encrypt(what, "none", config.id());
|
428
|
+
}
|
429
|
+
;
|
415
430
|
const packet = transport.newPacket({});
|
416
431
|
packet.method("connector.config-update");
|
417
432
|
packet.args({
|
418
|
-
value
|
433
|
+
value
|
419
434
|
});
|
420
435
|
transport.send(packet);
|
421
436
|
};
|
@@ -473,7 +488,7 @@ ${text}
|
|
473
488
|
await theOAuth.periodicRefresh();
|
474
489
|
}
|
475
490
|
catch (e) {
|
476
|
-
console.log(
|
491
|
+
console.log("periodic refresh", e);
|
477
492
|
}
|
478
493
|
}, 4 * 60 * 60 * 15000);
|
479
494
|
}
|
@@ -1,5 +1,5 @@
|
|
1
1
|
export class Config {
|
2
|
-
constructor({ registrationToken, version, name, id, endpoint, wsEndpoint, privateKey, publicKey, introspect, configSchema, icon }: {
|
2
|
+
constructor({ registrationToken, version, name, id, endpoint, wsEndpoint, privateKey, publicKey, introspect, configSchema, icon, }: {
|
3
3
|
registrationToken: any;
|
4
4
|
version: any;
|
5
5
|
name: any;
|
@@ -1,7 +1,7 @@
|
|
1
1
|
import C from "./connection/constants.mjs";
|
2
2
|
import JWE from "../util/jwe/index.mjs";
|
3
3
|
class Config {
|
4
|
-
constructor({ registrationToken, version, name, id, endpoint, wsEndpoint, privateKey, publicKey, introspect, configSchema, icon }) {
|
4
|
+
constructor({ registrationToken, version, name, id, endpoint, wsEndpoint, privateKey, publicKey, introspect, configSchema, icon, }) {
|
5
5
|
this._token = null;
|
6
6
|
this._registrationToken = registrationToken;
|
7
7
|
this._version = version;
|
@@ -47,15 +47,25 @@ class Transport {
|
|
47
47
|
local.close();
|
48
48
|
this.running = true;
|
49
49
|
const ws = (local.ws = new WebSocket(config.wsUrl(), ["connector"], C.augmentRequest({ headers: {} }, config)));
|
50
|
+
ws.onPing = function () {
|
51
|
+
clearTimeout(this.pingTimeout);
|
52
|
+
this.pingTimeout = setTimeout(() => {
|
53
|
+
console.log("terminating ws");
|
54
|
+
if (local.running)
|
55
|
+
this.terminate();
|
56
|
+
}, 30000 + 15000);
|
57
|
+
};
|
50
58
|
ws.on("open", () => {
|
51
59
|
console.log("websocket connected");
|
52
60
|
local.connected = true;
|
61
|
+
ws.onPing();
|
53
62
|
local.pinger = setInterval(() => ws.ping(() => null), pingInterval);
|
54
63
|
local.onConnect(local);
|
55
64
|
});
|
56
65
|
ws.on("message", (message) => {
|
57
66
|
setTimeout(() => local.onMessages(JSON.parse(message)), 0);
|
58
67
|
});
|
68
|
+
ws.on("ping", () => ws.onPing());
|
59
69
|
ws.on("error", (message) => {
|
60
70
|
console.log("error:", message);
|
61
71
|
});
|
package/package.json
CHANGED
package/src/builder/index.mts
CHANGED
@@ -38,7 +38,7 @@ export class Builder {
|
|
38
38
|
await this.parsePackageJson();
|
39
39
|
await this.discoverTypes();
|
40
40
|
await this.checkIcon();
|
41
|
-
|
41
|
+
|
42
42
|
// @ts-ignore
|
43
43
|
const Controller = (
|
44
44
|
await import(__dirname + "/../../../../../build/controller/index.mjs")
|
@@ -46,11 +46,11 @@ export class Builder {
|
|
46
46
|
|
47
47
|
return new RuntimeContext(new Controller(), this.data);
|
48
48
|
}
|
49
|
-
|
49
|
+
|
50
50
|
private async checkIcon() {
|
51
51
|
const data = this.data;
|
52
|
-
const root = __dirname + "/../../../../../"
|
53
|
-
|
52
|
+
const root = __dirname + "/../../../../../";
|
53
|
+
|
54
54
|
data.icon = `${root}/logo.png`;
|
55
55
|
}
|
56
56
|
|
@@ -1,7 +1,7 @@
|
|
1
1
|
import { AbstractController } from "../controller/index.mjs";
|
2
2
|
import { Connector } from "../internal/index.mjs";
|
3
3
|
import fs from "node:fs";
|
4
|
-
|
4
|
+
|
5
5
|
export default class RuntimeContext {
|
6
6
|
constructor(
|
7
7
|
private controller: AbstractController,
|
@@ -14,25 +14,22 @@ export default class RuntimeContext {
|
|
14
14
|
if (!(controller instanceof AbstractController))
|
15
15
|
throw new Error("the controller needs to extend AbstractController");
|
16
16
|
const data: any = this.data;
|
17
|
-
|
17
|
+
|
18
18
|
let icon;
|
19
|
-
|
20
|
-
try
|
21
|
-
|
22
|
-
|
23
|
-
{
|
24
|
-
icon = fs.readFileSync(data.icon).toString('base64');
|
19
|
+
|
20
|
+
try {
|
21
|
+
if (data.icon) {
|
22
|
+
icon = fs.readFileSync(data.icon).toString("base64");
|
25
23
|
}
|
26
|
-
} catch(e) {
|
24
|
+
} catch (e) {
|
27
25
|
// blank
|
28
26
|
}
|
29
|
-
|
30
27
|
|
31
28
|
const connector = new Connector({
|
32
29
|
id: data.id,
|
33
30
|
version: data.version,
|
34
31
|
name: `${data.id}/${data.version}`,
|
35
|
-
icon
|
32
|
+
icon,
|
36
33
|
});
|
37
34
|
|
38
35
|
const configuration = connector.configure().config(data.config || {});
|
@@ -56,7 +53,10 @@ export default class RuntimeContext {
|
|
56
53
|
configuration.types(data.types).resolvers(resolvers);
|
57
54
|
|
58
55
|
if (data.options?.endpoint?.enabled) {
|
59
|
-
configuration.endpoint(
|
56
|
+
configuration.endpoint(
|
57
|
+
(arg) => controller.__endpoint(arg),
|
58
|
+
data.options?.endpoint?.required,
|
59
|
+
);
|
60
60
|
}
|
61
61
|
|
62
62
|
if (data.auth?.oauth) {
|
@@ -81,7 +81,7 @@ export default class RuntimeContext {
|
|
81
81
|
);
|
82
82
|
|
83
83
|
connector.run();
|
84
|
-
|
84
|
+
|
85
85
|
const term = async () => {
|
86
86
|
await controller._doStop(true);
|
87
87
|
|
@@ -31,21 +31,20 @@ const transform = (meta: any) => {
|
|
31
31
|
const docs = sig.getJSDoc().serialize() || [];
|
32
32
|
const desc = docs.find((what: any) => what.kind === "description")
|
33
33
|
?.value;
|
34
|
-
|
34
|
+
|
35
35
|
const example = docs.find((what: any) => what.kind === "example")
|
36
36
|
?.value;
|
37
37
|
|
38
38
|
let eg;
|
39
|
-
if (example)
|
40
|
-
{
|
39
|
+
if (example) {
|
41
40
|
const parts = example.split(/```/);
|
42
|
-
const backticks =
|
43
|
-
eg = `@example ${parts[0] ||
|
41
|
+
const backticks = "```";
|
42
|
+
eg = `@example ${parts[0] || "usage"}\n${backticks}${
|
43
|
+
parts[1]
|
44
|
+
}${backticks}`;
|
44
45
|
}
|
45
|
-
|
46
|
-
const paramDocs =
|
47
|
-
docs
|
48
|
-
.filter((what: any) => what.kind === "param")
|
46
|
+
|
47
|
+
const paramDocs = docs.filter((what: any) => what.kind === "param");
|
49
48
|
|
50
49
|
const params = sig
|
51
50
|
.getParameters()
|
@@ -62,22 +61,25 @@ const transform = (meta: any) => {
|
|
62
61
|
return `${p.getName()}${defaultVal}`;
|
63
62
|
})
|
64
63
|
.join("; ");
|
65
|
-
|
66
|
-
const suffix = serialized
|
67
|
-
.type
|
68
|
-
.properties
|
64
|
+
|
65
|
+
const suffix = serialized.type.properties
|
69
66
|
.map((p) => {
|
70
|
-
const comment = paramDocs.find(
|
71
|
-
|
72
|
-
|
67
|
+
const comment = paramDocs.find(
|
68
|
+
(what) => what.value.name === p.name,
|
69
|
+
);
|
70
|
+
const desc = (comment?.value.description || "").replace(
|
71
|
+
/\\@/gi,
|
72
|
+
"@",
|
73
|
+
);
|
74
|
+
|
73
75
|
return `\n/**\n${desc}\n */\n ${p.name}: ${p.type.text}`;
|
74
76
|
})
|
75
77
|
.join("; ");
|
76
|
-
|
78
|
+
|
77
79
|
return `{${prefix}}: {${suffix}}`;
|
78
80
|
})
|
79
81
|
.join(", ");
|
80
|
-
|
82
|
+
|
81
83
|
const retVal = sig
|
82
84
|
.serialize()
|
83
85
|
.return.type.text.replace(/^Promise</, "")
|
@@ -87,7 +89,7 @@ const transform = (meta: any) => {
|
|
87
89
|
/**
|
88
90
|
* ${desc || ""}
|
89
91
|
*
|
90
|
-
* ${eg ||
|
92
|
+
* ${eg || ""}
|
91
93
|
**/
|
92
94
|
declare function ${member.getName()}(${params}): ${retVal};
|
93
95
|
`;
|
@@ -101,6 +103,7 @@ declare function ${member.getName()}(${params}): ${retVal};
|
|
101
103
|
|
102
104
|
export default async (path: string) => {
|
103
105
|
const parsed = await parseFromFiles([path]);
|
104
|
-
if (parsed.errors?.length)
|
106
|
+
if (parsed.errors?.length)
|
107
|
+
throw new Error(path + " " + JSON.stringify(parsed.errors));
|
105
108
|
return transform(parsed.project?.getModules() || []);
|
106
109
|
};
|
package/src/controller/index.mts
CHANGED
@@ -22,7 +22,13 @@ export abstract class AbstractController {
|
|
22
22
|
throw new Error("not implemented");
|
23
23
|
}
|
24
24
|
|
25
|
-
protected getClient({
|
25
|
+
protected getClient({
|
26
|
+
baseUrl,
|
27
|
+
onResponse,
|
28
|
+
}: {
|
29
|
+
baseUrl: string;
|
30
|
+
onResponse?: (response: any) => void;
|
31
|
+
}): Promise<any> {
|
26
32
|
throw new Error("not implemented");
|
27
33
|
}
|
28
34
|
|
@@ -51,7 +51,7 @@ class Dispatcher {
|
|
51
51
|
placeholder: "e.g. 1234",
|
52
52
|
type: "line",
|
53
53
|
optional: !!arg.configurableClientOptional,
|
54
|
-
plain: true
|
54
|
+
plain: true,
|
55
55
|
},
|
56
56
|
clientSecret: {
|
57
57
|
name: "OAuth Client Secret",
|
@@ -62,7 +62,7 @@ class Dispatcher {
|
|
62
62
|
},
|
63
63
|
});
|
64
64
|
}
|
65
|
-
|
65
|
+
|
66
66
|
if (arg.configurableClientScope) {
|
67
67
|
this.config({
|
68
68
|
fields: {
|
@@ -75,8 +75,8 @@ class Dispatcher {
|
|
75
75
|
${arg.configurableClientScope}
|
76
76
|
`,
|
77
77
|
optional: true,
|
78
|
-
plain: true
|
79
|
-
}
|
78
|
+
plain: true,
|
79
|
+
},
|
80
80
|
},
|
81
81
|
});
|
82
82
|
}
|
@@ -111,7 +111,7 @@ ${arg.configurableClientScope}
|
|
111
111
|
_endpointToken: {
|
112
112
|
name: "Endpoint Token",
|
113
113
|
placeholder: "e.g. 1234",
|
114
|
-
type: !!notOptional?"managed":"line",
|
114
|
+
type: !!notOptional ? "managed" : "line",
|
115
115
|
plain: true,
|
116
116
|
optional: !notOptional,
|
117
117
|
},
|
package/src/internal/index.mjs
CHANGED
@@ -40,14 +40,13 @@ const reply = (arg, packet, transport) => {
|
|
40
40
|
const unwrap = async (ret, options) => {
|
41
41
|
if (options?.text) return await ret.text();
|
42
42
|
if (options?.base64) return (await ret.buffer()).toString("base64");
|
43
|
-
|
43
|
+
|
44
44
|
const text = await ret.text();
|
45
|
-
|
46
|
-
try
|
47
|
-
{
|
45
|
+
|
46
|
+
try {
|
48
47
|
return JSON.parse(text);
|
49
|
-
} catch(e) {
|
50
|
-
throw
|
48
|
+
} catch (e) {
|
49
|
+
throw e + " " + text;
|
51
50
|
}
|
52
51
|
};
|
53
52
|
|
@@ -60,7 +59,7 @@ class Fetcher {
|
|
60
59
|
|
61
60
|
async customize(options, args = {}) {}
|
62
61
|
|
63
|
-
async onError(e, url, options, retries, args) {
|
62
|
+
async onError(e, url, options, retries, args, rateLimit) {
|
64
63
|
var local = this;
|
65
64
|
|
66
65
|
return new Promise((resolve, reject) => {
|
@@ -70,7 +69,7 @@ class Fetcher {
|
|
70
69
|
} catch (e) {
|
71
70
|
reject(e);
|
72
71
|
}
|
73
|
-
}, 500);
|
72
|
+
}, rateLimit?10000:500);
|
74
73
|
});
|
75
74
|
}
|
76
75
|
|
@@ -120,9 +119,8 @@ class Fetcher {
|
|
120
119
|
e.status = status;
|
121
120
|
throw e;
|
122
121
|
}
|
123
|
-
|
124
|
-
if (local.onResponse)
|
125
|
-
{
|
122
|
+
|
123
|
+
if (local.onResponse) {
|
126
124
|
await local.onResponse(ret);
|
127
125
|
}
|
128
126
|
|
@@ -130,9 +128,9 @@ class Fetcher {
|
|
130
128
|
} catch (e) {
|
131
129
|
// too many requests
|
132
130
|
if (e.status === 429) {
|
133
|
-
|
131
|
+
return local.onError(e, url, options, retries, args, true);
|
134
132
|
}
|
135
|
-
|
133
|
+
|
136
134
|
--retries;
|
137
135
|
|
138
136
|
console.log(theURL, e);
|
@@ -161,17 +159,26 @@ class OAuthFetcher extends Fetcher {
|
|
161
159
|
if (!force && oauth.accessToken()) return oauth.accessToken();
|
162
160
|
|
163
161
|
const refreshToken = oauth.refreshToken();
|
164
|
-
|
165
|
-
|
162
|
+
|
163
|
+
try
|
164
|
+
{
|
165
|
+
if (!refreshToken) {
|
166
|
+
throw new Error("have no access_token and no refresh_token");
|
167
|
+
}
|
166
168
|
|
167
|
-
|
169
|
+
const ret = await oauth.obtainViaRefreshToken(oauth.refreshToken());
|
168
170
|
|
169
|
-
|
170
|
-
|
171
|
+
if (ret.access_token) {
|
172
|
+
oauth.update(ret.access_token, ret.refresh_token);
|
171
173
|
|
172
|
-
|
173
|
-
|
174
|
-
|
174
|
+
return ret.access_token;
|
175
|
+
} else {
|
176
|
+
throw new Error("could not obtain access token via refresh token");
|
177
|
+
}
|
178
|
+
} catch(e) {
|
179
|
+
oauth.invalidate(e);
|
180
|
+
|
181
|
+
throw(e);
|
175
182
|
}
|
176
183
|
}
|
177
184
|
|
@@ -179,24 +186,29 @@ class OAuthFetcher extends Fetcher {
|
|
179
186
|
var local = this;
|
180
187
|
|
181
188
|
return new Promise((resolve, reject) => {
|
182
|
-
setTimeout(
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
189
|
+
setTimeout(
|
190
|
+
async () => {
|
191
|
+
try {
|
192
|
+
resolve(
|
193
|
+
await local.fetch(url, options, retries, {
|
194
|
+
forceTokenRefresh: e.status === 401,
|
195
|
+
}),
|
196
|
+
);
|
197
|
+
} catch (e) {
|
198
|
+
reject(e);
|
199
|
+
}
|
200
|
+
},
|
201
|
+
rateLimit ? 10000 : 500,
|
202
|
+
);
|
193
203
|
});
|
194
204
|
}
|
195
205
|
|
196
206
|
async periodicRefresh() {
|
197
|
-
const local = this,
|
207
|
+
const local = this,
|
208
|
+
oauth = local.oauth;
|
209
|
+
|
198
210
|
if (!oauth.refreshToken()) return;
|
199
|
-
|
211
|
+
|
200
212
|
await local.getToken(true);
|
201
213
|
}
|
202
214
|
|
@@ -244,15 +256,21 @@ class OAuth {
|
|
244
256
|
|
245
257
|
async periodicRefresh() {
|
246
258
|
const clients = this.clients;
|
247
|
-
|
248
|
-
console.log(
|
249
|
-
|
259
|
+
|
260
|
+
console.log("refreshing oauth clients", clients.length);
|
261
|
+
|
250
262
|
for (let i = 0; i < clients.length; ++i) {
|
251
263
|
const client = clients[0];
|
252
|
-
|
264
|
+
|
253
265
|
await client.periodicRefresh();
|
254
266
|
}
|
255
267
|
}
|
268
|
+
|
269
|
+
async invalidate(err) {
|
270
|
+
console.log('could not obtain access token, marking connector as disconnected', err);
|
271
|
+
|
272
|
+
await this.upate(null, null);
|
273
|
+
}
|
256
274
|
|
257
275
|
getClient(arg = {}) {
|
258
276
|
const client = new OAuthFetcher({ ...arg, oauth: this });
|
@@ -321,7 +339,7 @@ class Connector {
|
|
321
339
|
publicKey: process.env.PUBLIC_KEY,
|
322
340
|
introspect,
|
323
341
|
configSchema,
|
324
|
-
icon: this.icon
|
342
|
+
icon: this.icon,
|
325
343
|
});
|
326
344
|
|
327
345
|
if (Object.keys(configSchema().fields).length) {
|
@@ -369,7 +387,7 @@ ${text}
|
|
369
387
|
const value = secrets[key];
|
370
388
|
if (!value) continue;
|
371
389
|
|
372
|
-
if (fields[key]?.plain || [
|
390
|
+
if (fields[key]?.plain || ["endpointUrl"].includes(key)) {
|
373
391
|
decrypted[key] = value;
|
374
392
|
} else {
|
375
393
|
try {
|
@@ -383,16 +401,17 @@ ${text}
|
|
383
401
|
this.startOAuth = async function (args) {
|
384
402
|
if (!this._oauth) throw new Error("oauth not configured");
|
385
403
|
|
386
|
-
const clientId =
|
404
|
+
const clientId =
|
405
|
+
process.env.OAUTH_CLIENT_ID ||
|
387
406
|
decrypted.clientId ||
|
388
|
-
|
389
|
-
|
407
|
+
this._oauth.clientId;
|
408
|
+
|
390
409
|
if (!clientId) throw new Error("clientId not configured");
|
391
410
|
|
392
411
|
const scopes =
|
393
412
|
process.env.OAUTH_SCOPE ||
|
394
413
|
decrypted.scope ||
|
395
|
-
|
414
|
+
this._oauth.scope ||
|
396
415
|
"";
|
397
416
|
const useCodeChallenge = !!that._oauth.useCodeChallenge;
|
398
417
|
|
@@ -417,18 +436,17 @@ ${text}
|
|
417
436
|
if (!arg.code || !arg.redirectURI)
|
418
437
|
throw new Error("need code and redirectUri");
|
419
438
|
|
420
|
-
const clientId =
|
421
|
-
|
422
|
-
|
423
|
-
|
439
|
+
const clientId =
|
440
|
+
process.env.OAUTH_CLIENT_ID ||
|
441
|
+
decrypted.clientId ||
|
442
|
+
that._oauth.clientId;
|
424
443
|
|
425
|
-
;
|
426
444
|
if (!clientId) throw new Error("clientId not configured");
|
427
445
|
|
428
446
|
const clientSecret =
|
429
447
|
process.env.OAUTH_CLIENT_SECRET ||
|
430
448
|
decrypted.clientSecret ||
|
431
|
-
|
449
|
+
that._oauth.clientSecret;
|
432
450
|
if (!clientSecret) throw new Error("clientSecret not configured");
|
433
451
|
|
434
452
|
const additionalTokenArgs = that._oauth.additionalTokenArgs || {};
|
@@ -507,12 +525,18 @@ ${text}
|
|
507
525
|
};
|
508
526
|
|
509
527
|
const saveOAuthResult = async (what) => {
|
510
|
-
|
528
|
+
let value = null;
|
529
|
+
|
530
|
+
if (what) {
|
531
|
+
const jwe = await config.validateKeys("RSA-OAEP-256");
|
532
|
+
value = await jwe.encrypt(what, "none", config.id())
|
533
|
+
};
|
534
|
+
|
511
535
|
const packet = transport.newPacket({});
|
512
536
|
|
513
537
|
packet.method("connector.config-update");
|
514
538
|
packet.args({
|
515
|
-
value
|
539
|
+
value
|
516
540
|
});
|
517
541
|
|
518
542
|
transport.send(packet);
|
@@ -522,17 +546,15 @@ ${text}
|
|
522
546
|
|
523
547
|
const getRefreshToken = async (refreshToken) => {
|
524
548
|
const clientId =
|
525
|
-
|
526
549
|
process.env.OAUTH_CLIENT_ID ||
|
527
|
-
decrypted.clientId ||
|
528
|
-
|
550
|
+
decrypted.clientId ||
|
551
|
+
that._oauth.clientId;
|
529
552
|
if (!clientId) throw new Error("clientId not configured");
|
530
553
|
|
531
554
|
const clientSecret =
|
532
|
-
|
533
555
|
process.env.OAUTH_CLIENT_SECRET ||
|
534
556
|
decrypted.clientSecret ||
|
535
|
-
|
557
|
+
that._oauth.clientSecret;
|
536
558
|
if (!clientSecret) throw new Error("clientSecret not configured");
|
537
559
|
|
538
560
|
const useAuthHeader = !!that._oauth.useAuthHeader;
|
@@ -580,21 +602,21 @@ ${text}
|
|
580
602
|
|
581
603
|
if (theOAuth) {
|
582
604
|
clearInterval(this._refreshOAuthToken);
|
583
|
-
|
605
|
+
|
584
606
|
if (!(this._oauth.noPeriodicTokenRefresh === false)) {
|
585
|
-
this._refreshOAuthToken = setInterval(
|
586
|
-
|
587
|
-
|
588
|
-
|
589
|
-
|
590
|
-
|
591
|
-
|
592
|
-
}
|
593
|
-
|
607
|
+
this._refreshOAuthToken = setInterval(
|
608
|
+
async () => {
|
609
|
+
try {
|
610
|
+
await theOAuth.periodicRefresh();
|
611
|
+
} catch (e) {
|
612
|
+
console.log("periodic refresh", e);
|
613
|
+
}
|
614
|
+
},
|
615
|
+
4 * 60 * 60 * 15000,
|
616
|
+
);
|
594
617
|
}
|
595
|
-
|
596
618
|
}
|
597
|
-
|
619
|
+
|
598
620
|
start({
|
599
621
|
config: decrypted,
|
600
622
|
oauth: theOAuth,
|
@@ -13,7 +13,7 @@ class Config {
|
|
13
13
|
publicKey,
|
14
14
|
introspect,
|
15
15
|
configSchema,
|
16
|
-
icon
|
16
|
+
icon,
|
17
17
|
}) {
|
18
18
|
this._token = null;
|
19
19
|
this._registrationToken = registrationToken;
|
@@ -100,7 +100,7 @@ class Config {
|
|
100
100
|
token() {
|
101
101
|
return this._token;
|
102
102
|
}
|
103
|
-
|
103
|
+
|
104
104
|
icon() {
|
105
105
|
return this._icon;
|
106
106
|
}
|
@@ -12,7 +12,7 @@ class Registration {
|
|
12
12
|
const configSchema = config.configSchema();
|
13
13
|
const intro = await config.introspect();
|
14
14
|
const icon = config.icon();
|
15
|
-
|
15
|
+
|
16
16
|
const response = await fetch(
|
17
17
|
config.url() + "register",
|
18
18
|
C.augmentRegistration(
|
@@ -25,7 +25,7 @@ class Registration {
|
|
25
25
|
id: config.id(),
|
26
26
|
publicKey: config.publicKey(),
|
27
27
|
schema: { configSchema, introspect: intro },
|
28
|
-
icon
|
28
|
+
icon,
|
29
29
|
}),
|
30
30
|
headers: { "Content-Type": "application/json" },
|
31
31
|
},
|
@@ -68,9 +68,18 @@ class Transport {
|
|
68
68
|
C.augmentRequest({ headers: {} }, config),
|
69
69
|
));
|
70
70
|
|
71
|
+
ws.onPing = function () {
|
72
|
+
clearTimeout(this.pingTimeout);
|
73
|
+
this.pingTimeout = setTimeout(() => {
|
74
|
+
console.log("terminating ws");
|
75
|
+
if (local.running) this.terminate();
|
76
|
+
}, 30000 + 15000);
|
77
|
+
};
|
78
|
+
|
71
79
|
ws.on("open", () => {
|
72
80
|
console.log("websocket connected");
|
73
81
|
local.connected = true;
|
82
|
+
ws.onPing();
|
74
83
|
local.pinger = setInterval(() => ws.ping(() => null), pingInterval);
|
75
84
|
|
76
85
|
local.onConnect(local);
|
@@ -80,6 +89,8 @@ class Transport {
|
|
80
89
|
setTimeout(() => local.onMessages(JSON.parse(message)), 0);
|
81
90
|
});
|
82
91
|
|
92
|
+
ws.on("ping", () => ws.onPing());
|
93
|
+
|
83
94
|
ws.on("error", (message) => {
|
84
95
|
console.log("error:", message);
|
85
96
|
});
|