@relaymessenger/chat-sdk-adapter 0.2.1 → 0.3.0-staging.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 +3 -3
- package/README.md +185 -98
- package/dist/adapter.d.ts +121 -0
- package/dist/adapter.d.ts.map +1 -0
- package/dist/adapter.js +643 -0
- package/dist/adapter.js.map +1 -0
- package/dist/client.d.ts +64 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +230 -0
- package/dist/client.js.map +1 -0
- package/dist/content.d.ts +11 -0
- package/dist/content.d.ts.map +1 -0
- package/dist/content.js +172 -0
- package/dist/content.js.map +1 -0
- package/dist/credentials.d.ts +13 -0
- package/dist/credentials.d.ts.map +1 -0
- package/dist/credentials.js +28 -0
- package/dist/credentials.js.map +1 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +10 -0
- package/dist/index.js.map +1 -0
- package/dist/reactions.d.ts +15 -0
- package/dist/reactions.d.ts.map +1 -0
- package/dist/reactions.js +58 -0
- package/dist/reactions.js.map +1 -0
- package/dist/signature.d.ts +22 -0
- package/dist/signature.d.ts.map +1 -0
- package/dist/signature.js +98 -0
- package/dist/signature.js.map +1 -0
- package/dist/thread-id.d.ts +8 -0
- package/dist/thread-id.d.ts.map +1 -0
- package/dist/thread-id.js +27 -0
- package/dist/thread-id.js.map +1 -0
- package/dist/turn.d.ts +16 -0
- package/dist/turn.d.ts.map +1 -0
- package/dist/turn.js +22 -0
- package/dist/turn.js.map +1 -0
- package/dist/types.d.ts +177 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +27 -0
- package/dist/types.js.map +1 -0
- package/dist/webhook.d.ts +9 -0
- package/dist/webhook.d.ts.map +1 -0
- package/dist/webhook.js +115 -0
- package/dist/webhook.js.map +1 -0
- package/package.json +51 -32
- package/dist/src/adapter.d.ts +0 -125
- package/dist/src/adapter.js +0 -724
- package/dist/src/chunk.d.ts +0 -25
- package/dist/src/chunk.js +0 -108
- package/dist/src/client.d.ts +0 -112
- package/dist/src/client.js +0 -180
- package/dist/src/format.d.ts +0 -43
- package/dist/src/format.js +0 -266
- package/dist/src/idempotency.d.ts +0 -50
- package/dist/src/idempotency.js +0 -75
- package/dist/src/index.d.ts +0 -14
- package/dist/src/index.js +0 -8
- package/dist/src/reactions.d.ts +0 -12
- package/dist/src/reactions.js +0 -98
- package/dist/src/signature.d.ts +0 -46
- package/dist/src/signature.js +0 -95
- package/dist/src/threadId.d.ts +0 -12
- package/dist/src/threadId.js +0 -28
- package/dist/src/turn.d.ts +0 -38
- package/dist/src/turn.js +0 -15
- package/dist/src/types.d.ts +0 -177
- package/dist/src/types.js +0 -7
package/dist/src/chunk.d.ts
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import type { RenderedText } from "./format.js";
|
|
2
|
-
/** Relay caps one text part at 8 KB of UTF-8. */
|
|
3
|
-
export declare const MAX_TEXT_PART_BYTES = 8192;
|
|
4
|
-
/**
|
|
5
|
-
* Relay caps one send call at 32 ordered parts. The server splits the call at
|
|
6
|
-
* ingest: each visible non-media part becomes its own message, contiguous
|
|
7
|
-
* media parts stay one media message, and a voice memo always commits
|
|
8
|
-
* alone. The name survives from when one call
|
|
9
|
-
* committed one message; it still bounds a single POST.
|
|
10
|
-
*/
|
|
11
|
-
export declare const MAX_PARTS_PER_MESSAGE = 32;
|
|
12
|
-
export declare function utf8Length(value: string): number;
|
|
13
|
-
/**
|
|
14
|
-
* Split rendered text into parts that each fit Relay's per-part ceiling.
|
|
15
|
-
* Nothing is truncated: a long reply becomes more parts, and if it needs more
|
|
16
|
-
* than one message the caller sends the overflow as follow-up messages.
|
|
17
|
-
*
|
|
18
|
-
* A cut consumes the whitespace run it lands on, and nothing else. Every part
|
|
19
|
-
* draws as its own balloon on iOS
|
|
20
|
-
* (`Relay-iOS/Relay/Views/Transcript/RelayCompositePartsModel.swift:6-7`), so a
|
|
21
|
-
* part must not open with a blank line or close with a trailing space; the
|
|
22
|
-
* whitespace at the seam is the only thing a split drops, and it is whitespace
|
|
23
|
-
* between two balloons, which nobody can see.
|
|
24
|
-
*/
|
|
25
|
-
export declare function chunkRenderedText(rendered: RenderedText, maxBytes?: number): RenderedText[];
|
package/dist/src/chunk.js
DELETED
|
@@ -1,108 +0,0 @@
|
|
|
1
|
-
/** Relay caps one text part at 8 KB of UTF-8. */
|
|
2
|
-
export const MAX_TEXT_PART_BYTES = 8192;
|
|
3
|
-
/**
|
|
4
|
-
* Relay caps one send call at 32 ordered parts. The server splits the call at
|
|
5
|
-
* ingest: each visible non-media part becomes its own message, contiguous
|
|
6
|
-
* media parts stay one media message, and a voice memo always commits
|
|
7
|
-
* alone. The name survives from when one call
|
|
8
|
-
* committed one message; it still bounds a single POST.
|
|
9
|
-
*/
|
|
10
|
-
export const MAX_PARTS_PER_MESSAGE = 32;
|
|
11
|
-
const encoder = new TextEncoder();
|
|
12
|
-
export function utf8Length(value) {
|
|
13
|
-
return encoder.encode(value).length;
|
|
14
|
-
}
|
|
15
|
-
/**
|
|
16
|
-
* Largest UTF-16 index whose prefix still fits in `maxBytes` of UTF-8, always
|
|
17
|
-
* landing on a code point boundary so a surrogate pair is never cut in half.
|
|
18
|
-
*/
|
|
19
|
-
function byteLimitIndex(text, maxBytes) {
|
|
20
|
-
let bytes = 0;
|
|
21
|
-
let index = 0;
|
|
22
|
-
for (const codePoint of text) {
|
|
23
|
-
const size = encoder.encode(codePoint).length;
|
|
24
|
-
if (bytes + size > maxBytes)
|
|
25
|
-
return index;
|
|
26
|
-
bytes += size;
|
|
27
|
-
index += codePoint.length;
|
|
28
|
-
}
|
|
29
|
-
return text.length;
|
|
30
|
-
}
|
|
31
|
-
/**
|
|
32
|
-
* Prefer a natural break inside the trailing quarter of the window: a blank
|
|
33
|
-
* line, then a line break, then whitespace. A hard cut is the last resort, and
|
|
34
|
-
* it still lands on a code point boundary.
|
|
35
|
-
*/
|
|
36
|
-
function breakIndex(text, limit) {
|
|
37
|
-
if (limit >= text.length)
|
|
38
|
-
return text.length;
|
|
39
|
-
const floor = Math.max(1, Math.floor(limit * 0.75));
|
|
40
|
-
for (const separator of ["\n\n", "\n", " "]) {
|
|
41
|
-
const found = text.lastIndexOf(separator, limit - separator.length);
|
|
42
|
-
if (found >= floor)
|
|
43
|
-
return found + separator.length;
|
|
44
|
-
}
|
|
45
|
-
return limit;
|
|
46
|
-
}
|
|
47
|
-
function sliceStyles(styles, start, end) {
|
|
48
|
-
const out = [];
|
|
49
|
-
for (const run of styles) {
|
|
50
|
-
const from = Math.max(run.start, start);
|
|
51
|
-
const to = Math.min(run.start + run.length, end);
|
|
52
|
-
if (to <= from)
|
|
53
|
-
continue;
|
|
54
|
-
out.push({ start: from - start, length: to - from, styles: run.styles });
|
|
55
|
-
}
|
|
56
|
-
return out;
|
|
57
|
-
}
|
|
58
|
-
/** How much whitespace sits at `from`, which a cut there consumes. */
|
|
59
|
-
function whitespaceRunLength(text, from) {
|
|
60
|
-
const run = /^\s+/.exec(text.slice(from));
|
|
61
|
-
return run ? run[0].length : 0;
|
|
62
|
-
}
|
|
63
|
-
/**
|
|
64
|
-
* Split rendered text into parts that each fit Relay's per-part ceiling.
|
|
65
|
-
* Nothing is truncated: a long reply becomes more parts, and if it needs more
|
|
66
|
-
* than one message the caller sends the overflow as follow-up messages.
|
|
67
|
-
*
|
|
68
|
-
* A cut consumes the whitespace run it lands on, and nothing else. Every part
|
|
69
|
-
* draws as its own balloon on iOS
|
|
70
|
-
* (`Relay-iOS/Relay/Views/Transcript/RelayCompositePartsModel.swift:6-7`), so a
|
|
71
|
-
* part must not open with a blank line or close with a trailing space; the
|
|
72
|
-
* whitespace at the seam is the only thing a split drops, and it is whitespace
|
|
73
|
-
* between two balloons, which nobody can see.
|
|
74
|
-
*/
|
|
75
|
-
export function chunkRenderedText(rendered, maxBytes = MAX_TEXT_PART_BYTES) {
|
|
76
|
-
if (!rendered.text)
|
|
77
|
-
return [];
|
|
78
|
-
if (utf8Length(rendered.text) <= maxBytes)
|
|
79
|
-
return [rendered];
|
|
80
|
-
const chunks = [];
|
|
81
|
-
let cursor = 0;
|
|
82
|
-
while (cursor < rendered.text.length) {
|
|
83
|
-
// A break separator shorter than the whitespace run it sits in leaves the
|
|
84
|
-
// rest of that run at the cursor. Step over it, or the next part opens
|
|
85
|
-
// with it: trimming only the tail cannot reach it.
|
|
86
|
-
const lead = whitespaceRunLength(rendered.text, cursor);
|
|
87
|
-
if (lead > 0) {
|
|
88
|
-
cursor += lead;
|
|
89
|
-
continue;
|
|
90
|
-
}
|
|
91
|
-
const remainder = rendered.text.slice(cursor);
|
|
92
|
-
const limit = byteLimitIndex(remainder, maxBytes);
|
|
93
|
-
// A single code point wider than the ceiling cannot happen (Relay's
|
|
94
|
-
// ceiling is kilobytes), but a zero-length step would spin forever.
|
|
95
|
-
const cut = limit <= 0 ? remainder.length : breakIndex(remainder, limit);
|
|
96
|
-
const end = cursor + Math.max(1, cut);
|
|
97
|
-
const text = rendered.text.slice(cursor, end);
|
|
98
|
-
const trimmed = text.replace(/\s+$/, "");
|
|
99
|
-
if (trimmed) {
|
|
100
|
-
chunks.push({
|
|
101
|
-
text: trimmed,
|
|
102
|
-
styles: sliceStyles(rendered.styles, cursor, cursor + trimmed.length),
|
|
103
|
-
});
|
|
104
|
-
}
|
|
105
|
-
cursor = end;
|
|
106
|
-
}
|
|
107
|
-
return chunks;
|
|
108
|
-
}
|
package/dist/src/client.d.ts
DELETED
|
@@ -1,112 +0,0 @@
|
|
|
1
|
-
import type { RelayAttachment, RelayConversation, RelayMessage, RelayOutgoingPart, RelayReactionType, RelaySendResult, RelayUserProfile } from "./types.js";
|
|
2
|
-
export interface RelayClientOptions {
|
|
3
|
-
/** Agent Token (`rly_live_...`). */
|
|
4
|
-
token: string;
|
|
5
|
-
/** Defaults to Relay production. */
|
|
6
|
-
baseUrl?: string;
|
|
7
|
-
fetch?: typeof fetch;
|
|
8
|
-
}
|
|
9
|
-
export interface RelaySendOptions {
|
|
10
|
-
conversationId: string;
|
|
11
|
-
parts: RelayOutgoingPart[];
|
|
12
|
-
idempotencyKey: string;
|
|
13
|
-
invocationId?: string;
|
|
14
|
-
replyTo?: {
|
|
15
|
-
messageId: string;
|
|
16
|
-
};
|
|
17
|
-
}
|
|
18
|
-
export interface RelayReactionOptions {
|
|
19
|
-
messageId: string;
|
|
20
|
-
operation: "add" | "remove";
|
|
21
|
-
type: RelayReactionType;
|
|
22
|
-
emoji?: string;
|
|
23
|
-
/**
|
|
24
|
-
* Anchor the reaction on one part of a media message. Only media messages
|
|
25
|
-
* carry addressable parts (per-photo reaction pills); a text or card
|
|
26
|
-
* message takes whole-message reactions only, so leave this unset there.
|
|
27
|
-
*/
|
|
28
|
-
partIndex?: number;
|
|
29
|
-
}
|
|
30
|
-
export interface RelayHistoryOptions {
|
|
31
|
-
conversationId: string;
|
|
32
|
-
limit?: number;
|
|
33
|
-
beforeSequence?: number;
|
|
34
|
-
}
|
|
35
|
-
export interface RelayUploadOptions {
|
|
36
|
-
body: Uint8Array;
|
|
37
|
-
contentType?: string;
|
|
38
|
-
filename?: string;
|
|
39
|
-
}
|
|
40
|
-
export declare class RelayApiError extends Error {
|
|
41
|
-
readonly status: number;
|
|
42
|
-
readonly code: string;
|
|
43
|
-
constructor(status: number, code: string, message: string);
|
|
44
|
-
}
|
|
45
|
-
/**
|
|
46
|
-
* Minimal Relay v1 client covering exactly what the Chat SDK adapter calls.
|
|
47
|
-
* Raw HTTPS remains the canonical contract; see
|
|
48
|
-
* https://docs.relayapp.im/api-reference/overview.
|
|
49
|
-
*/
|
|
50
|
-
export declare class RelayClient {
|
|
51
|
-
private readonly token;
|
|
52
|
-
private readonly baseUrl;
|
|
53
|
-
private readonly fetchImpl;
|
|
54
|
-
constructor(options: RelayClientOptions);
|
|
55
|
-
private authHeaders;
|
|
56
|
-
private json;
|
|
57
|
-
/** `POST /v1/messages`. The idempotency key is mandatory on this route. */
|
|
58
|
-
send(options: RelaySendOptions): Promise<RelaySendResult>;
|
|
59
|
-
/**
|
|
60
|
-
* `PATCH /v1/messages/{id}`. Relay allows edits for 15 minutes and at most
|
|
61
|
-
* five revisions, and accepts exactly one text part: an edit replaces one
|
|
62
|
-
* message's text, and anything else answers 422.
|
|
63
|
-
*/
|
|
64
|
-
edit(messageId: string, parts: RelayOutgoingPart[]): Promise<{
|
|
65
|
-
message: RelayMessage;
|
|
66
|
-
}>;
|
|
67
|
-
/** `DELETE /v1/messages/{id}`. Relay allows unsend for two minutes. */
|
|
68
|
-
unsend(messageId: string): Promise<{
|
|
69
|
-
message: RelayMessage;
|
|
70
|
-
}>;
|
|
71
|
-
/** `POST /v1/messages/{id}/reactions`. One route adds and removes. */
|
|
72
|
-
react(options: RelayReactionOptions): Promise<void>;
|
|
73
|
-
/**
|
|
74
|
-
* `POST /v1/conversations/{id}/typing`. Ephemeral: pushed to live devices,
|
|
75
|
-
* never entering the event log. Relay also exposes `/responding`, which
|
|
76
|
-
* commits a Read receipt before it starts typing; this adapter keeps the two
|
|
77
|
-
* apart so `markAsRead` stays the only call that moves a watermark.
|
|
78
|
-
*/
|
|
79
|
-
typing(options: {
|
|
80
|
-
conversationId: string;
|
|
81
|
-
started?: boolean;
|
|
82
|
-
label?: string;
|
|
83
|
-
invocationId?: string;
|
|
84
|
-
}): Promise<void>;
|
|
85
|
-
/**
|
|
86
|
-
* `POST /v1/conversations/{id}/read`. Watermark semantics: everything
|
|
87
|
-
* through `messageId` is read. Older or repeated targets are no-ops.
|
|
88
|
-
*/
|
|
89
|
-
markRead(conversationId: string, messageId: string): Promise<void>;
|
|
90
|
-
/** `GET /v1/conversations/{id}/messages`, newest first. */
|
|
91
|
-
history(options: RelayHistoryOptions): Promise<{
|
|
92
|
-
messages: RelayMessage[];
|
|
93
|
-
}>;
|
|
94
|
-
/** `GET /v1/conversations/{id}`. */
|
|
95
|
-
conversation(conversationId: string): Promise<{
|
|
96
|
-
conversation: RelayConversation;
|
|
97
|
-
}>;
|
|
98
|
-
/**
|
|
99
|
-
* `GET /v1/users/{id}`. Scoped: the user must currently share an active
|
|
100
|
-
* conversation with this agent, so an unknown id answers 404 rather than
|
|
101
|
-
* confirming that an account exists.
|
|
102
|
-
*/
|
|
103
|
-
user(userId: string): Promise<{
|
|
104
|
-
user: RelayUserProfile;
|
|
105
|
-
}>;
|
|
106
|
-
/**
|
|
107
|
-
* `POST /v1/attachments`. One raw body, `Content-Length` required and
|
|
108
|
-
* verified against the stored object. Used for Chat SDK file uploads and for
|
|
109
|
-
* attachments that arrive as bytes rather than a public URL.
|
|
110
|
-
*/
|
|
111
|
-
upload(options: RelayUploadOptions): Promise<RelayAttachment>;
|
|
112
|
-
}
|
package/dist/src/client.js
DELETED
|
@@ -1,180 +0,0 @@
|
|
|
1
|
-
export class RelayApiError extends Error {
|
|
2
|
-
status;
|
|
3
|
-
code;
|
|
4
|
-
constructor(status, code, message) {
|
|
5
|
-
super(message);
|
|
6
|
-
this.status = status;
|
|
7
|
-
this.code = code;
|
|
8
|
-
this.name = "RelayApiError";
|
|
9
|
-
}
|
|
10
|
-
}
|
|
11
|
-
const DEFAULT_BASE_URL = "https://api.relayapp.im";
|
|
12
|
-
async function raiseForStatus(response) {
|
|
13
|
-
if (response.ok)
|
|
14
|
-
return;
|
|
15
|
-
let code = "unknown";
|
|
16
|
-
let message = `${response.status}`;
|
|
17
|
-
try {
|
|
18
|
-
const body = (await response.json());
|
|
19
|
-
code = body.error?.code ?? code;
|
|
20
|
-
message = body.error?.message ?? message;
|
|
21
|
-
}
|
|
22
|
-
catch {
|
|
23
|
-
// non-JSON error body; keep the status text
|
|
24
|
-
}
|
|
25
|
-
throw new RelayApiError(response.status, code, message);
|
|
26
|
-
}
|
|
27
|
-
/**
|
|
28
|
-
* Minimal Relay v1 client covering exactly what the Chat SDK adapter calls.
|
|
29
|
-
* Raw HTTPS remains the canonical contract; see
|
|
30
|
-
* https://docs.relayapp.im/api-reference/overview.
|
|
31
|
-
*/
|
|
32
|
-
export class RelayClient {
|
|
33
|
-
token;
|
|
34
|
-
baseUrl;
|
|
35
|
-
fetchImpl;
|
|
36
|
-
constructor(options) {
|
|
37
|
-
if (!options.token)
|
|
38
|
-
throw new Error("Relay Agent Token is required");
|
|
39
|
-
this.token = options.token;
|
|
40
|
-
this.baseUrl = (options.baseUrl ?? DEFAULT_BASE_URL).replace(/\/$/, "");
|
|
41
|
-
// Bound to the global object because the call sites invoke this through a
|
|
42
|
-
// property, which would otherwise pass the client as `this`. undici accepts
|
|
43
|
-
// that; workerd rejects it with `Illegal invocation`, so an unbound fetch
|
|
44
|
-
// fails every request on Cloudflare Workers. Binding a caller-supplied
|
|
45
|
-
// fetch is safe: an already-bound function ignores a later `bind`.
|
|
46
|
-
this.fetchImpl = (options.fetch ?? globalThis.fetch).bind(globalThis);
|
|
47
|
-
}
|
|
48
|
-
authHeaders(extra) {
|
|
49
|
-
return { Authorization: `Bearer ${this.token}`, ...extra };
|
|
50
|
-
}
|
|
51
|
-
async json(path, init) {
|
|
52
|
-
const response = await this.fetchImpl(`${this.baseUrl}${path}`, {
|
|
53
|
-
...init,
|
|
54
|
-
headers: this.authHeaders(init.headers),
|
|
55
|
-
});
|
|
56
|
-
await raiseForStatus(response);
|
|
57
|
-
return (await response.json());
|
|
58
|
-
}
|
|
59
|
-
/** `POST /v1/messages`. The idempotency key is mandatory on this route. */
|
|
60
|
-
async send(options) {
|
|
61
|
-
return this.json("/v1/messages", {
|
|
62
|
-
method: "POST",
|
|
63
|
-
headers: {
|
|
64
|
-
"Content-Type": "application/json",
|
|
65
|
-
"Idempotency-Key": options.idempotencyKey,
|
|
66
|
-
},
|
|
67
|
-
body: JSON.stringify({
|
|
68
|
-
conversation_id: options.conversationId,
|
|
69
|
-
parts: options.parts,
|
|
70
|
-
...(options.invocationId ? { invocation_id: options.invocationId } : {}),
|
|
71
|
-
...(options.replyTo
|
|
72
|
-
? { reply_to: { message_id: options.replyTo.messageId } }
|
|
73
|
-
: {}),
|
|
74
|
-
}),
|
|
75
|
-
});
|
|
76
|
-
}
|
|
77
|
-
/**
|
|
78
|
-
* `PATCH /v1/messages/{id}`. Relay allows edits for 15 minutes and at most
|
|
79
|
-
* five revisions, and accepts exactly one text part: an edit replaces one
|
|
80
|
-
* message's text, and anything else answers 422.
|
|
81
|
-
*/
|
|
82
|
-
async edit(messageId, parts) {
|
|
83
|
-
return this.json(`/v1/messages/${encodeURIComponent(messageId)}`, {
|
|
84
|
-
method: "PATCH",
|
|
85
|
-
headers: { "Content-Type": "application/json" },
|
|
86
|
-
body: JSON.stringify({ parts }),
|
|
87
|
-
});
|
|
88
|
-
}
|
|
89
|
-
/** `DELETE /v1/messages/{id}`. Relay allows unsend for two minutes. */
|
|
90
|
-
async unsend(messageId) {
|
|
91
|
-
return this.json(`/v1/messages/${encodeURIComponent(messageId)}`, { method: "DELETE" });
|
|
92
|
-
}
|
|
93
|
-
/** `POST /v1/messages/{id}/reactions`. One route adds and removes. */
|
|
94
|
-
async react(options) {
|
|
95
|
-
const response = await this.fetchImpl(`${this.baseUrl}/v1/messages/${encodeURIComponent(options.messageId)}/reactions`, {
|
|
96
|
-
method: "POST",
|
|
97
|
-
headers: this.authHeaders({ "Content-Type": "application/json" }),
|
|
98
|
-
body: JSON.stringify({
|
|
99
|
-
operation: options.operation,
|
|
100
|
-
type: options.type,
|
|
101
|
-
...(options.emoji ? { emoji: options.emoji } : {}),
|
|
102
|
-
...(options.partIndex !== undefined
|
|
103
|
-
? { part_index: options.partIndex }
|
|
104
|
-
: {}),
|
|
105
|
-
}),
|
|
106
|
-
});
|
|
107
|
-
await raiseForStatus(response);
|
|
108
|
-
}
|
|
109
|
-
/**
|
|
110
|
-
* `POST /v1/conversations/{id}/typing`. Ephemeral: pushed to live devices,
|
|
111
|
-
* never entering the event log. Relay also exposes `/responding`, which
|
|
112
|
-
* commits a Read receipt before it starts typing; this adapter keeps the two
|
|
113
|
-
* apart so `markAsRead` stays the only call that moves a watermark.
|
|
114
|
-
*/
|
|
115
|
-
async typing(options) {
|
|
116
|
-
const response = await this.fetchImpl(`${this.baseUrl}/v1/conversations/${encodeURIComponent(options.conversationId)}/typing`, {
|
|
117
|
-
method: "POST",
|
|
118
|
-
headers: this.authHeaders({ "Content-Type": "application/json" }),
|
|
119
|
-
body: JSON.stringify({
|
|
120
|
-
started: options.started ?? true,
|
|
121
|
-
...(options.label ? { label: options.label } : {}),
|
|
122
|
-
...(options.invocationId
|
|
123
|
-
? { invocation_id: options.invocationId }
|
|
124
|
-
: {}),
|
|
125
|
-
}),
|
|
126
|
-
});
|
|
127
|
-
await raiseForStatus(response);
|
|
128
|
-
}
|
|
129
|
-
/**
|
|
130
|
-
* `POST /v1/conversations/{id}/read`. Watermark semantics: everything
|
|
131
|
-
* through `messageId` is read. Older or repeated targets are no-ops.
|
|
132
|
-
*/
|
|
133
|
-
async markRead(conversationId, messageId) {
|
|
134
|
-
const response = await this.fetchImpl(`${this.baseUrl}/v1/conversations/${encodeURIComponent(conversationId)}/read`, {
|
|
135
|
-
method: "POST",
|
|
136
|
-
headers: this.authHeaders({ "Content-Type": "application/json" }),
|
|
137
|
-
body: JSON.stringify({ message_id: messageId }),
|
|
138
|
-
});
|
|
139
|
-
await raiseForStatus(response);
|
|
140
|
-
}
|
|
141
|
-
/** `GET /v1/conversations/{id}/messages`, newest first. */
|
|
142
|
-
async history(options) {
|
|
143
|
-
const query = new URLSearchParams();
|
|
144
|
-
if (options.limit !== undefined)
|
|
145
|
-
query.set("limit", String(options.limit));
|
|
146
|
-
if (options.beforeSequence !== undefined) {
|
|
147
|
-
query.set("before_sequence", String(options.beforeSequence));
|
|
148
|
-
}
|
|
149
|
-
const suffix = query.size > 0 ? `?${query}` : "";
|
|
150
|
-
return this.json(`/v1/conversations/${encodeURIComponent(options.conversationId)}/messages${suffix}`, { method: "GET" });
|
|
151
|
-
}
|
|
152
|
-
/** `GET /v1/conversations/{id}`. */
|
|
153
|
-
async conversation(conversationId) {
|
|
154
|
-
return this.json(`/v1/conversations/${encodeURIComponent(conversationId)}`, { method: "GET" });
|
|
155
|
-
}
|
|
156
|
-
/**
|
|
157
|
-
* `GET /v1/users/{id}`. Scoped: the user must currently share an active
|
|
158
|
-
* conversation with this agent, so an unknown id answers 404 rather than
|
|
159
|
-
* confirming that an account exists.
|
|
160
|
-
*/
|
|
161
|
-
async user(userId) {
|
|
162
|
-
return this.json(`/v1/users/${encodeURIComponent(userId)}`, { method: "GET" });
|
|
163
|
-
}
|
|
164
|
-
/**
|
|
165
|
-
* `POST /v1/attachments`. One raw body, `Content-Length` required and
|
|
166
|
-
* verified against the stored object. Used for Chat SDK file uploads and for
|
|
167
|
-
* attachments that arrive as bytes rather than a public URL.
|
|
168
|
-
*/
|
|
169
|
-
async upload(options) {
|
|
170
|
-
const headers = {
|
|
171
|
-
"Content-Length": String(options.body.byteLength),
|
|
172
|
-
"Content-Type": options.contentType ?? "application/octet-stream",
|
|
173
|
-
};
|
|
174
|
-
if (options.filename)
|
|
175
|
-
headers["X-Relay-Filename"] = options.filename;
|
|
176
|
-
const body = options.body.slice().buffer;
|
|
177
|
-
const result = await this.json("/v1/attachments", { method: "POST", headers, body });
|
|
178
|
-
return result.attachment;
|
|
179
|
-
}
|
|
180
|
-
}
|
package/dist/src/format.d.ts
DELETED
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
import type { Root } from "chat";
|
|
2
|
-
import type { RelayStyleRange } from "./types.js";
|
|
3
|
-
/**
|
|
4
|
-
* Relay does not render Markdown. A text part carries canonical plain text
|
|
5
|
-
* plus optional `styles` runs, offsets in UTF-16 code units, and clients draw
|
|
6
|
-
* the runs. So the conversion from the Chat SDK's mdast is not a stringify: it
|
|
7
|
-
* flattens the tree to the text a person reads and records the emphasis it
|
|
8
|
-
* carried as style ranges, which is the only path that keeps both the words
|
|
9
|
-
* and the formatting.
|
|
10
|
-
*
|
|
11
|
-
* Constructs Relay has no style for keep their information in the text rather
|
|
12
|
-
* than losing it: a link whose label differs from its target renders as
|
|
13
|
-
* `label (url)`, a blockquote keeps a `> ` line prefix, and a table is drawn as
|
|
14
|
-
* a monospace ASCII grid.
|
|
15
|
-
*/
|
|
16
|
-
export interface RenderedText {
|
|
17
|
-
text: string;
|
|
18
|
-
styles: RelayStyleRange[];
|
|
19
|
-
}
|
|
20
|
-
/** Relay accepts at most 200 style ranges on one text part. */
|
|
21
|
-
export declare const MAX_STYLE_RANGES = 200;
|
|
22
|
-
/**
|
|
23
|
-
* Collapse the raw run list into what Relay's contract requires: sorted by
|
|
24
|
-
* start, non-overlapping, and no more than 200 entries. Nested emphasis
|
|
25
|
-
* produces overlapping runs, so they are flattened onto a per-character style
|
|
26
|
-
* set and then re-run-length-encoded.
|
|
27
|
-
*/
|
|
28
|
-
export declare function normalizeStyles(runs: RelayStyleRange[]): RelayStyleRange[];
|
|
29
|
-
/**
|
|
30
|
-
* Insert a prefix at the start of every line, remapping style offsets so the
|
|
31
|
-
* runs still cover the same characters.
|
|
32
|
-
*/
|
|
33
|
-
export declare function prefixLines(rendered: RenderedText, prefix: string, firstPrefix?: string): RenderedText;
|
|
34
|
-
/** Flatten an mdast tree into Relay text plus style runs. */
|
|
35
|
-
export declare function renderAst(ast: Root): RenderedText;
|
|
36
|
-
/** Flatten a Markdown string into Relay text plus style runs. */
|
|
37
|
-
export declare function renderMarkdown(markdown: string): RenderedText;
|
|
38
|
-
/**
|
|
39
|
-
* Text a caller supplied verbatim. The empty `styles` array is meaningful to
|
|
40
|
-
* Relay: it marks the part as structured plain text so no client tries to read
|
|
41
|
-
* it as a legacy Markdown body.
|
|
42
|
-
*/
|
|
43
|
-
export declare function renderRawText(value: string): RenderedText;
|