aurival 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/errors.js ADDED
@@ -0,0 +1,205 @@
1
+ /**
2
+ * ERRORS-V1 as JavaScript errors.
3
+ *
4
+ * One class per `type` (§1), then one subclass per `code` the SDK acts on
5
+ * (errors_v1.go's `errCatalogue`, the closed catalogue). `fromEnvelope` turns a
6
+ * wire envelope into the right instance and never throws itself.
7
+ */
8
+ /** Base for everything this SDK throws. */
9
+ export class AurivalError extends Error {
10
+ constructor(message) {
11
+ super(message);
12
+ this.name = new.target.name;
13
+ }
14
+ }
15
+ /** A network fault: dial refused, DNS, reset. Never an undici exception. */
16
+ export class TransportError extends AurivalError {
17
+ }
18
+ /** The server said something we cannot parse as the documented envelope. */
19
+ export class ProtocolError extends AurivalError {
20
+ }
21
+ /** One ERRORS-V1 envelope. Every instance carries `code` and `doc_url`. */
22
+ export class AurivalAPIError extends AurivalError {
23
+ type;
24
+ code;
25
+ doc_url;
26
+ request_id;
27
+ retry_after;
28
+ status;
29
+ constructor(init) {
30
+ super(init.message);
31
+ this.type = init.type;
32
+ this.code = init.code;
33
+ this.doc_url = init.doc_url;
34
+ this.request_id = init.request_id ?? null;
35
+ this.retry_after = init.retry_after ?? null;
36
+ this.status = init.status ?? null;
37
+ }
38
+ }
39
+ // --- one class per type (§1) ------------------------------------------------
40
+ /** `authentication_error` — 401, re-sign and retry once. */
41
+ export class AuthenticationError extends AurivalAPIError {
42
+ }
43
+ /** `invalid_request_error` — 400/404/409, never retry. */
44
+ export class InvalidRequestError extends AurivalAPIError {
45
+ }
46
+ /** `permission_error` — 403, never retry. */
47
+ export class PermissionDeniedError extends AurivalAPIError {
48
+ }
49
+ /** `rate_limit_error` — 429, honour `Retry-After`. */
50
+ export class RateLimitError extends AurivalAPIError {
51
+ }
52
+ /** `api_error` — 5xx, our fault, retry with backoff. */
53
+ export class APIError extends AurivalAPIError {
54
+ }
55
+ // --- one subclass per code the SDK acts on ----------------------------------
56
+ export class AccessTokenExpired extends AuthenticationError {
57
+ }
58
+ export class AccessTokenInvalid extends AuthenticationError {
59
+ }
60
+ export class KeyRevoked extends AuthenticationError {
61
+ }
62
+ export class BadAssertion extends AuthenticationError {
63
+ }
64
+ export class AssertionExpired extends AuthenticationError {
65
+ }
66
+ export class AssertionReplay extends AuthenticationError {
67
+ }
68
+ export class BadProof extends AuthenticationError {
69
+ }
70
+ export class BadPublicKey extends AuthenticationError {
71
+ }
72
+ export class KeyAlreadyPaired extends AuthenticationError {
73
+ }
74
+ export class NotFound extends InvalidRequestError {
75
+ }
76
+ export class InvalidCommandName extends InvalidRequestError {
77
+ }
78
+ export class EmptyText extends InvalidRequestError {
79
+ }
80
+ export class TextTooLong extends InvalidRequestError {
81
+ }
82
+ export class InvalidJSON extends InvalidRequestError {
83
+ }
84
+ export class ParameterMissing extends InvalidRequestError {
85
+ }
86
+ export class ParameterInvalid extends InvalidRequestError {
87
+ }
88
+ export class UnknownParameter extends InvalidRequestError {
89
+ }
90
+ export class IdempotencyKeyReused extends InvalidRequestError {
91
+ }
92
+ export class IdempotencyKeyInvalid extends InvalidRequestError {
93
+ }
94
+ export class BotLinkNotAllowed extends InvalidRequestError {
95
+ }
96
+ export class SessionSuperseded extends InvalidRequestError {
97
+ }
98
+ export class FrameTooLarge extends InvalidRequestError {
99
+ }
100
+ export class FrameInvalid extends InvalidRequestError {
101
+ }
102
+ export class UnknownOperation extends InvalidRequestError {
103
+ }
104
+ export class AckUnknownEvent extends InvalidRequestError {
105
+ }
106
+ /**
107
+ * `too_many_problems` (SDK-39). BA-R23 was ruled and has since landed on main
108
+ * (`a522dcb4`), so this is a real row rather than a placeholder.
109
+ */
110
+ export class TooManyProblems extends InvalidRequestError {
111
+ }
112
+ export class BotSuspended extends PermissionDeniedError {
113
+ }
114
+ export class BotPlaygroundOnly extends PermissionDeniedError {
115
+ }
116
+ export class RateLimited extends RateLimitError {
117
+ }
118
+ export class PairRateLimited extends RateLimitError {
119
+ }
120
+ export class SyncRateLimited extends RateLimitError {
121
+ }
122
+ export class InternalError extends APIError {
123
+ }
124
+ export class ServerRestarting extends APIError {
125
+ }
126
+ export class IdleTimeout extends APIError {
127
+ }
128
+ export const DOC_URL_PREFIX = 'https://bots.aurival.com/docs/errors#';
129
+ export const TYPE_CLASSES = {
130
+ authentication_error: AuthenticationError,
131
+ invalid_request_error: InvalidRequestError,
132
+ permission_error: PermissionDeniedError,
133
+ rate_limit_error: RateLimitError,
134
+ api_error: APIError,
135
+ };
136
+ export const CODE_CLASSES = {
137
+ access_token_expired: AccessTokenExpired,
138
+ access_token_invalid: AccessTokenInvalid,
139
+ bad_assertion: BadAssertion,
140
+ assertion_expired: AssertionExpired,
141
+ assertion_replay: AssertionReplay,
142
+ bad_proof: BadProof,
143
+ bad_public_key: BadPublicKey,
144
+ key_revoked: KeyRevoked,
145
+ key_already_paired: KeyAlreadyPaired,
146
+ not_found: NotFound,
147
+ invalid_command_name: InvalidCommandName,
148
+ empty_text: EmptyText,
149
+ text_too_long: TextTooLong,
150
+ bot_link_not_allowed: BotLinkNotAllowed,
151
+ invalid_json: InvalidJSON,
152
+ parameter_missing: ParameterMissing,
153
+ parameter_invalid: ParameterInvalid,
154
+ unknown_parameter: UnknownParameter,
155
+ idempotency_key_reused: IdempotencyKeyReused,
156
+ idempotency_key_invalid: IdempotencyKeyInvalid,
157
+ bot_suspended: BotSuspended,
158
+ bot_playground_only: BotPlaygroundOnly,
159
+ rate_limited: RateLimited,
160
+ pair_rate_limited: PairRateLimited,
161
+ sync_rate_limited: SyncRateLimited,
162
+ internal_error: InternalError,
163
+ session_superseded: SessionSuperseded,
164
+ frame_too_large: FrameTooLarge,
165
+ server_restarting: ServerRestarting,
166
+ idle_timeout: IdleTimeout,
167
+ frame_invalid: FrameInvalid,
168
+ unknown_operation: UnknownOperation,
169
+ ack_unknown_event: AckUnknownEvent,
170
+ too_many_problems: TooManyProblems,
171
+ };
172
+ function asString(value) {
173
+ return typeof value === 'string' ? value : null;
174
+ }
175
+ function asRecord(value) {
176
+ return typeof value === 'object' && value !== null && !Array.isArray(value)
177
+ ? value
178
+ : null;
179
+ }
180
+ /**
181
+ * Build an error from an ERRORS-V1 envelope.
182
+ *
183
+ * `payload` is the whole body/frame data: `{"error": {...}}` or already the
184
+ * inner object. Unknown code -> its type's class. Unknown type -> the base
185
+ * `AurivalAPIError`. Never throws.
186
+ */
187
+ export function fromEnvelope(payload, options = {}) {
188
+ const body = asRecord(payload['error']) ?? payload;
189
+ const code = asString(body['code']) ?? '';
190
+ const type = asString(body['type']) ?? '';
191
+ const message = asString(body['message']) ?? '';
192
+ const doc_url = asString(body['doc_url']) ?? DOC_URL_PREFIX + code;
193
+ const request_id = asString(body['request_id']);
194
+ const cls = CODE_CLASSES[code] ?? TYPE_CLASSES[type] ?? AurivalAPIError;
195
+ return new cls({
196
+ type,
197
+ code,
198
+ message,
199
+ doc_url,
200
+ request_id,
201
+ retry_after: options.retryAfter ?? null,
202
+ status: options.status ?? null,
203
+ });
204
+ }
205
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,77 @@
1
+ /**
2
+ * Plain data a command handler receives (CONTRACT-V1 §3, §3.1).
3
+ *
4
+ * `Event` is the raw wire frame; `Context` is what `bot.ts` hands to a handler,
5
+ * built from one. `Context` holds an `HttpClient` for `reply()` and nothing else
6
+ * network-shaped — never the seed, a token, or the `Auth` object (SDK-33).
7
+ */
8
+ import type { HttpClient } from './http.js';
9
+ export interface User {
10
+ id: string;
11
+ handle: string;
12
+ name: string;
13
+ }
14
+ export interface Chat {
15
+ id: string;
16
+ type: string;
17
+ name: string | null;
18
+ }
19
+ export interface Command {
20
+ name: string;
21
+ description: string;
22
+ }
23
+ export interface EventInit {
24
+ id: string;
25
+ type: string;
26
+ created_at: string;
27
+ sequence: number;
28
+ data: Record<string, unknown>;
29
+ }
30
+ export declare class Event {
31
+ readonly id: string;
32
+ readonly type: string;
33
+ readonly created_at: string;
34
+ readonly sequence: number;
35
+ readonly data: Record<string, unknown>;
36
+ constructor(init: EventInit);
37
+ /**
38
+ * `frame` is one WireEvent (`{object, id, type, created_at, sequence, data}`)
39
+ * — the `event` frame's payload, top-level, not re-wrapped.
40
+ */
41
+ static fromFrame(frame: Record<string, unknown>): Event;
42
+ }
43
+ export interface ContextInit {
44
+ command: string;
45
+ arguments: string;
46
+ chat: Chat;
47
+ sender: User;
48
+ event: Event;
49
+ message: string | null;
50
+ http: HttpClient;
51
+ }
52
+ /**
53
+ * What a command handler receives. Built by `bot.ts`'s dispatch closure from one
54
+ * `Event` — `Socket` never constructs one.
55
+ */
56
+ export declare class Context {
57
+ #private;
58
+ readonly command: string;
59
+ readonly arguments: string;
60
+ readonly chat: Chat;
61
+ readonly sender: User;
62
+ readonly event: Event;
63
+ readonly message: string | null;
64
+ constructor(init: ContextInit);
65
+ /** Build straight from a `command.invoked` event's raw `data`. */
66
+ static fromEvent(event: Event, http: HttpClient): Context;
67
+ /**
68
+ * `POST /v1/messages`, quoting the message that invoked the command
69
+ * (BA-R27, reversing SDK-30). One method, no flag. When the event carried no
70
+ * message id the field is omitted and the reply floats free.
71
+ *
72
+ * A fresh `Idempotency-Key` per call, reused across that call's retries by
73
+ * `HttpClient.request` itself.
74
+ */
75
+ reply(text: string): Promise<Record<string, unknown>>;
76
+ }
77
+ //# sourceMappingURL=events.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../src/events.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAE5C,MAAM,WAAW,IAAI;IACnB,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,IAAI;IACnB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;CACrB;AAED,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;CACrB;AAYD,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC/B;AAED,qBAAa,KAAK;IAChB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAEvC,YAAY,IAAI,EAAE,SAAS,EAM1B;IAED;;;OAGG;IACH,MAAM,CAAC,SAAS,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,KAAK,CAStD;CACF;AAeD,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,IAAI,CAAC;IACX,MAAM,EAAE,IAAI,CAAC;IACb,KAAK,EAAE,KAAK,CAAC;IACb,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,IAAI,EAAE,UAAU,CAAC;CAClB;AAED;;;GAGG;AACH,qBAAa,OAAO;;IAClB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC;IACpB,QAAQ,CAAC,MAAM,EAAE,IAAI,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAGhC,YAAY,IAAI,EAAE,WAAW,EAQ5B;IAED,kEAAkE;IAClE,MAAM,CAAC,SAAS,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,UAAU,GAAG,OAAO,CAexD;IAED;;;;;;;OAOG;IACG,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAE1D;CACF"}
package/dist/events.js ADDED
@@ -0,0 +1,106 @@
1
+ /**
2
+ * Plain data a command handler receives (CONTRACT-V1 §3, §3.1).
3
+ *
4
+ * `Event` is the raw wire frame; `Context` is what `bot.ts` hands to a handler,
5
+ * built from one. `Context` holds an `HttpClient` for `reply()` and nothing else
6
+ * network-shaped — never the seed, a token, or the `Auth` object (SDK-33).
7
+ */
8
+ import { randomUUID } from 'node:crypto';
9
+ function asRecord(value) {
10
+ return typeof value === 'object' && value !== null && !Array.isArray(value)
11
+ ? value
12
+ : null;
13
+ }
14
+ function asString(value, fallback = '') {
15
+ return typeof value === 'string' ? value : fallback;
16
+ }
17
+ export class Event {
18
+ id;
19
+ type;
20
+ created_at;
21
+ sequence;
22
+ data;
23
+ constructor(init) {
24
+ this.id = init.id;
25
+ this.type = init.type;
26
+ this.created_at = init.created_at;
27
+ this.sequence = init.sequence;
28
+ this.data = init.data;
29
+ }
30
+ /**
31
+ * `frame` is one WireEvent (`{object, id, type, created_at, sequence, data}`)
32
+ * — the `event` frame's payload, top-level, not re-wrapped.
33
+ */
34
+ static fromFrame(frame) {
35
+ const sequence = Number(frame['sequence']);
36
+ return new Event({
37
+ id: asString(frame['id']),
38
+ type: asString(frame['type']),
39
+ created_at: asString(frame['created_at']),
40
+ sequence: Number.isFinite(sequence) ? Math.trunc(sequence) : 0,
41
+ data: asRecord(frame['data']) ?? {},
42
+ });
43
+ }
44
+ }
45
+ function userFromWire(d) {
46
+ return { id: asString(d['id']), handle: asString(d['handle']), name: asString(d['name']) };
47
+ }
48
+ function chatFromWire(d) {
49
+ const name = d['name'];
50
+ return {
51
+ id: asString(d['id']),
52
+ type: asString(d['type']),
53
+ name: typeof name === 'string' ? name : null,
54
+ };
55
+ }
56
+ /**
57
+ * What a command handler receives. Built by `bot.ts`'s dispatch closure from one
58
+ * `Event` — `Socket` never constructs one.
59
+ */
60
+ export class Context {
61
+ command;
62
+ arguments;
63
+ chat;
64
+ sender;
65
+ event;
66
+ message;
67
+ #http;
68
+ constructor(init) {
69
+ this.command = init.command;
70
+ this.arguments = init.arguments;
71
+ this.chat = init.chat;
72
+ this.sender = init.sender;
73
+ this.event = init.event;
74
+ this.message = init.message;
75
+ this.#http = init.http;
76
+ }
77
+ /** Build straight from a `command.invoked` event's raw `data`. */
78
+ static fromEvent(event, http) {
79
+ const data = event.data;
80
+ const message = data['message'];
81
+ return new Context({
82
+ command: asString(data['command']),
83
+ arguments: asString(data['arguments']),
84
+ chat: chatFromWire(asRecord(data['chat']) ?? {}),
85
+ sender: userFromWire(asRecord(data['sender']) ?? {}),
86
+ event,
87
+ // The `msg_` id of the message the bot was addressed with
88
+ // (botview.go's CommandInvokedData.Message). `reply` quotes it (BA-R27).
89
+ // An absent field is null, not a crash — then the reply floats free.
90
+ message: typeof message === 'string' ? message : null,
91
+ http,
92
+ });
93
+ }
94
+ /**
95
+ * `POST /v1/messages`, quoting the message that invoked the command
96
+ * (BA-R27, reversing SDK-30). One method, no flag. When the event carried no
97
+ * message id the field is omitted and the reply floats free.
98
+ *
99
+ * A fresh `Idempotency-Key` per call, reused across that call's retries by
100
+ * `HttpClient.request` itself.
101
+ */
102
+ async reply(text) {
103
+ return this.#http.sendMessage(this.chat.id, text, randomUUID(), this.message);
104
+ }
105
+ }
106
+ //# sourceMappingURL=events.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"events.js","sourceRoot":"","sources":["../src/events.ts"],"names":[],"mappings":"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"}
package/dist/http.d.ts ADDED
@@ -0,0 +1,48 @@
1
+ /**
2
+ * The REST lane. One retry policy lives here (SDK-26/SDK-35/SDK-37) so every
3
+ * caller — `bot.ts`, `Context.reply`, pairing — gets it for free. Nothing from
4
+ * `fetch` escapes: every failure becomes one of `./errors.js`'s errors.
5
+ */
6
+ import type { Auth } from './auth.js';
7
+ export declare const DEFAULT_HOST = "https://bots.aurival.com";
8
+ /**
9
+ * Node has no stdlib logger, so this is the seam Python's `logging.Logger`
10
+ * occupies. `defaultLogger` mirrors an unconfigured `logging.getLogger`:
11
+ * warnings and errors reach stderr, debug and info are dropped unless
12
+ * `AURIVAL_DEBUG` is set.
13
+ */
14
+ export interface Logger {
15
+ debug(message: string, ...args: unknown[]): void;
16
+ info(message: string, ...args: unknown[]): void;
17
+ warn(message: string, ...args: unknown[]): void;
18
+ error(message: string, ...args: unknown[]): void;
19
+ }
20
+ export declare function defaultLogger(): Logger;
21
+ export interface RequestOptions {
22
+ body?: Record<string, unknown> | undefined;
23
+ headers?: Record<string, string> | undefined;
24
+ authenticated?: boolean | undefined;
25
+ idempotencyKey?: string | undefined;
26
+ retryAuth?: boolean | undefined;
27
+ }
28
+ export declare class HttpClient {
29
+ #private;
30
+ /** Injectable so a retry/backoff test never actually waits. */
31
+ sleep: (ms: number) => Promise<void>;
32
+ constructor(host: string, auth?: Auth | null, logger?: Logger);
33
+ /** Returns the decoded JSON body. Throws only SDK errors. */
34
+ request(method: string, path: string, options?: RequestOptions): Promise<Record<string, unknown>>;
35
+ /**
36
+ * `replyTo` is a `msg_` reference and is OMITTED when absent — the field is
37
+ * optional on the wire (CONTRACT-V1 §5.0) and a `null` there is a
38
+ * `parameter_invalid` waiting to happen.
39
+ */
40
+ sendMessage(chat: string, text: string, idempotencyKey: string, replyTo?: string | null): Promise<Record<string, unknown>>;
41
+ syncCommands(bot: string, commands: Array<{
42
+ name: string;
43
+ description: string;
44
+ }>): Promise<Record<string, unknown>>;
45
+ listCommands(bot: string): Promise<Record<string, unknown>>;
46
+ gatewayUrl(): string;
47
+ }
48
+ //# sourceMappingURL=http.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEtC,eAAO,MAAM,YAAY,6BAA6B,CAAC;AAQvD;;;;;GAKG;AACH,MAAM,WAAW,MAAM;IACrB,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;IACjD,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;IAChD,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;IAChD,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;CAClD;AAMD,wBAAgB,aAAa,IAAI,MAAM,CAYtC;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAAC;IAC3C,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,CAAC;IAC7C,aAAa,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACpC,cAAc,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACpC,SAAS,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CACjC;AAwCD,qBAAa,UAAU;;IAIrB,+DAA+D;IAC/D,KAAK,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAG/B;IAEL,YAAY,IAAI,EAAE,MAAM,EAAE,IAAI,GAAE,IAAI,GAAG,IAAW,EAAE,MAAM,CAAC,EAAE,MAAM,EAIlE;IAED,6DAA6D;IACvD,OAAO,CACX,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE,cAAmB,GAC3B,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CA8FlC;IAED;;;;OAIG;IACG,WAAW,CACf,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,cAAc,EAAE,MAAM,EACtB,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,GACtB,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAIlC;IAEK,YAAY,CAChB,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC,GACrD,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAKlC;IAEK,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAEhE;IAED,UAAU,IAAI,MAAM,CAMnB;CACF"}
package/dist/http.js ADDED
@@ -0,0 +1,201 @@
1
+ /**
2
+ * The REST lane. One retry policy lives here (SDK-26/SDK-35/SDK-37) so every
3
+ * caller — `bot.ts`, `Context.reply`, pairing — gets it for free. Nothing from
4
+ * `fetch` escapes: every failure becomes one of `./errors.js`'s errors.
5
+ */
6
+ import { randomUUID } from 'node:crypto';
7
+ import * as errors from './errors.js';
8
+ export const DEFAULT_HOST = 'https://bots.aurival.com';
9
+ // Both the rate-limit lane and the api_error/transport lane are bounded here
10
+ // (SDK-26): this many tries total, first attempt included.
11
+ const MAX_ATTEMPTS = 5;
12
+ const DEFAULT_RETRY_AFTER_MS = 1000;
13
+ const REQUEST_TIMEOUT_MS = 60_000;
14
+ function emit(level, message, args) {
15
+ process.stderr.write(`aurival ${level}: ${message}${args.length ? ' ' + args.join(' ') : ''}\n`);
16
+ }
17
+ export function defaultLogger() {
18
+ const verbose = Boolean(process.env['AURIVAL_DEBUG']);
19
+ return {
20
+ debug: (m, ...a) => {
21
+ if (verbose)
22
+ emit('debug', m, a);
23
+ },
24
+ info: (m, ...a) => {
25
+ if (verbose)
26
+ emit('info', m, a);
27
+ },
28
+ warn: (m, ...a) => emit('warn', m, a),
29
+ error: (m, ...a) => emit('error', m, a),
30
+ };
31
+ }
32
+ /** A non-JSON body, or JSON that is not an object, is a `ProtocolError`. */
33
+ function decodeObject(raw) {
34
+ let data;
35
+ try {
36
+ data = raw ? JSON.parse(raw) : null;
37
+ }
38
+ catch (exc) {
39
+ const detail = exc instanceof Error ? exc.message : String(exc);
40
+ throw new errors.ProtocolError(`response body was not valid JSON: ${detail}`);
41
+ }
42
+ if (typeof data !== 'object' || data === null || Array.isArray(data)) {
43
+ throw new errors.ProtocolError('response body was not a JSON object');
44
+ }
45
+ return data;
46
+ }
47
+ function envelopeBody(envelope) {
48
+ const inner = envelope['error'];
49
+ return typeof inner === 'object' && inner !== null && !Array.isArray(inner)
50
+ ? inner
51
+ : envelope;
52
+ }
53
+ function retryAfterMs(header, envelope) {
54
+ if (header !== null) {
55
+ const parsed = Number(header);
56
+ if (Number.isFinite(parsed))
57
+ return Math.max(0, parsed * 1000);
58
+ }
59
+ const value = envelopeBody(envelope)['retry_after'];
60
+ if (typeof value === 'number' && Number.isFinite(value))
61
+ return Math.max(0, value * 1000);
62
+ return DEFAULT_RETRY_AFTER_MS;
63
+ }
64
+ // attempt is 1-based. Plain exponential, capped — the shape doesn't matter much
65
+ // here since every test injects the sleep; being bounded does.
66
+ function backoffDelayMs(attempt) {
67
+ return Math.min(500 * 2 ** (attempt - 1), 8000);
68
+ }
69
+ export class HttpClient {
70
+ #host;
71
+ #auth;
72
+ #logger;
73
+ /** Injectable so a retry/backoff test never actually waits. */
74
+ sleep = (ms) => new Promise((resolve) => {
75
+ setTimeout(resolve, ms);
76
+ });
77
+ constructor(host, auth = null, logger) {
78
+ this.#host = host.replace(/\/+$/, '');
79
+ this.#auth = auth;
80
+ this.#logger = logger ?? defaultLogger();
81
+ }
82
+ /** Returns the decoded JSON body. Throws only SDK errors. */
83
+ async request(method, path, options = {}) {
84
+ const baseHeaders = { ...(options.headers ?? {}) };
85
+ if (options.idempotencyKey !== undefined) {
86
+ // Generated once by the caller and reused verbatim across every retry of
87
+ // this call (SDK-30) — never regenerated per attempt.
88
+ baseHeaders['Idempotency-Key'] = options.idempotencyKey;
89
+ }
90
+ const authenticated = options.authenticated ?? true;
91
+ const retryAuth = options.retryAuth ?? true;
92
+ const url = this.#host + path;
93
+ let authRetried = false;
94
+ let attempt = 0;
95
+ for (;;) {
96
+ attempt += 1;
97
+ const headers = { ...baseHeaders };
98
+ if (authenticated) {
99
+ if (this.#auth === null) {
100
+ throw new errors.AurivalError('request() needs an authenticated Auth but none was given');
101
+ }
102
+ headers['Authorization'] = `Bearer ${await this.#auth.token()}`;
103
+ }
104
+ let status;
105
+ let raw;
106
+ let retryAfterHeader;
107
+ try {
108
+ const init = {
109
+ method,
110
+ headers,
111
+ signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS),
112
+ };
113
+ if (options.body !== undefined) {
114
+ headers['content-type'] = 'application/json';
115
+ init.body = JSON.stringify(options.body);
116
+ }
117
+ const resp = await fetch(url, init);
118
+ status = resp.status;
119
+ raw = await resp.text();
120
+ retryAfterHeader = resp.headers.get('Retry-After');
121
+ }
122
+ catch (exc) {
123
+ // NOTHING about `exc` is logged or attached (SDK-33): a fetch failure
124
+ // carries a `cause` chain that can reach back to the request, and this
125
+ // request has an Authorization header on it. Only the bare message.
126
+ const detail = exc instanceof Error ? exc.message : String(exc);
127
+ if (attempt < MAX_ATTEMPTS) {
128
+ await this.sleep(backoffDelayMs(attempt));
129
+ continue;
130
+ }
131
+ throw new errors.TransportError(detail);
132
+ }
133
+ if (status < 400)
134
+ return decodeObject(raw);
135
+ const envelope = decodeObject(raw);
136
+ const retryAfter = retryAfterMs(retryAfterHeader, envelope);
137
+ const exc = errors.fromEnvelope(envelope, { status, retryAfter: retryAfter / 1000 });
138
+ if (exc instanceof errors.AuthenticationError) {
139
+ const expiredOrInvalid = exc.code === 'access_token_expired' || exc.code === 'access_token_invalid';
140
+ if (authenticated && expiredOrInvalid && retryAuth && !authRetried && this.#auth !== null) {
141
+ authRetried = true;
142
+ await this.#auth.refresh();
143
+ continue;
144
+ }
145
+ throw exc;
146
+ }
147
+ if (exc instanceof errors.RateLimitError) {
148
+ // Only the generic `rate_limited` retries here. `pair_rate_limited` and
149
+ // `sync_rate_limited` are owned by their callers (auth.pair, bot.ts's
150
+ // background sync per SDK-35) — retrying them here would make
151
+ // syncCommands swallow SyncRateLimited, which it must not.
152
+ if (exc.constructor === errors.RateLimited && attempt < MAX_ATTEMPTS) {
153
+ this.#logger.warn(`rate limited, retrying after ${(retryAfter / 1000).toFixed(1)}s`);
154
+ await this.sleep(retryAfter);
155
+ continue;
156
+ }
157
+ throw exc;
158
+ }
159
+ if (exc instanceof errors.APIError) {
160
+ if (attempt < MAX_ATTEMPTS) {
161
+ await this.sleep(backoffDelayMs(attempt));
162
+ continue;
163
+ }
164
+ throw exc;
165
+ }
166
+ // invalid_request_error, permission_error: never retried.
167
+ throw exc;
168
+ }
169
+ }
170
+ /**
171
+ * `replyTo` is a `msg_` reference and is OMITTED when absent — the field is
172
+ * optional on the wire (CONTRACT-V1 §5.0) and a `null` there is a
173
+ * `parameter_invalid` waiting to happen.
174
+ */
175
+ async sendMessage(chat, text, idempotencyKey, replyTo) {
176
+ const body = { chat, text };
177
+ if (replyTo != null && replyTo !== '')
178
+ body['reply_to'] = replyTo;
179
+ return this.request('POST', '/v1/messages', { body, idempotencyKey });
180
+ }
181
+ async syncCommands(bot, commands) {
182
+ return this.request('PUT', `/v1/bots/${bot}/commands`, {
183
+ body: { commands },
184
+ idempotencyKey: randomUUID(),
185
+ });
186
+ }
187
+ async listCommands(bot) {
188
+ return this.request('GET', `/v1/bots/${bot}/commands`);
189
+ }
190
+ gatewayUrl() {
191
+ let base;
192
+ if (this.#host.startsWith('https://'))
193
+ base = 'wss://' + this.#host.slice('https://'.length);
194
+ else if (this.#host.startsWith('http://'))
195
+ base = 'ws://' + this.#host.slice('http://'.length);
196
+ else
197
+ base = this.#host;
198
+ return base + '/v1/gateway';
199
+ }
200
+ }
201
+ //# sourceMappingURL=http.js.map