@aloma.io/integration-sdk 3.0.1 → 3.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/README.md +2 -6
- package/build/builder/index.d.mts +1 -1
- package/build/builder/index.mjs +11 -15
- package/build/builder/runtime-context.d.mts +1 -1
- package/build/builder/runtime-context.mjs +7 -10
- package/build/builder/transform/index.mjs +18 -18
- package/build/controller/index.mjs +5 -5
- package/build/index.d.mts +2 -2
- package/build/index.mjs +2 -2
- package/build/internal/dispatcher/index.cjs +30 -41
- package/build/internal/index.cjs +71 -86
- package/build/internal/util/jwe/cli.cjs +3 -3
- package/build/internal/util/jwe/index.cjs +10 -10
- package/build/internal/websocket/config.cjs +7 -7
- package/build/internal/websocket/connection/constants.cjs +3 -3
- package/build/internal/websocket/connection/index.cjs +9 -9
- package/build/internal/websocket/connection/registration.cjs +7 -7
- package/build/internal/websocket/index.cjs +3 -3
- package/build/internal/websocket/transport/durable.cjs +6 -6
- package/build/internal/websocket/transport/index.cjs +18 -18
- package/build/internal/websocket/transport/packet.cjs +2 -2
- package/build/internal/websocket/transport/processor.cjs +5 -5
- package/package.json +1 -1
- package/build/cli.d.mts +0 -2
- package/build/cli.mjs +0 -93
package/README.md
CHANGED
@@ -1,9 +1,5 @@
|
|
1
1
|
# nodejs - Aloma Integration SDK
|
2
2
|
|
3
|
-
##
|
3
|
+
## Creating a new Connector
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
## Integration Examples
|
8
|
-
|
9
|
-
See `examples` directory.
|
5
|
+
With the aloma integration SDK cli you can simply create a new connector via `npx @aloma.io/integration-sdk create connectorName --connector-id 1234`.
|
package/build/builder/index.mjs
CHANGED
@@ -1,8 +1,8 @@
|
|
1
|
-
import fs from
|
2
|
-
import parseTypes from
|
3
|
-
import RuntimeContext from
|
4
|
-
import { fileURLToPath } from
|
5
|
-
import path from
|
1
|
+
import fs from 'node:fs';
|
2
|
+
import parseTypes from './transform/index.mjs';
|
3
|
+
import RuntimeContext from './runtime-context.mjs';
|
4
|
+
import { fileURLToPath } from 'node:url';
|
5
|
+
import path from 'node:path';
|
6
6
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
7
7
|
const notEmpty = (what, name) => {
|
8
8
|
if (!what?.trim())
|
@@ -10,9 +10,7 @@ const notEmpty = (what, name) => {
|
|
10
10
|
return what;
|
11
11
|
};
|
12
12
|
export class Builder {
|
13
|
-
data = {
|
14
|
-
controller: "./build/controller/.controller-for-types.mts",
|
15
|
-
};
|
13
|
+
data = { controller: './build/controller/.controller-for-types.mts' };
|
16
14
|
config(arg) {
|
17
15
|
this.data.config = arg;
|
18
16
|
return this;
|
@@ -29,19 +27,17 @@ export class Builder {
|
|
29
27
|
await this.parsePackageJson();
|
30
28
|
await this.discoverTypes();
|
31
29
|
// @ts-ignore
|
32
|
-
const Controller = (await import(__dirname +
|
30
|
+
const Controller = (await import(__dirname + '/../../../../../build/controller/index.mjs')).default;
|
33
31
|
return new RuntimeContext(new Controller(), this.data);
|
34
32
|
}
|
35
33
|
async parsePackageJson() {
|
36
34
|
const data = this.data;
|
37
|
-
const packageJson = JSON.parse(fs.readFileSync(__dirname +
|
38
|
-
|
39
|
-
|
40
|
-
notEmpty((data.id = packageJson.connectorId), "id");
|
41
|
-
notEmpty((data.version = packageJson.version), "version");
|
35
|
+
const packageJson = JSON.parse(fs.readFileSync(__dirname + '/../../../../../package.json', { encoding: 'utf-8' }));
|
36
|
+
notEmpty(data.id = packageJson.connectorId, 'id');
|
37
|
+
notEmpty(data.version = packageJson.version, 'version');
|
42
38
|
}
|
43
39
|
async discoverTypes() {
|
44
|
-
notEmpty(this.data.controller,
|
40
|
+
notEmpty(this.data.controller, 'controller');
|
45
41
|
const content = fs.readFileSync(this.data.controller);
|
46
42
|
const { text, methods } = parseTypes(this.data.controller);
|
47
43
|
this.data.types = text;
|
@@ -1,5 +1,5 @@
|
|
1
|
-
import { AbstractController } from
|
2
|
-
import { Connector } from
|
1
|
+
import { AbstractController } from '../controller/index.mjs';
|
2
|
+
import { Connector } from '../internal/index.cjs';
|
3
3
|
export default class RuntimeContext {
|
4
4
|
controller;
|
5
5
|
data;
|
@@ -10,7 +10,7 @@ export default class RuntimeContext {
|
|
10
10
|
async start() {
|
11
11
|
const controller = this.controller;
|
12
12
|
if (!(controller instanceof AbstractController))
|
13
|
-
throw new Error(
|
13
|
+
throw new Error('the controller needs to extend AbstractController');
|
14
14
|
const data = this.data;
|
15
15
|
const connector = new Connector({
|
16
16
|
id: data.id,
|
@@ -19,12 +19,7 @@ export default class RuntimeContext {
|
|
19
19
|
});
|
20
20
|
const configuration = connector.configure().config(data.config || {});
|
21
21
|
const resolvers = {};
|
22
|
-
const methods = [
|
23
|
-
...data.methods,
|
24
|
-
"__endpoint",
|
25
|
-
"__configQuery",
|
26
|
-
"__default",
|
27
|
-
];
|
22
|
+
const methods = [...data.methods, '__endpoint', '__configQuery', '__default'];
|
28
23
|
methods.forEach((method) => {
|
29
24
|
resolvers[method] = async (args) => {
|
30
25
|
if (!methods.includes(method))
|
@@ -32,7 +27,9 @@ export default class RuntimeContext {
|
|
32
27
|
return controller[method](args);
|
33
28
|
};
|
34
29
|
});
|
35
|
-
configuration
|
30
|
+
configuration
|
31
|
+
.types(data.types)
|
32
|
+
.resolvers(resolvers);
|
36
33
|
if (data.options?.endpoint?.enabled) {
|
37
34
|
configuration.endpoint((arg) => controller.__endpoint(arg));
|
38
35
|
}
|
@@ -1,19 +1,19 @@
|
|
1
|
-
import { parseFromFiles } from
|
1
|
+
import { parseFromFiles } from '@ts-ast-parser/core';
|
2
2
|
const transform = (meta) => {
|
3
3
|
if (!meta?.length)
|
4
|
-
throw new Error(
|
4
|
+
throw new Error('metadata is empty');
|
5
5
|
meta = meta[0];
|
6
6
|
if (meta.getDeclarations()?.length !== 1) {
|
7
|
-
throw new Error(
|
7
|
+
throw new Error('connector file needs to export default class');
|
8
8
|
}
|
9
9
|
const methods = {};
|
10
10
|
const decl = meta.getDeclarations()[0];
|
11
11
|
const members = decl.getMethods().filter((member) => {
|
12
12
|
return !(member.isStatic() ||
|
13
13
|
member.isInherited() ||
|
14
|
-
member.getKind() !==
|
15
|
-
member.getModifier() !==
|
16
|
-
member.getName().startsWith(
|
14
|
+
member.getKind() !== 'Method' ||
|
15
|
+
member.getModifier() !== 'public' ||
|
16
|
+
member.getName().startsWith('_'));
|
17
17
|
});
|
18
18
|
const text = members
|
19
19
|
.map((member) => {
|
@@ -22,13 +22,13 @@ const transform = (meta) => {
|
|
22
22
|
.getSignatures()
|
23
23
|
.map((sig) => {
|
24
24
|
const docs = sig.getJSDoc().serialize() || [];
|
25
|
-
const desc = docs.find((what) => what.kind ===
|
25
|
+
const desc = docs.find((what) => what.kind === 'description')?.value;
|
26
26
|
const paramDocs = docs
|
27
|
-
.filter((what) => what.kind ===
|
27
|
+
.filter((what) => what.kind === 'param')
|
28
28
|
.map((what) => {
|
29
|
-
return ` * @param {${what.value.type}} ${what.value.name} - ${what.value.description ||
|
29
|
+
return ` * @param {${what.value.type}} ${what.value.name} - ${what.value.description || ''}`;
|
30
30
|
})
|
31
|
-
.join(
|
31
|
+
.join('\n') || ' *';
|
32
32
|
const params = sig
|
33
33
|
.getParameters()
|
34
34
|
.map((param) => {
|
@@ -38,32 +38,32 @@ const transform = (meta) => {
|
|
38
38
|
const tmp = param
|
39
39
|
.getNamedElements()
|
40
40
|
.map((p) => {
|
41
|
-
const defaultVal = p.default != null ?
|
41
|
+
const defaultVal = p.default != null ? ' = ' + p.default : '';
|
42
42
|
return `${p.name}${defaultVal}`;
|
43
43
|
})
|
44
|
-
.join(
|
44
|
+
.join('; ');
|
45
45
|
return `{${tmp}}: ${param.getType().text}`;
|
46
46
|
case false:
|
47
47
|
return `${param.getName()}: ${param.getType().text}`;
|
48
48
|
}
|
49
49
|
})
|
50
|
-
.join(
|
50
|
+
.join(', ');
|
51
51
|
const retVal = sig
|
52
52
|
.getReturnType()
|
53
|
-
.type.text.replace(/^Promise</,
|
54
|
-
.replace(/>$/,
|
53
|
+
.type.text.replace(/^Promise</, '')
|
54
|
+
.replace(/>$/, '');
|
55
55
|
return `
|
56
56
|
/**
|
57
|
-
* ${desc ||
|
57
|
+
* ${desc || ''}
|
58
58
|
*
|
59
59
|
${paramDocs}
|
60
60
|
**/
|
61
61
|
declare function ${member.getName()}(${params}): ${retVal};
|
62
62
|
`;
|
63
63
|
})
|
64
|
-
.join(
|
64
|
+
.join('\n');
|
65
65
|
})
|
66
|
-
.join(
|
66
|
+
.join('');
|
67
67
|
return { text, methods: Object.keys(methods) };
|
68
68
|
};
|
69
69
|
export default (path) => {
|
@@ -7,19 +7,19 @@ export class AbstractController {
|
|
7
7
|
return Promise.resolve({});
|
8
8
|
}
|
9
9
|
fallback(arg) {
|
10
|
-
throw new Error(
|
10
|
+
throw new Error('method not found');
|
11
11
|
}
|
12
12
|
endpoint(arg) {
|
13
|
-
throw new Error(
|
13
|
+
throw new Error('method not found');
|
14
14
|
}
|
15
15
|
async newTask(name, data) {
|
16
|
-
throw new Error(
|
16
|
+
throw new Error('not implemented');
|
17
17
|
}
|
18
18
|
getClient({ baseUrl }) {
|
19
|
-
throw new Error(
|
19
|
+
throw new Error('not implemented');
|
20
20
|
}
|
21
21
|
async updateTask(name, data) {
|
22
|
-
throw new Error(
|
22
|
+
throw new Error('not implemented');
|
23
23
|
}
|
24
24
|
async __endpoint(arg) {
|
25
25
|
return this.endpoint(arg);
|
package/build/index.d.mts
CHANGED
@@ -1,2 +1,2 @@
|
|
1
|
-
export * from
|
2
|
-
export * from
|
1
|
+
export * from './builder/index.mjs';
|
2
|
+
export * from './controller/index.mjs';
|
package/build/index.mjs
CHANGED
@@ -1,2 +1,2 @@
|
|
1
|
-
export * from
|
2
|
-
export * from
|
1
|
+
export * from './builder/index.mjs';
|
2
|
+
export * from './controller/index.mjs';
|
@@ -14,26 +14,26 @@ class Dispatcher {
|
|
14
14
|
oauth: true,
|
15
15
|
fields: {
|
16
16
|
oauthResult: {
|
17
|
-
name:
|
18
|
-
placeholder:
|
19
|
-
type:
|
17
|
+
name: 'OAuth Result',
|
18
|
+
placeholder: 'will be set by finishing the oauth flow',
|
19
|
+
type: 'managed',
|
20
20
|
},
|
21
21
|
},
|
22
22
|
});
|
23
23
|
return this;
|
24
24
|
}
|
25
25
|
if (!arg.authorizationURL)
|
26
|
-
throw new Error(
|
26
|
+
throw new Error('need a authorizationURL');
|
27
27
|
if (!arg.tokenURL && !arg.finishOAuth)
|
28
|
-
throw new Error(
|
28
|
+
throw new Error('need a tokenURL or finishOAuth()');
|
29
29
|
this._oauth = { ...arg };
|
30
30
|
this.config({
|
31
31
|
oauth: true,
|
32
32
|
fields: {
|
33
33
|
oauthResult: {
|
34
|
-
name:
|
35
|
-
placeholder:
|
36
|
-
type:
|
34
|
+
name: 'OAuth Result',
|
35
|
+
placeholder: 'will be set by finishing the oauth flow',
|
36
|
+
type: 'managed',
|
37
37
|
},
|
38
38
|
},
|
39
39
|
});
|
@@ -41,14 +41,14 @@ class Dispatcher {
|
|
41
41
|
this.config({
|
42
42
|
fields: {
|
43
43
|
clientId: {
|
44
|
-
name:
|
45
|
-
placeholder:
|
46
|
-
type:
|
44
|
+
name: 'OAuth Client ID',
|
45
|
+
placeholder: 'e.g. 1234',
|
46
|
+
type: 'line',
|
47
47
|
},
|
48
48
|
clientSecret: {
|
49
|
-
name:
|
50
|
-
placeholder:
|
51
|
-
type:
|
49
|
+
name: 'OAuth Client Secret',
|
50
|
+
placeholder: 'e.g. axd5xde',
|
51
|
+
type: 'line',
|
52
52
|
},
|
53
53
|
},
|
54
54
|
});
|
@@ -72,9 +72,9 @@ class Dispatcher {
|
|
72
72
|
this.config({
|
73
73
|
fields: {
|
74
74
|
_endpointToken: {
|
75
|
-
name:
|
76
|
-
placeholder:
|
77
|
-
type:
|
75
|
+
name: 'Endpoint Token (set to enable the endpoint)',
|
76
|
+
placeholder: 'e.g. 1234',
|
77
|
+
type: 'line',
|
78
78
|
plain: true,
|
79
79
|
optional: true,
|
80
80
|
},
|
@@ -84,19 +84,19 @@ class Dispatcher {
|
|
84
84
|
return this;
|
85
85
|
}
|
86
86
|
startOAuth() {
|
87
|
-
throw new Error(
|
87
|
+
throw new Error('oauth not configured');
|
88
88
|
}
|
89
89
|
finishOAuth() {
|
90
|
-
throw new Error(
|
90
|
+
throw new Error('oauth not configured');
|
91
91
|
}
|
92
92
|
build() {
|
93
93
|
if (!this._types || !this._resolvers)
|
94
|
-
throw new Error(
|
94
|
+
throw new Error('missing types or resolvers');
|
95
95
|
var local = this;
|
96
96
|
const _resolvers = { ...this._resolvers };
|
97
97
|
const main = this._main || (() => { });
|
98
98
|
const start = async (transport) => {
|
99
|
-
console.log(
|
99
|
+
console.log('starting ...');
|
100
100
|
await main(transport);
|
101
101
|
};
|
102
102
|
const resolveMethod = (query) => {
|
@@ -110,44 +110,33 @@ class Dispatcher {
|
|
110
110
|
if (!Array.isArray(query))
|
111
111
|
query = [query];
|
112
112
|
query = query
|
113
|
-
.filter((what) => !!what?.trim() &&
|
114
|
-
![
|
115
|
-
"constructor",
|
116
|
-
"__proto__",
|
117
|
-
"toString",
|
118
|
-
"toSource",
|
119
|
-
"prototype",
|
120
|
-
].includes(what))
|
113
|
+
.filter((what) => !!what?.trim() && !['constructor', '__proto__', 'toString', 'toSource', 'prototype'].includes(what))
|
121
114
|
.slice(0, 20);
|
122
115
|
const method = resolveMethod(query);
|
123
116
|
if (!method && !_resolvers.__default)
|
124
117
|
throw new Error(`${query} not found`);
|
125
|
-
return method
|
126
|
-
? method(variables)
|
127
|
-
: _resolvers.__default(variables ? { ...variables, __method: query } : variables);
|
118
|
+
return method ? method(variables) : _resolvers.__default(variables ? { ...variables, __method: query } : variables);
|
128
119
|
};
|
129
120
|
const introspect = () => local._types;
|
130
121
|
const configSchema = () => local._config;
|
131
122
|
const processPacket = async (packet) => {
|
132
123
|
switch (packet.method()) {
|
133
|
-
case
|
124
|
+
case 'connector.introspect':
|
134
125
|
const intro = await introspect({});
|
135
126
|
return { configSchema: local._config, introspect: intro };
|
136
|
-
case
|
127
|
+
case 'connector.start-oauth':
|
137
128
|
return await local.startOAuth(packet.args());
|
138
|
-
case
|
129
|
+
case 'connector.finish-oauth':
|
139
130
|
return await local.finishOAuth(packet.args());
|
140
|
-
case
|
131
|
+
case 'connector.query':
|
141
132
|
const ret = await execute(packet.args());
|
142
|
-
return typeof ret ===
|
143
|
-
|
144
|
-
: { [packet.args().query]: ret };
|
145
|
-
case "connector.set-config":
|
133
|
+
return typeof ret === 'object' && !Array.isArray(ret) ? ret : { [packet.args().query]: ret };
|
134
|
+
case 'connector.set-config':
|
146
135
|
await local.onConfig({ ...packet.args().secrets });
|
147
136
|
return;
|
148
137
|
}
|
149
138
|
console.dir(packet, { depth: null });
|
150
|
-
throw new Error(
|
139
|
+
throw new Error('cannot handle packet');
|
151
140
|
};
|
152
141
|
return {
|
153
142
|
introspect,
|
package/build/internal/index.cjs
CHANGED
@@ -1,27 +1,27 @@
|
|
1
1
|
"use strict";
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
3
3
|
// @ts-nocheck
|
4
|
-
require(
|
5
|
-
const fs = require(
|
6
|
-
const { Config } = require(
|
7
|
-
const { Connection } = require(
|
8
|
-
const { Transport } = require(
|
9
|
-
const { Dispatcher } = require(
|
10
|
-
const { WebsocketConnector } = require(
|
11
|
-
const JWE = require(
|
12
|
-
const fetch = require(
|
13
|
-
const cuid = require(
|
4
|
+
require('dotenv').config();
|
5
|
+
const fs = require('fs');
|
6
|
+
const { Config } = require('./websocket/config.cjs');
|
7
|
+
const { Connection } = require('./websocket/connection/index.cjs');
|
8
|
+
const { Transport } = require('./websocket/transport/index.cjs');
|
9
|
+
const { Dispatcher } = require('./dispatcher/index.cjs');
|
10
|
+
const { WebsocketConnector } = require('./websocket/index.cjs');
|
11
|
+
const JWE = require('./util/jwe/index.cjs');
|
12
|
+
const fetch = require('node-fetch');
|
13
|
+
const cuid = require('@paralleldrive/cuid2').init({ length: 32 });
|
14
14
|
// TODO fetch with retry
|
15
15
|
const handlePacketError = (packet, e, transport) => {
|
16
16
|
if (!packet.cb()) {
|
17
|
-
console.dir({ msg:
|
17
|
+
console.dir({ msg: 'packet error', e, packet }, { depth: null });
|
18
18
|
return;
|
19
19
|
}
|
20
|
-
transport.send(transport.newPacket({ c: packet.cb(), a: { error:
|
20
|
+
transport.send(transport.newPacket({ c: packet.cb(), a: { error: '' + e } }));
|
21
21
|
};
|
22
22
|
const reply = (arg, packet, transport) => {
|
23
23
|
if (!packet.cb()) {
|
24
|
-
console.dir({ msg:
|
24
|
+
console.dir({ msg: 'cannot reply to packet without cb', arg, packet }, { depth: null });
|
25
25
|
return;
|
26
26
|
}
|
27
27
|
transport.send(transport.newPacket({ c: packet.cb(), a: { ...arg } }));
|
@@ -30,7 +30,7 @@ const unwrap = async (ret, options) => {
|
|
30
30
|
if (options?.text)
|
31
31
|
return await ret.text();
|
32
32
|
if (options?.base64)
|
33
|
-
return (await ret.buffer()).toString(
|
33
|
+
return (await ret.buffer()).toString('base64');
|
34
34
|
return await ret.json();
|
35
35
|
};
|
36
36
|
class Fetcher {
|
@@ -57,13 +57,13 @@ class Fetcher {
|
|
57
57
|
if (retries == null)
|
58
58
|
retries = local.retry;
|
59
59
|
try {
|
60
|
-
const theURL = `${baseUrl?.endsWith(
|
60
|
+
const theURL = `${baseUrl?.endsWith('/') ? baseUrl : baseUrl + '/'}${url}`.replace(/\/\/+/gi, '/');
|
61
61
|
await local.customize(options, args);
|
62
62
|
const ret = await fetch(theURL, options);
|
63
63
|
const status = await ret.status;
|
64
64
|
if (status > 399) {
|
65
65
|
const text = await ret.text();
|
66
|
-
const e = new Error(status +
|
66
|
+
const e = new Error(status + ' ' + text);
|
67
67
|
e.status = status;
|
68
68
|
throw e;
|
69
69
|
}
|
@@ -92,14 +92,14 @@ class OAuthFetcher extends Fetcher {
|
|
92
92
|
return oauth.accessToken();
|
93
93
|
const refreshToken = oauth.refreshToken();
|
94
94
|
if (!refreshToken)
|
95
|
-
throw new Error(
|
95
|
+
throw new Error('have no access_token and no refresh_token');
|
96
96
|
const ret = await oauth.obtainViaRefreshToken(oauth.refreshToken());
|
97
97
|
if (ret.access_token) {
|
98
98
|
oauth.update(ret.access_token, ret.refresh_token);
|
99
99
|
return ret.access_token;
|
100
100
|
}
|
101
101
|
else {
|
102
|
-
throw new Error(
|
102
|
+
throw new Error('could not obtain access token via refresh token');
|
103
103
|
}
|
104
104
|
}
|
105
105
|
async onError(e, url, options, retries, args) {
|
@@ -107,9 +107,7 @@ class OAuthFetcher extends Fetcher {
|
|
107
107
|
return new Promise((resolve, reject) => {
|
108
108
|
setTimeout(async () => {
|
109
109
|
try {
|
110
|
-
resolve(await local.fetch(url, options, retries, {
|
111
|
-
forceTokenRefresh: e.status === 401,
|
112
|
-
}));
|
110
|
+
resolve(await local.fetch(url, options, retries, { forceTokenRefresh: e.status === 401 }));
|
113
111
|
}
|
114
112
|
catch (e) {
|
115
113
|
reject(e);
|
@@ -165,36 +163,36 @@ class Connector {
|
|
165
163
|
async run() {
|
166
164
|
var local = this;
|
167
165
|
const makeMetrics = () => {
|
168
|
-
const metrics = require(
|
166
|
+
const metrics = require('prom-client');
|
169
167
|
const defaultLabels = {
|
170
168
|
service: local.name,
|
171
169
|
connectorId: local.id,
|
172
170
|
connectorVersion: local.version,
|
173
|
-
node: process.env.HOSTNAME ||
|
171
|
+
node: process.env.HOSTNAME || 'test',
|
174
172
|
};
|
175
173
|
metrics.register.setDefaultLabels(defaultLabels);
|
176
174
|
metrics.collectDefaultMetrics();
|
177
175
|
return metrics;
|
178
176
|
};
|
179
177
|
const makeMetricsServer = (metrics) => {
|
180
|
-
const app = require(
|
181
|
-
app.get(
|
178
|
+
const app = require('express')();
|
179
|
+
app.get('/metrics', async (request, response, next) => {
|
182
180
|
response.status(200);
|
183
|
-
response.set(
|
181
|
+
response.set('Content-type', metrics.contentType);
|
184
182
|
response.send(await metrics.register.metrics());
|
185
183
|
response.end();
|
186
184
|
});
|
187
185
|
return app;
|
188
186
|
};
|
189
|
-
makeMetricsServer(makeMetrics()).listen(4050,
|
187
|
+
makeMetricsServer(makeMetrics()).listen(4050, '0.0.0.0');
|
190
188
|
const { processPacket, start, introspect, configSchema } = this.dispatcher.build();
|
191
189
|
const config = new Config({
|
192
190
|
id: this.id,
|
193
191
|
version: this.version,
|
194
192
|
name: process.env.HOSTNAME || this.name,
|
195
193
|
registrationToken: process.env.REGISTRATION_TOKEN,
|
196
|
-
endpoint: process.env.DEVICE_ENDPOINT ||
|
197
|
-
wsEndpoint: process.env.WEBSOCKET_ENDPOINT ||
|
194
|
+
endpoint: process.env.DEVICE_ENDPOINT || 'https://connect.aloma.io/',
|
195
|
+
wsEndpoint: process.env.WEBSOCKET_ENDPOINT || 'wss://transport.aloma.io/transport/',
|
198
196
|
privateKey: process.env.PRIVATE_KEY,
|
199
197
|
publicKey: process.env.PUBLIC_KEY,
|
200
198
|
introspect,
|
@@ -207,15 +205,15 @@ class Connector {
|
|
207
205
|
catch (e) {
|
208
206
|
const haveKey = !!process.env.PRIVATE_KEY;
|
209
207
|
const jwe = new JWE({});
|
210
|
-
var text =
|
208
|
+
var text = 'Please double check the env variables';
|
211
209
|
if (!haveKey) {
|
212
210
|
await jwe.newPair();
|
213
211
|
text =
|
214
|
-
|
212
|
+
'fresh keys generated, set environment variables: \n\nPRIVATE_KEY: ' +
|
215
213
|
(await jwe.exportPrivateAsBase64()) +
|
216
|
-
|
214
|
+
'\n\nPUBLIC_KEY: ' +
|
217
215
|
(await jwe.exportPublicAsBase64()) +
|
218
|
-
|
216
|
+
'\n';
|
219
217
|
}
|
220
218
|
console.log(`
|
221
219
|
Error:
|
@@ -234,7 +232,7 @@ ${text}
|
|
234
232
|
const decrypted = {};
|
235
233
|
const fields = configSchema().fields;
|
236
234
|
const keys = Object.keys(secrets);
|
237
|
-
const jwe = await config.validateKeys(
|
235
|
+
const jwe = await config.validateKeys('RSA-OAEP-256');
|
238
236
|
for (var i = 0; i < keys.length; ++i) {
|
239
237
|
const key = keys[i];
|
240
238
|
const value = secrets[key];
|
@@ -248,22 +246,17 @@ ${text}
|
|
248
246
|
decrypted[key] = await jwe.decrypt(value, config.id());
|
249
247
|
}
|
250
248
|
catch (e) {
|
251
|
-
console.log(
|
249
|
+
console.log('failed to decrypt key', key, config.id(), e);
|
252
250
|
}
|
253
251
|
}
|
254
252
|
}
|
255
253
|
this.startOAuth = async function (args) {
|
256
254
|
if (!this._oauth)
|
257
|
-
throw new Error(
|
258
|
-
const clientId = this._oauth.clientId ||
|
259
|
-
process.env.OAUTH_CLIENT_ID ||
|
260
|
-
decrypted.clientId;
|
255
|
+
throw new Error('oauth not configured');
|
256
|
+
const clientId = this._oauth.clientId || process.env.OAUTH_CLIENT_ID || decrypted.clientId;
|
261
257
|
if (!clientId)
|
262
|
-
throw new Error(
|
263
|
-
const scopes = this._oauth.scope ||
|
264
|
-
process.env.OAUTH_SCOPE ||
|
265
|
-
decrypted.scope ||
|
266
|
-
"";
|
258
|
+
throw new Error('clientId not configured');
|
259
|
+
const scopes = this._oauth.scope || process.env.OAUTH_SCOPE || decrypted.scope || '';
|
267
260
|
const useCodeChallenge = !!that._oauth.useCodeChallenge;
|
268
261
|
return {
|
269
262
|
url: this._oauth.authorizationURL
|
@@ -275,23 +268,19 @@ ${text}
|
|
275
268
|
this.finishOAuth = async function (arg) {
|
276
269
|
var that = this;
|
277
270
|
if (!this._oauth)
|
278
|
-
throw new Error(
|
271
|
+
throw new Error('oauth not configured');
|
279
272
|
if (!this._oauth.tokenURL && !this._oauth.finishOAuth)
|
280
|
-
throw new Error(
|
273
|
+
throw new Error('need tokenURL or finishOAuth(arg)');
|
281
274
|
var data = null;
|
282
275
|
const doFinish = async () => {
|
283
276
|
if (!arg.code || !arg.redirectURI)
|
284
|
-
throw new Error(
|
285
|
-
const clientId = that._oauth.clientId ||
|
286
|
-
process.env.OAUTH_CLIENT_ID ||
|
287
|
-
decrypted.clientId;
|
277
|
+
throw new Error('need code and redirectUri');
|
278
|
+
const clientId = that._oauth.clientId || process.env.OAUTH_CLIENT_ID || decrypted.clientId;
|
288
279
|
if (!clientId)
|
289
|
-
throw new Error(
|
290
|
-
const clientSecret = that._oauth.clientSecret ||
|
291
|
-
process.env.OAUTH_CLIENT_SECRET ||
|
292
|
-
decrypted.clientSecret;
|
280
|
+
throw new Error('clientId not configured');
|
281
|
+
const clientSecret = that._oauth.clientSecret || process.env.OAUTH_CLIENT_SECRET || decrypted.clientSecret;
|
293
282
|
if (!clientSecret)
|
294
|
-
throw new Error(
|
283
|
+
throw new Error('clientSecret not configured');
|
295
284
|
const additionalTokenArgs = that._oauth.additionalTokenArgs || {};
|
296
285
|
const useAuthHeader = !!that._oauth.useAuthHeader;
|
297
286
|
const useCodeChallenge = !!that._oauth.useCodeChallenge;
|
@@ -304,8 +293,8 @@ ${text}
|
|
304
293
|
body.code_verifier = arg.codeVerifier;
|
305
294
|
}
|
306
295
|
let headers = {
|
307
|
-
|
308
|
-
Accept:
|
296
|
+
'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8',
|
297
|
+
Accept: 'application/json',
|
309
298
|
};
|
310
299
|
if (useAuthHeader) {
|
311
300
|
headers = {
|
@@ -321,7 +310,7 @@ ${text}
|
|
321
310
|
};
|
322
311
|
}
|
323
312
|
const response = await fetch(that._oauth.tokenURL, {
|
324
|
-
method:
|
313
|
+
method: 'POST',
|
325
314
|
body: new URLSearchParams(body),
|
326
315
|
headers,
|
327
316
|
});
|
@@ -330,17 +319,17 @@ ${text}
|
|
330
319
|
if (status === 200) {
|
331
320
|
const ret = JSON.parse(text);
|
332
321
|
if (ret.error) {
|
333
|
-
throw new Error(`${status} ${ret.error} ${ret.error_description ||
|
322
|
+
throw new Error(`${status} ${ret.error} ${ret.error_description || ''}`);
|
334
323
|
}
|
335
324
|
else if (ret.access_token) {
|
336
325
|
return { ...ret };
|
337
326
|
}
|
338
327
|
else {
|
339
|
-
throw new Error(status +
|
328
|
+
throw new Error(status + ' response has no access_token - ' + text);
|
340
329
|
}
|
341
330
|
}
|
342
331
|
else {
|
343
|
-
throw new Error(status +
|
332
|
+
throw new Error(status + ' ' + text);
|
344
333
|
}
|
345
334
|
};
|
346
335
|
if (this._oauth.finishOAuth) {
|
@@ -353,30 +342,26 @@ ${text}
|
|
353
342
|
else {
|
354
343
|
data = await doFinish();
|
355
344
|
}
|
356
|
-
const jwe = await config.validateKeys(
|
357
|
-
return { value: await jwe.encrypt(data,
|
345
|
+
const jwe = await config.validateKeys('RSA-OAEP-256');
|
346
|
+
return { value: await jwe.encrypt(data, 'none', config.id()) };
|
358
347
|
};
|
359
348
|
const saveOAuthResult = async (what) => {
|
360
|
-
const jwe = await config.validateKeys(
|
349
|
+
const jwe = await config.validateKeys('RSA-OAEP-256');
|
361
350
|
const packet = transport.newPacket({});
|
362
|
-
packet.method(
|
351
|
+
packet.method('connector.config-update');
|
363
352
|
packet.args({
|
364
|
-
value: await jwe.encrypt(what,
|
353
|
+
value: await jwe.encrypt(what, 'none', config.id()),
|
365
354
|
});
|
366
355
|
transport.send(packet);
|
367
356
|
};
|
368
357
|
const that = this;
|
369
358
|
const getRefreshToken = async (refreshToken) => {
|
370
|
-
const clientId = that._oauth.clientId ||
|
371
|
-
process.env.OAUTH_CLIENT_ID ||
|
372
|
-
decrypted.clientId;
|
359
|
+
const clientId = that._oauth.clientId || process.env.OAUTH_CLIENT_ID || decrypted.clientId;
|
373
360
|
if (!clientId)
|
374
|
-
throw new Error(
|
375
|
-
const clientSecret = that._oauth.clientSecret ||
|
376
|
-
process.env.OAUTH_CLIENT_SECRET ||
|
377
|
-
decrypted.clientSecret;
|
361
|
+
throw new Error('clientId not configured');
|
362
|
+
const clientSecret = that._oauth.clientSecret || process.env.OAUTH_CLIENT_SECRET || decrypted.clientSecret;
|
378
363
|
if (!clientSecret)
|
379
|
-
throw new Error(
|
364
|
+
throw new Error('clientSecret not configured');
|
380
365
|
const useAuthHeader = !!that._oauth.useAuthHeader;
|
381
366
|
let headers = {};
|
382
367
|
if (useAuthHeader) {
|
@@ -386,16 +371,16 @@ ${text}
|
|
386
371
|
};
|
387
372
|
}
|
388
373
|
const response = await fetch(that._oauth.tokenURL, {
|
389
|
-
method:
|
374
|
+
method: 'POST',
|
390
375
|
body: new URLSearchParams({
|
391
|
-
grant_type:
|
376
|
+
grant_type: 'refresh_token',
|
392
377
|
refresh_token: refreshToken,
|
393
378
|
client_id: clientId,
|
394
379
|
client_secret: clientSecret,
|
395
380
|
}),
|
396
381
|
headers: {
|
397
|
-
|
398
|
-
Accept:
|
382
|
+
'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8',
|
383
|
+
Accept: 'application/json',
|
399
384
|
...headers,
|
400
385
|
},
|
401
386
|
});
|
@@ -405,7 +390,7 @@ ${text}
|
|
405
390
|
return JSON.parse(text);
|
406
391
|
}
|
407
392
|
else {
|
408
|
-
throw new Error(
|
393
|
+
throw new Error('could not get refresh token ' + status + ' ' + text);
|
409
394
|
}
|
410
395
|
};
|
411
396
|
const theOAuth = decrypted.oauthResult
|
@@ -414,11 +399,11 @@ ${text}
|
|
414
399
|
start({
|
415
400
|
config: decrypted,
|
416
401
|
oauth: theOAuth,
|
417
|
-
getClient: (arg) => theOAuth ? theOAuth.getClient(arg) : new Fetcher({ ...arg }),
|
402
|
+
getClient: (arg) => (theOAuth ? theOAuth.getClient(arg) : new Fetcher({ ...arg })),
|
418
403
|
newTask: (name, data) => {
|
419
404
|
return new Promise((resolve, reject) => {
|
420
405
|
const packet = transport.newPacket({}, (ret) => (ret?.error ? reject(ret.error) : resolve(ret)), `_req-${cuid()}`);
|
421
|
-
packet.method(
|
406
|
+
packet.method('connector.task.new');
|
422
407
|
packet.args({
|
423
408
|
name,
|
424
409
|
a: data,
|
@@ -429,7 +414,7 @@ ${text}
|
|
429
414
|
updateTask: (id, data) => {
|
430
415
|
return new Promise((resolve, reject) => {
|
431
416
|
const packet = transport.newPacket({}, (ret) => (ret?.error ? reject(ret.error) : resolve(ret)), `_req-${cuid()}`);
|
432
|
-
packet.method(
|
417
|
+
packet.method('connector.task.update');
|
433
418
|
packet.args({
|
434
419
|
id,
|
435
420
|
a: data,
|
@@ -462,14 +447,14 @@ ${text}
|
|
462
447
|
});
|
463
448
|
process.exit(0);
|
464
449
|
};
|
465
|
-
process.on(
|
450
|
+
process.on('uncaughtException', (e) => {
|
466
451
|
console.log(e);
|
467
452
|
});
|
468
|
-
process.on(
|
453
|
+
process.on('unhandledRejection', (e) => {
|
469
454
|
console.log(e);
|
470
455
|
});
|
471
|
-
process.on(
|
472
|
-
process.on(
|
456
|
+
process.on('SIGTERM', term);
|
457
|
+
process.on('SIGINT', term);
|
473
458
|
await server.start();
|
474
459
|
}
|
475
460
|
}
|
@@ -1,12 +1,12 @@
|
|
1
1
|
"use strict";
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
-
const JWE = require(
|
3
|
+
const JWE = require('./index');
|
4
4
|
const main = async () => {
|
5
5
|
const jwe = new JWE({});
|
6
6
|
await jwe.newPair();
|
7
|
-
console.log(
|
7
|
+
console.log('private key');
|
8
8
|
console.log(await jwe.exportPrivateAsBase64());
|
9
|
-
console.log(
|
9
|
+
console.log('public key');
|
10
10
|
console.log(await jwe.exportPublicAsBase64());
|
11
11
|
};
|
12
12
|
setTimeout(() => null, 100);
|
@@ -1,9 +1,9 @@
|
|
1
1
|
"use strict";
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
-
const jose = require(
|
3
|
+
const jose = require('jose');
|
4
4
|
class JWE {
|
5
|
-
constructor({ algorithm =
|
6
|
-
this.issuer =
|
5
|
+
constructor({ algorithm = 'PS256' }) {
|
6
|
+
this.issuer = 'home.aloma.io';
|
7
7
|
this.algorithm = algorithm;
|
8
8
|
}
|
9
9
|
async newPair() {
|
@@ -17,11 +17,11 @@ class JWE {
|
|
17
17
|
}
|
18
18
|
async exportPrivateAsBase64() {
|
19
19
|
const pair = await this.exportPair();
|
20
|
-
return Buffer.from(pair.privateKey).toString(
|
20
|
+
return Buffer.from(pair.privateKey).toString('base64');
|
21
21
|
}
|
22
22
|
async exportPublicAsBase64() {
|
23
23
|
const pair = await this.exportPair();
|
24
|
-
return Buffer.from(pair.publicKey).toString(
|
24
|
+
return Buffer.from(pair.publicKey).toString('base64');
|
25
25
|
}
|
26
26
|
async importPair({ publicKey, privateKey, algorithm }) {
|
27
27
|
this.pair = {
|
@@ -31,18 +31,18 @@ class JWE {
|
|
31
31
|
}
|
32
32
|
async importBase64Pair({ publicKey, privateKey, algorithm }) {
|
33
33
|
this.importPair({
|
34
|
-
publicKey: Buffer.from(publicKey,
|
35
|
-
privateKey: Buffer.from(privateKey,
|
34
|
+
publicKey: Buffer.from(publicKey, 'base64').toString(),
|
35
|
+
privateKey: Buffer.from(privateKey, 'base64').toString(),
|
36
36
|
algorithm,
|
37
37
|
});
|
38
38
|
}
|
39
|
-
async encrypt(what, expiration =
|
39
|
+
async encrypt(what, expiration = '7d', audience, algorithm = 'RSA-OAEP-256') {
|
40
40
|
const item = new jose.EncryptJWT({ _data: { ...what } })
|
41
|
-
.setProtectedHeader({ alg: algorithm, enc:
|
41
|
+
.setProtectedHeader({ alg: algorithm, enc: 'A256GCM' })
|
42
42
|
.setIssuedAt()
|
43
43
|
.setIssuer(this.issuer)
|
44
44
|
.setAudience(audience);
|
45
|
-
if (expiration && expiration !==
|
45
|
+
if (expiration && expiration !== 'none')
|
46
46
|
item.setExpirationTime(expiration);
|
47
47
|
return await item.encrypt(this.pair.publicKey);
|
48
48
|
}
|
@@ -1,7 +1,7 @@
|
|
1
1
|
"use strict";
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
-
const C = require(
|
4
|
-
const JWE = require(
|
3
|
+
const C = require('./connection/constants.cjs');
|
4
|
+
const JWE = require('../util/jwe/index.cjs');
|
5
5
|
class Config {
|
6
6
|
constructor({ registrationToken, version, name, id, endpoint, wsEndpoint, privateKey, publicKey, introspect, configSchema, }) {
|
7
7
|
this._token = null;
|
@@ -18,17 +18,17 @@ class Config {
|
|
18
18
|
this._introspect = introspect;
|
19
19
|
this._configSchema = configSchema;
|
20
20
|
if (!registrationToken)
|
21
|
-
throw new Error(
|
21
|
+
throw new Error('empty registration token (set env.REGISTRATION_TOKEN)');
|
22
22
|
if (!endpoint)
|
23
|
-
throw new Error(
|
23
|
+
throw new Error('empty endpoint (set env.DEVICE_ENDPOINT)');
|
24
24
|
if (!wsEndpoint)
|
25
|
-
throw new Error(
|
25
|
+
throw new Error('empty registration token (set env.WEBSOCKET_ENDPOINT)');
|
26
26
|
if (!this._id || !this._version)
|
27
|
-
throw new Error(
|
27
|
+
throw new Error('need connector id and version');
|
28
28
|
}
|
29
29
|
async validateKeys(algorithm) {
|
30
30
|
if (!this._privateKey || !this._publicKey)
|
31
|
-
throw new Error(
|
31
|
+
throw new Error('need private and public key');
|
32
32
|
await this._jwe.importBase64Pair({
|
33
33
|
publicKey: this._publicKey,
|
34
34
|
privateKey: this._privateKey,
|
@@ -1,11 +1,11 @@
|
|
1
1
|
"use strict";
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
-
const AUTHORIZATION =
|
3
|
+
const AUTHORIZATION = 'Authorization';
|
4
4
|
module.exports = {
|
5
5
|
augmentRequest: (what, config) => {
|
6
6
|
what.headers = {
|
7
7
|
...what.headers,
|
8
|
-
|
8
|
+
'User-Agent': config.id() + '/' + config.version(),
|
9
9
|
};
|
10
10
|
what.headers[AUTHORIZATION] = `Connector ${config.token()}`;
|
11
11
|
return what;
|
@@ -13,7 +13,7 @@ module.exports = {
|
|
13
13
|
augmentRegistration: (what, config) => {
|
14
14
|
what.headers = {
|
15
15
|
...what.headers,
|
16
|
-
|
16
|
+
'User-Agent': config.id() + '/' + config.version(),
|
17
17
|
};
|
18
18
|
what.headers[AUTHORIZATION] = `Connector ${config.registrationToken()}`;
|
19
19
|
return what;
|
@@ -1,8 +1,8 @@
|
|
1
1
|
"use strict";
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
-
const fetch = require(
|
4
|
-
const { Registration } = require(
|
5
|
-
const C = require(
|
3
|
+
const fetch = require('node-fetch');
|
4
|
+
const { Registration } = require('./registration.cjs');
|
5
|
+
const C = require('./constants.cjs');
|
6
6
|
class Connection {
|
7
7
|
constructor({ config, onStart }) {
|
8
8
|
this.config = config;
|
@@ -11,10 +11,10 @@ class Connection {
|
|
11
11
|
async start() {
|
12
12
|
var local = this, config = local.config;
|
13
13
|
try {
|
14
|
-
const response = await fetch(config.url() +
|
15
|
-
method:
|
14
|
+
const response = await fetch(config.url() + 'connect', C.augmentRequest({
|
15
|
+
method: 'POST',
|
16
16
|
body: JSON.stringify({}),
|
17
|
-
headers: {
|
17
|
+
headers: { 'Content-Type': 'application/json' },
|
18
18
|
}, config));
|
19
19
|
if (response.status === 401) {
|
20
20
|
config.setToken(await new Registration(local.config).run());
|
@@ -39,10 +39,10 @@ class Connection {
|
|
39
39
|
}
|
40
40
|
async close() {
|
41
41
|
try {
|
42
|
-
await fetch(this.config.url() +
|
43
|
-
method:
|
42
|
+
await fetch(this.config.url() + 'disconnect', C.augmentRequest({
|
43
|
+
method: 'POST',
|
44
44
|
body: JSON.stringify({}),
|
45
|
-
headers: {
|
45
|
+
headers: { 'Content-Type': 'application/json' },
|
46
46
|
}, this.config));
|
47
47
|
}
|
48
48
|
catch (e) {
|
@@ -1,7 +1,7 @@
|
|
1
1
|
"use strict";
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
-
const fetch = require(
|
4
|
-
const C = require(
|
3
|
+
const fetch = require('node-fetch');
|
4
|
+
const C = require('./constants.cjs');
|
5
5
|
class Registration {
|
6
6
|
constructor(config) {
|
7
7
|
this.config = config;
|
@@ -11,21 +11,21 @@ class Registration {
|
|
11
11
|
const config = this.config;
|
12
12
|
const configSchema = config.configSchema();
|
13
13
|
const intro = await config.introspect();
|
14
|
-
const response = await fetch(config.url() +
|
15
|
-
method:
|
14
|
+
const response = await fetch(config.url() + 'register', C.augmentRegistration({
|
15
|
+
method: 'POST',
|
16
16
|
body: JSON.stringify({
|
17
|
-
deployment: process.env.DEPLOYMENT ||
|
17
|
+
deployment: process.env.DEPLOYMENT || '',
|
18
18
|
name: config.name(),
|
19
19
|
version: config.version(),
|
20
20
|
id: config.id(),
|
21
21
|
publicKey: config.publicKey(),
|
22
22
|
schema: { configSchema, introspect: intro },
|
23
23
|
}),
|
24
|
-
headers: {
|
24
|
+
headers: { 'Content-Type': 'application/json' },
|
25
25
|
}, config));
|
26
26
|
if (response.status === 200)
|
27
27
|
return (await response.json()).key;
|
28
|
-
throw new Error(
|
28
|
+
throw new Error('authentication failed');
|
29
29
|
}
|
30
30
|
}
|
31
31
|
module.exports = { Registration };
|
@@ -1,8 +1,8 @@
|
|
1
1
|
"use strict";
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
-
const WebSocket = require(
|
4
|
-
const { Connection } = require(
|
5
|
-
const { Transport } = require(
|
3
|
+
const WebSocket = require('ws');
|
4
|
+
const { Connection } = require('./connection/index.cjs');
|
5
|
+
const { Transport } = require('./transport/index.cjs');
|
6
6
|
class WebsocketConnector {
|
7
7
|
constructor({ config, onMessage, onConnect }) {
|
8
8
|
var local = this;
|
@@ -1,6 +1,6 @@
|
|
1
1
|
"use strict";
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
-
const WebSocket = require(
|
3
|
+
const WebSocket = require('ws');
|
4
4
|
class DurableWebsocket {
|
5
5
|
constructor({ endpoint, secret, onConnect, onMessage }) {
|
6
6
|
this.endpoint = endpoint;
|
@@ -28,7 +28,7 @@ class DurableWebsocket {
|
|
28
28
|
rejectUnauthorized: false,
|
29
29
|
headers: { Authorization: `Bearer ${local.secret}` },
|
30
30
|
}));
|
31
|
-
ws.on(
|
31
|
+
ws.on('open', () => {
|
32
32
|
local.connecting = false;
|
33
33
|
local.fails = 0;
|
34
34
|
var item;
|
@@ -37,15 +37,15 @@ class DurableWebsocket {
|
|
37
37
|
}
|
38
38
|
local.onConnect(local);
|
39
39
|
});
|
40
|
-
ws.on(
|
40
|
+
ws.on('message', (message) => {
|
41
41
|
setImmediate(() => local.onMessage(JSON.parse(message)));
|
42
42
|
});
|
43
|
-
ws.on(
|
43
|
+
ws.on('error', (message) => {
|
44
44
|
if (local.fails > 50)
|
45
|
-
console.log(
|
45
|
+
console.log('error:', message.message);
|
46
46
|
++local.fails;
|
47
47
|
});
|
48
|
-
ws.on(
|
48
|
+
ws.on('close', (message) => {
|
49
49
|
local.connecting = false;
|
50
50
|
if (!local.closed)
|
51
51
|
setTimeout(() => local.start(), 5000);
|
@@ -1,11 +1,11 @@
|
|
1
1
|
"use strict";
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
-
const fetch = require(
|
4
|
-
const C = require(
|
5
|
-
const cuid = require(
|
6
|
-
const { DurableWebsocket } = require(
|
7
|
-
const WebSocket = require(
|
8
|
-
const { Packet, Callback } = require(
|
3
|
+
const fetch = require('node-fetch');
|
4
|
+
const C = require('../connection/constants.cjs');
|
5
|
+
const cuid = require('@paralleldrive/cuid2').init({ length: 32 });
|
6
|
+
const { DurableWebsocket } = require('./durable.cjs');
|
7
|
+
const WebSocket = require('ws');
|
8
|
+
const { Packet, Callback } = require('./packet.cjs');
|
9
9
|
const cleanInterval = 45 * 1000;
|
10
10
|
const pingInterval = 30 * 1000;
|
11
11
|
class Transport {
|
@@ -38,7 +38,7 @@ class Transport {
|
|
38
38
|
local.ws.send(JSON.stringify({ p: packets }));
|
39
39
|
}
|
40
40
|
catch (e) {
|
41
|
-
console.log(
|
41
|
+
console.log('could not send packets ', e);
|
42
42
|
packets.forEach((packet) => local.packets.unshift(packet));
|
43
43
|
}
|
44
44
|
}
|
@@ -48,20 +48,20 @@ class Transport {
|
|
48
48
|
return;
|
49
49
|
local.close();
|
50
50
|
this.running = true;
|
51
|
-
const ws = (local.ws = new WebSocket(config.wsUrl(), [
|
52
|
-
ws.on(
|
53
|
-
console.log(
|
51
|
+
const ws = (local.ws = new WebSocket(config.wsUrl(), ['connector'], C.augmentRequest({ headers: {} }, config)));
|
52
|
+
ws.on('open', () => {
|
53
|
+
console.log('websocket connected');
|
54
54
|
local.connected = true;
|
55
55
|
local.pinger = setInterval(() => ws.ping(() => null), pingInterval);
|
56
56
|
local.onConnect(local);
|
57
57
|
});
|
58
|
-
ws.on(
|
58
|
+
ws.on('message', (message) => {
|
59
59
|
setTimeout(() => local.onMessages(JSON.parse(message)), 0);
|
60
60
|
});
|
61
|
-
ws.on(
|
62
|
-
console.log(
|
61
|
+
ws.on('error', (message) => {
|
62
|
+
console.log('error:', message);
|
63
63
|
});
|
64
|
-
ws.on(
|
64
|
+
ws.on('close', (message) => {
|
65
65
|
local.connected = false;
|
66
66
|
clearInterval(local.pinger);
|
67
67
|
if (local.running)
|
@@ -92,7 +92,7 @@ class Transport {
|
|
92
92
|
this.callbacks[packet.cb()].cb(packet.args());
|
93
93
|
}
|
94
94
|
catch (e) {
|
95
|
-
console.log(
|
95
|
+
console.log('error processing packet', e, packet);
|
96
96
|
}
|
97
97
|
finally {
|
98
98
|
delete this.callbacks[packet.cb()];
|
@@ -117,12 +117,12 @@ class Transport {
|
|
117
117
|
if (!cb)
|
118
118
|
return;
|
119
119
|
if (cb.created < then) {
|
120
|
-
console.log(
|
120
|
+
console.log('callback timeout', key);
|
121
121
|
try {
|
122
|
-
cb.cb({ error:
|
122
|
+
cb.cb({ error: 'timeout' });
|
123
123
|
}
|
124
124
|
catch (e) {
|
125
|
-
console.log(
|
125
|
+
console.log('error while callback', key, cb, e);
|
126
126
|
}
|
127
127
|
delete local.callbacks[key];
|
128
128
|
}
|
@@ -1,7 +1,7 @@
|
|
1
1
|
"use strict";
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
-
const fetch = require(
|
4
|
-
const cuid = require(
|
3
|
+
const fetch = require('node-fetch');
|
4
|
+
const cuid = require('@paralleldrive/cuid2').init({ length: 32 });
|
5
5
|
class Packet {
|
6
6
|
constructor(data = {}) {
|
7
7
|
this.data = data;
|
@@ -1,6 +1,6 @@
|
|
1
1
|
"use strict";
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
-
const { Packet, Callback } = require(
|
3
|
+
const { Packet, Callback } = require('./packet.cjs');
|
4
4
|
class Processor {
|
5
5
|
constructor({ transport, processPacket }) {
|
6
6
|
var local = this;
|
@@ -33,24 +33,24 @@ class Processor {
|
|
33
33
|
callbacks[packet.cb()](packet.args());
|
34
34
|
}
|
35
35
|
catch (e) {
|
36
|
-
console.log(
|
36
|
+
console.log('error in callback', callbacks[packet.cb()], packet);
|
37
37
|
}
|
38
38
|
delete local.transport.callbacks[packet.cb()];
|
39
39
|
}
|
40
40
|
else if (packet.event()) {
|
41
|
-
console.log(
|
41
|
+
console.log('handle event packet', packet);
|
42
42
|
}
|
43
43
|
else {
|
44
44
|
try {
|
45
45
|
const result = await local._processPacket(packet);
|
46
46
|
const reply = local.transport.newPacket({});
|
47
|
-
reply.method(
|
47
|
+
reply.method('connector.reply');
|
48
48
|
reply.cb(original.cb());
|
49
49
|
reply.args({ ...result });
|
50
50
|
local.transport.send(reply);
|
51
51
|
}
|
52
52
|
catch (e) {
|
53
|
-
console.log(
|
53
|
+
console.log('error processing packet', e, packet);
|
54
54
|
}
|
55
55
|
}
|
56
56
|
}
|
package/package.json
CHANGED
package/build/cli.d.mts
DELETED
package/build/cli.mjs
DELETED
@@ -1,93 +0,0 @@
|
|
1
|
-
#!/usr/bin/env node
|
2
|
-
import { Command } from "commander";
|
3
|
-
import fs from "node:fs";
|
4
|
-
import { fileURLToPath } from "node:url";
|
5
|
-
import path from "node:path";
|
6
|
-
import JWE from './internal/util/jwe/index.cjs';
|
7
|
-
import util from 'node:util';
|
8
|
-
import ChildProcess from 'node:child_process';
|
9
|
-
const exec = util.promisify(ChildProcess.exec);
|
10
|
-
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
11
|
-
const files = [
|
12
|
-
{ name: "index.mts", dir: "src/controller" },
|
13
|
-
{ name: "index.mts", dir: "src" },
|
14
|
-
{ name: "package.json", dir: "" },
|
15
|
-
{ name: "Containerfile", dir: "" },
|
16
|
-
{ name: "entrypoint.sh", dir: "" },
|
17
|
-
{ name: "tsconfig.json", dir: "" },
|
18
|
-
];
|
19
|
-
const extract = ({ target, name, connectorId }) => {
|
20
|
-
const source = `${__dirname}/../template/connector/`;
|
21
|
-
if (!fs.existsSync(source)) {
|
22
|
-
throw new Error(`source ${source} does not exist`);
|
23
|
-
}
|
24
|
-
files.forEach(({ name, dir }) => {
|
25
|
-
if (dir) {
|
26
|
-
fs.mkdirSync(`${target}/${dir}`, { recursive: true });
|
27
|
-
}
|
28
|
-
const content = fs.readFileSync(`${source}/${dir}/${name}`, {
|
29
|
-
encoding: "utf-8",
|
30
|
-
});
|
31
|
-
fs.writeFileSync(`${target}/${dir}/${name}`, content);
|
32
|
-
});
|
33
|
-
const content = JSON.parse(fs.readFileSync(`${target}/package.json`, { encoding: "utf-8" }));
|
34
|
-
content.name = name;
|
35
|
-
content.connectorId = connectorId;
|
36
|
-
fs.writeFileSync(`${target}/package.json`, JSON.stringify(content, null, 2));
|
37
|
-
fs.writeFileSync(`${target}/.gitignore`, `.DS_Store
|
38
|
-
node_modules
|
39
|
-
build
|
40
|
-
.env`);
|
41
|
-
};
|
42
|
-
const generateKeys = async ({ target }) => {
|
43
|
-
const jwe = new JWE({});
|
44
|
-
await jwe.newPair();
|
45
|
-
const priv = await jwe.exportPrivateAsBase64();
|
46
|
-
const pub = await jwe.exportPublicAsBase64();
|
47
|
-
const content = `REGISTRATION_TOKEN=
|
48
|
-
PRIVATE_KEY=${priv}
|
49
|
-
PUBLIC_KEY=${pub}
|
50
|
-
`;
|
51
|
-
fs.writeFileSync(`${target}/.env`, content);
|
52
|
-
};
|
53
|
-
const program = new Command();
|
54
|
-
program
|
55
|
-
.name("npx @aloma.io/integration-sdk")
|
56
|
-
.description("aloma.io integration sdk")
|
57
|
-
.version("0.8.0")
|
58
|
-
.showHelpAfterError();
|
59
|
-
program
|
60
|
-
.command("create")
|
61
|
-
.description("Create a new connector project")
|
62
|
-
.argument("<name>", "name of the project")
|
63
|
-
.requiredOption("--connector-id <id>", "id of the connector")
|
64
|
-
.action(async (name, options) => {
|
65
|
-
name = name.replace(/[\/\.]/gi, "");
|
66
|
-
if (!name)
|
67
|
-
throw new Error("name is empty");
|
68
|
-
const target = `${process.cwd()}/${name}`;
|
69
|
-
fs.mkdirSync(target);
|
70
|
-
console.log('Creating connector ...');
|
71
|
-
extract({ ...options, target, name });
|
72
|
-
console.log('Generating keys ...');
|
73
|
-
await generateKeys({ target });
|
74
|
-
console.log('Installing dependencies ...');
|
75
|
-
await exec(`cd ${target}; yarn`);
|
76
|
-
console.log('Building ...');
|
77
|
-
await exec(`cd ${target}; yarn build`);
|
78
|
-
console.log(`
|
79
|
-
Success!
|
80
|
-
|
81
|
-
1.) Add the connector to a workspace
|
82
|
-
2.) Edit ./${name}/.env and insert the registration token
|
83
|
-
3.) Start the connector with cd ./${name}/; yarn start`);
|
84
|
-
});
|
85
|
-
program
|
86
|
-
.command("build")
|
87
|
-
.description("Build the current connector project")
|
88
|
-
.action(async (str, options) => {
|
89
|
-
const { stdout, stderr } = await exec(`rm -rf build; mkdir -p build/controller; cp ./src/controller/index.mts ./build/controller/.controller-for-types.mts;`);
|
90
|
-
if (stdout)
|
91
|
-
console.log(stdout);
|
92
|
-
});
|
93
|
-
program.parse();
|