10xgraph-client 0.0.0-stage → 0.6.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 (125) hide show
  1. package/CHANGELOG.md +276 -0
  2. package/LICENSE +21 -0
  3. package/README.md +400 -2
  4. package/dist/agent.d.ts +22 -0
  5. package/dist/agent.d.ts.map +1 -0
  6. package/dist/client.d.ts +479 -0
  7. package/dist/client.d.ts.map +1 -0
  8. package/dist/compat.d.ts +28 -0
  9. package/dist/compat.d.ts.map +1 -0
  10. package/dist/endpoints/addThreadMessages.d.ts +22 -0
  11. package/dist/endpoints/addThreadMessages.d.ts.map +1 -0
  12. package/dist/endpoints/clearThreadState.d.ts +15 -0
  13. package/dist/endpoints/clearThreadState.d.ts.map +1 -0
  14. package/dist/endpoints/deleteMemory.d.ts +19 -0
  15. package/dist/endpoints/deleteMemory.d.ts.map +1 -0
  16. package/dist/endpoints/deleteThread.d.ts +19 -0
  17. package/dist/endpoints/deleteThread.d.ts.map +1 -0
  18. package/dist/endpoints/deleteThreadMessage.d.ts +20 -0
  19. package/dist/endpoints/deleteThreadMessage.d.ts.map +1 -0
  20. package/dist/endpoints/files.d.ts +83 -0
  21. package/dist/endpoints/files.d.ts.map +1 -0
  22. package/dist/endpoints/fixGraph.d.ts +29 -0
  23. package/dist/endpoints/fixGraph.d.ts.map +1 -0
  24. package/dist/endpoints/forgetMemories.d.ts +22 -0
  25. package/dist/endpoints/forgetMemories.d.ts.map +1 -0
  26. package/dist/endpoints/getMemory.d.ts +19 -0
  27. package/dist/endpoints/getMemory.d.ts.map +1 -0
  28. package/dist/endpoints/graph.d.ts +39 -0
  29. package/dist/endpoints/graph.d.ts.map +1 -0
  30. package/dist/endpoints/graphTools.d.ts +32 -0
  31. package/dist/endpoints/graphTools.d.ts.map +1 -0
  32. package/dist/endpoints/invoke.d.ts +59 -0
  33. package/dist/endpoints/invoke.d.ts.map +1 -0
  34. package/dist/endpoints/listMemories.d.ts +19 -0
  35. package/dist/endpoints/listMemories.d.ts.map +1 -0
  36. package/dist/endpoints/metadata.d.ts +6 -0
  37. package/dist/endpoints/metadata.d.ts.map +1 -0
  38. package/dist/endpoints/observability.d.ts +58 -0
  39. package/dist/endpoints/observability.d.ts.map +1 -0
  40. package/dist/endpoints/ping.d.ts +10 -0
  41. package/dist/endpoints/ping.d.ts.map +1 -0
  42. package/dist/endpoints/realtime.d.ts +134 -0
  43. package/dist/endpoints/realtime.d.ts.map +1 -0
  44. package/dist/endpoints/searchMemory.d.ts +57 -0
  45. package/dist/endpoints/searchMemory.d.ts.map +1 -0
  46. package/dist/endpoints/stateSchema.d.ts +50 -0
  47. package/dist/endpoints/stateSchema.d.ts.map +1 -0
  48. package/dist/endpoints/stopGraph.d.ts +26 -0
  49. package/dist/endpoints/stopGraph.d.ts.map +1 -0
  50. package/dist/endpoints/storeMemory.d.ts +33 -0
  51. package/dist/endpoints/storeMemory.d.ts.map +1 -0
  52. package/dist/endpoints/stream.d.ts +60 -0
  53. package/dist/endpoints/stream.d.ts.map +1 -0
  54. package/dist/endpoints/threadDetails.d.ts +19 -0
  55. package/dist/endpoints/threadDetails.d.ts.map +1 -0
  56. package/dist/endpoints/threadMessage.d.ts +17 -0
  57. package/dist/endpoints/threadMessage.d.ts.map +1 -0
  58. package/dist/endpoints/threadMessages.d.ts +23 -0
  59. package/dist/endpoints/threadMessages.d.ts.map +1 -0
  60. package/dist/endpoints/threadState.d.ts +14 -0
  61. package/dist/endpoints/threadState.d.ts.map +1 -0
  62. package/dist/endpoints/threads.d.ts +30 -0
  63. package/dist/endpoints/threads.d.ts.map +1 -0
  64. package/dist/endpoints/updateMemory.d.ts +21 -0
  65. package/dist/endpoints/updateMemory.d.ts.map +1 -0
  66. package/dist/endpoints/updateThreadState.d.ts +18 -0
  67. package/dist/endpoints/updateThreadState.d.ts.map +1 -0
  68. package/dist/endpoints/wsStream.d.ts +33 -0
  69. package/dist/endpoints/wsStream.d.ts.map +1 -0
  70. package/dist/errors.d.ts +155 -0
  71. package/dist/errors.d.ts.map +1 -0
  72. package/dist/index.cjs +6 -0
  73. package/dist/index.cjs.map +1 -0
  74. package/dist/index.d.ts +39 -0
  75. package/dist/index.d.ts.map +1 -0
  76. package/dist/index.js +2664 -0
  77. package/dist/index.js.map +1 -0
  78. package/dist/message.d.ts +174 -0
  79. package/dist/message.d.ts.map +1 -0
  80. package/dist/request.d.ts +33 -0
  81. package/dist/request.d.ts.map +1 -0
  82. package/dist/tools.d.ts +67 -0
  83. package/dist/tools.d.ts.map +1 -0
  84. package/dist/ws.d.ts +48 -0
  85. package/dist/ws.d.ts.map +1 -0
  86. package/package.json +99 -4
  87. package/src/agent.ts +43 -0
  88. package/src/client.ts +1044 -0
  89. package/src/compat.ts +35 -0
  90. package/src/endpoints/addThreadMessages.ts +83 -0
  91. package/src/endpoints/clearThreadState.ts +75 -0
  92. package/src/endpoints/deleteMemory.ts +91 -0
  93. package/src/endpoints/deleteThread.ts +78 -0
  94. package/src/endpoints/deleteThreadMessage.ts +83 -0
  95. package/src/endpoints/files.ts +274 -0
  96. package/src/endpoints/fixGraph.ts +91 -0
  97. package/src/endpoints/forgetMemories.ts +95 -0
  98. package/src/endpoints/getMemory.ts +82 -0
  99. package/src/endpoints/graph.ts +97 -0
  100. package/src/endpoints/graphTools.ts +90 -0
  101. package/src/endpoints/invoke.ts +318 -0
  102. package/src/endpoints/listMemories.ts +97 -0
  103. package/src/endpoints/metadata.ts +6 -0
  104. package/src/endpoints/observability.ts +107 -0
  105. package/src/endpoints/ping.ts +58 -0
  106. package/src/endpoints/realtime.ts +326 -0
  107. package/src/endpoints/searchMemory.ts +132 -0
  108. package/src/endpoints/stateSchema.ts +106 -0
  109. package/src/endpoints/stopGraph.ts +85 -0
  110. package/src/endpoints/storeMemory.ts +98 -0
  111. package/src/endpoints/stream.ts +440 -0
  112. package/src/endpoints/threadDetails.ts +78 -0
  113. package/src/endpoints/threadMessage.ts +76 -0
  114. package/src/endpoints/threadMessages.ts +97 -0
  115. package/src/endpoints/threadState.ts +74 -0
  116. package/src/endpoints/threads.ts +112 -0
  117. package/src/endpoints/updateMemory.ts +90 -0
  118. package/src/endpoints/updateThreadState.ts +82 -0
  119. package/src/endpoints/wsStream.ts +251 -0
  120. package/src/errors.ts +553 -0
  121. package/src/index.ts +108 -0
  122. package/src/message.ts +436 -0
  123. package/src/request.ts +168 -0
  124. package/src/tools.ts +225 -0
  125. package/src/ws.ts +100 -0
