xmemory 1.0.1 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,8 +1,210 @@
1
- # `xmemory`
1
+ # xmemory
2
2
 
3
- Integration code with `xmemory`.
3
+ TypeScript/JavaScript client library for the [Xmemory](https://xmemory.ai) API.
4
4
 
5
- For now just the Mastra prompt.
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install xmemory
9
+ ```
10
+
11
+ ## Quick start
12
+
13
+ ```typescript
14
+ import { XmemoryClient } from "xmemory";
15
+
16
+ const xm = new XmemoryClient({
17
+ url: "https://api.xmemory.ai", // or set XMEM_API_URL env var
18
+ token: "<your-token>", // or set XMEM_AUTH_TOKEN env var
19
+ });
20
+
21
+ // Write and read from an existing instance
22
+ const inst = xm.instance("<your-instance-id>");
23
+
24
+ await inst.write("Alice is a software engineer who loves TypeScript.");
25
+ const result = await inst.read("What does Alice do?");
26
+ console.log(result.reader_result);
27
+ ```
28
+
29
+ ## Configuration
30
+
31
+ | Parameter | Env var | Default | Description |
32
+ |-------------|-------------------|----------------------------|----------------------------------------|
33
+ | `url` | `XMEM_API_URL` | `https://api.xmemory.ai` | Base URL of the Xmemory API |
34
+ | `token` | `XMEM_AUTH_TOKEN` | `undefined` | Bearer token for authentication |
35
+ | `timeoutMs` | — | `60000` | Default request timeout in milliseconds |
36
+
37
+ ## Creating a client
38
+
39
+ ```typescript
40
+ import { XmemoryClient, xmemoryInstance } from "xmemory";
41
+
42
+ // Option 1: constructor (no health check)
43
+ const xm1 = new XmemoryClient({ token: "..." });
44
+
45
+ // Option 2: factory with health check
46
+ const xm2 = await XmemoryClient.create({ token: "..." });
47
+
48
+ // Option 3: convenience function (same as Option 2)
49
+ const xm3 = await xmemoryInstance({ token: "..." });
50
+ ```
51
+
52
+ ## Admin operations
53
+
54
+ All cluster and instance management lives under `client.admin`.
55
+
56
+ ### Clusters
57
+
58
+ ```typescript
59
+ const clusters = await xm.admin.listClusters();
60
+ const cluster = await xm.admin.getCluster(clusterId);
61
+ ```
62
+
63
+ ### Create an instance
64
+
65
+ ```typescript
66
+ import { SchemaType } from "xmemory";
67
+
68
+ const inst = await xm.admin.createInstance(
69
+ clusterId,
70
+ "my-instance",
71
+ schemaYml,
72
+ SchemaType.YML,
73
+ { description: "User profiles" },
74
+ );
75
+
76
+ // inst is an InstanceHandle — use it directly for data operations
77
+ await inst.write("Alice joined the team.");
78
+ ```
79
+
80
+ ### List and get instances
81
+
82
+ ```typescript
83
+ const instances = await xm.admin.listInstances();
84
+ const info = await xm.admin.getInstance(instanceId);
85
+ ```
86
+
87
+ ### Schema operations
88
+
89
+ ```typescript
90
+ const schema = await xm.admin.getInstanceSchema(instanceId);
91
+ await xm.admin.updateInstanceSchema(instanceId, newYml, SchemaType.YML);
92
+ ```
93
+
94
+ ### Generate schema
95
+
96
+ ```typescript
97
+ const result = await xm.admin.generateSchema(clusterId, "Track user profiles and preferences");
98
+ console.log(result.data_schema);
99
+ ```
100
+
101
+ ### Update metadata and delete
102
+
103
+ ```typescript
104
+ await xm.admin.updateInstanceMetadata(instanceId, "new-name", "new description");
105
+ const deletedIds = await xm.admin.deleteInstance(instanceId);
106
+ ```
107
+
108
+ ## Instance data operations
109
+
110
+ Get a handle to an instance and use it for reads, writes, and extractions.
111
+
112
+ ```typescript
113
+ const inst = xm.instance("<instance-id>");
114
+ ```
115
+
116
+ ### `inst.write(text, options?)` → `WriteResult`
117
+
118
+ Extract and store structured objects from text.
119
+
120
+ ```typescript
121
+ const result = await inst.write("Bob is a designer based in Berlin.");
122
+ console.log(result.write_id, result.trace_id);
123
+ ```
124
+
125
+ Options: `{ extractionLogic?, diffEngine?, timeoutMs? }` — `extractionLogic` defaults to `"deep"`.
126
+
127
+ ### `inst.writeAsync(text, options?)` → `AsyncWriteResult`
128
+
129
+ Start an asynchronous write. Returns a `write_id` for tracking.
130
+
131
+ ```typescript
132
+ const { write_id } = await inst.writeAsync("Carol manages the London office.");
133
+ ```
134
+
135
+ ### `inst.writeStatus(writeId, options?)` → `WriteStatusResult`
136
+
137
+ Poll the status of an async write.
138
+
139
+ ```typescript
140
+ const status = await inst.writeStatus(write_id);
141
+ console.log(status.write_status); // "queued" | "processing" | "completed" | "failed" | "not_found"
142
+ ```
143
+
144
+ ### `inst.read(query, options?)` → `ReadResult`
145
+
146
+ Query the instance.
147
+
148
+ ```typescript
149
+ const result = await inst.read("Who is on the team?");
150
+ console.log(result.reader_result);
151
+ ```
152
+
153
+ Options: `{ readMode?, traceId?, timeoutMs? }` — `readMode` defaults to `"single-answer"`.
154
+
155
+ ### `inst.extract(text, options?)` → `ExtractResult`
156
+
157
+ Extract objects from text without storing them.
158
+
159
+ ```typescript
160
+ const result = await inst.extract("Dave is an engineer in Tokyo.");
161
+ console.log(result.objects_extracted);
162
+ ```
163
+
164
+ ### `inst.getSchema(options?)` → `InstanceSchemaInfo`
165
+
166
+ ```typescript
167
+ const schema = await inst.getSchema();
168
+ console.log(schema.data_schema);
169
+ ```
170
+
171
+ ## Error handling
172
+
173
+ All errors throw `XmemoryAPIError`. Health check failures throw `XmemoryHealthCheckError` (a subclass).
174
+
175
+ ```typescript
176
+ import { XmemoryClient, XmemoryAPIError, XmemoryHealthCheckError } from "xmemory";
177
+
178
+ try {
179
+ const xm = await XmemoryClient.create({ token: "..." });
180
+ } catch (e) {
181
+ if (e instanceof XmemoryHealthCheckError) {
182
+ console.error("Server unreachable:", e.message);
183
+ }
184
+ }
185
+
186
+ try {
187
+ await inst.read("query");
188
+ } catch (e) {
189
+ if (e instanceof XmemoryAPIError) {
190
+ console.error(`API error (HTTP ${e.status}): ${e.message}`);
191
+ }
192
+ }
193
+ ```
194
+
195
+ ## All timeouts are per-request
196
+
197
+ Every method accepts an optional `timeoutMs` in its options bag, overriding the client default.
198
+
199
+ ```typescript
200
+ const result = await inst.read("query", { timeoutMs: 120_000 });
201
+ ```
202
+
203
+ ---
204
+
205
+ ## Mastra integration
206
+
207
+ You can also use `xmemory` as an MCP server within [Mastra.ai](https://mastra.ai).
6
208
 
7
209
  First, create a local Mastra instance:
8
210
 
package/dist/client.d.ts CHANGED
@@ -1,37 +1,44 @@
1
1
  /**
2
- * xmemory HTTP client for Node.js.
2
+ * XmemoryClient main entry point for the xmemory API.
3
3
  */
4
- import type { ReadResponse, SchemaTypeValue, WriteResponse } from "./types.js";
5
- export { SchemaType } from "./types.js";
6
- export type { SchemaTypeValue, CreateInstanceResponse, WriteResponse, ReadResponse, ReaderResult } from "./types.js";
7
- export declare class XmemoryAPIError extends Error {
8
- readonly status?: number | undefined;
9
- constructor(message: string, status?: number | undefined);
10
- }
11
- export interface XmemoryInstanceOptions {
12
- url?: string;
13
- token?: string;
14
- timeout?: number;
4
+ import { InstanceHandle } from "./instance.js";
5
+ import { type ClusterInfo, type CreateInstanceOptions, type GenerateSchemaOptions, type GenerateSchemaResult, type InstanceInfo, type InstanceSchemaInfo, type RequestOptions, type SchemaTypeValue, type XmemoryClientOptions } from "./types.js";
6
+ export interface AdminNamespace {
7
+ listClusters(options?: RequestOptions & {
8
+ ids?: string[];
9
+ }): Promise<ClusterInfo[]>;
10
+ getCluster(clusterId: string, options?: RequestOptions): Promise<ClusterInfo>;
11
+ createInstance(clusterId: string, name: string, schemaText: string, schemaType: SchemaTypeValue, options?: CreateInstanceOptions): Promise<InstanceHandle>;
12
+ listInstances(options?: RequestOptions & {
13
+ ids?: string[];
14
+ }): Promise<InstanceInfo[]>;
15
+ getInstance(instanceId: string, options?: RequestOptions): Promise<InstanceInfo>;
16
+ deleteInstance(instanceId: string, options?: RequestOptions): Promise<string[]>;
17
+ getInstanceSchema(instanceId: string, options?: RequestOptions): Promise<InstanceSchemaInfo>;
18
+ updateInstanceSchema(instanceId: string, schemaText: string, schemaType: SchemaTypeValue, options?: RequestOptions): Promise<InstanceInfo>;
19
+ updateInstanceMetadata(instanceId: string, name: string, description: string, options?: RequestOptions): Promise<InstanceInfo>;
20
+ generateSchema(clusterId: string, schemaDescription: string, options?: GenerateSchemaOptions): Promise<GenerateSchemaResult>;
15
21
  }
16
22
  export declare class XmemoryClient {
17
- readonly baseUrl: string;
18
- readonly timeoutMs: number;
19
- readonly token: string | undefined;
20
- instanceId: string | null;
21
- constructor(options?: XmemoryInstanceOptions);
22
- static create(options?: XmemoryInstanceOptions): Promise<XmemoryClient>;
23
- private checkHealth;
24
- private requireInstanceId;
25
- createInstance(schemaText: string, schemaType: SchemaTypeValue, timeout?: number): Promise<boolean>;
26
- write(text: string, options?: {
27
- timeout?: number;
28
- }): Promise<WriteResponse>;
29
- read(query: string, options?: {
30
- timeout?: number;
31
- }): Promise<ReadResponse>;
32
- get instance_id(): string | null;
23
+ private readonly _baseUrl;
24
+ private readonly _timeoutMs;
25
+ private readonly _token;
26
+ readonly admin: AdminNamespace;
27
+ constructor(options?: XmemoryClientOptions);
28
+ /** Factory that performs a health check before returning the client. */
29
+ static create(options?: XmemoryClientOptions): Promise<XmemoryClient>;
30
+ /** Return an InstanceHandle scoped to the given instance ID. */
31
+ instance(instanceId: string): InstanceHandle;
32
+ /** GET /healthz — throws XmemoryHealthCheckError on failure. */
33
+ checkHealth(): Promise<void>;
34
+ private _fetch;
35
+ private _headers;
36
+ /** Core request — returns the raw API wrapper `{ids, items, errors}`. */
37
+ private _request;
38
+ private _requestOne;
39
+ private _requestList;
40
+ private _requestIds;
41
+ private _buildAdmin;
33
42
  }
34
- /**
35
- * Create an xmemory client.
36
- */
37
- export declare function xmemoryInstance(options?: XmemoryInstanceOptions): Promise<XmemoryClient>;
43
+ /** Convenience factory — creates a client with a health check. */
44
+ export declare function xmemoryInstance(options?: XmemoryClientOptions): Promise<XmemoryClient>;
package/dist/client.js CHANGED
@@ -1,140 +1,208 @@
1
1
  /**
2
- * xmemory HTTP client for Node.js.
2
+ * XmemoryClient main entry point for the xmemory API.
3
3
  */
4
- export { SchemaType } from "./types.js";
5
- const DEFAULT_BASE_URL = "http://0.0.0.0:8000";
4
+ import { InstanceHandle } from "./instance.js";
5
+ import { XmemoryAPIError, XmemoryHealthCheckError, buildInstanceSchema, } from "./types.js";
6
+ const DEFAULT_BASE_URL = "https://api.xmemory.ai";
6
7
  const DEFAULT_TIMEOUT_MS = 60_000;
7
- export class XmemoryAPIError extends Error {
8
- status;
9
- constructor(message, status) {
10
- super(message);
11
- this.status = status;
12
- this.name = "XmemoryAPIError";
13
- }
14
- }
15
- async function getEnv(name) {
16
- if (typeof process !== "undefined" && process.env) {
17
- return process.env[name];
18
- }
19
- return undefined;
20
- }
21
- async function fetchWithTimeout(url, options) {
22
- const { timeoutMs = DEFAULT_TIMEOUT_MS, ...fetchOptions } = options;
23
- const controller = new AbortController();
24
- const id = setTimeout(() => controller.abort(), timeoutMs);
25
- try {
26
- const res = await fetch(url, {
27
- ...fetchOptions,
28
- signal: controller.signal,
29
- });
30
- return res;
31
- }
32
- finally {
33
- clearTimeout(id);
34
- }
35
- }
36
- async function postJson(baseUrl, path, body, token, timeoutMs) {
37
- const url = `${baseUrl.replace(/\/$/, "")}${path}`;
38
- const headers = {
39
- Accept: "application/json",
40
- "Content-Type": "application/json",
41
- };
42
- if (token) {
43
- headers["Authorization"] = `Bearer ${token}`;
44
- }
45
- const res = await fetchWithTimeout(url, {
46
- method: "POST",
47
- headers,
48
- body: JSON.stringify(body),
49
- timeoutMs,
50
- });
51
- const raw = await res.text();
52
- let payload;
53
- try {
54
- payload = raw ? JSON.parse(raw) : {};
55
- }
56
- catch {
57
- throw new XmemoryAPIError(`Invalid JSON from server (${res.status})`, res.status);
58
- }
59
- if (typeof payload === "object" && payload !== null && payload.status === "error") {
60
- const err = payload;
61
- const msg = err.error_message || err.error || String(payload);
62
- throw new XmemoryAPIError(`${path} failed: ${msg}`, res.status);
63
- }
64
- if (!res.ok) {
65
- throw new XmemoryAPIError(`HTTP ${res.status}: ${raw.slice(0, 200)}`, res.status);
66
- }
67
- return payload;
68
- }
8
+ // ---------------------------------------------------------------------------
9
+ // Client
10
+ // ---------------------------------------------------------------------------
69
11
  export class XmemoryClient {
70
- baseUrl;
71
- timeoutMs;
72
- token;
73
- instanceId = null;
12
+ _baseUrl;
13
+ _timeoutMs;
14
+ _token;
15
+ admin;
74
16
  constructor(options = {}) {
75
- this.baseUrl = options.url ?? "";
76
- this.timeoutMs = (options.timeout ?? 60) * 1000;
77
- this.token = options.token;
17
+ const env = typeof process !== "undefined" ? process.env : undefined;
18
+ this._baseUrl = (options.url ?? env?.XMEM_API_URL ?? DEFAULT_BASE_URL).replace(/\/+$/, "");
19
+ this._token = options.token ?? env?.XMEM_AUTH_TOKEN;
20
+ this._timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
21
+ this.admin = this._buildAdmin();
78
22
  }
23
+ /** Factory that performs a health check before returning the client. */
79
24
  static async create(options = {}) {
80
- const url = options.url ?? (await getEnv("XMEM_API_URL")) ?? DEFAULT_BASE_URL;
81
- const token = options.token ?? (await getEnv("XMEM_AUTH_TOKEN"));
82
- const client = new XmemoryClient({ ...options, url, token });
25
+ const client = new XmemoryClient(options);
83
26
  await client.checkHealth();
84
27
  return client;
85
28
  }
29
+ /** Return an InstanceHandle scoped to the given instance ID. */
30
+ instance(instanceId) {
31
+ return new InstanceHandle(instanceId, this._requestOne.bind(this));
32
+ }
33
+ /** GET /healthz — throws XmemoryHealthCheckError on failure. */
86
34
  async checkHealth() {
87
- const url = `${this.baseUrl.replace(/\/$/, "")}/api/healthz`;
88
- const res = await fetchWithTimeout(url, {
89
- method: "GET",
90
- headers: { Accept: "application/json" },
91
- timeoutMs: this.timeoutMs,
92
- });
93
- if (!res.ok) {
94
- throw new XmemoryAPIError(`Health check failed: ${res.status} at ${url}`, res.status);
35
+ const url = `${this._baseUrl}/healthz`;
36
+ try {
37
+ const res = await this._fetch(url, { method: "GET" }, this._timeoutMs);
38
+ if (!res.ok) {
39
+ throw new XmemoryHealthCheckError(`Health check failed: HTTP ${res.status} at ${url}`, res.status);
40
+ }
95
41
  }
96
- }
97
- requireInstanceId(op) {
98
- if (!this.instanceId) {
99
- throw new XmemoryAPIError(`instance_id is required for ${op}() but none was provided or saved.`);
42
+ catch (err) {
43
+ if (err instanceof XmemoryHealthCheckError)
44
+ throw err;
45
+ throw new XmemoryHealthCheckError(`Health check failed: ${err instanceof Error ? err.message : String(err)}`);
100
46
  }
101
- return this.instanceId;
102
47
  }
103
- async createInstance(schemaText, schemaType, timeout) {
104
- const path = "/instance/create";
105
- const body = schemaType === 0 ? { yml_schema: schemaText } : { json_schema: schemaText };
106
- const timeoutMs = timeout != null ? timeout * 1000 : this.timeoutMs;
107
- const response = await postJson(this.baseUrl, path, body, this.token, timeoutMs);
108
- if (response.status === "ok" && response.instance_id) {
109
- this.instanceId = response.instance_id;
48
+ // -----------------------------------------------------------------------
49
+ // Private: HTTP layer
50
+ // -----------------------------------------------------------------------
51
+ async _fetch(url, init, timeoutMs) {
52
+ const controller = new AbortController();
53
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
54
+ try {
55
+ return await fetch(url, { ...init, signal: controller.signal });
56
+ }
57
+ finally {
58
+ clearTimeout(timer);
110
59
  }
111
- return response.status === "ok";
112
- }
113
- async write(text, options) {
114
- const iid = this.requireInstanceId("write");
115
- const timeoutMs = options?.timeout != null ? options.timeout * 1000 : this.timeoutMs;
116
- return postJson(this.baseUrl, "/write", {
117
- instance_id: iid,
118
- text,
119
- extraction_logic: "deep",
120
- }, this.token, timeoutMs);
121
60
  }
122
- async read(query, options) {
123
- const iid = this.requireInstanceId("read");
124
- const timeoutMs = options?.timeout != null ? options.timeout * 1000 : this.timeoutMs;
125
- return postJson(this.baseUrl, "/read", {
126
- instance_id: iid,
127
- query,
128
- mode: "single-answer",
129
- }, this.token, timeoutMs);
61
+ _headers(hasBody = false) {
62
+ const h = {
63
+ Accept: "application/json",
64
+ };
65
+ if (hasBody)
66
+ h["Content-Type"] = "application/json";
67
+ if (this._token)
68
+ h["Authorization"] = `Bearer ${this._token}`;
69
+ return h;
70
+ }
71
+ /** Core request — returns the raw API wrapper `{ids, items, errors}`. */
72
+ async _request(method, path, options) {
73
+ let url = `${this._baseUrl}${path}`;
74
+ if (options?.params) {
75
+ const sp = new URLSearchParams();
76
+ for (const [key, val] of Object.entries(options.params)) {
77
+ if (Array.isArray(val)) {
78
+ for (const v of val)
79
+ sp.append(key, v);
80
+ }
81
+ else {
82
+ sp.append(key, val);
83
+ }
84
+ }
85
+ const qs = sp.toString();
86
+ if (qs)
87
+ url += `?${qs}`;
88
+ }
89
+ const timeoutMs = options?.timeoutMs ?? this._timeoutMs;
90
+ const hasBody = !!(options?.body && method !== "GET");
91
+ const init = { method, headers: this._headers(hasBody) };
92
+ if (hasBody) {
93
+ init.body = JSON.stringify(options.body);
94
+ }
95
+ const res = await this._fetch(url, init, timeoutMs);
96
+ const raw = await res.text();
97
+ let payload;
98
+ try {
99
+ payload = raw ? JSON.parse(raw) : {};
100
+ }
101
+ catch {
102
+ throw new XmemoryAPIError(`Invalid JSON from server (${res.status}): ${raw.slice(0, 200)}`, res.status);
103
+ }
104
+ if (!res.ok) {
105
+ const msg = typeof payload === "object" && payload !== null && "message" in payload
106
+ ? String(payload.message)
107
+ : raw.slice(0, 200);
108
+ throw new XmemoryAPIError(`HTTP ${res.status}: ${msg}`, res.status);
109
+ }
110
+ const response = payload;
111
+ if (response.errors?.length) {
112
+ const first = response.errors[0];
113
+ throw new XmemoryAPIError(`API error: ${first.message} (${first.code})`, res.status);
114
+ }
115
+ return response;
130
116
  }
131
- get instance_id() {
132
- return this.instanceId;
117
+ async _requestOne(method, path, options) {
118
+ const response = await this._request(method, path, options);
119
+ const items = response.items ?? [];
120
+ if (items.length === 0) {
121
+ throw new XmemoryAPIError(`Expected one item from ${method} ${path}, got none`);
122
+ }
123
+ if (items.length > 1) {
124
+ throw new XmemoryAPIError(`Expected one item from ${method} ${path}, got ${items.length}`);
125
+ }
126
+ return items[0];
127
+ }
128
+ async _requestList(method, path, options) {
129
+ const response = await this._request(method, path, options);
130
+ return (response.items ?? []);
131
+ }
132
+ async _requestIds(method, path, options) {
133
+ const response = await this._request(method, path, options);
134
+ return response.ids ?? [];
135
+ }
136
+ // -----------------------------------------------------------------------
137
+ // Private: build admin namespace
138
+ // -----------------------------------------------------------------------
139
+ _buildAdmin() {
140
+ return {
141
+ listClusters: async (options) => {
142
+ const params = options?.ids ? { ids: options.ids } : undefined;
143
+ return this._requestList("GET", "/clusters", { params, timeoutMs: options?.timeoutMs });
144
+ },
145
+ getCluster: async (clusterId, options) => {
146
+ return this._requestOne("GET", `/clusters/${clusterId}`, {
147
+ timeoutMs: options?.timeoutMs,
148
+ });
149
+ },
150
+ createInstance: async (clusterId, name, schemaText, schemaType, options) => {
151
+ const body = {
152
+ name,
153
+ instance_schema: buildInstanceSchema(schemaText, schemaType),
154
+ };
155
+ if (options?.description != null)
156
+ body.description = options.description;
157
+ if (options?.schemaDescription != null)
158
+ body.schema_description = options.schemaDescription;
159
+ const info = await this._requestOne("POST", `/clusters/${clusterId}/instances`, {
160
+ body,
161
+ timeoutMs: options?.timeoutMs,
162
+ });
163
+ return this.instance(info.id);
164
+ },
165
+ listInstances: async (options) => {
166
+ const params = options?.ids ? { ids: options.ids } : undefined;
167
+ return this._requestList("GET", "/instances", { params, timeoutMs: options?.timeoutMs });
168
+ },
169
+ getInstance: async (instanceId, options) => {
170
+ return this._requestOne("GET", `/instances/${instanceId}`, {
171
+ timeoutMs: options?.timeoutMs,
172
+ });
173
+ },
174
+ deleteInstance: async (instanceId, options) => {
175
+ return this._requestIds("DELETE", `/instances/${instanceId}`, {
176
+ timeoutMs: options?.timeoutMs,
177
+ });
178
+ },
179
+ getInstanceSchema: async (instanceId, options) => {
180
+ return this._requestOne("GET", `/instances/${instanceId}/schema`, {
181
+ timeoutMs: options?.timeoutMs,
182
+ });
183
+ },
184
+ updateInstanceSchema: async (instanceId, schemaText, schemaType, options) => {
185
+ return this._requestOne("PUT", `/instances/${instanceId}/schema`, {
186
+ body: { instance_schema: buildInstanceSchema(schemaText, schemaType) },
187
+ timeoutMs: options?.timeoutMs,
188
+ });
189
+ },
190
+ updateInstanceMetadata: async (instanceId, name, description, options) => {
191
+ return this._requestOne("PUT", `/instances/${instanceId}`, {
192
+ body: { name, description },
193
+ timeoutMs: options?.timeoutMs,
194
+ });
195
+ },
196
+ generateSchema: async (clusterId, schemaDescription, options) => {
197
+ const body = { schema_description: schemaDescription };
198
+ if (options?.currentYmlSchema != null)
199
+ body.current_yml_schema = options.currentYmlSchema;
200
+ return this._requestOne("POST", `/clusters/${clusterId}/instances/generate_schema`, { body, timeoutMs: options?.timeoutMs });
201
+ },
202
+ };
133
203
  }
134
204
  }
135
- /**
136
- * Create an xmemory client.
137
- */
205
+ /** Convenience factory — creates a client with a health check. */
138
206
  export async function xmemoryInstance(options = {}) {
139
207
  return XmemoryClient.create(options);
140
208
  }
@@ -0,0 +1,11 @@
1
+ /**
2
+ * xmemory — TypeScript client for the xmemory API.
3
+ */
4
+ export { XmemoryClient, xmemoryInstance } from "./client.js";
5
+ export type { AdminNamespace } from "./client.js";
6
+ export { InstanceHandle } from "./instance.js";
7
+ export { XmemoryAPIError, XmemoryHealthCheckError } from "./types.js";
8
+ export { SchemaType } from "./types.js";
9
+ export type { SchemaTypeValue, ExtractionLogic, ReadMode, WriteQueueStatus } from "./types.js";
10
+ export type { XmemoryClientOptions, RequestOptions, ReadOptions, WriteOptions, ExtractOptions, CreateInstanceOptions, GenerateSchemaOptions, } from "./types.js";
11
+ export type { ClusterInfo, InstanceInfo, InstanceSchemaInfo, ReadResult, WriteResult, AsyncWriteResult, WriteStatusResult, ExtractResult, GenerateSchemaResult, } from "./types.js";
package/dist/index.js ADDED
@@ -0,0 +1,11 @@
1
+ /**
2
+ * xmemory — TypeScript client for the xmemory API.
3
+ */
4
+ // Client
5
+ export { XmemoryClient, xmemoryInstance } from "./client.js";
6
+ // Instance handle
7
+ export { InstanceHandle } from "./instance.js";
8
+ // Error classes
9
+ export { XmemoryAPIError, XmemoryHealthCheckError } from "./types.js";
10
+ // Enums
11
+ export { SchemaType } from "./types.js";
@@ -0,0 +1,15 @@
1
+ /**
2
+ * InstanceHandle — scoped data operations on a single xmemory instance.
3
+ */
4
+ import type { AsyncWriteResult, ExtractOptions, ExtractResult, InstanceSchemaInfo, ReadOptions, ReadResult, RequestOneFn, RequestOptions, WriteOptions, WriteResult, WriteStatusResult } from "./types.js";
5
+ export declare class InstanceHandle {
6
+ readonly id: string;
7
+ private readonly _requestOne;
8
+ constructor(id: string, requestOne: RequestOneFn);
9
+ read(query: string, options?: ReadOptions): Promise<ReadResult>;
10
+ write(text: string, options?: WriteOptions): Promise<WriteResult>;
11
+ writeAsync(text: string, options?: WriteOptions): Promise<AsyncWriteResult>;
12
+ writeStatus(writeId: string, options?: RequestOptions): Promise<WriteStatusResult>;
13
+ extract(text: string, options?: ExtractOptions): Promise<ExtractResult>;
14
+ getSchema(options?: RequestOptions): Promise<InstanceSchemaInfo>;
15
+ }
@@ -0,0 +1,68 @@
1
+ /**
2
+ * InstanceHandle — scoped data operations on a single xmemory instance.
3
+ */
4
+ export class InstanceHandle {
5
+ id;
6
+ _requestOne;
7
+ constructor(id, requestOne) {
8
+ this.id = id;
9
+ this._requestOne = requestOne;
10
+ }
11
+ async read(query, options) {
12
+ const body = {
13
+ query,
14
+ mode: options?.readMode ?? "single-answer",
15
+ };
16
+ if (options?.traceId != null)
17
+ body.trace_id = options.traceId;
18
+ return this._requestOne("POST", `/instances/${this.id}/read`, {
19
+ body,
20
+ timeoutMs: options?.timeoutMs,
21
+ });
22
+ }
23
+ async write(text, options) {
24
+ const body = {
25
+ text,
26
+ extraction_logic: options?.extractionLogic ?? "deep",
27
+ };
28
+ if (options?.diffEngine != null)
29
+ body.diff_engine = options.diffEngine;
30
+ return this._requestOne("POST", `/instances/${this.id}/write`, {
31
+ body,
32
+ timeoutMs: options?.timeoutMs,
33
+ });
34
+ }
35
+ async writeAsync(text, options) {
36
+ const body = {
37
+ text,
38
+ extraction_logic: options?.extractionLogic ?? "deep",
39
+ };
40
+ if (options?.diffEngine != null)
41
+ body.diff_engine = options.diffEngine;
42
+ return this._requestOne("POST", `/instances/${this.id}/write_async`, {
43
+ body,
44
+ timeoutMs: options?.timeoutMs,
45
+ });
46
+ }
47
+ async writeStatus(writeId, options) {
48
+ return this._requestOne("POST", `/instances/${this.id}/write_status`, {
49
+ body: { write_id: writeId },
50
+ timeoutMs: options?.timeoutMs,
51
+ });
52
+ }
53
+ async extract(text, options) {
54
+ const body = {
55
+ text,
56
+ extraction_logic: options?.extractionLogic ?? "deep",
57
+ };
58
+ return this._requestOne("POST", `/instances/${this.id}/extract`, {
59
+ body,
60
+ timeoutMs: options?.timeoutMs,
61
+ });
62
+ }
63
+ async getSchema(options) {
64
+ return this._requestOne("GET", `/instances/${this.id}/schema`, {
65
+ timeoutMs: options?.timeoutMs,
66
+ });
67
+ }
68
+ }
package/dist/types.d.ts CHANGED
@@ -1,39 +1,111 @@
1
1
  /**
2
- * Types for the xmemory API.
2
+ * Types, enums, and error classes for the xmemory API.
3
3
  */
4
4
  export declare const SchemaType: {
5
5
  readonly YML: 0;
6
6
  readonly JSON: 1;
7
7
  };
8
8
  export type SchemaTypeValue = (typeof SchemaType)[keyof typeof SchemaType];
9
- export interface CreateInstanceYMLRequest {
10
- yml_schema: string;
9
+ export type ExtractionLogic = "fast" | "regular" | "deep";
10
+ export type ReadMode = "single-answer" | "raw-tables" | "xresponse";
11
+ export type WriteQueueStatus = "queued" | "processing" | "completed" | "failed" | "not_found";
12
+ export declare class XmemoryAPIError extends Error {
13
+ readonly status?: number | undefined;
14
+ constructor(message: string, status?: number | undefined);
11
15
  }
12
- export interface CreateInstanceResponse {
13
- status: "ok" | "error";
14
- instance_id?: string | null;
15
- error_message?: string | null;
16
+ export declare class XmemoryHealthCheckError extends XmemoryAPIError {
17
+ constructor(message: string, status?: number);
16
18
  }
17
- export interface WriteRequest {
18
- instance_id: string;
19
- text: string;
20
- extraction_logic?: "fast" | "regular" | "deep";
19
+ export interface ClusterInfo {
20
+ readonly id: string;
21
+ readonly org_id: string;
22
+ readonly name: string;
23
+ readonly description: string | null;
21
24
  }
22
- export interface WriteResponse {
23
- status: "ok" | "error";
24
- error_message?: string | null;
25
+ export interface InstanceInfo {
26
+ readonly id: string;
27
+ readonly cluster_id: string;
28
+ readonly name: string;
29
+ readonly description: string | null;
30
+ readonly data_schema: Record<string, unknown> | null;
25
31
  }
26
- export interface ReadRequest {
27
- instance_id: string;
28
- query: string;
29
- mode?: "single-answer" | "raw-tables" | "xresponse";
32
+ export interface InstanceSchemaInfo {
33
+ readonly data_schema: Record<string, unknown>;
30
34
  }
31
- export interface ReaderResult {
32
- answer?: string;
33
- [key: string]: unknown;
35
+ export interface ReadResult {
36
+ readonly trace_id: string | null;
37
+ readonly reader_result: unknown;
34
38
  }
35
- export interface ReadResponse {
36
- status: "ok" | "error";
37
- reader_result?: ReaderResult | null;
38
- error_message?: string | null;
39
+ export interface WriteResult {
40
+ readonly write_id: string;
41
+ readonly trace_id: string | null;
42
+ readonly cleaned_objects: unknown;
43
+ readonly diff_plan: unknown;
39
44
  }
45
+ export interface AsyncWriteResult {
46
+ readonly write_id: string;
47
+ }
48
+ export interface WriteStatusResult {
49
+ readonly write_id: string;
50
+ readonly write_status: WriteQueueStatus;
51
+ readonly error_detail: string | null;
52
+ readonly completed_at: string | null;
53
+ }
54
+ export interface ExtractResult {
55
+ readonly trace_id: string | null;
56
+ readonly objects_extracted: unknown;
57
+ }
58
+ export interface GenerateSchemaResult {
59
+ readonly data_schema: Record<string, unknown>;
60
+ }
61
+ export interface XmemoryClientOptions {
62
+ url?: string;
63
+ token?: string;
64
+ timeoutMs?: number;
65
+ }
66
+ export interface RequestOptions {
67
+ timeoutMs?: number;
68
+ }
69
+ export interface ReadOptions {
70
+ readMode?: ReadMode;
71
+ traceId?: string;
72
+ timeoutMs?: number;
73
+ }
74
+ export interface WriteOptions {
75
+ extractionLogic?: ExtractionLogic;
76
+ diffEngine?: boolean;
77
+ timeoutMs?: number;
78
+ }
79
+ export interface ExtractOptions {
80
+ extractionLogic?: ExtractionLogic;
81
+ timeoutMs?: number;
82
+ }
83
+ export interface CreateInstanceOptions {
84
+ description?: string;
85
+ schemaDescription?: string;
86
+ timeoutMs?: number;
87
+ }
88
+ export interface GenerateSchemaOptions {
89
+ currentYmlSchema?: string;
90
+ timeoutMs?: number;
91
+ }
92
+ export interface ApiError {
93
+ readonly code: string;
94
+ readonly message: string;
95
+ readonly field?: string;
96
+ readonly resource_id?: string;
97
+ }
98
+ export interface RawApiResponse {
99
+ readonly ids?: string[];
100
+ readonly items?: unknown[];
101
+ readonly errors?: ApiError[];
102
+ }
103
+ export interface InternalRequestOptions {
104
+ body?: Record<string, unknown>;
105
+ params?: Record<string, string | string[]>;
106
+ timeoutMs?: number;
107
+ }
108
+ export type RequestOneFn = <T>(method: string, path: string, options?: InternalRequestOptions) => Promise<T>;
109
+ export type RequestListFn = <T>(method: string, path: string, options?: InternalRequestOptions) => Promise<T[]>;
110
+ export type RequestIdsFn = (method: string, path: string, options?: InternalRequestOptions) => Promise<string[]>;
111
+ export declare function buildInstanceSchema(schemaText: string, schemaType: SchemaTypeValue): Record<string, unknown>;
package/dist/types.js CHANGED
@@ -1,7 +1,30 @@
1
1
  /**
2
- * Types for the xmemory API.
2
+ * Types, enums, and error classes for the xmemory API.
3
3
  */
4
- export const SchemaType = {
5
- YML: 0,
6
- JSON: 1,
7
- };
4
+ // ---------------------------------------------------------------------------
5
+ // Enums
6
+ // ---------------------------------------------------------------------------
7
+ export const SchemaType = { YML: 0, JSON: 1 };
8
+ // ---------------------------------------------------------------------------
9
+ // Error classes
10
+ // ---------------------------------------------------------------------------
11
+ export class XmemoryAPIError extends Error {
12
+ status;
13
+ constructor(message, status) {
14
+ super(message);
15
+ this.status = status;
16
+ this.name = "XmemoryAPIError";
17
+ }
18
+ }
19
+ export class XmemoryHealthCheckError extends XmemoryAPIError {
20
+ constructor(message, status) {
21
+ super(message, status);
22
+ this.name = "XmemoryHealthCheckError";
23
+ }
24
+ }
25
+ export function buildInstanceSchema(schemaText, schemaType) {
26
+ if (schemaType === SchemaType.YML) {
27
+ return { yml: { value: schemaText } };
28
+ }
29
+ return { json_schema: { value: schemaText } };
30
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "xmemory",
3
- "version": "1.0.1",
3
+ "version": "2.0.0",
4
4
  "description": "xmemory",
5
5
  "keywords": [
6
6
  "xmemory"
@@ -16,14 +16,15 @@
16
16
  "license": "MIT",
17
17
  "author": "Dima Korolev",
18
18
  "type": "module",
19
- "main": "dist/client.js",
20
- "types": "dist/client.d.ts",
19
+ "main": "dist/index.js",
20
+ "types": "dist/index.d.ts",
21
21
  "files": [
22
22
  "dist"
23
23
  ],
24
24
  "scripts": {
25
25
  "build": "tsc",
26
26
  "test": "tsc --noEmit && node --import tsx test.ts",
27
+ "test:types": "tsc --noEmit",
27
28
  "prepublishOnly": "npm run build"
28
29
  },
29
30
  "devDependencies": {