@lumifyai/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/LICENSE +21 -0
- package/README.md +177 -0
- package/dist/client.d.ts +67 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +205 -0
- package/dist/client.js.map +1 -0
- package/dist/errors.d.ts +91 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +119 -0
- package/dist/errors.js.map +1 -0
- package/dist/generated/models.d.ts +316 -0
- package/dist/generated/models.d.ts.map +1 -0
- package/dist/generated/models.js +9 -0
- package/dist/generated/models.js.map +1 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -0
- package/dist/lumify.d.ts +32 -0
- package/dist/lumify.d.ts.map +1 -0
- package/dist/lumify.js +42 -0
- package/dist/lumify.js.map +1 -0
- package/dist/meta.d.ts +27 -0
- package/dist/meta.d.ts.map +1 -0
- package/dist/meta.js +46 -0
- package/dist/meta.js.map +1 -0
- package/dist/pagination.d.ts +41 -0
- package/dist/pagination.d.ts.map +1 -0
- package/dist/pagination.js +53 -0
- package/dist/pagination.js.map +1 -0
- package/dist/resources/agent.d.ts +39 -0
- package/dist/resources/agent.d.ts.map +1 -0
- package/dist/resources/agent.js +52 -0
- package/dist/resources/agent.js.map +1 -0
- package/dist/resources/events.d.ts +89 -0
- package/dist/resources/events.d.ts.map +1 -0
- package/dist/resources/events.js +92 -0
- package/dist/resources/events.js.map +1 -0
- package/dist/resources/players.d.ts +39 -0
- package/dist/resources/players.d.ts.map +1 -0
- package/dist/resources/players.js +51 -0
- package/dist/resources/players.js.map +1 -0
- package/dist/resources/sports.d.ts +25 -0
- package/dist/resources/sports.d.ts.map +1 -0
- package/dist/resources/sports.js +25 -0
- package/dist/resources/sports.js.map +1 -0
- package/dist/resources/teams.d.ts +29 -0
- package/dist/resources/teams.d.ts.map +1 -0
- package/dist/resources/teams.js +37 -0
- package/dist/resources/teams.js.map +1 -0
- package/dist/resources/webhooks.d.ts +35 -0
- package/dist/resources/webhooks.d.ts.map +1 -0
- package/dist/resources/webhooks.js +38 -0
- package/dist/resources/webhooks.js.map +1 -0
- package/dist/sse.d.ts +57 -0
- package/dist/sse.d.ts.map +1 -0
- package/dist/sse.js +165 -0
- package/dist/sse.js.map +1 -0
- package/dist/webhook-signature.d.ts +30 -0
- package/dist/webhook-signature.d.ts.map +1 -0
- package/dist/webhook-signature.js +82 -0
- package/dist/webhook-signature.js.map +1 -0
- package/package.json +56 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Lumify AI
|
|
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,177 @@
|
|
|
1
|
+
# @lumifyai/sdk
|
|
2
|
+
|
|
3
|
+
Official TypeScript/JavaScript client for [Lumify](https://lumify.ai), the
|
|
4
|
+
agent-ready sports intelligence API — schedules, live scores, odds, line
|
|
5
|
+
movement, public betting splits, and AI bet intelligence across MLB, NFL,
|
|
6
|
+
NCAAF, NBA, NHL, tennis, and soccer.
|
|
7
|
+
|
|
8
|
+
> **Status:** v0.1.0 — the data-plane slice (sports/seasons/events/teams/players,
|
|
9
|
+
> SSE streaming, webhooks, agent onboarding). Same data as the REST API and the
|
|
10
|
+
> [MCP server](https://www.npmjs.com/package/@lumifyai/mcp) — this SDK *is* the
|
|
11
|
+
> typed REST path, not a third implementation.
|
|
12
|
+
|
|
13
|
+
## Install
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm install @lumifyai/sdk
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Requires Node.js 18+ (uses native `fetch` and Web Crypto — zero runtime
|
|
20
|
+
dependencies) or any modern browser/edge runtime.
|
|
21
|
+
|
|
22
|
+
## Quick start
|
|
23
|
+
|
|
24
|
+
```ts
|
|
25
|
+
import { Lumify } from "@lumifyai/sdk";
|
|
26
|
+
|
|
27
|
+
const client = new Lumify({ apiKey: process.env.LUMIFY_API_KEY! });
|
|
28
|
+
|
|
29
|
+
const { sports } = await client.sports.list();
|
|
30
|
+
|
|
31
|
+
const event = await client.events.get(12345, {
|
|
32
|
+
includeOdds: true,
|
|
33
|
+
includeIntelligence: true,
|
|
34
|
+
});
|
|
35
|
+
console.log(event.status, event.intelligence?.bets);
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Create a key at <https://lumify.ai/api-keys> or programmatically via
|
|
39
|
+
`client.agent.keys.create()`.
|
|
40
|
+
|
|
41
|
+
## Resources
|
|
42
|
+
|
|
43
|
+
```ts
|
|
44
|
+
client.sports.list() / client.seasons.list()
|
|
45
|
+
client.events.list(filters) / .get(id, { includeOdds?, includeIntelligence?, bookmaker? })
|
|
46
|
+
client.events.odds(id) / .oddsHistory(id) / .score(id) / .intelligence(id) / .splits(id)
|
|
47
|
+
client.events.stream(id) // SSE async iterator of live score updates
|
|
48
|
+
client.events.paginate(filters) / .iterate(filters) // cursor pagination helpers
|
|
49
|
+
client.teams.list(filters) / .get(id)
|
|
50
|
+
client.players.list(filters) / .get(id) / .events(id, filters)
|
|
51
|
+
client.webhooks.create() / .list() / .delete(id) / .verify(secret, header, rawBody)
|
|
52
|
+
client.agent.keys.create() / .list() / .revoke(id)
|
|
53
|
+
client.agent.credits.get() / .listPacks() / .topup(packId)
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Every method maps 1:1 to a REST endpoint and returns the same JSON shape you'd
|
|
57
|
+
get from `curl` — see <https://lumify.ai/docs/reference> for full field docs.
|
|
58
|
+
|
|
59
|
+
## Pagination
|
|
60
|
+
|
|
61
|
+
List endpoints are cursor-paginated (`after_id`/`limit`, max 100). Use the
|
|
62
|
+
iterator helpers instead of tracking cursors by hand:
|
|
63
|
+
|
|
64
|
+
```ts
|
|
65
|
+
for await (const event of client.events.iterate({ sport: "nfl", status: "scheduled" })) {
|
|
66
|
+
console.log(event.id, event.starts_at);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Or page-by-page (events pages use `events`, not `data`):
|
|
70
|
+
for await (const page of client.events.paginate({ sport: "nfl" }, { limit: 50 })) {
|
|
71
|
+
console.log(page.events?.length, "events, next cursor:", page.next_after_id);
|
|
72
|
+
}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Live score streaming (SSE)
|
|
76
|
+
|
|
77
|
+
```ts
|
|
78
|
+
for await (const evt of client.events.stream(eventId)) {
|
|
79
|
+
if (evt.event === "score") console.log(evt.data.status, evt.data.clock);
|
|
80
|
+
if (evt.event === "done") break;
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Cheaper than polling `client.events.score(id)` — the server only emits on
|
|
85
|
+
change, plus periodic keep-alives, and closes when the event finishes.
|
|
86
|
+
|
|
87
|
+
## Webhooks
|
|
88
|
+
|
|
89
|
+
```ts
|
|
90
|
+
const sub = await client.webhooks.create({ url: "https://you.example.com/hooks/lumify" });
|
|
91
|
+
// sub.signing_secret ("whsec_...") is returned once — store it.
|
|
92
|
+
|
|
93
|
+
// In your webhook handler, verify against the *raw* request body:
|
|
94
|
+
await client.webhooks.verify(signingSecret, req.header("Lumify-Signature")!, rawBody);
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
`verify()` throws `WebhookSignatureError` (bad format, signature mismatch, or a
|
|
98
|
+
stale/replayed timestamp) — treat that as "reject with 4xx", not a crash.
|
|
99
|
+
|
|
100
|
+
## Errors
|
|
101
|
+
|
|
102
|
+
Every non-2xx response throws a typed subclass of `LumifyError` — switch on
|
|
103
|
+
`err.code` (the stable machine-readable slug), not `err.message`:
|
|
104
|
+
|
|
105
|
+
```ts
|
|
106
|
+
import { NotFoundError, RateLimitError, ValidationError } from "@lumifyai/sdk";
|
|
107
|
+
|
|
108
|
+
try {
|
|
109
|
+
await client.events.get(999999999);
|
|
110
|
+
} catch (err) {
|
|
111
|
+
if (err instanceof NotFoundError) { /* ... */ }
|
|
112
|
+
if (err instanceof RateLimitError) console.log("retry after", err.retryAfter, "s");
|
|
113
|
+
if (err instanceof ValidationError) console.log(err.fieldErrors);
|
|
114
|
+
}
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
`AuthenticationError` (401), `PaymentError` (402), `PermissionError` (403, has `.upgradeUrl` on
|
|
118
|
+
sport-scope denials), `NotFoundError` (404), `ValidationError` (422, has
|
|
119
|
+
`.fieldErrors`), `RateLimitError` (429, has `.retryAfter` from the envelope or
|
|
120
|
+
`Retry-After` header), `APIError` (5xx), and `ConnectionError` (network/timeout,
|
|
121
|
+
never reached the server) all extend `LumifyError` (`.code`, `.status`, `.docUrl`,
|
|
122
|
+
`.requestId`).
|
|
123
|
+
|
|
124
|
+
GET requests are automatically retried (default: 2 attempts) with exponential
|
|
125
|
+
backoff on `429`/`5xx`/network failures, honoring `Retry-After`. Non-idempotent
|
|
126
|
+
requests (`POST`/webhook & key creation) are never auto-retried. Configure with
|
|
127
|
+
`maxRetries` / `timeoutMs` on the `Lumify` constructor.
|
|
128
|
+
|
|
129
|
+
## Credits and rate limits
|
|
130
|
+
|
|
131
|
+
Every successful response carries `X-Credits-Used`, `X-Credits-Remaining`, and
|
|
132
|
+
`X-RateLimit-*` headers. Read them via `getMeta()` (attached as hidden metadata
|
|
133
|
+
on the returned object, so it never pollutes `JSON.stringify` or your own
|
|
134
|
+
types):
|
|
135
|
+
|
|
136
|
+
```ts
|
|
137
|
+
import { getMeta } from "@lumifyai/sdk";
|
|
138
|
+
|
|
139
|
+
const odds = await client.events.odds(eventId);
|
|
140
|
+
const meta = getMeta(odds);
|
|
141
|
+
console.log(meta?.creditsUsed, meta?.rateLimitRemaining);
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
Queries for data that isn't available yet (e.g. odds not yet posted) return
|
|
145
|
+
`creditsUsed: 0` — you're never charged for a "not available" read.
|
|
146
|
+
|
|
147
|
+
## Sync with REST, MCP, and the OpenAPI contract
|
|
148
|
+
|
|
149
|
+
This SDK's response types (`src/generated/models.ts`) are generated from
|
|
150
|
+
Lumify's live OpenAPI schema, not hand-maintained — see
|
|
151
|
+
`scripts/export_openapi_sdk.py` (repo root) and `scripts/gen-models.mjs`
|
|
152
|
+
(this package). CI fails if either is stale, so the SDK can't silently drift
|
|
153
|
+
from what the API actually returns. The client ergonomics (this README's
|
|
154
|
+
resource shape, pagination/SSE/webhook helpers) are hand-written on top.
|
|
155
|
+
|
|
156
|
+
```bash
|
|
157
|
+
python scripts/export_openapi_sdk.py # regenerate the schema slice
|
|
158
|
+
node clients/lumify-sdk/scripts/gen-models.mjs # regenerate the TS models
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
## Development
|
|
162
|
+
|
|
163
|
+
```bash
|
|
164
|
+
npm install
|
|
165
|
+
npm run build # tsc -> dist/
|
|
166
|
+
npm test # build + node --test
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
## License
|
|
170
|
+
|
|
171
|
+
[MIT](./LICENSE) © 2026 Lumify AI
|
|
172
|
+
|
|
173
|
+
## Related
|
|
174
|
+
|
|
175
|
+
- Docs: <https://lumify.ai/docs>
|
|
176
|
+
- MCP server (for AI agent runtimes): [`@lumifyai/mcp`](https://www.npmjs.com/package/@lumifyai/mcp)
|
|
177
|
+
- npm: <https://www.npmjs.com/package/@lumifyai/sdk>
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
export declare const DEFAULT_BASE_URL = "https://lumify.ai";
|
|
2
|
+
export interface LumifyClientOptions {
|
|
3
|
+
/** Lumify API key (`lmfy-...`). Create one at https://lumify.ai/api-keys. */
|
|
4
|
+
apiKey: string;
|
|
5
|
+
/** Override the API origin — mainly for testing against a local server. */
|
|
6
|
+
baseUrl?: string;
|
|
7
|
+
/** Per-request timeout in milliseconds. Default 30000. */
|
|
8
|
+
timeoutMs?: number;
|
|
9
|
+
/** Retries for idempotent (GET) requests on 429/5xx/network errors. Default 2. */
|
|
10
|
+
maxRetries?: number;
|
|
11
|
+
/** Injectable fetch implementation (tests, non-standard runtimes). */
|
|
12
|
+
fetch?: typeof fetch;
|
|
13
|
+
/** Extra string appended to the User-Agent header. */
|
|
14
|
+
userAgent?: string;
|
|
15
|
+
}
|
|
16
|
+
export type QueryParams = Record<string, string | number | boolean | null | undefined>;
|
|
17
|
+
export interface RequestOptions {
|
|
18
|
+
query?: QueryParams;
|
|
19
|
+
body?: unknown;
|
|
20
|
+
/** Override retry behavior for this call (defaults to the method's idempotency). */
|
|
21
|
+
idempotent?: boolean;
|
|
22
|
+
signal?: AbortSignal;
|
|
23
|
+
}
|
|
24
|
+
/** Low-level HTTP transport shared by every resource. Not usually constructed directly — use {@link Lumify}. */
|
|
25
|
+
export declare class LumifyClient {
|
|
26
|
+
readonly baseUrl: string;
|
|
27
|
+
private readonly apiKey;
|
|
28
|
+
private readonly timeoutMs;
|
|
29
|
+
private readonly maxRetries;
|
|
30
|
+
private readonly fetchImpl;
|
|
31
|
+
private readonly userAgent;
|
|
32
|
+
constructor(opts: LumifyClientOptions);
|
|
33
|
+
/** Build an absolute URL for a path, without performing the request. */
|
|
34
|
+
url(path: string, query?: QueryParams): string;
|
|
35
|
+
/**
|
|
36
|
+
* Base headers for a request that needs raw `fetch` (SSE streaming), where
|
|
37
|
+
* `request()`'s buffered JSON handling doesn't apply. Not part of the
|
|
38
|
+
* supported public API surface for arbitrary callers — resources within
|
|
39
|
+
* this package use it to avoid duplicating auth/UA construction.
|
|
40
|
+
*/
|
|
41
|
+
authHeaders(accept?: string): Record<string, string>;
|
|
42
|
+
/** The injected/global `fetch` this client uses — for raw streaming calls (SSE). */
|
|
43
|
+
get fetchFn(): typeof fetch;
|
|
44
|
+
/** Per-request timeout (ms) configured on this client — used as the SSE connect timeout default. */
|
|
45
|
+
get requestTimeoutMs(): number;
|
|
46
|
+
/** GET a resource and parse its JSON body. */
|
|
47
|
+
get<T>(path: string, options?: RequestOptions): Promise<T>;
|
|
48
|
+
/** POST a resource and parse its JSON body. Not retried by default (not idempotent). */
|
|
49
|
+
post<T>(path: string, options?: RequestOptions): Promise<T>;
|
|
50
|
+
/** DELETE a resource and parse its JSON body. */
|
|
51
|
+
delete<T>(path: string, options?: RequestOptions): Promise<T>;
|
|
52
|
+
/**
|
|
53
|
+
* Perform the raw fetch, with:
|
|
54
|
+
* - Bearer auth + JSON headers
|
|
55
|
+
* - a hard per-request timeout
|
|
56
|
+
* - retries with exponential backoff for idempotent requests on 429/5xx/network
|
|
57
|
+
* failures, honoring `Retry-After` / `error.retry_after` on 429
|
|
58
|
+
* - the unified error envelope mapped to a typed {@link LumifyError} subclass
|
|
59
|
+
* - X-Credits and X-RateLimit response headers attached to the parsed body
|
|
60
|
+
* via {@link attachMeta} (read with {@link getMeta})
|
|
61
|
+
*/
|
|
62
|
+
request<T>(method: string, path: string, options?: RequestOptions): Promise<T>;
|
|
63
|
+
private shouldRetry;
|
|
64
|
+
private backoffMs;
|
|
65
|
+
private attempt;
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,gBAAgB,sBAAsB,CAAC;AAKpD,MAAM,WAAW,mBAAmB;IAClC,6EAA6E;IAC7E,MAAM,EAAE,MAAM,CAAC;IACf,2EAA2E;IAC3E,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,0DAA0D;IAC1D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,kFAAkF;IAClF,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,sEAAsE;IACtE,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;IACrB,sDAAsD;IACtD,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG,SAAS,CAAC,CAAC;AAEvF,MAAM,WAAW,cAAc;IAC7B,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,oFAAoF;IACpF,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAiBD,gHAAgH;AAChH,qBAAa,YAAY;IACvB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAe;IACzC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IAEnC,YAAY,IAAI,EAAE,mBAAmB,EAgBpC;IAED,wEAAwE;IACxE,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,WAAW,GAAG,MAAM,CAE7C;IAED;;;;;OAKG;IACH,WAAW,CAAC,MAAM,SAAqB,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAM/D;IAED,oFAAoF;IACpF,IAAI,OAAO,IAAI,OAAO,KAAK,CAE1B;IAED,oGAAoG;IACpG,IAAI,gBAAgB,IAAI,MAAM,CAE7B;IAED,8CAA8C;IAC9C,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,cAAmB,GAAG,OAAO,CAAC,CAAC,CAAC,CAE7D;IAED,wFAAwF;IACxF,IAAI,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,cAAmB,GAAG,OAAO,CAAC,CAAC,CAAC,CAE9D;IAED,iDAAiD;IACjD,MAAM,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,cAAmB,GAAG,OAAO,CAAC,CAAC,CAAC,CAEhE;IAED;;;;;;;;;OASG;IACG,OAAO,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,cAAmB,GAAG,OAAO,CAAC,CAAC,CAAC,CAoBvF;IAED,OAAO,CAAC,WAAW;IAMnB,OAAO,CAAC,SAAS;YAUH,OAAO;CAmDtB"}
|
package/dist/client.js
ADDED
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
import { ConnectionError, APIError, errorFromResponse } from "./errors.js";
|
|
2
|
+
import { attachMeta, parseMeta } from "./meta.js";
|
|
3
|
+
export const DEFAULT_BASE_URL = "https://lumify.ai";
|
|
4
|
+
const DEFAULT_TIMEOUT_MS = 30_000;
|
|
5
|
+
const DEFAULT_MAX_RETRIES = 2;
|
|
6
|
+
const SDK_VERSION = "0.1.0";
|
|
7
|
+
function buildQuery(params) {
|
|
8
|
+
if (!params)
|
|
9
|
+
return "";
|
|
10
|
+
const usp = new URLSearchParams();
|
|
11
|
+
for (const [key, value] of Object.entries(params)) {
|
|
12
|
+
if (value === undefined || value === null)
|
|
13
|
+
continue;
|
|
14
|
+
usp.set(key, String(value));
|
|
15
|
+
}
|
|
16
|
+
const qs = usp.toString();
|
|
17
|
+
return qs ? `?${qs}` : "";
|
|
18
|
+
}
|
|
19
|
+
async function sleep(ms) {
|
|
20
|
+
await new Promise((resolve) => setTimeout(resolve, ms));
|
|
21
|
+
}
|
|
22
|
+
/** Low-level HTTP transport shared by every resource. Not usually constructed directly — use {@link Lumify}. */
|
|
23
|
+
export class LumifyClient {
|
|
24
|
+
baseUrl;
|
|
25
|
+
apiKey;
|
|
26
|
+
timeoutMs;
|
|
27
|
+
maxRetries;
|
|
28
|
+
fetchImpl;
|
|
29
|
+
userAgent;
|
|
30
|
+
constructor(opts) {
|
|
31
|
+
if (!opts.apiKey) {
|
|
32
|
+
throw new Error("Lumify SDK: `apiKey` is required (create one at https://lumify.ai/api-keys).");
|
|
33
|
+
}
|
|
34
|
+
this.apiKey = opts.apiKey;
|
|
35
|
+
this.baseUrl = (opts.baseUrl ?? DEFAULT_BASE_URL).replace(/\/$/, "");
|
|
36
|
+
this.timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
37
|
+
this.maxRetries = opts.maxRetries ?? DEFAULT_MAX_RETRIES;
|
|
38
|
+
this.fetchImpl = opts.fetch ?? globalThis.fetch;
|
|
39
|
+
if (!this.fetchImpl) {
|
|
40
|
+
throw new Error("Lumify SDK: no `fetch` available in this runtime. Use Node 18+, a browser, " +
|
|
41
|
+
"or pass a `fetch` implementation in the client options.");
|
|
42
|
+
}
|
|
43
|
+
this.userAgent = `lumify-sdk-js/${SDK_VERSION}${opts.userAgent ? ` ${opts.userAgent}` : ""}`;
|
|
44
|
+
}
|
|
45
|
+
/** Build an absolute URL for a path, without performing the request. */
|
|
46
|
+
url(path, query) {
|
|
47
|
+
return `${this.baseUrl}${path}${buildQuery(query)}`;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Base headers for a request that needs raw `fetch` (SSE streaming), where
|
|
51
|
+
* `request()`'s buffered JSON handling doesn't apply. Not part of the
|
|
52
|
+
* supported public API surface for arbitrary callers — resources within
|
|
53
|
+
* this package use it to avoid duplicating auth/UA construction.
|
|
54
|
+
*/
|
|
55
|
+
authHeaders(accept = "application/json") {
|
|
56
|
+
return {
|
|
57
|
+
Authorization: `Bearer ${this.apiKey}`,
|
|
58
|
+
Accept: accept,
|
|
59
|
+
"User-Agent": this.userAgent,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
/** The injected/global `fetch` this client uses — for raw streaming calls (SSE). */
|
|
63
|
+
get fetchFn() {
|
|
64
|
+
return this.fetchImpl;
|
|
65
|
+
}
|
|
66
|
+
/** Per-request timeout (ms) configured on this client — used as the SSE connect timeout default. */
|
|
67
|
+
get requestTimeoutMs() {
|
|
68
|
+
return this.timeoutMs;
|
|
69
|
+
}
|
|
70
|
+
/** GET a resource and parse its JSON body. */
|
|
71
|
+
get(path, options = {}) {
|
|
72
|
+
return this.request("GET", path, { ...options, idempotent: options.idempotent ?? true });
|
|
73
|
+
}
|
|
74
|
+
/** POST a resource and parse its JSON body. Not retried by default (not idempotent). */
|
|
75
|
+
post(path, options = {}) {
|
|
76
|
+
return this.request("POST", path, { ...options, idempotent: options.idempotent ?? false });
|
|
77
|
+
}
|
|
78
|
+
/** DELETE a resource and parse its JSON body. */
|
|
79
|
+
delete(path, options = {}) {
|
|
80
|
+
return this.request("DELETE", path, { ...options, idempotent: options.idempotent ?? true });
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Perform the raw fetch, with:
|
|
84
|
+
* - Bearer auth + JSON headers
|
|
85
|
+
* - a hard per-request timeout
|
|
86
|
+
* - retries with exponential backoff for idempotent requests on 429/5xx/network
|
|
87
|
+
* failures, honoring `Retry-After` / `error.retry_after` on 429
|
|
88
|
+
* - the unified error envelope mapped to a typed {@link LumifyError} subclass
|
|
89
|
+
* - X-Credits and X-RateLimit response headers attached to the parsed body
|
|
90
|
+
* via {@link attachMeta} (read with {@link getMeta})
|
|
91
|
+
*/
|
|
92
|
+
async request(method, path, options = {}) {
|
|
93
|
+
const idempotent = options.idempotent ?? method === "GET";
|
|
94
|
+
const attempts = idempotent ? Math.max(1, this.maxRetries + 1) : 1;
|
|
95
|
+
let lastError;
|
|
96
|
+
for (let attempt = 0; attempt < attempts; attempt++) {
|
|
97
|
+
if (attempt > 0) {
|
|
98
|
+
await sleep(this.backoffMs(attempt, lastError));
|
|
99
|
+
}
|
|
100
|
+
try {
|
|
101
|
+
return await this.attempt(method, path, options);
|
|
102
|
+
}
|
|
103
|
+
catch (err) {
|
|
104
|
+
lastError = err;
|
|
105
|
+
if (!this.shouldRetry(err) || attempt === attempts - 1) {
|
|
106
|
+
throw err;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
// Unreachable — the loop always returns or throws — but keeps TS satisfied.
|
|
111
|
+
throw lastError;
|
|
112
|
+
}
|
|
113
|
+
shouldRetry(err) {
|
|
114
|
+
if (err instanceof ConnectionError)
|
|
115
|
+
return true;
|
|
116
|
+
const status = err.status;
|
|
117
|
+
return status === 429 || (typeof status === "number" && status >= 500);
|
|
118
|
+
}
|
|
119
|
+
backoffMs(attempt, lastError) {
|
|
120
|
+
const retryAfter = lastError?.retryAfter;
|
|
121
|
+
if (typeof retryAfter === "number" && retryAfter >= 0) {
|
|
122
|
+
return retryAfter * 1000;
|
|
123
|
+
}
|
|
124
|
+
const base = 250 * 2 ** (attempt - 1);
|
|
125
|
+
const jitter = Math.random() * 100;
|
|
126
|
+
return base + jitter;
|
|
127
|
+
}
|
|
128
|
+
async attempt(method, path, options) {
|
|
129
|
+
const url = this.url(path, options.query);
|
|
130
|
+
const headers = {
|
|
131
|
+
Authorization: `Bearer ${this.apiKey}`,
|
|
132
|
+
Accept: "application/json",
|
|
133
|
+
"User-Agent": this.userAgent,
|
|
134
|
+
};
|
|
135
|
+
let body;
|
|
136
|
+
if (options.body !== undefined) {
|
|
137
|
+
headers["Content-Type"] = "application/json";
|
|
138
|
+
body = JSON.stringify(options.body);
|
|
139
|
+
}
|
|
140
|
+
const controller = new AbortController();
|
|
141
|
+
const timeout = setTimeout(() => controller.abort(new Error("timeout")), this.timeoutMs);
|
|
142
|
+
const signal = options.signal ? anySignal([options.signal, controller.signal]) : controller.signal;
|
|
143
|
+
let res;
|
|
144
|
+
try {
|
|
145
|
+
res = await this.fetchImpl(url, { method, headers, body, signal });
|
|
146
|
+
}
|
|
147
|
+
catch (err) {
|
|
148
|
+
throw new ConnectionError(`Request to ${method} ${path} failed: ${err instanceof Error ? err.message : String(err)}`, { cause: err });
|
|
149
|
+
}
|
|
150
|
+
finally {
|
|
151
|
+
clearTimeout(timeout);
|
|
152
|
+
}
|
|
153
|
+
const requestId = res.headers.get("x-request-id");
|
|
154
|
+
const text = await res.text();
|
|
155
|
+
const json = text ? safeJsonParse(text) : undefined;
|
|
156
|
+
const parseFailed = Boolean(text) && json === undefined;
|
|
157
|
+
if (!res.ok) {
|
|
158
|
+
const payload = json?.error;
|
|
159
|
+
const retryAfterHeader = parseRetryAfter(res.headers.get("retry-after"));
|
|
160
|
+
throw errorFromResponse(res.status, payload, requestId, { retryAfterHeader });
|
|
161
|
+
}
|
|
162
|
+
if (parseFailed) {
|
|
163
|
+
throw new APIError(`Response from ${method} ${path} was not valid JSON.`, {
|
|
164
|
+
status: res.status,
|
|
165
|
+
code: "invalid_response",
|
|
166
|
+
requestId,
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
const meta = parseMeta(res.headers);
|
|
170
|
+
return attachMeta(json, meta);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
function safeJsonParse(text) {
|
|
174
|
+
try {
|
|
175
|
+
return JSON.parse(text);
|
|
176
|
+
}
|
|
177
|
+
catch {
|
|
178
|
+
return undefined;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
/** Parse `Retry-After` as seconds. Supports integer seconds; ignores HTTP-date forms. */
|
|
182
|
+
function parseRetryAfter(header) {
|
|
183
|
+
if (header == null || header === "")
|
|
184
|
+
return undefined;
|
|
185
|
+
const seconds = Number(header);
|
|
186
|
+
if (!Number.isFinite(seconds) || seconds < 0)
|
|
187
|
+
return undefined;
|
|
188
|
+
return seconds;
|
|
189
|
+
}
|
|
190
|
+
/** Minimal AbortSignal.any polyfill-free combinator (works without lib.dom's AbortSignal.any). */
|
|
191
|
+
function anySignal(signals) {
|
|
192
|
+
if (typeof AbortSignal !== "undefined" && "any" in AbortSignal) {
|
|
193
|
+
return AbortSignal.any(signals);
|
|
194
|
+
}
|
|
195
|
+
const controller = new AbortController();
|
|
196
|
+
for (const s of signals) {
|
|
197
|
+
if (s.aborted) {
|
|
198
|
+
controller.abort(s.reason);
|
|
199
|
+
break;
|
|
200
|
+
}
|
|
201
|
+
s.addEventListener("abort", () => controller.abort(s.reason), { once: true });
|
|
202
|
+
}
|
|
203
|
+
return controller.signal;
|
|
204
|
+
}
|
|
205
|
+
//# 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,91 @@
|
|
|
1
|
+
/** Shape of the `error` object inside every Lumify error envelope. */
|
|
2
|
+
export interface LumifyErrorPayload {
|
|
3
|
+
code: string;
|
|
4
|
+
message: string;
|
|
5
|
+
status: number;
|
|
6
|
+
doc_url?: string;
|
|
7
|
+
/** Present on 429 responses; seconds until the rate-limit window resets. */
|
|
8
|
+
retry_after?: number;
|
|
9
|
+
/** Present on some 403 responses (sport-scope denials). */
|
|
10
|
+
upgrade_url?: string;
|
|
11
|
+
/** Present on 422 validation errors. */
|
|
12
|
+
errors?: Array<{
|
|
13
|
+
field: string;
|
|
14
|
+
message: string;
|
|
15
|
+
type: string;
|
|
16
|
+
}>;
|
|
17
|
+
[key: string]: unknown;
|
|
18
|
+
}
|
|
19
|
+
export interface LumifyErrorOptions {
|
|
20
|
+
status: number;
|
|
21
|
+
code: string;
|
|
22
|
+
docUrl?: string;
|
|
23
|
+
requestId?: string | null;
|
|
24
|
+
payload?: LumifyErrorPayload;
|
|
25
|
+
cause?: unknown;
|
|
26
|
+
}
|
|
27
|
+
/** Base class for every error the SDK throws for a non-2xx API response. */
|
|
28
|
+
export declare class LumifyError extends Error {
|
|
29
|
+
/** Stable machine-readable slug, e.g. "not_found" — switch on this. */
|
|
30
|
+
readonly code: string;
|
|
31
|
+
/** HTTP status code. */
|
|
32
|
+
readonly status: number;
|
|
33
|
+
/** Link to the error-code reference docs. */
|
|
34
|
+
readonly docUrl?: string;
|
|
35
|
+
/** Value of the `X-Request-Id` request header, if the caller sent one. */
|
|
36
|
+
readonly requestId?: string | null;
|
|
37
|
+
/** The full parsed `error` object from the response envelope. */
|
|
38
|
+
readonly payload?: LumifyErrorPayload;
|
|
39
|
+
constructor(message: string, opts: LumifyErrorOptions);
|
|
40
|
+
}
|
|
41
|
+
export declare class AuthenticationError extends LumifyError {
|
|
42
|
+
constructor(message: string, opts: LumifyErrorOptions);
|
|
43
|
+
}
|
|
44
|
+
export declare class PermissionError extends LumifyError {
|
|
45
|
+
/** Present on sport-scope denials — where to upgrade the API key's plan/scope. */
|
|
46
|
+
readonly upgradeUrl?: string;
|
|
47
|
+
constructor(message: string, opts: LumifyErrorOptions);
|
|
48
|
+
}
|
|
49
|
+
export declare class NotFoundError extends LumifyError {
|
|
50
|
+
constructor(message: string, opts: LumifyErrorOptions);
|
|
51
|
+
}
|
|
52
|
+
export declare class RateLimitError extends LumifyError {
|
|
53
|
+
/** Seconds to wait before retrying (mirrors the `Retry-After` header / `error.retry_after`). */
|
|
54
|
+
readonly retryAfter?: number;
|
|
55
|
+
constructor(message: string, opts: LumifyErrorOptions & {
|
|
56
|
+
retryAfter?: number;
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
export interface FieldError {
|
|
60
|
+
field: string;
|
|
61
|
+
message: string;
|
|
62
|
+
type: string;
|
|
63
|
+
}
|
|
64
|
+
export declare class ValidationError extends LumifyError {
|
|
65
|
+
readonly fieldErrors: FieldError[];
|
|
66
|
+
constructor(message: string, opts: LumifyErrorOptions);
|
|
67
|
+
}
|
|
68
|
+
/** 402 — credit top-up or payment method required. */
|
|
69
|
+
export declare class PaymentError extends LumifyError {
|
|
70
|
+
constructor(message: string, opts: LumifyErrorOptions);
|
|
71
|
+
}
|
|
72
|
+
/** 5xx or any status this SDK doesn't have a dedicated class for. */
|
|
73
|
+
export declare class APIError extends LumifyError {
|
|
74
|
+
constructor(message: string, opts: LumifyErrorOptions);
|
|
75
|
+
}
|
|
76
|
+
/** Network failure, timeout, or abort — the request never got a response. */
|
|
77
|
+
export declare class ConnectionError extends LumifyError {
|
|
78
|
+
constructor(message: string, opts?: {
|
|
79
|
+
cause?: unknown;
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
export interface ErrorFromResponseOptions {
|
|
83
|
+
/** Seconds parsed from the `Retry-After` response header, when present. */
|
|
84
|
+
retryAfterHeader?: number;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Build the right LumifyError subclass from a parsed error envelope.
|
|
88
|
+
* Falls back to APIError for unrecognized status codes.
|
|
89
|
+
*/
|
|
90
|
+
export declare function errorFromResponse(status: number, payload: LumifyErrorPayload | undefined, requestId: string | null, options?: ErrorFromResponseOptions): LumifyError;
|
|
91
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"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"}
|