package/src/message.ts ADDED
@@ -0,0 +1,436 @@
1
+ // Removed incorrect import of Literal and Union from 'typescript'
2
+
3
+ // Define MediaRef type
4
+ export class MediaRef {
5
+ kind: 'url' | 'file_id' | 'data' = 'url';
6
+ url?: string;
7
+ file_id?: string;
8
+ data_base64?: string;
9
+ mime_type?: string;
10
+ size_bytes?: number;
11
+ sha256?: string;
12
+ filename?: string;
13
+ width?: number;
14
+ height?: number;
15
+ duration_ms?: number;
16
+ page?: number;
17
+
18
+ constructor(
19
+ kind: 'url' | 'file_id' | 'data' = 'url',
20
+ url?: string,
21
+ file_id?: string,
22
+ data_base64?: string,
23
+ mime_type?: string,
24
+ size_bytes?: number,
25
+ sha256?: string,
26
+ filename?: string,
27
+ width?: number,
28
+ height?: number,
29
+ duration_ms?: number,
30
+ page?: number
31
+ ) {
32
+ this.kind = kind;
33
+ this.url = url;
34
+ this.file_id = file_id;
35
+ this.data_base64 = data_base64;
36
+ this.mime_type = mime_type;
37
+ this.size_bytes = size_bytes;
38
+ this.sha256 = sha256;
39
+ this.filename = filename;
40
+ this.width = width;
41
+ this.height = height;
42
+ this.duration_ms = duration_ms;
43
+ this.page = page;
44
+ }
45
+ }
46
+
47
+ // Define AnnotationRef type
48
+ export class AnnotationRef {
49
+ url?: string;
50
+ file_id?: string;
51
+ page?: number;
52
+ index?: number;
53
+ title?: string;
54
+
55
+ constructor(url?: string, file_id?: string, page?: number, index?: number, title?: string) {
56
+ this.url = url;
57
+ this.file_id = file_id;
58
+ this.page = page;
59
+ this.index = index;
60
+ this.title = title;
61
+ }
62
+ }
63
+
64
+ // Define TextBlock type
65
+ export class TextBlock {
66
+ type: 'text' = 'text';
67
+ text: string = '';
68
+ annotations: AnnotationRef[] = [];
69
+
70
+ constructor(text: string = '', annotations: AnnotationRef[] = []) {
71
+ this.text = text;
72
+ this.annotations = annotations;
73
+ }
74
+ }
75
+
76
+ // Define ImageBlock type
77
+ export class ImageBlock {
78
+ type: 'image' = 'image';
79
+ media: MediaRef = new MediaRef();
80
+ alt_text?: string;
81
+ bbox?: number[];
82
+
83
+ constructor(media: MediaRef = new MediaRef(), alt_text?: string, bbox?: number[]) {
84
+ this.media = media;
85
+ this.alt_text = alt_text;
86
+ this.bbox = bbox;
87
+ }
88
+ }
89
+
90
+ // Define AudioBlock type
91
+ export class AudioBlock {
92
+ type: 'audio' = 'audio';
93
+ media: MediaRef = new MediaRef();
94
+ transcript?: string;
95
+ sample_rate?: number;
96
+ channels?: number;
97
+
98
+ constructor(
99
+ media: MediaRef = new MediaRef(),
100
+ transcript?: string,
101
+ sample_rate?: number,
102
+ channels?: number
103
+ ) {
104
+ this.media = media;
105
+ this.transcript = transcript;
106
+ this.sample_rate = sample_rate;
107
+ this.channels = channels;
108
+ }
109
+ }
110
+
111
+ // Define VideoBlock type
112
+ export class VideoBlock {
113
+ type: 'video' = 'video';
114
+ media: MediaRef = new MediaRef();
115
+ thumbnail?: MediaRef;
116
+
117
+ constructor(media: MediaRef = new MediaRef(), thumbnail?: MediaRef) {
118
+ this.media = media;
119
+ this.thumbnail = thumbnail;
120
+ }
121
+ }
122
+
123
+ // Define DocumentBlock type
124
+ export class DocumentBlock {
125
+ type: 'document' = 'document';
126
+ media: MediaRef = new MediaRef();
127
+ pages?: number[];
128
+ excerpt?: string;
129
+
130
+ constructor(media: MediaRef = new MediaRef(), pages?: number[], excerpt?: string) {
131
+ this.media = media;
132
+ this.pages = pages;
133
+ this.excerpt = excerpt;
134
+ }
135
+ }
136
+
137
+ // Define DataBlock type
138
+ export class DataBlock {
139
+ type: 'data' = 'data';
140
+ mime_type: string = '';
141
+ data_base64?: string;
142
+ media?: MediaRef;
143
+
144
+ constructor(mime_type: string = '', data_base64?: string, media?: MediaRef) {
145
+ this.mime_type = mime_type;
146
+ this.data_base64 = data_base64;
147
+ this.media = media;
148
+ }
149
+ }
150
+
151
+ // Define ToolCallBlock type
152
+ export class ToolCallBlock {
153
+ type: 'tool_call' = 'tool_call';
154
+ id: string = '';
155
+ name: string = '';
156
+ args: Record<string, any> = {};
157
+ tool_type?: string;
158
+
159
+ constructor(
160
+ id: string = '',
161
+ name: string = '',
162
+ args: Record<string, any> = {},
163
+ tool_type?: string
164
+ ) {
165
+ this.id = id;
166
+ this.name = name;
167
+ this.args = args;
168
+ this.tool_type = tool_type;
169
+ }
170
+ }
171
+
172
+ // Define RemoteToolCallBlock type
173
+ export class RemoteToolCallBlock {
174
+ type: 'remote_tool_call' = 'remote_tool_call';
175
+ id: string = '';
176
+ name: string = '';
177
+ args: Record<string, any> = {};
178
+ tool_type: string = 'remote';
179
+
180
+ constructor(
181
+ id: string = '',
182
+ name: string = '',
183
+ args: Record<string, any> = {},
184
+ tool_type: string = 'remote'
185
+ ) {
186
+ this.id = id;
187
+ this.name = name;
188
+ this.args = args;
189
+ this.tool_type = tool_type;
190
+ }
191
+ }
192
+
193
+ // Define ToolResultBlock type
194
+ export class ToolResultBlock {
195
+ type: 'tool_result' = 'tool_result';
196
+ call_id: string = '';
197
+ output: any;
198
+ is_error: boolean = false;
199
+ status?: 'completed' | 'failed';
200
+
201
+ constructor(props: {
202
+ call_id: string;
203
+ output: any;
204
+ status: 'completed' | 'failed';
205
+ is_error: boolean;
206
+ }) {
207
+ this.call_id = props.call_id;
208
+ this.output = props.output;
209
+ this.status = props.status;
210
+ this.is_error = props.is_error;
211
+ }
212
+ }
213
+
214
+ // Define ReasoningBlock type
215
+ export class ReasoningBlock {
216
+ type: 'reasoning' = 'reasoning';
217
+ summary: string = '';
218
+ details?: string[];
219
+
220
+ constructor(summary: string = '', details?: string[]) {
221
+ this.summary = summary;
222
+ this.details = details;
223
+ }
224
+ }
225
+
226
+ // Define AnnotationBlock type
227
+ export class AnnotationBlock {
228
+ type: 'annotation' = 'annotation';
229
+ kind: 'citation' | 'note' = 'citation';
230
+ refs: AnnotationRef[] = [];
231
+ spans?: [number, number][];
232
+
233
+ constructor(
234
+ kind: 'citation' | 'note' = 'citation',
235
+ refs: AnnotationRef[] = [],
236
+ spans?: [number, number][]
237
+ ) {
238
+ this.kind = kind;
239
+ this.refs = refs;
240
+ this.spans = spans;
241
+ }
242
+ }
243
+
244
+ // Define ErrorBlock type
245
+ export class ErrorBlock {
246
+ type: 'error' = 'error';
247
+ message: string = '';
248
+ code?: string;
249
+ data?: Record<string, any>;
250
+
251
+ constructor(message: string = '', code?: string, data?: Record<string, any>) {
252
+ this.message = message;
253
+ this.code = code;
254
+ this.data = data;
255
+ }
256
+ }
257
+
258
+ // Define ContentBlock union type
259
+ export type ContentBlock =
260
+ | TextBlock
261
+ | ImageBlock
262
+ | AudioBlock
263
+ | VideoBlock
264
+ | DocumentBlock
265
+ | DataBlock
266
+ | ToolCallBlock
267
+ | RemoteToolCallBlock
268
+ | ToolResultBlock
269
+ | ReasoningBlock
270
+ | AnnotationBlock
271
+ | ErrorBlock;
272
+
273
+ // Define TokenUsages type
274
+ export class TokenUsages {
275
+ completion_tokens: number = 0;
276
+ prompt_tokens: number = 0;
277
+ total_tokens: number = 0;
278
+ reasoning_tokens: number = 0;
279
+ cache_creation_input_tokens: number = 0;
280
+ cache_read_input_tokens: number = 0;
281
+ image_tokens?: number = 0;
282
+ audio_tokens?: number = 0;
283
+ }
284
+
285
+ // Define Message class
286
+ export class Message {
287
+ message_id: string | null = null;
288
+ role: 'user' | 'assistant' | 'system' | 'tool';
289
+ content: ContentBlock[] = [];
290
+ delta: boolean = false;
291
+ tools_calls?: Record<string, any>[];
292
+ timestamp: number = Date.now();
293
+ metadata: Record<string, any> = {};
294
+ usages?: TokenUsages;
295
+ raw?: Record<string, any>;
296
+
297
+ constructor(
298
+ role: 'user' | 'assistant' | 'system' | 'tool',
299
+ content: ContentBlock[],
300
+ message_id: string | null = null
301
+ ) {
302
+ this.role = role;
303
+ this.content = content;
304
+ this.message_id = message_id;
305
+ }
306
+
307
+ static text_message(
308
+ content: string,
309
+ role: 'user' | 'assistant' | 'system' | 'tool' = 'user',
310
+ message_id: string | null = null
311
+ ): Message {
312
+ return new Message(role, [{ type: 'text', text: content } as TextBlock], message_id);
313
+ }
314
+
315
+ static tool_message(
316
+ content: ContentBlock[],
317
+ message_id: string | null = null,
318
+ meta: Record<string, any> = {}
319
+ ): Message {
320
+ const message = new Message('tool', content, message_id);
321
+ message.metadata = meta;
322
+ return message;
323
+ }
324
+
325
+ text(): string {
326
+ return this.content
327
+ .map((block) => {
328
+ if (block.type === 'text') {
329
+ return (block as TextBlock).text;
330
+ } else if (block.type === 'tool_result') {
331
+ const output = (block as ToolResultBlock).output;
332
+ return typeof output === 'string' ? output : JSON.stringify(output);
333
+ }
334
+ return '';
335
+ })
336
+ .join('');
337
+ }
338
+
339
+ attach_media(media: MediaRef, as_type: 'image' | 'audio' | 'video' | 'document'): void {
340
+ let block: ContentBlock;
341
+ switch (as_type) {
342
+ case 'image':
343
+ block = { type: 'image', media } as ImageBlock;
344
+ break;
345
+ case 'audio':
346
+ block = { type: 'audio', media } as AudioBlock;
347
+ break;
348
+ case 'video':
349
+ block = { type: 'video', media } as VideoBlock;
350
+ break;
351
+ case 'document':
352
+ block = { type: 'document', media } as DocumentBlock;
353
+ break;
354
+ default:
355
+ throw new Error(`Unsupported media type: ${as_type}`);
356
+ }
357
+ this.content.push(block);
358
+ }
359
+
360
+ // ------------------------------------------------------------------
361
+ // Multimodal convenience constructors (Sprint 5.3)
362
+ // ------------------------------------------------------------------
363
+
364
+ /**
365
+ * Create a message with an image (via URL or base64).
366
+ *
367
+ * @example
368
+ * ```ts
369
+ * const msg = Message.withImage('Describe this', 'https://example.com/photo.jpg');
370
+ * const msg2 = Message.withImage('Describe this', 'data:image/png;base64,...');
371
+ * ```
372
+ */
373
+ static withImage(
374
+ text: string,
375
+ imageUrl: string,
376
+ role: 'user' | 'assistant' | 'system' = 'user'
377
+ ): Message {
378
+ return new Message(role, [
379
+ new TextBlock(text),
380
+ new ImageBlock(new MediaRef('url', imageUrl, undefined, undefined, undefined)),
381
+ ]);
382
+ }
383
+
384
+ /**
385
+ * Create a message with a file reference (e.g. from uploadFile result).
386
+ *
387
+ * @example
388
+ * ```ts
389
+ * const upload = await client.uploadFile(pdfFile);
390
+ * const msg = Message.withFile('Summarize this PDF', upload.data.file_id, 'application/pdf');
391
+ * ```
392
+ */
393
+ static withFile(
394
+ text: string,
395
+ fileId: string,
396
+ mimeType?: string,
397
+ role: 'user' | 'assistant' | 'system' = 'user'
398
+ ): Message {
399
+ const media = new MediaRef('file_id', undefined, fileId, undefined, mimeType);
400
+ const isImage = mimeType?.startsWith('image/');
401
+ const isAudio = mimeType?.startsWith('audio/');
402
+ const isVideo = mimeType?.startsWith('video/');
403
+
404
+ let block: ContentBlock;
405
+ if (isImage) {
406
+ block = new ImageBlock(media);
407
+ } else if (isAudio) {
408
+ block = new AudioBlock(media);
409
+ } else if (isVideo) {
410
+ block = new VideoBlock(media);
411
+ } else {
412
+ block = new DocumentBlock(media);
413
+ }
414
+
415
+ return new Message(role, [new TextBlock(text), block]);
416
+ }
417
+
418
+ /**
419
+ * Create a multimodal message with arbitrary content blocks.
420
+ *
421
+ * @example
422
+ * ```ts
423
+ * const msg = Message.multimodal([
424
+ * new TextBlock('Look at these'),
425
+ * new ImageBlock(new MediaRef('url', 'https://...')),
426
+ * new ImageBlock(new MediaRef('url', 'https://...')),
427
+ * ]);
428
+ * ```
429
+ */
430
+ static multimodal(
431
+ blocks: ContentBlock[],
432
+ role: 'user' | 'assistant' | 'system' = 'user'
433
+ ): Message {
434
+ return new Message(role, blocks);
435
+ }
436
+ }
package/src/request.ts ADDED
@@ -0,0 +1,168 @@
1
+ import type { WebSocketImpl } from './ws.js';
2
+
3
+ export interface TenxGraphBearerAuth {
4
+ type: 'bearer';
5
+ token: string;
6
+ }
7
+
8
+ export interface TenxGraphBasicAuth {
9
+ type: 'basic';
10
+ username: string;
11
+ password: string;
12
+ }
13
+
14
+ export interface TenxGraphHeaderAuth {
15
+ type: 'header';
16
+ name: string;
17
+ value: string;
18
+ prefix?: string | null;
19
+ }
20
+
21
+ export type TenxGraphAuth = TenxGraphBearerAuth | TenxGraphBasicAuth | TenxGraphHeaderAuth;
22
+
23
+ export interface RequestContext {
24
+ baseUrl: string;
25
+ authToken?: string | null;
26
+ auth?: TenxGraphAuth | null;
27
+ headers?: HeadersInit;
28
+ credentials?: RequestCredentials;
29
+ timeout: number;
30
+ debug: boolean;
31
+ webSocketImpl?: WebSocketImpl;
32
+ }
33
+
34
+ function setHeader(
35
+ target: Record<string, string>,
36
+ name: string,
37
+ value: string | null | undefined
38
+ ): void {
39
+ if (value == null) {
40
+ return;
41
+ }
42
+
43
+ for (const existingName of Object.keys(target)) {
44
+ if (existingName.toLowerCase() === name.toLowerCase()) {
45
+ delete target[existingName];
46
+ }
47
+ }
48
+
49
+ target[name] = value;
50
+ }
51
+
52
+ function mergeHeaders(target: Record<string, string>, source?: HeadersInit | null): void {
53
+ if (!source) {
54
+ return;
55
+ }
56
+
57
+ if (source instanceof Headers) {
58
+ source.forEach((value, name) => {
59
+ setHeader(target, name, value);
60
+ });
61
+ return;
62
+ }
63
+
64
+ if (Array.isArray(source)) {
65
+ for (const [name, value] of source) {
66
+ setHeader(target, name, value);
67
+ }
68
+ return;
69
+ }
70
+
71
+ for (const [name, value] of Object.entries(source)) {
72
+ if (value !== undefined) {
73
+ setHeader(target, name, String(value));
74
+ }
75
+ }
76
+ }
77
+
78
+ function hasHeader(target: Record<string, string>, name: string): boolean {
79
+ return Object.keys(target).some(
80
+ (existingName) => existingName.toLowerCase() === name.toLowerCase()
81
+ );
82
+ }
83
+
84
+ function encodeBase64(value: string): string {
85
+ const bufferConstructor = (
86
+ globalThis as {
87
+ Buffer?: { from(input: string, encoding: string): { toString(encoding: string): string } };
88
+ }
89
+ ).Buffer;
90
+ if (bufferConstructor) {
91
+ return bufferConstructor.from(value, 'utf-8').toString('base64');
92
+ }
93
+
94
+ if (typeof btoa === 'function') {
95
+ const bytes = new TextEncoder().encode(value);
96
+ let binary = '';
97
+ for (const byte of bytes) {
98
+ binary += String.fromCharCode(byte);
99
+ }
100
+ return btoa(binary);
101
+ }
102
+
103
+ throw new Error('Basic authentication is not supported in this runtime');
104
+ }
105
+
106
+ function applyAuth(target: Record<string, string>, auth?: TenxGraphAuth | null): void {
107
+ if (!auth) {
108
+ return;
109
+ }
110
+
111
+ if (auth.type === 'bearer') {
112
+ setHeader(target, 'Authorization', `Bearer ${auth.token}`);
113
+ return;
114
+ }
115
+
116
+ if (auth.type === 'basic') {
117
+ const credentials = encodeBase64(`${auth.username}:${auth.password}`);
118
+ setHeader(target, 'Authorization', `Basic ${credentials}`);
119
+ return;
120
+ }
121
+
122
+ const headerValue = auth.prefix ? `${auth.prefix} ${auth.value}` : auth.value;
123
+ setHeader(target, auth.name, headerValue);
124
+ }
125
+
126
+ export function buildHeaders(
127
+ context: Pick<RequestContext, 'authToken' | 'auth' | 'headers'>,
128
+ defaults?: HeadersInit
129
+ ): Record<string, string> {
130
+ const headers: Record<string, string> = {};
131
+
132
+ mergeHeaders(headers, defaults);
133
+ mergeHeaders(headers, context.headers);
134
+
135
+ if (context.auth) {
136
+ applyAuth(headers, context.auth);
137
+ } else if (context.authToken && !hasHeader(headers, 'Authorization')) {
138
+ setHeader(headers, 'Authorization', `Bearer ${context.authToken}`);
139
+ }
140
+
141
+ return headers;
142
+ }
143
+
144
+ export function getRequestCredentials(
145
+ context: Pick<RequestContext, 'credentials'>
146
+ ): Pick<RequestInit, 'credentials'> | Record<string, never> {
147
+ if (!context.credentials) {
148
+ return {};
149
+ }
150
+
151
+ return { credentials: context.credentials };
152
+ }
153
+
154
+ export function bearerAuth(token: string): TenxGraphBearerAuth {
155
+ return { type: 'bearer', token };
156
+ }
157
+
158
+ export function basicAuth(username: string, password: string): TenxGraphBasicAuth {
159
+ return { type: 'basic', username, password };
160
+ }
161
+
162
+ export function headerAuth(
163
+ name: string,
164
+ value: string,
165
+ prefix?: string | null
166
+ ): TenxGraphHeaderAuth {
167
+ return { type: 'header', name, value, prefix };
168
+ }