@functional-systems/lambdadb 0.4.3 → 0.5.0-rc.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.
Files changed (209) hide show
  1. package/CHANGELOG.md +71 -0
  2. package/FUNCTIONS.md +7 -2
  3. package/README.md +60 -2
  4. package/RUNTIMES.md +7 -0
  5. package/USAGE.md +20 -0
  6. package/dist/commonjs/client.d.ts +25 -10
  7. package/dist/commonjs/client.d.ts.map +1 -1
  8. package/dist/commonjs/client.js +182 -56
  9. package/dist/commonjs/client.js.map +1 -1
  10. package/dist/commonjs/compat/qdrant/client.d.ts +3 -6
  11. package/dist/commonjs/compat/qdrant/client.d.ts.map +1 -1
  12. package/dist/commonjs/compat/qdrant/client.js +17 -11
  13. package/dist/commonjs/compat/qdrant/client.js.map +1 -1
  14. package/dist/commonjs/funcs/collectionsCreate.js +1 -1
  15. package/dist/commonjs/funcs/collectionsDelete.js +1 -1
  16. package/dist/commonjs/funcs/collectionsDocsGetBulkUpsert.js +4 -0
  17. package/dist/commonjs/funcs/collectionsDocsGetBulkUpsert.js.map +1 -1
  18. package/dist/commonjs/funcs/collectionsDocsListDocs.js +2 -0
  19. package/dist/commonjs/funcs/collectionsDocsListDocs.js.map +1 -1
  20. package/dist/commonjs/index.d.ts +4 -1
  21. package/dist/commonjs/index.d.ts.map +1 -1
  22. package/dist/commonjs/index.js +15 -1
  23. package/dist/commonjs/index.js.map +1 -1
  24. package/dist/commonjs/lib/config.d.ts +2 -2
  25. package/dist/commonjs/lib/config.js +2 -2
  26. package/dist/commonjs/lib/config.js.map +1 -1
  27. package/dist/commonjs/lib/queryInput.d.ts +3 -11
  28. package/dist/commonjs/lib/queryInput.d.ts.map +1 -1
  29. package/dist/commonjs/lib/queryInput.js.map +1 -1
  30. package/dist/commonjs/models/collectionresponse.d.ts +12 -21
  31. package/dist/commonjs/models/collectionresponse.d.ts.map +1 -1
  32. package/dist/commonjs/models/collectionresponse.js +5 -6
  33. package/dist/commonjs/models/collectionresponse.js.map +1 -1
  34. package/dist/commonjs/models/index.d.ts +1 -0
  35. package/dist/commonjs/models/index.d.ts.map +1 -1
  36. package/dist/commonjs/models/index.js +1 -0
  37. package/dist/commonjs/models/index.js.map +1 -1
  38. package/dist/commonjs/models/operations/bulkupsertdocs.d.ts +6 -0
  39. package/dist/commonjs/models/operations/bulkupsertdocs.d.ts.map +1 -1
  40. package/dist/commonjs/models/operations/bulkupsertdocs.js +2 -0
  41. package/dist/commonjs/models/operations/bulkupsertdocs.js.map +1 -1
  42. package/dist/commonjs/models/operations/createcollection.d.ts +20 -13
  43. package/dist/commonjs/models/operations/createcollection.d.ts.map +1 -1
  44. package/dist/commonjs/models/operations/createcollection.js +15 -7
  45. package/dist/commonjs/models/operations/createcollection.js.map +1 -1
  46. package/dist/commonjs/models/operations/deletedocs.d.ts +3 -0
  47. package/dist/commonjs/models/operations/deletedocs.d.ts.map +1 -1
  48. package/dist/commonjs/models/operations/deletedocs.js +1 -0
  49. package/dist/commonjs/models/operations/deletedocs.js.map +1 -1
  50. package/dist/commonjs/models/operations/fetchdocs.d.ts +3 -0
  51. package/dist/commonjs/models/operations/fetchdocs.d.ts.map +1 -1
  52. package/dist/commonjs/models/operations/fetchdocs.js +9 -0
  53. package/dist/commonjs/models/operations/fetchdocs.js.map +1 -1
  54. package/dist/commonjs/models/operations/getbulkupsertdocs.d.ts +5 -0
  55. package/dist/commonjs/models/operations/getbulkupsertdocs.d.ts.map +1 -1
  56. package/dist/commonjs/models/operations/getbulkupsertdocs.js +5 -3
  57. package/dist/commonjs/models/operations/getbulkupsertdocs.js.map +1 -1
  58. package/dist/commonjs/models/operations/listdocs.d.ts +9 -0
  59. package/dist/commonjs/models/operations/listdocs.d.ts.map +1 -1
  60. package/dist/commonjs/models/operations/listdocs.js +11 -0
  61. package/dist/commonjs/models/operations/listdocs.js.map +1 -1
  62. package/dist/commonjs/models/operations/querycollection.d.ts +3 -0
  63. package/dist/commonjs/models/operations/querycollection.d.ts.map +1 -1
  64. package/dist/commonjs/models/operations/querycollection.js +9 -0
  65. package/dist/commonjs/models/operations/querycollection.js.map +1 -1
  66. package/dist/commonjs/models/operations/updatecollection.d.ts +10 -4
  67. package/dist/commonjs/models/operations/updatecollection.d.ts.map +1 -1
  68. package/dist/commonjs/models/operations/updatecollection.js +8 -1
  69. package/dist/commonjs/models/operations/updatecollection.js.map +1 -1
  70. package/dist/commonjs/models/operations/updatedocs.d.ts +3 -0
  71. package/dist/commonjs/models/operations/updatedocs.d.ts.map +1 -1
  72. package/dist/commonjs/models/operations/updatedocs.js +1 -0
  73. package/dist/commonjs/models/operations/updatedocs.js.map +1 -1
  74. package/dist/commonjs/models/operations/upsertdocs.d.ts +3 -0
  75. package/dist/commonjs/models/operations/upsertdocs.d.ts.map +1 -1
  76. package/dist/commonjs/models/operations/upsertdocs.js +1 -0
  77. package/dist/commonjs/models/operations/upsertdocs.js.map +1 -1
  78. package/dist/commonjs/models/versioning.d.ts +100 -0
  79. package/dist/commonjs/models/versioning.d.ts.map +1 -0
  80. package/dist/commonjs/models/versioning.js +93 -0
  81. package/dist/commonjs/models/versioning.js.map +1 -0
  82. package/dist/commonjs/types/public.d.ts +80 -6
  83. package/dist/commonjs/types/public.d.ts.map +1 -1
  84. package/dist/commonjs/types/public.js +30 -7
  85. package/dist/commonjs/types/public.js.map +1 -1
  86. package/dist/commonjs/versioning.d.ts +63 -0
  87. package/dist/commonjs/versioning.d.ts.map +1 -0
  88. package/dist/commonjs/versioning.js +390 -0
  89. package/dist/commonjs/versioning.js.map +1 -0
  90. package/dist/esm/client.d.ts +25 -10
  91. package/dist/esm/client.d.ts.map +1 -1
  92. package/dist/esm/client.js +183 -58
  93. package/dist/esm/client.js.map +1 -1
  94. package/dist/esm/compat/qdrant/client.d.ts +3 -6
  95. package/dist/esm/compat/qdrant/client.d.ts.map +1 -1
  96. package/dist/esm/compat/qdrant/client.js +17 -11
  97. package/dist/esm/compat/qdrant/client.js.map +1 -1
  98. package/dist/esm/funcs/collectionsCreate.js +1 -1
  99. package/dist/esm/funcs/collectionsDelete.js +1 -1
  100. package/dist/esm/funcs/collectionsDocsGetBulkUpsert.js +5 -1
  101. package/dist/esm/funcs/collectionsDocsGetBulkUpsert.js.map +1 -1
  102. package/dist/esm/funcs/collectionsDocsListDocs.js +2 -0
  103. package/dist/esm/funcs/collectionsDocsListDocs.js.map +1 -1
  104. package/dist/esm/index.d.ts +4 -1
  105. package/dist/esm/index.d.ts.map +1 -1
  106. package/dist/esm/index.js +3 -1
  107. package/dist/esm/index.js.map +1 -1
  108. package/dist/esm/lib/config.d.ts +2 -2
  109. package/dist/esm/lib/config.js +2 -2
  110. package/dist/esm/lib/config.js.map +1 -1
  111. package/dist/esm/lib/queryInput.d.ts +3 -11
  112. package/dist/esm/lib/queryInput.d.ts.map +1 -1
  113. package/dist/esm/lib/queryInput.js.map +1 -1
  114. package/dist/esm/models/collectionresponse.d.ts +12 -21
  115. package/dist/esm/models/collectionresponse.d.ts.map +1 -1
  116. package/dist/esm/models/collectionresponse.js +5 -6
  117. package/dist/esm/models/collectionresponse.js.map +1 -1
  118. package/dist/esm/models/index.d.ts +1 -0
  119. package/dist/esm/models/index.d.ts.map +1 -1
  120. package/dist/esm/models/index.js +1 -0
  121. package/dist/esm/models/index.js.map +1 -1
  122. package/dist/esm/models/operations/bulkupsertdocs.d.ts +6 -0
  123. package/dist/esm/models/operations/bulkupsertdocs.d.ts.map +1 -1
  124. package/dist/esm/models/operations/bulkupsertdocs.js +2 -0
  125. package/dist/esm/models/operations/bulkupsertdocs.js.map +1 -1
  126. package/dist/esm/models/operations/createcollection.d.ts +20 -13
  127. package/dist/esm/models/operations/createcollection.d.ts.map +1 -1
  128. package/dist/esm/models/operations/createcollection.js +15 -7
  129. package/dist/esm/models/operations/createcollection.js.map +1 -1
  130. package/dist/esm/models/operations/deletedocs.d.ts +3 -0
  131. package/dist/esm/models/operations/deletedocs.d.ts.map +1 -1
  132. package/dist/esm/models/operations/deletedocs.js +1 -0
  133. package/dist/esm/models/operations/deletedocs.js.map +1 -1
  134. package/dist/esm/models/operations/fetchdocs.d.ts +3 -0
  135. package/dist/esm/models/operations/fetchdocs.d.ts.map +1 -1
  136. package/dist/esm/models/operations/fetchdocs.js +9 -0
  137. package/dist/esm/models/operations/fetchdocs.js.map +1 -1
  138. package/dist/esm/models/operations/getbulkupsertdocs.d.ts +5 -0
  139. package/dist/esm/models/operations/getbulkupsertdocs.d.ts.map +1 -1
  140. package/dist/esm/models/operations/getbulkupsertdocs.js +6 -4
  141. package/dist/esm/models/operations/getbulkupsertdocs.js.map +1 -1
  142. package/dist/esm/models/operations/listdocs.d.ts +9 -0
  143. package/dist/esm/models/operations/listdocs.d.ts.map +1 -1
  144. package/dist/esm/models/operations/listdocs.js +11 -0
  145. package/dist/esm/models/operations/listdocs.js.map +1 -1
  146. package/dist/esm/models/operations/querycollection.d.ts +3 -0
  147. package/dist/esm/models/operations/querycollection.d.ts.map +1 -1
  148. package/dist/esm/models/operations/querycollection.js +9 -0
  149. package/dist/esm/models/operations/querycollection.js.map +1 -1
  150. package/dist/esm/models/operations/updatecollection.d.ts +10 -4
  151. package/dist/esm/models/operations/updatecollection.d.ts.map +1 -1
  152. package/dist/esm/models/operations/updatecollection.js +8 -1
  153. package/dist/esm/models/operations/updatecollection.js.map +1 -1
  154. package/dist/esm/models/operations/updatedocs.d.ts +3 -0
  155. package/dist/esm/models/operations/updatedocs.d.ts.map +1 -1
  156. package/dist/esm/models/operations/updatedocs.js +1 -0
  157. package/dist/esm/models/operations/updatedocs.js.map +1 -1
  158. package/dist/esm/models/operations/upsertdocs.d.ts +3 -0
  159. package/dist/esm/models/operations/upsertdocs.d.ts.map +1 -1
  160. package/dist/esm/models/operations/upsertdocs.js +1 -0
  161. package/dist/esm/models/operations/upsertdocs.js.map +1 -1
  162. package/dist/esm/models/versioning.d.ts +100 -0
  163. package/dist/esm/models/versioning.d.ts.map +1 -0
  164. package/dist/esm/models/versioning.js +57 -0
  165. package/dist/esm/models/versioning.js.map +1 -0
  166. package/dist/esm/types/public.d.ts +80 -6
  167. package/dist/esm/types/public.d.ts.map +1 -1
  168. package/dist/esm/types/public.js +26 -7
  169. package/dist/esm/types/public.js.map +1 -1
  170. package/dist/esm/versioning.d.ts +63 -0
  171. package/dist/esm/versioning.d.ts.map +1 -0
  172. package/dist/esm/versioning.js +344 -0
  173. package/dist/esm/versioning.js.map +1 -0
  174. package/jsr.json +3 -1
  175. package/package.json +14 -2
  176. package/src/client.ts +300 -61
  177. package/src/compat/qdrant/client.ts +28 -16
  178. package/src/funcs/collectionsCreate.ts +1 -1
  179. package/src/funcs/collectionsDelete.ts +1 -1
  180. package/src/funcs/collectionsDocsGetBulkUpsert.ts +6 -1
  181. package/src/funcs/collectionsDocsListDocs.ts +2 -0
  182. package/src/index.ts +17 -0
  183. package/src/lib/config.ts +2 -2
  184. package/src/lib/queryInput.ts +3 -10
  185. package/src/models/collectionresponse.ts +17 -26
  186. package/src/models/index.ts +1 -0
  187. package/src/models/operations/bulkupsertdocs.ts +8 -0
  188. package/src/models/operations/createcollection.ts +39 -18
  189. package/src/models/operations/deletedocs.ts +4 -0
  190. package/src/models/operations/fetchdocs.ts +12 -0
  191. package/src/models/operations/getbulkupsertdocs.ts +11 -4
  192. package/src/models/operations/listdocs.ts +20 -0
  193. package/src/models/operations/querycollection.ts +12 -0
  194. package/src/models/operations/updatecollection.ts +21 -3
  195. package/src/models/operations/updatedocs.ts +4 -0
  196. package/src/models/operations/upsertdocs.ts +4 -0
  197. package/src/models/versioning.ts +118 -0
  198. package/src/types/public.ts +127 -14
  199. package/src/versioning.ts +490 -0
  200. package/examples/collectionScoped.example.ts +0 -38
  201. package/examples/collectionsList.example.ts +0 -25
  202. package/examples/package-lock.json +0 -612
  203. package/examples/package.json +0 -18
  204. package/test/integration/qdrant-compat-external.test.mjs +0 -351
  205. package/test/integration/qdrant-compat-live.test.mjs +0 -122
  206. package/test/null-response.test.mjs +0 -73
  207. package/test/public-api.test.mjs +0 -540
  208. package/test/qdrant-compat.test.mjs +0 -547
  209. package/tsconfig.json +0 -39
