@lumavox/server 0.2.2 → 0.4.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.
@@ -15,7 +15,7 @@
15
15
  * - **Each read sees its own capability**: an image's id is a 404 on
16
16
  * `videos.get`. `generations.get` reads any the key may generate.
17
17
  */
18
- import type { GenerationInfo, GenerationPage, ListGenerationsData, SkyboxStyle } from "../gen/index.js";
18
+ import type { GenerationInfo, GenerationPage, ListGenerationsData, SkyboxStylePage } from "../gen/index.js";
19
19
  import type { RequestOptions } from "../transport.js";
20
20
  import { Polled } from "./resource.js";
21
21
  export type GenerationListParams = NonNullable<ListGenerationsData["query"]>;
@@ -28,8 +28,8 @@ export declare class Jobs<Body> extends Polled<GenerationInfo> {
28
28
  }
29
29
  /** `/v1/skybox`, and the provider's styles. */
30
30
  export declare class Skybox<Body> extends Jobs<Body> {
31
- /** The styles available now, each with its `style_id`; empty when the provider is unreachable. */
32
- styles(options?: RequestOptions): Promise<SkyboxStyle[]>;
31
+ /** The styles available now, in one page: each `id` is a `style_id`; none when the provider is unreachable. */
32
+ styles(options?: RequestOptions): Promise<SkyboxStylePage>;
33
33
  }
34
34
  /** Every generation the key may make, read-only. */
