@cerebro-labs/agentnava-sdk 0.26.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.
Files changed (67) hide show
  1. package/LICENSE +202 -0
  2. package/NOTICE +12 -0
  3. package/README.md +230 -0
  4. package/agent.d.ts +285 -0
  5. package/agent.js +394 -0
  6. package/agent.js.map +1 -0
  7. package/attach.d.ts +49 -0
  8. package/attach.js +115 -0
  9. package/attach.js.map +1 -0
  10. package/connection-status.d.ts +28 -0
  11. package/connection-status.js +61 -0
  12. package/connection-status.js.map +1 -0
  13. package/connection.d.ts +89 -0
  14. package/connection.js +143 -0
  15. package/connection.js.map +1 -0
  16. package/conversation.d.ts +177 -0
  17. package/conversation.js +348 -0
  18. package/conversation.js.map +1 -0
  19. package/end-user.d.ts +159 -0
  20. package/end-user.js +209 -0
  21. package/end-user.js.map +1 -0
  22. package/errors.d.ts +43 -0
  23. package/errors.js +55 -0
  24. package/errors.js.map +1 -0
  25. package/http.d.ts +32 -0
  26. package/http.js +192 -0
  27. package/http.js.map +1 -0
  28. package/import-tools.d.ts +282 -0
  29. package/import-tools.js +686 -0
  30. package/import-tools.js.map +1 -0
  31. package/index.d.ts +16 -0
  32. package/index.js +38 -0
  33. package/index.js.map +1 -0
  34. package/knowledge-base.d.ts +165 -0
  35. package/knowledge-base.js +274 -0
  36. package/knowledge-base.js.map +1 -0
  37. package/load-agent-dir.d.ts +17 -0
  38. package/load-agent-dir.js +192 -0
  39. package/load-agent-dir.js.map +1 -0
  40. package/package.json +32 -0
  41. package/project.d.ts +94 -0
  42. package/project.js +155 -0
  43. package/project.js.map +1 -0
  44. package/secret.d.ts +45 -0
  45. package/secret.js +69 -0
  46. package/secret.js.map +1 -0
  47. package/templates-inline.d.ts +2 -0
  48. package/templates-inline.js +16 -0
  49. package/templates-inline.js.map +1 -0
  50. package/templates.d.ts +16 -0
  51. package/templates.js +32 -0
  52. package/templates.js.map +1 -0
  53. package/turn.d.ts +11 -0
  54. package/turn.js +244 -0
  55. package/turn.js.map +1 -0
  56. package/types.d.ts +485 -0
  57. package/types.js +4 -0
  58. package/types.js.map +1 -0
  59. package/version.d.ts +1 -0
  60. package/version.js +5 -0
  61. package/version.js.map +1 -0
  62. package/workflows.d.ts +36 -0
  63. package/workflows.js +101 -0
  64. package/workflows.js.map +1 -0
  65. package/workspace.d.ts +290 -0
  66. package/workspace.js +390 -0
  67. package/workspace.js.map +1 -0
