@aloma.io/integration-sdk 3.0.2 → 3.0.4
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 +1 -1
- package/build/builder/index.d.mts +1 -1
- package/build/builder/index.mjs +15 -11
- package/build/builder/runtime-context.d.mts +1 -1
- package/build/builder/runtime-context.mjs +10 -7
- package/build/builder/transform/index.mjs +18 -18
- package/build/cli.d.mts +2 -0
- package/build/cli.mjs +93 -0
- 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 +41 -30
- package/build/internal/index.cjs +86 -71
- 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/examples/hello-world/src/controller/index.mts +1 -1
- package/package.json +1 -1
- package/template/connector/src/controller/index.mts +1 -1
package/README.md
CHANGED
@@ -2,4 +2,4 @@
|
|
2
2
|
|
3
3
|
## Creating a new Connector
|
4
4
|
|
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`.
|
5
|
+
With the aloma integration SDK cli you can simply create a new connector via `npx @aloma.io/integration-sdk@latest 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,7 +10,9 @@ const notEmpty = (what, name) => {
|
|
10
10
|
return what;
|
11
11
|
};
|
12
12
|
export class Builder {
|
13
|
-
data = {
|
13
|
+
data = {
|
14
|
+
controller: "./build/controller/.controller-for-types.mts",
|
15
|
+
};
|
14
16
|
config(arg) {
|
15
17
|
this.data.config = arg;
|
16
18
|
return this;
|
@@ -27,17 +29,19 @@ export class Builder {
|
|
27
29
|
await this.parsePackageJson();
|
28
30
|
await this.discoverTypes();
|
29
31
|
// @ts-ignore
|
30
|
-
const Controller = (await import(__dirname +
|
32
|
+
const Controller = (await import(__dirname + "/../../../../../build/controller/index.mjs")).default;
|
31
33
|
return new RuntimeContext(new Controller(), this.data);
|
32
34
|
}
|
33
35
|
async parsePackageJson() {
|
34
36
|
const data = this.data;
|
35
|
-
const packageJson = JSON.parse(fs.readFileSync(__dirname +
|
36
|
-
|
37
|
-
|
37
|
+
const packageJson = JSON.parse(fs.readFileSync(__dirname + "/../../../../../package.json", {
|
38
|
+
encoding: "utf-8",
|
39
|
+
}));
|
40
|
+
notEmpty((data.id = packageJson.connectorId), "id");
|
41
|
+
notEmpty((data.version = packageJson.version), "version");
|
38
42
|
}
|
39
43
|
async discoverTypes() {
|
40
|
-
notEmpty(this.data.controller,
|
44
|
+
notEmpty(this.data.controller, "controller");
|
41
45
|
const content = fs.readFileSync(this.data.controller);
|
42
46
|
const { text, methods } = parseTypes(this.data.controller);
|
43
47
|
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,7 +19,12 @@ export default class RuntimeContext {
|
|
19
19
|
});
|
20
20
|
const configuration = connector.configure().config(data.config || {});
|
21
21
|
const resolvers = {};
|
22
|
-
const methods = [
|
22
|
+
const methods = [
|
23
|
+
...data.methods,
|
24
|
+
"__endpoint",
|
25
|
+
"__configQuery",
|
26
|
+
"__default",
|
27
|
+
];
|
23
28
|
methods.forEach((method) => {
|
24
29
|
resolvers[method] = async (args) => {
|
25
30
|
if (!methods.includes(method))
|
@@ -27,9 +32,7 @@ export default class RuntimeContext {
|
|
27
32
|
return controller[method](args);
|
28
33
|
};
|
29
34
|
});
|
30
|
-
configuration
|
31
|
-
.types(data.types)
|
32
|
-
.resolvers(resolvers);
|
35
|
+
configuration.types(data.types).resolvers(resolvers);
|
33
36
|
if (data.options?.endpoint?.enabled) {
|
34
37
|
configuration.endpoint((arg) => controller.__endpoint(arg));
|
35
38
|
}
|
@@ -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) => {
|
package/build/cli.d.mts
ADDED
package/build/cli.mjs
ADDED
@@ -0,0 +1,93 @@
|
|
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();
|
@@ -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,33 +110,44 @@ class Dispatcher {
|
|
110
110
|
if (!Array.isArray(query))
|
111
111
|
query = [query];
|
112
112
|
query = query
|
113
|
-
.filter((what) => !!what?.trim() &&
|
113
|
+
.filter((what) => !!what?.trim() &&
|
114
|
+
![
|
115
|
+
"constructor",
|
116
|
+
"__proto__",
|
117
|
+
"toString",
|
118
|
+
"toSource",
|
119
|
+
"prototype",
|
120
|
+
].includes(what))
|
114
121
|
.slice(0, 20);
|
115
122
|
const method = resolveMethod(query);
|
116
123
|
if (!method && !_resolvers.__default)
|
117
124
|
throw new Error(`${query} not found`);
|
118
|
-
return method
|
125
|
+
return method
|
126
|
+
? method(variables)
|
127
|
+
: _resolvers.__default(variables ? { ...variables, __method: query } : variables);
|
119
128
|
};
|
120
129
|
const introspect = () => local._types;
|
121
130
|
const configSchema = () => local._config;
|
122
131
|
const processPacket = async (packet) => {
|
123
132
|
switch (packet.method()) {
|
124
|
-
case
|
133
|
+
case "connector.introspect":
|
125
134
|
const intro = await introspect({});
|
126
135
|
return { configSchema: local._config, introspect: intro };
|
127
|
-
case
|
136
|
+
case "connector.start-oauth":
|
128
137
|
return await local.startOAuth(packet.args());
|
129
|
-
case
|
138
|
+
case "connector.finish-oauth":
|
130
139
|
return await local.finishOAuth(packet.args());
|
131
|
-
case
|
140
|
+
case "connector.query":
|
132
141
|
const ret = await execute(packet.args());
|
133
|
-
return typeof ret ===
|
134
|
-
|
142
|
+
return typeof ret === "object" && !Array.isArray(ret)
|
143
|
+
? ret
|
144
|
+
: { [packet.args().query]: ret };
|
145
|
+
case "connector.set-config":
|
135
146
|
await local.onConfig({ ...packet.args().secrets });
|
136
147
|
return;
|
137
148
|
}
|
138
149
|
console.dir(packet, { depth: null });
|
139
|
-
throw new Error(
|
150
|
+
throw new Error("cannot handle packet");
|
140
151
|
};
|
141
152
|
return {
|
142
153
|
introspect,
|