khotan-data 0.0.1 → 0.1.1
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/AGENTS.md +54 -0
- package/README.md +117 -1
- package/dist/cli.js +2869 -0
- package/dist/factory.cjs +3303 -0
- package/dist/factory.cjs.map +1 -0
- package/dist/factory.d.cts +662 -0
- package/dist/factory.d.ts +662 -0
- package/dist/factory.js +3292 -0
- package/dist/factory.js.map +1 -0
- package/dist/plug-client.cjs +99 -0
- package/dist/plug-client.cjs.map +1 -0
- package/dist/plug-client.d.cts +71 -0
- package/dist/plug-client.d.ts +71 -0
- package/dist/plug-client.js +96 -0
- package/dist/plug-client.js.map +1 -0
- package/dist/templates/agent-skill.md +73 -0
- package/dist/templates/agents.md +41 -0
- package/dist/templates/cache.example.ts +11 -0
- package/dist/templates/cache.ts +58 -0
- package/dist/templates/catch.example.ts +36 -0
- package/dist/templates/catch.ts +119 -0
- package/dist/templates/config-page.tsx +20 -0
- package/dist/templates/debug-index-page.tsx +101 -0
- package/dist/templates/debug-page.tsx +48 -0
- package/dist/templates/graph-page.tsx +11 -0
- package/dist/templates/hub.tsx +450 -0
- package/dist/templates/inflow.example.ts +61 -0
- package/dist/templates/inflow.ts +98 -0
- package/dist/templates/khotan-config.ts +49 -0
- package/dist/templates/khotan-route.ts +13 -0
- package/dist/templates/logs-page.tsx +9 -0
- package/dist/templates/logs.tsx +20 -0
- package/dist/templates/mapping-browser.tsx +761 -0
- package/dist/templates/mappings-page.tsx +9 -0
- package/dist/templates/outflow.example.ts +52 -0
- package/dist/templates/outflow.ts +90 -0
- package/dist/templates/pass.example.ts +51 -0
- package/dist/templates/pass.ts +134 -0
- package/dist/templates/plug-debugger.tsx +1185 -0
- package/dist/templates/plug.example.ts +93 -0
- package/dist/templates/plug.ts +806 -0
- package/dist/templates/relay.example.ts +71 -0
- package/dist/templates/relay.ts +104 -0
- package/dist/templates/runs-table.tsx +592 -0
- package/dist/templates/schema.ts +505 -0
- package/dist/templates/skill-dashboard.md +144 -0
- package/dist/templates/skill-plug.md +216 -0
- package/dist/templates/skill-setup.md +161 -0
- package/dist/templates/skill-webhook.md +196 -0
- package/dist/templates/topology-canvas.tsx +1406 -0
- package/dist/templates/var-panel.tsx +276 -0
- package/dist/templates/webhook-events-table.tsx +241 -0
- package/dist/templates/wire-panel.tsx +216 -0
- package/dist/templates/wire.ts +155 -0
- package/package.json +46 -5
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
// ============================================================================
|
|
2
|
+
// Example: Relay
|
|
3
|
+
// Generated by khotan CLI · https://github.com/khotan-data
|
|
4
|
+
//
|
|
5
|
+
// Copy this file, rename it for your source/destination pair, and register the
|
|
6
|
+
// exported flow in {outputDir}/khotan.ts.
|
|
7
|
+
// ============================================================================
|
|
8
|
+
|
|
9
|
+
import { khotanCache } from "khotan-data/factory";
|
|
10
|
+
import { relay, type RelayContext } from "./relay";
|
|
11
|
+
|
|
12
|
+
async function shopifyToHubspotWorkflow(ctx: RelayContext) {
|
|
13
|
+
"use workflow";
|
|
14
|
+
|
|
15
|
+
async function forwardProducts() {
|
|
16
|
+
"use step";
|
|
17
|
+
console.log("Starting relay", {
|
|
18
|
+
flow: ctx.flow.name,
|
|
19
|
+
to: ctx.flow.to,
|
|
20
|
+
khotanRunId: ctx.khotanRunId,
|
|
21
|
+
runType: ctx.runType,
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
const sourceResponse = await fetch("https://source.example.com/products", {
|
|
25
|
+
headers: {
|
|
26
|
+
Authorization: `Bearer ${ctx.vars["sourceToken"] ?? ""}`,
|
|
27
|
+
},
|
|
28
|
+
});
|
|
29
|
+
const payload = (await sourceResponse.json()) as {
|
|
30
|
+
data?: Array<Record<string, unknown>>;
|
|
31
|
+
};
|
|
32
|
+
const records = Array.isArray(payload.data) ? payload.data : [];
|
|
33
|
+
const snapshotCache = khotanCache(ctx, "shopify-products-snapshot");
|
|
34
|
+
const previousRecords =
|
|
35
|
+
(await snapshotCache.get<Array<Record<string, unknown>>>("latest")) ?? [];
|
|
36
|
+
|
|
37
|
+
await snapshotCache.set("latest", records, { ttl: "6h" });
|
|
38
|
+
|
|
39
|
+
for (const record of records) {
|
|
40
|
+
await fetch("https://destination.example.com/products", {
|
|
41
|
+
method: "POST",
|
|
42
|
+
headers: {
|
|
43
|
+
Authorization: `Bearer ${ctx.vars["destinationToken"] ?? ""}`,
|
|
44
|
+
"Content-Type": "application/json",
|
|
45
|
+
},
|
|
46
|
+
body: JSON.stringify(record),
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return {
|
|
51
|
+
extracted: records.length,
|
|
52
|
+
transformed: records.length,
|
|
53
|
+
created: records.length,
|
|
54
|
+
metadata: {
|
|
55
|
+
relay: ctx.flow.name,
|
|
56
|
+
to: ctx.flow.to,
|
|
57
|
+
previousCount: previousRecords.length,
|
|
58
|
+
},
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return forwardProducts();
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export const shopifyToHubspotRelay = relay({
|
|
66
|
+
name: "shopify-to-hubspot-products",
|
|
67
|
+
to: "hubspot",
|
|
68
|
+
resource: "products",
|
|
69
|
+
schedule: "0 * * * *",
|
|
70
|
+
workflow: shopifyToHubspotWorkflow,
|
|
71
|
+
});
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
// ============================================================================
|
|
2
|
+
// Relay — durable external service → external service data movement
|
|
3
|
+
// Generated by khotan CLI · https://github.com/khotan-data
|
|
4
|
+
//
|
|
5
|
+
// This file defines the relay() builder and types. Create per-service flow
|
|
6
|
+
// files (e.g. shopify-to-hubspot.ts) using this builder to read from the source
|
|
7
|
+
// plug and forward to a destination system with durable, retryable Vercel
|
|
8
|
+
// Workflow steps. Relay workflows can also use khotanCache(ctx, "name") for durable
|
|
9
|
+
// snapshots, checkpoints, and dedupe state between runs.
|
|
10
|
+
// ============================================================================
|
|
11
|
+
|
|
12
|
+
import type {
|
|
13
|
+
FlowRegistration,
|
|
14
|
+
FlowRunResult,
|
|
15
|
+
FlowWorkflowContext,
|
|
16
|
+
} from "khotan-data/factory";
|
|
17
|
+
|
|
18
|
+
export type RelayContext = FlowWorkflowContext & {
|
|
19
|
+
flow: FlowWorkflowContext["flow"] & { type: "relay"; to?: string | null };
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export type RelayWorkflow = (
|
|
23
|
+
ctx: RelayContext,
|
|
24
|
+
) => Promise<FlowRunResult | void>;
|
|
25
|
+
|
|
26
|
+
export interface RelayConfig {
|
|
27
|
+
/** Unique name for this flow (used for DB tracking and Hub display) */
|
|
28
|
+
name: string;
|
|
29
|
+
/** Name of the destination plug/system for humans and future tooling */
|
|
30
|
+
to: string;
|
|
31
|
+
/** Logical resource this flow moves, e.g. "products" */
|
|
32
|
+
resource?: string;
|
|
33
|
+
/** Optional cron schedule used by scheduler integrations */
|
|
34
|
+
schedule?: string;
|
|
35
|
+
/** Durable workflow that reads from source and writes to destination */
|
|
36
|
+
workflow: RelayWorkflow;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function relay(config: RelayConfig): FlowRegistration {
|
|
40
|
+
return {
|
|
41
|
+
name: config.name,
|
|
42
|
+
type: "relay",
|
|
43
|
+
to: config.to,
|
|
44
|
+
resource: config.resource,
|
|
45
|
+
schedule: config.schedule,
|
|
46
|
+
workflow: config.workflow as FlowRegistration["workflow"],
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// ---------------------------------------------------------------------------
|
|
51
|
+
// Usage Example (create a file like flows/shopify-to-hubspot.ts)
|
|
52
|
+
// ---------------------------------------------------------------------------
|
|
53
|
+
//
|
|
54
|
+
// import { bindWorkflowPlug, khotanCache, relay, type RelayContext } from "khotan-data/factory";
|
|
55
|
+
// import { shopifyPlug } from "../plugs/shopify";
|
|
56
|
+
// import { hubspotPlug } from "../plugs/hubspot";
|
|
57
|
+
//
|
|
58
|
+
// async function shopifyToHubspotWorkflow(ctx: RelayContext) {
|
|
59
|
+
// "use workflow";
|
|
60
|
+
//
|
|
61
|
+
// async function forwardProducts() {
|
|
62
|
+
// "use step";
|
|
63
|
+
// console.log("Starting relay", {
|
|
64
|
+
// flow: ctx.flow.name,
|
|
65
|
+
// to: ctx.flow.to,
|
|
66
|
+
// khotanRunId: ctx.khotanRunId,
|
|
67
|
+
// runType: ctx.runType,
|
|
68
|
+
// });
|
|
69
|
+
// const shopify = bindWorkflowPlug(shopifyPlug, ctx);
|
|
70
|
+
// const hubspot = bindWorkflowPlug(hubspotPlug, ctx, "hubspot");
|
|
71
|
+
//
|
|
72
|
+
// const snapshotCache = khotanCache(ctx, "shopify-products-snapshot");
|
|
73
|
+
// const previous = await snapshotCache.get<Array<Record<string, unknown>>>("latest");
|
|
74
|
+
//
|
|
75
|
+
// const response = await shopify.get<{ data?: Array<Record<string, unknown>> }>("/products");
|
|
76
|
+
// const records = Array.isArray(response.data) ? response.data : [];
|
|
77
|
+
// await snapshotCache.set("latest", records);
|
|
78
|
+
//
|
|
79
|
+
// for (const record of records) {
|
|
80
|
+
// await hubspot.post("/products", { body: record });
|
|
81
|
+
// }
|
|
82
|
+
//
|
|
83
|
+
// return {
|
|
84
|
+
// extracted: records.length,
|
|
85
|
+
// transformed: records.length,
|
|
86
|
+
// created: records.length,
|
|
87
|
+
// metadata: {
|
|
88
|
+
// relay: ctx.flow.name,
|
|
89
|
+
// to: ctx.flow.to,
|
|
90
|
+
// previousCount: previous?.length ?? 0,
|
|
91
|
+
// },
|
|
92
|
+
// };
|
|
93
|
+
// }
|
|
94
|
+
//
|
|
95
|
+
// return forwardProducts();
|
|
96
|
+
// }
|
|
97
|
+
//
|
|
98
|
+
// export const shopifyToHubspotRelay = relay({
|
|
99
|
+
// name: "shopify-to-hubspot-products",
|
|
100
|
+
// to: "hubspot",
|
|
101
|
+
// resource: "products",
|
|
102
|
+
// schedule: "0 * * * *",
|
|
103
|
+
// workflow: shopifyToHubspotWorkflow,
|
|
104
|
+
// });
|