hebbrix 2.3.0 → 2.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # Changelog
2
2
 
3
+ ## 2.3.1 — 2026-08-27
4
+
5
+ - Make single-memory `wait_for_index` a client-enforced readiness contract:
6
+ submit exactly one write, poll the durable receipt to searchable completion,
7
+ preserve receipt and idempotency context on timeout or cancellation, and
8
+ reject terminal indexing states.
9
+
3
10
  ## 2.3.0 — 2026-08-27
4
11
 
5
12
  - Reconcile every exported advanced method with the canonical public OpenAPI,
package/README.md CHANGED
@@ -6,7 +6,7 @@ outcome-learning APIs.
6
6
  ## Install
7
7
 
8
8
  ```bash
9
- npm install hebbrix@2.3.0
9
+ npm install hebbrix@2.3.1
10
10
  ```
11
11
 
12
12
  Node.js 16+ and modern browsers are supported.
@@ -43,6 +43,28 @@ it throws `IndexingTimeoutError`; the error retains the receipt, durable memory
43
43
  IDs, and status URL. Reuse the same idempotency key with the same body to recover
44
44
  the same logical resources.
45
45
 
46
+ Single writes and batch writes use the same one-write readiness rule. The
47
+ client sends exactly one mutation, then uses read-only status requests. Set
48
+ `index_timeout_ms` and `index_poll_interval_ms` on `memories.create()` to tune
49
+ that client-side wait. A signal can cancel the initial request; once a receipt
50
+ is available, cancellation stops only the read-only polling.
51
+ `IndexingAbortedError` then preserves the durable receipt and IDs so
52
+ cancellation cannot be mistaken for a failed write. Terminal `failed`,
53
+ `cancelled`, or `canceled` states raise `IndexingTerminalError` with the same
54
+ receipt context.
55
+
56
+ ```typescript
57
+ const controller = new AbortController();
58
+ const ready = await client.memories.create({
59
+ content: "Customer prefers concise replies",
60
+ wait_for_index: true,
61
+ index_timeout_ms: 30_000,
62
+ index_poll_interval_ms: 250,
63
+ signal: controller.signal,
64
+ idempotency_key: "customer-42-preference-v1",
65
+ });
66
+ ```
67
+
46
68
  ```typescript
47
69
  const receipt = await client.memories.createBatch({
48
70
  memories: [{ content: "First fact" }, { content: "Second fact" }],
package/dist/index.d.mts CHANGED
@@ -38,6 +38,12 @@ interface Memory {
38
38
  source_reference?: string;
39
39
  access_count: number;
40
40
  last_accessed_at?: string;
41
+ /** Authoritative indexing state returned by GET /v1/memories/{id}. */
42
+ processing_status?: string;
43
+ /** True only when the memory is available to search. */
44
+ searchable?: boolean;
45
+ outbox_event_id?: string;
46
+ status_url?: string;
41
47
  created_at: string;
42
48
  updated_at: string;
43
49
  }
@@ -155,6 +161,12 @@ interface CreateMemoryParams {
155
161
  source?: string;
156
162
  /** Stable retry key sent as the Idempotency-Key transport header. */
157
163
  idempotency_key?: string;
164
+ /** Optional caller cancellation signal; it is never serialized. */
165
+ signal?: AbortSignal;
166
+ /** Client-side readiness deadline used only when wait_for_index=true. */
167
+ index_timeout_ms?: number;
168
+ /** Poll interval for a durable pending receipt. */
169
+ index_poll_interval_ms?: number;
158
170
  }
159
171
  interface MemoryAddResult {
160
172
  id: string;
@@ -162,6 +174,7 @@ interface MemoryAddResult {
162
174
  event: "ADD" | "UPDATE" | "NOOP" | string;
163
175
  memory?: string;
164
176
  reason?: string;
177
+ processing_status?: string;
165
178
  }
166
179
  interface MemoryAddResponse {
167
180
  results: MemoryAddResult[];
@@ -170,6 +183,9 @@ interface MemoryAddResponse {
170
183
  searchable: boolean;
171
184
  outbox_event_id?: string;
172
185
  status_url?: string;
186
+ idempotency_replay?: boolean;
187
+ request_id?: string;
188
+ retry_after?: string;
173
189
  job_id?: string;
174
190
  created_count: number;
175
191
  updated_count: number;
@@ -370,9 +386,23 @@ declare class CollectionsResource extends BaseResource {
370
386
  }
371
387
  declare class MemoriesResource extends BaseResource {
372
388
  /**
373
- * Create a new memory
389
+ * Create one logical memory write. When `wait_for_index=true`, a durable
390
+ * pending receipt is polled without issuing a second create request.
374
391
  */
375
392
  create(params: CreateMemoryParams): Promise<MemoryAddResponse>;
393
+ /** Poll a single-write durable receipt until every accepted memory is searchable. */
394
+ waitForSearchable(receipt: MemoryAddResponse, options?: {
395
+ timeoutMs?: number;
396
+ pollIntervalMs?: number;
397
+ signal?: AbortSignal;
398
+ idempotencyKey?: string;
399
+ }): Promise<MemoryAddResponse>;
400
+ private memoryIds;
401
+ private isSearchableCompletion;
402
+ private isTerminalStatus;
403
+ private readinessPath;
404
+ private throwIfPollingAborted;
405
+ private pollingDelay;
376
406
  /**
377
407
  * Create up to 100 memories with one unambiguous readiness contract.
378
408
  * `wait_for_index=true` resolves only for a fully searchable batch. A durable
@@ -689,11 +719,36 @@ declare class EntitlementError extends HebbrixError {
689
719
  details?: Record<string, any>;
690
720
  });
691
721
  }
692
- declare class IndexingTimeoutError extends Error {
722
+ interface IndexingWaitErrorOptions {
723
+ idempotencyKey?: string;
724
+ cause?: unknown;
725
+ }
726
+ /** Base class for readiness failures after the API has accepted a durable write. */
727
+ declare class IndexingWaitError extends Error {
693
728
  receipt: Record<string, any>;
694
729
  memoryIds: string[];
730
+ jobId?: string;
695
731
  statusUrl?: string;
696
- constructor(message: string, receipt: Record<string, any>);
732
+ requestId?: string;
733
+ outboxEventId?: string;
734
+ indexingEventId?: string;
735
+ eventId?: string;
736
+ idempotencyReplay?: boolean;
737
+ idempotencyKey?: string;
738
+ retryAfter?: string;
739
+ recovery: Record<string, unknown>;
740
+ cause?: unknown;
741
+ constructor(message: string, receipt: Record<string, any>, options?: IndexingWaitErrorOptions);
742
+ }
743
+ declare class IndexingTimeoutError extends IndexingWaitError {
744
+ constructor(message: string, receipt: Record<string, any>, options?: IndexingWaitErrorOptions);
745
+ }
746
+ declare class IndexingAbortedError extends IndexingWaitError {
747
+ constructor(message: string, receipt: Record<string, any>, options?: IndexingWaitErrorOptions);
748
+ }
749
+ declare class IndexingTerminalError extends IndexingWaitError {
750
+ processingStatus: string;
751
+ constructor(message: string, receipt: Record<string, any>, processingStatus: string, options?: IndexingWaitErrorOptions);
697
752
  }
698
753
  declare class AuthenticationError extends HebbrixError {
699
754
  constructor(message?: string, options?: {
@@ -752,4 +807,4 @@ interface SafetyEnvelope {
752
807
  */
753
808
  declare function enforceSearchSafety<T extends object>(response: T, rowsKey?: "results" | "sources"): T & SafetyEnvelope;
754
809
 
755
- export { type APIKeyResponse, AuthResource, type AuthResponse, AuthenticationError, type BatchMemoryCreateParams, type BatchMemoryItemParams, type BatchMemoryResponse, type ClientConfig, type Collection, CollectionsResource, ConsolidationResource, type CorrectionCreateParams, type CorrectionSearchParams, CorrectionsResource, type CreateCollectionParams, type CreateMemoryParams, type CursorPage, EntitlementError, type EvidenceClaim, type GroundingReceipt, HebbrixError, IndexingTimeoutError, type ListParams, MemoriesResource, type Memory, type MemoryAddResponse, type MemoryAddResult, MemoryClient, type MemoryJobReceipt, MemoryJobsResource, type MemoryListParams, MemoryToolsResource, type MemoryWithMetadata, NotFoundError, ProceduralResource, type ProofContext, type ProofLoopCandidate, type ProofLoopDecisionParams, type ProofLoopMetricParams, ProofLoopResource, RLResource, RateLimitError, type ReasonParams, type ReasoningResponse, type ReasoningSource, type SafetyEnvelope, type SearchParams, SearchResource, type SearchResponse, type SearchResult, ServerError, TemporalResource, type UpdateCollectionParams, type UpdateMemoryParams, type User, ValidationError, WorkingMemoryResource, enforceSearchSafety };
810
+ export { type APIKeyResponse, AuthResource, type AuthResponse, AuthenticationError, type BatchMemoryCreateParams, type BatchMemoryItemParams, type BatchMemoryResponse, type ClientConfig, type Collection, CollectionsResource, ConsolidationResource, type CorrectionCreateParams, type CorrectionSearchParams, CorrectionsResource, type CreateCollectionParams, type CreateMemoryParams, type CursorPage, EntitlementError, type EvidenceClaim, type GroundingReceipt, HebbrixError, IndexingAbortedError, IndexingTerminalError, IndexingTimeoutError, IndexingWaitError, type IndexingWaitErrorOptions, type ListParams, MemoriesResource, type Memory, type MemoryAddResponse, type MemoryAddResult, MemoryClient, type MemoryJobReceipt, MemoryJobsResource, type MemoryListParams, MemoryToolsResource, type MemoryWithMetadata, NotFoundError, ProceduralResource, type ProofContext, type ProofLoopCandidate, type ProofLoopDecisionParams, type ProofLoopMetricParams, ProofLoopResource, RLResource, RateLimitError, type ReasonParams, type ReasoningResponse, type ReasoningSource, type SafetyEnvelope, type SearchParams, SearchResource, type SearchResponse, type SearchResult, ServerError, TemporalResource, type UpdateCollectionParams, type UpdateMemoryParams, type User, ValidationError, WorkingMemoryResource, enforceSearchSafety };
package/dist/index.d.ts CHANGED
@@ -38,6 +38,12 @@ interface Memory {
38
38
  source_reference?: string;
39
39
  access_count: number;
40
40
  last_accessed_at?: string;
41
+ /** Authoritative indexing state returned by GET /v1/memories/{id}. */
42
+ processing_status?: string;
43
+ /** True only when the memory is available to search. */
44
+ searchable?: boolean;
45
+ outbox_event_id?: string;
46
+ status_url?: string;
41
47
  created_at: string;
42
48
  updated_at: string;
43
49
  }
@@ -155,6 +161,12 @@ interface CreateMemoryParams {
155
161
  source?: string;
156
162
  /** Stable retry key sent as the Idempotency-Key transport header. */
157
163
  idempotency_key?: string;
164
+ /** Optional caller cancellation signal; it is never serialized. */
165
+ signal?: AbortSignal;
166
+ /** Client-side readiness deadline used only when wait_for_index=true. */
167
+ index_timeout_ms?: number;
168
+ /** Poll interval for a durable pending receipt. */
169
+ index_poll_interval_ms?: number;
158
170
  }
159
171
  interface MemoryAddResult {
160
172
  id: string;
@@ -162,6 +174,7 @@ interface MemoryAddResult {
162
174
  event: "ADD" | "UPDATE" | "NOOP" | string;
163
175
  memory?: string;
164
176
  reason?: string;
177
+ processing_status?: string;
165
178
  }
166
179
  interface MemoryAddResponse {
167
180
  results: MemoryAddResult[];
@@ -170,6 +183,9 @@ interface MemoryAddResponse {
170
183
  searchable: boolean;
171
184
  outbox_event_id?: string;
172
185
  status_url?: string;
186
+ idempotency_replay?: boolean;
187
+ request_id?: string;
188
+ retry_after?: string;
173
189
  job_id?: string;
174
190
  created_count: number;
175
191
  updated_count: number;
@@ -370,9 +386,23 @@ declare class CollectionsResource extends BaseResource {
370
386
  }
371
387
  declare class MemoriesResource extends BaseResource {
372
388
  /**
373
- * Create a new memory
389
+ * Create one logical memory write. When `wait_for_index=true`, a durable
390
+ * pending receipt is polled without issuing a second create request.
374
391
  */
375
392
  create(params: CreateMemoryParams): Promise<MemoryAddResponse>;
393
+ /** Poll a single-write durable receipt until every accepted memory is searchable. */
394
+ waitForSearchable(receipt: MemoryAddResponse, options?: {
395
+ timeoutMs?: number;
396
+ pollIntervalMs?: number;
397
+ signal?: AbortSignal;
398
+ idempotencyKey?: string;
399
+ }): Promise<MemoryAddResponse>;
400
+ private memoryIds;
401
+ private isSearchableCompletion;
402
+ private isTerminalStatus;
403
+ private readinessPath;
404
+ private throwIfPollingAborted;
405
+ private pollingDelay;
376
406
  /**
377
407
  * Create up to 100 memories with one unambiguous readiness contract.
378
408
  * `wait_for_index=true` resolves only for a fully searchable batch. A durable
@@ -689,11 +719,36 @@ declare class EntitlementError extends HebbrixError {
689
719
  details?: Record<string, any>;
690
720
  });
691
721
  }
692
- declare class IndexingTimeoutError extends Error {
722
+ interface IndexingWaitErrorOptions {
723
+ idempotencyKey?: string;
724
+ cause?: unknown;
725
+ }
726
+ /** Base class for readiness failures after the API has accepted a durable write. */
727
+ declare class IndexingWaitError extends Error {
693
728
  receipt: Record<string, any>;
694
729
  memoryIds: string[];
730
+ jobId?: string;
695
731
  statusUrl?: string;
696
- constructor(message: string, receipt: Record<string, any>);
732
+ requestId?: string;
733
+ outboxEventId?: string;
734
+ indexingEventId?: string;
735
+ eventId?: string;
736
+ idempotencyReplay?: boolean;
737
+ idempotencyKey?: string;
738
+ retryAfter?: string;
739
+ recovery: Record<string, unknown>;
740
+ cause?: unknown;
741
+ constructor(message: string, receipt: Record<string, any>, options?: IndexingWaitErrorOptions);
742
+ }
743
+ declare class IndexingTimeoutError extends IndexingWaitError {
744
+ constructor(message: string, receipt: Record<string, any>, options?: IndexingWaitErrorOptions);
745
+ }
746
+ declare class IndexingAbortedError extends IndexingWaitError {
747
+ constructor(message: string, receipt: Record<string, any>, options?: IndexingWaitErrorOptions);
748
+ }
749
+ declare class IndexingTerminalError extends IndexingWaitError {
750
+ processingStatus: string;
751
+ constructor(message: string, receipt: Record<string, any>, processingStatus: string, options?: IndexingWaitErrorOptions);
697
752
  }
698
753
  declare class AuthenticationError extends HebbrixError {
699
754
  constructor(message?: string, options?: {
@@ -752,4 +807,4 @@ interface SafetyEnvelope {
752
807
  */
753
808
  declare function enforceSearchSafety<T extends object>(response: T, rowsKey?: "results" | "sources"): T & SafetyEnvelope;
754
809
 
755
- export { type APIKeyResponse, AuthResource, type AuthResponse, AuthenticationError, type BatchMemoryCreateParams, type BatchMemoryItemParams, type BatchMemoryResponse, type ClientConfig, type Collection, CollectionsResource, ConsolidationResource, type CorrectionCreateParams, type CorrectionSearchParams, CorrectionsResource, type CreateCollectionParams, type CreateMemoryParams, type CursorPage, EntitlementError, type EvidenceClaim, type GroundingReceipt, HebbrixError, IndexingTimeoutError, type ListParams, MemoriesResource, type Memory, type MemoryAddResponse, type MemoryAddResult, MemoryClient, type MemoryJobReceipt, MemoryJobsResource, type MemoryListParams, MemoryToolsResource, type MemoryWithMetadata, NotFoundError, ProceduralResource, type ProofContext, type ProofLoopCandidate, type ProofLoopDecisionParams, type ProofLoopMetricParams, ProofLoopResource, RLResource, RateLimitError, type ReasonParams, type ReasoningResponse, type ReasoningSource, type SafetyEnvelope, type SearchParams, SearchResource, type SearchResponse, type SearchResult, ServerError, TemporalResource, type UpdateCollectionParams, type UpdateMemoryParams, type User, ValidationError, WorkingMemoryResource, enforceSearchSafety };
810
+ export { type APIKeyResponse, AuthResource, type AuthResponse, AuthenticationError, type BatchMemoryCreateParams, type BatchMemoryItemParams, type BatchMemoryResponse, type ClientConfig, type Collection, CollectionsResource, ConsolidationResource, type CorrectionCreateParams, type CorrectionSearchParams, CorrectionsResource, type CreateCollectionParams, type CreateMemoryParams, type CursorPage, EntitlementError, type EvidenceClaim, type GroundingReceipt, HebbrixError, IndexingAbortedError, IndexingTerminalError, IndexingTimeoutError, IndexingWaitError, type IndexingWaitErrorOptions, type ListParams, MemoriesResource, type Memory, type MemoryAddResponse, type MemoryAddResult, MemoryClient, type MemoryJobReceipt, MemoryJobsResource, type MemoryListParams, MemoryToolsResource, type MemoryWithMetadata, NotFoundError, ProceduralResource, type ProofContext, type ProofLoopCandidate, type ProofLoopDecisionParams, type ProofLoopMetricParams, ProofLoopResource, RLResource, RateLimitError, type ReasonParams, type ReasoningResponse, type ReasoningSource, type SafetyEnvelope, type SearchParams, SearchResource, type SearchResponse, type SearchResult, ServerError, TemporalResource, type UpdateCollectionParams, type UpdateMemoryParams, type User, ValidationError, WorkingMemoryResource, enforceSearchSafety };
package/dist/index.js CHANGED
@@ -27,7 +27,10 @@ __export(index_exports, {
27
27
  CorrectionsResource: () => CorrectionsResource,
28
28
  EntitlementError: () => EntitlementError,
29
29
  HebbrixError: () => HebbrixError,
30
+ IndexingAbortedError: () => IndexingAbortedError,
31
+ IndexingTerminalError: () => IndexingTerminalError,
30
32
  IndexingTimeoutError: () => IndexingTimeoutError,
33
+ IndexingWaitError: () => IndexingWaitError,
31
34
  MemoriesResource: () => MemoriesResource,
32
35
  MemoryClient: () => MemoryClient,
33
36
  MemoryJobsResource: () => MemoryJobsResource,
@@ -119,16 +122,72 @@ var EntitlementError = class _EntitlementError extends HebbrixError {
119
122
  Object.setPrototypeOf(this, _EntitlementError.prototype);
120
123
  }
121
124
  };
122
- var IndexingTimeoutError = class _IndexingTimeoutError extends Error {
123
- constructor(message, receipt) {
125
+ var IndexingWaitError = class _IndexingWaitError extends Error {
126
+ constructor(message, receipt, options = {}) {
124
127
  super(message);
125
- this.name = "IndexingTimeoutError";
128
+ this.name = "IndexingWaitError";
126
129
  this.receipt = { ...receipt };
127
- this.memoryIds = [...receipt.memory_ids || []];
128
- this.statusUrl = receipt.status_url;
130
+ this.memoryIds = [
131
+ ...new Set(
132
+ [
133
+ ...receipt.memory_ids || [],
134
+ receipt.memory_id,
135
+ receipt.id,
136
+ ...(receipt.results || []).map(
137
+ (row) => row.memory_id || row.id
138
+ )
139
+ ].filter(Boolean)
140
+ )
141
+ ];
142
+ this.jobId = receipt.job_id;
143
+ this.statusUrl = receipt.status_url || (this.memoryIds.length === 1 ? `/v1/memories/${encodeURIComponent(this.memoryIds[0])}` : this.jobId ? `/v1/memory-jobs/${encodeURIComponent(this.jobId)}` : void 0);
144
+ this.requestId = receipt.request_id;
145
+ this.outboxEventId = receipt.outbox_event_id;
146
+ this.indexingEventId = receipt.indexing_event_id || this.outboxEventId;
147
+ this.eventId = receipt.event_id || this.indexingEventId;
148
+ this.idempotencyReplay = receipt.idempotency_replay;
149
+ this.idempotencyKey = options.idempotencyKey || receipt.idempotency_key;
150
+ this.retryAfter = receipt.retry_after;
151
+ this.recovery = Object.fromEntries(
152
+ Object.entries({
153
+ memory_ids: this.memoryIds,
154
+ job_id: this.jobId,
155
+ status_url: this.statusUrl,
156
+ request_id: this.requestId,
157
+ outbox_event_id: this.outboxEventId,
158
+ indexing_event_id: this.indexingEventId,
159
+ event_id: this.eventId,
160
+ idempotency_key: this.idempotencyKey,
161
+ idempotency_replay: this.idempotencyReplay,
162
+ retry_after: this.retryAfter
163
+ }).filter(([, value]) => value !== void 0 && value !== null)
164
+ );
165
+ this.cause = options.cause;
166
+ Object.setPrototypeOf(this, _IndexingWaitError.prototype);
167
+ }
168
+ };
169
+ var IndexingTimeoutError = class _IndexingTimeoutError extends IndexingWaitError {
170
+ constructor(message, receipt, options = {}) {
171
+ super(message, receipt, options);
172
+ this.name = "IndexingTimeoutError";
129
173
  Object.setPrototypeOf(this, _IndexingTimeoutError.prototype);
130
174
  }
131
175
  };
176
+ var IndexingAbortedError = class _IndexingAbortedError extends IndexingWaitError {
177
+ constructor(message, receipt, options = {}) {
178
+ super(message, receipt, options);
179
+ this.name = "IndexingAbortedError";
180
+ Object.setPrototypeOf(this, _IndexingAbortedError.prototype);
181
+ }
182
+ };
183
+ var IndexingTerminalError = class _IndexingTerminalError extends IndexingWaitError {
184
+ constructor(message, receipt, processingStatus, options = {}) {
185
+ super(message, receipt, options);
186
+ this.name = "IndexingTerminalError";
187
+ this.processingStatus = processingStatus;
188
+ Object.setPrototypeOf(this, _IndexingTerminalError.prototype);
189
+ }
190
+ };
132
191
  var AuthenticationError = class _AuthenticationError extends HebbrixError {
133
192
  constructor(message = "Authentication failed", options = {}) {
134
193
  super(message, 401, options);
@@ -242,22 +301,195 @@ var CollectionsResource = class extends BaseResource {
242
301
  };
243
302
  var MemoriesResource = class extends BaseResource {
244
303
  /**
245
- * Create a new memory
304
+ * Create one logical memory write. When `wait_for_index=true`, a durable
305
+ * pending receipt is polled without issuing a second create request.
246
306
  */
247
307
  async create(params) {
248
308
  if (!params.content?.trim() && !params.messages?.length) {
249
309
  throw new TypeError("content or messages must be provided");
250
310
  }
251
- const { idempotency_key, ...input } = params;
252
- return this.client.request("POST", "/v1/memories", {
253
- headers: idempotency_key ? { "Idempotency-Key": idempotency_key } : void 0,
254
- body: JSON.stringify({
255
- source_type: "text",
256
- metadata: {},
257
- infer: false,
258
- wait_for_index: false,
259
- ...input
260
- })
311
+ const {
312
+ idempotency_key,
313
+ signal,
314
+ index_timeout_ms,
315
+ index_poll_interval_ms,
316
+ ...input
317
+ } = params;
318
+ const receipt = await this.client.request(
319
+ "POST",
320
+ "/v1/memories",
321
+ {
322
+ headers: idempotency_key ? { "Idempotency-Key": idempotency_key } : void 0,
323
+ body: JSON.stringify({
324
+ source_type: "text",
325
+ metadata: {},
326
+ infer: false,
327
+ wait_for_index: false,
328
+ ...input
329
+ }),
330
+ signal
331
+ }
332
+ );
333
+ if (params.wait_for_index && !this.isSearchableCompletion(receipt)) {
334
+ return this.waitForSearchable(receipt, {
335
+ timeoutMs: index_timeout_ms,
336
+ pollIntervalMs: index_poll_interval_ms,
337
+ signal,
338
+ idempotencyKey: idempotency_key
339
+ });
340
+ }
341
+ return receipt;
342
+ }
343
+ /** Poll a single-write durable receipt until every accepted memory is searchable. */
344
+ async waitForSearchable(receipt, options = {}) {
345
+ if (this.isSearchableCompletion(receipt)) {
346
+ return receipt;
347
+ }
348
+ if (this.isTerminalStatus(receipt.processing_status)) {
349
+ const status = String(receipt.processing_status).toLowerCase();
350
+ throw new IndexingTerminalError(
351
+ `memory indexing reached terminal state ${status}`,
352
+ receipt,
353
+ status,
354
+ { idempotencyKey: options.idempotencyKey }
355
+ );
356
+ }
357
+ const ids = this.memoryIds(receipt);
358
+ if (!ids.length) {
359
+ throw new Error("memory receipt does not contain a durable memory id");
360
+ }
361
+ const timeoutMs = Math.max(0, options.timeoutMs ?? 6e4);
362
+ const pollIntervalMs = Math.max(50, options.pollIntervalMs ?? 500);
363
+ const deadline = Date.now() + timeoutMs;
364
+ const paths = ids.map(
365
+ (id, index) => index === 0 && receipt.status_url ? this.readinessPath(receipt.status_url, id) : `/v1/memories/${encodeURIComponent(id)}`
366
+ );
367
+ while (true) {
368
+ this.throwIfPollingAborted(receipt, options);
369
+ if (Date.now() >= deadline) {
370
+ throw new IndexingTimeoutError(
371
+ `memory was not searchable within ${timeoutMs}ms; the write is durable`,
372
+ receipt,
373
+ { idempotencyKey: options.idempotencyKey }
374
+ );
375
+ }
376
+ let rows;
377
+ try {
378
+ rows = await Promise.all(
379
+ paths.map(
380
+ (path) => this.client.request("GET", path, {
381
+ signal: options.signal
382
+ })
383
+ )
384
+ );
385
+ } catch (error) {
386
+ if (options.signal?.aborted) {
387
+ throw new IndexingAbortedError(
388
+ "memory readiness polling was aborted after the write became durable",
389
+ receipt,
390
+ { idempotencyKey: options.idempotencyKey, cause: error }
391
+ );
392
+ }
393
+ throw error;
394
+ }
395
+ const terminal = rows.find(
396
+ (row) => this.isTerminalStatus(row.processing_status)
397
+ );
398
+ if (terminal) {
399
+ const status = String(terminal.processing_status).toLowerCase();
400
+ throw new IndexingTerminalError(
401
+ `memory ${terminal.id} indexing reached terminal state ${status}`,
402
+ receipt,
403
+ status,
404
+ { idempotencyKey: options.idempotencyKey }
405
+ );
406
+ }
407
+ if (rows.every(
408
+ (row) => row.searchable === true && String(row.processing_status || "").toLowerCase() === "completed"
409
+ )) {
410
+ return {
411
+ ...receipt,
412
+ processing_status: "completed",
413
+ searchable: true,
414
+ results: receipt.results.map((result) => ({
415
+ ...result,
416
+ processing_status: "completed"
417
+ }))
418
+ };
419
+ }
420
+ const remainingMs = deadline - Date.now();
421
+ if (remainingMs <= 0) {
422
+ continue;
423
+ }
424
+ await this.pollingDelay(
425
+ Math.min(pollIntervalMs, remainingMs),
426
+ receipt,
427
+ options
428
+ );
429
+ }
430
+ }
431
+ memoryIds(receipt) {
432
+ return [
433
+ ...new Set(
434
+ (receipt.results || []).map((row) => row.memory_id || row.id).filter((id) => Boolean(id))
435
+ )
436
+ ];
437
+ }
438
+ isSearchableCompletion(receipt) {
439
+ return receipt.searchable === true && String(receipt.processing_status || "").toLowerCase() === "completed";
440
+ }
441
+ isTerminalStatus(status) {
442
+ return ["failed", "cancelled", "canceled"].includes(
443
+ String(status || "").toLowerCase()
444
+ );
445
+ }
446
+ readinessPath(statusUrl, memoryId) {
447
+ try {
448
+ const parsed = new URL(statusUrl, "https://status.hebbrix.invalid");
449
+ if (!["http:", "https:"].includes(parsed.protocol)) {
450
+ return `/v1/memories/${encodeURIComponent(memoryId)}`;
451
+ }
452
+ return `${parsed.pathname}${parsed.search}`;
453
+ } catch {
454
+ return `/v1/memories/${encodeURIComponent(memoryId)}`;
455
+ }
456
+ }
457
+ throwIfPollingAborted(receipt, options) {
458
+ if (options.signal?.aborted) {
459
+ throw new IndexingAbortedError(
460
+ "memory readiness polling was aborted after the write became durable",
461
+ receipt,
462
+ {
463
+ idempotencyKey: options.idempotencyKey,
464
+ cause: options.signal.reason
465
+ }
466
+ );
467
+ }
468
+ }
469
+ async pollingDelay(delayMs, receipt, options) {
470
+ await new Promise((resolve, reject) => {
471
+ const onAbort = () => {
472
+ clearTimeout(timer);
473
+ options.signal?.removeEventListener("abort", onAbort);
474
+ reject(
475
+ new IndexingAbortedError(
476
+ "memory readiness polling was aborted after the write became durable",
477
+ receipt,
478
+ {
479
+ idempotencyKey: options.idempotencyKey,
480
+ cause: options.signal?.reason
481
+ }
482
+ )
483
+ );
484
+ };
485
+ const timer = setTimeout(() => {
486
+ options.signal?.removeEventListener("abort", onAbort);
487
+ resolve();
488
+ }, delayMs);
489
+ options.signal?.addEventListener("abort", onAbort, { once: true });
490
+ if (options.signal?.aborted) {
491
+ onAbort();
492
+ }
261
493
  });
262
494
  }
263
495
  /**
@@ -608,9 +840,12 @@ var ProceduralResource = class extends BaseResource {
608
840
  * Execute a procedure
609
841
  */
610
842
  async execute(procedureId, context) {
611
- const response = await this.client.post(`/v1/procedures/${procedureId}/execute`, {
612
- input_state: context || {}
613
- });
843
+ const response = await this.client.post(
844
+ `/v1/procedures/${procedureId}/execute`,
845
+ {
846
+ input_state: context || {}
847
+ }
848
+ );
614
849
  return response?.execution_result || response;
615
850
  }
616
851
  /**
@@ -627,7 +862,10 @@ var ProceduralResource = class extends BaseResource {
627
862
  body.action = { steps: params.action_sequence };
628
863
  }
629
864
  if (params.metadata !== void 0) body.parameters = params.metadata;
630
- const response = await this.client.patch(`/v1/procedures/${procedureId}`, body);
865
+ const response = await this.client.patch(
866
+ `/v1/procedures/${procedureId}`,
867
+ body
868
+ );
631
869
  return this.unwrapProcedure(response);
632
870
  }
633
871
  /**
@@ -710,7 +948,9 @@ var TemporalResource = class extends BaseResource {
710
948
  */
711
949
  async pointInTime(timestamp, entity) {
712
950
  if (!entity) {
713
- throw new TypeError("entity is required and maps to the canonical subject");
951
+ throw new TypeError(
952
+ "entity is required and maps to the canonical subject"
953
+ );
714
954
  }
715
955
  return this.queryAtTime({
716
956
  timestamp,
@@ -794,7 +1034,8 @@ var MemoryToolsResource = class extends BaseResource {
794
1034
  */
795
1035
  async insert(params) {
796
1036
  const metadata = { ...params.metadata || {} };
797
- if (params.position !== void 0) metadata.requested_position = params.position;
1037
+ if (params.position !== void 0)
1038
+ metadata.requested_position = params.position;
798
1039
  if (params.reason !== void 0) metadata.reason = params.reason;
799
1040
  return this.client.post("/v1/memory-tools/insert", {
800
1041
  collection_id: params.collection_id,
@@ -838,7 +1079,7 @@ var MemoryClient = class {
838
1079
  getHeaders() {
839
1080
  const headers = {
840
1081
  "Content-Type": "application/json",
841
- "User-Agent": "hebbrix-typescript/2.3.0"
1082
+ "User-Agent": "hebbrix-typescript/2.3.1"
842
1083
  };
843
1084
  if (this.apiKey) {
844
1085
  headers["Authorization"] = `Bearer ${this.apiKey}`;
@@ -864,7 +1105,9 @@ var MemoryClient = class {
864
1105
  throw new RateLimitError(message, { code, requestId, details });
865
1106
  } else if (statusCode >= 500) {
866
1107
  throw new ServerError(message, { code, requestId, details });
867
- } else if ((statusCode === 402 || statusCode === 403) && (String(code || "").includes("ENTITLEMENT") || ["feature_not_available", "tier_upgrade_required"].includes(details?.error))) {
1108
+ } else if ((statusCode === 402 || statusCode === 403) && (String(code || "").includes("ENTITLEMENT") || ["feature_not_available", "tier_upgrade_required"].includes(
1109
+ details?.error
1110
+ ))) {
868
1111
  throw new EntitlementError(message, statusCode, {
869
1112
  code,
870
1113
  requestId,
@@ -876,7 +1119,11 @@ var MemoryClient = class {
876
1119
  }
877
1120
  async request(method, path, options = {}) {
878
1121
  const url = `${this.baseUrl}${path}`;
879
- const { headers: requestHeaders, signal: requestSignal, ...requestOptions } = options;
1122
+ const {
1123
+ headers: requestHeaders,
1124
+ signal: requestSignal,
1125
+ ...requestOptions
1126
+ } = options;
880
1127
  const response = await fetch(url, {
881
1128
  ...requestOptions,
882
1129
  method,
@@ -903,6 +1150,21 @@ var MemoryClient = class {
903
1150
  if (!response.ok) {
904
1151
  this.handleError(response, data);
905
1152
  }
1153
+ if (data && typeof data === "object" && !Array.isArray(data)) {
1154
+ const requestId = response.headers.get("X-Request-ID");
1155
+ const statusUrl = response.headers.get("Location");
1156
+ const outboxEventId = response.headers.get("X-Hebbrix-Index-Event");
1157
+ const retryAfter = response.headers.get("Retry-After");
1158
+ const idempotencyReplay = response.headers.get("X-Idempotent-Replay");
1159
+ data = {
1160
+ ...data,
1161
+ ...data.request_id === void 0 && requestId ? { request_id: requestId } : {},
1162
+ ...data.status_url === void 0 && statusUrl ? { status_url: statusUrl } : {},
1163
+ ...data.outbox_event_id === void 0 && outboxEventId ? { outbox_event_id: outboxEventId } : {},
1164
+ ...data.retry_after === void 0 && retryAfter ? { retry_after: retryAfter } : {},
1165
+ ...data.idempotency_replay === void 0 && idempotencyReplay ? { idempotency_replay: idempotencyReplay.toLowerCase() === "true" } : {}
1166
+ };
1167
+ }
906
1168
  return data;
907
1169
  }
908
1170
  async get(path, params) {
@@ -955,7 +1217,10 @@ var MemoryClient = class {
955
1217
  CorrectionsResource,
956
1218
  EntitlementError,
957
1219
  HebbrixError,
1220
+ IndexingAbortedError,
1221
+ IndexingTerminalError,
958
1222
  IndexingTimeoutError,
1223
+ IndexingWaitError,
959
1224
  MemoriesResource,
960
1225
  MemoryClient,
961
1226
  MemoryJobsResource,
package/dist/index.mjs CHANGED
@@ -71,16 +71,72 @@ var EntitlementError = class _EntitlementError extends HebbrixError {
71
71
  Object.setPrototypeOf(this, _EntitlementError.prototype);
72
72
  }
73
73
  };
74
- var IndexingTimeoutError = class _IndexingTimeoutError extends Error {
75
- constructor(message, receipt) {
74
+ var IndexingWaitError = class _IndexingWaitError extends Error {
75
+ constructor(message, receipt, options = {}) {
76
76
  super(message);
77
- this.name = "IndexingTimeoutError";
77
+ this.name = "IndexingWaitError";
78
78
  this.receipt = { ...receipt };
79
- this.memoryIds = [...receipt.memory_ids || []];
80
- this.statusUrl = receipt.status_url;
79
+ this.memoryIds = [
80
+ ...new Set(
81
+ [
82
+ ...receipt.memory_ids || [],
83
+ receipt.memory_id,
84
+ receipt.id,
85
+ ...(receipt.results || []).map(
86
+ (row) => row.memory_id || row.id
87
+ )
88
+ ].filter(Boolean)
89
+ )
90
+ ];
91
+ this.jobId = receipt.job_id;
92
+ this.statusUrl = receipt.status_url || (this.memoryIds.length === 1 ? `/v1/memories/${encodeURIComponent(this.memoryIds[0])}` : this.jobId ? `/v1/memory-jobs/${encodeURIComponent(this.jobId)}` : void 0);
93
+ this.requestId = receipt.request_id;
94
+ this.outboxEventId = receipt.outbox_event_id;
95
+ this.indexingEventId = receipt.indexing_event_id || this.outboxEventId;
96
+ this.eventId = receipt.event_id || this.indexingEventId;
97
+ this.idempotencyReplay = receipt.idempotency_replay;
98
+ this.idempotencyKey = options.idempotencyKey || receipt.idempotency_key;
99
+ this.retryAfter = receipt.retry_after;
100
+ this.recovery = Object.fromEntries(
101
+ Object.entries({
102
+ memory_ids: this.memoryIds,
103
+ job_id: this.jobId,
104
+ status_url: this.statusUrl,
105
+ request_id: this.requestId,
106
+ outbox_event_id: this.outboxEventId,
107
+ indexing_event_id: this.indexingEventId,
108
+ event_id: this.eventId,
109
+ idempotency_key: this.idempotencyKey,
110
+ idempotency_replay: this.idempotencyReplay,
111
+ retry_after: this.retryAfter
112
+ }).filter(([, value]) => value !== void 0 && value !== null)
113
+ );
114
+ this.cause = options.cause;
115
+ Object.setPrototypeOf(this, _IndexingWaitError.prototype);
116
+ }
117
+ };
118
+ var IndexingTimeoutError = class _IndexingTimeoutError extends IndexingWaitError {
119
+ constructor(message, receipt, options = {}) {
120
+ super(message, receipt, options);
121
+ this.name = "IndexingTimeoutError";
81
122
  Object.setPrototypeOf(this, _IndexingTimeoutError.prototype);
82
123
  }
83
124
  };
125
+ var IndexingAbortedError = class _IndexingAbortedError extends IndexingWaitError {
126
+ constructor(message, receipt, options = {}) {
127
+ super(message, receipt, options);
128
+ this.name = "IndexingAbortedError";
129
+ Object.setPrototypeOf(this, _IndexingAbortedError.prototype);
130
+ }
131
+ };
132
+ var IndexingTerminalError = class _IndexingTerminalError extends IndexingWaitError {
133
+ constructor(message, receipt, processingStatus, options = {}) {
134
+ super(message, receipt, options);
135
+ this.name = "IndexingTerminalError";
136
+ this.processingStatus = processingStatus;
137
+ Object.setPrototypeOf(this, _IndexingTerminalError.prototype);
138
+ }
139
+ };
84
140
  var AuthenticationError = class _AuthenticationError extends HebbrixError {
85
141
  constructor(message = "Authentication failed", options = {}) {
86
142
  super(message, 401, options);
@@ -194,22 +250,195 @@ var CollectionsResource = class extends BaseResource {
194
250
  };
195
251
  var MemoriesResource = class extends BaseResource {
196
252
  /**
197
- * Create a new memory
253
+ * Create one logical memory write. When `wait_for_index=true`, a durable
254
+ * pending receipt is polled without issuing a second create request.
198
255
  */
199
256
  async create(params) {
200
257
  if (!params.content?.trim() && !params.messages?.length) {
201
258
  throw new TypeError("content or messages must be provided");
202
259
  }
203
- const { idempotency_key, ...input } = params;
204
- return this.client.request("POST", "/v1/memories", {
205
- headers: idempotency_key ? { "Idempotency-Key": idempotency_key } : void 0,
206
- body: JSON.stringify({
207
- source_type: "text",
208
- metadata: {},
209
- infer: false,
210
- wait_for_index: false,
211
- ...input
212
- })
260
+ const {
261
+ idempotency_key,
262
+ signal,
263
+ index_timeout_ms,
264
+ index_poll_interval_ms,
265
+ ...input
266
+ } = params;
267
+ const receipt = await this.client.request(
268
+ "POST",
269
+ "/v1/memories",
270
+ {
271
+ headers: idempotency_key ? { "Idempotency-Key": idempotency_key } : void 0,
272
+ body: JSON.stringify({
273
+ source_type: "text",
274
+ metadata: {},
275
+ infer: false,
276
+ wait_for_index: false,
277
+ ...input
278
+ }),
279
+ signal
280
+ }
281
+ );
282
+ if (params.wait_for_index && !this.isSearchableCompletion(receipt)) {
283
+ return this.waitForSearchable(receipt, {
284
+ timeoutMs: index_timeout_ms,
285
+ pollIntervalMs: index_poll_interval_ms,
286
+ signal,
287
+ idempotencyKey: idempotency_key
288
+ });
289
+ }
290
+ return receipt;
291
+ }
292
+ /** Poll a single-write durable receipt until every accepted memory is searchable. */
293
+ async waitForSearchable(receipt, options = {}) {
294
+ if (this.isSearchableCompletion(receipt)) {
295
+ return receipt;
296
+ }
297
+ if (this.isTerminalStatus(receipt.processing_status)) {
298
+ const status = String(receipt.processing_status).toLowerCase();
299
+ throw new IndexingTerminalError(
300
+ `memory indexing reached terminal state ${status}`,
301
+ receipt,
302
+ status,
303
+ { idempotencyKey: options.idempotencyKey }
304
+ );
305
+ }
306
+ const ids = this.memoryIds(receipt);
307
+ if (!ids.length) {
308
+ throw new Error("memory receipt does not contain a durable memory id");
309
+ }
310
+ const timeoutMs = Math.max(0, options.timeoutMs ?? 6e4);
311
+ const pollIntervalMs = Math.max(50, options.pollIntervalMs ?? 500);
312
+ const deadline = Date.now() + timeoutMs;
313
+ const paths = ids.map(
314
+ (id, index) => index === 0 && receipt.status_url ? this.readinessPath(receipt.status_url, id) : `/v1/memories/${encodeURIComponent(id)}`
315
+ );
316
+ while (true) {
317
+ this.throwIfPollingAborted(receipt, options);
318
+ if (Date.now() >= deadline) {
319
+ throw new IndexingTimeoutError(
320
+ `memory was not searchable within ${timeoutMs}ms; the write is durable`,
321
+ receipt,
322
+ { idempotencyKey: options.idempotencyKey }
323
+ );
324
+ }
325
+ let rows;
326
+ try {
327
+ rows = await Promise.all(
328
+ paths.map(
329
+ (path) => this.client.request("GET", path, {
330
+ signal: options.signal
331
+ })
332
+ )
333
+ );
334
+ } catch (error) {
335
+ if (options.signal?.aborted) {
336
+ throw new IndexingAbortedError(
337
+ "memory readiness polling was aborted after the write became durable",
338
+ receipt,
339
+ { idempotencyKey: options.idempotencyKey, cause: error }
340
+ );
341
+ }
342
+ throw error;
343
+ }
344
+ const terminal = rows.find(
345
+ (row) => this.isTerminalStatus(row.processing_status)
346
+ );
347
+ if (terminal) {
348
+ const status = String(terminal.processing_status).toLowerCase();
349
+ throw new IndexingTerminalError(
350
+ `memory ${terminal.id} indexing reached terminal state ${status}`,
351
+ receipt,
352
+ status,
353
+ { idempotencyKey: options.idempotencyKey }
354
+ );
355
+ }
356
+ if (rows.every(
357
+ (row) => row.searchable === true && String(row.processing_status || "").toLowerCase() === "completed"
358
+ )) {
359
+ return {
360
+ ...receipt,
361
+ processing_status: "completed",
362
+ searchable: true,
363
+ results: receipt.results.map((result) => ({
364
+ ...result,
365
+ processing_status: "completed"
366
+ }))
367
+ };
368
+ }
369
+ const remainingMs = deadline - Date.now();
370
+ if (remainingMs <= 0) {
371
+ continue;
372
+ }
373
+ await this.pollingDelay(
374
+ Math.min(pollIntervalMs, remainingMs),
375
+ receipt,
376
+ options
377
+ );
378
+ }
379
+ }
380
+ memoryIds(receipt) {
381
+ return [
382
+ ...new Set(
383
+ (receipt.results || []).map((row) => row.memory_id || row.id).filter((id) => Boolean(id))
384
+ )
385
+ ];
386
+ }
387
+ isSearchableCompletion(receipt) {
388
+ return receipt.searchable === true && String(receipt.processing_status || "").toLowerCase() === "completed";
389
+ }
390
+ isTerminalStatus(status) {
391
+ return ["failed", "cancelled", "canceled"].includes(
392
+ String(status || "").toLowerCase()
393
+ );
394
+ }
395
+ readinessPath(statusUrl, memoryId) {
396
+ try {
397
+ const parsed = new URL(statusUrl, "https://status.hebbrix.invalid");
398
+ if (!["http:", "https:"].includes(parsed.protocol)) {
399
+ return `/v1/memories/${encodeURIComponent(memoryId)}`;
400
+ }
401
+ return `${parsed.pathname}${parsed.search}`;
402
+ } catch {
403
+ return `/v1/memories/${encodeURIComponent(memoryId)}`;
404
+ }
405
+ }
406
+ throwIfPollingAborted(receipt, options) {
407
+ if (options.signal?.aborted) {
408
+ throw new IndexingAbortedError(
409
+ "memory readiness polling was aborted after the write became durable",
410
+ receipt,
411
+ {
412
+ idempotencyKey: options.idempotencyKey,
413
+ cause: options.signal.reason
414
+ }
415
+ );
416
+ }
417
+ }
418
+ async pollingDelay(delayMs, receipt, options) {
419
+ await new Promise((resolve, reject) => {
420
+ const onAbort = () => {
421
+ clearTimeout(timer);
422
+ options.signal?.removeEventListener("abort", onAbort);
423
+ reject(
424
+ new IndexingAbortedError(
425
+ "memory readiness polling was aborted after the write became durable",
426
+ receipt,
427
+ {
428
+ idempotencyKey: options.idempotencyKey,
429
+ cause: options.signal?.reason
430
+ }
431
+ )
432
+ );
433
+ };
434
+ const timer = setTimeout(() => {
435
+ options.signal?.removeEventListener("abort", onAbort);
436
+ resolve();
437
+ }, delayMs);
438
+ options.signal?.addEventListener("abort", onAbort, { once: true });
439
+ if (options.signal?.aborted) {
440
+ onAbort();
441
+ }
213
442
  });
214
443
  }
215
444
  /**
@@ -560,9 +789,12 @@ var ProceduralResource = class extends BaseResource {
560
789
  * Execute a procedure
561
790
  */
562
791
  async execute(procedureId, context) {
563
- const response = await this.client.post(`/v1/procedures/${procedureId}/execute`, {
564
- input_state: context || {}
565
- });
792
+ const response = await this.client.post(
793
+ `/v1/procedures/${procedureId}/execute`,
794
+ {
795
+ input_state: context || {}
796
+ }
797
+ );
566
798
  return response?.execution_result || response;
567
799
  }
568
800
  /**
@@ -579,7 +811,10 @@ var ProceduralResource = class extends BaseResource {
579
811
  body.action = { steps: params.action_sequence };
580
812
  }
581
813
  if (params.metadata !== void 0) body.parameters = params.metadata;
582
- const response = await this.client.patch(`/v1/procedures/${procedureId}`, body);
814
+ const response = await this.client.patch(
815
+ `/v1/procedures/${procedureId}`,
816
+ body
817
+ );
583
818
  return this.unwrapProcedure(response);
584
819
  }
585
820
  /**
@@ -662,7 +897,9 @@ var TemporalResource = class extends BaseResource {
662
897
  */
663
898
  async pointInTime(timestamp, entity) {
664
899
  if (!entity) {
665
- throw new TypeError("entity is required and maps to the canonical subject");
900
+ throw new TypeError(
901
+ "entity is required and maps to the canonical subject"
902
+ );
666
903
  }
667
904
  return this.queryAtTime({
668
905
  timestamp,
@@ -746,7 +983,8 @@ var MemoryToolsResource = class extends BaseResource {
746
983
  */
747
984
  async insert(params) {
748
985
  const metadata = { ...params.metadata || {} };
749
- if (params.position !== void 0) metadata.requested_position = params.position;
986
+ if (params.position !== void 0)
987
+ metadata.requested_position = params.position;
750
988
  if (params.reason !== void 0) metadata.reason = params.reason;
751
989
  return this.client.post("/v1/memory-tools/insert", {
752
990
  collection_id: params.collection_id,
@@ -790,7 +1028,7 @@ var MemoryClient = class {
790
1028
  getHeaders() {
791
1029
  const headers = {
792
1030
  "Content-Type": "application/json",
793
- "User-Agent": "hebbrix-typescript/2.3.0"
1031
+ "User-Agent": "hebbrix-typescript/2.3.1"
794
1032
  };
795
1033
  if (this.apiKey) {
796
1034
  headers["Authorization"] = `Bearer ${this.apiKey}`;
@@ -816,7 +1054,9 @@ var MemoryClient = class {
816
1054
  throw new RateLimitError(message, { code, requestId, details });
817
1055
  } else if (statusCode >= 500) {
818
1056
  throw new ServerError(message, { code, requestId, details });
819
- } else if ((statusCode === 402 || statusCode === 403) && (String(code || "").includes("ENTITLEMENT") || ["feature_not_available", "tier_upgrade_required"].includes(details?.error))) {
1057
+ } else if ((statusCode === 402 || statusCode === 403) && (String(code || "").includes("ENTITLEMENT") || ["feature_not_available", "tier_upgrade_required"].includes(
1058
+ details?.error
1059
+ ))) {
820
1060
  throw new EntitlementError(message, statusCode, {
821
1061
  code,
822
1062
  requestId,
@@ -828,7 +1068,11 @@ var MemoryClient = class {
828
1068
  }
829
1069
  async request(method, path, options = {}) {
830
1070
  const url = `${this.baseUrl}${path}`;
831
- const { headers: requestHeaders, signal: requestSignal, ...requestOptions } = options;
1071
+ const {
1072
+ headers: requestHeaders,
1073
+ signal: requestSignal,
1074
+ ...requestOptions
1075
+ } = options;
832
1076
  const response = await fetch(url, {
833
1077
  ...requestOptions,
834
1078
  method,
@@ -855,6 +1099,21 @@ var MemoryClient = class {
855
1099
  if (!response.ok) {
856
1100
  this.handleError(response, data);
857
1101
  }
1102
+ if (data && typeof data === "object" && !Array.isArray(data)) {
1103
+ const requestId = response.headers.get("X-Request-ID");
1104
+ const statusUrl = response.headers.get("Location");
1105
+ const outboxEventId = response.headers.get("X-Hebbrix-Index-Event");
1106
+ const retryAfter = response.headers.get("Retry-After");
1107
+ const idempotencyReplay = response.headers.get("X-Idempotent-Replay");
1108
+ data = {
1109
+ ...data,
1110
+ ...data.request_id === void 0 && requestId ? { request_id: requestId } : {},
1111
+ ...data.status_url === void 0 && statusUrl ? { status_url: statusUrl } : {},
1112
+ ...data.outbox_event_id === void 0 && outboxEventId ? { outbox_event_id: outboxEventId } : {},
1113
+ ...data.retry_after === void 0 && retryAfter ? { retry_after: retryAfter } : {},
1114
+ ...data.idempotency_replay === void 0 && idempotencyReplay ? { idempotency_replay: idempotencyReplay.toLowerCase() === "true" } : {}
1115
+ };
1116
+ }
858
1117
  return data;
859
1118
  }
860
1119
  async get(path, params) {
@@ -906,7 +1165,10 @@ export {
906
1165
  CorrectionsResource,
907
1166
  EntitlementError,
908
1167
  HebbrixError,
1168
+ IndexingAbortedError,
1169
+ IndexingTerminalError,
909
1170
  IndexingTimeoutError,
1171
+ IndexingWaitError,
910
1172
  MemoriesResource,
911
1173
  MemoryClient,
912
1174
  MemoryJobsResource,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hebbrix",
3
- "version": "2.3.0",
3
+ "version": "2.3.1",
4
4
  "description": "Typed TypeScript client for Hebbrix memory, retrieval, and outcome-learning APIs",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
@@ -46,10 +46,14 @@
46
46
  ],
47
47
  "author": "Hebbrix Team <support@hebbrix.com>",
48
48
  "license": "MIT",
49
+ "repository": {
50
+ "type": "git",
51
+ "url": "git+https://github.com/Hebbrix/hebbrix-typescript.git"
52
+ },
49
53
  "bugs": {
50
- "url": "https://www.hebbrix.com/contact"
54
+ "url": "https://github.com/Hebbrix/hebbrix-typescript/issues"
51
55
  },
52
- "homepage": "https://hebbrix.com",
56
+ "homepage": "https://docs.hebbrix.com",
53
57
  "publishConfig": {
54
58
  "access": "public"
55
59
  },