@lumavox/server 0.2.1 → 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.
- package/README.md +21 -16
- package/dist/errors.d.ts +24 -16
- package/dist/errors.js +21 -40
- package/dist/gen/index.d.ts +1 -1
- package/dist/gen/types.gen.d.ts +1767 -1750
- package/dist/index.d.ts +2 -1
- package/dist/paging.d.ts +19 -29
- package/dist/paging.js +17 -32
- package/dist/resources/agents.d.ts +10 -5
- package/dist/resources/agents.js +9 -3
- package/dist/resources/assets.d.ts +14 -9
- package/dist/resources/assets.js +16 -11
- package/dist/resources/end-users.d.ts +25 -18
- package/dist/resources/end-users.js +47 -43
- package/dist/resources/ephemeral-keys.d.ts +9 -9
- package/dist/resources/ephemeral-keys.js +9 -12
- package/dist/resources/generations.d.ts +3 -3
- package/dist/resources/generations.js +3 -7
- package/dist/resources/knowledge.d.ts +11 -12
- package/dist/resources/knowledge.js +8 -13
- package/dist/resources/resource.d.ts +12 -22
- package/dist/resources/resource.js +21 -4
- package/dist/resources/speech.d.ts +10 -21
- package/dist/resources/speech.js +4 -4
- package/dist/resources/templates.d.ts +4 -2
- package/dist/resources/templates.js +5 -1
- package/dist/resources/usage.d.ts +2 -2
- package/dist/resources/voices.d.ts +8 -6
- package/dist/resources/voices.js +8 -6
- package/dist/transport.d.ts +7 -3
- package/dist/transport.js +40 -19
- package/dist/upload.d.ts +7 -5
- package/dist/upload.js +8 -2
- package/dist/wait.d.ts +5 -9
- package/dist/wait.js +3 -3
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -5,8 +5,9 @@
|
|
|
5
5
|
* SDK's own options (`RequestOptions`) go in a last argument.
|
|
6
6
|
*/
|
|
7
7
|
export { type Client, type ClientOptions, createClient, DEFAULT_BASE_URL, } from "./client.js";
|
|
8
|
-
export { AuthenticationError, ConflictError, ConnectionError, InsufficientCreditsError, NotFoundError, PermissionError, PlatformError, type PlatformErrorInit, RateLimitError, ServerError, TimeoutError, ValidationError, } from "./errors.js";
|
|
8
|
+
export { AuthenticationError, ConflictError, ConnectionError, InsufficientCreditsError, NotFoundError, PermissionError, PlatformError, type PlatformErrorCode, type PlatformErrorInit, RateLimitError, ServerError, TimeoutError, ValidationError, } from "./errors.js";
|
|
9
9
|
export type * from "./gen/index.js";
|
|
10
|
+
export type { Page } from "./paging.js";
|
|
10
11
|
export type { AgentKnowledge, AgentSettings, Agents, } from "./resources/agents.js";
|
|
11
12
|
export type { AssetListParams, Assets, AssetUploadFields, FolderListParams, Folders, } from "./resources/assets.js";
|
|
12
13
|
export type { EndUserCreated, EndUserExport, EndUserListParams, EndUsers, } from "./resources/end-users.js";
|
package/dist/paging.d.ts
CHANGED
|
@@ -1,34 +1,24 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Paging as the API pages: every
|
|
3
|
-
*
|
|
4
|
-
*
|
|
2
|
+
* Paging as the API pages: every list answers one shape, `{data,
|
|
3
|
+
* next_cursor}`, asked for with `limit` and `cursor`, and `next_cursor` is
|
|
4
|
+
* `null` on the last page (`docs/history/wire.md`). So one iterator serves
|
|
5
|
+
* every list: each resource's `list()` is every item, page after page by
|
|
6
|
+
* cursor, and `page()` beside it is one page, as the route answers it.
|
|
5
7
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
* - **The backwards `next_before`** of a transcript, which only the
|
|
16
|
-
* export reads, by hand (`resources/end-users.ts`).
|
|
17
|
-
*
|
|
18
|
-
* A route that does not page (voices, agents, templates, a folder's
|
|
19
|
-
* level) has no iterator: its `list()` answers what the route does.
|
|
8
|
+
* - **Nothing is seen twice, nothing is counted**: the cursor is the
|
|
9
|
+
* store's own position, opaque, and no list says its total.
|
|
10
|
+
* - **A list bounded by nature** — agents, voices, templates, a folder's
|
|
11
|
+
* level — answers the same page with `next_cursor` always `null`, so its
|
|
12
|
+
* `list()` reads once; the day the route pages, it reads on without a
|
|
13
|
+
* change here.
|
|
14
|
+
* - **A list inside a resource** — a session's messages, which
|
|
15
|
+
* `endUsers.export` reads back to the start — pages by its own field's
|
|
16
|
+
* `next_cursor` (`resources/end-users.ts`).
|
|
20
17
|
*/
|
|
21
|
-
/** One page of
|
|
22
|
-
export interface
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
}
|
|
26
|
-
/** Every item, `limit` at a time from `offset`, until a short page or the total. */
|
|
27
|
-
export declare function byOffset<T>(read: (offset: number, limit: number) => Promise<OffsetPage<T>>, limit: number, offset?: number): AsyncGenerator<T, void, undefined>;
|
|
28
|
-
/** One page of a cursor-paged list: its items, and where the next one starts. */
|
|
29
|
-
export interface CursorPage<T> {
|
|
30
|
-
items: T[];
|
|
31
|
-
next?: string | null;
|
|
18
|
+
/** One page of any list: its items, and where the next starts — `null` on the last. */
|
|
19
|
+
export interface Page<T> {
|
|
20
|
+
data: T[];
|
|
21
|
+
next_cursor: string | null;
|
|
32
22
|
}
|
|
33
23
|
/** Every item, page after page, until a page names no next one. */
|
|
34
|
-
export declare function
|
|
24
|
+
export declare function pages<T>(read: (cursor: string | undefined) => Promise<Page<T>>): AsyncGenerator<T, void, undefined>;
|
package/dist/paging.js
CHANGED
|
@@ -1,41 +1,26 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Paging as the API pages: every
|
|
3
|
-
*
|
|
4
|
-
*
|
|
2
|
+
* Paging as the API pages: every list answers one shape, `{data,
|
|
3
|
+
* next_cursor}`, asked for with `limit` and `cursor`, and `next_cursor` is
|
|
4
|
+
* `null` on the last page (`docs/history/wire.md`). So one iterator serves
|
|
5
|
+
* every list: each resource's `list()` is every item, page after page by
|
|
6
|
+
* cursor, and `page()` beside it is one page, as the route answers it.
|
|
5
7
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
* - **The backwards `next_before`** of a transcript, which only the
|
|
16
|
-
* export reads, by hand (`resources/end-users.ts`).
|
|
17
|
-
*
|
|
18
|
-
* A route that does not page (voices, agents, templates, a folder's
|
|
19
|
-
* level) has no iterator: its `list()` answers what the route does.
|
|
8
|
+
* - **Nothing is seen twice, nothing is counted**: the cursor is the
|
|
9
|
+
* store's own position, opaque, and no list says its total.
|
|
10
|
+
* - **A list bounded by nature** — agents, voices, templates, a folder's
|
|
11
|
+
* level — answers the same page with `next_cursor` always `null`, so its
|
|
12
|
+
* `list()` reads once; the day the route pages, it reads on without a
|
|
13
|
+
* change here.
|
|
14
|
+
* - **A list inside a resource** — a session's messages, which
|
|
15
|
+
* `endUsers.export` reads back to the start — pages by its own field's
|
|
16
|
+
* `next_cursor` (`resources/end-users.ts`).
|
|
20
17
|
*/
|
|
21
|
-
/** Every item, `limit` at a time from `offset`, until a short page or the total. */
|
|
22
|
-
export async function* byOffset(read, limit, offset = 0) {
|
|
23
|
-
for (;;) {
|
|
24
|
-
const page = await read(offset, limit);
|
|
25
|
-
yield* page.items;
|
|
26
|
-
offset += page.items.length;
|
|
27
|
-
const last = page.items.length < limit ||
|
|
28
|
-
(page.total !== undefined && offset >= page.total);
|
|
29
|
-
if (last)
|
|
30
|
-
return;
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
18
|
/** Every item, page after page, until a page names no next one. */
|
|
34
|
-
export async function*
|
|
19
|
+
export async function* pages(read) {
|
|
35
20
|
let cursor;
|
|
36
21
|
do {
|
|
37
22
|
const page = await read(cursor);
|
|
38
|
-
yield* page.
|
|
39
|
-
cursor = page.
|
|
23
|
+
yield* page.data;
|
|
24
|
+
cursor = page.next_cursor ?? undefined;
|
|
40
25
|
} while (cursor);
|
|
41
26
|
}
|
|
@@ -8,9 +8,11 @@
|
|
|
8
8
|
* - **`settings`** are the organisation's, for every agent;
|
|
9
9
|
* **`knowledge.set`** replaces the entries one agent may look up.
|
|
10
10
|
* - **`create` is a 409 at the plan's maximum agents**; `delete` answers
|
|
11
|
-
*
|
|
11
|
+
* `true`, and `false` for one already gone.
|
|
12
|
+
* - **`list()` reads one page**: an organisation's agents are few, and the
|
|
13
|
+
* route answers them all with `next_cursor` `null` (`paging.ts`).
|
|
12
14
|
*/
|
|
13
|
-
import type { AgentCreateRequest, AgentInfo,
|
|
15
|
+
import type { AgentCreateRequest, AgentInfo, AgentKnowledgeUpdate, AgentPage, AgentSettingsInfo, AgentSettingsUpdate, AgentSummary, AgentUpdate, KnowledgeAssigned, KnowledgeInfo } from "../gen/index.js";
|
|
14
16
|
import type { RequestOptions, Transport } from "../transport.js";
|
|
15
17
|
import { Editable } from "./resource.js";
|
|
16
18
|
/** `agents.settings`: the organisation's, for every agent. */
|
|
@@ -20,15 +22,18 @@ export interface AgentSettings {
|
|
|
20
22
|
}
|
|
21
23
|
/** `agents.knowledge`: the entries one agent may look up. */
|
|
22
24
|
export interface AgentKnowledge {
|
|
23
|
-
|
|
25
|
+
/** Every entry it may look up. */
|
|
26
|
+
list(agentId: string, options?: RequestOptions): AsyncGenerator<KnowledgeInfo, void, undefined>;
|
|
24
27
|
/** Replaces them all with these. */
|
|
25
|
-
set(agentId: string, body:
|
|
28
|
+
set(agentId: string, body: AgentKnowledgeUpdate, options?: RequestOptions): Promise<KnowledgeAssigned>;
|
|
26
29
|
}
|
|
27
30
|
export declare class Agents extends Editable<AgentInfo, AgentUpdate> {
|
|
28
31
|
readonly settings: AgentSettings;
|
|
29
32
|
readonly knowledge: AgentKnowledge;
|
|
30
33
|
constructor(api: Transport, base: string);
|
|
34
|
+
/** The page of agents, as the route answers it. */
|
|
35
|
+
page(options?: RequestOptions): Promise<AgentPage>;
|
|
31
36
|
/** Every agent. */
|
|
32
|
-
list(options?: RequestOptions):
|
|
37
|
+
list(options?: RequestOptions): AsyncGenerator<AgentSummary, void, undefined>;
|
|
33
38
|
create(body: AgentCreateRequest, options?: RequestOptions): Promise<AgentInfo>;
|
|
34
39
|
}
|
package/dist/resources/agents.js
CHANGED
|
@@ -8,7 +8,9 @@
|
|
|
8
8
|
* - **`settings`** are the organisation's, for every agent;
|
|
9
9
|
* **`knowledge.set`** replaces the entries one agent may look up.
|
|
10
10
|
* - **`create` is a 409 at the plan's maximum agents**; `delete` answers
|
|
11
|
-
*
|
|
11
|
+
* `true`, and `false` for one already gone.
|
|
12
|
+
* - **`list()` reads one page**: an organisation's agents are few, and the
|
|
13
|
+
* route answers them all with `next_cursor` `null` (`paging.ts`).
|
|
12
14
|
*/
|
|
13
15
|
import { Editable } from "./resource.js";
|
|
14
16
|
export class Agents extends Editable {
|
|
@@ -19,13 +21,17 @@ export class Agents extends Editable {
|
|
|
19
21
|
update: (body, options) => this.send("PUT", "/settings", options, body),
|
|
20
22
|
};
|
|
21
23
|
this.knowledge = {
|
|
22
|
-
list: (id, options) => this.
|
|
24
|
+
list: (id, options) => this.each(this.at(id, "/knowledge"), {}, options),
|
|
23
25
|
set: (id, body, options) => this.send("PUT", this.at(id, "/knowledge"), options, body),
|
|
24
26
|
};
|
|
25
27
|
}
|
|
28
|
+
/** The page of agents, as the route answers it. */
|
|
29
|
+
page(options) {
|
|
30
|
+
return this.send("GET", "", options);
|
|
31
|
+
}
|
|
26
32
|
/** Every agent. */
|
|
27
33
|
list(options) {
|
|
28
|
-
return this.
|
|
34
|
+
return this.each("", {}, options);
|
|
29
35
|
}
|
|
30
36
|
create(body, options) {
|
|
31
37
|
return this.send("POST", "", options, body);
|
|
@@ -9,17 +9,18 @@
|
|
|
9
9
|
* `failed`. A transcription of one still `pending` is a 409.
|
|
10
10
|
* - **`upload(data, fields)`** is the ticket, the `PUT` and the confirm
|
|
11
11
|
* in one (`upload.ts`).
|
|
12
|
-
* - **`delete`
|
|
13
|
-
* `move` answer how many they touched
|
|
12
|
+
* - **`delete` answers `true`**, and `false` for one already gone: done.
|
|
13
|
+
* `deleteMany` and `move` answer how many they touched; a folder's
|
|
14
|
+
* `delete` how many it moved up a level, and `null` for one gone.
|
|
14
15
|
* - **`list()` pages by cursor**, 200 a page; a folder's `list()` is one
|
|
15
|
-
* level,
|
|
16
|
+
* level, which the route answers in one page.
|
|
16
17
|
*/
|
|
17
|
-
import type { AssetBulkRequest,
|
|
18
|
+
import type { AssetBulkRequest, AssetDetail, AssetMoveRequest, AssetPage, AssetSummary, AssetsAffected, AssetUpdate, FolderCreate, FolderDeleted, FolderDetail, FolderPage, FolderSummary, FolderUpdate, ListAssetFoldersData, ListAssetsData, UploadConfirm, UploadTicket, UploadTicketRequest } from "../gen/index.js";
|
|
18
19
|
import type { RequestOptions, Transport } from "../transport.js";
|
|
19
20
|
import { type UploadData, type UploadOptions } from "../upload.js";
|
|
20
21
|
import { Editable, Waitable } from "./resource.js";
|
|
21
22
|
export type AssetListParams = NonNullable<ListAssetsData["query"]>;
|
|
22
|
-
export type FolderListParams = NonNullable<
|
|
23
|
+
export type FolderListParams = NonNullable<ListAssetFoldersData["query"]>;
|
|
23
24
|
/** A file's place in the library: the confirm's fields, and its type. */
|
|
24
25
|
export type AssetUploadFields = Omit<UploadConfirm, "asset_id" | "content_type"> & {
|
|
25
26
|
/** A Blob's own type by default. */
|
|
@@ -30,16 +31,20 @@ export type AssetUploadFields = Omit<UploadConfirm, "asset_id" | "content_type">
|
|
|
30
31
|
* counts and ancestors; `update` renames it or moves it under another;
|
|
31
32
|
* `delete` moves what it held up a level.
|
|
32
33
|
*/
|
|
33
|
-
export declare class Folders extends Editable<FolderDetail, FolderUpdate, FolderSummary, FolderDeleted> {
|
|
34
|
-
/** One level
|
|
35
|
-
|
|
34
|
+
export declare class Folders extends Editable<FolderDetail, FolderUpdate, FolderSummary, FolderDeleted | null> {
|
|
35
|
+
/** One level — the top, or `parent_id`'s children — as the route answers it. */
|
|
36
|
+
page(params?: FolderListParams, options?: RequestOptions): Promise<FolderPage>;
|
|
37
|
+
/** Every folder of one level: the top, or `parent_id`'s children. */
|
|
38
|
+
list(params?: FolderListParams, options?: RequestOptions): AsyncGenerator<FolderSummary, void, undefined>;
|
|
39
|
+
/** Deletes it, moving what it held up a level: how many moved, or `null` when there is none. */
|
|
40
|
+
delete(id: string, options?: RequestOptions): Promise<FolderDeleted | null>;
|
|
36
41
|
create(body: FolderCreate, options?: RequestOptions): Promise<FolderSummary>;
|
|
37
42
|
}
|
|
38
43
|
/**
|
|
39
44
|
* `update` renames an asset or files it in a folder; `delete` deletes it
|
|
40
45
|
* and its files.
|
|
41
46
|
*/
|
|
42
|
-
export declare class Assets extends Waitable<AssetDetail, AssetUpdate
|
|
47
|
+
export declare class Assets extends Waitable<AssetDetail, AssetUpdate> {
|
|
43
48
|
readonly folders: Folders;
|
|
44
49
|
constructor(api: Transport, base: string);
|
|
45
50
|
/** One page, with the `next_cursor` of the next. */
|
package/dist/resources/assets.js
CHANGED
|
@@ -9,15 +9,15 @@
|
|
|
9
9
|
* `failed`. A transcription of one still `pending` is a 409.
|
|
10
10
|
* - **`upload(data, fields)`** is the ticket, the `PUT` and the confirm
|
|
11
11
|
* in one (`upload.ts`).
|
|
12
|
-
* - **`delete`
|
|
13
|
-
* `move` answer how many they touched
|
|
12
|
+
* - **`delete` answers `true`**, and `false` for one already gone: done.
|
|
13
|
+
* `deleteMany` and `move` answer how many they touched; a folder's
|
|
14
|
+
* `delete` how many it moved up a level, and `null` for one gone.
|
|
14
15
|
* - **`list()` pages by cursor**, 200 a page; a folder's `list()` is one
|
|
15
|
-
* level,
|
|
16
|
+
* level, which the route answers in one page.
|
|
16
17
|
*/
|
|
17
|
-
import { byCursor } from "../paging.js";
|
|
18
18
|
import { needType, put, } from "../upload.js";
|
|
19
19
|
import { Editable, Waitable } from "./resource.js";
|
|
20
|
-
/** The route's
|
|
20
|
+
/** The route's largest page. */
|
|
21
21
|
const PAGE = 200;
|
|
22
22
|
/**
|
|
23
23
|
* `assets.folders`: the library's tree. `get` answers a folder with its
|
|
@@ -25,10 +25,18 @@ const PAGE = 200;
|
|
|
25
25
|
* `delete` moves what it held up a level.
|
|
26
26
|
*/
|
|
27
27
|
export class Folders extends Editable {
|
|
28
|
-
/** One level
|
|
29
|
-
|
|
28
|
+
/** One level — the top, or `parent_id`'s children — as the route answers it. */
|
|
29
|
+
page(params = {}, options) {
|
|
30
30
|
return this.send("GET", "", options, params);
|
|
31
31
|
}
|
|
32
|
+
/** Every folder of one level: the top, or `parent_id`'s children. */
|
|
33
|
+
list(params = {}, options) {
|
|
34
|
+
return this.each("", params, options);
|
|
35
|
+
}
|
|
36
|
+
/** Deletes it, moving what it held up a level: how many moved, or `null` when there is none. */
|
|
37
|
+
delete(id, options) {
|
|
38
|
+
return this.drop(id, options);
|
|
39
|
+
}
|
|
32
40
|
create(body, options) {
|
|
33
41
|
return this.send("POST", "", options, body);
|
|
34
42
|
}
|
|
@@ -48,10 +56,7 @@ export class Assets extends Waitable {
|
|
|
48
56
|
}
|
|
49
57
|
/** Every asset the filter matches, page after page (200 a page by default). */
|
|
50
58
|
list(params = {}, options) {
|
|
51
|
-
return
|
|
52
|
-
const page = await this.page({ limit: PAGE, ...params, cursor }, options);
|
|
53
|
-
return { items: page.assets, next: page.next_cursor };
|
|
54
|
-
});
|
|
59
|
+
return this.each("", params, options, PAGE);
|
|
55
60
|
}
|
|
56
61
|
/** A signed URL to `PUT` a file to, with exactly this type. */
|
|
57
62
|
uploadUrl(body, options) {
|
|
@@ -20,19 +20,21 @@
|
|
|
20
20
|
* their own, since their conversations and facts are their end user DO's
|
|
21
21
|
* and an API key cannot read them (`/v1/agent/*` takes only an ephemeral
|
|
22
22
|
* key): it mints a five-minute key for them, lists their sessions (200 a
|
|
23
|
-
* page), reads each transcript
|
|
24
|
-
* sessions at a time), reads their facts, and
|
|
25
|
-
* `finally` — after an abort or a failure too. The
|
|
26
|
-
* `limits()` when cold) + ⌈S/200⌉ lists + Σ⌈M/200⌉
|
|
27
|
-
* facts read + one revoke. **Its ceilings**: the
|
|
28
|
-
* the person's live-key cap or the plan's mint rate
|
|
29
|
-
* the mint does (422, 429) and can be retried once a
|
|
30
|
-
* five minutes, so a history that takes longer to
|
|
31
|
-
* its one micro-credit is set aside like any key's,
|
|
32
|
-
* with no balance cannot export (402); and the facts
|
|
33
|
-
*
|
|
23
|
+
* page), reads each transcript back to its start by `messages.next_cursor`
|
|
24
|
+
* (200 messages a page, four sessions at a time), reads their facts, and
|
|
25
|
+
* revokes the key in `finally` — after an abort or a failure too. The
|
|
26
|
+
* cost: one mint (and `limits()` when cold) + ⌈S/200⌉ lists + Σ⌈M/200⌉
|
|
27
|
+
* transcript pages + one facts read + one revoke. **Its ceilings**: the
|
|
28
|
+
* key is ordinary, so at the person's live-key cap or the plan's mint rate
|
|
29
|
+
* the export fails as the mint does (422, 429) and can be retried once a
|
|
30
|
+
* key lapses; it lives five minutes, so a history that takes longer to
|
|
31
|
+
* read fails with a 401; its one micro-credit is set aside like any key's,
|
|
32
|
+
* so an organisation with no balance cannot export (402); and the facts
|
|
33
|
+
* route answers the newest 100 in one page until it pages (left-overs
|
|
34
|
+
* #109) — read here by its cursor, so the day it does, the export has
|
|
35
|
+
* them all.
|
|
34
36
|
*/
|
|
35
|
-
import type { EndUserCreateRequest, EndUserDeleted, EndUserInfo,
|
|
37
|
+
import type { EndUserCreateRequest, EndUserDeleted, EndUserInfo, EndUserPage, EndUserUpdateRequest, FactInfo, ListEndUsersData, SessionDetail } from "../gen/index.js";
|
|
36
38
|
import { type RequestOptions, type Transport } from "../transport.js";
|
|
37
39
|
import type { EphemeralKeys } from "./ephemeral-keys.js";
|
|
38
40
|
import { Editable } from "./resource.js";
|
|
@@ -50,12 +52,15 @@ export type EndUserCreated = EndUserInfo & {
|
|
|
50
52
|
export interface EndUserExport {
|
|
51
53
|
/** Their `eu_…` id. */
|
|
52
54
|
end_user_id: string;
|
|
53
|
-
/**
|
|
55
|
+
/**
|
|
56
|
+
* Every conversation, most recent first, each with every message,
|
|
57
|
+
* oldest first, in its one page of `messages` (`next_cursor` `null`).
|
|
58
|
+
*/
|
|
54
59
|
sessions: SessionDetail[];
|
|
55
|
-
/** What is remembered about them, oldest first — the
|
|
60
|
+
/** What is remembered about them, oldest first — the newest 100 for now. */
|
|
56
61
|
facts: FactInfo[];
|
|
57
62
|
}
|
|
58
|
-
export declare class EndUsers extends Editable<EndUserInfo, EndUserUpdateRequest, EndUserInfo, EndUserDeleted> {
|
|
63
|
+
export declare class EndUsers extends Editable<EndUserInfo, EndUserUpdateRequest, EndUserInfo, EndUserDeleted | null> {
|
|
59
64
|
private readonly keys;
|
|
60
65
|
constructor(api: Transport, base: string, keys: EphemeralKeys);
|
|
61
66
|
/**
|
|
@@ -64,10 +69,12 @@ export declare class EndUsers extends Editable<EndUserInfo, EndUserUpdateRequest
|
|
|
64
69
|
* existing `external_id` is answered as ever).
|
|
65
70
|
*/
|
|
66
71
|
create(body?: EndUserCreateRequest, options?: RequestOptions): Promise<EndUserCreated>;
|
|
67
|
-
/** One page, newest first, with the `
|
|
68
|
-
page(params?: EndUserListParams, options?: RequestOptions): Promise<
|
|
72
|
+
/** One page, newest first, with the `next_cursor` of the next. */
|
|
73
|
+
page(params?: EndUserListParams, options?: RequestOptions): Promise<EndUserPage>;
|
|
69
74
|
/** Every person, newest first, page after page (`limit` a page, 200 by default). */
|
|
70
|
-
list(params?: Omit<EndUserListParams, "
|
|
75
|
+
list(params?: Omit<EndUserListParams, "cursor">, options?: RequestOptions): AsyncGenerator<EndUserInfo, void, undefined>;
|
|
76
|
+
/** Deletes them and all they had: the counts, or `null` when there is no such person. */
|
|
77
|
+
delete(id: string, options?: RequestOptions): Promise<EndUserDeleted | null>;
|
|
71
78
|
/** Everything about one person, read with a key of their own (see the header). */
|
|
72
79
|
export(id: string, options?: RequestOptions): Promise<EndUserExport>;
|
|
73
80
|
}
|
|
@@ -20,28 +20,37 @@
|
|
|
20
20
|
* their own, since their conversations and facts are their end user DO's
|
|
21
21
|
* and an API key cannot read them (`/v1/agent/*` takes only an ephemeral
|
|
22
22
|
* key): it mints a five-minute key for them, lists their sessions (200 a
|
|
23
|
-
* page), reads each transcript
|
|
24
|
-
* sessions at a time), reads their facts, and
|
|
25
|
-
* `finally` — after an abort or a failure too. The
|
|
26
|
-
* `limits()` when cold) + ⌈S/200⌉ lists + Σ⌈M/200⌉
|
|
27
|
-
* facts read + one revoke. **Its ceilings**: the
|
|
28
|
-
* the person's live-key cap or the plan's mint rate
|
|
29
|
-
* the mint does (422, 429) and can be retried once a
|
|
30
|
-
* five minutes, so a history that takes longer to
|
|
31
|
-
* its one micro-credit is set aside like any key's,
|
|
32
|
-
* with no balance cannot export (402); and the facts
|
|
33
|
-
*
|
|
23
|
+
* page), reads each transcript back to its start by `messages.next_cursor`
|
|
24
|
+
* (200 messages a page, four sessions at a time), reads their facts, and
|
|
25
|
+
* revokes the key in `finally` — after an abort or a failure too. The
|
|
26
|
+
* cost: one mint (and `limits()` when cold) + ⌈S/200⌉ lists + Σ⌈M/200⌉
|
|
27
|
+
* transcript pages + one facts read + one revoke. **Its ceilings**: the
|
|
28
|
+
* key is ordinary, so at the person's live-key cap or the plan's mint rate
|
|
29
|
+
* the export fails as the mint does (422, 429) and can be retried once a
|
|
30
|
+
* key lapses; it lives five minutes, so a history that takes longer to
|
|
31
|
+
* read fails with a 401; its one micro-credit is set aside like any key's,
|
|
32
|
+
* so an organisation with no balance cannot export (402); and the facts
|
|
33
|
+
* route answers the newest 100 in one page until it pages (left-overs
|
|
34
|
+
* #109) — read here by its cursor, so the day it does, the export has
|
|
35
|
+
* them all.
|
|
34
36
|
*/
|
|
35
|
-
import {
|
|
37
|
+
import { pages } from "../paging.js";
|
|
36
38
|
import { segment, } from "../transport.js";
|
|
37
39
|
import { Editable } from "./resource.js";
|
|
38
|
-
/** The routes'
|
|
40
|
+
/** The routes' largest page, for end users, sessions and transcripts alike. */
|
|
39
41
|
const PAGE = 200;
|
|
40
42
|
/** The export key's lifetime and limit: the shortest useful, the least set aside. */
|
|
41
43
|
const EXPORT_TTL_S = 300;
|
|
42
|
-
const
|
|
44
|
+
const EXPORT_CREDIT_MICROS = 1;
|
|
43
45
|
/** Transcripts read at once. */
|
|
44
46
|
const EXPORT_PARALLEL = 4;
|
|
47
|
+
/** Every item of `items`, in an array. */
|
|
48
|
+
async function all(items) {
|
|
49
|
+
const out = [];
|
|
50
|
+
for await (const item of items)
|
|
51
|
+
out.push(item);
|
|
52
|
+
return out;
|
|
53
|
+
}
|
|
45
54
|
/** `work` over every item, `width` at a time, answers in the items' order. */
|
|
46
55
|
async function inParallel(items, width, work) {
|
|
47
56
|
const out = new Array(items.length);
|
|
@@ -75,22 +84,23 @@ export class EndUsers extends Editable {
|
|
|
75
84
|
}, options);
|
|
76
85
|
return { ...answer.data, created: answer.status === 201 };
|
|
77
86
|
}
|
|
78
|
-
/** One page, newest first, with the `
|
|
87
|
+
/** One page, newest first, with the `next_cursor` of the next. */
|
|
79
88
|
page(params = {}, options) {
|
|
80
89
|
return this.send("GET", "", options, params);
|
|
81
90
|
}
|
|
82
91
|
/** Every person, newest first, page after page (`limit` a page, 200 by default). */
|
|
83
92
|
list(params = {}, options) {
|
|
84
|
-
return
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
93
|
+
return this.each("", params, options, PAGE);
|
|
94
|
+
}
|
|
95
|
+
/** Deletes them and all they had: the counts, or `null` when there is no such person. */
|
|
96
|
+
delete(id, options) {
|
|
97
|
+
return this.drop(id, options);
|
|
88
98
|
}
|
|
89
99
|
/** Everything about one person, read with a key of their own (see the header). */
|
|
90
100
|
async export(id, options = {}) {
|
|
91
101
|
const key = await this.keys.create({
|
|
92
102
|
end_user_id: id,
|
|
93
|
-
|
|
103
|
+
credit_limit_micros: EXPORT_CREDIT_MICROS,
|
|
94
104
|
expires_in_seconds: EXPORT_TTL_S,
|
|
95
105
|
label: "export",
|
|
96
106
|
}, options);
|
|
@@ -99,33 +109,27 @@ export class EndUsers extends Editable {
|
|
|
99
109
|
const read = (path, query) => this.api
|
|
100
110
|
.request({ method: "GET", path, query, token: key.key }, options)
|
|
101
111
|
.then((answer) => answer.data);
|
|
102
|
-
const listed =
|
|
103
|
-
for await (const session of byOffset(async (offset, limit) => ({
|
|
104
|
-
items: await read("/v1/agent/sessions", {
|
|
105
|
-
offset,
|
|
106
|
-
limit,
|
|
107
|
-
}),
|
|
108
|
-
}), PAGE)) {
|
|
109
|
-
listed.push(session);
|
|
110
|
-
}
|
|
112
|
+
const listed = await all(pages((cursor) => read("/v1/agent/sessions", { limit: PAGE, cursor })));
|
|
111
113
|
const sessions = await inParallel(listed, EXPORT_PARALLEL, async (s) => {
|
|
112
|
-
const
|
|
113
|
-
|
|
114
|
+
const page = (cursor) => read(`/v1/agent/sessions/${segment(s.id)}`, {
|
|
115
|
+
limit: PAGE,
|
|
116
|
+
cursor,
|
|
117
|
+
});
|
|
118
|
+
// The newest messages first; each older page goes before them.
|
|
114
119
|
const newest = await page();
|
|
115
|
-
const
|
|
116
|
-
for (let
|
|
117
|
-
const older = await page(
|
|
118
|
-
|
|
119
|
-
|
|
120
|
+
const held = [newest.messages.data];
|
|
121
|
+
for (let cursor = newest.messages.next_cursor; cursor;) {
|
|
122
|
+
const older = (await page(cursor)).messages;
|
|
123
|
+
held.unshift(older.data);
|
|
124
|
+
cursor = older.next_cursor;
|
|
120
125
|
}
|
|
121
|
-
return {
|
|
126
|
+
return {
|
|
127
|
+
...newest,
|
|
128
|
+
messages: { data: held.flat(), next_cursor: null },
|
|
129
|
+
};
|
|
122
130
|
});
|
|
123
|
-
const facts = await read("/v1/agent/facts");
|
|
124
|
-
return {
|
|
125
|
-
end_user_id: key.end_user_id ?? facts.end_user_id,
|
|
126
|
-
sessions,
|
|
127
|
-
facts: facts.facts,
|
|
128
|
-
};
|
|
131
|
+
const facts = await all(pages((cursor) => read("/v1/agent/facts", { cursor })));
|
|
132
|
+
return { end_user_id: key.end_user_id ?? id, sessions, facts };
|
|
129
133
|
}
|
|
130
134
|
finally {
|
|
131
135
|
// Without the caller's signal: an aborted export still revokes.
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
* `client.ephemeralKeys`: the keys an end user's device talks to agents
|
|
3
3
|
* with — `/v1/ephemeral-keys*` and `/v1/token`.
|
|
4
4
|
*
|
|
5
|
-
* - **A key is prepaid**: its `
|
|
6
|
-
* when it is minted (402 when it cannot be), and what it does not spend
|
|
5
|
+
* - **A key is prepaid**: its `credit_limit_micros` is set aside from the
|
|
6
|
+
* balance when it is minted (402 when it cannot be), and what it does not spend
|
|
7
7
|
* comes back when it settles.
|
|
8
8
|
* - **`create` clamps the lifetime by default** to the platform's maximum,
|
|
9
9
|
* read from `limits()` — which the API never does: past a cap is a 422
|
|
@@ -17,10 +17,10 @@
|
|
|
17
17
|
* (`apps/api/src/org/areas/keys.ts` `revokeEphemeral`). Waiting for the
|
|
18
18
|
* final figures needs the key's read route (left-overs #106).
|
|
19
19
|
* - **`inspect` reads a key as itself** (`GET /v1/token` with that key).
|
|
20
|
-
* Its `
|
|
20
|
+
* Its `credits_spent_micros` moves only when the key settles — at the end, or
|
|
21
21
|
* daily — so a live key reads as unspent (left-overs #105).
|
|
22
22
|
*/
|
|
23
|
-
import type { EphemeralKeyCreateRequest, EphemeralKeyCreateResponse, EphemeralKeyInfo, EphemeralKeyLimits, EphemeralTokenSelf, ListEphemeralKeysData } from "../gen/index.js";
|
|
23
|
+
import type { EphemeralKeyCreateRequest, EphemeralKeyCreateResponse, EphemeralKeyInfo, EphemeralKeyLimits, EphemeralKeyPage, EphemeralTokenSelf, ListEphemeralKeysData } from "../gen/index.js";
|
|
24
24
|
import { type RequestOptions } from "../transport.js";
|
|
25
25
|
import { Resource } from "./resource.js";
|
|
26
26
|
export type EphemeralKeyListParams = NonNullable<ListEphemeralKeysData["query"]>;
|
|
@@ -43,7 +43,7 @@ export declare class EphemeralKeys extends Resource {
|
|
|
43
43
|
/**
|
|
44
44
|
* Mints a key for one end user — returned **once**, as `key`. Scopes
|
|
45
45
|
* are exactly `["agent"]` (the default). 402 when the balance cannot set
|
|
46
|
-
* `
|
|
46
|
+
* `credit_limit_micros` aside, 422 past a cap, 429 past the plan's mints a
|
|
47
47
|
* minute (retried after its `Retry-After`).
|
|
48
48
|
*/
|
|
49
49
|
create(body: EphemeralKeyCreateRequest, options?: EphemeralKeyCreateOptions): Promise<EphemeralKeyCreateResponse>;
|
|
@@ -58,8 +58,8 @@ export declare class EphemeralKeys extends Resource {
|
|
|
58
58
|
* when the key is refused — expired, revoked, spent or not a key.
|
|
59
59
|
*/
|
|
60
60
|
inspect(key: string, options?: RequestOptions): Promise<EphemeralTokenSelf | null>;
|
|
61
|
-
/** One page of this organisation's keys: live ones unless `live_only` is `false`. */
|
|
62
|
-
page(params?: EphemeralKeyListParams, options?: RequestOptions): Promise<
|
|
63
|
-
/** Every key, page after page (`limit` a page,
|
|
64
|
-
list(params?: Omit<EphemeralKeyListParams, "
|
|
61
|
+
/** One page of this organisation's keys, newest first: live ones unless `live_only` is `false`. */
|
|
62
|
+
page(params?: EphemeralKeyListParams, options?: RequestOptions): Promise<EphemeralKeyPage>;
|
|
63
|
+
/** Every key, page after page (`limit` a page, 200 by default). */
|
|
64
|
+
list(params?: Omit<EphemeralKeyListParams, "cursor">, options?: RequestOptions): AsyncGenerator<EphemeralKeyInfo, void, undefined>;
|
|
65
65
|
}
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
* `client.ephemeralKeys`: the keys an end user's device talks to agents
|
|
3
3
|
* with — `/v1/ephemeral-keys*` and `/v1/token`.
|
|
4
4
|
*
|
|
5
|
-
* - **A key is prepaid**: its `
|
|
6
|
-
* when it is minted (402 when it cannot be), and what it does not spend
|
|
5
|
+
* - **A key is prepaid**: its `credit_limit_micros` is set aside from the
|
|
6
|
+
* balance when it is minted (402 when it cannot be), and what it does not spend
|
|
7
7
|
* comes back when it settles.
|
|
8
8
|
* - **`create` clamps the lifetime by default** to the platform's maximum,
|
|
9
9
|
* read from `limits()` — which the API never does: past a cap is a 422
|
|
@@ -17,16 +17,15 @@
|
|
|
17
17
|
* (`apps/api/src/org/areas/keys.ts` `revokeEphemeral`). Waiting for the
|
|
18
18
|
* final figures needs the key's read route (left-overs #106).
|
|
19
19
|
* - **`inspect` reads a key as itself** (`GET /v1/token` with that key).
|
|
20
|
-
* Its `
|
|
20
|
+
* Its `credits_spent_micros` moves only when the key settles — at the end, or
|
|
21
21
|
* daily — so a live key reads as unspent (left-overs #105).
|
|
22
22
|
*/
|
|
23
23
|
import { AuthenticationError } from "../errors.js";
|
|
24
|
-
import { byOffset } from "../paging.js";
|
|
25
24
|
import { orNull } from "../transport.js";
|
|
26
25
|
import { Resource } from "./resource.js";
|
|
27
26
|
const LIMITS_TTL_MS = 5 * 60_000;
|
|
28
|
-
/** The route's
|
|
29
|
-
const PAGE =
|
|
27
|
+
/** The route's largest page. */
|
|
28
|
+
const PAGE = 200;
|
|
30
29
|
/** `promise`, or the signal's reason when it aborts first. */
|
|
31
30
|
function until(promise, signal) {
|
|
32
31
|
if (!signal)
|
|
@@ -72,7 +71,7 @@ export class EphemeralKeys extends Resource {
|
|
|
72
71
|
/**
|
|
73
72
|
* Mints a key for one end user — returned **once**, as `key`. Scopes
|
|
74
73
|
* are exactly `["agent"]` (the default). 402 when the balance cannot set
|
|
75
|
-
* `
|
|
74
|
+
* `credit_limit_micros` aside, 422 past a cap, 429 past the plan's mints a
|
|
76
75
|
* minute (retried after its `Retry-After`).
|
|
77
76
|
*/
|
|
78
77
|
async create(body, options = {}) {
|
|
@@ -116,14 +115,12 @@ export class EphemeralKeys extends Resource {
|
|
|
116
115
|
}
|
|
117
116
|
return self;
|
|
118
117
|
}
|
|
119
|
-
/** One page of this organisation's keys: live ones unless `live_only` is `false`. */
|
|
118
|
+
/** One page of this organisation's keys, newest first: live ones unless `live_only` is `false`. */
|
|
120
119
|
page(params = {}, options) {
|
|
121
120
|
return this.send("GET", "", options, params);
|
|
122
121
|
}
|
|
123
|
-
/** Every key, page after page (`limit` a page,
|
|
122
|
+
/** Every key, page after page (`limit` a page, 200 by default). */
|
|
124
123
|
list(params = {}, options) {
|
|
125
|
-
return
|
|
126
|
-
items: await this.page({ ...params, offset, limit }, options),
|
|
127
|
-
}), params.limit ?? PAGE);
|
|
124
|
+
return this.each("", params, options, PAGE);
|
|
128
125
|
}
|
|
129
126
|
}
|