@clawvard/sdk 0.1.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 +132 -0
- package/dist/errors.d.ts +18 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +27 -0
- package/dist/errors.js.map +1 -0
- package/dist/generated.d.ts +39 -0
- package/dist/generated.d.ts.map +1 -0
- package/dist/generated.js +58 -0
- package/dist/generated.js.map +1 -0
- package/dist/http-client.d.ts +62 -0
- package/dist/http-client.d.ts.map +1 -0
- package/dist/http-client.js +107 -0
- package/dist/http-client.js.map +1 -0
- package/dist/index.d.ts +185 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +129 -0
- package/dist/index.js.map +1 -0
- package/dist/job.d.ts +34 -0
- package/dist/job.d.ts.map +1 -0
- package/dist/job.js +96 -0
- package/dist/job.js.map +1 -0
- package/dist/plugin.d.ts +30 -0
- package/dist/plugin.d.ts.map +1 -0
- package/dist/plugin.js +15 -0
- package/dist/plugin.js.map +1 -0
- package/dist/service-types.d.ts +132 -0
- package/dist/service-types.d.ts.map +1 -0
- package/dist/service-types.js +28 -0
- package/dist/service-types.js.map +1 -0
- package/package.json +35 -0
package/README.md
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
# @clawvard/sdk
|
|
2
|
+
|
|
3
|
+
Typed TypeScript client for **Clawvard's non-LLM service layer** —
|
|
4
|
+
composed workflows, video / image / data jobs, third-party API
|
|
5
|
+
integrations. Same `sk-xxx` key works for the OpenAI SDK against
|
|
6
|
+
[token.clawvard.school](https://token.clawvard.school) and for this
|
|
7
|
+
SDK against [clawvard.school](https://clawvard.school).
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pnpm add @clawvard/sdk
|
|
11
|
+
# or: npm i @clawvard/sdk / yarn add @clawvard/sdk
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Quick start
|
|
15
|
+
|
|
16
|
+
```ts
|
|
17
|
+
import { Clawvard } from "@clawvard/sdk";
|
|
18
|
+
|
|
19
|
+
const cv = new Clawvard({ apiKey: "sk-xxx" });
|
|
20
|
+
|
|
21
|
+
// Local services (instant, charged per call)
|
|
22
|
+
const { hex } = await cv.text.hash({ text: "hello", algorithm: "sha256" });
|
|
23
|
+
const { dataUri } = await cv.url.qrCode({ text: "https://clawvard.school" });
|
|
24
|
+
|
|
25
|
+
// Long-running jobs (auto-poll, refundable on failure)
|
|
26
|
+
const result = await cv.video.removeSilence({ inputUrl: "https://…" })
|
|
27
|
+
.onProgress((pct, note) => console.log(`${(pct * 100).toFixed(0)}% — ${note}`))
|
|
28
|
+
.wait();
|
|
29
|
+
|
|
30
|
+
// Untyped escape hatch — call any registered service by id
|
|
31
|
+
const out = await cv.workflow.run<MyOutput>("my.service", input).wait();
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
For LLM calls (chat / embeddings / Whisper / DALL·E), point the
|
|
35
|
+
OpenAI SDK at Token Relay with the same `sk-xxx`:
|
|
36
|
+
|
|
37
|
+
```ts
|
|
38
|
+
import { OpenAI } from "openai";
|
|
39
|
+
const ai = new OpenAI({
|
|
40
|
+
apiKey: "sk-xxx",
|
|
41
|
+
baseURL: "https://token.clawvard.school/v1",
|
|
42
|
+
});
|
|
43
|
+
await ai.chat.completions.create({ model: "claude-opus-4-7", messages });
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## What's in the box
|
|
47
|
+
|
|
48
|
+
| Class | Purpose |
|
|
49
|
+
|---|---|
|
|
50
|
+
| `Clawvard` | Main client — composes generated namespaces with platform helpers |
|
|
51
|
+
| `Job<T>` | Handle for long-running jobs — `.wait()`, `.onProgress(cb)`, `.cancel()`, `.id()` |
|
|
52
|
+
| `HttpClient` | Lower-level: `.invoke()`, `.invokeJob()`, raw `.raw()` — exposed via `cv.client` |
|
|
53
|
+
| Generated namespaces | One per service group (`cv.util.*`, `cv.text.*`, `cv.url.*`, `cv.video.*`, …) |
|
|
54
|
+
| `cv.workflow.run(id, input)` | Untyped invoker — works for any registered service without bumping the SDK |
|
|
55
|
+
| `cv.catalog()` | Public catalog with pricing per service |
|
|
56
|
+
| `cv.usage()` / `cv.usageFor(g, m)` | Caller's usage stats per service |
|
|
57
|
+
|
|
58
|
+
## Per-call options
|
|
59
|
+
|
|
60
|
+
```ts
|
|
61
|
+
// Idempotency: same key → server returns the original outcome (no double-charge)
|
|
62
|
+
await cv.client.invoke("video", "render", input, {
|
|
63
|
+
idempotencyKey: crypto.randomUUID(),
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
// Webhooks (job services only): platform POSTs the terminal state
|
|
67
|
+
// to your URL with HMAC signature header `X-Clawvard-Signature`
|
|
68
|
+
await cv.client.invokeJob("video", "removeSilence", input, {
|
|
69
|
+
idempotencyKey: "...",
|
|
70
|
+
webhookUrl: "https://you.com/webhook",
|
|
71
|
+
});
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Configuration
|
|
75
|
+
|
|
76
|
+
```ts
|
|
77
|
+
const cv = new Clawvard({
|
|
78
|
+
apiKey: "sk-xxx", // Required for remote calls
|
|
79
|
+
baseUrl: "https://clawvard.school", // Default; override for staging
|
|
80
|
+
pollIntervalMs: 2000, // Job polling cadence
|
|
81
|
+
retry: { maxRetries: 3, baseDelayMs: 250 },
|
|
82
|
+
fetch: customFetch, // For testing / edge runtimes
|
|
83
|
+
plugins: [], // School / capability plugins
|
|
84
|
+
});
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### Auto-retry policy
|
|
88
|
+
|
|
89
|
+
- **GET**: always retry on 5xx + network errors
|
|
90
|
+
- **POST/PUT/DELETE**: only retry on 5xx if `Idempotency-Key` is set;
|
|
91
|
+
always retry on network errors (request never reached the server)
|
|
92
|
+
- **4xx**: never retry (caller's bug)
|
|
93
|
+
|
|
94
|
+
## Errors
|
|
95
|
+
|
|
96
|
+
```ts
|
|
97
|
+
import { ClawvardError, MissingApiKeyError } from "@clawvard/sdk";
|
|
98
|
+
|
|
99
|
+
try {
|
|
100
|
+
await cv.video.render(input);
|
|
101
|
+
} catch (err) {
|
|
102
|
+
if (err instanceof MissingApiKeyError) { /* config issue */ }
|
|
103
|
+
// Server errors carry .status + .hint:
|
|
104
|
+
// (err as Error & { status?: number; hint?: string }).status
|
|
105
|
+
}
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## Plugins
|
|
109
|
+
|
|
110
|
+
Capability packages can attach namespaces:
|
|
111
|
+
|
|
112
|
+
```ts
|
|
113
|
+
import { Clawvard } from "@clawvard/sdk";
|
|
114
|
+
import { mediaPlugin } from "@clawvard/sdk-media";
|
|
115
|
+
|
|
116
|
+
const cv = new Clawvard({
|
|
117
|
+
apiKey: "sk-xxx",
|
|
118
|
+
plugins: [mediaPlugin()],
|
|
119
|
+
});
|
|
120
|
+
await cv.video.extractFrames({ url, every: "1s" });
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
## Resources
|
|
124
|
+
|
|
125
|
+
- Docs: [clawvard.school/docs](https://clawvard.school/docs)
|
|
126
|
+
- Service catalog: [clawvard.school/services](https://clawvard.school/services)
|
|
127
|
+
- Get an API key: [clawvard.school/token-relay](https://clawvard.school/token-relay)
|
|
128
|
+
- Issues: [github.com/THEZIONLABS/clawvard](https://github.com/THEZIONLABS/clawvard)
|
|
129
|
+
|
|
130
|
+
## License
|
|
131
|
+
|
|
132
|
+
MIT
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SDK-side error classes. Server-side `error: "..."` strings come back
|
|
3
|
+
* via `toApiError` in http-client.ts; these are for client-side preflight
|
|
4
|
+
* errors raised before any HTTP call goes out.
|
|
5
|
+
*/
|
|
6
|
+
export declare class ClawvardError extends Error {
|
|
7
|
+
readonly code: string;
|
|
8
|
+
constructor(message: string, code: string);
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Raised when a remote method is called but no API key was supplied at
|
|
12
|
+
* construction. Local-only methods (e.g., `cv.video.extractFrames()`) do
|
|
13
|
+
* not raise this — they don't need a key.
|
|
14
|
+
*/
|
|
15
|
+
export declare class MissingApiKeyError extends ClawvardError {
|
|
16
|
+
constructor(operation: string);
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,qBAAa,aAAc,SAAQ,KAAK;aACO,IAAI,EAAE,MAAM;gBAA7C,OAAO,EAAE,MAAM,EAAkB,IAAI,EAAE,MAAM;CAI1D;AAED;;;;GAIG;AACH,qBAAa,kBAAmB,SAAQ,aAAa;gBACvC,SAAS,EAAE,MAAM;CAS9B"}
|
package/dist/errors.js
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SDK-side error classes. Server-side `error: "..."` strings come back
|
|
3
|
+
* via `toApiError` in http-client.ts; these are for client-side preflight
|
|
4
|
+
* errors raised before any HTTP call goes out.
|
|
5
|
+
*/
|
|
6
|
+
export class ClawvardError extends Error {
|
|
7
|
+
code;
|
|
8
|
+
constructor(message, code) {
|
|
9
|
+
super(message);
|
|
10
|
+
this.code = code;
|
|
11
|
+
this.name = "ClawvardError";
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Raised when a remote method is called but no API key was supplied at
|
|
16
|
+
* construction. Local-only methods (e.g., `cv.video.extractFrames()`) do
|
|
17
|
+
* not raise this — they don't need a key.
|
|
18
|
+
*/
|
|
19
|
+
export class MissingApiKeyError extends ClawvardError {
|
|
20
|
+
constructor(operation) {
|
|
21
|
+
super(`Clawvard: apiKey is required to call \`${operation}\`. Pass it to ` +
|
|
22
|
+
`\`new Clawvard({ apiKey: "sk-xxx" })\` or call only local ` +
|
|
23
|
+
`helpers (e.g. \`cv.video.*\`, \`cv.subtitle.*\`).`, "missing_api_key");
|
|
24
|
+
this.name = "MissingApiKeyError";
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,MAAM,OAAO,aAAc,SAAQ,KAAK;IACO;IAA7C,YAAY,OAAe,EAAkB,IAAY;QACvD,KAAK,CAAC,OAAO,CAAC,CAAC;QAD4B,SAAI,GAAJ,IAAI,CAAQ;QAEvD,IAAI,CAAC,IAAI,GAAG,eAAe,CAAC;IAC9B,CAAC;CACF;AAED;;;;GAIG;AACH,MAAM,OAAO,kBAAmB,SAAQ,aAAa;IACnD,YAAY,SAAiB;QAC3B,KAAK,CACH,0CAA0C,SAAS,iBAAiB;YAClE,4DAA4D;YAC5D,mDAAmD,EACrD,iBAAiB,CAClB,CAAC;QACF,IAAI,CAAC,IAAI,GAAG,oBAAoB,CAAC;IACnC,CAAC;CACF"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AUTO-GENERATED — do not edit by hand.
|
|
3
|
+
*
|
|
4
|
+
* Run `pnpm sdk:gen` to regenerate from `src/lib/services/registry.ts`.
|
|
5
|
+
*/
|
|
6
|
+
import type { HttpClient } from "./http-client";
|
|
7
|
+
import type { Job } from "./job";
|
|
8
|
+
import type { InputArgs, OutputOf } from "./service-types";
|
|
9
|
+
export declare class TextNamespace {
|
|
10
|
+
private readonly c;
|
|
11
|
+
constructor(c: HttpClient);
|
|
12
|
+
/** text.word-count (local) — generated. */
|
|
13
|
+
wordCount(...args: InputArgs<"text.word-count">): Promise<OutputOf<"text.word-count">>;
|
|
14
|
+
/** text.hash (local) — generated. */
|
|
15
|
+
hash(...args: InputArgs<"text.hash">): Promise<OutputOf<"text.hash">>;
|
|
16
|
+
}
|
|
17
|
+
export declare class UrlNamespace {
|
|
18
|
+
private readonly c;
|
|
19
|
+
constructor(c: HttpClient);
|
|
20
|
+
/** url.qr-code (local) — generated. */
|
|
21
|
+
qrCode(...args: InputArgs<"url.qr-code">): Promise<OutputOf<"url.qr-code">>;
|
|
22
|
+
/** url.preview (local) — generated. */
|
|
23
|
+
preview(...args: InputArgs<"url.preview">): Promise<OutputOf<"url.preview">>;
|
|
24
|
+
}
|
|
25
|
+
export declare class UtilNamespace {
|
|
26
|
+
private readonly c;
|
|
27
|
+
constructor(c: HttpClient);
|
|
28
|
+
/** util.ip-check (proxy) — generated. */
|
|
29
|
+
ipCheck(...args: InputArgs<"util.ip-check">): Promise<OutputOf<"util.ip-check">>;
|
|
30
|
+
/** util.delay-echo (job) — generated. */
|
|
31
|
+
delayEcho(...args: InputArgs<"util.delay-echo">): Job<OutputOf<"util.delay-echo">>;
|
|
32
|
+
}
|
|
33
|
+
export declare class GeneratedClient {
|
|
34
|
+
readonly text: TextNamespace;
|
|
35
|
+
readonly url: UrlNamespace;
|
|
36
|
+
readonly util: UtilNamespace;
|
|
37
|
+
constructor(client: HttpClient);
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=generated.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generated.d.ts","sourceRoot":"","sources":["../src/generated.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,OAAO,CAAC;AACjC,OAAO,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAG3D,qBAAa,aAAa;IACZ,OAAO,CAAC,QAAQ,CAAC,CAAC;gBAAD,CAAC,EAAE,UAAU;IAE1C,2CAA2C;IAC3C,SAAS,CAAC,GAAG,IAAI,EAAE,SAAS,CAAC,iBAAiB,CAAC,GAAG,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAC,CAAC;IAItF,qCAAqC;IACrC,IAAI,CAAC,GAAG,IAAI,EAAE,SAAS,CAAC,WAAW,CAAC,GAAG,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;CAGtE;AAED,qBAAa,YAAY;IACX,OAAO,CAAC,QAAQ,CAAC,CAAC;gBAAD,CAAC,EAAE,UAAU;IAE1C,uCAAuC;IACvC,MAAM,CAAC,GAAG,IAAI,EAAE,SAAS,CAAC,aAAa,CAAC,GAAG,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC;IAI3E,uCAAuC;IACvC,OAAO,CAAC,GAAG,IAAI,EAAE,SAAS,CAAC,aAAa,CAAC,GAAG,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC;CAG7E;AAED,qBAAa,aAAa;IACZ,OAAO,CAAC,QAAQ,CAAC,CAAC;gBAAD,CAAC,EAAE,UAAU;IAE1C,yCAAyC;IACzC,OAAO,CAAC,GAAG,IAAI,EAAE,SAAS,CAAC,eAAe,CAAC,GAAG,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAC,CAAC;IAIhF,yCAAyC;IACzC,SAAS,CAAC,GAAG,IAAI,EAAE,SAAS,CAAC,iBAAiB,CAAC,GAAG,GAAG,CAAC,QAAQ,CAAC,iBAAiB,CAAC,CAAC;CAGnF;AAED,qBAAa,eAAe;IAC1B,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC;IAC7B,QAAQ,CAAC,GAAG,EAAE,YAAY,CAAC;IAC3B,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC;gBAEjB,MAAM,EAAE,UAAU;CAK/B"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AUTO-GENERATED — do not edit by hand.
|
|
3
|
+
*
|
|
4
|
+
* Run `pnpm sdk:gen` to regenerate from `src/lib/services/registry.ts`.
|
|
5
|
+
*/
|
|
6
|
+
export class TextNamespace {
|
|
7
|
+
c;
|
|
8
|
+
constructor(c) {
|
|
9
|
+
this.c = c;
|
|
10
|
+
}
|
|
11
|
+
/** text.word-count (local) — generated. */
|
|
12
|
+
wordCount(...args) {
|
|
13
|
+
return this.c.invoke("text", "wordCount", args[0]);
|
|
14
|
+
}
|
|
15
|
+
/** text.hash (local) — generated. */
|
|
16
|
+
hash(...args) {
|
|
17
|
+
return this.c.invoke("text", "hash", args[0]);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
export class UrlNamespace {
|
|
21
|
+
c;
|
|
22
|
+
constructor(c) {
|
|
23
|
+
this.c = c;
|
|
24
|
+
}
|
|
25
|
+
/** url.qr-code (local) — generated. */
|
|
26
|
+
qrCode(...args) {
|
|
27
|
+
return this.c.invoke("url", "qrCode", args[0]);
|
|
28
|
+
}
|
|
29
|
+
/** url.preview (local) — generated. */
|
|
30
|
+
preview(...args) {
|
|
31
|
+
return this.c.invoke("url", "preview", args[0]);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
export class UtilNamespace {
|
|
35
|
+
c;
|
|
36
|
+
constructor(c) {
|
|
37
|
+
this.c = c;
|
|
38
|
+
}
|
|
39
|
+
/** util.ip-check (proxy) — generated. */
|
|
40
|
+
ipCheck(...args) {
|
|
41
|
+
return this.c.invoke("util", "ipCheck", args[0]);
|
|
42
|
+
}
|
|
43
|
+
/** util.delay-echo (job) — generated. */
|
|
44
|
+
delayEcho(...args) {
|
|
45
|
+
return this.c.invokeJob("util", "delayEcho", args[0]);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
export class GeneratedClient {
|
|
49
|
+
text;
|
|
50
|
+
url;
|
|
51
|
+
util;
|
|
52
|
+
constructor(client) {
|
|
53
|
+
this.text = new TextNamespace(client);
|
|
54
|
+
this.url = new UrlNamespace(client);
|
|
55
|
+
this.util = new UtilNamespace(client);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=generated.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generated.js","sourceRoot":"","sources":["../src/generated.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAOH,MAAM,OAAO,aAAa;IACK;IAA7B,YAA6B,CAAa;QAAb,MAAC,GAAD,CAAC,CAAY;IAAG,CAAC;IAE9C,2CAA2C;IAC3C,SAAS,CAAC,GAAG,IAAkC;QAC7C,OAAO,IAAI,CAAC,CAAC,CAAC,MAAM,CAA8B,MAAM,EAAE,WAAW,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IAClF,CAAC;IAED,qCAAqC;IACrC,IAAI,CAAC,GAAG,IAA4B;QAClC,OAAO,IAAI,CAAC,CAAC,CAAC,MAAM,CAAwB,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IACvE,CAAC;CACF;AAED,MAAM,OAAO,YAAY;IACM;IAA7B,YAA6B,CAAa;QAAb,MAAC,GAAD,CAAC,CAAY;IAAG,CAAC;IAE9C,uCAAuC;IACvC,MAAM,CAAC,GAAG,IAA8B;QACtC,OAAO,IAAI,CAAC,CAAC,CAAC,MAAM,CAA0B,KAAK,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IAC1E,CAAC;IAED,uCAAuC;IACvC,OAAO,CAAC,GAAG,IAA8B;QACvC,OAAO,IAAI,CAAC,CAAC,CAAC,MAAM,CAA0B,KAAK,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IAC3E,CAAC;CACF;AAED,MAAM,OAAO,aAAa;IACK;IAA7B,YAA6B,CAAa;QAAb,MAAC,GAAD,CAAC,CAAY;IAAG,CAAC;IAE9C,yCAAyC;IACzC,OAAO,CAAC,GAAG,IAAgC;QACzC,OAAO,IAAI,CAAC,CAAC,CAAC,MAAM,CAA4B,MAAM,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IAC9E,CAAC;IAED,yCAAyC;IACzC,SAAS,CAAC,GAAG,IAAkC;QAC7C,OAAO,IAAI,CAAC,CAAC,CAAC,SAAS,CAA8B,MAAM,EAAE,WAAW,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IACrF,CAAC;CACF;AAED,MAAM,OAAO,eAAe;IACjB,IAAI,CAAgB;IACpB,GAAG,CAAe;IAClB,IAAI,CAAgB;IAE7B,YAAY,MAAkB;QAC5B,IAAI,CAAC,IAAI,GAAG,IAAI,aAAa,CAAC,MAAM,CAAC,CAAC;QACtC,IAAI,CAAC,GAAG,GAAG,IAAI,YAAY,CAAC,MAAM,CAAC,CAAC;QACpC,IAAI,CAAC,IAAI,GAAG,IAAI,aAAa,CAAC,MAAM,CAAC,CAAC;IACxC,CAAC;CACF"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Internal HTTP client used by every namespace method.
|
|
3
|
+
* Not part of the public surface — exported only so the
|
|
4
|
+
* auto-generated client can construct one.
|
|
5
|
+
*/
|
|
6
|
+
import { Job } from "./job";
|
|
7
|
+
export interface ClawvardHttpConfig {
|
|
8
|
+
/** Optional — local-only callers (e.g. `cv.video.extractFrames`) work without it. */
|
|
9
|
+
apiKey?: string;
|
|
10
|
+
baseUrl: string;
|
|
11
|
+
pollIntervalMs: number;
|
|
12
|
+
fetchImpl: typeof globalThis.fetch;
|
|
13
|
+
/** Auto-retry policy for transient failures (5xx + network errors).
|
|
14
|
+
* Default is 3 attempts with exponential backoff. Set `maxRetries:0`
|
|
15
|
+
* to disable. */
|
|
16
|
+
retry?: {
|
|
17
|
+
maxRetries: number;
|
|
18
|
+
baseDelayMs: number;
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
export declare class HttpClient {
|
|
22
|
+
private readonly baseUrl;
|
|
23
|
+
private readonly apiKey;
|
|
24
|
+
private readonly fetchImpl;
|
|
25
|
+
private readonly retry;
|
|
26
|
+
readonly pollIntervalMs: number;
|
|
27
|
+
constructor(config: ClawvardHttpConfig);
|
|
28
|
+
/** Throws `MissingApiKeyError` if no key was supplied. Used by every
|
|
29
|
+
* remote method before issuing the HTTP call. Local-only callers
|
|
30
|
+
* (e.g. cv.video.extractFrames) skip this check entirely. */
|
|
31
|
+
requireApiKey(operation: string): string;
|
|
32
|
+
/** Fetch wrapper with optional bearer auth + transparent retry on
|
|
33
|
+
* 5xx + network errors. Retries are only safe for idempotent
|
|
34
|
+
* operations: GET/HEAD always retried; POST/PUT/DELETE only when the
|
|
35
|
+
* caller provides an `Idempotency-Key` header (the dispatcher dedups
|
|
36
|
+
* on the server side). Non-idempotent POSTs without the header are
|
|
37
|
+
* retried only on network errors (where we know the request never
|
|
38
|
+
* reached the server).
|
|
39
|
+
*
|
|
40
|
+
* Authorization header is added only when an `apiKey` was configured;
|
|
41
|
+
* endpoints that need auth respond 401 and the caller surfaces that. */
|
|
42
|
+
raw(path: string, init?: RequestInit): Promise<Response>;
|
|
43
|
+
invoke<T>(group: string, method: string, body: unknown, options?: InvokeOptions): Promise<T>;
|
|
44
|
+
invokeJob<T>(group: string, method: string, body: unknown, options?: InvokeOptions): Job<T>;
|
|
45
|
+
}
|
|
46
|
+
/** Per-call overrides passed to namespace methods. Most callers can
|
|
47
|
+
* ignore this — it's used by `cv.client.invoke(...)` and the
|
|
48
|
+
* retry-friendly forms. */
|
|
49
|
+
export interface InvokeOptions {
|
|
50
|
+
/** Sent as the `Idempotency-Key` header. Same key + same caller =
|
|
51
|
+
* the dispatcher returns the original invocation's outcome instead
|
|
52
|
+
* of re-charging / re-creating. Setting this also unlocks SDK auto-
|
|
53
|
+
* retry on 5xx for the call (otherwise only network errors retry). */
|
|
54
|
+
idempotencyKey?: string;
|
|
55
|
+
/** (Job services only) Sent as the `X-Webhook-Url` header. The
|
|
56
|
+
* platform POSTs the terminal job state to this URL so callers
|
|
57
|
+
* don't have to poll. Body is HMAC-signed with the server's
|
|
58
|
+
* webhook secret — verify via the `X-Clawvard-Signature` header. */
|
|
59
|
+
webhookUrl?: string;
|
|
60
|
+
}
|
|
61
|
+
export declare function toApiError(res: Response): Promise<Error>;
|
|
62
|
+
//# sourceMappingURL=http-client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http-client.d.ts","sourceRoot":"","sources":["../src/http-client.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EAAE,GAAG,EAAE,MAAM,OAAO,CAAC;AAE5B,MAAM,WAAW,kBAAkB;IACjC,qFAAqF;IACrF,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,EAAE,OAAO,UAAU,CAAC,KAAK,CAAC;IACnC;;sBAEkB;IAClB,KAAK,CAAC,EAAE;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC;CACrD;AAED,qBAAa,UAAU;IACrB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAqB;IAC5C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAA0B;IACpD,OAAO,CAAC,QAAQ,CAAC,KAAK,CAA8C;IACpE,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;gBAEpB,MAAM,EAAE,kBAAkB;IAQtC;;kEAE8D;IAC9D,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM;IAKxC;;;;;;;;;6EASyE;IACnE,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,QAAQ,CAAC;IA4BxD,MAAM,CAAC,CAAC,EACZ,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,OAAO,EACb,OAAO,CAAC,EAAE,aAAa,GACtB,OAAO,CAAC,CAAC,CAAC;IAcb,SAAS,CAAC,CAAC,EACT,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,OAAO,EACb,OAAO,CAAC,EAAE,aAAa,GACtB,GAAG,CAAC,CAAC,CAAC;CAIV;AAED;;4BAE4B;AAC5B,MAAM,WAAW,aAAa;IAC5B;;;2EAGuE;IACvE,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;;;yEAGqE;IACrE,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAMD,wBAAsB,UAAU,CAAC,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,KAAK,CAAC,CAW9D"}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Internal HTTP client used by every namespace method.
|
|
3
|
+
* Not part of the public surface — exported only so the
|
|
4
|
+
* auto-generated client can construct one.
|
|
5
|
+
*/
|
|
6
|
+
import { MissingApiKeyError } from "./errors";
|
|
7
|
+
import { Job } from "./job";
|
|
8
|
+
export class HttpClient {
|
|
9
|
+
baseUrl;
|
|
10
|
+
apiKey;
|
|
11
|
+
fetchImpl;
|
|
12
|
+
retry;
|
|
13
|
+
pollIntervalMs;
|
|
14
|
+
constructor(config) {
|
|
15
|
+
this.baseUrl = config.baseUrl.replace(/\/+$/, "");
|
|
16
|
+
this.apiKey = config.apiKey;
|
|
17
|
+
this.fetchImpl = config.fetchImpl;
|
|
18
|
+
this.pollIntervalMs = config.pollIntervalMs;
|
|
19
|
+
this.retry = config.retry ?? { maxRetries: 3, baseDelayMs: 250 };
|
|
20
|
+
}
|
|
21
|
+
/** Throws `MissingApiKeyError` if no key was supplied. Used by every
|
|
22
|
+
* remote method before issuing the HTTP call. Local-only callers
|
|
23
|
+
* (e.g. cv.video.extractFrames) skip this check entirely. */
|
|
24
|
+
requireApiKey(operation) {
|
|
25
|
+
if (!this.apiKey)
|
|
26
|
+
throw new MissingApiKeyError(operation);
|
|
27
|
+
return this.apiKey;
|
|
28
|
+
}
|
|
29
|
+
/** Fetch wrapper with optional bearer auth + transparent retry on
|
|
30
|
+
* 5xx + network errors. Retries are only safe for idempotent
|
|
31
|
+
* operations: GET/HEAD always retried; POST/PUT/DELETE only when the
|
|
32
|
+
* caller provides an `Idempotency-Key` header (the dispatcher dedups
|
|
33
|
+
* on the server side). Non-idempotent POSTs without the header are
|
|
34
|
+
* retried only on network errors (where we know the request never
|
|
35
|
+
* reached the server).
|
|
36
|
+
*
|
|
37
|
+
* Authorization header is added only when an `apiKey` was configured;
|
|
38
|
+
* endpoints that need auth respond 401 and the caller surfaces that. */
|
|
39
|
+
async raw(path, init) {
|
|
40
|
+
const method = (init?.method || "GET").toUpperCase();
|
|
41
|
+
const headersIn = (init?.headers || {});
|
|
42
|
+
const hasIdemKey = "Idempotency-Key" in headersIn || "idempotency-key" in headersIn;
|
|
43
|
+
const isReadOnly = method === "GET" || method === "HEAD";
|
|
44
|
+
const fullySafe = isReadOnly || hasIdemKey;
|
|
45
|
+
const url = `${this.baseUrl}${path}`;
|
|
46
|
+
const headers = { ...headersIn };
|
|
47
|
+
if (this.apiKey)
|
|
48
|
+
headers.Authorization = `Bearer ${this.apiKey}`;
|
|
49
|
+
const merged = { ...init, headers };
|
|
50
|
+
let lastError;
|
|
51
|
+
for (let attempt = 0; attempt <= this.retry.maxRetries; attempt++) {
|
|
52
|
+
try {
|
|
53
|
+
const res = await this.fetchImpl(url, merged);
|
|
54
|
+
if (res.status < 500)
|
|
55
|
+
return res;
|
|
56
|
+
if (!fullySafe)
|
|
57
|
+
return res;
|
|
58
|
+
if (attempt === this.retry.maxRetries)
|
|
59
|
+
return res;
|
|
60
|
+
}
|
|
61
|
+
catch (err) {
|
|
62
|
+
lastError = err;
|
|
63
|
+
if (attempt === this.retry.maxRetries)
|
|
64
|
+
throw err;
|
|
65
|
+
}
|
|
66
|
+
await sleep(this.retry.baseDelayMs * 2 ** attempt);
|
|
67
|
+
}
|
|
68
|
+
throw lastError ?? new Error("retry exhausted");
|
|
69
|
+
}
|
|
70
|
+
async invoke(group, method, body, options) {
|
|
71
|
+
this.requireApiKey(`${group}.${method}`);
|
|
72
|
+
const headers = { "Content-Type": "application/json" };
|
|
73
|
+
if (options?.idempotencyKey)
|
|
74
|
+
headers["Idempotency-Key"] = options.idempotencyKey;
|
|
75
|
+
if (options?.webhookUrl)
|
|
76
|
+
headers["X-Webhook-Url"] = options.webhookUrl;
|
|
77
|
+
const res = await this.raw(`/api/services/invoke/${group}/${method}`, {
|
|
78
|
+
method: "POST",
|
|
79
|
+
headers,
|
|
80
|
+
body: JSON.stringify(body ?? {}),
|
|
81
|
+
});
|
|
82
|
+
if (!res.ok)
|
|
83
|
+
throw await toApiError(res);
|
|
84
|
+
return (await res.json());
|
|
85
|
+
}
|
|
86
|
+
invokeJob(group, method, body, options) {
|
|
87
|
+
this.requireApiKey(`${group}.${method}`);
|
|
88
|
+
return new Job(this, group, method, body, options);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
function sleep(ms) {
|
|
92
|
+
return new Promise((r) => setTimeout(r, ms));
|
|
93
|
+
}
|
|
94
|
+
export async function toApiError(res) {
|
|
95
|
+
let payload = {};
|
|
96
|
+
try {
|
|
97
|
+
payload = await res.json();
|
|
98
|
+
}
|
|
99
|
+
catch {
|
|
100
|
+
/* non-JSON body */
|
|
101
|
+
}
|
|
102
|
+
const err = new Error(payload.error || res.statusText);
|
|
103
|
+
err.status = res.status;
|
|
104
|
+
err.hint = payload.hint;
|
|
105
|
+
return err;
|
|
106
|
+
}
|
|
107
|
+
//# sourceMappingURL=http-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http-client.js","sourceRoot":"","sources":["../src/http-client.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @clawvard/sdk — unified service client for Clawvard's composed /
|
|
3
|
+
* long-running / external-API-integrated services.
|
|
4
|
+
*
|
|
5
|
+
* ⚠️ NOT FOR LLM PASSTHROUGHS. Chat, embeddings, Whisper, TTS, DALL·E
|
|
6
|
+
* etc. are served by Token Relay at `https://token.clawvard.school`
|
|
7
|
+
* with `sk-xxx` keys. Use the OpenAI SDK (or any OpenAI-compatible
|
|
8
|
+
* client) pointed at that base URL for those.
|
|
9
|
+
*
|
|
10
|
+
* This SDK covers:
|
|
11
|
+
* - Composed workflows (multi-step recipes)
|
|
12
|
+
* - Long-running jobs (video render, batch processing)
|
|
13
|
+
* - External-API integrations (Shotstack, Mux, Replicate, ...)
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* import { Clawvard } from "@clawvard/sdk";
|
|
17
|
+
*
|
|
18
|
+
* const cv = new Clawvard({ apiKey: "sk-xxx" });
|
|
19
|
+
*
|
|
20
|
+
* // Smoke test (proxy)
|
|
21
|
+
* const { ip } = await cv.util.ipCheck();
|
|
22
|
+
*
|
|
23
|
+
* // Job — auto-polls to completion with progress callback
|
|
24
|
+
* const result = await cv.util.delayEcho({ seconds: 5 })
|
|
25
|
+
* .onProgress((pct, note) => console.log(`${(pct * 100).toFixed(0)}% — ${note}`))
|
|
26
|
+
* .wait();
|
|
27
|
+
*
|
|
28
|
+
* // Arbitrary registered service by id (untyped escape hatch)
|
|
29
|
+
* const post = await cv.workflow.run("workflow.podcast2blog", { audioUrl: "..." }).wait();
|
|
30
|
+
*/
|
|
31
|
+
import { HttpClient } from "./http-client";
|
|
32
|
+
import { Job } from "./job";
|
|
33
|
+
import { GeneratedClient } from "./generated";
|
|
34
|
+
import type { ClawvardPlugin } from "./plugin";
|
|
35
|
+
export { Job } from "./job";
|
|
36
|
+
export { HttpClient } from "./http-client";
|
|
37
|
+
export type { InvokeOptions } from "./http-client";
|
|
38
|
+
export type { ServiceTypeMap, InputOf, OutputOf, InputArgs, } from "./service-types";
|
|
39
|
+
export type { ClawvardPlugin, ClawvardInstance } from "./plugin";
|
|
40
|
+
export { ClawvardError, MissingApiKeyError } from "./errors";
|
|
41
|
+
export interface ClawvardConfig {
|
|
42
|
+
/** Token Relay-issued `sk-xxx` API key. Mint or list yours at
|
|
43
|
+
* https://clawvard.school/token-relay. The same key works for the
|
|
44
|
+
* OpenAI SDK pointed at `https://token.clawvard.school` AND for
|
|
45
|
+
* this SDK — there's no separate "Clawvard key" any more.
|
|
46
|
+
*
|
|
47
|
+
* Optional — local-only methods (e.g. `cv.video.extractFrames` from
|
|
48
|
+
* `@clawvard/sdk-media`) work without it. Remote calls throw
|
|
49
|
+
* `MissingApiKeyError` when no key is configured. */
|
|
50
|
+
apiKey?: string;
|
|
51
|
+
/** Override base URL. Defaults to production. */
|
|
52
|
+
baseUrl?: string;
|
|
53
|
+
/** Poll interval for jobs, ms. Defaults to 2000. */
|
|
54
|
+
pollIntervalMs?: number;
|
|
55
|
+
/** Fetch implementation override (for testing / edge runtimes). */
|
|
56
|
+
fetch?: typeof globalThis.fetch;
|
|
57
|
+
/** Auto-retry policy for transient failures. Default = 3 attempts
|
|
58
|
+
* with exponential backoff (250ms base). Set `{maxRetries: 0}` to
|
|
59
|
+
* disable. POST/PUT/DELETE only retry on 5xx when the call carries
|
|
60
|
+
* an Idempotency-Key, but ALL methods retry on network errors. */
|
|
61
|
+
retry?: {
|
|
62
|
+
maxRetries: number;
|
|
63
|
+
baseDelayMs?: number;
|
|
64
|
+
};
|
|
65
|
+
/** School / capability plugins. Each plugin's `install()` runs once
|
|
66
|
+
* at construction and may attach namespaces to the instance. */
|
|
67
|
+
plugins?: ClawvardPlugin[];
|
|
68
|
+
}
|
|
69
|
+
/** The main SDK client. Composes the auto-generated namespace methods
|
|
70
|
+
* (one per registered service `group`) with hand-written platform
|
|
71
|
+
* helpers (`catalog`, `usage`, `usageFor`, `workflow.run`).
|
|
72
|
+
*
|
|
73
|
+
* When backend adds a new service to `src/lib/services/registry.ts`
|
|
74
|
+
* and runs `pnpm sdk:gen`, a new typed method appears on the
|
|
75
|
+
* appropriate namespace automatically. */
|
|
76
|
+
export declare class Clawvard extends GeneratedClient {
|
|
77
|
+
/** Untyped invocation by id — escape hatch for newly-registered
|
|
78
|
+
* services not yet in `ServiceTypeMap`, or for callers that don't
|
|
79
|
+
* want to bump their SDK version. */
|
|
80
|
+
readonly workflow: WorkflowNamespace;
|
|
81
|
+
/** Lower-level HTTP client. Use this when you need per-call options
|
|
82
|
+
* the generated namespace methods don't expose, e.g. an
|
|
83
|
+
* `Idempotency-Key` header:
|
|
84
|
+
*
|
|
85
|
+
* cv.client.invoke("video", "render", input, { idempotencyKey: "..." })
|
|
86
|
+
* cv.client.invokeJob("video", "removeSilence", input, { idempotencyKey: "..." })
|
|
87
|
+
* */
|
|
88
|
+
readonly client: HttpClient;
|
|
89
|
+
constructor(config?: ClawvardConfig);
|
|
90
|
+
/**
|
|
91
|
+
* Fetch the service catalog. Each entry carries pricing + runtime +
|
|
92
|
+
* access flags — enough to render a marketplace tile without any
|
|
93
|
+
* other request. Public endpoint, no auth required.
|
|
94
|
+
*/
|
|
95
|
+
catalog(): Promise<ServiceCatalogEntry[]>;
|
|
96
|
+
/**
|
|
97
|
+
* Caller's usage across every registered service. Auth required.
|
|
98
|
+
* Services never called show zero stats so the UI can render a
|
|
99
|
+
* complete table.
|
|
100
|
+
*/
|
|
101
|
+
usage(): Promise<UsageReport>;
|
|
102
|
+
/**
|
|
103
|
+
* Caller's usage of a single service. Pass `includeHistory: true`
|
|
104
|
+
* to also get the N most recent invocation rows.
|
|
105
|
+
*/
|
|
106
|
+
usageFor(group: string, method: string, options?: {
|
|
107
|
+
includeHistory?: boolean;
|
|
108
|
+
limit?: number;
|
|
109
|
+
}): Promise<SingleServiceUsage>;
|
|
110
|
+
}
|
|
111
|
+
/** Untyped invocation by service id — for services not yet in
|
|
112
|
+
* `ServiceTypeMap` or for callers who prefer string-keyed access. */
|
|
113
|
+
declare class WorkflowNamespace {
|
|
114
|
+
private readonly c;
|
|
115
|
+
constructor(c: HttpClient);
|
|
116
|
+
/** Composable workflow / generic invoke. Returns a `Job<T>` so the
|
|
117
|
+
* caller can await `.wait()` for both proxy and job services
|
|
118
|
+
* (proxy services complete on the first poll). */
|
|
119
|
+
run<T>(id: string, input: unknown): Job<T>;
|
|
120
|
+
}
|
|
121
|
+
/** Price display bundled with every catalog entry. */
|
|
122
|
+
export interface PriceDisplay {
|
|
123
|
+
/** Authoritative price — what gets deducted on success. */
|
|
124
|
+
credits: number;
|
|
125
|
+
/** ¥ at the published rate (10 credits = ¥1). 2dp. */
|
|
126
|
+
cny: number;
|
|
127
|
+
/** $ at the published rate (100 credits = $1). 4dp. */
|
|
128
|
+
usd: number;
|
|
129
|
+
}
|
|
130
|
+
export interface ServiceCatalogEntry {
|
|
131
|
+
id: string;
|
|
132
|
+
group: string;
|
|
133
|
+
method: string;
|
|
134
|
+
summary: string;
|
|
135
|
+
description?: string;
|
|
136
|
+
costCredits: number;
|
|
137
|
+
approxCostHintUsd?: number;
|
|
138
|
+
runtime: "proxy" | "job" | "local";
|
|
139
|
+
pricing: PriceDisplay;
|
|
140
|
+
access?: {
|
|
141
|
+
beta?: boolean;
|
|
142
|
+
requiresCoursePurchase?: string;
|
|
143
|
+
minAccountTier?: string;
|
|
144
|
+
};
|
|
145
|
+
rateLimit?: {
|
|
146
|
+
perMinute?: number;
|
|
147
|
+
perHour?: number;
|
|
148
|
+
perDay?: number;
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
/** One row of per-service usage for a specific user. */
|
|
152
|
+
export interface ServiceUsage {
|
|
153
|
+
serviceId: string;
|
|
154
|
+
calls: number;
|
|
155
|
+
refunded: number;
|
|
156
|
+
netCalls: number;
|
|
157
|
+
creditsSpent: number;
|
|
158
|
+
lastCalledAt: string | null;
|
|
159
|
+
}
|
|
160
|
+
/** Shape of `GET /api/services/usage`. */
|
|
161
|
+
export interface UsageReport {
|
|
162
|
+
version: 1;
|
|
163
|
+
totals: {
|
|
164
|
+
calls: number;
|
|
165
|
+
refunded: number;
|
|
166
|
+
netCalls: number;
|
|
167
|
+
creditsSpent: number;
|
|
168
|
+
};
|
|
169
|
+
services: ServiceUsage[];
|
|
170
|
+
}
|
|
171
|
+
/** One row of invocation history. */
|
|
172
|
+
export interface InvocationRecord {
|
|
173
|
+
invocationId: string;
|
|
174
|
+
creditsSpent: number;
|
|
175
|
+
createdAt: string;
|
|
176
|
+
refunded: boolean;
|
|
177
|
+
}
|
|
178
|
+
/** Shape of `GET /api/services/usage/:group/:method`. */
|
|
179
|
+
export interface SingleServiceUsage {
|
|
180
|
+
version: 1;
|
|
181
|
+
serviceId: string;
|
|
182
|
+
summary: ServiceUsage;
|
|
183
|
+
history?: InvocationRecord[];
|
|
184
|
+
}
|
|
185
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @clawvard/sdk — unified service client for Clawvard's composed /
|
|
3
|
+
* long-running / external-API-integrated services.
|
|
4
|
+
*
|
|
5
|
+
* ⚠️ NOT FOR LLM PASSTHROUGHS. Chat, embeddings, Whisper, TTS, DALL·E
|
|
6
|
+
* etc. are served by Token Relay at `https://token.clawvard.school`
|
|
7
|
+
* with `sk-xxx` keys. Use the OpenAI SDK (or any OpenAI-compatible
|
|
8
|
+
* client) pointed at that base URL for those.
|
|
9
|
+
*
|
|
10
|
+
* This SDK covers:
|
|
11
|
+
* - Composed workflows (multi-step recipes)
|
|
12
|
+
* - Long-running jobs (video render, batch processing)
|
|
13
|
+
* - External-API integrations (Shotstack, Mux, Replicate, ...)
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* import { Clawvard } from "@clawvard/sdk";
|
|
17
|
+
*
|
|
18
|
+
* const cv = new Clawvard({ apiKey: "sk-xxx" });
|
|
19
|
+
*
|
|
20
|
+
* // Smoke test (proxy)
|
|
21
|
+
* const { ip } = await cv.util.ipCheck();
|
|
22
|
+
*
|
|
23
|
+
* // Job — auto-polls to completion with progress callback
|
|
24
|
+
* const result = await cv.util.delayEcho({ seconds: 5 })
|
|
25
|
+
* .onProgress((pct, note) => console.log(`${(pct * 100).toFixed(0)}% — ${note}`))
|
|
26
|
+
* .wait();
|
|
27
|
+
*
|
|
28
|
+
* // Arbitrary registered service by id (untyped escape hatch)
|
|
29
|
+
* const post = await cv.workflow.run("workflow.podcast2blog", { audioUrl: "..." }).wait();
|
|
30
|
+
*/
|
|
31
|
+
import { HttpClient } from "./http-client";
|
|
32
|
+
import { GeneratedClient } from "./generated";
|
|
33
|
+
export { Job } from "./job";
|
|
34
|
+
export { HttpClient } from "./http-client";
|
|
35
|
+
export { ClawvardError, MissingApiKeyError } from "./errors";
|
|
36
|
+
const DEFAULT_BASE_URL = "https://clawvard.school";
|
|
37
|
+
const DEFAULT_POLL_MS = 2000;
|
|
38
|
+
/** The main SDK client. Composes the auto-generated namespace methods
|
|
39
|
+
* (one per registered service `group`) with hand-written platform
|
|
40
|
+
* helpers (`catalog`, `usage`, `usageFor`, `workflow.run`).
|
|
41
|
+
*
|
|
42
|
+
* When backend adds a new service to `src/lib/services/registry.ts`
|
|
43
|
+
* and runs `pnpm sdk:gen`, a new typed method appears on the
|
|
44
|
+
* appropriate namespace automatically. */
|
|
45
|
+
export class Clawvard extends GeneratedClient {
|
|
46
|
+
/** Untyped invocation by id — escape hatch for newly-registered
|
|
47
|
+
* services not yet in `ServiceTypeMap`, or for callers that don't
|
|
48
|
+
* want to bump their SDK version. */
|
|
49
|
+
workflow;
|
|
50
|
+
/** Lower-level HTTP client. Use this when you need per-call options
|
|
51
|
+
* the generated namespace methods don't expose, e.g. an
|
|
52
|
+
* `Idempotency-Key` header:
|
|
53
|
+
*
|
|
54
|
+
* cv.client.invoke("video", "render", input, { idempotencyKey: "..." })
|
|
55
|
+
* cv.client.invokeJob("video", "removeSilence", input, { idempotencyKey: "..." })
|
|
56
|
+
* */
|
|
57
|
+
client;
|
|
58
|
+
constructor(config = {}) {
|
|
59
|
+
const http = new HttpClient({
|
|
60
|
+
...(config.apiKey ? { apiKey: config.apiKey } : {}),
|
|
61
|
+
baseUrl: config.baseUrl || DEFAULT_BASE_URL,
|
|
62
|
+
pollIntervalMs: config.pollIntervalMs ?? DEFAULT_POLL_MS,
|
|
63
|
+
fetchImpl: config.fetch || globalThis.fetch.bind(globalThis),
|
|
64
|
+
retry: config.retry
|
|
65
|
+
? { maxRetries: config.retry.maxRetries, baseDelayMs: config.retry.baseDelayMs ?? 250 }
|
|
66
|
+
: { maxRetries: 3, baseDelayMs: 250 },
|
|
67
|
+
});
|
|
68
|
+
super(http);
|
|
69
|
+
this.client = http;
|
|
70
|
+
this.workflow = new WorkflowNamespace(http);
|
|
71
|
+
// Run plugins last so they can inspect / wrap previously-installed
|
|
72
|
+
// namespaces if needed. Each plugin attaches its own namespaces;
|
|
73
|
+
// declaration merging in the plugin's own package types them.
|
|
74
|
+
if (config.plugins) {
|
|
75
|
+
for (const plugin of config.plugins) {
|
|
76
|
+
plugin.install(this, http);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Fetch the service catalog. Each entry carries pricing + runtime +
|
|
82
|
+
* access flags — enough to render a marketplace tile without any
|
|
83
|
+
* other request. Public endpoint, no auth required.
|
|
84
|
+
*/
|
|
85
|
+
async catalog() {
|
|
86
|
+
const res = await this.client.raw("/api/services/catalog", { method: "GET" });
|
|
87
|
+
const json = (await res.json());
|
|
88
|
+
return json.services;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Caller's usage across every registered service. Auth required.
|
|
92
|
+
* Services never called show zero stats so the UI can render a
|
|
93
|
+
* complete table.
|
|
94
|
+
*/
|
|
95
|
+
async usage() {
|
|
96
|
+
const res = await this.client.raw("/api/services/usage", { method: "GET" });
|
|
97
|
+
return (await res.json());
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Caller's usage of a single service. Pass `includeHistory: true`
|
|
101
|
+
* to also get the N most recent invocation rows.
|
|
102
|
+
*/
|
|
103
|
+
async usageFor(group, method, options) {
|
|
104
|
+
const qs = new URLSearchParams();
|
|
105
|
+
if (options?.includeHistory)
|
|
106
|
+
qs.set("history", "1");
|
|
107
|
+
if (options?.limit)
|
|
108
|
+
qs.set("limit", String(options.limit));
|
|
109
|
+
const suffix = qs.toString() ? `?${qs.toString()}` : "";
|
|
110
|
+
const res = await this.client.raw(`/api/services/usage/${group}/${method}${suffix}`, { method: "GET" });
|
|
111
|
+
return (await res.json());
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
/** Untyped invocation by service id — for services not yet in
|
|
115
|
+
* `ServiceTypeMap` or for callers who prefer string-keyed access. */
|
|
116
|
+
class WorkflowNamespace {
|
|
117
|
+
c;
|
|
118
|
+
constructor(c) {
|
|
119
|
+
this.c = c;
|
|
120
|
+
}
|
|
121
|
+
/** Composable workflow / generic invoke. Returns a `Job<T>` so the
|
|
122
|
+
* caller can await `.wait()` for both proxy and job services
|
|
123
|
+
* (proxy services complete on the first poll). */
|
|
124
|
+
run(id, input) {
|
|
125
|
+
const [group, method] = id.includes(".") ? id.split(".", 2) : ["workflow", id];
|
|
126
|
+
return this.c.invokeJob(group, method, input);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/job.d.ts
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Job — handle for a long-running service invocation. Auto-starts on
|
|
3
|
+
* construction, exposes `.onProgress(cb)` for incremental updates,
|
|
4
|
+
* `.wait()` to poll to completion, and `.cancel()` to abort.
|
|
5
|
+
*/
|
|
6
|
+
import { HttpClient, type InvokeOptions } from "./http-client";
|
|
7
|
+
export declare class Job<T> {
|
|
8
|
+
private readonly client;
|
|
9
|
+
private readonly group;
|
|
10
|
+
private readonly method;
|
|
11
|
+
private readonly input;
|
|
12
|
+
private readonly options?;
|
|
13
|
+
private jobId;
|
|
14
|
+
private progressCallback;
|
|
15
|
+
private readonly started;
|
|
16
|
+
constructor(client: HttpClient, group: string, method: string, input: unknown, options?: InvokeOptions | undefined);
|
|
17
|
+
private start;
|
|
18
|
+
/** Register a callback for each progress tick. Chain before `.wait()`. */
|
|
19
|
+
onProgress(cb: (pct: number, note?: string) => void): this;
|
|
20
|
+
/** Poll until the job reaches a terminal state. Throws on failure. */
|
|
21
|
+
wait(): Promise<T>;
|
|
22
|
+
/** Fire-and-forget: get the job ID without waiting. */
|
|
23
|
+
id(): Promise<string>;
|
|
24
|
+
/** Cancel the job. If still pending/running, the platform refunds
|
|
25
|
+
* the credits that were charged on creation. Returns the new
|
|
26
|
+
* status; resolves to `"cancelled"` if the cancel landed before a
|
|
27
|
+
* terminal state, or the existing terminal state if the worker
|
|
28
|
+
* already finished. */
|
|
29
|
+
cancel(): Promise<{
|
|
30
|
+
status: "cancelled" | "completed" | "failed";
|
|
31
|
+
refunded: boolean;
|
|
32
|
+
}>;
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=job.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"job.d.ts","sourceRoot":"","sources":["../src/job.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,UAAU,EAAc,KAAK,aAAa,EAAE,MAAM,eAAe,CAAC;AAE3E,qBAAa,GAAG,CAAC,CAAC;IAMd,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC;IAT3B,OAAO,CAAC,KAAK,CAAuB;IACpC,OAAO,CAAC,gBAAgB,CAAuD;IAC/E,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAgB;gBAGrB,MAAM,EAAE,UAAU,EAClB,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,OAAO,EACd,OAAO,CAAC,EAAE,aAAa,YAAA;YAK5B,KAAK;IAcnB,0EAA0E;IAC1E,UAAU,CAAC,EAAE,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,KAAK,IAAI,GAAG,IAAI;IAK1D,sEAAsE;IAChE,IAAI,IAAI,OAAO,CAAC,CAAC,CAAC;IA0BxB,uDAAuD;IACjD,EAAE,IAAI,OAAO,CAAC,MAAM,CAAC;IAM3B;;;;4BAIwB;IAClB,MAAM,IAAI,OAAO,CAAC;QAAE,MAAM,EAAE,WAAW,GAAG,WAAW,GAAG,QAAQ,CAAC;QAAC,QAAQ,EAAE,OAAO,CAAA;KAAE,CAAC;CAO7F"}
|
package/dist/job.js
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Job — handle for a long-running service invocation. Auto-starts on
|
|
3
|
+
* construction, exposes `.onProgress(cb)` for incremental updates,
|
|
4
|
+
* `.wait()` to poll to completion, and `.cancel()` to abort.
|
|
5
|
+
*/
|
|
6
|
+
import { toApiError } from "./http-client";
|
|
7
|
+
export class Job {
|
|
8
|
+
client;
|
|
9
|
+
group;
|
|
10
|
+
method;
|
|
11
|
+
input;
|
|
12
|
+
options;
|
|
13
|
+
jobId = null;
|
|
14
|
+
progressCallback = null;
|
|
15
|
+
started;
|
|
16
|
+
constructor(client, group, method, input, options) {
|
|
17
|
+
this.client = client;
|
|
18
|
+
this.group = group;
|
|
19
|
+
this.method = method;
|
|
20
|
+
this.input = input;
|
|
21
|
+
this.options = options;
|
|
22
|
+
this.started = this.start();
|
|
23
|
+
}
|
|
24
|
+
async start() {
|
|
25
|
+
const headers = { "Content-Type": "application/json" };
|
|
26
|
+
if (this.options?.idempotencyKey)
|
|
27
|
+
headers["Idempotency-Key"] = this.options.idempotencyKey;
|
|
28
|
+
if (this.options?.webhookUrl)
|
|
29
|
+
headers["X-Webhook-Url"] = this.options.webhookUrl;
|
|
30
|
+
const res = await this.client.raw(`/api/services/invoke/${this.group}/${this.method}`, {
|
|
31
|
+
method: "POST",
|
|
32
|
+
headers,
|
|
33
|
+
body: JSON.stringify(this.input ?? {}),
|
|
34
|
+
});
|
|
35
|
+
if (!res.ok)
|
|
36
|
+
throw await toApiError(res);
|
|
37
|
+
const body = (await res.json());
|
|
38
|
+
this.jobId = body.jobId;
|
|
39
|
+
}
|
|
40
|
+
/** Register a callback for each progress tick. Chain before `.wait()`. */
|
|
41
|
+
onProgress(cb) {
|
|
42
|
+
this.progressCallback = cb;
|
|
43
|
+
return this;
|
|
44
|
+
}
|
|
45
|
+
/** Poll until the job reaches a terminal state. Throws on failure. */
|
|
46
|
+
async wait() {
|
|
47
|
+
await this.started;
|
|
48
|
+
if (!this.jobId)
|
|
49
|
+
throw new Error("Job: never started");
|
|
50
|
+
let lastPct = -1;
|
|
51
|
+
for (;;) {
|
|
52
|
+
const res = await this.client.raw(`/api/services/jobs/${this.jobId}`, { method: "GET" });
|
|
53
|
+
if (!res.ok)
|
|
54
|
+
throw await toApiError(res);
|
|
55
|
+
const status = (await res.json());
|
|
56
|
+
if (status.progress && status.progress.pct !== lastPct) {
|
|
57
|
+
lastPct = status.progress.pct;
|
|
58
|
+
this.progressCallback?.(status.progress.pct, status.progress.note);
|
|
59
|
+
}
|
|
60
|
+
if (status.status === "completed")
|
|
61
|
+
return status.result;
|
|
62
|
+
if (status.status === "failed") {
|
|
63
|
+
const msg = status.error?.message ?? "job failed";
|
|
64
|
+
throw new Error(msg);
|
|
65
|
+
}
|
|
66
|
+
if (status.status === "cancelled")
|
|
67
|
+
throw new Error("job cancelled");
|
|
68
|
+
await sleep(this.client.pollIntervalMs);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
/** Fire-and-forget: get the job ID without waiting. */
|
|
72
|
+
async id() {
|
|
73
|
+
await this.started;
|
|
74
|
+
if (!this.jobId)
|
|
75
|
+
throw new Error("Job: never started");
|
|
76
|
+
return this.jobId;
|
|
77
|
+
}
|
|
78
|
+
/** Cancel the job. If still pending/running, the platform refunds
|
|
79
|
+
* the credits that were charged on creation. Returns the new
|
|
80
|
+
* status; resolves to `"cancelled"` if the cancel landed before a
|
|
81
|
+
* terminal state, or the existing terminal state if the worker
|
|
82
|
+
* already finished. */
|
|
83
|
+
async cancel() {
|
|
84
|
+
await this.started;
|
|
85
|
+
if (!this.jobId)
|
|
86
|
+
throw new Error("Job: never started");
|
|
87
|
+
const res = await this.client.raw(`/api/services/jobs/${this.jobId}`, { method: "DELETE" });
|
|
88
|
+
if (!res.ok)
|
|
89
|
+
throw await toApiError(res);
|
|
90
|
+
return (await res.json());
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
function sleep(ms) {
|
|
94
|
+
return new Promise((r) => setTimeout(r, ms));
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=job.js.map
|
package/dist/job.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"job.js","sourceRoot":"","sources":["../src/job.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAc,UAAU,EAAsB,MAAM,eAAe,CAAC;AAE3E,MAAM,OAAO,GAAG;IAMK;IACA;IACA;IACA;IACA;IATX,KAAK,GAAkB,IAAI,CAAC;IAC5B,gBAAgB,GAAkD,IAAI,CAAC;IAC9D,OAAO,CAAgB;IAExC,YACmB,MAAkB,EAClB,KAAa,EACb,MAAc,EACd,KAAc,EACd,OAAuB;QAJvB,WAAM,GAAN,MAAM,CAAY;QAClB,UAAK,GAAL,KAAK,CAAQ;QACb,WAAM,GAAN,MAAM,CAAQ;QACd,UAAK,GAAL,KAAK,CAAS;QACd,YAAO,GAAP,OAAO,CAAgB;QAExC,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC;IAC9B,CAAC;IAEO,KAAK,CAAC,KAAK;QACjB,MAAM,OAAO,GAA2B,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAC;QAC/E,IAAI,IAAI,CAAC,OAAO,EAAE,cAAc;YAAE,OAAO,CAAC,iBAAiB,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,cAAc,CAAC;QAC3F,IAAI,IAAI,CAAC,OAAO,EAAE,UAAU;YAAE,OAAO,CAAC,eAAe,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC;QACjF,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,wBAAwB,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,MAAM,EAAE,EAAE;YACrF,MAAM,EAAE,MAAM;YACd,OAAO;YACP,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC;SACvC,CAAC,CAAC;QACH,IAAI,CAAC,GAAG,CAAC,EAAE;YAAE,MAAM,MAAM,UAAU,CAAC,GAAG,CAAC,CAAC;QACzC,MAAM,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAsB,CAAC;QACrD,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC;IAC1B,CAAC;IAED,0EAA0E;IAC1E,UAAU,CAAC,EAAwC;QACjD,IAAI,CAAC,gBAAgB,GAAG,EAAE,CAAC;QAC3B,OAAO,IAAI,CAAC;IACd,CAAC;IAED,sEAAsE;IACtE,KAAK,CAAC,IAAI;QACR,MAAM,IAAI,CAAC,OAAO,CAAC;QACnB,IAAI,CAAC,IAAI,CAAC,KAAK;YAAE,MAAM,IAAI,KAAK,CAAC,oBAAoB,CAAC,CAAC;QAEvD,IAAI,OAAO,GAAG,CAAC,CAAC,CAAC;QACjB,SAAS,CAAC;YACR,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,sBAAsB,IAAI,CAAC,KAAK,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;YACzF,IAAI,CAAC,GAAG,CAAC,EAAE;gBAAE,MAAM,MAAM,UAAU,CAAC,GAAG,CAAC,CAAC;YACzC,MAAM,MAAM,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAiB,CAAC;YAElD,IAAI,MAAM,CAAC,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,GAAG,KAAK,OAAO,EAAE,CAAC;gBACvD,OAAO,GAAG,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC;gBAC9B,IAAI,CAAC,gBAAgB,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;YACrE,CAAC;YAED,IAAI,MAAM,CAAC,MAAM,KAAK,WAAW;gBAAE,OAAO,MAAM,CAAC,MAAW,CAAC;YAC7D,IAAI,MAAM,CAAC,MAAM,KAAK,QAAQ,EAAE,CAAC;gBAC/B,MAAM,GAAG,GAAG,MAAM,CAAC,KAAK,EAAE,OAAO,IAAI,YAAY,CAAC;gBAClD,MAAM,IAAI,KAAK,CAAC,GAAG,CAAC,CAAC;YACvB,CAAC;YACD,IAAI,MAAM,CAAC,MAAM,KAAK,WAAW;gBAAE,MAAM,IAAI,KAAK,CAAC,eAAe,CAAC,CAAC;YAEpE,MAAM,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC;QAC1C,CAAC;IACH,CAAC;IAED,uDAAuD;IACvD,KAAK,CAAC,EAAE;QACN,MAAM,IAAI,CAAC,OAAO,CAAC;QACnB,IAAI,CAAC,IAAI,CAAC,KAAK;YAAE,MAAM,IAAI,KAAK,CAAC,oBAAoB,CAAC,CAAC;QACvD,OAAO,IAAI,CAAC,KAAK,CAAC;IACpB,CAAC;IAED;;;;4BAIwB;IACxB,KAAK,CAAC,MAAM;QACV,MAAM,IAAI,CAAC,OAAO,CAAC;QACnB,IAAI,CAAC,IAAI,CAAC,KAAK;YAAE,MAAM,IAAI,KAAK,CAAC,oBAAoB,CAAC,CAAC;QACvD,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,sBAAsB,IAAI,CAAC,KAAK,EAAE,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAC;QAC5F,IAAI,CAAC,GAAG,CAAC,EAAE;YAAE,MAAM,MAAM,UAAU,CAAC,GAAG,CAAC,CAAC;QACzC,OAAO,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAwE,CAAC;IACnG,CAAC;CACF;AAWD,SAAS,KAAK,CAAC,EAAU;IACvB,OAAO,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;AAC/C,CAAC"}
|
package/dist/plugin.d.ts
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Plugin protocol — lets `@clawvard/sdk-<school>` packages register
|
|
3
|
+
* additional namespaces (and types via declaration merging) onto a
|
|
4
|
+
* `Clawvard` instance.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* import { Clawvard } from "@clawvard/sdk";
|
|
8
|
+
* import { mediaPlugin } from "@clawvard/sdk-media";
|
|
9
|
+
*
|
|
10
|
+
* const cv = new Clawvard({ apiKey, plugins: [mediaPlugin] });
|
|
11
|
+
* cv.media.translateSubtitles({...}); // typed via declaration merging
|
|
12
|
+
* cv.video.extractFrames({...}); // local helper, no apiKey needed
|
|
13
|
+
*/
|
|
14
|
+
import type { HttpClient } from "./http-client";
|
|
15
|
+
export interface ClawvardPlugin {
|
|
16
|
+
/** Stable name — for diagnostics / dedup. */
|
|
17
|
+
name: string;
|
|
18
|
+
/** Called once at construction. Mutate `cv` to add namespaces. */
|
|
19
|
+
install(cv: ClawvardInstance, http: HttpClient): void;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* The shape plugins see — `cv` is mutated to receive new namespace
|
|
23
|
+
* properties. Sub-packages declaration-merge their namespaces into
|
|
24
|
+
* `Clawvard` itself in their `index.ts` so end-user code sees a typed
|
|
25
|
+
* `cv.media.*` / `cv.video.*`.
|
|
26
|
+
*/
|
|
27
|
+
export interface ClawvardInstance {
|
|
28
|
+
[namespace: string]: unknown;
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=plugin.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAEhD,MAAM,WAAW,cAAc;IAC7B,6CAA6C;IAC7C,IAAI,EAAE,MAAM,CAAC;IACb,kEAAkE;IAClE,OAAO,CAAC,EAAE,EAAE,gBAAgB,EAAE,IAAI,EAAE,UAAU,GAAG,IAAI,CAAC;CACvD;AAED;;;;;GAKG;AACH,MAAM,WAAW,gBAAgB;IAG/B,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC;CAC9B"}
|
package/dist/plugin.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Plugin protocol — lets `@clawvard/sdk-<school>` packages register
|
|
3
|
+
* additional namespaces (and types via declaration merging) onto a
|
|
4
|
+
* `Clawvard` instance.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* import { Clawvard } from "@clawvard/sdk";
|
|
8
|
+
* import { mediaPlugin } from "@clawvard/sdk-media";
|
|
9
|
+
*
|
|
10
|
+
* const cv = new Clawvard({ apiKey, plugins: [mediaPlugin] });
|
|
11
|
+
* cv.media.translateSubtitles({...}); // typed via declaration merging
|
|
12
|
+
* cv.video.extractFrames({...}); // local helper, no apiKey needed
|
|
13
|
+
*/
|
|
14
|
+
export {};
|
|
15
|
+
//# sourceMappingURL=plugin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin.js","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG"}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ServiceTypeMap — typed input/output per registered service id.
|
|
3
|
+
*
|
|
4
|
+
* Core SDK declares its own services here (util.*, plus any future
|
|
5
|
+
* shared text/audio/image entries). School sub-packages
|
|
6
|
+
* (`@clawvard/sdk-media`, etc.) extend this interface via
|
|
7
|
+
* declaration merging:
|
|
8
|
+
*
|
|
9
|
+
* declare module "@clawvard/sdk" {
|
|
10
|
+
* interface ServiceTypeMap {
|
|
11
|
+
* "media.translate-subtitles": { input: ...; output: ... };
|
|
12
|
+
* }
|
|
13
|
+
* }
|
|
14
|
+
*
|
|
15
|
+
* Services not in the map still work via the generated client, but
|
|
16
|
+
* their `input`/`output` fall back to `unknown`.
|
|
17
|
+
*
|
|
18
|
+
* Typical workflow when adding a service to **core**:
|
|
19
|
+
* 1. Add the entry to `SERVICES[]` in `src/lib/services/registry.ts`
|
|
20
|
+
* 2. Define the `Input`/`Output` interfaces below
|
|
21
|
+
* 3. Add `"<id>": { input: ...; output: ... }` to `ServiceTypeMap`
|
|
22
|
+
* 4. Run `pnpm sdk:gen`
|
|
23
|
+
*
|
|
24
|
+
* For a **school sub-package**: see `docs/services-onboarding.md`
|
|
25
|
+
* → "Adding a school sub-package".
|
|
26
|
+
*/
|
|
27
|
+
export interface UtilDelayEchoInput {
|
|
28
|
+
/** Seconds to sleep before echoing. Default 3, max 30. */
|
|
29
|
+
seconds?: number;
|
|
30
|
+
/** Arbitrary payload echoed back in the result. */
|
|
31
|
+
payload?: unknown;
|
|
32
|
+
}
|
|
33
|
+
export interface UtilDelayEchoOutput {
|
|
34
|
+
echoed: unknown;
|
|
35
|
+
sleptSeconds: number;
|
|
36
|
+
jobId: string;
|
|
37
|
+
}
|
|
38
|
+
export interface UtilIpCheckOutput {
|
|
39
|
+
ip: string;
|
|
40
|
+
}
|
|
41
|
+
export interface TextWordCountInput {
|
|
42
|
+
text: string;
|
|
43
|
+
}
|
|
44
|
+
export interface TextWordCountOutput {
|
|
45
|
+
chars: number;
|
|
46
|
+
charsNoWhitespace: number;
|
|
47
|
+
words: number;
|
|
48
|
+
lines: number;
|
|
49
|
+
sentences: number;
|
|
50
|
+
longestLineChars: number;
|
|
51
|
+
}
|
|
52
|
+
export interface TextHashInput {
|
|
53
|
+
text: string;
|
|
54
|
+
algorithm?: "sha256" | "sha1" | "md5";
|
|
55
|
+
}
|
|
56
|
+
export interface TextHashOutput {
|
|
57
|
+
algorithm: string;
|
|
58
|
+
hex: string;
|
|
59
|
+
}
|
|
60
|
+
export interface UrlQrCodeInput {
|
|
61
|
+
/** Text or URL to encode. Max 2000 chars. */
|
|
62
|
+
text: string;
|
|
63
|
+
/** Pixel size of one side (64-1024). Default 256. */
|
|
64
|
+
size?: number;
|
|
65
|
+
}
|
|
66
|
+
export interface UrlQrCodeOutput {
|
|
67
|
+
/** PNG data URI ready to drop into an <img src="…">. */
|
|
68
|
+
dataUri: string;
|
|
69
|
+
byteLength: number;
|
|
70
|
+
}
|
|
71
|
+
export interface UrlPreviewInput {
|
|
72
|
+
url: string;
|
|
73
|
+
}
|
|
74
|
+
export interface UrlPreviewOutput {
|
|
75
|
+
url: string;
|
|
76
|
+
title?: string;
|
|
77
|
+
description?: string;
|
|
78
|
+
image?: string;
|
|
79
|
+
siteName?: string;
|
|
80
|
+
type?: string;
|
|
81
|
+
}
|
|
82
|
+
export interface VideoRemoveSilenceInput {
|
|
83
|
+
inputUrl: string;
|
|
84
|
+
silenceThresholdDb?: number;
|
|
85
|
+
minSilenceMs?: number;
|
|
86
|
+
}
|
|
87
|
+
export interface VideoRemoveSilenceOutput {
|
|
88
|
+
outputUrl: string;
|
|
89
|
+
cutSeconds: number;
|
|
90
|
+
segmentsRemoved: number;
|
|
91
|
+
}
|
|
92
|
+
export interface ServiceTypeMap {
|
|
93
|
+
"util.ip-check": {
|
|
94
|
+
input: void;
|
|
95
|
+
output: UtilIpCheckOutput;
|
|
96
|
+
};
|
|
97
|
+
"util.delay-echo": {
|
|
98
|
+
input: UtilDelayEchoInput;
|
|
99
|
+
output: UtilDelayEchoOutput;
|
|
100
|
+
};
|
|
101
|
+
"text.word-count": {
|
|
102
|
+
input: TextWordCountInput;
|
|
103
|
+
output: TextWordCountOutput;
|
|
104
|
+
};
|
|
105
|
+
"text.hash": {
|
|
106
|
+
input: TextHashInput;
|
|
107
|
+
output: TextHashOutput;
|
|
108
|
+
};
|
|
109
|
+
"url.qr-code": {
|
|
110
|
+
input: UrlQrCodeInput;
|
|
111
|
+
output: UrlQrCodeOutput;
|
|
112
|
+
};
|
|
113
|
+
"url.preview": {
|
|
114
|
+
input: UrlPreviewInput;
|
|
115
|
+
output: UrlPreviewOutput;
|
|
116
|
+
};
|
|
117
|
+
"video.remove-silence": {
|
|
118
|
+
input: VideoRemoveSilenceInput;
|
|
119
|
+
output: VideoRemoveSilenceOutput;
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
/** Helper: resolve the input type for a given service id, or `unknown`. */
|
|
123
|
+
export type InputOf<Id extends string> = Id extends keyof ServiceTypeMap ? ServiceTypeMap[Id]["input"] : unknown;
|
|
124
|
+
/** Helper: resolve the output type for a given service id, or `unknown`. */
|
|
125
|
+
export type OutputOf<Id extends string> = Id extends keyof ServiceTypeMap ? ServiceTypeMap[Id]["output"] : unknown;
|
|
126
|
+
/** Helper: turn `InputOf<Id>` into a rest-parameter tuple. Services
|
|
127
|
+
* declared with `input: void` become callable with NO arguments
|
|
128
|
+
* (`cv.util.ipCheck()`); everything else takes one positional arg.
|
|
129
|
+
* The tuple always has length 1 so the generated code can read
|
|
130
|
+
* `args[0]` unconditionally — for void inputs that's `undefined`. */
|
|
131
|
+
export type InputArgs<Id extends string> = InputOf<Id> extends void ? [input?: undefined] : [input: InputOf<Id>];
|
|
132
|
+
//# sourceMappingURL=service-types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"service-types.d.ts","sourceRoot":"","sources":["../src/service-types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ServiceTypeMap — typed input/output per registered service id.
|
|
3
|
+
*
|
|
4
|
+
* Core SDK declares its own services here (util.*, plus any future
|
|
5
|
+
* shared text/audio/image entries). School sub-packages
|
|
6
|
+
* (`@clawvard/sdk-media`, etc.) extend this interface via
|
|
7
|
+
* declaration merging:
|
|
8
|
+
*
|
|
9
|
+
* declare module "@clawvard/sdk" {
|
|
10
|
+
* interface ServiceTypeMap {
|
|
11
|
+
* "media.translate-subtitles": { input: ...; output: ... };
|
|
12
|
+
* }
|
|
13
|
+
* }
|
|
14
|
+
*
|
|
15
|
+
* Services not in the map still work via the generated client, but
|
|
16
|
+
* their `input`/`output` fall back to `unknown`.
|
|
17
|
+
*
|
|
18
|
+
* Typical workflow when adding a service to **core**:
|
|
19
|
+
* 1. Add the entry to `SERVICES[]` in `src/lib/services/registry.ts`
|
|
20
|
+
* 2. Define the `Input`/`Output` interfaces below
|
|
21
|
+
* 3. Add `"<id>": { input: ...; output: ... }` to `ServiceTypeMap`
|
|
22
|
+
* 4. Run `pnpm sdk:gen`
|
|
23
|
+
*
|
|
24
|
+
* For a **school sub-package**: see `docs/services-onboarding.md`
|
|
25
|
+
* → "Adding a school sub-package".
|
|
26
|
+
*/
|
|
27
|
+
export {};
|
|
28
|
+
//# sourceMappingURL=service-types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"service-types.js","sourceRoot":"","sources":["../src/service-types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG"}
|
package/package.json
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@clawvard/sdk",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Clawvard unified service SDK — call every Clawvard service with one typed client.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"module": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.js"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"dist",
|
|
17
|
+
"README.md"
|
|
18
|
+
],
|
|
19
|
+
"scripts": {
|
|
20
|
+
"build": "tsc",
|
|
21
|
+
"prepublishOnly": "pnpm build"
|
|
22
|
+
},
|
|
23
|
+
"keywords": [
|
|
24
|
+
"clawvard",
|
|
25
|
+
"ai",
|
|
26
|
+
"llm",
|
|
27
|
+
"agent",
|
|
28
|
+
"video",
|
|
29
|
+
"sdk"
|
|
30
|
+
],
|
|
31
|
+
"license": "MIT",
|
|
32
|
+
"engines": {
|
|
33
|
+
"node": ">=18"
|
|
34
|
+
}
|
|
35
|
+
}
|