@nirmos/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 +62 -0
- package/dist/cjs/client.js +61 -0
- package/dist/cjs/client.js.map +1 -0
- package/dist/cjs/core/errors.js +143 -0
- package/dist/cjs/core/errors.js.map +1 -0
- package/dist/cjs/core/metadata.js +104 -0
- package/dist/cjs/core/metadata.js.map +1 -0
- package/dist/cjs/core/transport.js +276 -0
- package/dist/cjs/core/transport.js.map +1 -0
- package/dist/cjs/core/types.js +3 -0
- package/dist/cjs/core/types.js.map +1 -0
- package/dist/cjs/gateway/chat-stream.js +262 -0
- package/dist/cjs/gateway/chat-stream.js.map +1 -0
- package/dist/cjs/gateway/chat.js +102 -0
- package/dist/cjs/gateway/chat.js.map +1 -0
- package/dist/cjs/gateway/embeddings.js +33 -0
- package/dist/cjs/gateway/embeddings.js.map +1 -0
- package/dist/cjs/gateway/gateway.js +18 -0
- package/dist/cjs/gateway/gateway.js.map +1 -0
- package/dist/cjs/gateway/images.js +36 -0
- package/dist/cjs/gateway/images.js.map +1 -0
- package/dist/cjs/gateway/mappers.js +184 -0
- package/dist/cjs/gateway/mappers.js.map +1 -0
- package/dist/cjs/gateway/types.js +3 -0
- package/dist/cjs/gateway/types.js.map +1 -0
- package/dist/cjs/index.js +25 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/package.json +3 -0
- package/dist/cjs/prompts/cache.js +48 -0
- package/dist/cjs/prompts/cache.js.map +1 -0
- package/dist/cjs/prompts/mappers.js +242 -0
- package/dist/cjs/prompts/mappers.js.map +1 -0
- package/dist/cjs/prompts/prompts.js +121 -0
- package/dist/cjs/prompts/prompts.js.map +1 -0
- package/dist/cjs/prompts/render.js +86 -0
- package/dist/cjs/prompts/render.js.map +1 -0
- package/dist/cjs/prompts/types.js +3 -0
- package/dist/cjs/prompts/types.js.map +1 -0
- package/dist/cjs/prompts/versions.js +51 -0
- package/dist/cjs/prompts/versions.js.map +1 -0
- package/dist/esm/client.d.ts +28 -0
- package/dist/esm/client.d.ts.map +1 -0
- package/dist/esm/client.js +58 -0
- package/dist/esm/client.js.map +1 -0
- package/dist/esm/core/errors.d.ts +72 -0
- package/dist/esm/core/errors.d.ts.map +1 -0
- package/dist/esm/core/errors.js +125 -0
- package/dist/esm/core/errors.js.map +1 -0
- package/dist/esm/core/metadata.d.ts +11 -0
- package/dist/esm/core/metadata.d.ts.map +1 -0
- package/dist/esm/core/metadata.js +95 -0
- package/dist/esm/core/metadata.js.map +1 -0
- package/dist/esm/core/transport.d.ts +28 -0
- package/dist/esm/core/transport.d.ts.map +1 -0
- package/dist/esm/core/transport.js +272 -0
- package/dist/esm/core/transport.js.map +1 -0
- package/dist/esm/core/types.d.ts +43 -0
- package/dist/esm/core/types.d.ts.map +1 -0
- package/dist/esm/core/types.js +2 -0
- package/dist/esm/core/types.js.map +1 -0
- package/dist/esm/gateway/chat-stream.d.ts +9 -0
- package/dist/esm/gateway/chat-stream.d.ts.map +1 -0
- package/dist/esm/gateway/chat-stream.js +258 -0
- package/dist/esm/gateway/chat-stream.js.map +1 -0
- package/dist/esm/gateway/chat.d.ts +12 -0
- package/dist/esm/gateway/chat.d.ts.map +1 -0
- package/dist/esm/gateway/chat.js +98 -0
- package/dist/esm/gateway/chat.js.map +1 -0
- package/dist/esm/gateway/embeddings.d.ts +9 -0
- package/dist/esm/gateway/embeddings.d.ts.map +1 -0
- package/dist/esm/gateway/embeddings.js +29 -0
- package/dist/esm/gateway/embeddings.js.map +1 -0
- package/dist/esm/gateway/gateway.d.ts +12 -0
- package/dist/esm/gateway/gateway.d.ts.map +1 -0
- package/dist/esm/gateway/gateway.js +14 -0
- package/dist/esm/gateway/gateway.js.map +1 -0
- package/dist/esm/gateway/images.d.ts +9 -0
- package/dist/esm/gateway/images.d.ts.map +1 -0
- package/dist/esm/gateway/images.js +32 -0
- package/dist/esm/gateway/images.js.map +1 -0
- package/dist/esm/gateway/mappers.d.ts +11 -0
- package/dist/esm/gateway/mappers.d.ts.map +1 -0
- package/dist/esm/gateway/mappers.js +174 -0
- package/dist/esm/gateway/mappers.js.map +1 -0
- package/dist/esm/gateway/types.d.ts +168 -0
- package/dist/esm/gateway/types.d.ts.map +1 -0
- package/dist/esm/gateway/types.js +2 -0
- package/dist/esm/gateway/types.js.map +1 -0
- package/dist/esm/index.d.ts +8 -0
- package/dist/esm/index.d.ts.map +1 -0
- package/dist/esm/index.js +4 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/prompts/cache.d.ts +13 -0
- package/dist/esm/prompts/cache.d.ts.map +1 -0
- package/dist/esm/prompts/cache.js +44 -0
- package/dist/esm/prompts/cache.js.map +1 -0
- package/dist/esm/prompts/mappers.d.ts +8 -0
- package/dist/esm/prompts/mappers.d.ts.map +1 -0
- package/dist/esm/prompts/mappers.js +235 -0
- package/dist/esm/prompts/mappers.js.map +1 -0
- package/dist/esm/prompts/prompts.d.ts +17 -0
- package/dist/esm/prompts/prompts.d.ts.map +1 -0
- package/dist/esm/prompts/prompts.js +117 -0
- package/dist/esm/prompts/prompts.js.map +1 -0
- package/dist/esm/prompts/render.d.ts +3 -0
- package/dist/esm/prompts/render.d.ts.map +1 -0
- package/dist/esm/prompts/render.js +83 -0
- package/dist/esm/prompts/render.js.map +1 -0
- package/dist/esm/prompts/types.d.ts +119 -0
- package/dist/esm/prompts/types.d.ts.map +1 -0
- package/dist/esm/prompts/types.js +2 -0
- package/dist/esm/prompts/types.js.map +1 -0
- package/dist/esm/prompts/versions.d.ts +12 -0
- package/dist/esm/prompts/versions.d.ts.map +1 -0
- package/dist/esm/prompts/versions.js +47 -0
- package/dist/esm/prompts/versions.js.map +1 -0
- package/package.json +50 -0
- package/src/client.ts +89 -0
- package/src/core/errors.ts +160 -0
- package/src/core/metadata.ts +141 -0
- package/src/core/transport.ts +331 -0
- package/src/core/types.ts +51 -0
- package/src/gateway/chat-stream.ts +307 -0
- package/src/gateway/chat.ts +134 -0
- package/src/gateway/embeddings.ts +44 -0
- package/src/gateway/gateway.ts +17 -0
- package/src/gateway/images.ts +41 -0
- package/src/gateway/mappers.ts +234 -0
- package/src/gateway/types.ts +206 -0
- package/src/index.ts +83 -0
- package/src/prompts/cache.ts +50 -0
- package/src/prompts/mappers.ts +318 -0
- package/src/prompts/prompts.ts +188 -0
- package/src/prompts/render.ts +117 -0
- package/src/prompts/types.ts +148 -0
- package/src/prompts/versions.ts +80 -0
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { normalizeVersion, normalizeVersionPage, toWireVersionCreate, } from "./mappers.js";
|
|
2
|
+
export class PromptVersions {
|
|
3
|
+
#transport;
|
|
4
|
+
#invalidate;
|
|
5
|
+
constructor(transport, invalidate) {
|
|
6
|
+
this.#transport = transport;
|
|
7
|
+
this.#invalidate = invalidate;
|
|
8
|
+
}
|
|
9
|
+
async create(identifier, params, options) {
|
|
10
|
+
const { data } = await this.#transport.request({
|
|
11
|
+
method: "POST",
|
|
12
|
+
path: `/v1/prompts/${encodeURIComponent(identifier)}/versions`,
|
|
13
|
+
body: toWireVersionCreate(params),
|
|
14
|
+
options,
|
|
15
|
+
});
|
|
16
|
+
this.#invalidate();
|
|
17
|
+
return normalizeVersion(data);
|
|
18
|
+
}
|
|
19
|
+
async retrieve(identifier, version, options) {
|
|
20
|
+
const { data } = await this.#transport.request({
|
|
21
|
+
method: "GET",
|
|
22
|
+
path: `/v1/prompts/${encodeURIComponent(identifier)}/versions/${version}`,
|
|
23
|
+
options,
|
|
24
|
+
});
|
|
25
|
+
return normalizeVersion(data);
|
|
26
|
+
}
|
|
27
|
+
async list(identifier, options = {}) {
|
|
28
|
+
const { limit, cursor, ...requestOptions } = options;
|
|
29
|
+
const { data } = await this.#transport.request({
|
|
30
|
+
method: "GET",
|
|
31
|
+
path: `/v1/prompts/${encodeURIComponent(identifier)}/versions`,
|
|
32
|
+
query: { limit, cursor },
|
|
33
|
+
options: requestOptions,
|
|
34
|
+
});
|
|
35
|
+
return normalizeVersionPage(data);
|
|
36
|
+
}
|
|
37
|
+
async activate(identifier, version, options) {
|
|
38
|
+
const { data } = await this.#transport.request({
|
|
39
|
+
method: "POST",
|
|
40
|
+
path: `/v1/prompts/${encodeURIComponent(identifier)}/versions/${version}/activate`,
|
|
41
|
+
options,
|
|
42
|
+
});
|
|
43
|
+
this.#invalidate();
|
|
44
|
+
return normalizeVersion(data);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=versions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"versions.js","sourceRoot":"","sources":["../../../src/prompts/versions.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,gBAAgB,EAChB,oBAAoB,EACpB,mBAAmB,GACpB,MAAM,cAAc,CAAC;AAStB,MAAM,OAAO,cAAc;IAChB,UAAU,CAAgB;IAC1B,WAAW,CAAa;IAEjC,YAAY,SAAwB,EAAE,UAAsB;QAC1D,IAAI,CAAC,UAAU,GAAG,SAAS,CAAC;QAC5B,IAAI,CAAC,WAAW,GAAG,UAAU,CAAC;IAChC,CAAC;IAED,KAAK,CAAC,MAAM,CACV,UAA4B,EAC5B,MAAiC,EACjC,OAAwB;QAExB,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,OAAO,CAAU;YACtD,MAAM,EAAE,MAAM;YACd,IAAI,EAAE,eAAe,kBAAkB,CAAC,UAAU,CAAC,WAAW;YAC9D,IAAI,EAAE,mBAAmB,CAAC,MAAM,CAAC;YACjC,OAAO;SACR,CAAC,CAAC;QACH,IAAI,CAAC,WAAW,EAAE,CAAC;QACnB,OAAO,gBAAgB,CAAC,IAAI,CAAC,CAAC;IAChC,CAAC;IAED,KAAK,CAAC,QAAQ,CACZ,UAA4B,EAC5B,OAAe,EACf,OAAwB;QAExB,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,OAAO,CAAU;YACtD,MAAM,EAAE,KAAK;YACb,IAAI,EAAE,eAAe,kBAAkB,CAAC,UAAU,CAAC,aAAa,OAAO,EAAE;YACzE,OAAO;SACR,CAAC,CAAC;QACH,OAAO,gBAAgB,CAAC,IAAI,CAAC,CAAC;IAChC,CAAC;IAED,KAAK,CAAC,IAAI,CACR,UAA4B,EAC5B,UAAoC,EAAE;QAEtC,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,cAAc,EAAE,GAAG,OAAO,CAAC;QACrD,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,OAAO,CAAU;YACtD,MAAM,EAAE,KAAK;YACb,IAAI,EAAE,eAAe,kBAAkB,CAAC,UAAU,CAAC,WAAW;YAC9D,KAAK,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE;YACxB,OAAO,EAAE,cAAc;SACxB,CAAC,CAAC;QACH,OAAO,oBAAoB,CAAC,IAAI,CAAC,CAAC;IACpC,CAAC;IAED,KAAK,CAAC,QAAQ,CACZ,UAA4B,EAC5B,OAAe,EACf,OAAwB;QAExB,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,OAAO,CAAU;YACtD,MAAM,EAAE,MAAM;YACd,IAAI,EAAE,eAAe,kBAAkB,CAAC,UAAU,CAAC,aAAa,OAAO,WAAW;YAClF,OAAO;SACR,CAAC,CAAC;QACH,IAAI,CAAC,WAAW,EAAE,CAAC;QACnB,OAAO,gBAAgB,CAAC,IAAI,CAAC,CAAC;IAChC,CAAC;CACF"}
|
package/package.json
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@nirmos/sdk",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Official TypeScript SDK for the Nirmos AI platform.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"sideEffects": false,
|
|
8
|
+
"files": [
|
|
9
|
+
"dist",
|
|
10
|
+
"src",
|
|
11
|
+
"README.md"
|
|
12
|
+
],
|
|
13
|
+
"main": "./dist/cjs/index.js",
|
|
14
|
+
"module": "./dist/esm/index.js",
|
|
15
|
+
"types": "./dist/esm/index.d.ts",
|
|
16
|
+
"exports": {
|
|
17
|
+
".": {
|
|
18
|
+
"types": "./dist/esm/index.d.ts",
|
|
19
|
+
"import": "./dist/esm/index.js",
|
|
20
|
+
"require": "./dist/cjs/index.js"
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
"scripts": {
|
|
24
|
+
"build": "node ./scripts/clean.mjs && tsc -p tsconfig.build.json && tsc -p tsconfig.cjs.json && node ./scripts/write-cjs-package.mjs",
|
|
25
|
+
"check-types": "tsc --noEmit",
|
|
26
|
+
"lint": "eslint src tests --max-warnings 0",
|
|
27
|
+
"prepack": "pnpm build",
|
|
28
|
+
"test": "pnpm build && tsc -p tests/tsconfig.json && node --test tests/*.test.mjs"
|
|
29
|
+
},
|
|
30
|
+
"engines": {
|
|
31
|
+
"node": ">=18"
|
|
32
|
+
},
|
|
33
|
+
"publishConfig": {
|
|
34
|
+
"access": "public"
|
|
35
|
+
},
|
|
36
|
+
"keywords": [
|
|
37
|
+
"nirmos",
|
|
38
|
+
"ai",
|
|
39
|
+
"llm",
|
|
40
|
+
"gateway",
|
|
41
|
+
"prompts",
|
|
42
|
+
"sdk"
|
|
43
|
+
],
|
|
44
|
+
"devDependencies": {
|
|
45
|
+
"@repo/eslint-config": "workspace:*",
|
|
46
|
+
"@repo/typescript-config": "workspace:*",
|
|
47
|
+
"eslint": "^9.39.1",
|
|
48
|
+
"typescript": "5.9.2"
|
|
49
|
+
}
|
|
50
|
+
}
|
package/src/client.ts
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { ConfigurationError } from "./core/errors.js";
|
|
2
|
+
import { HttpTransport } from "./core/transport.js";
|
|
3
|
+
import type { HeadersInput } from "./core/types.js";
|
|
4
|
+
import { Gateway } from "./gateway/gateway.js";
|
|
5
|
+
import { Prompts } from "./prompts/prompts.js";
|
|
6
|
+
import type { PromptCacheConfig } from "./prompts/types.js";
|
|
7
|
+
|
|
8
|
+
export interface NirmosOptions {
|
|
9
|
+
/** Nirmos API key. Keep this key on trusted servers. */
|
|
10
|
+
apiKey: string;
|
|
11
|
+
/** API origin. Defaults to https://api.nirmos.com. */
|
|
12
|
+
baseUrl?: string;
|
|
13
|
+
/** Default request timeout. Defaults to 60 seconds. Set to 0 to disable. */
|
|
14
|
+
timeoutMs?: number;
|
|
15
|
+
/** Retry count for safe GET requests. Defaults to 2. */
|
|
16
|
+
maxRetries?: number;
|
|
17
|
+
/** Custom fetch implementation for tests or specialized runtimes. */
|
|
18
|
+
fetch?: typeof globalThis.fetch;
|
|
19
|
+
/** Headers added to every request. */
|
|
20
|
+
headers?: HeadersInput;
|
|
21
|
+
/** In-memory managed prompt cache configuration. Set false to disable. */
|
|
22
|
+
promptCache?: PromptCacheConfig | false;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export class Nirmos {
|
|
26
|
+
readonly gateway: Gateway;
|
|
27
|
+
readonly prompts: Prompts;
|
|
28
|
+
|
|
29
|
+
constructor(options: NirmosOptions) {
|
|
30
|
+
validateOptions(options);
|
|
31
|
+
const transport = new HttpTransport({
|
|
32
|
+
apiKey: options.apiKey,
|
|
33
|
+
baseUrl: normalizeBaseUrl(options.baseUrl ?? "https://api.nirmos.com"),
|
|
34
|
+
timeoutMs: nonNegative(options.timeoutMs, 60_000),
|
|
35
|
+
maxRetries: nonNegativeInteger(options.maxRetries, 2),
|
|
36
|
+
fetch: options.fetch ?? globalThis.fetch,
|
|
37
|
+
headers: options.headers,
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
this.prompts = new Prompts(transport, options.promptCache);
|
|
41
|
+
this.gateway = new Gateway(transport, this.prompts);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** Explicit alias for codebases that prefer client-suffixed class names. */
|
|
46
|
+
export { Nirmos as NirmosClient };
|
|
47
|
+
|
|
48
|
+
function validateOptions(options: NirmosOptions): void {
|
|
49
|
+
if (!options || typeof options !== "object") {
|
|
50
|
+
throw configError("Nirmos options are required.");
|
|
51
|
+
}
|
|
52
|
+
if (!options.apiKey || !options.apiKey.trim()) {
|
|
53
|
+
throw configError("Nirmos apiKey is required.");
|
|
54
|
+
}
|
|
55
|
+
if (typeof (options.fetch ?? globalThis.fetch) !== "function") {
|
|
56
|
+
throw configError(
|
|
57
|
+
"No fetch implementation found. Provide options.fetch in this runtime.",
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function normalizeBaseUrl(value: string): string {
|
|
63
|
+
let url: URL;
|
|
64
|
+
try {
|
|
65
|
+
url = new URL(value);
|
|
66
|
+
} catch {
|
|
67
|
+
throw configError("Nirmos baseUrl must be a valid absolute URL.");
|
|
68
|
+
}
|
|
69
|
+
return url.toString().replace(/\/+$/, "");
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function nonNegative(value: number | undefined, fallback: number): number {
|
|
73
|
+
return value !== undefined && Number.isFinite(value) && value >= 0
|
|
74
|
+
? value
|
|
75
|
+
: fallback;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function nonNegativeInteger(
|
|
79
|
+
value: number | undefined,
|
|
80
|
+
fallback: number,
|
|
81
|
+
): number {
|
|
82
|
+
return value !== undefined && Number.isInteger(value) && value >= 0
|
|
83
|
+
? value
|
|
84
|
+
: fallback;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function configError(message: string): ConfigurationError {
|
|
88
|
+
return new ConfigurationError(message);
|
|
89
|
+
}
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import type { RequestMetadata } from "./types.js";
|
|
2
|
+
|
|
3
|
+
export interface NirmosErrorOptions {
|
|
4
|
+
cause?: unknown;
|
|
5
|
+
code?: string;
|
|
6
|
+
requestId?: string;
|
|
7
|
+
traceId?: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export class NirmosError extends Error {
|
|
11
|
+
readonly code?: string;
|
|
12
|
+
readonly requestId?: string;
|
|
13
|
+
readonly traceId?: string;
|
|
14
|
+
|
|
15
|
+
constructor(message: string, options: NirmosErrorOptions = {}) {
|
|
16
|
+
super(message, { cause: options.cause });
|
|
17
|
+
this.name = "NirmosError";
|
|
18
|
+
this.code = options.code;
|
|
19
|
+
this.requestId = options.requestId;
|
|
20
|
+
this.traceId = options.traceId;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export class ConfigurationError extends NirmosError {
|
|
25
|
+
constructor(message: string, options: NirmosErrorOptions = {}) {
|
|
26
|
+
super(message, {
|
|
27
|
+
...options,
|
|
28
|
+
code: options.code ?? "SDK_CONFIGURATION_ERROR",
|
|
29
|
+
});
|
|
30
|
+
this.name = "ConfigurationError";
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export interface APIErrorOptions extends NirmosErrorOptions {
|
|
35
|
+
status: number;
|
|
36
|
+
retryable?: boolean;
|
|
37
|
+
retryAfterMs?: number;
|
|
38
|
+
details?: unknown;
|
|
39
|
+
metadata?: RequestMetadata;
|
|
40
|
+
headers?: Headers;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export class APIError extends NirmosError {
|
|
44
|
+
readonly status: number;
|
|
45
|
+
readonly retryable: boolean;
|
|
46
|
+
readonly retryAfterMs?: number;
|
|
47
|
+
readonly details?: unknown;
|
|
48
|
+
readonly metadata?: RequestMetadata;
|
|
49
|
+
readonly headers?: Headers;
|
|
50
|
+
|
|
51
|
+
constructor(message: string, options: APIErrorOptions) {
|
|
52
|
+
super(message, options);
|
|
53
|
+
this.name = "APIError";
|
|
54
|
+
this.status = options.status;
|
|
55
|
+
this.retryable = options.retryable ?? false;
|
|
56
|
+
this.retryAfterMs = options.retryAfterMs;
|
|
57
|
+
this.details = options.details;
|
|
58
|
+
this.metadata = options.metadata;
|
|
59
|
+
this.headers = options.headers;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export class AuthenticationError extends APIError {
|
|
64
|
+
constructor(message: string, options: APIErrorOptions) {
|
|
65
|
+
super(message, options);
|
|
66
|
+
this.name = "AuthenticationError";
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export class PermissionDeniedError extends APIError {
|
|
71
|
+
constructor(message: string, options: APIErrorOptions) {
|
|
72
|
+
super(message, options);
|
|
73
|
+
this.name = "PermissionDeniedError";
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export class NotFoundError extends APIError {
|
|
78
|
+
constructor(message: string, options: APIErrorOptions) {
|
|
79
|
+
super(message, options);
|
|
80
|
+
this.name = "NotFoundError";
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export class ConflictError extends APIError {
|
|
85
|
+
constructor(message: string, options: APIErrorOptions) {
|
|
86
|
+
super(message, options);
|
|
87
|
+
this.name = "ConflictError";
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export class ValidationError extends APIError {
|
|
92
|
+
constructor(message: string, options: APIErrorOptions) {
|
|
93
|
+
super(message, options);
|
|
94
|
+
this.name = "ValidationError";
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export class RateLimitError extends APIError {
|
|
99
|
+
constructor(message: string, options: APIErrorOptions) {
|
|
100
|
+
super(message, options);
|
|
101
|
+
this.name = "RateLimitError";
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export class ServerError extends APIError {
|
|
106
|
+
constructor(message: string, options: APIErrorOptions) {
|
|
107
|
+
super(message, options);
|
|
108
|
+
this.name = "ServerError";
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export class TimeoutError extends NirmosError {
|
|
113
|
+
readonly timeoutMs: number;
|
|
114
|
+
|
|
115
|
+
constructor(timeoutMs: number, options: NirmosErrorOptions = {}) {
|
|
116
|
+
super(`Request timed out after ${timeoutMs}ms.`, {
|
|
117
|
+
...options,
|
|
118
|
+
code: options.code ?? "REQUEST_TIMEOUT",
|
|
119
|
+
});
|
|
120
|
+
this.name = "TimeoutError";
|
|
121
|
+
this.timeoutMs = timeoutMs;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
export class RequestAbortedError extends NirmosError {
|
|
126
|
+
constructor(options: NirmosErrorOptions = {}) {
|
|
127
|
+
super("Request was aborted.", {
|
|
128
|
+
...options,
|
|
129
|
+
code: options.code ?? "REQUEST_ABORTED",
|
|
130
|
+
});
|
|
131
|
+
this.name = "RequestAbortedError";
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
export class NetworkError extends NirmosError {
|
|
136
|
+
constructor(cause?: unknown) {
|
|
137
|
+
super("Unable to reach the Nirmos API.", {
|
|
138
|
+
cause,
|
|
139
|
+
code: "NETWORK_ERROR",
|
|
140
|
+
});
|
|
141
|
+
this.name = "NetworkError";
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
export class StreamError extends NirmosError {
|
|
146
|
+
constructor(message: string, options: NirmosErrorOptions = {}) {
|
|
147
|
+
super(message, { ...options, code: options.code ?? "STREAM_ERROR" });
|
|
148
|
+
this.name = "StreamError";
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
export class PromptRenderError extends NirmosError {
|
|
153
|
+
readonly missingVariables: readonly string[];
|
|
154
|
+
|
|
155
|
+
constructor(message: string, missingVariables: readonly string[] = []) {
|
|
156
|
+
super(message, { code: "PROMPT_RENDER_ERROR" });
|
|
157
|
+
this.name = "PromptRenderError";
|
|
158
|
+
this.missingVariables = missingVariables;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import type { RequestMetadata } from "./types.js";
|
|
2
|
+
|
|
3
|
+
type UnknownRecord = Record<string, unknown>;
|
|
4
|
+
|
|
5
|
+
function asRecord(value: unknown): UnknownRecord | undefined {
|
|
6
|
+
return value !== null && typeof value === "object" && !Array.isArray(value)
|
|
7
|
+
? (value as UnknownRecord)
|
|
8
|
+
: undefined;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function stringValue(value: unknown): string | undefined {
|
|
12
|
+
return typeof value === "string" && value.length > 0 ? value : undefined;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function numberValue(value: unknown): number | undefined {
|
|
16
|
+
return typeof value === "number" && Number.isFinite(value)
|
|
17
|
+
? value
|
|
18
|
+
: undefined;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function header(response: Response, ...names: string[]): string | undefined {
|
|
22
|
+
for (const name of names) {
|
|
23
|
+
const value = response.headers.get(name);
|
|
24
|
+
if (value) return value;
|
|
25
|
+
}
|
|
26
|
+
return undefined;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function numericHeader(
|
|
30
|
+
response: Response,
|
|
31
|
+
...names: string[]
|
|
32
|
+
): number | undefined {
|
|
33
|
+
const value = header(response, ...names);
|
|
34
|
+
if (!value) return undefined;
|
|
35
|
+
const number = Number.parseFloat(value.replace(/ms$/i, ""));
|
|
36
|
+
return Number.isFinite(number) ? number : undefined;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function extractMetadata(
|
|
40
|
+
response: Response,
|
|
41
|
+
payload?: unknown,
|
|
42
|
+
): RequestMetadata {
|
|
43
|
+
const root = asRecord(payload);
|
|
44
|
+
const bodyMeta =
|
|
45
|
+
asRecord(root?._meta) ?? asRecord(root?.meta) ?? asRecord(root?.metadata);
|
|
46
|
+
|
|
47
|
+
const metadata: RequestMetadata = {
|
|
48
|
+
requestId:
|
|
49
|
+
stringValue(bodyMeta?.request_id) ??
|
|
50
|
+
stringValue(bodyMeta?.requestId) ??
|
|
51
|
+
header(response, "x-nirmos-request-id", "x-request-id"),
|
|
52
|
+
traceId:
|
|
53
|
+
stringValue(bodyMeta?.trace_id) ??
|
|
54
|
+
stringValue(bodyMeta?.traceId) ??
|
|
55
|
+
header(response, "x-nirmos-trace-id", "x-trace-id"),
|
|
56
|
+
provider:
|
|
57
|
+
stringValue(bodyMeta?.provider) ?? header(response, "x-nirmos-provider"),
|
|
58
|
+
model: stringValue(bodyMeta?.model) ?? header(response, "x-nirmos-model"),
|
|
59
|
+
latencyMs:
|
|
60
|
+
numberValue(bodyMeta?.latency_ms) ??
|
|
61
|
+
numberValue(bodyMeta?.latencyMs) ??
|
|
62
|
+
numericHeader(response, "x-nirmos-response-time", "x-response-time"),
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
const cacheStatus = header(
|
|
66
|
+
response,
|
|
67
|
+
"x-nirmos-cache-status",
|
|
68
|
+
"x-promptnetra-cache-status",
|
|
69
|
+
);
|
|
70
|
+
const cacheLayer = header(
|
|
71
|
+
response,
|
|
72
|
+
"x-nirmos-cache-layer",
|
|
73
|
+
"x-promptnetra-cache-layer",
|
|
74
|
+
);
|
|
75
|
+
const remainingTtlSeconds = numericHeader(
|
|
76
|
+
response,
|
|
77
|
+
"x-nirmos-cache-remaining-ttl",
|
|
78
|
+
"x-promptnetra-cache-remaining-ttl",
|
|
79
|
+
);
|
|
80
|
+
|
|
81
|
+
if (cacheStatus || cacheLayer || remainingTtlSeconds !== undefined) {
|
|
82
|
+
metadata.cache = {
|
|
83
|
+
status: cacheStatus,
|
|
84
|
+
layer: cacheLayer,
|
|
85
|
+
remainingTtlSeconds,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
return metadata;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export function compactMetadata(metadata: RequestMetadata): RequestMetadata {
|
|
93
|
+
return Object.fromEntries(
|
|
94
|
+
Object.entries(metadata).filter(([, value]) => value !== undefined),
|
|
95
|
+
) as RequestMetadata;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export function asUnknownRecord(value: unknown): UnknownRecord {
|
|
99
|
+
return asRecord(value) ?? {};
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export function readString(
|
|
103
|
+
record: UnknownRecord,
|
|
104
|
+
...keys: string[]
|
|
105
|
+
): string | undefined {
|
|
106
|
+
for (const key of keys) {
|
|
107
|
+
const value = stringValue(record[key]);
|
|
108
|
+
if (value !== undefined) return value;
|
|
109
|
+
}
|
|
110
|
+
return undefined;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export function readNumber(
|
|
114
|
+
record: UnknownRecord,
|
|
115
|
+
...keys: string[]
|
|
116
|
+
): number | undefined {
|
|
117
|
+
for (const key of keys) {
|
|
118
|
+
const value = numberValue(record[key]);
|
|
119
|
+
if (value !== undefined) return value;
|
|
120
|
+
}
|
|
121
|
+
return undefined;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export function readBoolean(
|
|
125
|
+
record: UnknownRecord,
|
|
126
|
+
...keys: string[]
|
|
127
|
+
): boolean | undefined {
|
|
128
|
+
for (const key of keys) {
|
|
129
|
+
const value = record[key];
|
|
130
|
+
if (typeof value === "boolean") return value;
|
|
131
|
+
}
|
|
132
|
+
return undefined;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
export function readArray(record: UnknownRecord, ...keys: string[]): unknown[] {
|
|
136
|
+
for (const key of keys) {
|
|
137
|
+
const value = record[key];
|
|
138
|
+
if (Array.isArray(value)) return value;
|
|
139
|
+
}
|
|
140
|
+
return [];
|
|
141
|
+
}
|