ainvoker 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/LICENSE +21 -0
- package/README.md +69 -0
- package/dist/index.cjs +138 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +114 -0
- package/dist/index.d.ts +114 -0
- package/dist/index.js +134 -0
- package/dist/index.js.map +1 -0
- package/package.json +52 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 AInvoker
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# @ainvoker/sdk
|
|
2
|
+
|
|
3
|
+
Official TypeScript/JavaScript SDK for the AInvoker AI gateway.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install ainvoker
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Requires Node.js 18+ (native `fetch`).
|
|
12
|
+
|
|
13
|
+
## Quick start
|
|
14
|
+
|
|
15
|
+
```ts
|
|
16
|
+
import { Ainvoker, isAinvokerError } from "ainvoker"
|
|
17
|
+
|
|
18
|
+
const ai = new Ainvoker({
|
|
19
|
+
apiKey: process.env.AINVOKER_API_KEY!,
|
|
20
|
+
// optional — defaults to http://localhost:3000
|
|
21
|
+
// baseUrl: "https://api.example.com",
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
try {
|
|
25
|
+
const result = await ai.text.chat({
|
|
26
|
+
model: "openai/gpt-4o-mini",
|
|
27
|
+
messages: [{ role: "user", content: "Hello" }],
|
|
28
|
+
})
|
|
29
|
+
console.log(result.message.content)
|
|
30
|
+
} catch (error) {
|
|
31
|
+
if (isAinvokerError(error)) {
|
|
32
|
+
console.error(error.status, error.code, error.message)
|
|
33
|
+
} else {
|
|
34
|
+
throw error
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Local smoke
|
|
40
|
+
|
|
41
|
+
With the API running locally:
|
|
42
|
+
|
|
43
|
+
1. Copy `.env.example` → `.env` and set `AINVOKER_API_KEY`
|
|
44
|
+
2. Run:
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
npm run smoke
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Optional env: `AINVOKER_BASE_URL`, `AINVOKER_MODEL`.
|
|
51
|
+
|
|
52
|
+
## Development
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
npm install
|
|
56
|
+
npm test
|
|
57
|
+
npm run build
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Publishing
|
|
61
|
+
|
|
62
|
+
Version is semver (`0.1.0` while the API surface is early). Before publish:
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
npm run prepublishOnly # typecheck + test + build
|
|
66
|
+
npm publish # requires npm login + @ainvoker org access
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
`publishConfig.access` is `public` so the scoped package can be published without a paid org private default.
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// src/errors.ts
|
|
4
|
+
var AinvokerError = class extends Error {
|
|
5
|
+
status;
|
|
6
|
+
code;
|
|
7
|
+
/** Parsed response body when available (error envelope or raw JSON). */
|
|
8
|
+
body;
|
|
9
|
+
constructor(status, code, message, body = void 0) {
|
|
10
|
+
super(message);
|
|
11
|
+
this.name = "AinvokerError";
|
|
12
|
+
this.status = status;
|
|
13
|
+
this.code = code;
|
|
14
|
+
this.body = body;
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
function isAinvokerError(error) {
|
|
18
|
+
return error instanceof AinvokerError;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// src/http.ts
|
|
22
|
+
function isRecord(value) {
|
|
23
|
+
return value !== null && typeof value === "object";
|
|
24
|
+
}
|
|
25
|
+
function parseErrorPayload(json) {
|
|
26
|
+
if (!isRecord(json) || !isRecord(json.error)) {
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
const { code, message } = json.error;
|
|
30
|
+
if (typeof code !== "string" || typeof message !== "string") {
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
return { code, message };
|
|
34
|
+
}
|
|
35
|
+
function hasDataEnvelope(json) {
|
|
36
|
+
return isRecord(json) && "data" in json;
|
|
37
|
+
}
|
|
38
|
+
var HttpClient = class {
|
|
39
|
+
apiKey;
|
|
40
|
+
baseUrl;
|
|
41
|
+
constructor(options) {
|
|
42
|
+
this.apiKey = options.apiKey;
|
|
43
|
+
this.baseUrl = options.baseUrl.replace(/\/+$/, "");
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* POST JSON to a path under `baseUrl`. Unwraps `{ data: T }` on success.
|
|
47
|
+
*/
|
|
48
|
+
async post(path, body) {
|
|
49
|
+
const url = `${this.baseUrl}${path.startsWith("/") ? path : `/${path}`}`;
|
|
50
|
+
let response;
|
|
51
|
+
try {
|
|
52
|
+
response = await fetch(url, {
|
|
53
|
+
method: "POST",
|
|
54
|
+
headers: {
|
|
55
|
+
Authorization: `Bearer ${this.apiKey}`,
|
|
56
|
+
"Content-Type": "application/json",
|
|
57
|
+
Accept: "application/json"
|
|
58
|
+
},
|
|
59
|
+
body: JSON.stringify(body)
|
|
60
|
+
});
|
|
61
|
+
} catch (cause) {
|
|
62
|
+
const message = cause instanceof Error ? cause.message : "Network request failed";
|
|
63
|
+
throw new AinvokerError(0, "NETWORK_ERROR", message);
|
|
64
|
+
}
|
|
65
|
+
const text = await response.text();
|
|
66
|
+
let json = void 0;
|
|
67
|
+
if (text.length > 0) {
|
|
68
|
+
try {
|
|
69
|
+
json = JSON.parse(text);
|
|
70
|
+
} catch {
|
|
71
|
+
throw new AinvokerError(
|
|
72
|
+
response.status,
|
|
73
|
+
"INVALID_RESPONSE",
|
|
74
|
+
"Response body was not valid JSON",
|
|
75
|
+
text
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
if (!response.ok) {
|
|
80
|
+
const parsed = parseErrorPayload(json);
|
|
81
|
+
throw new AinvokerError(
|
|
82
|
+
response.status,
|
|
83
|
+
parsed?.code ?? "HTTP_ERROR",
|
|
84
|
+
parsed?.message ?? `Request failed with status ${response.status}`,
|
|
85
|
+
json
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
if (!hasDataEnvelope(json)) {
|
|
89
|
+
throw new AinvokerError(
|
|
90
|
+
response.status,
|
|
91
|
+
"INVALID_RESPONSE",
|
|
92
|
+
"Response missing data envelope",
|
|
93
|
+
json
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
return json.data;
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
// src/resources/text.ts
|
|
101
|
+
var TextResource = class {
|
|
102
|
+
constructor(http) {
|
|
103
|
+
this.http = http;
|
|
104
|
+
}
|
|
105
|
+
http;
|
|
106
|
+
/**
|
|
107
|
+
* Text chat completion via the AInvoker gateway (`POST /v1/text/chat`).
|
|
108
|
+
*
|
|
109
|
+
* Authenticate with a project API key. `model` must be a `provider/model`
|
|
110
|
+
* slug (e.g. `"openai/gpt-4o-mini"` or `"gemini/gemini-2.5-flash"`).
|
|
111
|
+
*/
|
|
112
|
+
chat(params) {
|
|
113
|
+
return this.http.post("/v1/text/chat", params);
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
// src/client.ts
|
|
118
|
+
var DEFAULT_BASE_URL = "http://localhost:3000";
|
|
119
|
+
var Ainvoker = class {
|
|
120
|
+
/** Text modality (`/v1/text/...`). */
|
|
121
|
+
text;
|
|
122
|
+
constructor(options) {
|
|
123
|
+
if (!options.apiKey || options.apiKey.trim().length === 0) {
|
|
124
|
+
throw new Error("Ainvoker: apiKey is required");
|
|
125
|
+
}
|
|
126
|
+
const http = new HttpClient({
|
|
127
|
+
apiKey: options.apiKey,
|
|
128
|
+
baseUrl: options.baseUrl ?? DEFAULT_BASE_URL
|
|
129
|
+
});
|
|
130
|
+
this.text = new TextResource(http);
|
|
131
|
+
}
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
exports.Ainvoker = Ainvoker;
|
|
135
|
+
exports.AinvokerError = AinvokerError;
|
|
136
|
+
exports.isAinvokerError = isAinvokerError;
|
|
137
|
+
//# sourceMappingURL=index.cjs.map
|
|
138
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/errors.ts","../src/http.ts","../src/resources/text.ts","../src/client.ts"],"names":[],"mappings":"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","file":"index.cjs","sourcesContent":["/**\r\n * Known AInvoker API / SDK error codes.\r\n * Unknown server codes remain assignable via the open string union.\r\n */\r\nexport type AinvokerErrorCode =\r\n | \"UNAUTHORIZED\"\r\n | \"FORBIDDEN\"\r\n | \"NOT_FOUND\"\r\n | \"VALIDATION_ERROR\"\r\n | \"CONFLICT\"\r\n | \"UPSTREAM_ERROR\"\r\n | \"INTERNAL_ERROR\"\r\n | \"NETWORK_ERROR\"\r\n | \"INVALID_RESPONSE\"\r\n | \"HTTP_ERROR\"\r\n | (string & {})\r\n\r\n/**\r\n * Error thrown when the AInvoker API returns a non-success response\r\n * or the response body cannot be parsed as expected.\r\n */\r\nexport class AinvokerError extends Error {\r\n readonly status: number\r\n readonly code: AinvokerErrorCode\r\n /** Parsed response body when available (error envelope or raw JSON). */\r\n readonly body: unknown\r\n\r\n constructor(\r\n status: number,\r\n code: AinvokerErrorCode,\r\n message: string,\r\n body: unknown = undefined,\r\n ) {\r\n super(message)\r\n this.name = \"AinvokerError\"\r\n this.status = status\r\n this.code = code\r\n this.body = body\r\n }\r\n}\r\n\r\n/** Type guard for {@link AinvokerError}. */\r\nexport function isAinvokerError(error: unknown): error is AinvokerError {\r\n return error instanceof AinvokerError\r\n}\r\n","import { AinvokerError } from \"./errors.js\"\r\nimport type { AinvokerErrorCode } from \"./errors.js\"\r\nimport type { DataEnvelope } from \"./types.js\"\r\n\r\nexport interface HttpClientOptions {\r\n apiKey: string\r\n baseUrl: string\r\n}\r\n\r\nfunction isRecord(value: unknown): value is Record<string, unknown> {\r\n return value !== null && typeof value === \"object\"\r\n}\r\n\r\nfunction parseErrorPayload(json: unknown): { code: AinvokerErrorCode; message: string } | null {\r\n if (!isRecord(json) || !isRecord(json.error)) {\r\n return null\r\n }\r\n const { code, message } = json.error\r\n if (typeof code !== \"string\" || typeof message !== \"string\") {\r\n return null\r\n }\r\n return { code, message }\r\n}\r\n\r\nfunction hasDataEnvelope(json: unknown): json is DataEnvelope<unknown> {\r\n return isRecord(json) && \"data\" in json\r\n}\r\n\r\nexport class HttpClient {\r\n private readonly apiKey: string\r\n private readonly baseUrl: string\r\n\r\n constructor(options: HttpClientOptions) {\r\n this.apiKey = options.apiKey\r\n this.baseUrl = options.baseUrl.replace(/\\/+$/, \"\")\r\n }\r\n\r\n /**\r\n * POST JSON to a path under `baseUrl`. Unwraps `{ data: T }` on success.\r\n */\r\n async post<T>(path: string, body: unknown): Promise<T> {\r\n const url = `${this.baseUrl}${path.startsWith(\"/\") ? path : `/${path}`}`\r\n\r\n let response: Response\r\n try {\r\n response = await fetch(url, {\r\n method: \"POST\",\r\n headers: {\r\n Authorization: `Bearer ${this.apiKey}`,\r\n \"Content-Type\": \"application/json\",\r\n Accept: \"application/json\",\r\n },\r\n body: JSON.stringify(body),\r\n })\r\n } catch (cause) {\r\n const message = cause instanceof Error ? cause.message : \"Network request failed\"\r\n throw new AinvokerError(0, \"NETWORK_ERROR\", message)\r\n }\r\n\r\n const text = await response.text()\r\n let json: unknown = undefined\r\n if (text.length > 0) {\r\n try {\r\n json = JSON.parse(text) as unknown\r\n } catch {\r\n throw new AinvokerError(\r\n response.status,\r\n \"INVALID_RESPONSE\",\r\n \"Response body was not valid JSON\",\r\n text,\r\n )\r\n }\r\n }\r\n\r\n if (!response.ok) {\r\n const parsed = parseErrorPayload(json)\r\n throw new AinvokerError(\r\n response.status,\r\n parsed?.code ?? \"HTTP_ERROR\",\r\n parsed?.message ?? `Request failed with status ${response.status}`,\r\n json,\r\n )\r\n }\r\n\r\n if (!hasDataEnvelope(json)) {\r\n throw new AinvokerError(\r\n response.status,\r\n \"INVALID_RESPONSE\",\r\n \"Response missing data envelope\",\r\n json,\r\n )\r\n }\r\n\r\n return json.data as T\r\n }\r\n}\r\n","import type { HttpClient } from \"../http.js\"\r\nimport type { TextChatParams, TextChatResult } from \"../types.js\"\r\n\r\n/**\r\n * Text modality methods (`/v1/text/...`).\r\n */\r\nexport class TextResource {\r\n constructor(private readonly http: HttpClient) {}\r\n\r\n /**\r\n * Text chat completion via the AInvoker gateway (`POST /v1/text/chat`).\r\n *\r\n * Authenticate with a project API key. `model` must be a `provider/model`\r\n * slug (e.g. `\"openai/gpt-4o-mini\"` or `\"gemini/gemini-2.5-flash\"`).\r\n */\r\n chat(params: TextChatParams): Promise<TextChatResult> {\r\n return this.http.post<TextChatResult>(\"/v1/text/chat\", params)\r\n }\r\n}\r\n","import { HttpClient } from \"./http.js\"\r\nimport { TextResource } from \"./resources/text.js\"\r\nimport type { AinvokerOptions } from \"./types.js\"\r\n\r\nconst DEFAULT_BASE_URL = \"http://localhost:3000\"\r\n\r\n/**\r\n * Official AInvoker SDK client.\r\n *\r\n * Use modality namespaces such as {@link Ainvoker.text} for gateway calls.\r\n */\r\nexport class Ainvoker {\r\n /** Text modality (`/v1/text/...`). */\r\n readonly text: TextResource\r\n\r\n constructor(options: AinvokerOptions) {\r\n if (!options.apiKey || options.apiKey.trim().length === 0) {\r\n throw new Error(\"Ainvoker: apiKey is required\")\r\n }\r\n\r\n const http = new HttpClient({\r\n apiKey: options.apiKey,\r\n baseUrl: options.baseUrl ?? DEFAULT_BASE_URL,\r\n })\r\n\r\n this.text = new TextResource(http)\r\n }\r\n}\r\n"]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
interface HttpClientOptions {
|
|
2
|
+
apiKey: string;
|
|
3
|
+
baseUrl: string;
|
|
4
|
+
}
|
|
5
|
+
declare class HttpClient {
|
|
6
|
+
private readonly apiKey;
|
|
7
|
+
private readonly baseUrl;
|
|
8
|
+
constructor(options: HttpClientOptions);
|
|
9
|
+
/**
|
|
10
|
+
* POST JSON to a path under `baseUrl`. Unwraps `{ data: T }` on success.
|
|
11
|
+
*/
|
|
12
|
+
post<T>(path: string, body: unknown): Promise<T>;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Client configuration for {@link Ainvoker}.
|
|
17
|
+
*/
|
|
18
|
+
interface AinvokerOptions {
|
|
19
|
+
/**
|
|
20
|
+
* Project API key (`ain_…`).
|
|
21
|
+
* Sent as `Authorization: Bearer <apiKey>`.
|
|
22
|
+
*/
|
|
23
|
+
apiKey: string;
|
|
24
|
+
/**
|
|
25
|
+
* API host. Defaults to `http://localhost:3000`.
|
|
26
|
+
* Override for staging/production or a custom deployment.
|
|
27
|
+
*/
|
|
28
|
+
baseUrl?: string;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* A single chat turn.
|
|
32
|
+
*/
|
|
33
|
+
interface ChatMessage {
|
|
34
|
+
role: "system" | "user" | "assistant";
|
|
35
|
+
content: string;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Parameters for {@link TextResource.chat}.
|
|
39
|
+
*/
|
|
40
|
+
interface TextChatParams {
|
|
41
|
+
/**
|
|
42
|
+
* Provider model slug, e.g. `"openai/gpt-4o-mini"` or `"gemini/gemini-2.5-flash"`.
|
|
43
|
+
*/
|
|
44
|
+
model: string;
|
|
45
|
+
messages: ChatMessage[];
|
|
46
|
+
/** Sampling temperature (0–2). */
|
|
47
|
+
temperature?: number;
|
|
48
|
+
/** Maximum tokens to generate. */
|
|
49
|
+
maxTokens?: number;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Token usage reported by the gateway (may be null).
|
|
53
|
+
*/
|
|
54
|
+
interface ChatUsage {
|
|
55
|
+
inputTokens: number;
|
|
56
|
+
outputTokens: number;
|
|
57
|
+
totalTokens: number;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Successful text chat result (API `{ data }` unwrapped).
|
|
61
|
+
*/
|
|
62
|
+
interface TextChatResult {
|
|
63
|
+
id: string;
|
|
64
|
+
model: string;
|
|
65
|
+
message: ChatMessage;
|
|
66
|
+
usage: ChatUsage | null;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Text modality methods (`/v1/text/...`).
|
|
71
|
+
*/
|
|
72
|
+
declare class TextResource {
|
|
73
|
+
private readonly http;
|
|
74
|
+
constructor(http: HttpClient);
|
|
75
|
+
/**
|
|
76
|
+
* Text chat completion via the AInvoker gateway (`POST /v1/text/chat`).
|
|
77
|
+
*
|
|
78
|
+
* Authenticate with a project API key. `model` must be a `provider/model`
|
|
79
|
+
* slug (e.g. `"openai/gpt-4o-mini"` or `"gemini/gemini-2.5-flash"`).
|
|
80
|
+
*/
|
|
81
|
+
chat(params: TextChatParams): Promise<TextChatResult>;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Official AInvoker SDK client.
|
|
86
|
+
*
|
|
87
|
+
* Use modality namespaces such as {@link Ainvoker.text} for gateway calls.
|
|
88
|
+
*/
|
|
89
|
+
declare class Ainvoker {
|
|
90
|
+
/** Text modality (`/v1/text/...`). */
|
|
91
|
+
readonly text: TextResource;
|
|
92
|
+
constructor(options: AinvokerOptions);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Known AInvoker API / SDK error codes.
|
|
97
|
+
* Unknown server codes remain assignable via the open string union.
|
|
98
|
+
*/
|
|
99
|
+
type AinvokerErrorCode = "UNAUTHORIZED" | "FORBIDDEN" | "NOT_FOUND" | "VALIDATION_ERROR" | "CONFLICT" | "UPSTREAM_ERROR" | "INTERNAL_ERROR" | "NETWORK_ERROR" | "INVALID_RESPONSE" | "HTTP_ERROR" | (string & {});
|
|
100
|
+
/**
|
|
101
|
+
* Error thrown when the AInvoker API returns a non-success response
|
|
102
|
+
* or the response body cannot be parsed as expected.
|
|
103
|
+
*/
|
|
104
|
+
declare class AinvokerError extends Error {
|
|
105
|
+
readonly status: number;
|
|
106
|
+
readonly code: AinvokerErrorCode;
|
|
107
|
+
/** Parsed response body when available (error envelope or raw JSON). */
|
|
108
|
+
readonly body: unknown;
|
|
109
|
+
constructor(status: number, code: AinvokerErrorCode, message: string, body?: unknown);
|
|
110
|
+
}
|
|
111
|
+
/** Type guard for {@link AinvokerError}. */
|
|
112
|
+
declare function isAinvokerError(error: unknown): error is AinvokerError;
|
|
113
|
+
|
|
114
|
+
export { Ainvoker, AinvokerError, type AinvokerErrorCode, type AinvokerOptions, type ChatMessage, type ChatUsage, type TextChatParams, type TextChatResult, isAinvokerError };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
interface HttpClientOptions {
|
|
2
|
+
apiKey: string;
|
|
3
|
+
baseUrl: string;
|
|
4
|
+
}
|
|
5
|
+
declare class HttpClient {
|
|
6
|
+
private readonly apiKey;
|
|
7
|
+
private readonly baseUrl;
|
|
8
|
+
constructor(options: HttpClientOptions);
|
|
9
|
+
/**
|
|
10
|
+
* POST JSON to a path under `baseUrl`. Unwraps `{ data: T }` on success.
|
|
11
|
+
*/
|
|
12
|
+
post<T>(path: string, body: unknown): Promise<T>;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Client configuration for {@link Ainvoker}.
|
|
17
|
+
*/
|
|
18
|
+
interface AinvokerOptions {
|
|
19
|
+
/**
|
|
20
|
+
* Project API key (`ain_…`).
|
|
21
|
+
* Sent as `Authorization: Bearer <apiKey>`.
|
|
22
|
+
*/
|
|
23
|
+
apiKey: string;
|
|
24
|
+
/**
|
|
25
|
+
* API host. Defaults to `http://localhost:3000`.
|
|
26
|
+
* Override for staging/production or a custom deployment.
|
|
27
|
+
*/
|
|
28
|
+
baseUrl?: string;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* A single chat turn.
|
|
32
|
+
*/
|
|
33
|
+
interface ChatMessage {
|
|
34
|
+
role: "system" | "user" | "assistant";
|
|
35
|
+
content: string;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Parameters for {@link TextResource.chat}.
|
|
39
|
+
*/
|
|
40
|
+
interface TextChatParams {
|
|
41
|
+
/**
|
|
42
|
+
* Provider model slug, e.g. `"openai/gpt-4o-mini"` or `"gemini/gemini-2.5-flash"`.
|
|
43
|
+
*/
|
|
44
|
+
model: string;
|
|
45
|
+
messages: ChatMessage[];
|
|
46
|
+
/** Sampling temperature (0–2). */
|
|
47
|
+
temperature?: number;
|
|
48
|
+
/** Maximum tokens to generate. */
|
|
49
|
+
maxTokens?: number;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Token usage reported by the gateway (may be null).
|
|
53
|
+
*/
|
|
54
|
+
interface ChatUsage {
|
|
55
|
+
inputTokens: number;
|
|
56
|
+
outputTokens: number;
|
|
57
|
+
totalTokens: number;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Successful text chat result (API `{ data }` unwrapped).
|
|
61
|
+
*/
|
|
62
|
+
interface TextChatResult {
|
|
63
|
+
id: string;
|
|
64
|
+
model: string;
|
|
65
|
+
message: ChatMessage;
|
|
66
|
+
usage: ChatUsage | null;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Text modality methods (`/v1/text/...`).
|
|
71
|
+
*/
|
|
72
|
+
declare class TextResource {
|
|
73
|
+
private readonly http;
|
|
74
|
+
constructor(http: HttpClient);
|
|
75
|
+
/**
|
|
76
|
+
* Text chat completion via the AInvoker gateway (`POST /v1/text/chat`).
|
|
77
|
+
*
|
|
78
|
+
* Authenticate with a project API key. `model` must be a `provider/model`
|
|
79
|
+
* slug (e.g. `"openai/gpt-4o-mini"` or `"gemini/gemini-2.5-flash"`).
|
|
80
|
+
*/
|
|
81
|
+
chat(params: TextChatParams): Promise<TextChatResult>;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Official AInvoker SDK client.
|
|
86
|
+
*
|
|
87
|
+
* Use modality namespaces such as {@link Ainvoker.text} for gateway calls.
|
|
88
|
+
*/
|
|
89
|
+
declare class Ainvoker {
|
|
90
|
+
/** Text modality (`/v1/text/...`). */
|
|
91
|
+
readonly text: TextResource;
|
|
92
|
+
constructor(options: AinvokerOptions);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Known AInvoker API / SDK error codes.
|
|
97
|
+
* Unknown server codes remain assignable via the open string union.
|
|
98
|
+
*/
|
|
99
|
+
type AinvokerErrorCode = "UNAUTHORIZED" | "FORBIDDEN" | "NOT_FOUND" | "VALIDATION_ERROR" | "CONFLICT" | "UPSTREAM_ERROR" | "INTERNAL_ERROR" | "NETWORK_ERROR" | "INVALID_RESPONSE" | "HTTP_ERROR" | (string & {});
|
|
100
|
+
/**
|
|
101
|
+
* Error thrown when the AInvoker API returns a non-success response
|
|
102
|
+
* or the response body cannot be parsed as expected.
|
|
103
|
+
*/
|
|
104
|
+
declare class AinvokerError extends Error {
|
|
105
|
+
readonly status: number;
|
|
106
|
+
readonly code: AinvokerErrorCode;
|
|
107
|
+
/** Parsed response body when available (error envelope or raw JSON). */
|
|
108
|
+
readonly body: unknown;
|
|
109
|
+
constructor(status: number, code: AinvokerErrorCode, message: string, body?: unknown);
|
|
110
|
+
}
|
|
111
|
+
/** Type guard for {@link AinvokerError}. */
|
|
112
|
+
declare function isAinvokerError(error: unknown): error is AinvokerError;
|
|
113
|
+
|
|
114
|
+
export { Ainvoker, AinvokerError, type AinvokerErrorCode, type AinvokerOptions, type ChatMessage, type ChatUsage, type TextChatParams, type TextChatResult, isAinvokerError };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
// src/errors.ts
|
|
2
|
+
var AinvokerError = class extends Error {
|
|
3
|
+
status;
|
|
4
|
+
code;
|
|
5
|
+
/** Parsed response body when available (error envelope or raw JSON). */
|
|
6
|
+
body;
|
|
7
|
+
constructor(status, code, message, body = void 0) {
|
|
8
|
+
super(message);
|
|
9
|
+
this.name = "AinvokerError";
|
|
10
|
+
this.status = status;
|
|
11
|
+
this.code = code;
|
|
12
|
+
this.body = body;
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
function isAinvokerError(error) {
|
|
16
|
+
return error instanceof AinvokerError;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// src/http.ts
|
|
20
|
+
function isRecord(value) {
|
|
21
|
+
return value !== null && typeof value === "object";
|
|
22
|
+
}
|
|
23
|
+
function parseErrorPayload(json) {
|
|
24
|
+
if (!isRecord(json) || !isRecord(json.error)) {
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
const { code, message } = json.error;
|
|
28
|
+
if (typeof code !== "string" || typeof message !== "string") {
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
return { code, message };
|
|
32
|
+
}
|
|
33
|
+
function hasDataEnvelope(json) {
|
|
34
|
+
return isRecord(json) && "data" in json;
|
|
35
|
+
}
|
|
36
|
+
var HttpClient = class {
|
|
37
|
+
apiKey;
|
|
38
|
+
baseUrl;
|
|
39
|
+
constructor(options) {
|
|
40
|
+
this.apiKey = options.apiKey;
|
|
41
|
+
this.baseUrl = options.baseUrl.replace(/\/+$/, "");
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* POST JSON to a path under `baseUrl`. Unwraps `{ data: T }` on success.
|
|
45
|
+
*/
|
|
46
|
+
async post(path, body) {
|
|
47
|
+
const url = `${this.baseUrl}${path.startsWith("/") ? path : `/${path}`}`;
|
|
48
|
+
let response;
|
|
49
|
+
try {
|
|
50
|
+
response = await fetch(url, {
|
|
51
|
+
method: "POST",
|
|
52
|
+
headers: {
|
|
53
|
+
Authorization: `Bearer ${this.apiKey}`,
|
|
54
|
+
"Content-Type": "application/json",
|
|
55
|
+
Accept: "application/json"
|
|
56
|
+
},
|
|
57
|
+
body: JSON.stringify(body)
|
|
58
|
+
});
|
|
59
|
+
} catch (cause) {
|
|
60
|
+
const message = cause instanceof Error ? cause.message : "Network request failed";
|
|
61
|
+
throw new AinvokerError(0, "NETWORK_ERROR", message);
|
|
62
|
+
}
|
|
63
|
+
const text = await response.text();
|
|
64
|
+
let json = void 0;
|
|
65
|
+
if (text.length > 0) {
|
|
66
|
+
try {
|
|
67
|
+
json = JSON.parse(text);
|
|
68
|
+
} catch {
|
|
69
|
+
throw new AinvokerError(
|
|
70
|
+
response.status,
|
|
71
|
+
"INVALID_RESPONSE",
|
|
72
|
+
"Response body was not valid JSON",
|
|
73
|
+
text
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
if (!response.ok) {
|
|
78
|
+
const parsed = parseErrorPayload(json);
|
|
79
|
+
throw new AinvokerError(
|
|
80
|
+
response.status,
|
|
81
|
+
parsed?.code ?? "HTTP_ERROR",
|
|
82
|
+
parsed?.message ?? `Request failed with status ${response.status}`,
|
|
83
|
+
json
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
if (!hasDataEnvelope(json)) {
|
|
87
|
+
throw new AinvokerError(
|
|
88
|
+
response.status,
|
|
89
|
+
"INVALID_RESPONSE",
|
|
90
|
+
"Response missing data envelope",
|
|
91
|
+
json
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
return json.data;
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
// src/resources/text.ts
|
|
99
|
+
var TextResource = class {
|
|
100
|
+
constructor(http) {
|
|
101
|
+
this.http = http;
|
|
102
|
+
}
|
|
103
|
+
http;
|
|
104
|
+
/**
|
|
105
|
+
* Text chat completion via the AInvoker gateway (`POST /v1/text/chat`).
|
|
106
|
+
*
|
|
107
|
+
* Authenticate with a project API key. `model` must be a `provider/model`
|
|
108
|
+
* slug (e.g. `"openai/gpt-4o-mini"` or `"gemini/gemini-2.5-flash"`).
|
|
109
|
+
*/
|
|
110
|
+
chat(params) {
|
|
111
|
+
return this.http.post("/v1/text/chat", params);
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
// src/client.ts
|
|
116
|
+
var DEFAULT_BASE_URL = "http://localhost:3000";
|
|
117
|
+
var Ainvoker = class {
|
|
118
|
+
/** Text modality (`/v1/text/...`). */
|
|
119
|
+
text;
|
|
120
|
+
constructor(options) {
|
|
121
|
+
if (!options.apiKey || options.apiKey.trim().length === 0) {
|
|
122
|
+
throw new Error("Ainvoker: apiKey is required");
|
|
123
|
+
}
|
|
124
|
+
const http = new HttpClient({
|
|
125
|
+
apiKey: options.apiKey,
|
|
126
|
+
baseUrl: options.baseUrl ?? DEFAULT_BASE_URL
|
|
127
|
+
});
|
|
128
|
+
this.text = new TextResource(http);
|
|
129
|
+
}
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
export { Ainvoker, AinvokerError, isAinvokerError };
|
|
133
|
+
//# sourceMappingURL=index.js.map
|
|
134
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/errors.ts","../src/http.ts","../src/resources/text.ts","../src/client.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\r\n * Known AInvoker API / SDK error codes.\r\n * Unknown server codes remain assignable via the open string union.\r\n */\r\nexport type AinvokerErrorCode =\r\n | \"UNAUTHORIZED\"\r\n | \"FORBIDDEN\"\r\n | \"NOT_FOUND\"\r\n | \"VALIDATION_ERROR\"\r\n | \"CONFLICT\"\r\n | \"UPSTREAM_ERROR\"\r\n | \"INTERNAL_ERROR\"\r\n | \"NETWORK_ERROR\"\r\n | \"INVALID_RESPONSE\"\r\n | \"HTTP_ERROR\"\r\n | (string & {})\r\n\r\n/**\r\n * Error thrown when the AInvoker API returns a non-success response\r\n * or the response body cannot be parsed as expected.\r\n */\r\nexport class AinvokerError extends Error {\r\n readonly status: number\r\n readonly code: AinvokerErrorCode\r\n /** Parsed response body when available (error envelope or raw JSON). */\r\n readonly body: unknown\r\n\r\n constructor(\r\n status: number,\r\n code: AinvokerErrorCode,\r\n message: string,\r\n body: unknown = undefined,\r\n ) {\r\n super(message)\r\n this.name = \"AinvokerError\"\r\n this.status = status\r\n this.code = code\r\n this.body = body\r\n }\r\n}\r\n\r\n/** Type guard for {@link AinvokerError}. */\r\nexport function isAinvokerError(error: unknown): error is AinvokerError {\r\n return error instanceof AinvokerError\r\n}\r\n","import { AinvokerError } from \"./errors.js\"\r\nimport type { AinvokerErrorCode } from \"./errors.js\"\r\nimport type { DataEnvelope } from \"./types.js\"\r\n\r\nexport interface HttpClientOptions {\r\n apiKey: string\r\n baseUrl: string\r\n}\r\n\r\nfunction isRecord(value: unknown): value is Record<string, unknown> {\r\n return value !== null && typeof value === \"object\"\r\n}\r\n\r\nfunction parseErrorPayload(json: unknown): { code: AinvokerErrorCode; message: string } | null {\r\n if (!isRecord(json) || !isRecord(json.error)) {\r\n return null\r\n }\r\n const { code, message } = json.error\r\n if (typeof code !== \"string\" || typeof message !== \"string\") {\r\n return null\r\n }\r\n return { code, message }\r\n}\r\n\r\nfunction hasDataEnvelope(json: unknown): json is DataEnvelope<unknown> {\r\n return isRecord(json) && \"data\" in json\r\n}\r\n\r\nexport class HttpClient {\r\n private readonly apiKey: string\r\n private readonly baseUrl: string\r\n\r\n constructor(options: HttpClientOptions) {\r\n this.apiKey = options.apiKey\r\n this.baseUrl = options.baseUrl.replace(/\\/+$/, \"\")\r\n }\r\n\r\n /**\r\n * POST JSON to a path under `baseUrl`. Unwraps `{ data: T }` on success.\r\n */\r\n async post<T>(path: string, body: unknown): Promise<T> {\r\n const url = `${this.baseUrl}${path.startsWith(\"/\") ? path : `/${path}`}`\r\n\r\n let response: Response\r\n try {\r\n response = await fetch(url, {\r\n method: \"POST\",\r\n headers: {\r\n Authorization: `Bearer ${this.apiKey}`,\r\n \"Content-Type\": \"application/json\",\r\n Accept: \"application/json\",\r\n },\r\n body: JSON.stringify(body),\r\n })\r\n } catch (cause) {\r\n const message = cause instanceof Error ? cause.message : \"Network request failed\"\r\n throw new AinvokerError(0, \"NETWORK_ERROR\", message)\r\n }\r\n\r\n const text = await response.text()\r\n let json: unknown = undefined\r\n if (text.length > 0) {\r\n try {\r\n json = JSON.parse(text) as unknown\r\n } catch {\r\n throw new AinvokerError(\r\n response.status,\r\n \"INVALID_RESPONSE\",\r\n \"Response body was not valid JSON\",\r\n text,\r\n )\r\n }\r\n }\r\n\r\n if (!response.ok) {\r\n const parsed = parseErrorPayload(json)\r\n throw new AinvokerError(\r\n response.status,\r\n parsed?.code ?? \"HTTP_ERROR\",\r\n parsed?.message ?? `Request failed with status ${response.status}`,\r\n json,\r\n )\r\n }\r\n\r\n if (!hasDataEnvelope(json)) {\r\n throw new AinvokerError(\r\n response.status,\r\n \"INVALID_RESPONSE\",\r\n \"Response missing data envelope\",\r\n json,\r\n )\r\n }\r\n\r\n return json.data as T\r\n }\r\n}\r\n","import type { HttpClient } from \"../http.js\"\r\nimport type { TextChatParams, TextChatResult } from \"../types.js\"\r\n\r\n/**\r\n * Text modality methods (`/v1/text/...`).\r\n */\r\nexport class TextResource {\r\n constructor(private readonly http: HttpClient) {}\r\n\r\n /**\r\n * Text chat completion via the AInvoker gateway (`POST /v1/text/chat`).\r\n *\r\n * Authenticate with a project API key. `model` must be a `provider/model`\r\n * slug (e.g. `\"openai/gpt-4o-mini\"` or `\"gemini/gemini-2.5-flash\"`).\r\n */\r\n chat(params: TextChatParams): Promise<TextChatResult> {\r\n return this.http.post<TextChatResult>(\"/v1/text/chat\", params)\r\n }\r\n}\r\n","import { HttpClient } from \"./http.js\"\r\nimport { TextResource } from \"./resources/text.js\"\r\nimport type { AinvokerOptions } from \"./types.js\"\r\n\r\nconst DEFAULT_BASE_URL = \"http://localhost:3000\"\r\n\r\n/**\r\n * Official AInvoker SDK client.\r\n *\r\n * Use modality namespaces such as {@link Ainvoker.text} for gateway calls.\r\n */\r\nexport class Ainvoker {\r\n /** Text modality (`/v1/text/...`). */\r\n readonly text: TextResource\r\n\r\n constructor(options: AinvokerOptions) {\r\n if (!options.apiKey || options.apiKey.trim().length === 0) {\r\n throw new Error(\"Ainvoker: apiKey is required\")\r\n }\r\n\r\n const http = new HttpClient({\r\n apiKey: options.apiKey,\r\n baseUrl: options.baseUrl ?? DEFAULT_BASE_URL,\r\n })\r\n\r\n this.text = new TextResource(http)\r\n }\r\n}\r\n"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "ainvoker",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Official TypeScript/JavaScript SDK for the AInvoker AI gateway",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": "AInvoker",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"main": "./dist/index.cjs",
|
|
9
|
+
"module": "./dist/index.js",
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"exports": {
|
|
12
|
+
".": {
|
|
13
|
+
"types": "./dist/index.d.ts",
|
|
14
|
+
"import": "./dist/index.js",
|
|
15
|
+
"require": "./dist/index.cjs"
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
"files": [
|
|
19
|
+
"dist",
|
|
20
|
+
"LICENSE",
|
|
21
|
+
"README.md"
|
|
22
|
+
],
|
|
23
|
+
"sideEffects": false,
|
|
24
|
+
"engines": {
|
|
25
|
+
"node": ">=18"
|
|
26
|
+
},
|
|
27
|
+
"keywords": [
|
|
28
|
+
"ainvoker",
|
|
29
|
+
"ai",
|
|
30
|
+
"sdk",
|
|
31
|
+
"llm",
|
|
32
|
+
"gateway",
|
|
33
|
+
"openai",
|
|
34
|
+
"gemini"
|
|
35
|
+
],
|
|
36
|
+
"scripts": {
|
|
37
|
+
"build": "tsup",
|
|
38
|
+
"test": "vitest run",
|
|
39
|
+
"test:watch": "vitest",
|
|
40
|
+
"typecheck": "tsc --noEmit",
|
|
41
|
+
"smoke": "tsx examples/smoke.ts",
|
|
42
|
+
"prepublishOnly": "npm run typecheck && npm test && npm run build"
|
|
43
|
+
},
|
|
44
|
+
"devDependencies": {
|
|
45
|
+
"@types/node": "^22.15.21",
|
|
46
|
+
"dotenv": "^17.4.2",
|
|
47
|
+
"tsup": "^8.5.0",
|
|
48
|
+
"tsx": "^4.19.4",
|
|
49
|
+
"typescript": "^5.8.3",
|
|
50
|
+
"vitest": "^3.1.4"
|
|
51
|
+
}
|
|
52
|
+
}
|