dtc-mcp 0.2.0 → 1.0.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 +169 -402
- package/data/docs.json +4338 -0
- package/dist/docs/loader.d.ts +40 -0
- package/dist/docs/loader.js +110 -0
- package/dist/docs/loader.js.map +1 -0
- package/dist/docs/search.d.ts +47 -0
- package/dist/docs/search.js +101 -0
- package/dist/docs/search.js.map +1 -0
- package/dist/index.js +3 -2
- package/dist/index.js.map +1 -1
- package/dist/sandbox/bridge.d.ts +2 -0
- package/dist/sandbox/bridge.js +101 -0
- package/dist/sandbox/bridge.js.map +1 -0
- package/dist/sandbox/node-discovery.d.ts +7 -0
- package/dist/sandbox/node-discovery.js +228 -0
- package/dist/sandbox/node-discovery.js.map +1 -0
- package/dist/sandbox/protocol.d.ts +76 -0
- package/dist/sandbox/protocol.js +20 -0
- package/dist/sandbox/protocol.js.map +1 -0
- package/dist/sandbox/proxy-template.d.ts +19 -0
- package/dist/sandbox/proxy-template.js +83 -0
- package/dist/sandbox/proxy-template.js.map +1 -0
- package/dist/sandbox/runner.d.ts +20 -0
- package/dist/sandbox/runner.js +99 -0
- package/dist/sandbox/runner.js.map +1 -0
- package/dist/sandbox/sandbox-helpers.d.ts +14 -0
- package/dist/sandbox/sandbox-helpers.js +98 -0
- package/dist/sandbox/sandbox-helpers.js.map +1 -0
- package/dist/sandbox/sidecar/index.d.ts +16 -0
- package/dist/sandbox/sidecar/index.js +346 -0
- package/dist/sandbox/sidecar/index.js.map +1 -0
- package/dist/sandbox/sidecar-runner.d.ts +32 -0
- package/dist/sandbox/sidecar-runner.js +325 -0
- package/dist/sandbox/sidecar-runner.js.map +1 -0
- package/dist/sandbox/timeout.d.ts +16 -0
- package/dist/sandbox/timeout.js +38 -0
- package/dist/sandbox/timeout.js.map +1 -0
- package/dist/sandbox/vm-runner.d.ts +35 -0
- package/dist/sandbox/vm-runner.js +182 -0
- package/dist/sandbox/vm-runner.js.map +1 -0
- package/dist/sdk/klaviyo/host.d.ts +43 -0
- package/dist/sdk/klaviyo/host.js +218 -0
- package/dist/sdk/klaviyo/host.js.map +1 -0
- package/dist/sdk/shopify/host.d.ts +23 -0
- package/dist/sdk/shopify/host.js +175 -0
- package/dist/sdk/shopify/host.js.map +1 -0
- package/dist/server.js +7 -7
- package/dist/server.js.map +1 -1
- package/dist/shared/errors.d.ts +0 -14
- package/dist/shared/errors.js +0 -73
- package/dist/shared/errors.js.map +1 -1
- package/dist/{platforms/klaviyo/tools.d.ts → tools/execute_code.d.ts} +1 -1
- package/dist/tools/execute_code.js +70 -0
- package/dist/tools/execute_code.js.map +1 -0
- package/dist/{platforms/shopify/tools.d.ts → tools/read_doc.d.ts} +1 -1
- package/dist/tools/read_doc.js +70 -0
- package/dist/tools/read_doc.js.map +1 -0
- package/dist/tools/search_docs.d.ts +2 -0
- package/dist/tools/search_docs.js +55 -0
- package/dist/tools/search_docs.js.map +1 -0
- package/package.json +16 -5
- package/dist/cross-platform/correlator.d.ts +0 -10
- package/dist/cross-platform/correlator.js +0 -166
- package/dist/cross-platform/correlator.js.map +0 -1
- package/dist/cross-platform/tools.d.ts +0 -2
- package/dist/cross-platform/tools.js +0 -30
- package/dist/cross-platform/tools.js.map +0 -1
- package/dist/platforms/klaviyo/client.d.ts +0 -91
- package/dist/platforms/klaviyo/client.js +0 -389
- package/dist/platforms/klaviyo/client.js.map +0 -1
- package/dist/platforms/klaviyo/tools.js +0 -363
- package/dist/platforms/klaviyo/tools.js.map +0 -1
- package/dist/platforms/klaviyo/transforms.d.ts +0 -59
- package/dist/platforms/klaviyo/transforms.js +0 -326
- package/dist/platforms/klaviyo/transforms.js.map +0 -1
- package/dist/platforms/shopify/client.d.ts +0 -51
- package/dist/platforms/shopify/client.js +0 -352
- package/dist/platforms/shopify/client.js.map +0 -1
- package/dist/platforms/shopify/tools.js +0 -368
- package/dist/platforms/shopify/tools.js.map +0 -1
- package/dist/platforms/shopify/transforms.d.ts +0 -83
- package/dist/platforms/shopify/transforms.js +0 -308
- package/dist/platforms/shopify/transforms.js.map +0 -1
- package/dist/shared/pagination.d.ts +0 -21
- package/dist/shared/pagination.js +0 -36
- package/dist/shared/pagination.js.map +0 -1
- package/dist/shared/types.d.ts +0 -318
- package/dist/shared/types.js +0 -3
- package/dist/shared/types.js.map +0 -1
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
export interface DocChunk {
|
|
2
|
+
/** Stable ID, used as MiniSearch primary key. */
|
|
3
|
+
id: string;
|
|
4
|
+
/** Short display title (e.g. "klaviyo.campaigns.list"). */
|
|
5
|
+
title: string;
|
|
6
|
+
/** "klaviyo" | "shopify" | "guide" */
|
|
7
|
+
platform: string;
|
|
8
|
+
/** "method" | "guide" | "type" — for filter UI down the road. */
|
|
9
|
+
category: string;
|
|
10
|
+
/** 1-line summary. */
|
|
11
|
+
summary: string;
|
|
12
|
+
/** Full markdown body (usage, params, example). */
|
|
13
|
+
content: string;
|
|
14
|
+
/** Optional tags for ranking boost. */
|
|
15
|
+
tags?: string[];
|
|
16
|
+
}
|
|
17
|
+
export interface DocsIndex {
|
|
18
|
+
version: string;
|
|
19
|
+
generatedAt: string;
|
|
20
|
+
chunks: DocChunk[];
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Load the docs index from the most recent source available:
|
|
24
|
+
* 1. ~/.cache/dtc-mcp/docs.json
|
|
25
|
+
* 2. bundled data/docs.json (always present in the package)
|
|
26
|
+
*
|
|
27
|
+
* The cache check happens first so docs can be updated independently of npm
|
|
28
|
+
* releases — the dtc-mcp-docs repo refreshes the CDN copy on a daily cron.
|
|
29
|
+
*/
|
|
30
|
+
export declare function loadDocs(): Promise<DocsIndex>;
|
|
31
|
+
/**
|
|
32
|
+
* Try to refresh the docs from the configured CDN. Returns the new index if
|
|
33
|
+
* it changed, null if 304 / unchanged / unreachable. Never throws — refresh
|
|
34
|
+
* failures must not break the MCP server, which can always fall back to the
|
|
35
|
+
* cached or bundled copy.
|
|
36
|
+
*
|
|
37
|
+
* Configure via `DTC_MCP_DOCS_URL`; set `DTC_MCP_DOCS_REFRESH=0` to disable
|
|
38
|
+
* background refreshes (offline mode).
|
|
39
|
+
*/
|
|
40
|
+
export declare function refreshDocs(): Promise<DocsIndex | null>;
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { readFile, writeFile, mkdir, stat } from "node:fs/promises";
|
|
2
|
+
import { fileURLToPath } from "node:url";
|
|
3
|
+
import { dirname, resolve } from "node:path";
|
|
4
|
+
import { homedir } from "node:os";
|
|
5
|
+
import { log } from "../config.js";
|
|
6
|
+
const DEFAULT_DOCS_URL = "https://cdn.jsdelivr.net/gh/rafaelsztutman/dtc-mcp-docs@latest/docs.json";
|
|
7
|
+
function bundledPath() {
|
|
8
|
+
const here = dirname(fileURLToPath(import.meta.url));
|
|
9
|
+
return resolve(here, "..", "..", "data", "docs.json");
|
|
10
|
+
}
|
|
11
|
+
function cacheDir() {
|
|
12
|
+
return resolve(homedir(), ".cache", "dtc-mcp");
|
|
13
|
+
}
|
|
14
|
+
function cacheFile() {
|
|
15
|
+
return resolve(cacheDir(), "docs.json");
|
|
16
|
+
}
|
|
17
|
+
function etagFile() {
|
|
18
|
+
return resolve(cacheDir(), "docs.etag");
|
|
19
|
+
}
|
|
20
|
+
async function readJsonIfExists(path) {
|
|
21
|
+
try {
|
|
22
|
+
await stat(path);
|
|
23
|
+
const text = await readFile(path, "utf8");
|
|
24
|
+
return JSON.parse(text);
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
async function readEtag() {
|
|
31
|
+
try {
|
|
32
|
+
return (await readFile(etagFile(), "utf8")).trim();
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Load the docs index from the most recent source available:
|
|
40
|
+
* 1. ~/.cache/dtc-mcp/docs.json
|
|
41
|
+
* 2. bundled data/docs.json (always present in the package)
|
|
42
|
+
*
|
|
43
|
+
* The cache check happens first so docs can be updated independently of npm
|
|
44
|
+
* releases — the dtc-mcp-docs repo refreshes the CDN copy on a daily cron.
|
|
45
|
+
*/
|
|
46
|
+
export async function loadDocs() {
|
|
47
|
+
const cached = await readJsonIfExists(cacheFile());
|
|
48
|
+
if (cached) {
|
|
49
|
+
log("debug", "Docs loaded from cache", { version: cached.version });
|
|
50
|
+
return cached;
|
|
51
|
+
}
|
|
52
|
+
const bundled = await readJsonIfExists(bundledPath());
|
|
53
|
+
if (bundled) {
|
|
54
|
+
log("debug", "Docs loaded from bundle", { version: bundled.version });
|
|
55
|
+
return bundled;
|
|
56
|
+
}
|
|
57
|
+
throw new Error(`No docs index found. Expected ${bundledPath()} to be present in the package.`);
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Try to refresh the docs from the configured CDN. Returns the new index if
|
|
61
|
+
* it changed, null if 304 / unchanged / unreachable. Never throws — refresh
|
|
62
|
+
* failures must not break the MCP server, which can always fall back to the
|
|
63
|
+
* cached or bundled copy.
|
|
64
|
+
*
|
|
65
|
+
* Configure via `DTC_MCP_DOCS_URL`; set `DTC_MCP_DOCS_REFRESH=0` to disable
|
|
66
|
+
* background refreshes (offline mode).
|
|
67
|
+
*/
|
|
68
|
+
export async function refreshDocs() {
|
|
69
|
+
if (process.env.DTC_MCP_DOCS_REFRESH === "0")
|
|
70
|
+
return null;
|
|
71
|
+
const url = process.env.DTC_MCP_DOCS_URL ?? DEFAULT_DOCS_URL;
|
|
72
|
+
try {
|
|
73
|
+
const etag = await readEtag();
|
|
74
|
+
const headers = { Accept: "application/json" };
|
|
75
|
+
if (etag)
|
|
76
|
+
headers["If-None-Match"] = etag;
|
|
77
|
+
const res = await fetch(url, { headers });
|
|
78
|
+
if (res.status === 304) {
|
|
79
|
+
log("debug", "Docs unchanged (304)");
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
if (!res.ok) {
|
|
83
|
+
log("warn", "Docs refresh failed", { status: res.status });
|
|
84
|
+
return null;
|
|
85
|
+
}
|
|
86
|
+
const text = await res.text();
|
|
87
|
+
const next = JSON.parse(text);
|
|
88
|
+
if (!Array.isArray(next.chunks)) {
|
|
89
|
+
log("warn", "Docs refresh returned malformed payload");
|
|
90
|
+
return null;
|
|
91
|
+
}
|
|
92
|
+
await mkdir(cacheDir(), { recursive: true });
|
|
93
|
+
await writeFile(cacheFile(), text, "utf8");
|
|
94
|
+
const newEtag = res.headers.get("etag");
|
|
95
|
+
if (newEtag)
|
|
96
|
+
await writeFile(etagFile(), newEtag, "utf8");
|
|
97
|
+
log("info", "Docs refreshed", {
|
|
98
|
+
version: next.version,
|
|
99
|
+
chunks: next.chunks.length,
|
|
100
|
+
});
|
|
101
|
+
return next;
|
|
102
|
+
}
|
|
103
|
+
catch (e) {
|
|
104
|
+
log("debug", "Docs refresh error", {
|
|
105
|
+
error: e instanceof Error ? e.message : String(e),
|
|
106
|
+
});
|
|
107
|
+
return null;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
//# sourceMappingURL=loader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loader.js","sourceRoot":"","sources":["../../src/docs/loader.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { type DocChunk } from "./loader.js";
|
|
2
|
+
export interface SearchHit {
|
|
3
|
+
id: string;
|
|
4
|
+
title: string;
|
|
5
|
+
platform: string;
|
|
6
|
+
category: string;
|
|
7
|
+
summary: string;
|
|
8
|
+
/** Full markdown body of the chunk. */
|
|
9
|
+
content: string;
|
|
10
|
+
score: number;
|
|
11
|
+
}
|
|
12
|
+
export declare function search(query: string, options?: {
|
|
13
|
+
limit?: number;
|
|
14
|
+
platform?: string;
|
|
15
|
+
}): Promise<{
|
|
16
|
+
version: string;
|
|
17
|
+
hits: SearchHit[];
|
|
18
|
+
}>;
|
|
19
|
+
export interface DocByIdResult {
|
|
20
|
+
version: string;
|
|
21
|
+
found: boolean;
|
|
22
|
+
chunk?: DocChunk;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Fetch one chunk by exact ID. Used by the `read_doc` MCP tool — Anthropic's
|
|
26
|
+
* "filesystem-as-API" pattern adapted to the docs layer. Cheaper and more
|
|
27
|
+
* deterministic than `search` when the LLM already knows the path.
|
|
28
|
+
*/
|
|
29
|
+
export declare function readById(id: string): Promise<DocByIdResult>;
|
|
30
|
+
export interface DocListResult {
|
|
31
|
+
version: string;
|
|
32
|
+
count: number;
|
|
33
|
+
paths: Array<{
|
|
34
|
+
id: string;
|
|
35
|
+
title: string;
|
|
36
|
+
platform: string;
|
|
37
|
+
category: string;
|
|
38
|
+
summary: string;
|
|
39
|
+
}>;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* List all chunk IDs (with one-line summaries). Used by `read_doc()` with no
|
|
43
|
+
* argument so the LLM can discover what's available without a search query.
|
|
44
|
+
*/
|
|
45
|
+
export declare function listPaths(options?: {
|
|
46
|
+
platform?: string;
|
|
47
|
+
}): Promise<DocListResult>;
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import MiniSearch from "minisearch";
|
|
2
|
+
import { loadDocs, refreshDocs } from "./loader.js";
|
|
3
|
+
let state = null;
|
|
4
|
+
let loadPromise = null;
|
|
5
|
+
function buildIndex(docs) {
|
|
6
|
+
const index = new MiniSearch({
|
|
7
|
+
idField: "id",
|
|
8
|
+
fields: ["title", "summary", "content", "tags", "platform"],
|
|
9
|
+
storeFields: ["title", "platform", "category", "summary"],
|
|
10
|
+
searchOptions: {
|
|
11
|
+
boost: { title: 3, summary: 2, content: 1, platform: 1.5 },
|
|
12
|
+
fuzzy: 0.2,
|
|
13
|
+
prefix: true,
|
|
14
|
+
combineWith: "AND",
|
|
15
|
+
},
|
|
16
|
+
});
|
|
17
|
+
index.addAll(docs.chunks);
|
|
18
|
+
const chunks = new Map(docs.chunks.map((c) => [c.id, c]));
|
|
19
|
+
return { index, chunks, version: docs.version };
|
|
20
|
+
}
|
|
21
|
+
async function ensureIndex() {
|
|
22
|
+
if (state)
|
|
23
|
+
return state;
|
|
24
|
+
if (loadPromise)
|
|
25
|
+
return loadPromise;
|
|
26
|
+
loadPromise = (async () => {
|
|
27
|
+
const docs = await loadDocs();
|
|
28
|
+
state = buildIndex(docs);
|
|
29
|
+
// Fire-and-forget background refresh. If a newer version is available
|
|
30
|
+
// we swap the in-memory index for it without blocking the first query.
|
|
31
|
+
void refreshDocs().then((next) => {
|
|
32
|
+
if (next)
|
|
33
|
+
state = buildIndex(next);
|
|
34
|
+
});
|
|
35
|
+
return state;
|
|
36
|
+
})();
|
|
37
|
+
return loadPromise;
|
|
38
|
+
}
|
|
39
|
+
export async function search(query, options = {}) {
|
|
40
|
+
const limit = options.limit ?? 5;
|
|
41
|
+
const st = await ensureIndex();
|
|
42
|
+
const trimmed = query.trim();
|
|
43
|
+
if (!trimmed) {
|
|
44
|
+
return { version: st.version, hits: [] };
|
|
45
|
+
}
|
|
46
|
+
const results = st.index.search(trimmed, {
|
|
47
|
+
filter: options.platform
|
|
48
|
+
? (r) => r.platform.toLowerCase() === options.platform.toLowerCase()
|
|
49
|
+
: undefined,
|
|
50
|
+
});
|
|
51
|
+
const hits = results.slice(0, limit).map((r) => {
|
|
52
|
+
const chunk = st.chunks.get(r.id);
|
|
53
|
+
return {
|
|
54
|
+
id: r.id,
|
|
55
|
+
title: chunk?.title ?? r.title,
|
|
56
|
+
platform: chunk?.platform ?? r.platform,
|
|
57
|
+
category: chunk?.category ?? r.category,
|
|
58
|
+
summary: chunk?.summary ?? r.summary,
|
|
59
|
+
content: chunk?.content ?? "",
|
|
60
|
+
score: r.score,
|
|
61
|
+
};
|
|
62
|
+
});
|
|
63
|
+
return { version: st.version, hits };
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Fetch one chunk by exact ID. Used by the `read_doc` MCP tool — Anthropic's
|
|
67
|
+
* "filesystem-as-API" pattern adapted to the docs layer. Cheaper and more
|
|
68
|
+
* deterministic than `search` when the LLM already knows the path.
|
|
69
|
+
*/
|
|
70
|
+
export async function readById(id) {
|
|
71
|
+
const st = await ensureIndex();
|
|
72
|
+
const chunk = st.chunks.get(id);
|
|
73
|
+
return {
|
|
74
|
+
version: st.version,
|
|
75
|
+
found: !!chunk,
|
|
76
|
+
chunk,
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* List all chunk IDs (with one-line summaries). Used by `read_doc()` with no
|
|
81
|
+
* argument so the LLM can discover what's available without a search query.
|
|
82
|
+
*/
|
|
83
|
+
export async function listPaths(options = {}) {
|
|
84
|
+
const st = await ensureIndex();
|
|
85
|
+
const platform = options.platform?.toLowerCase();
|
|
86
|
+
const paths = [];
|
|
87
|
+
for (const chunk of st.chunks.values()) {
|
|
88
|
+
if (platform && chunk.platform.toLowerCase() !== platform)
|
|
89
|
+
continue;
|
|
90
|
+
paths.push({
|
|
91
|
+
id: chunk.id,
|
|
92
|
+
title: chunk.title,
|
|
93
|
+
platform: chunk.platform,
|
|
94
|
+
category: chunk.category,
|
|
95
|
+
summary: chunk.summary,
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
paths.sort((a, b) => a.id.localeCompare(b.id));
|
|
99
|
+
return { version: st.version, count: paths.length, paths };
|
|
100
|
+
}
|
|
101
|
+
//# sourceMappingURL=search.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search.js","sourceRoot":"","sources":["../../src/docs/search.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
3
3
|
import { createServer } from "./server.js";
|
|
4
|
-
//
|
|
4
|
+
// Local-dev convenience: load .env if present. .mcpb installs pass user_config
|
|
5
|
+
// through process.env directly, so this is a no-op there.
|
|
5
6
|
import("dotenv")
|
|
6
7
|
.then(async (m) => {
|
|
7
8
|
const { fileURLToPath } = await import("url");
|
|
@@ -16,5 +17,5 @@ server.connect(transport).catch((err) => {
|
|
|
16
17
|
console.error("[dtc-mcp] fatal: failed to connect:", err);
|
|
17
18
|
process.exit(1);
|
|
18
19
|
});
|
|
19
|
-
console.error("[dtc-mcp]
|
|
20
|
+
console.error("[dtc-mcp] v1.0.0 ready");
|
|
20
21
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,+EAA+E;AAC/E,0DAA0D;AAC1D,MAAM,CAAC,QAAQ,CAAC;KACb,IAAI,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE;IAChB,MAAM,EAAE,aAAa,EAAE,GAAG,MAAM,MAAM,CAAC,KAAK,CAAC,CAAC;IAC9C,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,CAAC;IAClD,MAAM,GAAG,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;IACpD,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,OAAO,CAAC,GAAG,EAAE,IAAI,EAAE,MAAM,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;AACtE,CAAC,CAAC;KACD,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;AAEnB,MAAM,MAAM,GAAG,YAAY,EAAE,CAAC;AAC9B,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;AAE7C,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,CAAC,GAAY,EAAE,EAAE;IAC/C,OAAO,CAAC,KAAK,CAAC,qCAAqC,EAAE,GAAG,CAAC,CAAC;IAC1D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC;AAEH,OAAO,CAAC,KAAK,CAAC,wBAAwB,CAAC,CAAC"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { klaviyoGet, klaviyoPost, klaviyoPaginate, getConversionMetricId, } from "../sdk/klaviyo/host.js";
|
|
2
|
+
import { shopifyGql, shopifyQL, shopifyTimezone, } from "../sdk/shopify/host.js";
|
|
3
|
+
import { isShopifyConfigured } from "../config.js";
|
|
4
|
+
function requireShopify() {
|
|
5
|
+
if (!isShopifyConfigured()) {
|
|
6
|
+
throw new Error("Shopify not configured. Set SHOPIFY_STORE + SHOPIFY_CLIENT_ID + SHOPIFY_CLIENT_SECRET, or SHOPIFY_STORE + SHOPIFY_ACCESS_TOKEN (legacy).");
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Registry of methods the sandbox can invoke. Every entry is an exact path
|
|
11
|
+
* that maps to a host function. Unknown paths are rejected — the sandbox can
|
|
12
|
+
* never reach into arbitrary host code.
|
|
13
|
+
*
|
|
14
|
+
* Paths are also exported as `methodPaths` so the in-isolate proxy template
|
|
15
|
+
* can mirror this surface as typed namespaces.
|
|
16
|
+
*/
|
|
17
|
+
const handlers = {
|
|
18
|
+
// Low-level Klaviyo escape hatches
|
|
19
|
+
"klaviyo.get": (args) => {
|
|
20
|
+
const [path, options] = args;
|
|
21
|
+
return klaviyoGet(path, options);
|
|
22
|
+
},
|
|
23
|
+
"klaviyo.post": (args) => {
|
|
24
|
+
const [path, body, options] = args;
|
|
25
|
+
return klaviyoPost(path, body, options);
|
|
26
|
+
},
|
|
27
|
+
"klaviyo.paginate": (args) => {
|
|
28
|
+
const [path, options] = args;
|
|
29
|
+
return klaviyoPaginate(path, options);
|
|
30
|
+
},
|
|
31
|
+
"klaviyo.getConversionMetricId": () => getConversionMetricId(),
|
|
32
|
+
// Convenience helpers (sugar over the escape hatches; same rate-limit + cache path)
|
|
33
|
+
"klaviyo.campaigns.list": (args) => {
|
|
34
|
+
const [params] = args;
|
|
35
|
+
return klaviyoGet("campaigns", { params });
|
|
36
|
+
},
|
|
37
|
+
"klaviyo.campaigns.get": (args) => {
|
|
38
|
+
const [id, params] = args;
|
|
39
|
+
return klaviyoGet(`campaigns/${id}`, { params });
|
|
40
|
+
},
|
|
41
|
+
"klaviyo.flows.list": (args) => {
|
|
42
|
+
const [params] = args;
|
|
43
|
+
return klaviyoGet("flows", { params });
|
|
44
|
+
},
|
|
45
|
+
"klaviyo.flows.get": (args) => {
|
|
46
|
+
const [id, params] = args;
|
|
47
|
+
return klaviyoGet(`flows/${id}`, { params });
|
|
48
|
+
},
|
|
49
|
+
"klaviyo.lists.list": (args) => {
|
|
50
|
+
const [params] = args;
|
|
51
|
+
return klaviyoGet("lists", { params });
|
|
52
|
+
},
|
|
53
|
+
"klaviyo.segments.list": (args) => {
|
|
54
|
+
const [params] = args;
|
|
55
|
+
return klaviyoGet("segments", { params });
|
|
56
|
+
},
|
|
57
|
+
"klaviyo.profiles.list": (args) => {
|
|
58
|
+
const [params] = args;
|
|
59
|
+
return klaviyoGet("profiles", { params });
|
|
60
|
+
},
|
|
61
|
+
"klaviyo.events.list": (args) => {
|
|
62
|
+
const [params] = args;
|
|
63
|
+
return klaviyoGet("events", { params });
|
|
64
|
+
},
|
|
65
|
+
"klaviyo.metrics.list": (args) => {
|
|
66
|
+
const [params] = args;
|
|
67
|
+
return klaviyoGet("metrics", { params });
|
|
68
|
+
},
|
|
69
|
+
"klaviyo.reporting.campaignValues": (args) => {
|
|
70
|
+
const [body] = args;
|
|
71
|
+
return klaviyoPost("campaign-values-reports", body, { tier: "reporting" });
|
|
72
|
+
},
|
|
73
|
+
"klaviyo.reporting.flowValues": (args) => {
|
|
74
|
+
const [body] = args;
|
|
75
|
+
return klaviyoPost("flow-values-reports", body, { tier: "reporting" });
|
|
76
|
+
},
|
|
77
|
+
// Shopify
|
|
78
|
+
"shopify.gql": (args) => {
|
|
79
|
+
requireShopify();
|
|
80
|
+
const [query, options] = args;
|
|
81
|
+
return shopifyGql(query, options);
|
|
82
|
+
},
|
|
83
|
+
"shopify.ql": (args) => {
|
|
84
|
+
requireShopify();
|
|
85
|
+
const [ql] = args;
|
|
86
|
+
return shopifyQL(ql);
|
|
87
|
+
},
|
|
88
|
+
"shopify.timezone": () => {
|
|
89
|
+
requireShopify();
|
|
90
|
+
return shopifyTimezone();
|
|
91
|
+
},
|
|
92
|
+
};
|
|
93
|
+
export const methodPaths = Object.keys(handlers);
|
|
94
|
+
export async function invoke(path, args) {
|
|
95
|
+
const handler = handlers[path];
|
|
96
|
+
if (!handler) {
|
|
97
|
+
throw new Error(`Unknown SDK method: ${path}. Use search_docs to find valid methods.`);
|
|
98
|
+
}
|
|
99
|
+
return handler(args);
|
|
100
|
+
}
|
|
101
|
+
//# sourceMappingURL=bridge.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bridge.js","sourceRoot":"","sources":["../../src/sandbox/bridge.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,UAAU,EACV,WAAW,EACX,eAAe,EACf,qBAAqB,GACtB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EACL,UAAU,EACV,SAAS,EACT,eAAe,GAChB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAInD,SAAS,cAAc;IACrB,IAAI,CAAC,mBAAmB,EAAE,EAAE,CAAC;QAC3B,MAAM,IAAI,KAAK,CACb,0IAA0I,CAC3I,CAAC;IACJ,CAAC;AACH,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,QAAQ,GAA4B;IACxC,mCAAmC;IACnC,aAAa,EAAE,CAAC,IAAI,EAAE,EAAE;QACtB,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,IAAkG,CAAC;QAC3H,OAAO,UAAU,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IACnC,CAAC;IACD,cAAc,EAAE,CAAC,IAAI,EAAE,EAAE;QACvB,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,CAAC,GAAG,IAI7B,CAAC;QACF,OAAO,WAAW,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;IAC1C,CAAC;IACD,kBAAkB,EAAE,CAAC,IAAI,EAAE,EAAE;QAC3B,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,IAOvB,CAAC;QACF,OAAO,eAAe,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IACxC,CAAC;IACD,+BAA+B,EAAE,GAAG,EAAE,CAAC,qBAAqB,EAAE;IAE9D,oFAAoF;IACpF,wBAAwB,EAAE,CAAC,IAAI,EAAE,EAAE;QACjC,MAAM,CAAC,MAAM,CAAC,GAAG,IAA4C,CAAC;QAC9D,OAAO,UAAU,CAAC,WAAW,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC;IAC7C,CAAC;IACD,uBAAuB,EAAE,CAAC,IAAI,EAAE,EAAE;QAChC,MAAM,CAAC,EAAE,EAAE,MAAM,CAAC,GAAG,IAAoD,CAAC;QAC1E,OAAO,UAAU,CAAC,aAAa,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC;IACnD,CAAC;IACD,oBAAoB,EAAE,CAAC,IAAI,EAAE,EAAE;QAC7B,MAAM,CAAC,MAAM,CAAC,GAAG,IAA4C,CAAC;QAC9D,OAAO,UAAU,CAAC,OAAO,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC;IACzC,CAAC;IACD,mBAAmB,EAAE,CAAC,IAAI,EAAE,EAAE;QAC5B,MAAM,CAAC,EAAE,EAAE,MAAM,CAAC,GAAG,IAAoD,CAAC;QAC1E,OAAO,UAAU,CAAC,SAAS,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC;IAC/C,CAAC;IACD,oBAAoB,EAAE,CAAC,IAAI,EAAE,EAAE;QAC7B,MAAM,CAAC,MAAM,CAAC,GAAG,IAA4C,CAAC;QAC9D,OAAO,UAAU,CAAC,OAAO,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC;IACzC,CAAC;IACD,uBAAuB,EAAE,CAAC,IAAI,EAAE,EAAE;QAChC,MAAM,CAAC,MAAM,CAAC,GAAG,IAA4C,CAAC;QAC9D,OAAO,UAAU,CAAC,UAAU,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC;IAC5C,CAAC;IACD,uBAAuB,EAAE,CAAC,IAAI,EAAE,EAAE;QAChC,MAAM,CAAC,MAAM,CAAC,GAAG,IAA4C,CAAC;QAC9D,OAAO,UAAU,CAAC,UAAU,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC;IAC5C,CAAC;IACD,qBAAqB,EAAE,CAAC,IAAI,EAAE,EAAE;QAC9B,MAAM,CAAC,MAAM,CAAC,GAAG,IAA4C,CAAC;QAC9D,OAAO,UAAU,CAAC,QAAQ,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC;IAC1C,CAAC;IACD,sBAAsB,EAAE,CAAC,IAAI,EAAE,EAAE;QAC/B,MAAM,CAAC,MAAM,CAAC,GAAG,IAA4C,CAAC;QAC9D,OAAO,UAAU,CAAC,SAAS,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC;IAC3C,CAAC;IACD,kCAAkC,EAAE,CAAC,IAAI,EAAE,EAAE;QAC3C,MAAM,CAAC,IAAI,CAAC,GAAG,IAAiC,CAAC;QACjD,OAAO,WAAW,CAAC,yBAAyB,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC,CAAC;IAC7E,CAAC;IACD,8BAA8B,EAAE,CAAC,IAAI,EAAE,EAAE;QACvC,MAAM,CAAC,IAAI,CAAC,GAAG,IAAiC,CAAC;QACjD,OAAO,WAAW,CAAC,qBAAqB,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC,CAAC;IACzE,CAAC;IAED,UAAU;IACV,aAAa,EAAE,CAAC,IAAI,EAAE,EAAE;QACtB,cAAc,EAAE,CAAC;QACjB,MAAM,CAAC,KAAK,EAAE,OAAO,CAAC,GAAG,IAGxB,CAAC;QACF,OAAO,UAAU,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;IACpC,CAAC;IACD,YAAY,EAAE,CAAC,IAAI,EAAE,EAAE;QACrB,cAAc,EAAE,CAAC;QACjB,MAAM,CAAC,EAAE,CAAC,GAAG,IAAgB,CAAC;QAC9B,OAAO,SAAS,CAAC,EAAE,CAAC,CAAC;IACvB,CAAC;IACD,kBAAkB,EAAE,GAAG,EAAE;QACvB,cAAc,EAAE,CAAC;QACjB,OAAO,eAAe,EAAE,CAAC;IAC3B,CAAC;CACF,CAAC;AAEF,MAAM,CAAC,MAAM,WAAW,GAAa,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;AAE3D,MAAM,CAAC,KAAK,UAAU,MAAM,CAAC,IAAY,EAAE,IAAe;IACxD,MAAM,OAAO,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;IAC/B,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CACb,uBAAuB,IAAI,0CAA0C,CACtE,CAAC;IACJ,CAAC;IACD,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC;AACvB,CAAC"}
|