35
35
  export declare class Generations extends Polled<GenerationInfo> {
@@ -15,10 +15,9 @@
15
15
  * - **Each read sees its own capability**: an image's id is a 404 on
16
16
  * `videos.get`. `generations.get` reads any the key may generate.
17
17
  */
18
- import { byCursor } from "../paging.js";
19
18
  import { poll } from "../wait.js";
20
19
  import { Polled } from "./resource.js";
21
- /** The route's own page bound. */
20
+ /** The route's largest page. */
22
21
  const PAGE = 100;
23
22
  /** One capability's queue: `/v1/images`, `/v1/videos`, … */
24
23
  export class Jobs extends Polled {
@@ -34,7 +33,7 @@ export class Jobs extends Polled {
34
33
  }
35
34
  /** `/v1/skybox`, and the provider's styles. */
36
35
  export class Skybox extends Jobs {
37
- /** The styles available now, each with its `style_id`; empty when the provider is unreachable. */
36
+ /** The styles available now, in one page: each `id` is a `style_id`; none when the provider is unreachable. */
38
37
  styles(options) {
39
38
  return this.send("GET", "/styles", options);
40
39
  }
@@ -47,9 +46,6 @@ export class Generations extends Polled {
47
46
  }
48
47
  /** Every generation, newest first, page after page (100 a page by default). */
49
48
  list(params = {}, options) {
50
- return byCursor(async (cursor) => {
51
- const page = await this.page({ limit: PAGE, ...params, cursor }, options);
52
- return { items: page.generations, next: page.next_cursor };
53
- });
49
+ return this.each("", params, options, PAGE);
54
50
  }
55
51
  }
@@ -10,27 +10,26 @@
10
10
  * - **`upload(file, fields)`** is the ticket, the `PUT` and `fromFile` in
11
11
  * one (`upload.ts`); the file's extension says how it is read, 10 MB at
12
12
  * most.
13
- * - **`list()` pages by offset**, 200 a page, with the `total` the filter
14
- * matches.
13
+ * - **`list()` pages by cursor**, 200 a page.
15
14
  * - **`update` with `expected_version`** refuses an edit made over
16
- * somebody else's (409); `delete` answers the entry as it was, and
17
- * `null` for one already gone.
15
+ * somebody else's (409); `delete` answers `true`, and `false` for one
16
+ * already gone.
18
17
  */
19
- import type { KnowledgeAssigned, KnowledgeAssignment, KnowledgeBulk, KnowledgeBulkResult, KnowledgeCategories, KnowledgeCreate, KnowledgeFileCreate, KnowledgeInfo, KnowledgeInsights, KnowledgeInsightsData, KnowledgeSearchList, KnowledgeSearchRequest, KnowledgeSearchResult, KnowledgeUpdate, KnowledgeUploadRequest, KnowledgeUploadTicket, KnowledgeUrlCreate, ListKnowledgeData } from "../gen/index.js";
18
+ import type { GetKnowledgeInsightsData, KnowledgeAgentsUpdate, KnowledgeAssigned, KnowledgeBulk, KnowledgeBulkResult, KnowledgeCategoryPage, KnowledgeCreate, KnowledgeFileCreate, KnowledgeInfo, KnowledgeInsights, KnowledgePage, KnowledgeSearchRequest, KnowledgeSearchResult, KnowledgeUpdate, KnowledgeUploadRequest, KnowledgeUploadTicket, KnowledgeUrlCreate, ListKnowledgeData } from "../gen/index.js";
20
19
  import type { RequestOptions } from "../transport.js";
21
20
  import { type UploadData, type UploadOptions } from "../upload.js";
22
21
  import { Waitable } from "./resource.js";
23
22
  export type KnowledgeListParams = NonNullable<ListKnowledgeData["query"]>;
24
- export type KnowledgeInsightsParams = NonNullable<KnowledgeInsightsData["query"]>;
23
+ export type KnowledgeInsightsParams = NonNullable<GetKnowledgeInsightsData["query"]>;
25
24
  /** A file's entry: `fromFile`'s fields, and its type when not its extension's. */
26
25
  export type KnowledgeUploadFields = Omit<KnowledgeFileCreate, "upload_id"> & {
27
26
  content_type?: string | null;
28
27
  };
29
28
  export declare class Knowledge extends Waitable<KnowledgeInfo, KnowledgeUpdate> {
30
- /** One page, with the `total` the filter matches. */
31
- page(params?: KnowledgeListParams, options?: RequestOptions): Promise<KnowledgeSearchList>;
29
+ /** One page, with the `next_cursor` of the next. */
30
+ page(params?: KnowledgeListParams, options?: RequestOptions): Promise<KnowledgePage>;
32
31
  /** Every entry the filter matches, page after page (200 a page by default). */
33
- list(params?: Omit<KnowledgeListParams, "offset">, options?: RequestOptions): AsyncGenerator<KnowledgeInfo, void, undefined>;
32
+ list(params?: Omit<KnowledgeListParams, "cursor">, options?: RequestOptions): AsyncGenerator<KnowledgeInfo, void, undefined>;
34
33
  /** A written entry, indexed after it is saved. */
35
34
  create(body: KnowledgeCreate, options?: RequestOptions): Promise<KnowledgeInfo>;
36
35
  /** Many written entries at once: what was made, and what was refused. */
@@ -48,11 +47,11 @@ export declare class Knowledge extends Waitable<KnowledgeInfo, KnowledgeUpdate>
48
47
  /** Reads its page again now. */
49
48
  refresh(id: string, options?: RequestOptions): Promise<KnowledgeInfo>;
50
49
  /** Replaces the agents that may look it up. */
51
- setAgents(id: string, body: KnowledgeAssignment, options?: RequestOptions): Promise<KnowledgeAssigned>;
50
+ setAgents(id: string, body: KnowledgeAgentsUpdate, options?: RequestOptions): Promise<KnowledgeAssigned>;
52
51
  /** What an agent would find for a question. */
53
52
  search(body: KnowledgeSearchRequest, options?: RequestOptions): Promise<KnowledgeSearchResult>;
54
- /** The categories in use. */
55
- categories(options?: RequestOptions): Promise<KnowledgeCategories>;
53
+ /** The categories in use, in one page. */
54
+ categories(options?: RequestOptions): Promise<KnowledgeCategoryPage>;
56
55
  /** What was looked up, and what went unanswered: 7 days by default. */
57
56
  insights(params?: KnowledgeInsightsParams, options?: RequestOptions): Promise<KnowledgeInsights>;
58
57
  }
@@ -10,28 +10,23 @@
10
10
  * - **`upload(file, fields)`** is the ticket, the `PUT` and `fromFile` in
11
11
  * one (`upload.ts`); the file's extension says how it is read, 10 MB at
12
12
  * most.
13
- * - **`list()` pages by offset**, 200 a page, with the `total` the filter
14
- * matches.
13
+ * - **`list()` pages by cursor**, 200 a page.
15
14
  * - **`update` with `expected_version`** refuses an edit made over
16
- * somebody else's (409); `delete` answers the entry as it was, and
17
- * `null` for one already gone.
15
+ * somebody else's (409); `delete` answers `true`, and `false` for one
16
+ * already gone.
18
17
  */
19
- import { byOffset } from "../paging.js";
20
18
  import { put, sizeOf, typeOf, } from "../upload.js";
21
19
  import { Waitable } from "./resource.js";
22
- /** The route's own page bound. */
20
+ /** The route's largest page. */
23
21
  const PAGE = 200;
24
22
  export class Knowledge extends Waitable {
25
- /** One page, with the `total` the filter matches. */
23
+ /** One page, with the `next_cursor` of the next. */
26
24
  page(params = {}, options) {
27
25
  return this.send("GET", "", options, params);
28
26
  }
29
27
  /** Every entry the filter matches, page after page (200 a page by default). */
30
28
  list(params = {}, options) {
31
- return byOffset(async (offset, limit) => {
32
- const page = await this.page({ ...params, offset, limit }, options);
33
- return { items: page.entries, total: page.total };
34
- }, params.limit ?? PAGE);
29
+ return this.each("", params, options, PAGE);
35
30
  }
36
31
  /** A written entry, indexed after it is saved. */
37
32
  create(body, options) {
@@ -58,7 +53,7 @@ export class Knowledge extends Waitable {
58
53
  const { content_type, ...body } = fields;
59
54
  const ticket = await this.uploadUrl({
60
55
  filename: body.filename,
61
- size: sizeOf(file, options.size) ?? null,
56
+ size_bytes: sizeOf(file, options.size) ?? null,
62
57
  content_type: typeOf(file, content_type) || null,
63
58
  }, options);
64
59
  await put(this.api, ticket, file, ticket.content_type, options);
@@ -80,7 +75,7 @@ export class Knowledge extends Waitable {
80
75
  search(body, options) {
81
76
  return this.send("POST", "/search", options, body);
82
77
  }
83
- /** The categories in use. */
78
+ /** The categories in use, in one page. */
84
79
  categories(options) {
85
80
  return this.send("GET", "/categories", options);
86
81
  }
@@ -1,21 +1,3 @@
1
- /**
2
- * What every resource shares, as a ladder of bases each method is written
3
- * once in — the SDK's size is a budget (`test/dist.test.ts`):
4
- *
5
- * - **`Resource`**: the transport, and the path its routes start with.
6
- * `send` takes the rest of the path, and `at(id)` is one item's, the id
7
- * encoded (an id the caller holds may carry `/` or `?`).
8
- * - **`Readable`**: `get(id)`; **`Polled`** adds `wait(id)` (`wait.ts`),
9
- * for a generation, which is read and waited on and nothing else.
10
- * - **`Editable`**: `update(id, body)` (`PATCH`) and `delete(id)`, which
11
- * answers `null` when there is nothing by that id — already done.
12
- * - **`Waitable`**: an editable whose items are jobs — a voice, an asset,
13
- * a knowledge entry — with `wait(id)` and `settled`, which an upload
14
- * answers through.
15
- *
16
- * Fields are `declare`d, not defined: each is assigned in a constructor,
17
- * and a definition is bytes in every customer's bundle.
18
- */
19
1
  import { type Method, type RequestOptions, type Transport } from "../transport.js";
20
2
  import type { UploadOptions } from "../upload.js";
21
3
  import { type Job } from "../wait.js";
@@ -27,6 +9,12 @@ export declare class Resource {
27
9
  protected send<T>(method: Method, rest: string, options?: RequestOptions, data?: unknown): Promise<T>;
28
10
  /** The rest of item `id`'s path, and of what follows it. */
29
11
  protected at(id: string, rest?: string): string;
12
+ /**
13
+ * Every item of the list at `base` + `rest`, page after page: `query`,
14
+ * then each page's cursor. `limit` is the route's largest page unless
15
+ * the query names one — fewer calls for a long list.
16
+ */
17
+ protected each<T>(rest: string, query?: object, options?: RequestOptions, limit?: number): AsyncGenerator<T, void, undefined>;
30
18
  }
31
19
  export declare class Readable<Item> extends Resource {
32
20
  /** One of them. A `NotFoundError` when there is none. */
@@ -36,15 +24,17 @@ export declare class Polled<Item extends Job> extends Readable<Item> {
36
24
  /** Reads it until its `status` is final (`wait.ts`). */
37
25
  wait(id: string, options?: RequestOptions): Promise<Item>;
38
26
  }
39
- export declare class Editable<Item, Update, Updated = Item, Deleted = Item> extends Readable<Item> {
27
+ export declare class Editable<Item, Update, Updated = Item, Deleted = boolean> extends Readable<Item> {
40
28
  /** Changes what `body` gives; absent fields are untouched. */
41
29
  update(id: string, body: Update, options?: RequestOptions): Promise<Updated>;
42
- /** Deletes it; `null` when there is none by that id — already done. */
43
- delete(id: string, options?: RequestOptions): Promise<Deleted | null>;
30
+ /** Deletes it: `true`, or `false` when there is none by that id — already done. */
31
+ delete(id: string, options?: RequestOptions): Promise<Deleted>;
32
+ /** The `DELETE` itself: its answer, `undefined` for a 204, `null` for a 404. */
33
+ protected drop<T>(id: string, options?: RequestOptions): Promise<T | null>;
44
34
  }
45
35
  export declare class Waitable<Item extends Job & {
46
36
  id: string;
47
- }, Update, Updated = Item, Deleted = Item> extends Editable<Item, Update, Updated, Deleted> {
37
+ }, Update, Updated = Item> extends Editable<Item, Update, Updated> {
48
38
  /** Reads it until its `status` is final (`wait.ts`). */
49
39
  wait(id: string, options?: RequestOptions): Promise<Item>;
50
40
  /** `item` as made, or as it ended when `options.wait` says to wait. */
@@ -4,11 +4,15 @@
4
4
  *
5
5
  * - **`Resource`**: the transport, and the path its routes start with.
6
6
  * `send` takes the rest of the path, and `at(id)` is one item's, the id
7
- * encoded (an id the caller holds may carry `/` or `?`).
7
+ * encoded (an id the caller holds may carry `/` or `?`). `each` is a
8
+ * list's every item, page after page (`paging.ts`).
8
9
  * - **`Readable`**: `get(id)`; **`Polled`** adds `wait(id)` (`wait.ts`),
9
10
  * for a generation, which is read and waited on and nothing else.
10
- * - **`Editable`**: `update(id, body)` (`PATCH`) and `delete(id)`, which
11
- * answers `null` when there is nothing by that id — already done.
11
+ * - **`Editable`**: `update(id, body)` (`PATCH`) and `delete(id)`. A
12
+ * delete of one thing is a 204 with no body, so it answers `true`, and
13
+ * `false` when there is nothing by that id — already done. One that
14
+ * reports what went with it (an end user's, a folder's) answers those
15
+ * counts, and `null` for nothing by that id: the same rule, with a body.
12
16
  * - **`Waitable`**: an editable whose items are jobs — a voice, an asset,
13
17
  * a knowledge entry — with `wait(id)` and `settled`, which an upload
14
18
  * answers through.
@@ -16,6 +20,7 @@
16
20
  * Fields are `declare`d, not defined: each is assigned in a constructor,
17
21
  * and a definition is bytes in every customer's bundle.
18
22
  */
23
+ import { pages } from "../paging.js";
19
24
  import { orNull, segment, } from "../transport.js";
20
25
  import { poll } from "../wait.js";
21
26
  export class Resource {
@@ -31,6 +36,14 @@ export class Resource {
31
36
  at(id, rest = "") {
32
37
  return `/${segment(id)}${rest}`;
33
38
  }
39
+ /**
40
+ * Every item of the list at `base` + `rest`, page after page: `query`,
41
+ * then each page's cursor. `limit` is the route's largest page unless
42
+ * the query names one — fewer calls for a long list.
43
+ */
44
+ each(rest, query, options, limit) {
45
+ return pages((cursor) => this.send("GET", rest, options, { limit, ...query, cursor }));
46
+ }
34
47
  }
35
48
  export class Readable extends Resource {
36
49
  /** One of them. A `NotFoundError` when there is none. */
@@ -49,8 +62,12 @@ export class Editable extends Readable {
49
62
  update(id, body, options) {
50
63
  return this.send("PATCH", this.at(id), options, body);
51
64
  }
52
- /** Deletes it; `null` when there is none by that id — already done. */
65
+ /** Deletes it: `true`, or `false` when there is none by that id — already done. */
53
66
  delete(id, options) {
67
+ return this.drop(id, options).then((gone) => gone !== null);
68
+ }
69
+ /** The `DELETE` itself: its answer, `undefined` for a 204, `null` for a 404. */
70
+ drop(id, options) {
54
71
  return orNull(this.send("DELETE", this.at(id), options));
55
72
  }
56
73
  }
@@ -6,10 +6,10 @@
6
6
  *
7
7
  * - **`tts.create(body)` answers the audio whole** (an `ArrayBuffer`, WAV
8
8
  * or raw `pcm`) **or, with `stream: true`, as it is made** (a
9
- * `ReadableStream` of `pcm`), beside what its headers say. A whole
10
- * answer names its sample rate (`X-Sample-Rate`); a stream names none,
11
- * so its rate is the one asked for, 24 000 Hz unset (the API's default,
12
- * `@ino/core/speech/catalog`; left-overs #111).
9
+ * `ReadableStream` of `pcm`), beside what its headers say. Both name
10
+ * their sample rate (`X-Sample-Rate`); a stream from an API before
11
+ * 0.31.10 named none, so without the header its rate is the one asked
12
+ * for, 24 000 Hz unset (the API's default, `@ino/core/speech/catalog`).
13
13
  * - **`stt.create(audio, params)` sends the audio as the body**, the
14
14
  * options as the query — the route's raw form, which a stream can be
15
15
  * sent as, unlike a multipart one. It answers the transcript, or with
@@ -17,7 +17,7 @@
17
17
  * only). Up to 25 MB.
18
18
  * - **A stream's timeout ends at its headers**; `signal` still ends it.
19
19
  */
20
- import type { StreamDone, StreamError, StreamSegment, StreamTranscript, TranscribeData, TranscriptWord, TtsRequest } from "../gen/index.js";
20
+ import type { TranscribeData, Transcription, TranscriptionStreamLine, TtsRequest } from "../gen/index.js";
21
21
  import type { RequestOptions } from "../transport.js";
22
22
  import { type UploadData } from "../upload.js";
23
23
  import { Resource } from "./resource.js";
@@ -51,23 +51,12 @@ export type SttParams = Omit<TranscribeData["body"], "file"> & {
51
51
  content_type?: string;
52
52
  };
53
53
  /**
54
- * `POST /v1/stt`'s whole answer. The document declares no schema for it
55
- * (left-overs #112), so this is the route's own (`transcript()` in
56
- * `apps/api/src/routes/stt.ts`), written out; `apps/api/test/sdk.test.ts`
57
- * holds the two together.
54
+ * `POST /v1/stt`'s whole answer, as the document declares it since api
55
+ * 0.31.10 (`Transcription`). The name the SDK has always exported.
58
56
  */
59
- export interface Transcript {
60
- text: string;
61
- language_code: string | null;
62
- language_probability: number | null;
63
- /** What was charged, per minute. */
64
- duration_seconds: number;
65
- model: string;
66
- /** With `timestamps: true`; `null` otherwise. */
67
- words: TranscriptWord[] | null;
68
- }
69
- /** One line of a streamed transcript. */
70
- export type SttEvent = StreamSegment | StreamTranscript | StreamError | StreamDone;
57
+ export type Transcript = Transcription;
58
+ /** One line of a streamed transcript: a `segment`, its `transcript` or `error`, and the `done`. */
59
+ export type SttEvent = TranscriptionStreamLine;
71
60
  export declare class Stt extends Resource {
72
61
  /** The transcript as it is made: an iterator of its events. */
73
62
  create(audio: UploadData, params: SttParams & {
@@ -6,10 +6,10 @@
6
6
  *
7
7
  * - **`tts.create(body)` answers the audio whole** (an `ArrayBuffer`, WAV
8
8
  * or raw `pcm`) **or, with `stream: true`, as it is made** (a
9
- * `ReadableStream` of `pcm`), beside what its headers say. A whole
10
- * answer names its sample rate (`X-Sample-Rate`); a stream names none,
11
- * so its rate is the one asked for, 24 000 Hz unset (the API's default,
12
- * `@ino/core/speech/catalog`; left-overs #111).
9
+ * `ReadableStream` of `pcm`), beside what its headers say. Both name
10
+ * their sample rate (`X-Sample-Rate`); a stream from an API before
11
+ * 0.31.10 named none, so without the header its rate is the one asked
12
+ * for, 24 000 Hz unset (the API's default, `@ino/core/speech/catalog`).
13
13
  * - **`stt.create(audio, params)` sends the audio as the body**, the
14
14
  * options as the query — the route's raw form, which a stream can be
15
15
  * sent as, unlike a multipart one. It answers the transcript, or with
@@ -11,7 +11,7 @@
11
11
  * - **`file(id, name)` needs no key** and answers the bytes; a template's
12
12
  * URLs already name each file and its `v`, which makes it cacheable.
13
13
  */
14
- import type { GenerationInfo, TemplateGenerateRequest, TemplateInfo, TemplateList } from "../gen/index.js";
14
+ import type { GenerationInfo, TemplateGenerateRequest, TemplateInfo, TemplatePage } from "../gen/index.js";
15
15
  import { type RequestOptions, type Transport } from "../transport.js";
16
16
  import type { Generations } from "./generations.js";
17
17
  import { Readable } from "./resource.js";
@@ -24,8 +24,10 @@ export interface TemplateFile {
24
24
  export declare class Templates extends Readable<TemplateInfo> {
25
25
  private readonly generations;
26
26
  constructor(api: Transport, base: string, generations: Generations);
27
+ /** The page of templates, as the route answers it: all of them, `next_cursor` `null`. */
28
+ page(options?: RequestOptions): Promise<TemplatePage>;
27
29
  /** Every template this organisation may generate from. */
28
- list(options?: RequestOptions): Promise<TemplateList>;
30
+ list(options?: RequestOptions): AsyncGenerator<TemplateInfo, void, undefined>;
29
31
  /** Generates from it, charged when accepted: the `gen_…` at once. */
30
32
  create(id: string, body?: TemplateGenerateRequest, options?: RequestOptions): Promise<GenerationInfo>;
31
33
  /** Generates from it and waits: the generation once it is final. */
@@ -20,9 +20,13 @@ export class Templates extends Readable {
20
20
  super(api, base);
21
21
  this.generations = generations;
22
22
  }
23
+ /** The page of templates, as the route answers it: all of them, `next_cursor` `null`. */
24
+ page(options) {
25
+ return this.send("GET", "", options);
26
+ }
23
27
  /** Every template this organisation may generate from. */
24
28
  list(options) {
25
- return this.send("GET", "", options);
29
+ return this.each("", {}, options);
26
30
  }
27
31
  /** Generates from it, charged when accepted: the `gen_…` at once. */
28
32
  create(id, body = {}, options) {
@@ -3,10 +3,10 @@
3
3
  * window of days, and `GET /v1/plan`, its plan and balance (`null` with
4
4
  * no subscription). Read-only, unmetered.
5
5
  */
6
- import type { OrgPlan, UsageData, UsageResponse } from "../gen/index.js";
6
+ import type { GetUsageData, OrgPlan, UsageResponse } from "../gen/index.js";
7
7
  import type { RequestOptions } from "../transport.js";
8
8
  import { Resource } from "./resource.js";
9
- export type UsageParams = NonNullable<UsageData["query"]>;
9
+ export type UsageParams = NonNullable<GetUsageData["query"]>;
10
10
  export declare class Usage extends Resource {
11
11
  /** Requests and seconds by capability, by day and by key: 30 days by default. */
12
12
  get(params?: UsageParams, options?: RequestOptions): Promise<UsageResponse>;
@@ -9,9 +9,11 @@
9
9
  * create in one (`upload.ts`); `consent: true` says you may clone it.
10
10
  * - **`design(body)` answers previews, not a voice**: keep one with
11
11
  * `saveDesign`. It is a provider call held open, and charged.
12
- * - **`delete` answers `false` when there was no such voice**: done.
12
+ * - **`delete` answers `true`**, and `false` when there was no such
13
+ * voice: done.
14
+ * - **`list()` reads one page**: the route answers every voice in it.
13
15
  */
14
- import type { VoiceDesignRequest, VoiceDesignResult, VoiceDesignSaveRequest, VoiceDetail, VoiceInfo, VoiceUpdate, VoiceUpload, VoiceUploadRequest, VoiceUploadTicket } from "../gen/index.js";
16
+ import type { VoiceDesignRequest, VoiceDesignResult, VoiceDesignSaveRequest, VoiceDetail, VoiceInfo, VoiceInfoPage, VoiceUpdate, VoiceUpload, VoiceUploadRequest, VoiceUploadTicket } from "../gen/index.js";
15
17
  import type { RequestOptions } from "../transport.js";
16
18
  import { type UploadData, type UploadOptions } from "../upload.js";
17
19
  import { Waitable } from "./resource.js";
@@ -21,17 +23,17 @@ export type VoiceUploadFields = Omit<VoiceUpload, "upload_id"> & {
21
23
  content_type?: string;
22
24
  };
23
25
  /** `update` renames a voice, or changes its description or defaults. */
24
- export declare class Voices extends Waitable<VoiceDetail, VoiceUpdate, VoiceDetail, boolean> {
26
+ export declare class Voices extends Waitable<VoiceDetail, VoiceUpdate> {
27
+ /** The page of voices, as the route answers it: all of them, `next_cursor` `null`. */
28
+ page(options?: RequestOptions): Promise<VoiceInfoPage>;
25
29
  /** Every voice this organisation may speak with. */
26
- list(options?: RequestOptions): Promise<VoiceInfo[]>;
30
+ list(options?: RequestOptions): AsyncGenerator<VoiceInfo, void, undefined>;
27
31
  /** Clones a recording already `PUT` to its ticket: `pending` at once. */
28
32
  create(body: VoiceUpload, options?: RequestOptions): Promise<VoiceDetail>;
29
33
  /** A signed URL to `PUT` a recording to, with exactly this type. */
30
34
  uploadUrl(body: VoiceUploadRequest, options?: RequestOptions): Promise<VoiceUploadTicket>;
31
35
  /** Uploads a recording and clones it: `uploadUrl`, the `PUT`, `create`. */
32
36
  upload(recording: UploadData, fields: VoiceUploadFields, options?: UploadOptions): Promise<VoiceDetail>;
33
- /** Deletes it: `true`, or `false` when there was none by that id (a 204 has no body). */
34
- delete(id: string, options?: RequestOptions): Promise<boolean>;
35
37
  /** Speaks its samples again, one per model. */
36
38
  resample(id: string, options?: RequestOptions): Promise<VoiceDetail>;
37
39
  /** Previews of a voice made from a description; charged. */
@@ -9,15 +9,21 @@
9
9
  * create in one (`upload.ts`); `consent: true` says you may clone it.
10
10
  * - **`design(body)` answers previews, not a voice**: keep one with
11
11
  * `saveDesign`. It is a provider call held open, and charged.
12
- * - **`delete` answers `false` when there was no such voice**: done.
12
+ * - **`delete` answers `true`**, and `false` when there was no such
13
+ * voice: done.
14
+ * - **`list()` reads one page**: the route answers every voice in it.
13
15
  */
14
16
  import { needType, put, } from "../upload.js";
15
17
  import { Waitable } from "./resource.js";
16
18
  /** `update` renames a voice, or changes its description or defaults. */
17
19
  export class Voices extends Waitable {
20
+ /** The page of voices, as the route answers it: all of them, `next_cursor` `null`. */
21
+ page(options) {
22
+ return this.send("GET", "", options);
23
+ }
18
24
  /** Every voice this organisation may speak with. */
19
25
  list(options) {
20
- return this.send("GET", "", options);
26
+ return this.each("", {}, options);
21
27
  }
22
28
  /** Clones a recording already `PUT` to its ticket: `pending` at once. */
23
29
  create(body, options) {
@@ -34,10 +40,6 @@ export class Voices extends Waitable {
34
40
  await put(this.api, ticket, recording, ticket.content_type, options);
35
41
  return this.settled(await this.create({ ...body, upload_id: ticket.upload_id }, options), options);
36
42
  }
37
- /** Deletes it: `true`, or `false` when there was none by that id (a 204 has no body). */
38
- async delete(id, options) {
39
- return (await super.delete(id, options)) !== null;
40
- }
41
43
  /** Speaks its samples again, one per model. */
42
44
  resample(id, options) {
43
45
  return this.send("POST", this.at(id, "/sample"), options);
package/dist/transport.js CHANGED
@@ -84,7 +84,7 @@ export function parsed(text, status, requestId) {
84
84
  catch (cause) {
85
85
  throw new PlatformError({
86
86
  status,
87
- type: "invalid_response",
87
+ code: "invalid_response",
88
88
  message: `HTTP ${status} with a body that is not JSON.`,
89
89
  requestId,
90
90
  cause,
@@ -163,13 +163,13 @@ export class Transport {
163
163
  throw outcome.kind === "timeout"
164
164
  ? new TimeoutError({
165
165
  status: 0,
166
- type: "timeout",
166
+ code: "timeout",
167
167
  message: "The API did not answer in time.",
168
168
  requestId,
169
169
  })
170
170
  : new ConnectionError({
171
171
  status: 0,
172
- type: "connection_error",
172
+ code: "connection_error",
173
173
  message: "Could not reach the API.",
174
174
  requestId,
175
175
  cause: outcome.error,
package/dist/upload.d.ts CHANGED
@@ -6,9 +6,11 @@
6
6
  *
7
7
  * - **The `PUT` carries no credential** — the URL is signed — and exactly
8
8
  * the `Content-Type` the ticket was asked for, which is signed into it.
9
- * - **Its timer is the ticket's lifetime** unless the caller sets one: the
10
- * URL is refused after it anyway, and a large file on a slow link is not
11
- * a call that timed out at the client's 30 s — and then sent twice more.
9
+ * - **Its timer runs to the ticket's `expires_at`** unless the caller sets
10
+ * one: the URL is refused after it anyway, and a large file on a slow
11
+ * link is not a call that timed out at the client's 30 s — and then sent
12
+ * twice more. A minute at least: the instant is the API's clock, and a
13
+ * machine whose clock runs ahead would otherwise time out at once.
12
14
  * - **A Blob, an ArrayBuffer or a typed array; a stream only with its
13
15
  * `size`**: a signed `PUT` needs `Content-Length`, which a stream cannot
14
16
  * say. On Workers the stream goes through `FixedLengthStream`, which is
@@ -30,8 +32,8 @@ export declare const sizeOf: (data: UploadData, size?: number) => number | undef
30
32
  export declare const typeOf: (data: UploadData, type?: string | null) => string;
31
33
  /** `type`, or a `TypeError` naming what to pass. */
32
34
  export declare function needType(data: UploadData, type?: string | null): string;
33
- /** The bytes, to a ticket's signed URL, valid for its `expires_in` seconds. */
35
+ /** The bytes, to a ticket's signed URL, valid until its `expires_at`. */
34
36
  export declare function put(api: Transport, ticket: {
35
37
  url: string;
36
- expires_in: number;
38
+ expires_at: string;
37
39
  }, data: UploadData, type: string, options: UploadOptions): Promise<void>;
package/dist/upload.js CHANGED
@@ -14,7 +14,9 @@ export function needType(data, type) {
14
14
  throw new TypeError("This upload needs its content_type.");
15
15
  return found;
16
16
  }
17
- /** The bytes, to a ticket's signed URL, valid for its `expires_in` seconds. */
17
+ /** The least time a `PUT` is given, whatever the ticket's clock says. */
18
+ const MIN_PUT_MS = 60_000;
19
+ /** The bytes, to a ticket's signed URL, valid until its `expires_at`. */
18
20
  export async function put(api, ticket, data, type, options) {
19
21
  let raw = data;
20
22
  const headers = {};
@@ -30,5 +32,9 @@ export async function put(api, ticket, data, type, options) {
30
32
  if (Fixed)
31
33
  raw = data.pipeThrough(new Fixed(size));
32
34
  }
33
- await api.request({ method: "PUT", path: ticket.url, raw, type, headers, open: true }, { ...options, timeoutMs: options.timeoutMs ?? ticket.expires_in * 1000 });
35
+ await api.request({ method: "PUT", path: ticket.url, raw, type, headers, open: true }, {
36
+ ...options,
37
+ timeoutMs: options.timeoutMs ??
38
+ Math.max(Date.parse(ticket.expires_at) - Date.now(), MIN_PUT_MS),
39
+ });
34
40
  }
package/dist/wait.d.ts CHANGED
@@ -6,9 +6,9 @@
6
6
  *
7
7
  * - **One set of in-progress states for every kind**: a generation is
8
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`,
9
+ * knowledge file or page `importing` before that (`STATUSES` in
10
+ * `apps/api/src/knowledge/service.ts`), which the document lists only
11
+ * since api 0.31.10. Anything else — `succeeded`,
12
12
  * `failed`, `moderated`, `ready`, or a state this release does not know
13
13
  * — ends the wait, so a new one cannot hang a caller.
14
14
  * - **It answers the last read, never throws for a failure**: a `failed`
@@ -27,13 +27,9 @@
27
27
  * the root `CLAUDE.md`; in their first second, 250 are.
28
28
  */
29
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
- */
30
+ /** A job as each kind's read answers it: with its `status`. */
35
31
  export interface Job {
36
- status?: string;
32
+ status: string;
37
33
  }
38
34
  /**
39
35
  * Reads `read` until its status is final, starting from `first` (a job
package/dist/wait.js CHANGED
@@ -6,9 +6,9 @@
6
6
  *
7
7
  * - **One set of in-progress states for every kind**: a generation is
8
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`,
9
+ * knowledge file or page `importing` before that (`STATUSES` in
10
+ * `apps/api/src/knowledge/service.ts`), which the document lists only
11
+ * since api 0.31.10. Anything else — `succeeded`,
12
12
  * `failed`, `moderated`, `ready`, or a state this release does not know
13
13
  * — ends the wait, so a new one cannot hang a caller.
14
14
  * - **It answers the last read, never throws for a failure**: a `failed`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lumavox/server",
3
- "version": "0.2.2",
3
+ "version": "0.4.0",
4
4
  "description": "The Lumavox API from your server: end users, ephemeral keys and the rest, typed from the published OpenAPI document. Zero dependencies.",
5
5
  "license": "MIT",
6
6
  "type": "module",