@intfunc/sdk 0.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 -0
- package/dist/client.d.ts +149 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +198 -0
- package/dist/client.js.map +1 -0
- package/dist/errors.d.ts +46 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +74 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -0
- package/dist/slug.d.ts +30 -0
- package/dist/slug.d.ts.map +1 -0
- package/dist/slug.js +50 -0
- package/dist/slug.js.map +1 -0
- package/package.json +28 -0
package/README.md
ADDED
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
# @intfunc/sdk
|
|
2
|
+
|
|
3
|
+
Official TypeScript client for the **Intelligent Functions** API. An intelligent
|
|
4
|
+
function is a stateless, versioned function backed by a single LLM call: you give
|
|
5
|
+
it a typed input, it returns a typed, schema-validated output.
|
|
6
|
+
|
|
7
|
+
```ts
|
|
8
|
+
const summarize = client.fn<{ text: string }, { summary: string }>("blog/summarize");
|
|
9
|
+
const { summary } = await summarize({ text: article });
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## Install
|
|
13
|
+
|
|
14
|
+
```sh
|
|
15
|
+
npm install @intfunc/sdk
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Requires a runtime with a global `fetch` (Node 18+, Bun, Deno, Cloudflare
|
|
19
|
+
Workers, or the browser). To use a custom implementation, pass `options.fetch`.
|
|
20
|
+
|
|
21
|
+
## Quickstart
|
|
22
|
+
|
|
23
|
+
```ts
|
|
24
|
+
import { IntelligentFunctions } from "@intfunc/sdk";
|
|
25
|
+
|
|
26
|
+
// Reads INTFUNC_API_KEY (and optional INTFUNC_BASE_URL) from the environment.
|
|
27
|
+
const client = new IntelligentFunctions();
|
|
28
|
+
|
|
29
|
+
// Bind a "projectSlug/functionSlug" key to a reusable, typed handle.
|
|
30
|
+
const sentiment = client.fn<{ text: string }, { label: string; score: number }>(
|
|
31
|
+
"blog/sentiment",
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
// Call it like a local async function — you get just the output.
|
|
35
|
+
const { label, score } = await sentiment({ text: "I love this!" });
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
The `fn()` handle is the recommended way to call functions: define it once, then
|
|
39
|
+
invoke it anywhere. Provide the input/output type parameters and every call site
|
|
40
|
+
is fully typed.
|
|
41
|
+
|
|
42
|
+
## Configuration
|
|
43
|
+
|
|
44
|
+
`new IntelligentFunctions(options?)` — every option is optional and falls back to
|
|
45
|
+
an environment variable or a default.
|
|
46
|
+
|
|
47
|
+
| Option | Env var | Default | Description |
|
|
48
|
+
| ------------ | ------------------- | -------------------------- | -------------------------------------------------- |
|
|
49
|
+
| `apiKey` | `INTFUNC_API_KEY` | — | Project API key issued from the console. |
|
|
50
|
+
| `baseUrl` | `INTFUNC_BASE_URL` | `https://api.intfunc.com` | API base URL. |
|
|
51
|
+
| `timeout` | — | `120000` (ms) | Per-request timeout; aborts and retries if exceeded. |
|
|
52
|
+
| `maxRetries` | — | `2` | Retries on network errors, 408, 429, and 5xx. |
|
|
53
|
+
| `fetch` | — | `globalThis.fetch` | Custom fetch implementation. |
|
|
54
|
+
|
|
55
|
+
```ts
|
|
56
|
+
const client = new IntelligentFunctions({
|
|
57
|
+
apiKey: "sk_...",
|
|
58
|
+
timeout: 60_000,
|
|
59
|
+
maxRetries: 3,
|
|
60
|
+
});
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
An API key is scoped to a single project, so a handle can only invoke functions
|
|
64
|
+
in that key's own project — a mismatched `projectSlug` returns
|
|
65
|
+
`FunctionNotFoundError`.
|
|
66
|
+
|
|
67
|
+
## Calling functions
|
|
68
|
+
|
|
69
|
+
### Handles (recommended)
|
|
70
|
+
|
|
71
|
+
```ts
|
|
72
|
+
const classify = client.fn<{ text: string }, { category: string }>("support/classify");
|
|
73
|
+
|
|
74
|
+
await classify({ text }); // -> { category } (just the output)
|
|
75
|
+
await classify.run({ text }); // -> { output, provider, model, version, usage, runId }
|
|
76
|
+
const v3 = classify.pin(3); // a handle locked to version 3
|
|
77
|
+
await v3({ text }); // always runs version 3
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
- **`handle(input, options?)`** — returns the output only. The 90% case.
|
|
81
|
+
- **`handle.run(input, options?)`** — returns the full envelope with token
|
|
82
|
+
`usage`, the resolved `version`, and the captured dataset `runId`.
|
|
83
|
+
- **`handle.pin(version)`** — a new handle bound to a fixed version. Without a
|
|
84
|
+
pin, calls always use the latest published version.
|
|
85
|
+
|
|
86
|
+
Per-call `options`:
|
|
87
|
+
|
|
88
|
+
```ts
|
|
89
|
+
const controller = new AbortController();
|
|
90
|
+
await classify({ text }, {
|
|
91
|
+
version: 2, // one-off version override
|
|
92
|
+
timeout: 30_000, // override the client timeout for this call
|
|
93
|
+
signal: controller.signal // cancel in flight
|
|
94
|
+
});
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### Direct method
|
|
98
|
+
|
|
99
|
+
If you prefer not to bind a handle:
|
|
100
|
+
|
|
101
|
+
```ts
|
|
102
|
+
const result = await client.runFunction<{ category: string }>(
|
|
103
|
+
"support", "classify", { text }, { version: 2 },
|
|
104
|
+
);
|
|
105
|
+
result.output; // { category }
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## Errors
|
|
109
|
+
|
|
110
|
+
Every non-2xx response throws an `ApiError`, or a subclass you can branch on
|
|
111
|
+
without inspecting `.status`:
|
|
112
|
+
|
|
113
|
+
```ts
|
|
114
|
+
import {
|
|
115
|
+
InputValidationError, // 400 — input didn't match the function's schema
|
|
116
|
+
AuthError, // 401 — missing/invalid/revoked API key
|
|
117
|
+
FunctionNotFoundError,// 404 — no such function (or wrong project)
|
|
118
|
+
FunctionRunError, // 502 — the model call failed / produced no valid output
|
|
119
|
+
ApiError, // base — any other status
|
|
120
|
+
} from "@intfunc/sdk";
|
|
121
|
+
|
|
122
|
+
try {
|
|
123
|
+
await sentiment({ text });
|
|
124
|
+
} catch (err) {
|
|
125
|
+
if (err instanceof InputValidationError) {
|
|
126
|
+
// fix the input
|
|
127
|
+
} else if (err instanceof FunctionRunError) {
|
|
128
|
+
// transient model failure — surface or retry manually
|
|
129
|
+
} else if (err instanceof ApiError) {
|
|
130
|
+
console.error(err.status, err.message, err.body);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
## Retries & timeouts
|
|
136
|
+
|
|
137
|
+
Requests are retried automatically with exponential backoff (plus jitter, and
|
|
138
|
+
honoring a `Retry-After` header) on network errors, timeouts, `408`, `429`, and
|
|
139
|
+
`5xx` responses — up to `maxRetries` times. A caller-initiated `AbortSignal` is
|
|
140
|
+
never retried. Set `maxRetries: 0` to disable.
|
|
141
|
+
|
|
142
|
+
## Managing functions
|
|
143
|
+
|
|
144
|
+
```ts
|
|
145
|
+
await client.listFunctions({ project: "blog" });
|
|
146
|
+
await client.getFunction("blog", "summarize", { version: 2 });
|
|
147
|
+
await client.createFunction({
|
|
148
|
+
projectId: "prj_...",
|
|
149
|
+
name: "Summarize",
|
|
150
|
+
provider: "anthropic",
|
|
151
|
+
model: "claude-sonnet-5",
|
|
152
|
+
prompt: "Summarize the input article in one sentence.",
|
|
153
|
+
inputSchema: { type: "object", properties: { text: { type: "string" } }, required: ["text"] },
|
|
154
|
+
outputSchema: { type: "object", properties: { summary: { type: "string" } }, required: ["summary"] },
|
|
155
|
+
});
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
Creating a function with an existing `slug` publishes the next **version** of it.
|
|
159
|
+
|
|
160
|
+
## API reference
|
|
161
|
+
|
|
162
|
+
| Member | Returns |
|
|
163
|
+
| ------------------------------------------------- | -------------------------- |
|
|
164
|
+
| `fn<In, Out>(key, { version? })` | `FunctionHandle<In, Out>` |
|
|
165
|
+
| `runFunction<T>(project, fn, input, options?)` | `RunIFunctionResult<T>` |
|
|
166
|
+
| `getFunction(project, fn, { version? })` | `IFunction` |
|
|
167
|
+
| `listFunctions({ project? })` | `IFunction[]` |
|
|
168
|
+
| `createFunction(input)` | `IFunction` |
|
|
169
|
+
| `health()` | `{ status: string }` |
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
export interface ClientOptions {
|
|
2
|
+
/**
|
|
3
|
+
* Base URL of the API, e.g. https://api.intfunc.com.
|
|
4
|
+
* Falls back to `INTFUNC_BASE_URL`, then the hosted default.
|
|
5
|
+
*/
|
|
6
|
+
baseUrl?: string;
|
|
7
|
+
/** API key issued from the console. Falls back to `INTFUNC_API_KEY`. */
|
|
8
|
+
apiKey?: string;
|
|
9
|
+
/**
|
|
10
|
+
* Per-request timeout in milliseconds (default 120_000). The request is
|
|
11
|
+
* aborted and — if retries remain — retried when it exceeds this.
|
|
12
|
+
*/
|
|
13
|
+
timeout?: number;
|
|
14
|
+
/**
|
|
15
|
+
* How many times to retry a failed request (default 2). Retries apply to
|
|
16
|
+
* network errors, timeouts, 408, 429, and 5xx responses, with backoff.
|
|
17
|
+
*/
|
|
18
|
+
maxRetries?: number;
|
|
19
|
+
/** Optional custom fetch implementation (defaults to global fetch). */
|
|
20
|
+
fetch?: typeof fetch;
|
|
21
|
+
}
|
|
22
|
+
/** Per-call overrides for a function invocation. */
|
|
23
|
+
export interface RunOptions {
|
|
24
|
+
/** Pin to a specific function version (defaults to latest). */
|
|
25
|
+
version?: number;
|
|
26
|
+
/** Abort the call early. Composes with the client-level timeout. */
|
|
27
|
+
signal?: AbortSignal;
|
|
28
|
+
/** Override the client-level timeout for this call, in milliseconds. */
|
|
29
|
+
timeout?: number;
|
|
30
|
+
}
|
|
31
|
+
export interface User {
|
|
32
|
+
id: string;
|
|
33
|
+
email: string;
|
|
34
|
+
name: string | null;
|
|
35
|
+
createdAt: string;
|
|
36
|
+
}
|
|
37
|
+
/** An intelligent function: a stateless function backed by a single LLM call. */
|
|
38
|
+
export interface IFunction {
|
|
39
|
+
id: string;
|
|
40
|
+
userId: string;
|
|
41
|
+
projectId: string;
|
|
42
|
+
slug: string;
|
|
43
|
+
name: string | null;
|
|
44
|
+
provider: string;
|
|
45
|
+
model: string;
|
|
46
|
+
prompt: string;
|
|
47
|
+
inputSchema: Record<string, unknown>;
|
|
48
|
+
outputSchema: Record<string, unknown>;
|
|
49
|
+
version: number;
|
|
50
|
+
createdAt: string;
|
|
51
|
+
}
|
|
52
|
+
export interface CreateIFunctionInput {
|
|
53
|
+
/** The project this function belongs to. */
|
|
54
|
+
projectId: string;
|
|
55
|
+
/** Optional; when omitted the slug is derived from `name` server-side. */
|
|
56
|
+
slug?: string;
|
|
57
|
+
name?: string;
|
|
58
|
+
provider: string;
|
|
59
|
+
model: string;
|
|
60
|
+
prompt: string;
|
|
61
|
+
inputSchema: Record<string, unknown>;
|
|
62
|
+
outputSchema: Record<string, unknown>;
|
|
63
|
+
}
|
|
64
|
+
export interface RunIFunctionResult<T = unknown> {
|
|
65
|
+
output: T;
|
|
66
|
+
provider: string;
|
|
67
|
+
model: string;
|
|
68
|
+
version: number;
|
|
69
|
+
usage?: {
|
|
70
|
+
inputTokens: number;
|
|
71
|
+
outputTokens: number;
|
|
72
|
+
};
|
|
73
|
+
/** Id of the captured dataset row for this run (when capture is enabled). */
|
|
74
|
+
runId?: string;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* A reusable, typed reference to a single function. Call it like a function to
|
|
78
|
+
* get just the output; call `.run()` for the full result envelope.
|
|
79
|
+
*
|
|
80
|
+
* @example
|
|
81
|
+
* const sentiment = client.fn<{ text: string }, { label: string }>("blog/sentiment");
|
|
82
|
+
* const { label } = await sentiment({ text: "great post" }); // just the output
|
|
83
|
+
* const full = await sentiment.run({ text: "great post" }); // + usage, version, runId
|
|
84
|
+
* const v3 = sentiment.pin(3); // handle locked to version 3
|
|
85
|
+
*/
|
|
86
|
+
export interface FunctionHandle<In extends Record<string, unknown>, Out> {
|
|
87
|
+
(input: In, options?: RunOptions): Promise<Out>;
|
|
88
|
+
/** Invoke and return the full result envelope (output + metadata). */
|
|
89
|
+
run(input: In, options?: RunOptions): Promise<RunIFunctionResult<Out>>;
|
|
90
|
+
/** A new handle to the same function, pinned to `version`. */
|
|
91
|
+
pin(version: number): FunctionHandle<In, Out>;
|
|
92
|
+
/** The `projectSlug/functionSlug` key this handle points at. */
|
|
93
|
+
readonly key: string;
|
|
94
|
+
readonly projectSlug: string;
|
|
95
|
+
readonly functionSlug: string;
|
|
96
|
+
/** The pinned version, or `undefined` for "latest". */
|
|
97
|
+
readonly version: number | undefined;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Official client for the IntelligentFunctions API.
|
|
101
|
+
*
|
|
102
|
+
* @example
|
|
103
|
+
* // Reads INTFUNC_API_KEY / INTFUNC_BASE_URL from the environment.
|
|
104
|
+
* const client = new IntelligentFunctions();
|
|
105
|
+
*
|
|
106
|
+
* const summarize = client.fn<{ text: string }, { summary: string }>("blog/summarize");
|
|
107
|
+
* const { summary } = await summarize({ text: article });
|
|
108
|
+
*/
|
|
109
|
+
export declare class IntelligentFunctions {
|
|
110
|
+
private readonly baseUrl;
|
|
111
|
+
private readonly apiKey?;
|
|
112
|
+
private readonly timeout;
|
|
113
|
+
private readonly maxRetries;
|
|
114
|
+
private readonly fetchImpl;
|
|
115
|
+
constructor(options?: ClientOptions);
|
|
116
|
+
/**
|
|
117
|
+
* Bind a `projectSlug/functionSlug` key to a reusable, typed handle. This is
|
|
118
|
+
* the recommended way to call a function: define the handle once, then invoke
|
|
119
|
+
* it like a local async function.
|
|
120
|
+
*/
|
|
121
|
+
fn<In extends Record<string, unknown> = Record<string, unknown>, Out = unknown>(key: string, options?: {
|
|
122
|
+
version?: number;
|
|
123
|
+
}): FunctionHandle<In, Out>;
|
|
124
|
+
health(): Promise<{
|
|
125
|
+
status: string;
|
|
126
|
+
}>;
|
|
127
|
+
listUsers(): Promise<User[]>;
|
|
128
|
+
/** Create a function, or a new version of an existing one (same project + slug). */
|
|
129
|
+
createFunction(input: CreateIFunctionInput): Promise<IFunction>;
|
|
130
|
+
/** List functions, optionally filtered to a single project by slug. */
|
|
131
|
+
listFunctions(options?: {
|
|
132
|
+
project?: string;
|
|
133
|
+
}): Promise<IFunction[]>;
|
|
134
|
+
/**
|
|
135
|
+
* Fetch a function by its `{projectSlug}/{functionSlug}` key (latest version,
|
|
136
|
+
* or a pinned `version`).
|
|
137
|
+
*/
|
|
138
|
+
getFunction(projectSlug: string, functionSlug: string, options?: {
|
|
139
|
+
version?: number;
|
|
140
|
+
}): Promise<IFunction>;
|
|
141
|
+
/**
|
|
142
|
+
* Run a function against a real input and return its structured output plus
|
|
143
|
+
* metadata. For a terser call site, prefer {@link fn} handles.
|
|
144
|
+
*/
|
|
145
|
+
runFunction<T = unknown>(projectSlug: string, functionSlug: string, input: Record<string, unknown>, options?: RunOptions): Promise<RunIFunctionResult<T>>;
|
|
146
|
+
private request;
|
|
147
|
+
}
|
|
148
|
+
export { ApiError, AuthError, FunctionNotFoundError, InputValidationError, FunctionRunError, } from "./errors.js";
|
|
149
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,aAAa;IAC5B;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,wEAAwE;IACxE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,uEAAuE;IACvE,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;CACtB;AAED,oDAAoD;AACpD,MAAM,WAAW,UAAU;IACzB,+DAA+D;IAC/D,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,oEAAoE;IACpE,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,wEAAwE;IACxE,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,IAAI;IACnB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,iFAAiF;AACjF,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACrC,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACtC,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,oBAAoB;IACnC,4CAA4C;IAC5C,SAAS,EAAE,MAAM,CAAC;IAClB,0EAA0E;IAC1E,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACrC,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACvC;AAED,MAAM,WAAW,kBAAkB,CAAC,CAAC,GAAG,OAAO;IAC7C,MAAM,EAAE,CAAC,CAAC;IACV,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAA;KAAE,CAAC;IACtD,6EAA6E;IAC7E,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;;;;GASG;AACH,MAAM,WAAW,cAAc,CAAC,EAAE,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG;IACrE,CAAC,KAAK,EAAE,EAAE,EAAE,OAAO,CAAC,EAAE,UAAU,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;IAChD,sEAAsE;IACtE,GAAG,CAAC,KAAK,EAAE,EAAE,EAAE,OAAO,CAAC,EAAE,UAAU,GAAG,OAAO,CAAC,kBAAkB,CAAC,GAAG,CAAC,CAAC,CAAC;IACvE,8DAA8D;IAC9D,GAAG,CAAC,OAAO,EAAE,MAAM,GAAG,cAAc,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC;IAC9C,gEAAgE;IAChE,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,uDAAuD;IACvD,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;CACtC;AAMD;;;;;;;;;GASG;AACH,qBAAa,oBAAoB;IAC/B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAe;IAEzC,YAAY,OAAO,GAAE,aAAkB,EAUtC;IAED;;;;OAIG;IACH,EAAE,CAAC,EAAE,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,GAAG,OAAO,EAC5E,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,GAC7B,cAAc,CAAC,EAAE,EAAE,GAAG,CAAC,CAmBzB;IAEK,MAAM,IAAI,OAAO,CAAC;QAAE,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAE1C;IAEK,SAAS,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC,CAEjC;IAED,oFAAoF;IAC9E,cAAc,CAAC,KAAK,EAAE,oBAAoB,GAAG,OAAO,CAAC,SAAS,CAAC,CAEpE;IAED,uEAAuE;IACjE,aAAa,CAAC,OAAO,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC,CAGxE;IAED;;;OAGG;IACG,WAAW,CACf,WAAW,EAAE,MAAM,EACnB,YAAY,EAAE,MAAM,EACpB,OAAO,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,GAC7B,OAAO,CAAC,SAAS,CAAC,CAEpB;IAED;;;OAGG;IACG,WAAW,CAAC,CAAC,GAAG,OAAO,EAC3B,WAAW,EAAE,MAAM,EACnB,YAAY,EAAE,MAAM,EACpB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,OAAO,CAAC,EAAE,UAAU,GACnB,OAAO,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC,CAMhC;YAEa,OAAO;CA4CtB;AAGD,OAAO,EACL,QAAQ,EACR,SAAS,EACT,qBAAqB,EACrB,oBAAoB,EACpB,gBAAgB,GACjB,MAAM,aAAa,CAAC"}
|
package/dist/client.js
ADDED
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
import { errorFromResponse } from "./errors.js";
|
|
2
|
+
const DEFAULT_BASE_URL = "https://api.intfunc.com";
|
|
3
|
+
const DEFAULT_TIMEOUT_MS = 120_000;
|
|
4
|
+
const DEFAULT_MAX_RETRIES = 2;
|
|
5
|
+
/**
|
|
6
|
+
* Official client for the IntelligentFunctions API.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* // Reads INTFUNC_API_KEY / INTFUNC_BASE_URL from the environment.
|
|
10
|
+
* const client = new IntelligentFunctions();
|
|
11
|
+
*
|
|
12
|
+
* const summarize = client.fn<{ text: string }, { summary: string }>("blog/summarize");
|
|
13
|
+
* const { summary } = await summarize({ text: article });
|
|
14
|
+
*/
|
|
15
|
+
export class IntelligentFunctions {
|
|
16
|
+
baseUrl;
|
|
17
|
+
apiKey;
|
|
18
|
+
timeout;
|
|
19
|
+
maxRetries;
|
|
20
|
+
fetchImpl;
|
|
21
|
+
constructor(options = {}) {
|
|
22
|
+
const env = readEnv();
|
|
23
|
+
this.baseUrl = (options.baseUrl ?? env.INTFUNC_BASE_URL ?? DEFAULT_BASE_URL).replace(/\/+$/, "");
|
|
24
|
+
this.apiKey = options.apiKey ?? env.INTFUNC_API_KEY;
|
|
25
|
+
this.timeout = options.timeout ?? DEFAULT_TIMEOUT_MS;
|
|
26
|
+
this.maxRetries = options.maxRetries ?? DEFAULT_MAX_RETRIES;
|
|
27
|
+
this.fetchImpl = options.fetch ?? globalThis.fetch;
|
|
28
|
+
if (!this.fetchImpl) {
|
|
29
|
+
throw new Error("No fetch implementation available; pass options.fetch.");
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Bind a `projectSlug/functionSlug` key to a reusable, typed handle. This is
|
|
34
|
+
* the recommended way to call a function: define the handle once, then invoke
|
|
35
|
+
* it like a local async function.
|
|
36
|
+
*/
|
|
37
|
+
fn(key, options) {
|
|
38
|
+
const { projectSlug, functionSlug } = parseKey(key);
|
|
39
|
+
const pinned = options?.version;
|
|
40
|
+
const run = (input, opts) => this.runFunction(projectSlug, functionSlug, input, { version: pinned, ...opts });
|
|
41
|
+
const handle = ((input, opts) => run(input, opts).then((r) => r.output));
|
|
42
|
+
handle.run = run;
|
|
43
|
+
handle.pin = (version) => this.fn(key, { version });
|
|
44
|
+
Object.defineProperties(handle, {
|
|
45
|
+
key: { value: key, enumerable: true },
|
|
46
|
+
projectSlug: { value: projectSlug, enumerable: true },
|
|
47
|
+
functionSlug: { value: functionSlug, enumerable: true },
|
|
48
|
+
version: { value: pinned, enumerable: true },
|
|
49
|
+
});
|
|
50
|
+
return handle;
|
|
51
|
+
}
|
|
52
|
+
async health() {
|
|
53
|
+
return this.request("GET", "/health");
|
|
54
|
+
}
|
|
55
|
+
async listUsers() {
|
|
56
|
+
return this.request("GET", "/v1/users");
|
|
57
|
+
}
|
|
58
|
+
/** Create a function, or a new version of an existing one (same project + slug). */
|
|
59
|
+
async createFunction(input) {
|
|
60
|
+
return this.request("POST", "/v1/functions", { body: input });
|
|
61
|
+
}
|
|
62
|
+
/** List functions, optionally filtered to a single project by slug. */
|
|
63
|
+
async listFunctions(options) {
|
|
64
|
+
const query = options?.project ? `?project=${encodeURIComponent(options.project)}` : "";
|
|
65
|
+
return this.request("GET", `/v1/functions${query}`);
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Fetch a function by its `{projectSlug}/{functionSlug}` key (latest version,
|
|
69
|
+
* or a pinned `version`).
|
|
70
|
+
*/
|
|
71
|
+
async getFunction(projectSlug, functionSlug, options) {
|
|
72
|
+
return this.request("GET", `${functionPath(projectSlug, functionSlug)}${versionQuery(options?.version)}`);
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Run a function against a real input and return its structured output plus
|
|
76
|
+
* metadata. For a terser call site, prefer {@link fn} handles.
|
|
77
|
+
*/
|
|
78
|
+
async runFunction(projectSlug, functionSlug, input, options) {
|
|
79
|
+
return this.request("POST", `${functionPath(projectSlug, functionSlug)}/run${versionQuery(options?.version)}`, { body: { input }, signal: options?.signal, timeout: options?.timeout });
|
|
80
|
+
}
|
|
81
|
+
async request(method, path, opts = {}) {
|
|
82
|
+
const { body, signal } = opts;
|
|
83
|
+
const timeout = opts.timeout ?? this.timeout;
|
|
84
|
+
const url = `${this.baseUrl}${path}`;
|
|
85
|
+
const headers = { accept: "application/json" };
|
|
86
|
+
if (this.apiKey)
|
|
87
|
+
headers["authorization"] = `Bearer ${this.apiKey}`;
|
|
88
|
+
if (body !== undefined)
|
|
89
|
+
headers["content-type"] = "application/json";
|
|
90
|
+
const payload = body !== undefined ? JSON.stringify(body) : undefined;
|
|
91
|
+
for (let attempt = 0;; attempt++) {
|
|
92
|
+
const { controller, cleanup } = linkAbort(signal, timeout);
|
|
93
|
+
let res;
|
|
94
|
+
try {
|
|
95
|
+
res = await this.fetchImpl(url, { method, headers, body: payload, signal: controller.signal });
|
|
96
|
+
}
|
|
97
|
+
catch (err) {
|
|
98
|
+
cleanup();
|
|
99
|
+
// A user-initiated abort is final; never retry or reshape it.
|
|
100
|
+
if (signal?.aborted)
|
|
101
|
+
throw err;
|
|
102
|
+
if (attempt < this.maxRetries) {
|
|
103
|
+
await sleep(backoffMs(attempt));
|
|
104
|
+
continue;
|
|
105
|
+
}
|
|
106
|
+
throw err;
|
|
107
|
+
}
|
|
108
|
+
cleanup();
|
|
109
|
+
if (!res.ok) {
|
|
110
|
+
if (isRetriable(res.status) && attempt < this.maxRetries) {
|
|
111
|
+
await res.body?.cancel().catch(() => { });
|
|
112
|
+
await sleep(retryAfterMs(res) ?? backoffMs(attempt));
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
const data = await readBody(res);
|
|
116
|
+
throw errorFromResponse(res.status, extractError(data, res.status), data);
|
|
117
|
+
}
|
|
118
|
+
return (await readBody(res));
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
// Re-export the error surface so `import { ApiError } from "@intfunc/sdk"` works.
|
|
123
|
+
export { ApiError, AuthError, FunctionNotFoundError, InputValidationError, FunctionRunError, } from "./errors.js";
|
|
124
|
+
function functionPath(projectSlug, functionSlug) {
|
|
125
|
+
return `/v1/functions/${encodeURIComponent(projectSlug)}/${encodeURIComponent(functionSlug)}`;
|
|
126
|
+
}
|
|
127
|
+
function versionQuery(version) {
|
|
128
|
+
return version !== undefined ? `?version=${version}` : "";
|
|
129
|
+
}
|
|
130
|
+
function parseKey(key) {
|
|
131
|
+
const parts = key.split("/");
|
|
132
|
+
if (parts.length !== 2 || !parts[0] || !parts[1]) {
|
|
133
|
+
throw new Error(`Invalid function key "${key}"; expected "projectSlug/functionSlug".`);
|
|
134
|
+
}
|
|
135
|
+
return { projectSlug: parts[0], functionSlug: parts[1] };
|
|
136
|
+
}
|
|
137
|
+
/** Wire a per-request timeout and an optional caller signal into one controller. */
|
|
138
|
+
function linkAbort(signal, timeout) {
|
|
139
|
+
const controller = new AbortController();
|
|
140
|
+
const timer = timeout > 0
|
|
141
|
+
? setTimeout(() => controller.abort(new DOMException("Request timed out", "TimeoutError")), timeout)
|
|
142
|
+
: undefined;
|
|
143
|
+
const onAbort = () => controller.abort(signal?.reason);
|
|
144
|
+
if (signal) {
|
|
145
|
+
if (signal.aborted)
|
|
146
|
+
controller.abort(signal.reason);
|
|
147
|
+
else
|
|
148
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
149
|
+
}
|
|
150
|
+
return {
|
|
151
|
+
controller,
|
|
152
|
+
cleanup: () => {
|
|
153
|
+
if (timer)
|
|
154
|
+
clearTimeout(timer);
|
|
155
|
+
signal?.removeEventListener("abort", onAbort);
|
|
156
|
+
},
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
function isRetriable(status) {
|
|
160
|
+
return status === 408 || status === 429 || status >= 500;
|
|
161
|
+
}
|
|
162
|
+
/** Exponential backoff with jitter: ~0.5s, 1s, 2s, … capped at 8s. */
|
|
163
|
+
function backoffMs(attempt) {
|
|
164
|
+
const base = Math.min(8_000, 500 * 2 ** attempt);
|
|
165
|
+
return base + Math.random() * 250;
|
|
166
|
+
}
|
|
167
|
+
function retryAfterMs(res) {
|
|
168
|
+
const header = res.headers.get("retry-after");
|
|
169
|
+
if (!header)
|
|
170
|
+
return undefined;
|
|
171
|
+
const seconds = Number(header);
|
|
172
|
+
return Number.isFinite(seconds) ? seconds * 1_000 : undefined;
|
|
173
|
+
}
|
|
174
|
+
function extractError(data, status) {
|
|
175
|
+
if (data && typeof data === "object" && "error" in data) {
|
|
176
|
+
return String(data.error);
|
|
177
|
+
}
|
|
178
|
+
return `Request failed with status ${status}`;
|
|
179
|
+
}
|
|
180
|
+
async function readBody(res) {
|
|
181
|
+
const text = await res.text();
|
|
182
|
+
return text ? safeJsonParse(text) : undefined;
|
|
183
|
+
}
|
|
184
|
+
function sleep(ms) {
|
|
185
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
186
|
+
}
|
|
187
|
+
function readEnv() {
|
|
188
|
+
return globalThis.process?.env ?? {};
|
|
189
|
+
}
|
|
190
|
+
function safeJsonParse(text) {
|
|
191
|
+
try {
|
|
192
|
+
return JSON.parse(text);
|
|
193
|
+
}
|
|
194
|
+
catch {
|
|
195
|
+
return text;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Error hierarchy for the IntelligentFunctions API.
|
|
3
|
+
*
|
|
4
|
+
* Every failed request throws an {@link ApiError} (or a subclass). Catch the
|
|
5
|
+
* subclass to branch on the failure kind without inspecting `.status`:
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* try {
|
|
9
|
+
* await sentiment({ text });
|
|
10
|
+
* } catch (err) {
|
|
11
|
+
* if (err instanceof InputValidationError) { ... } // 400
|
|
12
|
+
* else if (err instanceof AuthError) { ... } // 401
|
|
13
|
+
* else if (err instanceof FunctionNotFoundError) { ... } // 404
|
|
14
|
+
* else if (err instanceof FunctionRunError) { ... } // 502 (model failed)
|
|
15
|
+
* }
|
|
16
|
+
*/
|
|
17
|
+
export declare class ApiError extends Error {
|
|
18
|
+
/** HTTP status code returned by the API. */
|
|
19
|
+
readonly status: number;
|
|
20
|
+
/** Parsed response body, when the server returned one. */
|
|
21
|
+
readonly body?: unknown;
|
|
22
|
+
constructor(
|
|
23
|
+
/** HTTP status code returned by the API. */
|
|
24
|
+
status: number, message: string,
|
|
25
|
+
/** Parsed response body, when the server returned one. */
|
|
26
|
+
body?: unknown);
|
|
27
|
+
}
|
|
28
|
+
/** 401 — the API key was missing, invalid, or revoked. */
|
|
29
|
+
export declare class AuthError extends ApiError {
|
|
30
|
+
constructor(message: string, body?: unknown);
|
|
31
|
+
}
|
|
32
|
+
/** 404 — no such function, or it belongs to another project. */
|
|
33
|
+
export declare class FunctionNotFoundError extends ApiError {
|
|
34
|
+
constructor(message: string, body?: unknown);
|
|
35
|
+
}
|
|
36
|
+
/** 400 — the input did not satisfy the function's input schema. */
|
|
37
|
+
export declare class InputValidationError extends ApiError {
|
|
38
|
+
constructor(message: string, body?: unknown);
|
|
39
|
+
}
|
|
40
|
+
/** 502 — the underlying model call failed or produced no valid output. */
|
|
41
|
+
export declare class FunctionRunError extends ApiError {
|
|
42
|
+
constructor(message: string, body?: unknown);
|
|
43
|
+
}
|
|
44
|
+
/** Map an HTTP status to the most specific error class available. */
|
|
45
|
+
export declare function errorFromResponse(status: number, message: string, body?: unknown): ApiError;
|
|
46
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,qBAAa,QAAS,SAAQ,KAAK;IAE/B,4CAA4C;aAC5B,MAAM,EAAE,MAAM;IAE9B,0DAA0D;aAC1C,IAAI,CAAC,EAAE,OAAO;IALhC;IACE,4CAA4C;IAC5B,MAAM,EAAE,MAAM,EAC9B,OAAO,EAAE,MAAM;IACf,0DAA0D;IAC1C,IAAI,CAAC,EAAE,OAAO,EAI/B;CACF;AAED,0DAA0D;AAC1D,qBAAa,SAAU,SAAQ,QAAQ;IACrC,YAAY,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,EAG1C;CACF;AAED,gEAAgE;AAChE,qBAAa,qBAAsB,SAAQ,QAAQ;IACjD,YAAY,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,EAG1C;CACF;AAED,mEAAmE;AACnE,qBAAa,oBAAqB,SAAQ,QAAQ;IAChD,YAAY,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,EAG1C;CACF;AAED,0EAA0E;AAC1E,qBAAa,gBAAiB,SAAQ,QAAQ;IAC5C,YAAY,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,EAG1C;CACF;AAED,qEAAqE;AACrE,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,QAAQ,CAa3F"}
|
package/dist/errors.js
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Error hierarchy for the IntelligentFunctions API.
|
|
3
|
+
*
|
|
4
|
+
* Every failed request throws an {@link ApiError} (or a subclass). Catch the
|
|
5
|
+
* subclass to branch on the failure kind without inspecting `.status`:
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* try {
|
|
9
|
+
* await sentiment({ text });
|
|
10
|
+
* } catch (err) {
|
|
11
|
+
* if (err instanceof InputValidationError) { ... } // 400
|
|
12
|
+
* else if (err instanceof AuthError) { ... } // 401
|
|
13
|
+
* else if (err instanceof FunctionNotFoundError) { ... } // 404
|
|
14
|
+
* else if (err instanceof FunctionRunError) { ... } // 502 (model failed)
|
|
15
|
+
* }
|
|
16
|
+
*/
|
|
17
|
+
export class ApiError extends Error {
|
|
18
|
+
status;
|
|
19
|
+
body;
|
|
20
|
+
constructor(
|
|
21
|
+
/** HTTP status code returned by the API. */
|
|
22
|
+
status, message,
|
|
23
|
+
/** Parsed response body, when the server returned one. */
|
|
24
|
+
body) {
|
|
25
|
+
super(message);
|
|
26
|
+
this.status = status;
|
|
27
|
+
this.body = body;
|
|
28
|
+
this.name = "ApiError";
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
/** 401 — the API key was missing, invalid, or revoked. */
|
|
32
|
+
export class AuthError extends ApiError {
|
|
33
|
+
constructor(message, body) {
|
|
34
|
+
super(401, message, body);
|
|
35
|
+
this.name = "AuthError";
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
/** 404 — no such function, or it belongs to another project. */
|
|
39
|
+
export class FunctionNotFoundError extends ApiError {
|
|
40
|
+
constructor(message, body) {
|
|
41
|
+
super(404, message, body);
|
|
42
|
+
this.name = "FunctionNotFoundError";
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
/** 400 — the input did not satisfy the function's input schema. */
|
|
46
|
+
export class InputValidationError extends ApiError {
|
|
47
|
+
constructor(message, body) {
|
|
48
|
+
super(400, message, body);
|
|
49
|
+
this.name = "InputValidationError";
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
/** 502 — the underlying model call failed or produced no valid output. */
|
|
53
|
+
export class FunctionRunError extends ApiError {
|
|
54
|
+
constructor(message, body) {
|
|
55
|
+
super(502, message, body);
|
|
56
|
+
this.name = "FunctionRunError";
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
/** Map an HTTP status to the most specific error class available. */
|
|
60
|
+
export function errorFromResponse(status, message, body) {
|
|
61
|
+
switch (status) {
|
|
62
|
+
case 400:
|
|
63
|
+
return new InputValidationError(message, body);
|
|
64
|
+
case 401:
|
|
65
|
+
return new AuthError(message, body);
|
|
66
|
+
case 404:
|
|
67
|
+
return new FunctionNotFoundError(message, body);
|
|
68
|
+
case 502:
|
|
69
|
+
return new FunctionRunError(message, body);
|
|
70
|
+
default:
|
|
71
|
+
return new ApiError(status, message, body);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,MAAM,OAAO,QAAS,SAAQ,KAAK;IAGf,MAAM;IAGN,IAAI;IALtB;IACE,4CAA4C;IAC5B,MAAc,EAC9B,OAAe;IACf,0DAA0D;IAC1C,IAAc;QAE9B,KAAK,CAAC,OAAO,CAAC,CAAC;sBALC,MAAM;oBAGN,IAAI;QAGpB,IAAI,CAAC,IAAI,GAAG,UAAU,CAAC;IACzB,CAAC;CACF;AAED,0DAA0D;AAC1D,MAAM,OAAO,SAAU,SAAQ,QAAQ;IACrC,YAAY,OAAe,EAAE,IAAc;QACzC,KAAK,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC;QAC1B,IAAI,CAAC,IAAI,GAAG,WAAW,CAAC;IAC1B,CAAC;CACF;AAED,gEAAgE;AAChE,MAAM,OAAO,qBAAsB,SAAQ,QAAQ;IACjD,YAAY,OAAe,EAAE,IAAc;QACzC,KAAK,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC;QAC1B,IAAI,CAAC,IAAI,GAAG,uBAAuB,CAAC;IACtC,CAAC;CACF;AAED,mEAAmE;AACnE,MAAM,OAAO,oBAAqB,SAAQ,QAAQ;IAChD,YAAY,OAAe,EAAE,IAAc;QACzC,KAAK,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC;QAC1B,IAAI,CAAC,IAAI,GAAG,sBAAsB,CAAC;IACrC,CAAC;CACF;AAED,0EAA0E;AAC1E,MAAM,OAAO,gBAAiB,SAAQ,QAAQ;IAC5C,YAAY,OAAe,EAAE,IAAc;QACzC,KAAK,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC;QAC1B,IAAI,CAAC,IAAI,GAAG,kBAAkB,CAAC;IACjC,CAAC;CACF;AAED,qEAAqE;AACrE,MAAM,UAAU,iBAAiB,CAAC,MAAc,EAAE,OAAe,EAAE,IAAc;IAC/E,QAAQ,MAAM,EAAE,CAAC;QACf,KAAK,GAAG;YACN,OAAO,IAAI,oBAAoB,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;QACjD,KAAK,GAAG;YACN,OAAO,IAAI,SAAS,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;QACtC,KAAK,GAAG;YACN,OAAO,IAAI,qBAAqB,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;QAClD,KAAK,GAAG;YACN,OAAO,IAAI,gBAAgB,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;QAC7C;YACE,OAAO,IAAI,QAAQ,CAAC,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC;IAC/C,CAAC;AACH,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { IntelligentFunctions } from "./client.js";
|
|
2
|
+
export type { ClientOptions, RunOptions, FunctionHandle, User, IFunction, CreateIFunctionInput, RunIFunctionResult, } from "./client.js";
|
|
3
|
+
export { ApiError, AuthError, FunctionNotFoundError, InputValidationError, FunctionRunError, errorFromResponse, } from "./errors.js";
|
|
4
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AACnD,YAAY,EACV,aAAa,EACb,UAAU,EACV,cAAc,EACd,IAAI,EACJ,SAAS,EACT,oBAAoB,EACpB,kBAAkB,GACnB,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,QAAQ,EACR,SAAS,EACT,qBAAqB,EACrB,oBAAoB,EACpB,gBAAgB,EAChB,iBAAiB,GAClB,MAAM,aAAa,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAUnD,OAAO,EACL,QAAQ,EACR,SAAS,EACT,qBAAqB,EACrB,oBAAoB,EACpB,gBAAgB,EAChB,iBAAiB,GAClB,MAAM,aAAa,CAAC"}
|
package/dist/slug.d.ts
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canonical slug utilities. A slug is the human-friendly, URL-safe identifier
|
|
3
|
+
* that forms the function invocation key `{projectSlug}/{functionSlug}`, so this
|
|
4
|
+
* normalization is the single source of truth: the API validates with it, the
|
|
5
|
+
* console suggests with it, and SDK consumers can pre-derive slugs client-side.
|
|
6
|
+
*/
|
|
7
|
+
/** A valid slug: lowercase alphanumerics in hyphen-separated groups, no spaces. */
|
|
8
|
+
export declare const SLUG_REGEX: RegExp;
|
|
9
|
+
/** Max slug length; keeps keys and URLs reasonable. */
|
|
10
|
+
export declare const MAX_SLUG_LENGTH = 64;
|
|
11
|
+
/**
|
|
12
|
+
* Convert an arbitrary string (e.g. a display name) into a slug:
|
|
13
|
+
* lowercased, diacritics stripped, every run of non-`[a-z0-9]` collapsed to a
|
|
14
|
+
* single `-`, trimmed of leading/trailing `-`, and capped at {@link MAX_SLUG_LENGTH}.
|
|
15
|
+
*
|
|
16
|
+
* Returns `""` when the input has no slug-able characters — callers deriving a
|
|
17
|
+
* required slug should fall back (or reject) on an empty result.
|
|
18
|
+
*
|
|
19
|
+
* @example slugify("Summarize Ticket!") // "summarize-ticket"
|
|
20
|
+
* @example slugify(" Héllo World ") // "hello-world"
|
|
21
|
+
*/
|
|
22
|
+
export declare function slugify(input: string): string;
|
|
23
|
+
/** Whether `value` is already a well-formed slug. */
|
|
24
|
+
export declare function isValidSlug(value: string): boolean;
|
|
25
|
+
/**
|
|
26
|
+
* Return `base` if free, otherwise `base-2`, `base-3`, … until one is not taken.
|
|
27
|
+
* `taken` may be a Set of existing slugs or a predicate.
|
|
28
|
+
*/
|
|
29
|
+
export declare function uniqueSlug(base: string, taken: Set<string> | ((slug: string) => boolean)): string;
|
|
30
|
+
//# sourceMappingURL=slug.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"slug.d.ts","sourceRoot":"","sources":["../src/slug.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,mFAAmF;AACnF,eAAO,MAAM,UAAU,QAA+B,CAAC;AAEvD,uDAAuD;AACvD,eAAO,MAAM,eAAe,KAAK,CAAC;AAElC;;;;;;;;;;GAUG;AACH,wBAAgB,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAS7C;AAED,qDAAqD;AACrD,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAElD;AAED;;;GAGG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,GAAG,MAAM,CAOjG"}
|
package/dist/slug.js
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canonical slug utilities. A slug is the human-friendly, URL-safe identifier
|
|
3
|
+
* that forms the function invocation key `{projectSlug}/{functionSlug}`, so this
|
|
4
|
+
* normalization is the single source of truth: the API validates with it, the
|
|
5
|
+
* console suggests with it, and SDK consumers can pre-derive slugs client-side.
|
|
6
|
+
*/
|
|
7
|
+
/** A valid slug: lowercase alphanumerics in hyphen-separated groups, no spaces. */
|
|
8
|
+
export const SLUG_REGEX = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
9
|
+
/** Max slug length; keeps keys and URLs reasonable. */
|
|
10
|
+
export const MAX_SLUG_LENGTH = 64;
|
|
11
|
+
/**
|
|
12
|
+
* Convert an arbitrary string (e.g. a display name) into a slug:
|
|
13
|
+
* lowercased, diacritics stripped, every run of non-`[a-z0-9]` collapsed to a
|
|
14
|
+
* single `-`, trimmed of leading/trailing `-`, and capped at {@link MAX_SLUG_LENGTH}.
|
|
15
|
+
*
|
|
16
|
+
* Returns `""` when the input has no slug-able characters — callers deriving a
|
|
17
|
+
* required slug should fall back (or reject) on an empty result.
|
|
18
|
+
*
|
|
19
|
+
* @example slugify("Summarize Ticket!") // "summarize-ticket"
|
|
20
|
+
* @example slugify(" Héllo World ") // "hello-world"
|
|
21
|
+
*/
|
|
22
|
+
export function slugify(input) {
|
|
23
|
+
return input
|
|
24
|
+
.normalize("NFKD")
|
|
25
|
+
.replace(/[̀-ͯ]/g, "") // strip combining diacritical marks
|
|
26
|
+
.toLowerCase()
|
|
27
|
+
.replace(/[^a-z0-9]+/g, "-") // any run of non-slug chars -> single hyphen
|
|
28
|
+
.replace(/^-+|-+$/g, "") // trim leading/trailing hyphens
|
|
29
|
+
.slice(0, MAX_SLUG_LENGTH)
|
|
30
|
+
.replace(/-+$/g, ""); // re-trim in case the slice ended on a hyphen
|
|
31
|
+
}
|
|
32
|
+
/** Whether `value` is already a well-formed slug. */
|
|
33
|
+
export function isValidSlug(value) {
|
|
34
|
+
return value.length > 0 && value.length <= MAX_SLUG_LENGTH && SLUG_REGEX.test(value);
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Return `base` if free, otherwise `base-2`, `base-3`, … until one is not taken.
|
|
38
|
+
* `taken` may be a Set of existing slugs or a predicate.
|
|
39
|
+
*/
|
|
40
|
+
export function uniqueSlug(base, taken) {
|
|
41
|
+
const isTaken = typeof taken === "function" ? taken : (slug) => taken.has(slug);
|
|
42
|
+
if (!isTaken(base))
|
|
43
|
+
return base;
|
|
44
|
+
for (let n = 2;; n++) {
|
|
45
|
+
const candidate = `${base}-${n}`;
|
|
46
|
+
if (!isTaken(candidate))
|
|
47
|
+
return candidate;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=slug.js.map
|
package/dist/slug.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"slug.js","sourceRoot":"","sources":["../src/slug.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,mFAAmF;AACnF,MAAM,CAAC,MAAM,UAAU,GAAG,4BAA4B,CAAC;AAEvD,uDAAuD;AACvD,MAAM,CAAC,MAAM,eAAe,GAAG,EAAE,CAAC;AAElC;;;;;;;;;;GAUG;AACH,MAAM,UAAU,OAAO,CAAC,KAAa;IACnC,OAAO,KAAK;SACT,SAAS,CAAC,MAAM,CAAC;SACjB,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,oCAAoC;SAC1D,WAAW,EAAE;SACb,OAAO,CAAC,aAAa,EAAE,GAAG,CAAC,CAAC,6CAA6C;SACzE,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC,gCAAgC;SACxD,KAAK,CAAC,CAAC,EAAE,eAAe,CAAC;SACzB,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,CAAC,8CAA8C;AACxE,CAAC;AAED,qDAAqD;AACrD,MAAM,UAAU,WAAW,CAAC,KAAa;IACvC,OAAO,KAAK,CAAC,MAAM,GAAG,CAAC,IAAI,KAAK,CAAC,MAAM,IAAI,eAAe,IAAI,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AACvF,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,UAAU,CAAC,IAAY,EAAE,KAAgD;IACvF,MAAM,OAAO,GAAG,OAAO,KAAK,KAAK,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAY,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACxF,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IAChC,KAAK,IAAI,CAAC,GAAG,CAAC,GAAI,CAAC,EAAE,EAAE,CAAC;QACtB,MAAM,SAAS,GAAG,GAAG,IAAI,IAAI,CAAC,EAAE,CAAC;QACjC,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC;YAAE,OAAO,SAAS,CAAC;IAC5C,CAAC;AACH,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@intfunc/sdk",
|
|
3
|
+
"version": "0.0.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"module": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.js"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"dist"
|
|
16
|
+
],
|
|
17
|
+
"publishConfig": {
|
|
18
|
+
"access": "public"
|
|
19
|
+
},
|
|
20
|
+
"scripts": {
|
|
21
|
+
"build": "tsc -p tsconfig.json",
|
|
22
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
23
|
+
"clean": "rm -rf dist"
|
|
24
|
+
},
|
|
25
|
+
"devDependencies": {
|
|
26
|
+
"typescript": "^7.0.2"
|
|
27
|
+
}
|
|
28
|
+
}
|