package/src/client.ts CHANGED
@@ -12,6 +12,12 @@
12
12
 
13
13
  import { LambdaDBCore } from "./core.js";
14
14
  import type { SDKOptions } from "./lib/config.js";
15
+ import {
16
+ HTTPClient,
17
+ isAbortError,
18
+ isConnectionError,
19
+ isTimeoutError,
20
+ } from "./lib/http.js";
15
21
  import { collectionsCreate } from "./funcs/collectionsCreate.js";
16
22
  import { collectionsDelete } from "./funcs/collectionsDelete.js";
17
23
  import { collectionsGet } from "./funcs/collectionsGet.js";
@@ -27,14 +33,26 @@ import { collectionsDocsListDocsExtended } from "./funcs/collectionsDocsListDocs
27
33
  import { collectionsDocsUpdate } from "./funcs/collectionsDocsUpdate.js";
28
34
  import { collectionsDocsUpsert } from "./funcs/collectionsDocsUpsert.js";
29
35
  import type { RequestOptions } from "./lib/sdks.js";
30
- import { UnexpectedClientError } from "./models/errors/httpclienterrors.js";
36
+ import {
37
+ ConnectionError,
38
+ RequestAbortedError,
39
+ RequestTimeoutError,
40
+ UnexpectedClientError,
41
+ } from "./models/errors/httpclienterrors.js";
42
+ import {
43
+ CollectionAliases,
44
+ CollectionBranches,
45
+ CollectionTags,
46
+ } from "./versioning.js";
31
47
  import { unwrapAsync, OK, ERR } from "./types/fp.js";
