@lumavox/server 0.0.0-stage → 0.2.1
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 +134 -2
- package/dist/client.d.ts +59 -0
- package/dist/client.js +52 -0
- package/dist/errors.d.ts +86 -0
- package/dist/errors.js +137 -0
- package/dist/gen/index.d.ts +1 -0
- package/dist/gen/index.js +2 -0
- package/dist/gen/types.gen.d.ts +6563 -0
- package/dist/gen/types.gen.js +2 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.js +8 -0
- package/dist/paging.d.ts +34 -0
- package/dist/paging.js +41 -0
- package/dist/refuse.d.ts +11 -0
- package/dist/refuse.js +12 -0
- package/dist/resources/agents.d.ts +34 -0
- package/dist/resources/agents.js +33 -0
- package/dist/resources/assets.d.ts +59 -0
- package/dist/resources/assets.js +80 -0
- package/dist/resources/end-users.d.ts +73 -0
- package/dist/resources/end-users.js +139 -0
- package/dist/resources/ephemeral-keys.d.ts +65 -0
- package/dist/resources/ephemeral-keys.js +129 -0
- package/dist/resources/generations.d.ts +40 -0
- package/dist/resources/generations.js +55 -0
- package/dist/resources/knowledge.d.ts +58 -0
- package/dist/resources/knowledge.js +91 -0
- package/dist/resources/resource.d.ts +52 -0
- package/dist/resources/resource.js +68 -0
- package/dist/resources/speech.d.ts +80 -0
- package/dist/resources/speech.js +64 -0
- package/dist/resources/templates.d.ts +37 -0
- package/dist/resources/templates.js +50 -0
- package/dist/resources/usage.d.ts +15 -0
- package/dist/resources/usage.js +16 -0
- package/dist/resources/voices.d.ts +41 -0
- package/dist/resources/voices.js +53 -0
- package/dist/runtime.d.ts +22 -0
- package/dist/runtime.js +24 -0
- package/dist/stream.d.ts +6 -0
- package/dist/stream.js +37 -0
- package/dist/transport.d.ts +79 -0
- package/dist/transport.js +215 -0
- package/dist/upload.d.ts +37 -0
- package/dist/upload.js +34 -0
- package/dist/wait.d.ts +42 -0
- package/dist/wait.js +51 -0
- package/package.json +50 -4
package/dist/upload.js
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/** The data's size, when it can be told without reading it. */
|
|
2
|
+
export const sizeOf = (data, size) => size ??
|
|
3
|
+
(data instanceof ReadableStream
|
|
4
|
+
? undefined
|
|
5
|
+
: data instanceof Blob
|
|
6
|
+
? data.size
|
|
7
|
+
: data.byteLength);
|
|
8
|
+
/** The data's type: the caller's, or a Blob's own; `""` when neither says. */
|
|
9
|
+
export const typeOf = (data, type) => type || (data instanceof Blob ? data.type : "");
|
|
10
|
+
/** `type`, or a `TypeError` naming what to pass. */
|
|
11
|
+
export function needType(data, type) {
|
|
12
|
+
const found = typeOf(data, type);
|
|
13
|
+
if (!found)
|
|
14
|
+
throw new TypeError("This upload needs its content_type.");
|
|
15
|
+
return found;
|
|
16
|
+
}
|
|
17
|
+
/** The bytes, to a ticket's signed URL, valid for its `expires_in` seconds. */
|
|
18
|
+
export async function put(api, ticket, data, type, options) {
|
|
19
|
+
let raw = data;
|
|
20
|
+
const headers = {};
|
|
21
|
+
if (data instanceof ReadableStream) {
|
|
22
|
+
const size = options.size;
|
|
23
|
+
if (size === undefined) {
|
|
24
|
+
throw new TypeError("A stream uploads only with its size: { size }.");
|
|
25
|
+
}
|
|
26
|
+
headers["Content-Length"] = String(size);
|
|
27
|
+
// Workers' own class, read off the global: no other runtime has it,
|
|
28
|
+
// nor do the types a customer compiles against.
|
|
29
|
+
const { FixedLengthStream: Fixed } = globalThis;
|
|
30
|
+
if (Fixed)
|
|
31
|
+
raw = data.pipeThrough(new Fixed(size));
|
|
32
|
+
}
|
|
33
|
+
await api.request({ method: "PUT", path: ticket.url, raw, type, headers, open: true }, { ...options, timeoutMs: options.timeoutMs ?? ticket.expires_in * 1000 });
|
|
34
|
+
}
|
package/dist/wait.d.ts
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Waiting on a job: the API has no route for "a job" — each kind is read
|
|
3
|
+
* where it lives (a generation, a voice, an asset, a knowledge entry), and
|
|
4
|
+
* each says how it went in its `status`. `wait(id)` reads it until that
|
|
5
|
+
* status is no longer one of work in progress.
|
|
6
|
+
*
|
|
7
|
+
* - **One set of in-progress states for every kind**: a generation is
|
|
8
|
+
* `queued`, `submitted` or `running`, the rest `pending`, and a
|
|
9
|
+
* knowledge file or page `importing` before that — which the document
|
|
10
|
+
* does not list (left-overs #113; `STATUSES` in
|
|
11
|
+
* `apps/api/src/knowledge/service.ts`). Anything else — `succeeded`,
|
|
12
|
+
* `failed`, `moderated`, `ready`, or a state this release does not know
|
|
13
|
+
* — ends the wait, so a new one cannot hang a caller.
|
|
14
|
+
* - **It answers the last read, never throws for a failure**: a `failed`
|
|
15
|
+
* or `moderated` generation is refunded, and its `error` says why — the
|
|
16
|
+
* caller reads `status`, as the API's own docs say to.
|
|
17
|
+
* - **The polls**: 1 s, then ×1.5 each time, at most 10 s apart. The
|
|
18
|
+
* caller's `signal` ends the wait (`AbortSignal.timeout(…)` for a
|
|
19
|
+
* deadline); otherwise the job's own deadline does, which refunds what
|
|
20
|
+
* never reports (the API's `settlers.ts`).
|
|
21
|
+
* - **Its ceiling is the organisation's Durable Object, not a rate
|
|
22
|
+
* limit**: a poll is unmetered, so the per-minute window
|
|
23
|
+
* (`RATE_LIMIT_RPM`, the org's, which only metered routes count) never
|
|
24
|
+
* sees it (`admit` in `apps/api/src/org/object.ts`). Each poll is two
|
|
25
|
+
* calls on the org's DO — its admission and the read — so at the 10 s
|
|
26
|
+
* cap 2,500 waits at once are 500 calls a second, the DO's trigger in
|
|
27
|
+
* the root `CLAUDE.md`; in their first second, 250 are.
|
|
28
|
+
*/
|
|
29
|
+
import { type RequestOptions } from "./transport.js";
|
|
30
|
+
/**
|
|
31
|
+
* A job as each kind's read answers it: with a `status` — which the
|
|
32
|
+
* document lets an asset and an entry leave out (it has a default), and
|
|
33
|
+
* which, absent, is no work in progress.
|
|
34
|
+
*/
|
|
35
|
+
export interface Job {
|
|
36
|
+
status?: string;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Reads `read` until its status is final, starting from `first` (a job
|
|
40
|
+
* just made, so the first read waits) or with a read now.
|
|
41
|
+
*/
|
|
42
|
+
export declare function poll<T extends Job>(read: () => Promise<T>, options?: RequestOptions, first?: T): Promise<T>;
|
package/dist/wait.js
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Waiting on a job: the API has no route for "a job" — each kind is read
|
|
3
|
+
* where it lives (a generation, a voice, an asset, a knowledge entry), and
|
|
4
|
+
* each says how it went in its `status`. `wait(id)` reads it until that
|
|
5
|
+
* status is no longer one of work in progress.
|
|
6
|
+
*
|
|
7
|
+
* - **One set of in-progress states for every kind**: a generation is
|
|
8
|
+
* `queued`, `submitted` or `running`, the rest `pending`, and a
|
|
9
|
+
* knowledge file or page `importing` before that — which the document
|
|
10
|
+
* does not list (left-overs #113; `STATUSES` in
|
|
11
|
+
* `apps/api/src/knowledge/service.ts`). Anything else — `succeeded`,
|
|
12
|
+
* `failed`, `moderated`, `ready`, or a state this release does not know
|
|
13
|
+
* — ends the wait, so a new one cannot hang a caller.
|
|
14
|
+
* - **It answers the last read, never throws for a failure**: a `failed`
|
|
15
|
+
* or `moderated` generation is refunded, and its `error` says why — the
|
|
16
|
+
* caller reads `status`, as the API's own docs say to.
|
|
17
|
+
* - **The polls**: 1 s, then ×1.5 each time, at most 10 s apart. The
|
|
18
|
+
* caller's `signal` ends the wait (`AbortSignal.timeout(…)` for a
|
|
19
|
+
* deadline); otherwise the job's own deadline does, which refunds what
|
|
20
|
+
* never reports (the API's `settlers.ts`).
|
|
21
|
+
* - **Its ceiling is the organisation's Durable Object, not a rate
|
|
22
|
+
* limit**: a poll is unmetered, so the per-minute window
|
|
23
|
+
* (`RATE_LIMIT_RPM`, the org's, which only metered routes count) never
|
|
24
|
+
* sees it (`admit` in `apps/api/src/org/object.ts`). Each poll is two
|
|
25
|
+
* calls on the org's DO — its admission and the read — so at the 10 s
|
|
26
|
+
* cap 2,500 waits at once are 500 calls a second, the DO's trigger in
|
|
27
|
+
* the root `CLAUDE.md`; in their first second, 250 are.
|
|
28
|
+
*/
|
|
29
|
+
import { sleep } from "./transport.js";
|
|
30
|
+
const IN_PROGRESS = [
|
|
31
|
+
"queued",
|
|
32
|
+
"submitted",
|
|
33
|
+
"running",
|
|
34
|
+
"pending",
|
|
35
|
+
"importing",
|
|
36
|
+
];
|
|
37
|
+
const FIRST_MS = 1_000;
|
|
38
|
+
const MAX_MS = 10_000;
|
|
39
|
+
/**
|
|
40
|
+
* Reads `read` until its status is final, starting from `first` (a job
|
|
41
|
+
* just made, so the first read waits) or with a read now.
|
|
42
|
+
*/
|
|
43
|
+
export async function poll(read, options = {}, first) {
|
|
44
|
+
let job = first ?? (await read());
|
|
45
|
+
for (let ms = FIRST_MS; IN_PROGRESS.includes(job.status);) {
|
|
46
|
+
await sleep(ms, options.signal);
|
|
47
|
+
job = await read();
|
|
48
|
+
ms = Math.min(ms * 1.5, MAX_MS);
|
|
49
|
+
}
|
|
50
|
+
return job;
|
|
51
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,52 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lumavox/server",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "0.2.1",
|
|
4
|
+
"description": "The Lumavox API from your server: end users, ephemeral keys and the rest, typed from the published OpenAPI document. Zero dependencies.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"engines": {
|
|
8
|
+
"node": ">=20.3.0"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"dist"
|
|
12
|
+
],
|
|
13
|
+
"sideEffects": [
|
|
14
|
+
"./dist/refuse.js"
|
|
15
|
+
],
|
|
16
|
+
"exports": {
|
|
17
|
+
".": {
|
|
18
|
+
"types": "./dist/index.d.ts",
|
|
19
|
+
"workerd": "./dist/index.js",
|
|
20
|
+
"worker": "./dist/index.js",
|
|
21
|
+
"edge-light": "./dist/index.js",
|
|
22
|
+
"deno": "./dist/index.js",
|
|
23
|
+
"bun": "./dist/index.js",
|
|
24
|
+
"node": "./dist/index.js",
|
|
25
|
+
"react-native": "./dist/refuse.js",
|
|
26
|
+
"browser": "./dist/refuse.js",
|
|
27
|
+
"default": "./dist/index.js"
|
|
28
|
+
},
|
|
29
|
+
"./package.json": "./package.json"
|
|
30
|
+
},
|
|
31
|
+
"scripts": {
|
|
32
|
+
"generate": "openapi-ts",
|
|
33
|
+
"build": "node scripts/build.mjs",
|
|
34
|
+
"prepack": "node scripts/build.mjs",
|
|
35
|
+
"check": "biome check --write",
|
|
36
|
+
"format": "biome format --write",
|
|
37
|
+
"lint": "biome lint",
|
|
38
|
+
"test": "vitest run",
|
|
39
|
+
"test:unit": "vitest run",
|
|
40
|
+
"typecheck": "tsc --noEmit && tsc --noEmit -p test"
|
|
41
|
+
},
|
|
42
|
+
"devDependencies": {
|
|
43
|
+
"@biomejs/biome": "2.6.2",
|
|
44
|
+
"@cloudflare/vitest-plugin": "1.4.7",
|
|
45
|
+
"@cloudflare/workers-types": "^5.20261022.1",
|
|
46
|
+
"@hey-api/openapi-ts": "^0.99.0",
|
|
47
|
+
"@types/node": "^24",
|
|
48
|
+
"esbuild": "^0.28.1",
|
|
49
|
+
"typescript": "^6",
|
|
50
|
+
"vitest": "^4.1.12"
|
|
51
|
+
}
|
|
52
|
+
}
|