@hasna/connectors 1.3.45 → 1.4.0
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 +25 -10
- package/bin/index.js +1362 -11796
- package/bin/mcp.js +751 -10328
- package/bin/serve.js +2252 -11829
- package/connectors/cloudflare-workers/.env.example +5 -0
- package/connectors/cloudflare-workers/AGENTS.md +11 -0
- package/connectors/cloudflare-workers/CLAUDE.md +11 -0
- package/connectors/cloudflare-workers/README.md +45 -0
- package/connectors/cloudflare-workers/package.json +47 -0
- package/connectors/cloudflare-workers/src/api/client.test.ts +144 -0
- package/connectors/cloudflare-workers/src/api/client.ts +386 -0
- package/connectors/cloudflare-workers/src/api/index.ts +1 -0
- package/connectors/cloudflare-workers/src/cli/index.ts +206 -0
- package/connectors/cloudflare-workers/src/index.ts +16 -0
- package/connectors/cloudflare-workers/src/types/index.ts +53 -0
- package/connectors/cloudflare-workers/src/utils/config.ts +61 -0
- package/connectors/cloudflare-workers/src/utils/output.ts +26 -0
- package/connectors/cloudflare-workers/tsconfig.build.json +4 -0
- package/connectors/cloudflare-workers/tsconfig.json +14 -0
- package/connectors/tidio/.env.example +3 -2
- package/connectors/tidio/CLAUDE.md +21 -96
- package/connectors/tidio/README.md +22 -18
- package/connectors/tidio/package.json +4 -2
- package/connectors/tidio/src/api/client.ts +26 -15
- package/connectors/tidio/src/api/index.ts +185 -128
- package/connectors/tidio/src/api/tidio.test.ts +175 -44
- package/connectors/tidio/src/cli/index.ts +154 -388
- package/connectors/tidio/src/index.ts +5 -3
- package/connectors/tidio/src/types/index.ts +135 -82
- package/connectors/tidio/src/utils/config.ts +90 -44
- package/connectors/wandb/.env.example +7 -0
- package/connectors/wandb/AGENTS.md +43 -0
- package/connectors/wandb/CLAUDE.md +67 -0
- package/connectors/wandb/README.md +65 -0
- package/connectors/wandb/package.json +52 -0
- package/connectors/wandb/src/api/client.test.ts +116 -0
- package/connectors/wandb/src/api/client.ts +83 -0
- package/connectors/wandb/src/api/graphql.ts +9 -0
- package/connectors/wandb/src/api/index.ts +36 -0
- package/connectors/wandb/src/api/projects.ts +36 -0
- package/connectors/wandb/src/api/viewer.ts +20 -0
- package/connectors/wandb/src/cli/index.ts +265 -0
- package/connectors/wandb/src/index.ts +22 -0
- package/connectors/wandb/src/types/index.ts +75 -0
- package/connectors/wandb/src/utils/config.ts +164 -0
- package/connectors/wandb/src/utils/output.ts +119 -0
- package/connectors/wandb/tsconfig.json +16 -0
- package/connectors/weights-biases/.env.example +7 -0
- package/connectors/weights-biases/CLAUDE.md +65 -0
- package/connectors/weights-biases/README.md +62 -0
- package/connectors/weights-biases/package.json +53 -0
- package/connectors/weights-biases/src/api/client.test.ts +46 -0
- package/connectors/weights-biases/src/api/client.ts +119 -0
- package/connectors/weights-biases/src/api/events.ts +18 -0
- package/connectors/weights-biases/src/api/index.ts +56 -0
- package/connectors/weights-biases/src/api/runs.ts +28 -0
- package/connectors/weights-biases/src/api/search.ts +10 -0
- package/connectors/weights-biases/src/cli/index.ts +289 -0
- package/connectors/weights-biases/src/index.ts +19 -0
- package/connectors/weights-biases/src/types/index.ts +92 -0
- package/connectors/weights-biases/src/utils/config.ts +168 -0
- package/connectors/weights-biases/src/utils/output.ts +116 -0
- package/connectors/weights-biases/tsconfig.json +16 -0
- package/connectors/x/src/api/oauth.test.ts +205 -0
- package/connectors/zoominfo/.env.example +4 -0
- package/connectors/zoominfo/AGENTS.md +26 -0
- package/connectors/zoominfo/CLAUDE.md +20 -0
- package/connectors/zoominfo/README.md +69 -0
- package/connectors/zoominfo/package.json +52 -0
- package/connectors/zoominfo/src/api/client.test.ts +140 -0
- package/connectors/zoominfo/src/api/client.ts +228 -0
- package/connectors/zoominfo/src/api/index.ts +1 -0
- package/connectors/zoominfo/src/cli/index.ts +179 -0
- package/connectors/zoominfo/src/index.ts +3 -0
- package/connectors/zoominfo/src/types/index.ts +39 -0
- package/connectors/zoominfo/src/utils/config.ts +61 -0
- package/connectors/zoominfo/src/utils/output.ts +27 -0
- package/connectors/zoominfo/tsconfig.json +20 -0
- package/connectors/zotero/.env.example +7 -0
- package/connectors/zotero/.npmrc.example +2 -0
- package/connectors/zotero/AGENTS.md +40 -0
- package/connectors/zotero/CLAUDE.md +69 -0
- package/connectors/zotero/README.md +91 -0
- package/connectors/zotero/package.json +43 -0
- package/connectors/zotero/src/api/attachments.ts +130 -0
- package/connectors/zotero/src/api/client.test.ts +166 -0
- package/connectors/zotero/src/api/client.ts +169 -0
- package/connectors/zotero/src/api/collections.ts +26 -0
- package/connectors/zotero/src/api/index.ts +45 -0
- package/connectors/zotero/src/api/items.ts +64 -0
- package/connectors/zotero/src/cli/index.ts +386 -0
- package/connectors/zotero/src/index.ts +28 -0
- package/connectors/zotero/src/types/index.ts +129 -0
- package/connectors/zotero/src/utils/config.ts +245 -0
- package/connectors/zotero/src/utils/output.ts +119 -0
- package/connectors/zotero/tsconfig.json +16 -0
- package/connectors/zymbly/.env.example +2 -0
- package/connectors/zymbly/AGENTS.md +11 -0
- package/connectors/zymbly/CLAUDE.md +5 -0
- package/connectors/zymbly/README.md +35 -0
- package/connectors/zymbly/package.json +52 -0
- package/connectors/zymbly/src/api/client.test.ts +110 -0
- package/connectors/zymbly/src/api/client.ts +166 -0
- package/connectors/zymbly/src/api/index.ts +1 -0
- package/connectors/zymbly/src/cli/index.ts +156 -0
- package/connectors/zymbly/src/index.ts +12 -0
- package/connectors/zymbly/src/types/index.ts +34 -0
- package/connectors/zymbly/src/utils/config.ts +52 -0
- package/connectors/zymbly/src/utils/output.ts +17 -0
- package/connectors/zymbly/tsconfig.json +13 -0
- package/dist/db/database.d.ts +2 -1
- package/dist/db/sqlite-adapter.d.ts +43 -0
- package/dist/index.js +172 -9653
- package/dist/lib/compact-output.d.ts +40 -0
- package/dist/mcp/tools/jobs.d.ts +32 -0
- package/dist/mcp/tools/jobs.test.d.ts +1 -0
- package/dist/no-cloud-boundary.test.d.ts +1 -0
- package/package.json +3 -3
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
import { readFileSync } from "node:fs";
|
|
3
|
+
import { Command } from "commander";
|
|
4
|
+
import { CloudflareWorkers } from "../api";
|
|
5
|
+
import type { HttpMethod, JsonObject, JsonValue, OutputFormat, QueryParams, QueryValue } from "../types";
|
|
6
|
+
import { clearConfig, getAccountId, getApiToken, getBaseUrl, loadConfig, setAccountId, setApiToken, setBaseUrl } from "../utils/config";
|
|
7
|
+
import { error, info, print, success } from "../utils/output";
|
|
8
|
+
|
|
9
|
+
const CONNECTOR_NAME = "connect-cloudflare-workers";
|
|
10
|
+
const VERSION = "0.0.1";
|
|
11
|
+
|
|
12
|
+
const program = new Command();
|
|
13
|
+
|
|
14
|
+
program
|
|
15
|
+
.name(CONNECTOR_NAME)
|
|
16
|
+
.description("Cloudflare Workers REST API CLI")
|
|
17
|
+
.version(VERSION)
|
|
18
|
+
.option("-f, --format <format>", "Output format (json, pretty)", "pretty")
|
|
19
|
+
.option("--api-token <token>", "Cloudflare API token")
|
|
20
|
+
.option("--account-id <id>", "Cloudflare account ID")
|
|
21
|
+
.option("--base-url <url>", "Cloudflare API base URL");
|
|
22
|
+
|
|
23
|
+
function globalOptions(): Record<string, unknown> {
|
|
24
|
+
return program.opts() as Record<string, unknown>;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function optionString(source: Record<string, unknown>, key: string): string | undefined {
|
|
28
|
+
const value = source[key];
|
|
29
|
+
return typeof value === "string" ? value : undefined;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function getFormat(): OutputFormat {
|
|
33
|
+
return (optionString(globalOptions(), "format") || "pretty") as OutputFormat;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function client(): CloudflareWorkers {
|
|
37
|
+
const opts = globalOptions();
|
|
38
|
+
return new CloudflareWorkers({
|
|
39
|
+
apiToken: optionString(opts, "apiToken") || getApiToken(),
|
|
40
|
+
accountId: optionString(opts, "accountId") || getAccountId(),
|
|
41
|
+
baseUrl: optionString(opts, "baseUrl") || getBaseUrl(),
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function parseJsonValue(value: string | undefined, label: string, fallback: JsonValue | undefined): JsonValue | undefined {
|
|
46
|
+
if (!value) return fallback;
|
|
47
|
+
try {
|
|
48
|
+
return JSON.parse(value) as JsonValue;
|
|
49
|
+
} catch (err) {
|
|
50
|
+
throw new Error(`Invalid ${label}: ${err instanceof Error ? err.message : String(err)}`);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function parseJsonObject(value: string | undefined, label: string, fallback: JsonObject = {}): JsonObject {
|
|
55
|
+
const parsed = parseJsonValue(value, label, fallback);
|
|
56
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) throw new Error(`${label} must be a JSON object`);
|
|
57
|
+
return parsed as JsonObject;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function optionalJsonObject(value: string | undefined, label: string): JsonObject | undefined {
|
|
61
|
+
if (!value) return undefined;
|
|
62
|
+
return parseJsonObject(value, label);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function toQueryValue(value: unknown, label: string): QueryValue | QueryValue[] {
|
|
66
|
+
if (value === undefined || value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean") return value as QueryValue;
|
|
67
|
+
if (Array.isArray(value)) {
|
|
68
|
+
for (const item of value) {
|
|
69
|
+
if (item !== null && typeof item !== "string" && typeof item !== "number" && typeof item !== "boolean") {
|
|
70
|
+
throw new Error(`${label} array values must be string, number, boolean, or null`);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return value as QueryValue[];
|
|
74
|
+
}
|
|
75
|
+
throw new Error(`${label} must be string, number, boolean, array, null, or undefined`);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function params(source: Record<string, unknown>): QueryParams {
|
|
79
|
+
const parsed = parseJsonObject(optionString(source, "params"), "params", {});
|
|
80
|
+
const output: QueryParams = {};
|
|
81
|
+
for (const [key, value] of Object.entries(parsed)) output[key] = toQueryValue(value, `params.${key}`);
|
|
82
|
+
return output;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function body(source: Record<string, unknown>): JsonObject {
|
|
86
|
+
return parseJsonObject(optionString(source, "body"), "body");
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function bodyValue(source: Record<string, unknown>): JsonValue {
|
|
90
|
+
const parsed = parseJsonValue(optionString(source, "body"), "body", undefined);
|
|
91
|
+
if (parsed === undefined) throw new Error("body is required");
|
|
92
|
+
return parsed;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function scriptBody(source: Record<string, unknown>): string | Uint8Array {
|
|
96
|
+
const file = optionString(source, "file");
|
|
97
|
+
if (file) return readFileSync(file);
|
|
98
|
+
const text = optionString(source, "text");
|
|
99
|
+
if (text !== undefined) return text;
|
|
100
|
+
throw new Error("upload-script requires --file or --text");
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function method(value: unknown): HttpMethod {
|
|
104
|
+
const input = typeof value === "string" ? value.toUpperCase() : "GET";
|
|
105
|
+
if (!["GET", "POST", "PUT", "PATCH", "DELETE"].includes(input)) throw new Error("method must be one of GET, POST, PUT, PATCH, DELETE");
|
|
106
|
+
return input as HttpMethod;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
async function run(action: () => Promise<unknown>): Promise<void> {
|
|
110
|
+
try {
|
|
111
|
+
print(await action(), getFormat());
|
|
112
|
+
} catch (err) {
|
|
113
|
+
error(err instanceof Error ? err.message : String(err));
|
|
114
|
+
process.exit(1);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const configCmd = program.command("config").description("Manage CLI configuration");
|
|
119
|
+
|
|
120
|
+
configCmd.command("set-token <apiToken>").description("Store a Cloudflare API token").action((apiToken: string) => {
|
|
121
|
+
setApiToken(apiToken);
|
|
122
|
+
success("API token saved");
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
configCmd.command("set-account <accountId>").description("Store a Cloudflare account ID").action((accountId: string) => {
|
|
126
|
+
setAccountId(accountId);
|
|
127
|
+
success("Account ID saved");
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
configCmd.command("set-base-url <baseUrl>").description("Store the Cloudflare API base URL").action((baseUrl: string) => {
|
|
131
|
+
setBaseUrl(baseUrl);
|
|
132
|
+
success(`Base URL set to ${baseUrl}`);
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
configCmd.command("show").description("Show current configuration").action(() => {
|
|
136
|
+
const api = client();
|
|
137
|
+
const stored = loadConfig();
|
|
138
|
+
info(`API token: ${getApiToken() ? "configured" : "not set"}`);
|
|
139
|
+
info(`Account ID: ${getAccountId() ? "configured" : "not set"}`);
|
|
140
|
+
info(`Base URL: ${api.getBaseUrl()}`);
|
|
141
|
+
if (Object.keys(stored).length > 0) info("Stored config file is present");
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
configCmd.command("clear").description("Clear saved configuration").action(() => {
|
|
145
|
+
clearConfig();
|
|
146
|
+
success("Configuration cleared");
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
program.command("list-scripts").description("List Workers scripts").option("--params <json>", "Query parameters JSON").action((opts: Record<string, unknown>) => run(() => client().listScripts(params(opts))));
|
|
150
|
+
program.command("get-script <scriptName>").description("Get Workers script metadata").action((scriptName: string) => run(() => client().getScript(scriptName)));
|
|
151
|
+
program.command("script-content <scriptName>").description("Get Workers script source text").action((scriptName: string) => run(() => client().getScriptContent(scriptName)));
|
|
152
|
+
program.command("upload-script <scriptName>").description("Upload a Workers script as multipart form data").option("--file <path>", "Read script body from file").option("--text <value>", "Use text as script body").option("--metadata <json>", "Worker metadata JSON").option("--filename <name>", "Script part filename").option("--content-type <type>", "Script Content-Type").action((scriptName: string, opts: Record<string, unknown>) => run(() => client().uploadScript(scriptName, scriptBody(opts), {
|
|
153
|
+
metadata: optionalJsonObject(optionString(opts, "metadata"), "metadata"),
|
|
154
|
+
filename: optionString(opts, "filename"),
|
|
155
|
+
contentType: optionString(opts, "contentType"),
|
|
156
|
+
})));
|
|
157
|
+
program.command("delete-script <scriptName>").description("Delete a Workers script").action((scriptName: string) => run(() => client().deleteScript(scriptName)));
|
|
158
|
+
|
|
159
|
+
program.command("get-settings <scriptName>").description("Get script settings").action((scriptName: string) => run(() => client().getScriptSettings(scriptName)));
|
|
160
|
+
program.command("update-settings <scriptName>").description("Patch script settings").requiredOption("--body <json>", "Settings JSON body").action((scriptName: string, opts: Record<string, unknown>) => run(() => client().updateScriptSettings(scriptName, body(opts))));
|
|
161
|
+
program.command("list-deployments <scriptName>").description("List script deployments").action((scriptName: string) => run(() => client().listDeployments(scriptName)));
|
|
162
|
+
program.command("create-deployment <scriptName>").description("Create a script deployment").requiredOption("--body <json>", "Deployment JSON body").action((scriptName: string, opts: Record<string, unknown>) => run(() => client().createDeployment(scriptName, body(opts))));
|
|
163
|
+
program.command("list-versions <scriptName>").description("List script versions").action((scriptName: string) => run(() => client().listVersions(scriptName)));
|
|
164
|
+
program.command("get-version <scriptName> <versionId>").description("Get a script version").action((scriptName: string, versionId: string) => run(() => client().getVersion(scriptName, versionId)));
|
|
165
|
+
program.command("list-secrets <scriptName>").description("List script secrets").action((scriptName: string) => run(() => client().listSecrets(scriptName)));
|
|
166
|
+
program.command("put-secret <scriptName>").description("Create or update a script secret").requiredOption("--body <json>", "Secret JSON body").action((scriptName: string, opts: Record<string, unknown>) => run(() => client().putSecret(scriptName, body(opts))));
|
|
167
|
+
program.command("delete-secret <scriptName> <secretName>").description("Delete a script secret").action((scriptName: string, secretName: string) => run(() => client().deleteSecret(scriptName, secretName)));
|
|
168
|
+
program.command("get-schedules <scriptName>").description("Get script cron schedules").action((scriptName: string) => run(() => client().getSchedules(scriptName)));
|
|
169
|
+
program.command("put-schedules <scriptName>").description("Replace script cron schedules").requiredOption("--body <json>", "Schedules JSON body").action((scriptName: string, opts: Record<string, unknown>) => run(() => client().putSchedules(scriptName, body(opts))));
|
|
170
|
+
program.command("create-tail <scriptName>").description("Create a Workers tail").action((scriptName: string) => run(() => client().createTail(scriptName)));
|
|
171
|
+
program.command("delete-tail <scriptName> <tailId>").description("Delete a Workers tail").action((scriptName: string, tailId: string) => run(() => client().deleteTail(scriptName, tailId)));
|
|
172
|
+
|
|
173
|
+
program.command("get-account-subdomain").description("Get the account Workers subdomain").action(() => run(() => client().getAccountSubdomain()));
|
|
174
|
+
program.command("update-account-subdomain").description("Update the account Workers subdomain").requiredOption("--body <json>", "Subdomain JSON body").action((opts: Record<string, unknown>) => run(() => client().updateAccountSubdomain(body(opts))));
|
|
175
|
+
program.command("get-script-subdomain <scriptName>").description("Get a script subdomain setting").action((scriptName: string) => run(() => client().getScriptSubdomain(scriptName)));
|
|
176
|
+
program.command("update-script-subdomain <scriptName>").description("Update a script subdomain setting").requiredOption("--body <json>", "Script subdomain JSON body").action((scriptName: string, opts: Record<string, unknown>) => run(() => client().updateScriptSubdomain(scriptName, body(opts))));
|
|
177
|
+
|
|
178
|
+
program.command("list-routes <zoneId>").description("List zone Workers routes").action((zoneId: string) => run(() => client().listRoutes(zoneId)));
|
|
179
|
+
program.command("get-route <zoneId> <routeId>").description("Get a zone Workers route").action((zoneId: string, routeId: string) => run(() => client().getRoute(zoneId, routeId)));
|
|
180
|
+
program.command("create-route <zoneId>").description("Create a zone Workers route").requiredOption("--body <json>", "Route JSON body").action((zoneId: string, opts: Record<string, unknown>) => run(() => client().createRoute(zoneId, body(opts))));
|
|
181
|
+
program.command("update-route <zoneId> <routeId>").description("Update a zone Workers route").requiredOption("--body <json>", "Route JSON body").action((zoneId: string, routeId: string, opts: Record<string, unknown>) => run(() => client().updateRoute(zoneId, routeId, body(opts))));
|
|
182
|
+
program.command("delete-route <zoneId> <routeId>").description("Delete a zone Workers route").action((zoneId: string, routeId: string) => run(() => client().deleteRoute(zoneId, routeId)));
|
|
183
|
+
|
|
184
|
+
program.command("get-account-settings").description("Get Workers account settings").action(() => run(() => client().getAccountSettings()));
|
|
185
|
+
program.command("update-account-settings").description("Patch Workers account settings").requiredOption("--body <json>", "Account settings JSON body").action((opts: Record<string, unknown>) => run(() => client().updateAccountSettings(body(opts))));
|
|
186
|
+
|
|
187
|
+
program.command("list-beta-workers").description("List beta Workers").option("--params <json>", "Query parameters JSON").action((opts: Record<string, unknown>) => run(() => client().listBetaWorkers(params(opts))));
|
|
188
|
+
program.command("create-beta-worker").description("Create a beta Worker").requiredOption("--body <json>", "Beta Worker JSON body").action((opts: Record<string, unknown>) => run(() => client().createBetaWorker(body(opts))));
|
|
189
|
+
program.command("get-beta-worker <workerId>").description("Get a beta Worker").action((workerId: string) => run(() => client().getBetaWorker(workerId)));
|
|
190
|
+
program.command("delete-beta-worker <workerId>").description("Delete a beta Worker").action((workerId: string) => run(() => client().deleteBetaWorker(workerId)));
|
|
191
|
+
program.command("list-beta-versions <workerId>").description("List beta Worker versions").action((workerId: string) => run(() => client().listBetaVersions(workerId)));
|
|
192
|
+
program.command("create-beta-version <workerId>").description("Create a beta Worker version").requiredOption("--body <json>", "Beta version JSON body").action((workerId: string, opts: Record<string, unknown>) => run(() => client().createBetaVersion(workerId, body(opts))));
|
|
193
|
+
program.command("get-beta-version <workerId> <versionId>").description("Get a beta Worker version").action((workerId: string, versionId: string) => run(() => client().getBetaVersion(workerId, versionId)));
|
|
194
|
+
|
|
195
|
+
program
|
|
196
|
+
.command("raw <path>")
|
|
197
|
+
.description("Run a constrained raw Cloudflare Workers API request")
|
|
198
|
+
.option("-X, --method <method>", "HTTP method", "GET")
|
|
199
|
+
.option("--params <json>", "Query parameters JSON")
|
|
200
|
+
.option("--body <json>", "Request JSON body")
|
|
201
|
+
.action((path: string, opts: Record<string, unknown>) => run(() => client().rawRequest(method(opts.method), path, {
|
|
202
|
+
query: params(opts),
|
|
203
|
+
body: optionString(opts, "body") ? bodyValue(opts) : undefined,
|
|
204
|
+
})));
|
|
205
|
+
|
|
206
|
+
program.parse();
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export { CloudflareWorkers, CloudflareWorkersClient } from "./api";
|
|
2
|
+
export type {
|
|
3
|
+
CloudflareWorkersConfig,
|
|
4
|
+
CloudflareWorkersRawResponse,
|
|
5
|
+
CloudflareWorkersRequestOptions,
|
|
6
|
+
HttpMethod,
|
|
7
|
+
JsonObject,
|
|
8
|
+
JsonPrimitive,
|
|
9
|
+
JsonValue,
|
|
10
|
+
OutputFormat,
|
|
11
|
+
QueryParams,
|
|
12
|
+
QueryValue,
|
|
13
|
+
RequestBody,
|
|
14
|
+
ResponseType,
|
|
15
|
+
} from "./types";
|
|
16
|
+
export { CloudflareWorkersApiError } from "./types";
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
export type JsonPrimitive = string | number | boolean | null;
|
|
2
|
+
export type JsonValue = JsonPrimitive | JsonObject | JsonValue[];
|
|
3
|
+
|
|
4
|
+
export interface JsonObject {
|
|
5
|
+
[key: string]: JsonValue | undefined;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export type OutputFormat = "json" | "pretty";
|
|
9
|
+
export type HttpMethod = "GET" | "POST" | "PUT" | "PATCH" | "DELETE";
|
|
10
|
+
|
|
11
|
+
export type QueryPrimitive = string | number | boolean;
|
|
12
|
+
export type QueryValue = QueryPrimitive | Date | null | undefined;
|
|
13
|
+
|
|
14
|
+
export interface QueryParams {
|
|
15
|
+
[key: string]: QueryValue | QueryValue[];
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export type RequestBody = JsonValue | string | Uint8Array | ArrayBuffer | Blob | FormData;
|
|
19
|
+
export type ResponseType = "json" | "text" | "arrayBuffer";
|
|
20
|
+
|
|
21
|
+
export interface CloudflareWorkersConfig {
|
|
22
|
+
apiToken?: string;
|
|
23
|
+
accountId?: string;
|
|
24
|
+
baseUrl?: string;
|
|
25
|
+
timeoutMs?: number;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface CloudflareWorkersRawResponse {
|
|
29
|
+
status: number;
|
|
30
|
+
headers: Record<string, string>;
|
|
31
|
+
body: ArrayBuffer;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export interface CloudflareWorkersRequestOptions {
|
|
35
|
+
method?: HttpMethod;
|
|
36
|
+
query?: QueryParams;
|
|
37
|
+
body?: RequestBody;
|
|
38
|
+
headers?: Record<string, string>;
|
|
39
|
+
rawBody?: boolean;
|
|
40
|
+
responseType?: ResponseType;
|
|
41
|
+
signal?: AbortSignal;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export class CloudflareWorkersApiError extends Error {
|
|
45
|
+
constructor(
|
|
46
|
+
message: string,
|
|
47
|
+
readonly status?: number,
|
|
48
|
+
readonly details?: unknown,
|
|
49
|
+
) {
|
|
50
|
+
super(message);
|
|
51
|
+
this.name = "CloudflareWorkersApiError";
|
|
52
|
+
}
|
|
53
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { homedir } from "node:os";
|
|
3
|
+
import { dirname, join } from "node:path";
|
|
4
|
+
|
|
5
|
+
interface StoredConfig {
|
|
6
|
+
apiToken?: string;
|
|
7
|
+
accountId?: string;
|
|
8
|
+
baseUrl?: string;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const configPath = join(homedir(), ".hasna", "connectors", "cloudflare-workers.json");
|
|
12
|
+
|
|
13
|
+
function readConfig(): StoredConfig {
|
|
14
|
+
if (!existsSync(configPath)) return {};
|
|
15
|
+
try {
|
|
16
|
+
return JSON.parse(readFileSync(configPath, "utf8")) as StoredConfig;
|
|
17
|
+
} catch {
|
|
18
|
+
return {};
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function writeConfig(config: StoredConfig): void {
|
|
23
|
+
mkdirSync(dirname(configPath), { recursive: true });
|
|
24
|
+
writeFileSync(configPath, JSON.stringify(config, null, 2));
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function getConfigPath(): string {
|
|
28
|
+
return configPath;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function getApiToken(): string | undefined {
|
|
32
|
+
return process.env.CLOUDFLARE_WORKERS_API_TOKEN || process.env.CLOUDFLARE_API_TOKEN || readConfig().apiToken;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function setApiToken(apiToken: string): void {
|
|
36
|
+
writeConfig({ ...readConfig(), apiToken });
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function getAccountId(): string | undefined {
|
|
40
|
+
return process.env.CLOUDFLARE_WORKERS_ACCOUNT_ID || process.env.CLOUDFLARE_ACCOUNT_ID || readConfig().accountId;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export function setAccountId(accountId: string): void {
|
|
44
|
+
writeConfig({ ...readConfig(), accountId });
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export function getBaseUrl(): string | undefined {
|
|
48
|
+
return process.env.CLOUDFLARE_WORKERS_BASE_URL || readConfig().baseUrl;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export function setBaseUrl(baseUrl: string): void {
|
|
52
|
+
writeConfig({ ...readConfig(), baseUrl });
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function loadConfig(): StoredConfig {
|
|
56
|
+
return readConfig();
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export function clearConfig(): void {
|
|
60
|
+
if (existsSync(configPath)) rmSync(configPath);
|
|
61
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import chalk from "chalk";
|
|
2
|
+
import type { OutputFormat } from "../types";
|
|
3
|
+
|
|
4
|
+
export function print(data: unknown, format: OutputFormat = "pretty"): void {
|
|
5
|
+
if (format === "json") {
|
|
6
|
+
console.log(JSON.stringify(data, null, 2));
|
|
7
|
+
return;
|
|
8
|
+
}
|
|
9
|
+
if (typeof data === "string") {
|
|
10
|
+
console.log(data);
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
console.log(JSON.stringify(data, null, 2));
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function success(message: string): void {
|
|
17
|
+
console.log(chalk.green(message));
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function info(message: string): void {
|
|
21
|
+
console.log(chalk.cyan(message));
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function error(message: string): void {
|
|
25
|
+
console.error(chalk.red(message));
|
|
26
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "ESNext",
|
|
5
|
+
"moduleResolution": "bundler",
|
|
6
|
+
"strict": true,
|
|
7
|
+
"esModuleInterop": true,
|
|
8
|
+
"skipLibCheck": true,
|
|
9
|
+
"declaration": true,
|
|
10
|
+
"outDir": "dist",
|
|
11
|
+
"types": ["bun-types"]
|
|
12
|
+
},
|
|
13
|
+
"include": ["src/**/*.ts"]
|
|
14
|
+
}
|
|
@@ -1,2 +1,3 @@
|
|
|
1
|
-
# Tidio OpenAPI
|
|
2
|
-
|
|
1
|
+
# Tidio OpenAPI credentials from Developer > OpenAPI in the Tidio panel.
|
|
2
|
+
TIDIO_CLIENT_ID=ci_your_client_id_here
|
|
3
|
+
TIDIO_CLIENT_SECRET=cs_your_client_secret_here
|
|
@@ -1,105 +1,30 @@
|
|
|
1
|
-
#
|
|
1
|
+
# connect-tidio
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Tidio OpenAPI connector package.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Current API Contract
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
- Base URL: `https://api.tidio.com/`
|
|
8
|
+
- Accept header: `application/json; version=1`
|
|
9
|
+
- Auth headers:
|
|
10
|
+
- `X-Tidio-Openapi-Client-Id`
|
|
11
|
+
- `X-Tidio-Openapi-Client-Secret`
|
|
8
12
|
|
|
9
|
-
|
|
13
|
+
Do not reintroduce the legacy `https://api.tidio.co/v1` base URL or a single `X-Tidio-Openapi-Key` header.
|
|
10
14
|
|
|
11
|
-
|
|
12
|
-
bun install
|
|
13
|
-
bun run dev
|
|
14
|
-
bun run build
|
|
15
|
-
bun run typecheck
|
|
16
|
-
bun run dev contact list
|
|
17
|
-
bun run dev conversation list
|
|
18
|
-
bun run dev project get
|
|
19
|
-
bun run dev config show
|
|
20
|
-
```
|
|
15
|
+
## Supported Areas
|
|
21
16
|
|
|
22
|
-
|
|
17
|
+
- Contacts and contact properties
|
|
18
|
+
- Contact messages at `/contacts/{contactId}/messages`
|
|
19
|
+
- Departments
|
|
20
|
+
- Operators
|
|
21
|
+
- Project info
|
|
22
|
+
- Tickets
|
|
23
|
+
- Products for Lyro recommendations
|
|
24
|
+
- Lyro data sources and ticket answering helpers
|
|
23
25
|
|
|
24
|
-
-
|
|
25
|
-
- **Auth**: Custom header `X-Tidio-Openapi-Key: <api_key>` (NOT Bearer token)
|
|
26
|
-
- **Format**: JSON REST
|
|
27
|
-
- **Docs**: https://developers.tidio.com/reference
|
|
26
|
+
Do not add undocumented CRUD helpers for `/conversations`, `/tags`, `/automations`, `/canned-responses`, or `/webhooks` unless the current Tidio docs prove those OpenAPI paths exist.
|
|
28
27
|
|
|
29
|
-
##
|
|
28
|
+
## Security
|
|
30
29
|
|
|
31
|
-
|
|
32
|
-
src/
|
|
33
|
-
├── api/
|
|
34
|
-
│ ├── client.ts # HTTP client with X-Tidio-Openapi-Key auth and retry
|
|
35
|
-
│ └── index.ts # Tidio API wrapper class
|
|
36
|
-
├── cli/
|
|
37
|
-
│ └── index.ts # CLI commands
|
|
38
|
-
├── types/
|
|
39
|
-
│ └── index.ts # Type definitions
|
|
40
|
-
├── utils/
|
|
41
|
-
│ ├── config.ts # Multi-profile configuration
|
|
42
|
-
│ └── output.ts # CLI output formatting
|
|
43
|
-
└── index.ts # Library exports
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
## API Coverage
|
|
47
|
-
|
|
48
|
-
### Contacts
|
|
49
|
-
- List, get, create, update, delete contacts
|
|
50
|
-
|
|
51
|
-
### Conversations
|
|
52
|
-
- List, get conversations
|
|
53
|
-
- List and send messages
|
|
54
|
-
- Set status (open/closed/snoozed)
|
|
55
|
-
- Assign to operator or department
|
|
56
|
-
|
|
57
|
-
### Operators & Departments
|
|
58
|
-
- List and get operators
|
|
59
|
-
- List departments
|
|
60
|
-
|
|
61
|
-
### Tags
|
|
62
|
-
- List, create, delete tags
|
|
63
|
-
|
|
64
|
-
### Automations
|
|
65
|
-
- List automations
|
|
66
|
-
|
|
67
|
-
### Canned Responses
|
|
68
|
-
- List and create canned responses
|
|
69
|
-
|
|
70
|
-
### Webhooks
|
|
71
|
-
- List, create, delete webhooks
|
|
72
|
-
|
|
73
|
-
### Project
|
|
74
|
-
- Get project details
|
|
75
|
-
|
|
76
|
-
## Authentication
|
|
77
|
-
|
|
78
|
-
Uses API key authentication with the Tidio OpenAPI:
|
|
79
|
-
|
|
80
|
-
```typescript
|
|
81
|
-
'X-Tidio-Openapi-Key': apiKey
|
|
82
|
-
```
|
|
83
|
-
|
|
84
|
-
Generate the key in Tidio Panel under **Developer > OpenAPI**.
|
|
85
|
-
|
|
86
|
-
## Environment Variables
|
|
87
|
-
|
|
88
|
-
| Variable | Description |
|
|
89
|
-
|----------|-------------|
|
|
90
|
-
| `TIDIO_API_KEY` | OpenAPI key (overrides profile) |
|
|
91
|
-
|
|
92
|
-
## Data Storage
|
|
93
|
-
|
|
94
|
-
```
|
|
95
|
-
~/.hasna/connectors/connect-tidio/
|
|
96
|
-
├── current_profile # Active profile name
|
|
97
|
-
└── profiles/
|
|
98
|
-
├── default.json
|
|
99
|
-
└── {name}.json
|
|
100
|
-
```
|
|
101
|
-
|
|
102
|
-
## Dependencies
|
|
103
|
-
|
|
104
|
-
- commander: CLI framework
|
|
105
|
-
- chalk: Terminal styling
|
|
30
|
+
Profiles store client id and client secret under the connector config directory. Keep config directories `0700`, profile files `0600`, and validate profile names before joining filesystem paths.
|
|
@@ -1,14 +1,18 @@
|
|
|
1
1
|
# connect-tidio
|
|
2
2
|
|
|
3
|
-
TypeScript connector for the [Tidio OpenAPI](https://developers.tidio.com/reference).
|
|
3
|
+
TypeScript connector for the [Tidio OpenAPI](https://developers.tidio.com/reference).
|
|
4
4
|
|
|
5
5
|
## Features
|
|
6
6
|
|
|
7
|
-
-
|
|
8
|
-
- `
|
|
9
|
-
-
|
|
7
|
+
- Tidio OpenAPI v1 server: `https://api.tidio.com/`
|
|
8
|
+
- Required `Accept: application/json; version=1` requests
|
|
9
|
+
- `X-Tidio-Openapi-Client-Id` and `X-Tidio-Openapi-Client-Secret` authentication
|
|
10
|
+
- Contacts, contact messages, departments, operators, project info, tickets, products, and Lyro data source helpers
|
|
11
|
+
- Secure local profiles with private config directories and profile files
|
|
10
12
|
- Pretty and JSON output formats
|
|
11
|
-
- Automatic retry on rate limits
|
|
13
|
+
- Automatic retry on rate limits and server errors
|
|
14
|
+
|
|
15
|
+
This connector intentionally does not expose undocumented `/conversations`, `/tags`, `/automations`, `/canned-responses`, or `/webhooks` CRUD paths.
|
|
12
16
|
|
|
13
17
|
## Quick Start
|
|
14
18
|
|
|
@@ -16,30 +20,30 @@ TypeScript connector for the [Tidio OpenAPI](https://developers.tidio.com/refere
|
|
|
16
20
|
cd connectors/tidio
|
|
17
21
|
bun install
|
|
18
22
|
bun run dev --help
|
|
19
|
-
bun run dev config set-
|
|
20
|
-
bun run dev project
|
|
23
|
+
bun run dev config set-credentials ci_your_client_id cs_your_client_secret
|
|
24
|
+
bun run dev project
|
|
21
25
|
```
|
|
22
26
|
|
|
23
27
|
## Environment Variables
|
|
24
28
|
|
|
25
29
|
| Variable | Description |
|
|
26
30
|
|----------|-------------|
|
|
27
|
-
| `
|
|
31
|
+
| `TIDIO_CLIENT_ID` | OpenAPI client id, prefixed by `ci_` |
|
|
32
|
+
| `TIDIO_CLIENT_SECRET` | OpenAPI client secret, prefixed by `cs_` |
|
|
33
|
+
|
|
34
|
+
Environment variables override the active profile.
|
|
28
35
|
|
|
29
36
|
## CLI Commands
|
|
30
37
|
|
|
31
38
|
```bash
|
|
32
|
-
connect-tidio contact list|get|create|update|delete
|
|
33
|
-
connect-tidio
|
|
34
|
-
connect-tidio
|
|
35
|
-
connect-tidio
|
|
36
|
-
connect-tidio
|
|
37
|
-
connect-tidio
|
|
38
|
-
connect-tidio canned-response list|create
|
|
39
|
-
connect-tidio webhook list|create|delete
|
|
40
|
-
connect-tidio project get
|
|
39
|
+
connect-tidio contact list|get|create|update|delete|properties|viewed-pages|messages|send-message
|
|
40
|
+
connect-tidio operator
|
|
41
|
+
connect-tidio department
|
|
42
|
+
connect-tidio project
|
|
43
|
+
connect-tidio ticket list|get|reply|tags|custom-fields
|
|
44
|
+
connect-tidio lyro sources|ask-ticket
|
|
41
45
|
connect-tidio profile list|use|create|delete|show
|
|
42
|
-
connect-tidio config set-
|
|
46
|
+
connect-tidio config set-credentials|show|clear
|
|
43
47
|
```
|
|
44
48
|
|
|
45
49
|
## Build
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hasna/connect-tidio",
|
|
3
3
|
"version": "0.0.1",
|
|
4
|
-
"description": "Tidio connector -
|
|
4
|
+
"description": "Tidio OpenAPI connector - contacts, contact messages, departments, operators, project, tickets, products, and Lyro",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"connect-tidio": "./bin/index.js"
|
|
@@ -25,6 +25,8 @@
|
|
|
25
25
|
"live-chat",
|
|
26
26
|
"support",
|
|
27
27
|
"messaging",
|
|
28
|
+
"tickets",
|
|
29
|
+
"lyro",
|
|
28
30
|
"connector",
|
|
29
31
|
"cli",
|
|
30
32
|
"typescript",
|
|
@@ -45,6 +47,6 @@
|
|
|
45
47
|
},
|
|
46
48
|
"repository": {
|
|
47
49
|
"type": "git",
|
|
48
|
-
"url": "git+https://github.com/hasna/
|
|
50
|
+
"url": "git+https://github.com/hasna/connectors.git"
|
|
49
51
|
}
|
|
50
52
|
}
|