32
48
  import type { Result } from "./types/fp.js";
33
49
  import type * as operations from "./models/operations/index.js";
34
50
  import type * as models from "./models/index.js";
35
51
  import {
36
52
  listCollectionsResponseWithDates,
53
+ createCollectionResponseWithDates,
37
54
  getCollectionResponseWithDates,
55
+ updateCollectionResponseWithDates,
38
56
  type CreateCollectionInput,
39
57
  type UpdateCollectionInput,
40
58
  type QueryCollectionInput,
@@ -46,17 +64,18 @@ import {
46
64
  type ListCollectionsInput,
47
65
  type ListCollectionsResponseWithDates,
48
66
  type GetCollectionResponseWithDates,
49
- UpsertDocsInput,
50
- UpdateDocsInput,
51
- DeleteDocsInput,
52
- FetchDocsInput,
53
- FetchDocsResponse,
54
- FetchDocsDoc,
55
- BulkUpsertInput,
56
- MessageResponse,
57
- CreateCollectionResponse,
58
- UpdateCollectionResponse,
59
- GetBulkUpsertDocsResponse,
67
+ type CreateCollectionResponseWithDates,
68
+ type UpdateCollectionResponseWithDates,
69
+ type GetBulkUpsertInput,
70
+ type UpsertDocsInput,
71
+ type UpdateDocsInput,
72
+ type DeleteDocsInput,
73
+ type FetchDocsInput,
74
+ type FetchDocsResponse,
75
+ type FetchDocsDoc,
76
+ type BulkUpsertInput,
77
+ type MessageResponse,
78
+ type GetBulkUpsertDocsResponse,
60
79
  } from "./types/public.js";
61
80
  import type {
62
81
  ListCollectionsError,
@@ -87,15 +106,95 @@ export type { operations, models };
87
106
  /**
88
107
  * Fetches documents from a presigned docsUrl. Response must be { docs: [...] }.
89
108
  */
90
- async function fetchDocsFromUrl<T>(docsUrl: string): Promise<T[]> {
91
- const res = await fetch(docsUrl);
109
+ function transferSignal(options?: RequestOptions): AbortSignal | undefined {
110
+ const signal = options?.signal ?? options?.fetchOptions?.signal;
111
+ if (signal != null) return signal;
112
+ if (options?.timeoutMs != null && options.timeoutMs > 0) {
113
+ return AbortSignal.timeout(options.timeoutMs);
114
+ }
115
+ return undefined;
116
+ }
117
+
118
+ function withTransferSignal(
119
+ init: RequestInit,
120
+ options?: RequestOptions,
121
+ ): RequestInit {
122
+ const signal = transferSignal(options);
123
+ return signal === undefined ? init : { ...init, signal };
124
+ }
125
+
126
+ function serializeBulkUpsertPayload(
127
+ docs: UpsertDocsInput["docs"],
128
+ ): { jsonString: string; sizeBytes: number } {
129
+ try {
130
+ const jsonString = JSON.stringify({ docs });
131
+ if (jsonString === undefined) {
132
+ throw new TypeError("JSON.stringify returned undefined");
133
+ }
134
+ return {
135
+ jsonString,
136
+ sizeBytes: new TextEncoder().encode(jsonString).length,
137
+ };
138
+ } catch (cause) {
139
+ throw new UnexpectedClientError(
140
+ "Failed to serialize bulk upsert payload",
141
+ { cause },
142
+ );
143
+ }
144
+ }
145
+
146
+ function classifyTransferError(
147
+ message: string,
148
+ cause: unknown,
149
+ ): ConnectionError | RequestAbortedError | RequestTimeoutError | UnexpectedClientError {
150
+ if (isAbortError(cause)) {
151
+ return new RequestAbortedError("Request aborted by client", { cause });
152
+ }
153
+ if (isTimeoutError(cause)) {
154
+ return new RequestTimeoutError("Request timed out", { cause });
155
+ }
156
+ if (isConnectionError(cause)) {
157
+ return new ConnectionError("Unable to make request", { cause });
158
+ }
159
+ return new UnexpectedClientError(message, { cause });
160
+ }
161
+
162
+ async function readTransferText(
163
+ response: Response,
164
+ errorMessage: string,
165
+ ): Promise<string> {
166
+ try {
167
+ return await response.text();
168
+ } catch (cause) {
169
+ throw classifyTransferError(errorMessage, cause);
170
+ }
171
+ }
172
+
173
+ async function fetchDocsFromUrl<T>(
174
+ transferClient: HTTPClient,
175
+ docsUrl: string,
176
+ options?: RequestOptions,
177
+ ): Promise<T[]> {
178
+ let res: Response;
179
+ try {
180
+ res = await transferClient.request(
181
+ new Request(
182
+ docsUrl,
183
+ withTransferSignal({ method: "GET" }, options),
184
+ ),
185
+ );
186
+ } catch (cause) {
187
+ throw classifyTransferError("Failed to fetch documents from URL", cause);
188
+ }
189
+ const text = await readTransferText(
190
+ res,
191
+ "Failed to read documents from URL",
192
+ );
92
193
  if (!res.ok) {
93
- const text = await res.text();
94
194
  throw new UnexpectedClientError(
95
195
  `Failed to fetch documents from URL: ${res.status} ${res.statusText}${text ? ` - ${text}` : ""}`,
96
196
  );
97
197
  }
98
- const text = await res.text();
99
198
  if (text.trim() === "") {
100
199
  return [];
101
200
  }
@@ -146,6 +245,11 @@ export type LambdaDBClientOptions = SDKOptions & {
146
245
  * Project name (path segment under /projects/). Default: "playground"
147
246
  */
148
247
  projectName?: string;
248
+ /**
249
+ * Separate unauthenticated transport for presigned uploads and downloads.
250
+ * API authentication and API request headers are never copied to it.
251
+ */
252
+ transferClient?: HTTPClient;
149
253
  };
150
254
 
151
255
  function normalizeClientOptions(
@@ -156,8 +260,10 @@ function normalizeClientOptions(
156
260
  projectName = DEFAULT_PROJECT_NAME,
157
261
  serverURL,
158
262
  projectHost,
263
+ transferClient: _transferClient,
159
264
  ...rest
160
265
  } = options;
266
+ void _transferClient;
161
267
 
162
268
  if (serverURL !== undefined && serverURL !== null) {
163
269
  return { ...rest, serverURL };
@@ -176,8 +282,11 @@ function normalizeClientOptions(
176
282
  * `LambdaDB` when you want to avoid passing collectionName on every call.
177
283
  */
178
284
  export class LambdaDBClient extends LambdaDBCore {
179
- constructor(options?: LambdaDBClientOptions) {
285
+ readonly #transferClient: HTTPClient;
286
+
287
+ constructor(options: LambdaDBClientOptions = {}) {
180
288
  super(normalizeClientOptions(options));
289
+ this.#transferClient = options.transferClient ?? new HTTPClient();
181
290
  }
182
291
 
183
292
  /**
@@ -185,7 +294,7 @@ export class LambdaDBClient extends LambdaDBCore {
185
294
  * use this collection name; you do not pass it again.
186
295
  */
187
296
  collection(collectionName: string): CollectionHandle {
188
- return new CollectionHandle(this, collectionName);
297
+ return new CollectionHandle(this, collectionName, this.#transferClient);
189
298
  }
190
299
 
191
300
  /**
@@ -257,8 +366,10 @@ export class LambdaDBClient extends LambdaDBCore {
257
366
  async createCollection(
258
367
  request: CreateCollectionInput,
259
368
  options?: RequestOptions,
260
- ) {
261
- return unwrapAsync(collectionsCreate(this, request, options));
369
+ ): Promise<CreateCollectionResponseWithDates> {
370
+ return createCollectionResponseWithDates(
371
+ await unwrapAsync(collectionsCreate(this, request, options)),
372
+ );
262
373
  }
263
374
 
264
375
  /**
@@ -267,8 +378,10 @@ export class LambdaDBClient extends LambdaDBCore {
267
378
  async createCollectionSafe(
268
379
  request: CreateCollectionInput,
269
380
  options?: RequestOptions,
270
- ): Promise<Result<CreateCollectionResponse, CreateCollectionError>> {
271
- return await collectionsCreate(this, request, options);
381
+ ): Promise<Result<CreateCollectionResponseWithDates, CreateCollectionError>> {
382
+ const result = await collectionsCreate(this, request, options);
383
+ if (!result.ok) return result;
384
+ return OK(createCollectionResponseWithDates(result.value));
272
385
  }
273
386
  }
274
387
 
@@ -279,8 +392,13 @@ export class CollectionHandle {
279
392
  constructor(
280
393
  private readonly client: LambdaDBCore,
281
394
  readonly collectionName: string,
395
+ private readonly transferClient: HTTPClient = new HTTPClient(),
282
396
  ) {}
283
397
 
398
+ readonly branches = new CollectionBranches(this.client, this.collectionName);
399
+ readonly tags = new CollectionTags(this.client, this.collectionName);
400
+ readonly aliases = new CollectionAliases(this.client, this.collectionName);
401
+
284
402
  /**
285
403
  * Get metadata of this collection. Timestamp fields are returned as Date.
286
404
  */
@@ -312,8 +430,8 @@ export class CollectionHandle {
312
430
  async update(
313
431
  requestBody: UpdateCollectionInput,
314
432
  options?: RequestOptions,
315
- ) {
316
- return unwrapAsync(
433
+ ): Promise<UpdateCollectionResponseWithDates> {
434
+ const response = await unwrapAsync(
317
435
  collectionsUpdate(
318
436
  this.client,
319
437
  {
@@ -323,6 +441,7 @@ export class CollectionHandle {
323
441
  options,
324
442
  ),
325
443
  );
444
+ return updateCollectionResponseWithDates(response);
326
445
  }
327
446
 
328
447
  /**
@@ -331,12 +450,14 @@ export class CollectionHandle {
331
450
  async updateSafe(
332
451
  requestBody: UpdateCollectionInput,
333
452
  options?: RequestOptions,
334
- ): Promise<Result<UpdateCollectionResponse, UpdateCollectionError>> {
335
- return await collectionsUpdate(
453
+ ): Promise<Result<UpdateCollectionResponseWithDates, UpdateCollectionError>> {
454
+ const result = await collectionsUpdate(
336
455
  this.client,
337
456
  { collectionName: this.collectionName, requestBody },
338
457
  options,
339
458
  );
459
+ if (!result.ok) return result;
460
+ return OK(updateCollectionResponseWithDates(result.value));
340
461
  }
341
462
 
342
463
  /**
@@ -386,7 +507,9 @@ export class CollectionHandle {
386
507
  );
387
508
  if (!result.isDocsInline && result.docsUrl) {
388
509
  const docs = await fetchDocsFromUrl<QueryCollectionDoc>(
510
+ this.transferClient,
389
511
  result.docsUrl,
512
+ options,
390
513
  );
391
514
  return { ...result, docs, isDocsInline: true };
392
515
  }
@@ -409,7 +532,11 @@ export class CollectionHandle {
409
532
  if (!result.ok) return result;
410
533
  if (!result.value.isDocsInline && result.value.docsUrl) {
411
534
  try {
412
- const docs = await fetchDocsFromUrl<QueryCollectionDoc>(result.value.docsUrl);
535
+ const docs = await fetchDocsFromUrl<QueryCollectionDoc>(
536
+ this.transferClient,
537
+ result.value.docsUrl,
538
+ options,
539
+ );
413
540
  return OK({ ...result.value, docs, isDocsInline: true });
414
541
  } catch (e) {
415
542
  return ERR(e as QueryCollectionError);
@@ -418,16 +545,21 @@ export class CollectionHandle {
418
545
  return result;
419
546
  }
420
547
 
421
- readonly docs: CollectionDocs = new CollectionDocs(this.client, this.collectionName);
548
+ readonly docs: CollectionDocs = new CollectionDocs(
549
+ this.client,
550
+ this.collectionName,
551
+ this.transferClient,
552
+ );
422
553
  }
423
554
 
424
555
  /**
425
556
  * Document operations scoped to a collection.
426
557
  */
427
- class CollectionDocs {
558
+ export class CollectionDocs {
428
559
  constructor(
429
560
  private readonly client: LambdaDBCore,
430
561
  private readonly collectionName: string,
562
+ private readonly transferClient: HTTPClient,
431
563
  ) {}
432
564
 
433
565
  /**
@@ -455,6 +587,7 @@ class CollectionDocs {
455
587
  partitionFilter: params?.partitionFilter,
456
588
  fields: params?.fields,
457
589
  includeVectors: params?.includeVectors,
590
+ ref: params?.ref,
458
591
  },
459
592
  },
460
593
  options,
@@ -466,12 +599,18 @@ class CollectionDocs {
466
599
  size: params?.size,
467
600
  pageToken: params?.pageToken,
468
601
  includeVectors: params?.includeVectors,
602
+ refKind: params?.ref?.kind,
603
+ refName: params?.ref?.name,
469
604
  },
470
605
  options,
471
606
  ),
472
607
  );
473
608
  if (!result.isDocsInline && result.docsUrl) {
474
- const docs = await fetchDocsFromUrl<ListDocsDoc>(result.docsUrl);
609
+ const docs = await fetchDocsFromUrl<ListDocsDoc>(
610
+ this.transferClient,
611
+ result.docsUrl,
612
+ options,
613
+ );
475
614
  return { ...result, docs, isDocsInline: true };
476
615
  }
477
616
  return result;
@@ -500,6 +639,7 @@ class CollectionDocs {
500
639
  partitionFilter: params?.partitionFilter,
501
640
  fields: params?.fields,
502
641
  includeVectors: params?.includeVectors,
642
+ ref: params?.ref,
503
643
  },
504
644
  },
505
645
  options,
@@ -511,13 +651,19 @@ class CollectionDocs {
511
651
  size: params?.size,
512
652
  pageToken: params?.pageToken,
513
653
  includeVectors: params?.includeVectors,
654
+ refKind: params?.ref?.kind,
655
+ refName: params?.ref?.name,
514
656
  },
515
657
  options,
516
658
  );
517
659
  if (!result.ok) return result;
518
660
  if (!result.value.isDocsInline && result.value.docsUrl) {
519
661
  try {
520
- const docs = await fetchDocsFromUrl<ListDocsDoc>(result.value.docsUrl);
662
+ const docs = await fetchDocsFromUrl<ListDocsDoc>(
663
+ this.transferClient,
664
+ result.value.docsUrl,
665
+ options,
666
+ );
521
667
  return OK({ ...result.value, docs, isDocsInline: true });
522
668
  } catch (e) {
523
669
  return ERR(e as ListDocsError);
@@ -550,6 +696,7 @@ class CollectionDocs {
550
696
  partitionFilter: params?.partitionFilter,
551
697
  fields: params?.fields,
552
698
  includeVectors: params?.includeVectors,
699
+ ref: params?.ref,
553
700
  };
554
701
  while (true) {
555
702
  const page = await this.list({ ...baseParams, pageToken }, options);
@@ -698,7 +845,9 @@ class CollectionDocs {
698
845
  );
699
846
  if (!result.isDocsInline && result.docsUrl) {
700
847
  const docs = await fetchDocsFromUrl<FetchDocsDoc>(
848
+ this.transferClient,
701
849
  result.docsUrl,
850
+ options,
702
851
  );
703
852
  return { ...result, docs, isDocsInline: true };
704
853
  }
@@ -721,7 +870,11 @@ class CollectionDocs {
721
870
  if (!result.ok) return result;
722
871
  if (!result.value.isDocsInline && result.value.docsUrl) {
723
872
  try {
724
- const docs = await fetchDocsFromUrl<FetchDocsDoc>(result.value.docsUrl);
873
+ const docs = await fetchDocsFromUrl<FetchDocsDoc>(
874
+ this.transferClient,
875
+ result.value.docsUrl,
876
+ options,
877
+ );
725
878
  return OK({ ...result.value, docs, isDocsInline: true });
726
879
  } catch (e) {
727
880
  return ERR(e as FetchDocsError);
@@ -733,12 +886,28 @@ class CollectionDocs {
733
886
  /**
734
887
  * Get presigned URL and metadata for bulk upload (up to 200MB). Not supported for collections with managed embedding vector fields.
735
888
  */
736
- async getBulkUpsert(options?: RequestOptions) {
889
+ async getBulkUpsert(
890
+ options?: RequestOptions,
891
+ ): Promise<GetBulkUpsertDocsResponse>;
892
+ async getBulkUpsert(
893
+ input: GetBulkUpsertInput,
894
+ options?: RequestOptions,
895
+ ): Promise<GetBulkUpsertDocsResponse>;
896
+ async getBulkUpsert(
897
+ inputOrOptions?: GetBulkUpsertInput | RequestOptions,
898
+ options?: RequestOptions,
899
+ ): Promise<GetBulkUpsertDocsResponse> {
900
+ const hasInput = options !== undefined
901
+ || (inputOrOptions != null && "branch" in inputOrOptions);
902
+ const input = hasInput ? inputOrOptions as GetBulkUpsertInput : {};
903
+ const requestOptions = hasInput
904
+ ? options
905
+ : inputOrOptions as RequestOptions | undefined;
737
906
  return unwrapAsync(
738
907
  collectionsDocsGetBulkUpsert(
739
908
  this.client,
740
- { collectionName: this.collectionName },
741
- options,
909
+ { collectionName: this.collectionName, branch: input.branch },
910
+ requestOptions,
742
911
  ),
743
912
  );
744
913
  }
@@ -748,11 +917,25 @@ class CollectionDocs {
748
917
  */
749
918
  async getBulkUpsertSafe(
750
919
  options?: RequestOptions,
920
+ ): Promise<Result<GetBulkUpsertDocsResponse, GetBulkUpsertDocsError>>;
921
+ async getBulkUpsertSafe(
922
+ input: GetBulkUpsertInput,
923
+ options?: RequestOptions,
924
+ ): Promise<Result<GetBulkUpsertDocsResponse, GetBulkUpsertDocsError>>;
925
+ async getBulkUpsertSafe(
926
+ inputOrOptions?: GetBulkUpsertInput | RequestOptions,
927
+ options?: RequestOptions,
751
928
  ): Promise<Result<GetBulkUpsertDocsResponse, GetBulkUpsertDocsError>> {
929
+ const hasInput = options !== undefined
930
+ || (inputOrOptions != null && "branch" in inputOrOptions);
931
+ const input = hasInput ? inputOrOptions as GetBulkUpsertInput : {};
932
+ const requestOptions = hasInput
933
+ ? options
934
+ : inputOrOptions as RequestOptions | undefined;
752
935
  return await collectionsDocsGetBulkUpsert(
753
936
  this.client,
754
- { collectionName: this.collectionName },
755
- options,
937
+ { collectionName: this.collectionName, branch: input.branch },
938
+ requestOptions,
756
939
  );
757
940
  }
758
941
 
@@ -798,36 +981,50 @@ class CollectionDocs {
798
981
  body: UpsertDocsInput,
799
982
  options?: RequestOptions,
800
983
  ): Promise<MessageResponse> {
801
- const { url, type, httpMethod, objectKey, sizeLimitBytes } = await this.getBulkUpsert(options);
984
+ const { url, type, httpMethod, objectKey, sizeLimitBytes, headers } =
985
+ await this.getBulkUpsert({ branch: body.branch }, options);
802
986
 
803
- const payload = { docs: body.docs };
804
- const jsonString = JSON.stringify(payload);
805
- const sizeBytes = new TextEncoder().encode(jsonString).length;
987
+ const { jsonString, sizeBytes } = serializeBulkUpsertPayload(body.docs);
806
988
  if (sizeBytes > sizeLimitBytes) {
807
989
  throw new Error(
808
990
  `Bulk upsert payload size (${sizeBytes} bytes) exceeds limit (${sizeLimitBytes} bytes)`,
809
991
  );
810
992
  }
811
993
 
812
- const putResponse = await fetch(url, {
813
- method: httpMethod,
814
- headers: { "Content-Type": type },
815
- body: jsonString,
816
- });
994
+ const uploadHeaders = new Headers(headers);
995
+ uploadHeaders.set("Content-Type", type);
996
+ let putResponse: Response;
997
+ try {
998
+ putResponse = await this.transferClient.request(
999
+ new Request(
1000
+ url,
1001
+ withTransferSignal({
1002
+ method: httpMethod,
1003
+ headers: uploadHeaders,
1004
+ body: jsonString,
1005
+ }, options),
1006
+ ),
1007
+ );
1008
+ } catch (cause) {
1009
+ throw classifyTransferError("Bulk upsert upload failed", cause);
1010
+ }
817
1011
 
818
1012
  if (!putResponse.ok) {
819
- const text = await putResponse.text();
1013
+ const text = await readTransferText(
1014
+ putResponse,
1015
+ "Failed to read bulk upsert upload response",
1016
+ );
820
1017
  throw new Error(
821
1018
  `Bulk upsert upload failed: ${putResponse.status} ${putResponse.statusText}${text ? ` - ${text}` : ""}`,
822
1019
  );
823
1020
  }
824
1021
 
825
- return this.bulkUpsert({ objectKey }, options);
1022
+ return this.bulkUpsert({ objectKey, type, branch: body.branch }, options);
826
1023
  }
827
1024
 
828
1025
  /**
829
1026
  * Bulk upsert documents in one call (Safe: returns Result instead of throwing). Not supported for collections with managed embedding vector fields.
830
- * May return Error for local failures (payload size, upload). API errors use GetBulkUpsertDocsError or BulkUpsertDocsError.
1027
+ * May return Error for local failures (serialization, payload size, upload). API errors use GetBulkUpsertDocsError or BulkUpsertDocsError.
831
1028
  */
832
1029
  async bulkUpsertDocsSafe(
833
1030
  body: UpsertDocsInput,
@@ -838,13 +1035,28 @@ class CollectionDocs {
838
1035
  GetBulkUpsertDocsError | BulkUpsertDocsError | Error
839
1036
  >
840
1037
  > {
841
- const getResult = await this.getBulkUpsertSafe(options);
1038
+ const getResult = await this.getBulkUpsertSafe(
1039
+ { branch: body.branch },
1040
+ options,
1041
+ );
842
1042
  if (!getResult.ok) return getResult;
843
- const { url, type, httpMethod, objectKey, sizeLimitBytes } = getResult.value;
1043
+ const { url, type, httpMethod, objectKey, sizeLimitBytes, headers } =
1044
+ getResult.value;
844
1045
 
845
- const payload = { docs: body.docs };
846
- const jsonString = JSON.stringify(payload);
847
- const sizeBytes = new TextEncoder().encode(jsonString).length;
1046
+ let jsonString: string;
1047
+ let sizeBytes: number;
1048
+ try {
1049
+ ({ jsonString, sizeBytes } = serializeBulkUpsertPayload(body.docs));
1050
+ } catch (cause) {
1051
+ return ERR(
1052
+ cause instanceof Error
1053
+ ? cause
1054
+ : new UnexpectedClientError(
1055
+ "Failed to serialize bulk upsert payload",
1056
+ { cause },
1057
+ ),
1058
+ );
1059
+ }
848
1060
  if (sizeBytes > sizeLimitBytes) {
849
1061
  return ERR(
850
1062
  new Error(
@@ -853,14 +1065,41 @@ class CollectionDocs {
853
1065
  );
854
1066
  }
855
1067
 
856
- const putResponse = await fetch(url, {
857
- method: httpMethod,
858
- headers: { "Content-Type": type },
859
- body: jsonString,
860
- });
1068
+ let putResponse: Response;
1069
+ try {
1070
+ const uploadHeaders = new Headers(headers);
1071
+ uploadHeaders.set("Content-Type", type);
1072
+ putResponse = await this.transferClient.request(
1073
+ new Request(
1074
+ url,
1075
+ withTransferSignal({
1076
+ method: httpMethod,
1077
+ headers: uploadHeaders,
1078
+ body: jsonString,
1079
+ }, options),
1080
+ ),
1081
+ );
1082
+ } catch (cause) {
1083
+ return ERR(classifyTransferError("Bulk upsert upload failed", cause));
1084
+ }
861
1085
 
862
1086
  if (!putResponse.ok) {
863
- const text = await putResponse.text();
1087
+ let text: string;
1088
+ try {
1089
+ text = await readTransferText(
1090
+ putResponse,
1091
+ "Failed to read bulk upsert upload response",
1092
+ );
1093
+ } catch (cause) {
1094
+ return ERR(
1095
+ cause instanceof Error
1096
+ ? cause
1097
+ : new UnexpectedClientError(
1098
+ "Failed to read bulk upsert upload response",
1099
+ { cause },
1100
+ ),
1101
+ );
1102
+ }
864
1103
  return ERR(
865
1104
  new Error(
866
1105
  `Bulk upsert upload failed: ${putResponse.status} ${putResponse.statusText}${text ? ` - ${text}` : ""}`,
@@ -868,6 +1107,6 @@ class CollectionDocs {
868
1107
  );
869
1108
  }
870
1109
 
871
- return this.bulkUpsertSafe({ objectKey }, options);
1110
+ return this.bulkUpsertSafe({ objectKey, type, branch: body.branch }, options);
872
1111
  }
873
1112
  }