package/end-user.d.ts ADDED
@@ -0,0 +1,159 @@
1
+ import { Connection } from './connection.ts';
2
+ import { Secret } from './secret.ts';
3
+ import { Conversation } from './conversation.ts';
4
+ import type { Http } from './http.ts';
5
+ /**
6
+ * One of YOUR end users, as this platform sees them.
7
+ *
8
+ * WHY THE NAME IS `EndUser` AND NOT `User`. There are two populations of people
9
+ * in this product, and calling both of them "user" was a bug waiting to be
10
+ * written:
11
+ *
12
+ * | | workspace member | END USER |
13
+ * |---|---|---|
14
+ * | who | your colleague, on a seat | the person your application serves |
15
+ * | signs in to this platform | yes | NEVER |
16
+ * | who issues the id | we do | YOUR database |
17
+ * | do we authenticate it | yes | no, deliberately |
18
+ * | in this SDK | `ws.members()` | `ws.endUser(id)` |
19
+ *
20
+ * They were both spelled `userId`, so `ws.members()` handed you an id that
21
+ * `agent.start()` would accept without complaint and label a conversation with
22
+ * a teammate's internal platform id. It could never have errored, because an
23
+ * end-user id is never checked against anything. The two names now make that
24
+ * call impossible to write by accident.
25
+ *
26
+ * NOT `Customer`, which was tried and reverted. Two reasons. "Customer" already
27
+ * means the party that BUYS this platform, in our own strategy documents and in
28
+ * `subscriptions.stripe_customer_id`, so the word points the other way. And it
29
+ * is wrong for the common case: an enterprise deploying an internal workflow
30
+ * agent serves its own EMPLOYEES, who are not anybody's customers.
31
+ *
32
+ * WHY THIS OBJECT EXISTS. You are building an application for many people.
33
+ * Ananya has her own Gmail, her own conversations and her own history, and so
34
+ * do the other ten thousand. Every call you make is on behalf of one of them.
35
+ *
36
+ * Without this, the person is an argument: `endUserId` threaded through
37
+ * `connections.create`, `secrets.create`, `conversations` and `start`, and
38
+ * forgotten in exactly one of them one day. With it, you say who once and the
39
+ * rest follows:
40
+ *
41
+ * ```ts
42
+ * const ananya = ws.endUser(row.userId); // no request
43
+ *
44
+ * const gmail = await ananya.connections.create({ provider: 'gmail' });
45
+ * showToUser(gmail.url);
46
+ * await gmail.waitUntilConnected();
47
+ *
48
+ * const conversation = await agent.start({ endUserId: ananya.id });
49
+ * await conversation.attach(gmail); // EXPLICIT. Nothing is implied.
50
+ * await conversation.ask('what did I miss this morning?');
51
+ *
52
+ * await ananya.conversations(); // everything of hers, any agent
53
+ * ```
54
+ *
55
+ * NAMING AN END USER GRANTS NOTHING. `start({ endUserId })` labels the
56
+ * conversation so it can be listed back to them; it does not hand the agent
57
+ * their accounts. The `attach` is the grant, and it is a line you can see.
58
+ *
59
+ * An earlier version resolved a person's credentials automatically from that
60
+ * label. It was wrong even when it picked correctly: reading the code told you
61
+ * nothing about what the agent could reach, and one mistyped id silently swapped
62
+ * whose mailbox a turn read.
63
+ *
64
+ * THE ID IS YOURS. A row id from your database, opaque to us, and we never
65
+ * authenticate it. We are not an identity provider and do not want to be. It
66
+ * also means passing the wrong one hands that person somebody else's mailbox,
67
+ * which is a sharper consequence than the same mistake has for a chat list.
68
+ *
69
+ * Holding one makes NO request.
70
+ */
71
+ export declare class EndUser {
72
+ #private;
73
+ readonly id: string;
74
+ constructor(http: Http, id: string);
75
+ /**
76
+ * This person's own third-party accounts.
77
+ *
78
+ * Connected ONCE, in their browser. After that the account is theirs and
79
+ * stays theirs: you attach it to whichever conversations should use it,
80
+ * rather than sending them through a sign-in again per thread. That is the
81
+ * saving. The attach is not.
82
+ *
83
+ * Listing here is the CALLER'S view, for showing someone what they have
84
+ * connected and for revoking it when they leave. It is not what a turn
85
+ * consults: a turn sees only what was attached to it.
86
+ */
87
+ readonly connections: {
88
+ /** Begin connecting. Returns a `Connection` carrying the url to send
89
+ * them to; `waitUntilConnected()` tells you when they are done. */
90
+ create: (input: {
91
+ provider: string;
92
+ }) => Promise<Connection>;
93
+ /** Theirs alone. The shared workspace and agent accounts are not here;
94
+ * `ws.connections.list()` is the view that shows those. */
95
+ list: () => Promise<Connection[]>;
96
+ };
97
+ /**
98
+ * Credentials that belong to THIS PERSON: their API key for a system you
99
+ * integrate with, their token for a service only they have an account on.
100
+ *
101
+ * THIS WAS ABSENT UNTIL THERE WAS A WAY TO USE IT. A credential reaches a
102
+ * turn only by being ATTACHED. A connection could be, by id; a secret could
103
+ * not, because binding one took its VALUE, and you do not hold the value of a
104
+ * secret the platform stored for you. So a per-person secret would have been
105
+ * a surface that accepted writes, listed them back, and was read by nothing.
106
+ * It was left out rather than shipped looking like a feature.
107
+ *
108
+ * `sessionBindings.secretIds` is what closed it, and attaching is still an
109
+ * explicit line:
110
+ *
111
+ * ```ts
112
+ * const ananya = ws.endUser(row.userId);
113
+ * const key = await ananya.secrets.create({ name: 'ZENDESK_TOKEN', value: token });
114
+ *
115
+ * const conversation = await agent.start({ endUserId: ananya.id });
116
+ * await conversation.attach(key); // EXPLICIT. Nothing is implied.
117
+ * ```
118
+ *
119
+ * TWO THINGS THE PLATFORM ENFORCES, neither of which you can turn off:
120
+ * the agent must DECLARE that secret name at session scope, so attaching by
121
+ * id is not a way around the allowlist; and a secret belonging to one end
122
+ * user can only be attached to a conversation launched for that same person,
123
+ * so one mistyped id cannot hand Ananya's key to somebody else's turn.
124
+ */
125
+ readonly secrets: {
126
+ /** Store a credential for this person. The value is encrypted on arrival
127
+ * and never handed back, which is why attaching uses the id. */
128
+ create: (input: {
129
+ name: string;
130
+ value: string;
131
+ description?: string;
132
+ agentId?: string;
133
+ }) => Promise<Secret>;
134
+ /** This person's secrets, values excluded. The workspace's own are not in
135
+ * here: `ws.secrets.list()` answers that. */
136
+ list: () => Promise<Secret[]>;
137
+ };
138
+ /**
139
+ * Everything this person has said, ACROSS EVERY AGENT, newest first.
140
+ *
141
+ * `agent.conversations({ endUser })` answers the narrower question, one agent
142
+ * at a time. This is the one an application renders as "your chats", and it
143
+ * is the only listing in this SDK with a real cursor: pass `before` from the
144
+ * previous page to keep going, rather than being capped at 200.
145
+ */
146
+ conversations(options?: {
147
+ limit?: number;
148
+ before?: string;
149
+ }): Promise<Conversation[]>;
150
+ /**
151
+ * Cut this person off.
152
+ *
153
+ * Revokes every account they connected, so every conversation of theirs
154
+ * stops acting as them from the next turn. What off-boarding calls, and the
155
+ * reason it is one call rather than a loop the caller has to remember to
156
+ * write.
157
+ */
158
+ revokeConnections(): Promise<void>;
159
+ }
package/end-user.js ADDED
@@ -0,0 +1,209 @@
1
+ // One of YOUR end users: a person your application serves, who never signs in here.
2
+ import { Connection } from "./connection.js";
3
+ import { toConnectionStatus } from "./connection-status.js";
4
+ import { Secret } from "./secret.js";
5
+ import { Conversation } from "./conversation.js";
6
+ /**
7
+ * One of YOUR end users, as this platform sees them.
8
+ *
9
+ * WHY THE NAME IS `EndUser` AND NOT `User`. There are two populations of people
10
+ * in this product, and calling both of them "user" was a bug waiting to be
11
+ * written:
12
+ *
13
+ * | | workspace member | END USER |
14
+ * |---|---|---|
15
+ * | who | your colleague, on a seat | the person your application serves |
16
+ * | signs in to this platform | yes | NEVER |
17
+ * | who issues the id | we do | YOUR database |
18
+ * | do we authenticate it | yes | no, deliberately |
19
+ * | in this SDK | `ws.members()` | `ws.endUser(id)` |
20
+ *
21
+ * They were both spelled `userId`, so `ws.members()` handed you an id that
22
+ * `agent.start()` would accept without complaint and label a conversation with
23
+ * a teammate's internal platform id. It could never have errored, because an
24
+ * end-user id is never checked against anything. The two names now make that
25
+ * call impossible to write by accident.
26
+ *
27
+ * NOT `Customer`, which was tried and reverted. Two reasons. "Customer" already
28
+ * means the party that BUYS this platform, in our own strategy documents and in
29
+ * `subscriptions.stripe_customer_id`, so the word points the other way. And it
30
+ * is wrong for the common case: an enterprise deploying an internal workflow
31
+ * agent serves its own EMPLOYEES, who are not anybody's customers.
32
+ *
33
+ * WHY THIS OBJECT EXISTS. You are building an application for many people.
34
+ * Ananya has her own Gmail, her own conversations and her own history, and so
35
+ * do the other ten thousand. Every call you make is on behalf of one of them.
36
+ *
37
+ * Without this, the person is an argument: `endUserId` threaded through
38
+ * `connections.create`, `secrets.create`, `conversations` and `start`, and
39
+ * forgotten in exactly one of them one day. With it, you say who once and the
40
+ * rest follows:
41
+ *
42
+ * ```ts
43
+ * const ananya = ws.endUser(row.userId); // no request
44
+ *
45
+ * const gmail = await ananya.connections.create({ provider: 'gmail' });
46
+ * showToUser(gmail.url);
47
+ * await gmail.waitUntilConnected();
48
+ *
49
+ * const conversation = await agent.start({ endUserId: ananya.id });
50
+ * await conversation.attach(gmail); // EXPLICIT. Nothing is implied.
51
+ * await conversation.ask('what did I miss this morning?');
52
+ *
53
+ * await ananya.conversations(); // everything of hers, any agent
54
+ * ```
55
+ *
56
+ * NAMING AN END USER GRANTS NOTHING. `start({ endUserId })` labels the
57
+ * conversation so it can be listed back to them; it does not hand the agent
58
+ * their accounts. The `attach` is the grant, and it is a line you can see.
59
+ *
60
+ * An earlier version resolved a person's credentials automatically from that
61
+ * label. It was wrong even when it picked correctly: reading the code told you
62
+ * nothing about what the agent could reach, and one mistyped id silently swapped
63
+ * whose mailbox a turn read.
64
+ *
65
+ * THE ID IS YOURS. A row id from your database, opaque to us, and we never
66
+ * authenticate it. We are not an identity provider and do not want to be. It
67
+ * also means passing the wrong one hands that person somebody else's mailbox,
68
+ * which is a sharper consequence than the same mistake has for a chat list.
69
+ *
70
+ * Holding one makes NO request.
71
+ */
72
+ export class EndUser {
73
+ id;
74
+ #http;
75
+ constructor(http, id) {
76
+ this.#http = http;
77
+ this.id = id;
78
+ }
79
+ /**
80
+ * This person's own third-party accounts.
81
+ *
82
+ * Connected ONCE, in their browser. After that the account is theirs and
83
+ * stays theirs: you attach it to whichever conversations should use it,
84
+ * rather than sending them through a sign-in again per thread. That is the
85
+ * saving. The attach is not.
86
+ *
87
+ * Listing here is the CALLER'S view, for showing someone what they have
88
+ * connected and for revoking it when they leave. It is not what a turn
89
+ * consults: a turn sees only what was attached to it.
90
+ */
91
+ connections = {
92
+ /** Begin connecting. Returns a `Connection` carrying the url to send
93
+ * them to; `waitUntilConnected()` tells you when they are done. */
94
+ create: async (input) => {
95
+ const res = await this.#http.post('/v1/connections/connect', { provider: input.provider, endUserId: this.id });
96
+ return new Connection(this.#http, res.connectionId,
97
+ // NOT `as never`. That cast was here to let `scope: 'user'` through,
98
+ // a value outside ConnectionStatus's own type, and it disabled
99
+ // checking on every other field at the same time.
100
+ {
101
+ id: res.connectionId,
102
+ provider: input.provider,
103
+ connected: false,
104
+ declared: true,
105
+ required: false,
106
+ endUserId: this.id,
107
+ }, res.authUrl);
108
+ },
109
+ /** Theirs alone. The shared workspace and agent accounts are not here;
110
+ * `ws.connections.list()` is the view that shows those. */
111
+ list: async () => {
112
+ // WireConnection, not ConnectionStatus. The endpoint sends the wire
113
+ // shape, and typing it as the SDK shape is what hid the whole bug:
114
+ // `connected` is never sent, so every account here reported
115
+ // `connected === undefined` while type-checking as a boolean.
116
+ const res = await this.#http.get('/v1/connections', {
117
+ endUserId: this.id,
118
+ });
119
+ return (res.connections ?? [])
120
+ .filter((c) => c.id)
121
+ .map((c) => new Connection(this.#http, c.id, toConnectionStatus(c)));
122
+ },
123
+ };
124
+ /**
125
+ * Credentials that belong to THIS PERSON: their API key for a system you
126
+ * integrate with, their token for a service only they have an account on.
127
+ *
128
+ * THIS WAS ABSENT UNTIL THERE WAS A WAY TO USE IT. A credential reaches a
129
+ * turn only by being ATTACHED. A connection could be, by id; a secret could
130
+ * not, because binding one took its VALUE, and you do not hold the value of a
131
+ * secret the platform stored for you. So a per-person secret would have been
132
+ * a surface that accepted writes, listed them back, and was read by nothing.
133
+ * It was left out rather than shipped looking like a feature.
134
+ *
135
+ * `sessionBindings.secretIds` is what closed it, and attaching is still an
136
+ * explicit line:
137
+ *
138
+ * ```ts
139
+ * const ananya = ws.endUser(row.userId);
140
+ * const key = await ananya.secrets.create({ name: 'ZENDESK_TOKEN', value: token });
141
+ *
142
+ * const conversation = await agent.start({ endUserId: ananya.id });
143
+ * await conversation.attach(key); // EXPLICIT. Nothing is implied.
144
+ * ```
145
+ *
146
+ * TWO THINGS THE PLATFORM ENFORCES, neither of which you can turn off:
147
+ * the agent must DECLARE that secret name at session scope, so attaching by
148
+ * id is not a way around the allowlist; and a secret belonging to one end
149
+ * user can only be attached to a conversation launched for that same person,
150
+ * so one mistyped id cannot hand Ananya's key to somebody else's turn.
151
+ */
152
+ secrets = {
153
+ /** Store a credential for this person. The value is encrypted on arrival
154
+ * and never handed back, which is why attaching uses the id. */
155
+ create: async (input) => {
156
+ // FIELDS PICKED, never the input object forwarded. Removing a field
157
+ // from a type does not stop a JavaScript caller sending it, and
158
+ // forwarding wholesale is how `endUserId` kept reaching the API after
159
+ // it had supposedly been removed.
160
+ const res = await this.#http.post('/v1/secrets', {
161
+ name: input.name,
162
+ value: input.value,
163
+ endUserId: this.id,
164
+ ...(input.description !== undefined && { description: input.description }),
165
+ ...(input.agentId !== undefined && { agentId: input.agentId }),
166
+ });
167
+ const meta = res.secret ?? res;
168
+ return new Secret(this.#http, meta.id, meta);
169
+ },
170
+ /** This person's secrets, values excluded. The workspace's own are not in
171
+ * here: `ws.secrets.list()` answers that. */
172
+ list: async () => {
173
+ const res = await this.#http.get('/v1/secrets', {
174
+ end_user_id: this.id,
175
+ });
176
+ return (res.secrets ?? []).map((m) => new Secret(this.#http, m.id, m));
177
+ },
178
+ };
179
+ /**
180
+ * Everything this person has said, ACROSS EVERY AGENT, newest first.
181
+ *
182
+ * `agent.conversations({ endUser })` answers the narrower question, one agent
183
+ * at a time. This is the one an application renders as "your chats", and it
184
+ * is the only listing in this SDK with a real cursor: pass `before` from the
185
+ * previous page to keep going, rather than being capped at 200.
186
+ */
187
+ async conversations(options = {}) {
188
+ const res = await this.#http.get('/v1/conversations', {
189
+ end_user_id: this.id,
190
+ ...(options.limit !== undefined && { limit: options.limit }),
191
+ ...(options.before && { before: options.before }),
192
+ });
193
+ return (res.conversations ?? []).map((c) => new Conversation(this.#http, c.id, c));
194
+ }
195
+ /**
196
+ * Cut this person off.
197
+ *
198
+ * Revokes every account they connected, so every conversation of theirs
199
+ * stops acting as them from the next turn. What off-boarding calls, and the
200
+ * reason it is one call rather than a loop the caller has to remember to
201
+ * write.
202
+ */
203
+ async revokeConnections() {
204
+ for (const connection of await this.connections.list()) {
205
+ await connection.revoke();
206
+ }
207
+ }
208
+ }
209
+ //# sourceMappingURL=end-user.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"end-user.js","sourceRoot":"","sources":["../src/end-user.ts"],"names":[],"mappings":"AAAA,oFAAoF;AAEpF,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,kBAAkB,EAAuB,MAAM,wBAAwB,CAAC;AACjF,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAIjD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiEG;AACH,MAAM,OAAO,OAAO;IACV,EAAE,CAAS;IACX,KAAK,CAAO;IAErB,YAAY,IAAU,EAAE,EAAU;QACjC,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;QAClB,IAAI,CAAC,EAAE,GAAG,EAAE,CAAC;IACd,CAAC;IAED;;;;;;;;;;;OAWG;IACM,WAAW,GAAG;QACtB;4EACoE;QACpE,MAAM,EAAE,KAAK,EAAE,KAA2B,EAAuB,EAAE;YAClE,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,IAAI,CAChC,yBAAyB,EACzB,EAAE,QAAQ,EAAE,KAAK,CAAC,QAAQ,EAAE,SAAS,EAAE,IAAI,CAAC,EAAE,EAAE,CAChD,CAAC;YACF,OAAO,IAAI,UAAU,CACpB,IAAI,CAAC,KAAK,EACV,GAAG,CAAC,YAAY;YAChB,qEAAqE;YACrE,+DAA+D;YAC/D,kDAAkD;YAClD;gBACC,EAAE,EAAE,GAAG,CAAC,YAAY;gBACpB,QAAQ,EAAE,KAAK,CAAC,QAAQ;gBACxB,SAAS,EAAE,KAAK;gBAChB,QAAQ,EAAE,IAAI;gBACd,QAAQ,EAAE,KAAK;gBACf,SAAS,EAAE,IAAI,CAAC,EAAE;aAClB,EACD,GAAG,CAAC,OAAO,CACX,CAAC;QACH,CAAC;QAED;oEAC4D;QAC5D,IAAI,EAAE,KAAK,IAA2B,EAAE;YACvC,oEAAoE;YACpE,mEAAmE;YACnE,4DAA4D;YAC5D,8DAA8D;YAC9D,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,GAAG,CAAoC,iBAAiB,EAAE;gBACtF,SAAS,EAAE,IAAI,CAAC,EAAE;aAClB,CAAC,CAAC;YACH,OAAO,CAAC,GAAG,CAAC,WAAW,IAAI,EAAE,CAAC;iBAC5B,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;iBACnB,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,UAAU,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC,EAAE,EAAE,kBAAkB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACvE,CAAC;KACD,CAAC;IAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;OA2BG;IACM,OAAO,GAAG;QAClB;yEACiE;QACjE,MAAM,EAAE,KAAK,EAAE,KAKd,EAAmB,EAAE;YACrB,oEAAoE;YACpE,gEAAgE;YAChE,sEAAsE;YACtE,kCAAkC;YAClC,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,IAAI,CAAuC,aAAa,EAAE;gBACtF,IAAI,EAAE,KAAK,CAAC,IAAI;gBAChB,KAAK,EAAE,KAAK,CAAC,KAAK;gBAClB,SAAS,EAAE,IAAI,CAAC,EAAE;gBAClB,GAAG,CAAC,KAAK,CAAC,WAAW,KAAK,SAAS,IAAI,EAAE,WAAW,EAAE,KAAK,CAAC,WAAW,EAAE,CAAC;gBAC1E,GAAG,CAAC,KAAK,CAAC,OAAO,KAAK,SAAS,IAAI,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,CAAC;aAC9D,CAAC,CAAC;YACH,MAAM,IAAI,GAAG,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC;YAC/B,OAAO,IAAI,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;QAC9C,CAAC;QACD;sDAC8C;QAC9C,IAAI,EAAE,KAAK,IAAuB,EAAE;YACnC,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,GAAG,CAA4B,aAAa,EAAE;gBAC1E,WAAW,EAAE,IAAI,CAAC,EAAE;aACpB,CAAC,CAAC;YACH,OAAO,CAAC,GAAG,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC;QACxE,CAAC;KACD,CAAC;IAEF;;;;;;;OAOG;IACH,KAAK,CAAC,aAAa,CAAC,UAA+C,EAAE;QACpE,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,GAAG,CAA6C,mBAAmB,EAAE;YACjG,WAAW,EAAE,IAAI,CAAC,EAAE;YACpB,GAAG,CAAC,OAAO,CAAC,KAAK,KAAK,SAAS,IAAI,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,CAAC;YAC5D,GAAG,CAAC,OAAO,CAAC,MAAM,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC;SACjD,CAAC,CAAC;QACH,OAAO,CAAC,GAAG,CAAC,aAAa,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,YAAY,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC;IACpF,CAAC;IAED;;;;;;;OAOG;IACH,KAAK,CAAC,iBAAiB;QACtB,KAAK,MAAM,UAAU,IAAI,MAAM,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,EAAE,CAAC;YACxD,MAAM,UAAU,CAAC,MAAM,EAAE,CAAC;QAC3B,CAAC;IACF,CAAC;CACD","sourcesContent":["// One of YOUR end users: a person your application serves, who never signs in here.\n\nimport { Connection } from './connection.ts';\nimport { toConnectionStatus, type WireConnection } from './connection-status.ts';\nimport { Secret } from './secret.ts';\nimport { Conversation } from './conversation.ts';\nimport type { Http } from './http.ts';\nimport type { AgentConversationData, ConnectionStatus, SecretMeta } from './types.ts';\n\n/**\n * One of YOUR end users, as this platform sees them.\n *\n * WHY THE NAME IS `EndUser` AND NOT `User`. There are two populations of people\n * in this product, and calling both of them \"user\" was a bug waiting to be\n * written:\n *\n * | | workspace member | END USER |\n * |---|---|---|\n * | who | your colleague, on a seat | the person your application serves |\n * | signs in to this platform | yes | NEVER |\n * | who issues the id | we do | YOUR database |\n * | do we authenticate it | yes | no, deliberately |\n * | in this SDK | `ws.members()` | `ws.endUser(id)` |\n *\n * They were both spelled `userId`, so `ws.members()` handed you an id that\n * `agent.start()` would accept without complaint and label a conversation with\n * a teammate's internal platform id. It could never have errored, because an\n * end-user id is never checked against anything. The two names now make that\n * call impossible to write by accident.\n *\n * NOT `Customer`, which was tried and reverted. Two reasons. \"Customer\" already\n * means the party that BUYS this platform, in our own strategy documents and in\n * `subscriptions.stripe_customer_id`, so the word points the other way. And it\n * is wrong for the common case: an enterprise deploying an internal workflow\n * agent serves its own EMPLOYEES, who are not anybody's customers.\n *\n * WHY THIS OBJECT EXISTS. You are building an application for many people.\n * Ananya has her own Gmail, her own conversations and her own history, and so\n * do the other ten thousand. Every call you make is on behalf of one of them.\n *\n * Without this, the person is an argument: `endUserId` threaded through\n * `connections.create`, `secrets.create`, `conversations` and `start`, and\n * forgotten in exactly one of them one day. With it, you say who once and the\n * rest follows:\n *\n * ```ts\n * const ananya = ws.endUser(row.userId); // no request\n *\n * const gmail = await ananya.connections.create({ provider: 'gmail' });\n * showToUser(gmail.url);\n * await gmail.waitUntilConnected();\n *\n * const conversation = await agent.start({ endUserId: ananya.id });\n * await conversation.attach(gmail); // EXPLICIT. Nothing is implied.\n * await conversation.ask('what did I miss this morning?');\n *\n * await ananya.conversations(); // everything of hers, any agent\n * ```\n *\n * NAMING AN END USER GRANTS NOTHING. `start({ endUserId })` labels the\n * conversation so it can be listed back to them; it does not hand the agent\n * their accounts. The `attach` is the grant, and it is a line you can see.\n *\n * An earlier version resolved a person's credentials automatically from that\n * label. It was wrong even when it picked correctly: reading the code told you\n * nothing about what the agent could reach, and one mistyped id silently swapped\n * whose mailbox a turn read.\n *\n * THE ID IS YOURS. A row id from your database, opaque to us, and we never\n * authenticate it. We are not an identity provider and do not want to be. It\n * also means passing the wrong one hands that person somebody else's mailbox,\n * which is a sharper consequence than the same mistake has for a chat list.\n *\n * Holding one makes NO request.\n */\nexport class EndUser {\n\treadonly id: string;\n\treadonly #http: Http;\n\n\tconstructor(http: Http, id: string) {\n\t\tthis.#http = http;\n\t\tthis.id = id;\n\t}\n\n\t/**\n\t * This person's own third-party accounts.\n\t *\n\t * Connected ONCE, in their browser. After that the account is theirs and\n\t * stays theirs: you attach it to whichever conversations should use it,\n\t * rather than sending them through a sign-in again per thread. That is the\n\t * saving. The attach is not.\n\t *\n\t * Listing here is the CALLER'S view, for showing someone what they have\n\t * connected and for revoking it when they leave. It is not what a turn\n\t * consults: a turn sees only what was attached to it.\n\t */\n\treadonly connections = {\n\t\t/** Begin connecting. Returns a `Connection` carrying the url to send\n\t\t * them to; `waitUntilConnected()` tells you when they are done. */\n\t\tcreate: async (input: { provider: string }): Promise<Connection> => {\n\t\t\tconst res = await this.#http.post<{ authUrl: string; connectionId: string }>(\n\t\t\t\t'/v1/connections/connect',\n\t\t\t\t{ provider: input.provider, endUserId: this.id },\n\t\t\t);\n\t\t\treturn new Connection(\n\t\t\t\tthis.#http,\n\t\t\t\tres.connectionId,\n\t\t\t\t// NOT `as never`. That cast was here to let `scope: 'user'` through,\n\t\t\t\t// a value outside ConnectionStatus's own type, and it disabled\n\t\t\t\t// checking on every other field at the same time.\n\t\t\t\t{\n\t\t\t\t\tid: res.connectionId,\n\t\t\t\t\tprovider: input.provider,\n\t\t\t\t\tconnected: false,\n\t\t\t\t\tdeclared: true,\n\t\t\t\t\trequired: false,\n\t\t\t\t\tendUserId: this.id,\n\t\t\t\t},\n\t\t\t\tres.authUrl,\n\t\t\t);\n\t\t},\n\n\t\t/** Theirs alone. The shared workspace and agent accounts are not here;\n\t\t * `ws.connections.list()` is the view that shows those. */\n\t\tlist: async (): Promise<Connection[]> => {\n\t\t\t// WireConnection, not ConnectionStatus. The endpoint sends the wire\n\t\t\t// shape, and typing it as the SDK shape is what hid the whole bug:\n\t\t\t// `connected` is never sent, so every account here reported\n\t\t\t// `connected === undefined` while type-checking as a boolean.\n\t\t\tconst res = await this.#http.get<{ connections: WireConnection[] }>('/v1/connections', {\n\t\t\t\tendUserId: this.id,\n\t\t\t});\n\t\t\treturn (res.connections ?? [])\n\t\t\t\t.filter((c) => c.id)\n\t\t\t\t.map((c) => new Connection(this.#http, c.id, toConnectionStatus(c)));\n\t\t},\n\t};\n\n\t/**\n\t * Credentials that belong to THIS PERSON: their API key for a system you\n\t * integrate with, their token for a service only they have an account on.\n\t *\n\t * THIS WAS ABSENT UNTIL THERE WAS A WAY TO USE IT. A credential reaches a\n\t * turn only by being ATTACHED. A connection could be, by id; a secret could\n\t * not, because binding one took its VALUE, and you do not hold the value of a\n\t * secret the platform stored for you. So a per-person secret would have been\n\t * a surface that accepted writes, listed them back, and was read by nothing.\n\t * It was left out rather than shipped looking like a feature.\n\t *\n\t * `sessionBindings.secretIds` is what closed it, and attaching is still an\n\t * explicit line:\n\t *\n\t * ```ts\n\t * const ananya = ws.endUser(row.userId);\n\t * const key = await ananya.secrets.create({ name: 'ZENDESK_TOKEN', value: token });\n\t *\n\t * const conversation = await agent.start({ endUserId: ananya.id });\n\t * await conversation.attach(key); // EXPLICIT. Nothing is implied.\n\t * ```\n\t *\n\t * TWO THINGS THE PLATFORM ENFORCES, neither of which you can turn off:\n\t * the agent must DECLARE that secret name at session scope, so attaching by\n\t * id is not a way around the allowlist; and a secret belonging to one end\n\t * user can only be attached to a conversation launched for that same person,\n\t * so one mistyped id cannot hand Ananya's key to somebody else's turn.\n\t */\n\treadonly secrets = {\n\t\t/** Store a credential for this person. The value is encrypted on arrival\n\t\t * and never handed back, which is why attaching uses the id. */\n\t\tcreate: async (input: {\n\t\t\tname: string;\n\t\t\tvalue: string;\n\t\t\tdescription?: string;\n\t\t\tagentId?: string;\n\t\t}): Promise<Secret> => {\n\t\t\t// FIELDS PICKED, never the input object forwarded. Removing a field\n\t\t\t// from a type does not stop a JavaScript caller sending it, and\n\t\t\t// forwarding wholesale is how `endUserId` kept reaching the API after\n\t\t\t// it had supposedly been removed.\n\t\t\tconst res = await this.#http.post<{ secret?: SecretMeta } & SecretMeta>('/v1/secrets', {\n\t\t\t\tname: input.name,\n\t\t\t\tvalue: input.value,\n\t\t\t\tendUserId: this.id,\n\t\t\t\t...(input.description !== undefined && { description: input.description }),\n\t\t\t\t...(input.agentId !== undefined && { agentId: input.agentId }),\n\t\t\t});\n\t\t\tconst meta = res.secret ?? res;\n\t\t\treturn new Secret(this.#http, meta.id, meta);\n\t\t},\n\t\t/** This person's secrets, values excluded. The workspace's own are not in\n\t\t * here: `ws.secrets.list()` answers that. */\n\t\tlist: async (): Promise<Secret[]> => {\n\t\t\tconst res = await this.#http.get<{ secrets: SecretMeta[] }>('/v1/secrets', {\n\t\t\t\tend_user_id: this.id,\n\t\t\t});\n\t\t\treturn (res.secrets ?? []).map((m) => new Secret(this.#http, m.id, m));\n\t\t},\n\t};\n\n\t/**\n\t * Everything this person has said, ACROSS EVERY AGENT, newest first.\n\t *\n\t * `agent.conversations({ endUser })` answers the narrower question, one agent\n\t * at a time. This is the one an application renders as \"your chats\", and it\n\t * is the only listing in this SDK with a real cursor: pass `before` from the\n\t * previous page to keep going, rather than being capped at 200.\n\t */\n\tasync conversations(options: { limit?: number; before?: string } = {}): Promise<Conversation[]> {\n\t\tconst res = await this.#http.get<{ conversations: AgentConversationData[] }>('/v1/conversations', {\n\t\t\tend_user_id: this.id,\n\t\t\t...(options.limit !== undefined && { limit: options.limit }),\n\t\t\t...(options.before && { before: options.before }),\n\t\t});\n\t\treturn (res.conversations ?? []).map((c) => new Conversation(this.#http, c.id, c));\n\t}\n\n\t/**\n\t * Cut this person off.\n\t *\n\t * Revokes every account they connected, so every conversation of theirs\n\t * stops acting as them from the next turn. What off-boarding calls, and the\n\t * reason it is one call rather than a loop the caller has to remember to\n\t * write.\n\t */\n\tasync revokeConnections(): Promise<void> {\n\t\tfor (const connection of await this.connections.list()) {\n\t\t\tawait connection.revoke();\n\t\t}\n\t}\n}\n"]}
package/errors.d.ts ADDED
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Every failure from this SDK is an AgentNavaError.
3
+ *
4
+ * One error type, not a hierarchy. A caller who wants to branch reads `code`,
5
+ * and a caller who wants to retry reads `retryable`; neither is helped by
6
+ * `instanceof NotFoundError`, and both are hurt by having to know which of nine
7
+ * classes a given call can throw.
8
+ */
9
+ export declare class AgentNavaError extends Error {
10
+ /** Stable machine-readable reason, e.g. 'agent_not_found'.
11
+ *
12
+ * BRANCH ON THIS, never on `message`. Messages are written for a person
13
+ * reading a log and will be reworded; codes are part of the contract. */
14
+ readonly code: string;
15
+ /** The HTTP status. 404 covers both "no such thing" and "not yours", so a
16
+ * caller probing ids cannot tell another customer's agent from one that
17
+ * never existed. There is deliberately no 403. */
18
+ readonly status: number;
19
+ /** Whether trying the identical request again could succeed.
20
+ *
21
+ * True for 5xx and 429 only. A 400 will fail the same way forever, and a
22
+ * 404 will not become found, so retrying either just turns one error into
23
+ * several. This is the only thing worth automating on. */
24
+ readonly retryable: boolean;
25
+ /** Seconds to wait, on a 429 that said so. */
26
+ readonly retryAfter?: number;
27
+ /** The request id from the response, when there was one. Quote it to us and
28
+ * we can find the exact request in our logs. */
29
+ readonly requestId?: string;
30
+ constructor(init: {
31
+ message: string;
32
+ code: string;
33
+ status: number;
34
+ retryAfter?: number;
35
+ requestId?: string;
36
+ });
37
+ }
38
+ /** A failure with no HTTP response behind it: DNS, a dropped socket, a timeout.
39
+ *
40
+ * Reported as status 0 rather than invented as a 5xx, because a request that
41
+ * never arrived is a different thing from one the server failed. It is
42
+ * retryable for the same reason a 5xx is: nothing about the request was wrong. */
43
+ export declare function networkError(message: string, cause?: unknown): AgentNavaError;
package/errors.js ADDED
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Every failure from this SDK is an AgentNavaError.
3
+ *
4
+ * One error type, not a hierarchy. A caller who wants to branch reads `code`,
5
+ * and a caller who wants to retry reads `retryable`; neither is helped by
6
+ * `instanceof NotFoundError`, and both are hurt by having to know which of nine
7
+ * classes a given call can throw.
8
+ */
9
+ export class AgentNavaError extends Error {
10
+ /** Stable machine-readable reason, e.g. 'agent_not_found'.
11
+ *
12
+ * BRANCH ON THIS, never on `message`. Messages are written for a person
13
+ * reading a log and will be reworded; codes are part of the contract. */
14
+ code;
15
+ /** The HTTP status. 404 covers both "no such thing" and "not yours", so a
16
+ * caller probing ids cannot tell another customer's agent from one that
17
+ * never existed. There is deliberately no 403. */
18
+ status;
19
+ /** Whether trying the identical request again could succeed.
20
+ *
21
+ * True for 5xx and 429 only. A 400 will fail the same way forever, and a
22
+ * 404 will not become found, so retrying either just turns one error into
23
+ * several. This is the only thing worth automating on. */
24
+ retryable;
25
+ /** Seconds to wait, on a 429 that said so. */
26
+ retryAfter;
27
+ /** The request id from the response, when there was one. Quote it to us and
28
+ * we can find the exact request in our logs. */
29
+ requestId;
30
+ constructor(init) {
31
+ super(init.message);
32
+ this.name = 'AgentNavaError';
33
+ this.code = init.code;
34
+ this.status = init.status;
35
+ this.retryable = init.status >= 500 || init.status === 429;
36
+ if (init.retryAfter !== undefined)
37
+ this.retryAfter = init.retryAfter;
38
+ if (init.requestId !== undefined)
39
+ this.requestId = init.requestId;
40
+ }
41
+ }
42
+ /** A failure with no HTTP response behind it: DNS, a dropped socket, a timeout.
43
+ *
44
+ * Reported as status 0 rather than invented as a 5xx, because a request that
45
+ * never arrived is a different thing from one the server failed. It is
46
+ * retryable for the same reason a 5xx is: nothing about the request was wrong. */
47
+ export function networkError(message, cause) {
48
+ const err = new AgentNavaError({ message, code: 'network_error', status: 0 });
49
+ // status 0 is not >= 500, so retryable has to be asserted here.
50
+ Object.defineProperty(err, 'retryable', { value: true, enumerable: true });
51
+ if (cause !== undefined)
52
+ Object.defineProperty(err, 'cause', { value: cause });
53
+ return err;
54
+ }
55
+ //# sourceMappingURL=errors.js.map
package/errors.js.map ADDED
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,MAAM,OAAO,cAAe,SAAQ,KAAK;IACxC;;;8EAG0E;IACjE,IAAI,CAAS;IAEtB;;uDAEmD;IAC1C,MAAM,CAAS;IAExB;;;;+DAI2D;IAClD,SAAS,CAAU;IAE5B,8CAA8C;IACrC,UAAU,CAAU;IAE7B;qDACiD;IACxC,SAAS,CAAU;IAE5B,YAAY,IAMX;QACA,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACpB,IAAI,CAAC,IAAI,GAAG,gBAAgB,CAAC;QAC7B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC;QACtB,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;QAC1B,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,MAAM,KAAK,GAAG,CAAC;QAC3D,IAAI,IAAI,CAAC,UAAU,KAAK,SAAS;YAAE,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,UAAU,CAAC;QACrE,IAAI,IAAI,CAAC,SAAS,KAAK,SAAS;YAAE,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC;IACnE,CAAC;CACD;AAED;;;;mFAImF;AACnF,MAAM,UAAU,YAAY,CAAC,OAAe,EAAE,KAAe;IAC5D,MAAM,GAAG,GAAG,IAAI,cAAc,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,eAAe,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC;IAC9E,gEAAgE;IAChE,MAAM,CAAC,cAAc,CAAC,GAAG,EAAE,WAAW,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC;IAC3E,IAAI,KAAK,KAAK,SAAS;QAAE,MAAM,CAAC,cAAc,CAAC,GAAG,EAAE,OAAO,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC;IAC/E,OAAO,GAAG,CAAC;AACZ,CAAC","sourcesContent":["/**\n * Every failure from this SDK is an AgentNavaError.\n *\n * One error type, not a hierarchy. A caller who wants to branch reads `code`,\n * and a caller who wants to retry reads `retryable`; neither is helped by\n * `instanceof NotFoundError`, and both are hurt by having to know which of nine\n * classes a given call can throw.\n */\nexport class AgentNavaError extends Error {\n\t/** Stable machine-readable reason, e.g. 'agent_not_found'.\n\t *\n\t * BRANCH ON THIS, never on `message`. Messages are written for a person\n\t * reading a log and will be reworded; codes are part of the contract. */\n\treadonly code: string;\n\n\t/** The HTTP status. 404 covers both \"no such thing\" and \"not yours\", so a\n\t * caller probing ids cannot tell another customer's agent from one that\n\t * never existed. There is deliberately no 403. */\n\treadonly status: number;\n\n\t/** Whether trying the identical request again could succeed.\n\t *\n\t * True for 5xx and 429 only. A 400 will fail the same way forever, and a\n\t * 404 will not become found, so retrying either just turns one error into\n\t * several. This is the only thing worth automating on. */\n\treadonly retryable: boolean;\n\n\t/** Seconds to wait, on a 429 that said so. */\n\treadonly retryAfter?: number;\n\n\t/** The request id from the response, when there was one. Quote it to us and\n\t * we can find the exact request in our logs. */\n\treadonly requestId?: string;\n\n\tconstructor(init: {\n\t\tmessage: string;\n\t\tcode: string;\n\t\tstatus: number;\n\t\tretryAfter?: number;\n\t\trequestId?: string;\n\t}) {\n\t\tsuper(init.message);\n\t\tthis.name = 'AgentNavaError';\n\t\tthis.code = init.code;\n\t\tthis.status = init.status;\n\t\tthis.retryable = init.status >= 500 || init.status === 429;\n\t\tif (init.retryAfter !== undefined) this.retryAfter = init.retryAfter;\n\t\tif (init.requestId !== undefined) this.requestId = init.requestId;\n\t}\n}\n\n/** A failure with no HTTP response behind it: DNS, a dropped socket, a timeout.\n *\n * Reported as status 0 rather than invented as a 5xx, because a request that\n * never arrived is a different thing from one the server failed. It is\n * retryable for the same reason a 5xx is: nothing about the request was wrong. */\nexport function networkError(message: string, cause?: unknown): AgentNavaError {\n\tconst err = new AgentNavaError({ message, code: 'network_error', status: 0 });\n\t// status 0 is not >= 500, so retryable has to be asserted here.\n\tObject.defineProperty(err, 'retryable', { value: true, enumerable: true });\n\tif (cause !== undefined) Object.defineProperty(err, 'cause', { value: cause });\n\treturn err;\n}\n"]}
package/http.d.ts ADDED
@@ -0,0 +1,32 @@
1
+ export interface ClientOptions {
2
+ /** Defaults to `AGENTNAVA_API_KEY` from the environment. */
3
+ apiKey?: string;
4
+ /** Defaults to `https://api.agentnava.com`. */
5
+ baseURL?: string;
6
+ /** Per-request timeout in milliseconds. Default 60_000. */
7
+ timeout?: number;
8
+ /** Swap the fetch implementation, for tests or a proxy. */
9
+ fetch?: typeof globalThis.fetch;
10
+ }
11
+ export interface RequestOptions {
12
+ method?: 'GET' | 'POST' | 'PATCH' | 'PUT' | 'DELETE';
13
+ /** Sent as a JSON body. Mutually exclusive with `bytes`. */
14
+ body?: unknown;
15
+ /** Sent as the raw body, for file writes. Mutually exclusive with `body`. */
16
+ bytes?: ArrayBuffer | Uint8Array;
17
+ contentType?: string;
18
+ query?: Record<string, string | number | boolean | undefined>;
19
+ signal?: AbortSignal;
20
+ }
21
+ export declare class Http {
22
+ #private;
23
+ constructor(options?: ClientOptions);
24
+ private url;
25
+ /** Make the request and hand back the raw Response, errors already thrown. */
26
+ send(path: string, options?: RequestOptions): Promise<Response>;
27
+ request<T>(path: string, options?: RequestOptions): Promise<T>;
28
+ get<T>(path: string, query?: RequestOptions['query']): Promise<T>;
29
+ post<T>(path: string, body?: unknown, query?: RequestOptions['query']): Promise<T>;
30
+ patch<T>(path: string, body?: unknown): Promise<T>;
31
+ delete<T>(path: string, query?: RequestOptions['query']): Promise<T>;
32
+ }