@alexein/sdk 0.0.0-stage → 0.3.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.
@@ -0,0 +1,920 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } async function _asyncNullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return await rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }// src/json.ts
2
+ var object = (value) => typeof value === "object" && value !== null && !Array.isArray(value) ? value : {};
3
+ var list = (value) => Array.isArray(value) ? value : [];
4
+ var objects = (value) => list(value).map(object);
5
+ var text = (value) => typeof value === "string" ? value : value === void 0 || value === null ? "" : String(value);
6
+ var maybe = (value) => typeof value === "string" ? value : value === void 0 || value === null ? null : String(value);
7
+ var strings = (value) => list(value).map(text);
8
+ var maybeStrings = (value) => Array.isArray(value) ? strings(value) : null;
9
+ var count = (value) => typeof value === "number" ? value : Number(value) || 0;
10
+ var maybeCount = (value) => value === void 0 || value === null ? null : count(value);
11
+ var bool = (value) => value === true;
12
+ function compact(body) {
13
+ return Object.fromEntries(
14
+ Object.entries(body).filter(([, value]) => value !== void 0 && value !== null)
15
+ );
16
+ }
17
+
18
+ // src/memories.ts
19
+ function parseFact(value) {
20
+ const raw = object(value);
21
+ return {
22
+ type: "fact",
23
+ ref: text(raw.ref),
24
+ text: text(raw.text),
25
+ source: maybe(raw.source),
26
+ date: maybe(raw.date),
27
+ raw
28
+ };
29
+ }
30
+ function parseExcerpt(value) {
31
+ const raw = object(value);
32
+ return {
33
+ type: "excerpt",
34
+ ref: text(raw.ref),
35
+ text: text(raw.text),
36
+ date: maybe(raw.date),
37
+ addedAt: maybe(raw.added_at),
38
+ session: maybe(raw.session),
39
+ roles: strings(raw.roles),
40
+ raw
41
+ };
42
+ }
43
+ function parseMemory(value) {
44
+ const raw = object(value);
45
+ if (raw.type === "known") return { type: "known", text: text(raw.text), raw };
46
+ if (raw.type === "fact") return parseFact(raw);
47
+ if (raw.type === "excerpt") return parseExcerpt(raw);
48
+ return void 0;
49
+ }
50
+ function parseMemories(value) {
51
+ const out = [];
52
+ for (const entry of Array.isArray(value) ? value : []) {
53
+ const memory = parseMemory(entry);
54
+ if (memory) out.push(memory);
55
+ }
56
+ return out;
57
+ }
58
+ function refsOf(memories) {
59
+ return memories.flatMap((m) => m.type === "known" || !m.ref ? [] : [m.ref]);
60
+ }
61
+
62
+ // src/search.ts
63
+ function line(memory) {
64
+ const dated = memory.type === "excerpt" && memory.date ? `${memory.date.slice(0, 10)}: ` : "";
65
+ return `- ${dated}${memory.text}`;
66
+ }
67
+ var SearchResult = class _SearchResult {
68
+ constructor(query, answerable, notes, memories, sources2, failed, raw) {
69
+ this.query = query;
70
+ this.answerable = answerable;
71
+ this.notes = notes;
72
+ this.memories = memories;
73
+ this.sources = sources2;
74
+ this.failed = failed;
75
+ this.raw = raw;
76
+ }
77
+
78
+
79
+
80
+
81
+
82
+
83
+
84
+ static parse(value) {
85
+ const raw = object(value);
86
+ return new _SearchResult(
87
+ text(raw.query),
88
+ typeof raw.answerable === "boolean" ? raw.answerable : null,
89
+ strings(raw.notes),
90
+ parseMemories(raw.memories),
91
+ Array.isArray(raw.sources) ? list(raw.sources).map(object) : null,
92
+ false,
93
+ raw
94
+ );
95
+ }
96
+ /** What a `failOpen` client answers when memory could not be reached. */
97
+ static unavailable(query) {
98
+ return new _SearchResult(query, null, [], [], null, true, {});
99
+ }
100
+ get known() {
101
+ return this.memories.filter((m) => m.type === "known");
102
+ }
103
+ get facts() {
104
+ return this.memories.filter((m) => m.type === "fact");
105
+ }
106
+ get excerpts() {
107
+ return this.memories.filter((m) => m.type === "excerpt");
108
+ }
109
+ /** Every ref, in order: each opens with `user.open(ref)`. */
110
+ get refs() {
111
+ return refsOf(this.memories);
112
+ }
113
+ /**
114
+ * The text to paste into a prompt: each note on its own line, a blank line, then each memory on
115
+ * its own line as `- <text>` (an excerpt with a date as `- <YYYY-MM-DD>: <text>`), cut at a whole
116
+ * memory so it is never longer than `maxChars`. Empty when there are no memories, or when not
117
+ * even the first fits. The Python client and the n8n node write the same text.
118
+ */
119
+ context(maxChars = 4e3) {
120
+ const head = this.notes.length ? `${this.notes.join("\n")}
121
+
122
+ ` : "";
123
+ let out = "";
124
+ for (const memory of this.memories) {
125
+ const grown = `${out || head}${out ? "\n" : ""}${line(memory)}`;
126
+ if (grown.length > maxChars) break;
127
+ out = grown;
128
+ }
129
+ return out;
130
+ }
131
+ };
132
+
133
+ // src/errors.ts
134
+ var AlexeinError = class extends Error {
135
+ /** The HTTP status, or null when no response came back. */
136
+
137
+ /** The API's own explanation; for a transport failure, what went wrong. */
138
+
139
+ /** On a 422: each field the body got wrong. Empty otherwise. */
140
+
141
+ /**
142
+ * The request's id: the `X-Request-Id` this client sent, which the API logs and answers with.
143
+ * Quote it when you ask for help, or find the request in the console's request logs.
144
+ */
145
+
146
+ constructor(message, fields = {}) {
147
+ super(message, fields.cause === void 0 ? void 0 : { cause: fields.cause });
148
+ this.name = new.target.name;
149
+ this.status = _nullishCoalesce(fields.status, () => ( null));
150
+ this.detail = _nullishCoalesce(fields.detail, () => ( message));
151
+ this.errors = _nullishCoalesce(fields.errors, () => ( []));
152
+ this.requestId = _nullishCoalesce(fields.requestId, () => ( null));
153
+ }
154
+ /**
155
+ * Whether this means memory is unavailable - unreachable, too slow, too busy or failing - rather
156
+ * than that the request or the key is wrong. A `failOpen` client rides out an outage; a mistake
157
+ * still throws.
158
+ */
159
+ get outage() {
160
+ return this.status !== null && (this.status === 429 || this.status >= 500);
161
+ }
162
+ };
163
+ var AuthenticationError = class extends AlexeinError {
164
+ };
165
+ var PermissionDeniedError = class extends AlexeinError {
166
+ };
167
+ var NotFoundError = class extends AlexeinError {
168
+ };
169
+ var InvalidRequestError = class extends AlexeinError {
170
+ };
171
+ var RateLimitError = class extends AlexeinError {
172
+ };
173
+ var ServiceUnavailableError = class extends AlexeinError {
174
+ };
175
+ var APIConnectionError = class extends AlexeinError {
176
+ get outage() {
177
+ return true;
178
+ }
179
+ };
180
+ var APITimeoutError = class extends APIConnectionError {
181
+ };
182
+ function kindOf(status2) {
183
+ if (status2 === 401) return AuthenticationError;
184
+ if (status2 === 403) return PermissionDeniedError;
185
+ if (status2 === 404) return NotFoundError;
186
+ if (status2 === 429) return RateLimitError;
187
+ if (status2 >= 500) return ServiceUnavailableError;
188
+ if (status2 >= 400) return InvalidRequestError;
189
+ return AlexeinError;
190
+ }
191
+ function fieldErrors(value) {
192
+ return list(value).map((entry) => {
193
+ const error = object(entry);
194
+ if (Array.isArray(error.loc)) {
195
+ const at = error.loc[0] === "body" ? error.loc.slice(1) : error.loc;
196
+ return { field: at.map(String).join("."), message: text(error.msg) };
197
+ }
198
+ return { field: text(error.field), message: text(error.message) };
199
+ });
200
+ }
201
+ function errorFor(status2, body, requestId2) {
202
+ const errors = fieldErrors(_nullishCoalesce(body.errors, () => ( (Array.isArray(body.detail) ? body.detail : []))));
203
+ const detail = typeof body.detail === "string" ? body.detail : errors.map((e) => e.field ? `${e.field}: ${e.message}` : e.message).join("; ");
204
+ const Kind = kindOf(status2);
205
+ return new Kind(detail ? `${status2}: ${detail}` : String(status2), {
206
+ status: status2,
207
+ detail,
208
+ errors,
209
+ requestId: requestId2
210
+ });
211
+ }
212
+ function unreached(error, requestId2 = null) {
213
+ const name = error instanceof Error ? error.name : "";
214
+ const said = error instanceof Error ? error.message : String(error);
215
+ if (name === "TimeoutError" || name === "AbortError") {
216
+ return new APITimeoutError(`Alexein did not answer in time: ${said}`, {
217
+ cause: error,
218
+ requestId: requestId2
219
+ });
220
+ }
221
+ return new APIConnectionError(`Alexein could not be reached: ${said}`, {
222
+ cause: error,
223
+ requestId: requestId2
224
+ });
225
+ }
226
+
227
+ // src/version.ts
228
+ var VERSION = "0.3.0";
229
+
230
+ // src/settings.ts
231
+ var DEFAULT_BASE_URL = "https://api.alexein.ai";
232
+ var DEFAULT_TIMEOUT_MS = 6e4;
233
+ var DEFAULT_RETRIES = 2;
234
+ var KEYS_PAGE = "https://app.alexein.ai/console/keys";
235
+ var INTEGRATION = /^[a-z0-9][a-z0-9._-]{0,31}$/;
236
+ var USER_ID = /^[A-Za-z0-9][A-Za-z0-9._-]{0,34}$/;
237
+ function environment(name) {
238
+ const env = _optionalChain([globalThis, 'access', _ => _.process, 'optionalAccess', _2 => _2.env]);
239
+ return _optionalChain([env, 'optionalAccess', _3 => _3[name]]) || void 0;
240
+ }
241
+ function normalizeBaseUrl(url) {
242
+ return url.trim().replace(/\/+$/, "").replace(/\/v2$/, "").replace(/\/+$/, "");
243
+ }
244
+ function checkedUserId(id) {
245
+ if (typeof id !== "string" || !USER_ID.test(id)) {
246
+ throw new RangeError(
247
+ `not a usable app user id: ${JSON.stringify(id)} (1 to 35 letters, digits, '.', '_' and '-', beginning with a letter or digit)`
248
+ );
249
+ }
250
+ return id;
251
+ }
252
+ function count2(name, value, least) {
253
+ if (!Number.isFinite(value) || value < least) {
254
+ throw new RangeError(`${name} must be a number of at least ${least}: ${value}`);
255
+ }
256
+ return value;
257
+ }
258
+ function settings(options) {
259
+ const key = _nullishCoalesce(_nullishCoalesce(options.apiKey, () => ( environment("ALEXEIN_API_KEY"))), () => ( ""));
260
+ if (!key) {
261
+ throw new AlexeinError(
262
+ `No API key: pass apiKey, or set ALEXEIN_API_KEY. Make one in the console, under API keys: ${KEYS_PAGE}`
263
+ );
264
+ }
265
+ const integration = _nullishCoalesce(options.integration, () => ( null));
266
+ if (integration !== null && !INTEGRATION.test(integration)) {
267
+ throw new RangeError(
268
+ `integration must be one short lowercase word: ${JSON.stringify(integration)}`
269
+ );
270
+ }
271
+ const given = globalThis.fetch;
272
+ const send = _nullishCoalesce(options.fetch, () => ( (given ? given.bind(globalThis) : void 0)));
273
+ if (!send) throw new AlexeinError("No fetch in this runtime: pass one as the fetch option.");
274
+ return {
275
+ key,
276
+ baseUrl: normalizeBaseUrl(
277
+ _nullishCoalesce(_nullishCoalesce(options.baseUrl, () => ( environment("ALEXEIN_API_URL"))), () => ( DEFAULT_BASE_URL))
278
+ ),
279
+ timeout: count2("timeout", _nullishCoalesce(options.timeout, () => ( DEFAULT_TIMEOUT_MS)), 1),
280
+ maxRetries: Math.floor(count2("maxRetries", _nullishCoalesce(options.maxRetries, () => ( DEFAULT_RETRIES)), 0)),
281
+ failOpen: _nullishCoalesce(options.failOpen, () => ( false)),
282
+ integration,
283
+ userAgent: `alexein-js/${VERSION}${integration ? ` ${integration}` : ""}`,
284
+ log: _nullishCoalesce(options.logger, () => ( ((message) => console.warn(message)))),
285
+ fetch: send
286
+ };
287
+ }
288
+
289
+ // src/reads.ts
290
+ function parseMemoriesResult(value) {
291
+ const raw = object(value);
292
+ const memories = parseMemories(raw.memories);
293
+ return {
294
+ memories,
295
+ pattern: maybe(raw.pattern),
296
+ total: maybeCount(raw.total),
297
+ places: maybeStrings(raw.places),
298
+ raw,
299
+ [Symbol.iterator]: () => memories[Symbol.iterator]()
300
+ };
301
+ }
302
+ function parseOpened(value) {
303
+ const raw = object(value);
304
+ const memory = object(raw.memory);
305
+ return {
306
+ memory: memory.type === "fact" ? parseFact(memory) : parseExcerpt(memory),
307
+ sources: objects(raw.sources).map(parseExcerpt),
308
+ raw
309
+ };
310
+ }
311
+ function parseHistory(value) {
312
+ const raw = object(value);
313
+ return {
314
+ subject: text(raw.subject),
315
+ values: objects(raw.values).map((v) => ({
316
+ attribute: text(v.attribute),
317
+ value: text(v.value),
318
+ since: maybe(v.since),
319
+ negated: v.negated === true,
320
+ raw: v
321
+ })),
322
+ suggestions: maybeStrings(raw.suggestions),
323
+ raw
324
+ };
325
+ }
326
+ function parseSource(raw) {
327
+ return {
328
+ provider: text(raw.provider),
329
+ source: text(raw.source),
330
+ connection: text(raw.connection),
331
+ items: count(raw.items),
332
+ ended: count(raw.ended),
333
+ newest: maybe(raw.newest),
334
+ raw
335
+ };
336
+ }
337
+ function parseSources(value) {
338
+ const raw = object(value);
339
+ return { sources: objects(raw.sources).map(parseSource), raw };
340
+ }
341
+ function parseSummary(value) {
342
+ const raw = object(value);
343
+ return {
344
+ items: count(raw.items),
345
+ first: maybe(raw.first),
346
+ last: maybe(raw.last),
347
+ sources: objects(raw.sources).map(parseSource),
348
+ known: strings(raw.known),
349
+ raw
350
+ };
351
+ }
352
+ function parseOpenItems(value) {
353
+ const raw = object(value);
354
+ return {
355
+ items: objects(raw.items).map((i) => ({
356
+ ref: text(i.ref),
357
+ text: text(i.text),
358
+ date: maybe(i.date),
359
+ addedAt: maybe(i.added_at),
360
+ ageDays: maybeCount(i.age_days),
361
+ raw: i
362
+ })),
363
+ followUps: objects(raw.follow_ups).map((f) => ({
364
+ title: maybe(f.title),
365
+ who: maybe(f.who),
366
+ date: maybe(f.date),
367
+ ageDays: maybeCount(f.age_days),
368
+ raw: f
369
+ })),
370
+ raw
371
+ };
372
+ }
373
+
374
+ // src/pages.ts
375
+ function parseFactsPage(value) {
376
+ const raw = object(value);
377
+ return { facts: objects(raw.facts).map(parseFact), next: maybe(raw.next), raw };
378
+ }
379
+ function parseStoredItem(value) {
380
+ const raw = object(value);
381
+ const author = raw.author;
382
+ return {
383
+ id: text(raw.id),
384
+ kind: maybe(raw.kind),
385
+ text: text(raw.text),
386
+ title: maybe(raw.title),
387
+ at: maybe(raw.at),
388
+ author: typeof author === "string" ? author : author ? object(author) : null,
389
+ role: maybe(raw.role),
390
+ session: maybe(raw.session),
391
+ about: maybeStrings(raw.about),
392
+ metadata: raw.metadata ? object(raw.metadata) : null,
393
+ expires: maybe(raw.expires),
394
+ status: text(raw.status),
395
+ raw
396
+ };
397
+ }
398
+ function parseFound(value) {
399
+ const raw = object(value);
400
+ return raw.found === false || !raw.item ? null : parseStoredItem(raw.item);
401
+ }
402
+ function parseItemsPage(value) {
403
+ const raw = object(value);
404
+ return { items: objects(raw.items).map(parseStoredItem), next: maybe(raw.next), raw };
405
+ }
406
+ function parseUsersPage(value) {
407
+ const raw = object(value);
408
+ const users2 = objects(raw.users).map((u) => ({
409
+ user: text(u.user),
410
+ items: count(u.items),
411
+ facts: count(u.facts),
412
+ lastWrite: maybe(u.last_write),
413
+ raw: u
414
+ }));
415
+ return { users: users2, next: maybe(raw.next), raw };
416
+ }
417
+ function parseExportPage(value) {
418
+ const raw = object(value);
419
+ return {
420
+ user: text(raw.user),
421
+ exportedAt: maybe(raw.exported_at),
422
+ records: objects(raw.records).map((r) => ({ ...r, type: text(r.type) })),
423
+ next: maybe(raw.next),
424
+ withheld: strings(raw.withheld),
425
+ raw
426
+ };
427
+ }
428
+ function parseMe(value) {
429
+ const raw = object(value);
430
+ return {
431
+ kind: text(raw.kind),
432
+ org: maybe(raw.org),
433
+ project: maybe(raw.project),
434
+ keyId: maybe(raw.key_id),
435
+ writes: bool(raw.writes),
436
+ label: maybe(raw.label),
437
+ createdBy: maybe(raw.created_by),
438
+ orgName: maybe(raw.org_name),
439
+ projectName: maybe(raw.project_name),
440
+ space: maybe(raw.space),
441
+ raw
442
+ };
443
+ }
444
+ async function* paged(page, entries) {
445
+ let cursor;
446
+ do {
447
+ const got = await page(cursor);
448
+ yield* entries(got);
449
+ cursor = _nullishCoalesce(got.next, () => ( void 0));
450
+ } while (cursor);
451
+ }
452
+
453
+ // src/writes.ts
454
+ function addResult(items2, waiting, failed, raw) {
455
+ return { items: items2, waiting, failed, ids: items2.map((i) => i.id), raw };
456
+ }
457
+ function parseAddResult(value) {
458
+ const raw = object(value);
459
+ const items2 = objects(raw.items).map((i) => ({
460
+ id: text(i.id),
461
+ status: text(i.status),
462
+ redacted: i.redacted ? object(i.redacted) : null,
463
+ raw: i
464
+ }));
465
+ return addResult(items2, count(raw.waiting), false, raw);
466
+ }
467
+ function mergedAdd(results, failed = false) {
468
+ if (results.length === 1 && !failed) return results[0];
469
+ const items2 = results.flatMap((r) => r.items);
470
+ const waiting = results.reduce((n, r) => n + r.waiting, 0);
471
+ const raw = results.length ? { items: items2.map((i) => i.raw), waiting } : {};
472
+ return addResult(items2, waiting, failed, raw);
473
+ }
474
+ function parseStatuses(value) {
475
+ const raw = object(value);
476
+ const items2 = objects(raw.items).map((i) => ({
477
+ id: text(i.id),
478
+ status: text(i.status),
479
+ reason: maybe(i.reason),
480
+ raw: i
481
+ }));
482
+ return { items: items2, byId: Object.fromEntries(items2.map((i) => [i.id, i.status])), raw };
483
+ }
484
+ function parseForgotten(value) {
485
+ const raw = object(value);
486
+ const e = object(raw.erased);
487
+ return {
488
+ erased: {
489
+ items: count(e.items),
490
+ facts: count(e.facts),
491
+ versions: count(e.versions),
492
+ waiting: count(e.waiting),
493
+ relearning: count(e.relearning)
494
+ },
495
+ complete: bool(raw.complete),
496
+ raw
497
+ };
498
+ }
499
+ function parseCorrection(value) {
500
+ const raw = object(value);
501
+ return {
502
+ retracted: text(raw.retracted),
503
+ text: maybe(raw.text),
504
+ replacement: maybe(raw.replacement),
505
+ raw
506
+ };
507
+ }
508
+ function parseVersions(value) {
509
+ const raw = object(value);
510
+ return {
511
+ id: text(raw.id),
512
+ state: text(raw.state),
513
+ history: objects(raw.history).map((h) => ({
514
+ event: text(h.event),
515
+ at: maybe(h.at),
516
+ version: maybeCount(h.version),
517
+ item: h.item ? object(h.item) : null,
518
+ why: maybe(h.why),
519
+ raw: h
520
+ })),
521
+ raw
522
+ };
523
+ }
524
+ function parseDeleted(value) {
525
+ const raw = object(value);
526
+ return { user: text(raw.user), deleted: bool(raw.deleted), raw };
527
+ }
528
+
529
+ // src/calls.ts
530
+ var kinds = (kind) => kind === void 0 ? void 0 : Array.isArray(kind) ? kind : [kind];
531
+ function post(route, parse, body = {}) {
532
+ return { method: "POST", path: `/memory/${route}`, body: compact(body), parse };
533
+ }
534
+ var me = () => ({ method: "GET", path: "/me", parse: parseMe });
535
+ var users = (o) => post("users", parseUsersPage, { limit: o.limit, cursor: o.cursor });
536
+ var deleteUser = () => post("users/delete", parseDeleted);
537
+ var add = (body, key) => ({
538
+ method: "POST",
539
+ path: "/memory/add",
540
+ body,
541
+ headers: { "Idempotency-Key": key },
542
+ parse: parseAddResult
543
+ });
544
+ var search = (query, o) => post("search", SearchResult.parse, {
545
+ query,
546
+ before: o.before,
547
+ after: o.after,
548
+ filters: o.filters,
549
+ provider: o.provider,
550
+ source: o.source,
551
+ kind: kinds(o.kind),
552
+ fast: o.fast
553
+ });
554
+ var grep = (pattern, o) => post("grep", parseMemoriesResult, {
555
+ pattern,
556
+ limit: o.limit,
557
+ provider: o.provider,
558
+ source: o.source,
559
+ kind: kinds(o.kind)
560
+ });
561
+ var latest = (o) => post("latest", parseMemoriesResult, {
562
+ k: o.k,
563
+ place: o.place,
564
+ after: o.after,
565
+ before: o.before,
566
+ filters: o.filters,
567
+ provider: o.provider,
568
+ source: o.source,
569
+ kind: kinds(o.kind)
570
+ });
571
+ var around = (ref, width) => post("around", parseMemoriesResult, { ref, width });
572
+ var open = (ref) => post("open", parseOpened, { ref });
573
+ var history = (subject, attribute) => post("history", parseHistory, { subject, attribute });
574
+ var summary = () => post("summary", parseSummary);
575
+ var facts = (o) => post("facts", parseFactsPage, { limit: o.limit, cursor: o.cursor });
576
+ var openItems = (o) => post("open_items", parseOpenItems, {
577
+ kind: kinds(o.kind),
578
+ provider: o.provider,
579
+ place: o.place,
580
+ mine: o.mine,
581
+ within_days: o.withinDays,
582
+ limit: o.limit
583
+ });
584
+ var sources = () => post("sources", parseSources);
585
+ var items = (o) => post("items", parseItemsPage, { limit: o.limit, cursor: o.cursor, filters: o.filters });
586
+ var item = (id) => post("item", parseFound, { id });
587
+ var status = (ids) => post("status", parseStatuses, { items: ids });
588
+ function forget(named) {
589
+ const body = compact({
590
+ items: _optionalChain([named, 'access', _4 => _4.items, 'optionalAccess', _5 => _5.length]) ? named.items : void 0,
591
+ sessions: _optionalChain([named, 'access', _6 => _6.sessions, 'optionalAccess', _7 => _7.length]) ? named.sessions : void 0,
592
+ refs: _optionalChain([named, 'access', _8 => _8.refs, 'optionalAccess', _9 => _9.length]) ? named.refs : void 0
593
+ });
594
+ if (!Object.keys(body).length) {
595
+ throw new RangeError("forget needs at least one of items, sessions or refs");
596
+ }
597
+ return post("forget", parseForgotten, body);
598
+ }
599
+ var correct = (ref, replacement) => post("correct", parseCorrection, { ref, replacement });
600
+ var versions = (id) => post("versions", parseVersions, { id });
601
+ var exportPage = (o) => post("export", parseExportPage, { limit: o.limit, cursor: o.cursor });
602
+
603
+ // src/items.ts
604
+ var BATCH = 500;
605
+ function shape(given, defaults) {
606
+ const item2 = typeof given === "string" ? { text: given } : { ...given };
607
+ if (typeof item2.text !== "string" || !item2.text) {
608
+ throw new TypeError(`an item needs text: ${JSON.stringify(given)}`);
609
+ }
610
+ const own = Object.fromEntries(Object.entries(item2).filter(([, v]) => v !== void 0));
611
+ return { ...defaults, ...own };
612
+ }
613
+ function batches(items2, options) {
614
+ const { wait, redact, ...fields } = options;
615
+ const defaults = compact(fields);
616
+ const given = typeof items2 === "string" || !Array.isArray(items2) ? [items2] : items2;
617
+ const shaped = given.map((item2) => shape(item2, defaults));
618
+ if (!shaped.length) return [];
619
+ const call = crypto.randomUUID();
620
+ const out = [];
621
+ for (let at = 0; at < shaped.length; at += BATCH) {
622
+ out.push({
623
+ body: compact({ items: shaped.slice(at, at + BATCH), wait, redact }),
624
+ key: `${call}-${at / BATCH}`
625
+ });
626
+ }
627
+ return out;
628
+ }
629
+
630
+ // src/user.ts
631
+ var User = class {
632
+ /** @internal Made by `memory.user(id)`. */
633
+ constructor(transport, id, failOpen, log) {
634
+ this.transport = transport;
635
+ this.id = id;
636
+ this.failOpen = failOpen;
637
+ this.log = log;
638
+ }
639
+
640
+
641
+
642
+
643
+ send(call) {
644
+ return this.transport.send(call, this.id);
645
+ }
646
+ /**
647
+ * Remember text: a string, an item, or a list of either. The options fill in each item's unset
648
+ * fields. More than 500 items go as several requests; a retry never saves an item twice.
649
+ */
650
+ async add(items2, options = {}) {
651
+ const results = [];
652
+ for (const batch of batches(items2, options)) {
653
+ try {
654
+ results.push(await this.send(add(batch.body, batch.key)));
655
+ } catch (error) {
656
+ this.rideOut(error, "add");
657
+ return mergedAdd(results, true);
658
+ }
659
+ }
660
+ return mergedAdd(results);
661
+ }
662
+ /** What memory holds for a question: known lines, facts and excerpts, in order. */
663
+ async search(query, options = {}) {
664
+ try {
665
+ return await this.send(search(query, options));
666
+ } catch (error) {
667
+ this.rideOut(error, "search");
668
+ return SearchResult.unavailable(query);
669
+ }
670
+ }
671
+ /** Excerpts holding an exact phrase, ignoring case. */
672
+ grep(pattern, options = {}) {
673
+ return this.send(grep(pattern, options));
674
+ }
675
+ /** The most recent excerpts, newest first; with `after` and `before`, everything between. */
676
+ latest(options = {}) {
677
+ return this.send(latest(options));
678
+ }
679
+ /** The excerpts just before and after one, from the same conversation, in order. */
680
+ around(ref, options = {}) {
681
+ return this.send(around(ref, options.width));
682
+ }
683
+ /** One memory by its ref, whole: an excerpt, or a fact with the excerpts it came from. */
684
+ open(ref) {
685
+ return this.send(open(ref));
686
+ }
687
+ /** Every value a subject was stated to have, by attribute, oldest first. */
688
+ history(subject, options = {}) {
689
+ return this.send(history(subject, options.attribute));
690
+ }
691
+ /** This memory in brief: its items, their span, the connected sources and the known lines. */
692
+ summary() {
693
+ return this.send(summary());
694
+ }
695
+ /** The facts memory learned, newest first, a page at a time. */
696
+ facts(options = {}) {
697
+ return this.send(facts(options));
698
+ }
699
+ /** Every fact, across pages. */
700
+ iterFacts(options = {}) {
701
+ return paged(
702
+ (cursor) => this.facts({ ...options, cursor }),
703
+ (page) => page.facts
704
+ );
705
+ }
706
+ /** The issues and pull requests still open, and the asks nobody answered. */
707
+ openItems(options = {}) {
708
+ return this.send(openItems(options));
709
+ }
710
+ /** What each connected app delivered to this memory. */
711
+ sources() {
712
+ return this.send(sources());
713
+ }
714
+ /** The items added, newest first, as they were given, a page at a time. */
715
+ items(options = {}) {
716
+ return this.send(items(options));
717
+ }
718
+ /** Every item, across pages. */
719
+ iterItems(options = {}) {
720
+ return paged(
721
+ (cursor) => this.items({ ...options, cursor }),
722
+ (page) => page.items
723
+ );
724
+ }
725
+ /** One added item by its id, whole; null when memory holds none by that id. */
726
+ item(itemId) {
727
+ return this.send(item(itemId));
728
+ }
729
+ /** How far each item has got: `queued`, `stored`, `processed` or `unknown`. */
730
+ status(ids) {
731
+ return this.send(status(ids));
732
+ }
733
+ /** Erase these items, sessions and memories (by ref), with every copy and all learned from them. */
734
+ async forget(named) {
735
+ return this.send(forget(named));
736
+ }
737
+ /** Retract one fact for good, by its ref; a `replacement` is kept as a note. */
738
+ correct(ref, replacement) {
739
+ return this.send(correct(ref, replacement));
740
+ }
741
+ /** Every version of one added item, oldest first. Takes a key that writes. */
742
+ versions(itemId) {
743
+ return this.send(versions(itemId));
744
+ }
745
+ /** Everything memory holds for this app user, a page at a time. */
746
+ export(options = {}) {
747
+ return this.send(exportPage(options));
748
+ }
749
+ /** Every export record, across pages. */
750
+ iterExport(options = {}) {
751
+ return paged(
752
+ (cursor) => this.export({ ...options, cursor }),
753
+ (page) => page.records
754
+ );
755
+ }
756
+ /** Erase this app user whole: every item, fact and version. Not undone. */
757
+ delete() {
758
+ return this.send(deleteUser());
759
+ }
760
+ /**
761
+ * Throw `error` unless this client fails open and it is an outage; then log it, and the caller
762
+ * answers empty. Memory being down costs a reply its memory, not the reply.
763
+ */
764
+ rideOut(error, what) {
765
+ if (!(this.failOpen && error instanceof AlexeinError && error.outage)) throw error;
766
+ this.log(`Alexein is unavailable, so ${what} for ${this.id} was skipped: ${error.message}`);
767
+ }
768
+ };
769
+
770
+ // src/transport.ts
771
+ var RETRIED = /* @__PURE__ */ new Set([429, 503]);
772
+ var LONGEST_WAIT_MS = 6e4;
773
+ var SETS_USER_AGENT = typeof globalThis.document === "undefined";
774
+ var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
775
+ function requestId() {
776
+ return `req_${globalThis.crypto.randomUUID().replaceAll("-", "")}`;
777
+ }
778
+ function pauseFor(attempt, response) {
779
+ if (response !== void 0) {
780
+ if (!RETRIED.has(response.status)) return void 0;
781
+ const after = (_nullishCoalesce(response.headers.get("Retry-After"), () => ( ""))).trim();
782
+ if (/^\d+(\.\d+)?$/.test(after)) {
783
+ const ms = Number(after) * 1e3;
784
+ return ms <= LONGEST_WAIT_MS ? ms : void 0;
785
+ }
786
+ }
787
+ return 500 * 2 ** attempt * (0.75 + Math.random() * 0.5);
788
+ }
789
+ async function bodyOf(response) {
790
+ const said = await response.text();
791
+ if (!said) return { body: {}, said };
792
+ try {
793
+ return { body: JSON.parse(said), said };
794
+ } catch (e2) {
795
+ return { body: void 0, said };
796
+ }
797
+ }
798
+ var Transport = class {
799
+ constructor(settings2) {
800
+ this.settings = settings2;
801
+ }
802
+
803
+ /** Send `call` for app user `user` (none for `me` and `users`), retrying as the API asks. */
804
+ async send(call, user) {
805
+ const rid = requestId();
806
+ for (let attempt = 0; ; attempt++) {
807
+ let response;
808
+ let failure;
809
+ try {
810
+ response = await this.attempt(call, user, rid);
811
+ } catch (error) {
812
+ failure = unreached(error, rid);
813
+ }
814
+ if (_optionalChain([response, 'optionalAccess', _10 => _10.ok])) return this.answer(response, call, rid);
815
+ const pause = attempt < this.settings.maxRetries ? pauseFor(attempt, response) : void 0;
816
+ if (pause === void 0) throw await _asyncNullishCoalesce(failure, async () => ( await this.refusal(response, rid)));
817
+ await _optionalChain([response, 'optionalAccess', _11 => _11.body, 'optionalAccess', _12 => _12.cancel, 'call', _13 => _13(), 'access', _14 => _14.catch, 'call', _15 => _15(() => {
818
+ })]);
819
+ await sleep(pause);
820
+ }
821
+ }
822
+ attempt(call, user, rid) {
823
+ const headers = {
824
+ Authorization: `Bearer ${this.settings.key}`,
825
+ "X-Request-Id": rid,
826
+ ...call.headers
827
+ };
828
+ if (SETS_USER_AGENT) headers["User-Agent"] = this.settings.userAgent;
829
+ if (user !== void 0) headers["X-Alexein-User"] = user;
830
+ if (call.method === "POST") headers["Content-Type"] = "application/json";
831
+ return this.settings.fetch(`${this.settings.baseUrl}/v2${call.path}`, {
832
+ method: call.method,
833
+ headers,
834
+ body: call.method === "POST" ? JSON.stringify(_nullishCoalesce(call.body, () => ( {}))) : void 0,
835
+ signal: AbortSignal.timeout(this.settings.timeout)
836
+ });
837
+ }
838
+ async answer(response, call, rid) {
839
+ const { body, said } = await bodyOf(response);
840
+ if (body === void 0) {
841
+ throw new AlexeinError(`${response.status}: the answer is not JSON: ${said.slice(0, 200)}`, {
842
+ status: response.status,
843
+ requestId: _nullishCoalesce(response.headers.get("X-Request-Id"), () => ( rid))
844
+ });
845
+ }
846
+ return call.parse(body);
847
+ }
848
+ async refusal(response, rid) {
849
+ const { body, said } = await bodyOf(response);
850
+ const json = body === void 0 ? { detail: said.trim() } : object(body);
851
+ return errorFor(response.status, json, _nullishCoalesce(response.headers.get("X-Request-Id"), () => ( rid)));
852
+ }
853
+ };
854
+
855
+ // src/client.ts
856
+ var Memory = class {
857
+ /** The API's host, without `/v2`. */
858
+
859
+ /** Milliseconds one attempt may take. */
860
+
861
+
862
+
863
+ /** The word in the User-Agent, or null. */
864
+
865
+ #settings;
866
+ #transport;
867
+ constructor(options = {}) {
868
+ this.#settings = settings(options);
869
+ this.#transport = new Transport(this.#settings);
870
+ this.baseUrl = this.#settings.baseUrl;
871
+ this.timeout = this.#settings.timeout;
872
+ this.maxRetries = this.#settings.maxRetries;
873
+ this.failOpen = this.#settings.failOpen;
874
+ this.integration = this.#settings.integration;
875
+ }
876
+ /** What this key is: its organisation, project, and whether it writes. Names no app user. */
877
+ me() {
878
+ return this.#transport.send(me());
879
+ }
880
+ /**
881
+ * The memory of one of your app users, by your own id for them: 1 to 35 letters, digits, `.`,
882
+ * `_` and `-`, beginning with a letter or digit. A RangeError otherwise, before any request.
883
+ */
884
+ user(id) {
885
+ return new User(this.#transport, checkedUserId(id), this.failOpen, this.#settings.log);
886
+ }
887
+ /** The app users of this key's project with memory, a page at a time in id order. */
888
+ users(options = {}) {
889
+ return this.#transport.send(users(options));
890
+ }
891
+ /** Every app user with memory, across pages. */
892
+ iterUsers(options = {}) {
893
+ return paged(
894
+ (cursor) => this.users({ ...options, cursor }),
895
+ (page) => page.users
896
+ );
897
+ }
898
+ /** Nothing to release: each request is its own. Here so code written for Python reads the same. */
899
+ close() {
900
+ }
901
+ };
902
+
903
+
904
+
905
+
906
+
907
+
908
+
909
+
910
+
911
+
912
+
913
+
914
+
915
+
916
+
917
+
918
+
919
+
920
+ exports.SearchResult = SearchResult; exports.AlexeinError = AlexeinError; exports.AuthenticationError = AuthenticationError; exports.PermissionDeniedError = PermissionDeniedError; exports.NotFoundError = NotFoundError; exports.InvalidRequestError = InvalidRequestError; exports.RateLimitError = RateLimitError; exports.ServiceUnavailableError = ServiceUnavailableError; exports.APIConnectionError = APIConnectionError; exports.APITimeoutError = APITimeoutError; exports.VERSION = VERSION; exports.DEFAULT_BASE_URL = DEFAULT_BASE_URL; exports.DEFAULT_TIMEOUT_MS = DEFAULT_TIMEOUT_MS; exports.DEFAULT_RETRIES = DEFAULT_RETRIES; exports.User = User; exports.Memory = Memory;