@larc-iu/plaid-client 0.2.0-alpha.3 → 0.2.0-alpha.5

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/src/index.js CHANGED
@@ -2,26 +2,33 @@
2
2
  * plaid-client - JavaScript client for the Plaid annotation API
3
3
  */
4
4
 
5
- import { transformRequest, transformResponse } from './transforms.js';
5
+ import { transformRequest, transformResponse } from "./transforms.js";
6
6
  import {
7
- makeRequest, extractDocumentVersions, parseErrorBody, makeHttpError,
8
- makeNetworkError, timeoutSignal, DEFAULT_TIMEOUT_MS,
9
- } from './http.js';
10
- import { listAll, listPage, iterPages } from './pagination.js';
11
- import { createSSEConnection } from './sse.js';
7
+ makeRequest,
8
+ extractDocumentVersions,
9
+ parseErrorBody,
10
+ makeHttpError,
11
+ makeNetworkError,
12
+ timeoutSignal,
13
+ retryWhileBusy,
14
+ DEFAULT_TIMEOUT_MS,
15
+ DEFAULT_BATCH_TIMEOUT_MS,
16
+ } from "./http.js";
17
+ import { listAll, listPage, iterPages } from "./pagination.js";
18
+ import { createSSEConnection } from "./sse.js";
12
19
  import {
13
20
  discoverServices,
14
21
  discardService,
15
22
  serve,
16
23
  requestService,
17
- } from './services.js';
24
+ } from "./services.js";
18
25
 
19
26
  // Helper: normalize a document-read `layers` filter to the wire's
20
27
  // comma-separated form. Accepts an array of layer ids or a ready-made string;
21
28
  // anything empty becomes undefined so no `?layers=` is sent at all.
22
29
  function layersParam(layers) {
23
30
  if (layers === undefined || layers === null) return undefined;
24
- const joined = Array.isArray(layers) ? layers.join(',') : String(layers);
31
+ const joined = Array.isArray(layers) ? layers.join(",") : String(layers);
25
32
  return joined.length > 0 ? joined : undefined;
26
33
  }
27
34
 
@@ -30,7 +37,7 @@ function layersParam(layers) {
30
37
  // becomes undefined so no `?op-types=` is sent at all.
31
38
  function opTypesParam(opTypes) {
32
39
  if (opTypes === undefined || opTypes === null) return undefined;
33
- const joined = Array.isArray(opTypes) ? opTypes.join(',') : String(opTypes);
40
+ const joined = Array.isArray(opTypes) ? opTypes.join(",") : String(opTypes);
34
41
  return joined.length > 0 ? joined : undefined;
35
42
  }
36
43
 
@@ -47,25 +54,32 @@ function bodyOf(obj) {
47
54
  // and redemption). Deliberately does not go through PlaidClient._request: these
48
55
  // are called before any client exists, which is the whole point.
49
56
  async function anonymousPost(baseUrl, path, body, options = {}) {
50
- const base = baseUrl.replace(/\/$/, '');
57
+ const base = baseUrl.replace(/\/$/, "");
51
58
  const url = `${base}${path}`;
52
59
  try {
53
60
  const fetchOptions = {
54
- method: 'POST',
55
- headers: { 'Content-Type': 'application/json' },
61
+ method: "POST",
62
+ headers: { "Content-Type": "application/json" },
56
63
  body: JSON.stringify(body),
57
64
  };
58
- const signal = timeoutSignal(options.timeout !== undefined ? options.timeout : DEFAULT_TIMEOUT_MS);
65
+ const signal = timeoutSignal(
66
+ options.timeout !== undefined ? options.timeout : DEFAULT_TIMEOUT_MS,
67
+ );
59
68
  if (signal) fetchOptions.signal = signal;
60
69
 
61
70
  const response = await fetch(url, fetchOptions);
62
71
  if (!response.ok) {
63
- throw makeHttpError(response, await parseErrorBody(response), url, 'POST');
72
+ throw makeHttpError(
73
+ response,
74
+ await parseErrorBody(response),
75
+ url,
76
+ "POST",
77
+ );
64
78
  }
65
79
  return transformResponse(await response.json());
66
80
  } catch (error) {
67
81
  if (error.status) throw error;
68
- throw makeNetworkError(error, url, 'POST');
82
+ throw makeNetworkError(error, url, "POST");
69
83
  }
70
84
  }
71
85
 
@@ -76,11 +90,24 @@ class PlaidClient {
76
90
  * @param {string} token - The authentication token
77
91
  * @param {object} [options] - Client options
78
92
  * @param {number} [options.timeout=30000] - Per-request timeout in ms (0 or null disables it)
93
+ * @param {number} [options.batchTimeout=180000] - Timeout for batch submissions in ms (0 or null disables it)
79
94
  */
80
95
  constructor(baseUrl, token, options = {}) {
81
- this.baseUrl = baseUrl.replace(/\/$/, '');
96
+ this.baseUrl = baseUrl.replace(/\/$/, "");
82
97
  this.token = token;
83
- this.timeout = options.timeout !== undefined ? options.timeout : DEFAULT_TIMEOUT_MS;
98
+ this.timeout =
99
+ options.timeout !== undefined ? options.timeout : DEFAULT_TIMEOUT_MS;
100
+ // Batch submissions get a longer budget than a single request. Aborting a
101
+ // batch does NOT stop the server: it keeps running the transaction and
102
+ // holding the single SQLite write lock, so a client that gives up early
103
+ // just adds a retry on top of a write that is still in progress. Falls
104
+ // back to an explicit `timeout` when one was given.
105
+ this.batchTimeout =
106
+ options.batchTimeout !== undefined
107
+ ? options.batchTimeout
108
+ : options.timeout !== undefined
109
+ ? options.timeout
110
+ : DEFAULT_BATCH_TIMEOUT_MS;
84
111
  this.isBatching = false;
85
112
  this.batchOperations = [];
86
113
  this.documentVersions = {};
@@ -106,8 +133,9 @@ class PlaidClient {
106
133
  * @param {any} [metadata] - Metadata for the link. Omit to leave unset; pass null to send JSON null.
107
134
  */
108
135
  create: (vocabItem, tokens, metadata, auditMessage) =>
109
- this._request('POST', '/api/v1/vocab-links', { auditMessage,
110
- body: bodyOf({ 'vocab-item': vocabItem, tokens, metadata }),
136
+ this._request("POST", "/api/v1/vocab-links", {
137
+ auditMessage,
138
+ body: bodyOf({ "vocab-item": vocabItem, tokens, metadata }),
111
139
  }),
112
140
  /**
113
141
  * Create multiple vocab links in a single operation. Entries may
@@ -117,28 +145,37 @@ class PlaidClient {
117
145
  * @returns {Promise<{ids: string[]}>} The created entity IDs, in input order. (bulkDelete resolves to no value.)
118
146
  */
119
147
  bulkCreate: (body, auditMessage) =>
120
- this._request('POST', '/api/v1/vocab-links/bulk', { auditMessage, body }),
148
+ this._request("POST", "/api/v1/vocab-links/bulk", {
149
+ auditMessage,
150
+ body,
151
+ }),
121
152
  /**
122
153
  * Delete multiple vocab links in a single operation. Provide an array of IDs.
123
154
  * @param {string[]} body - The vocab link IDs to delete
124
155
  */
125
156
  bulkDelete: (body, auditMessage) =>
126
- this._request('DELETE', '/api/v1/vocab-links/bulk', { auditMessage, body }),
157
+ this._request("DELETE", "/api/v1/vocab-links/bulk", {
158
+ auditMessage,
159
+ body,
160
+ }),
127
161
  /**
128
162
  * Replace all metadata for a vocab link. The entire metadata map is replaced - existing metadata keys not included in the request will be removed.
129
163
  * @param {string} id - The resource ID
130
164
  * @param {any} body - The request body
131
165
  */
132
166
  setMetadata: (id, body, auditMessage) =>
133
- this._request('PUT', `/api/v1/vocab-links/${id}/metadata`, { auditMessage,
134
- rawBody: body, skipResponseTransform: true,
167
+ this._request("PUT", `/api/v1/vocab-links/${id}/metadata`, {
168
+ auditMessage,
169
+ rawBody: body,
170
+ skipResponseTransform: true,
135
171
  }),
136
172
  /**
137
173
  * Remove all metadata from a vocab link.
138
174
  * @param {string} id - The resource ID
139
175
  */
140
176
  deleteMetadata: (id, auditMessage) =>
141
- this._request('DELETE', `/api/v1/vocab-links/${id}/metadata`, { auditMessage,
177
+ this._request("DELETE", `/api/v1/vocab-links/${id}/metadata`, {
178
+ auditMessage,
142
179
  skipResponseTransform: true,
143
180
  }),
144
181
  /**
@@ -147,8 +184,10 @@ class PlaidClient {
147
184
  * @param {any} body - The metadata patch
148
185
  */
149
186
  patchMetadata: (id, body, auditMessage) =>
150
- this._request('PATCH', `/api/v1/vocab-links/${id}/metadata`, { auditMessage,
151
- rawBody: body, skipResponseTransform: true,
187
+ this._request("PATCH", `/api/v1/vocab-links/${id}/metadata`, {
188
+ auditMessage,
189
+ rawBody: body,
190
+ skipResponseTransform: true,
152
191
  }),
153
192
  /**
154
193
  * Get a vocab link by ID
@@ -156,15 +195,15 @@ class PlaidClient {
156
195
  * @param {string} [asOf] - Temporal query timestamp
157
196
  */
158
197
  get: (id, asOf) =>
159
- this._request('GET', `/api/v1/vocab-links/${id}`, {
160
- queryParams: { 'as-of': asOf },
198
+ this._request("GET", `/api/v1/vocab-links/${id}`, {
199
+ queryParams: { "as-of": asOf },
161
200
  }),
162
201
  /**
163
202
  * Delete a vocab link
164
203
  * @param {string} id - The resource ID
165
204
  */
166
205
  delete: (id, auditMessage) =>
167
- this._request('DELETE', `/api/v1/vocab-links/${id}`, { auditMessage }),
206
+ this._request("DELETE", `/api/v1/vocab-links/${id}`, { auditMessage }),
168
207
  };
169
208
 
170
209
  this.vocabLayers = {
@@ -175,22 +214,23 @@ class PlaidClient {
175
214
  * @param {string} [asOf] - Temporal query timestamp
176
215
  */
177
216
  get: (id, includeItems, asOf) =>
178
- this._request('GET', `/api/v1/vocab-layers/${id}`, {
179
- queryParams: { 'include-items': includeItems, 'as-of': asOf },
217
+ this._request("GET", `/api/v1/vocab-layers/${id}`, {
218
+ queryParams: { "include-items": includeItems, "as-of": asOf },
180
219
  }),
181
220
  /**
182
221
  * Delete a vocab layer.
183
222
  * @param {string} id - The resource ID
184
223
  */
185
224
  delete: (id, auditMessage) =>
186
- this._request('DELETE', `/api/v1/vocab-layers/${id}`, { auditMessage }),
225
+ this._request("DELETE", `/api/v1/vocab-layers/${id}`, { auditMessage }),
187
226
  /**
188
227
  * Update a vocab layer's name.
189
228
  * @param {string} id - The resource ID
190
229
  * @param {string} name - The name
191
230
  */
192
231
  update: (id, name, auditMessage) =>
193
- this._request('PATCH', `/api/v1/vocab-layers/${id}`, { auditMessage,
232
+ this._request("PATCH", `/api/v1/vocab-layers/${id}`, {
233
+ auditMessage,
194
234
  body: bodyOf({ name }),
195
235
  }),
196
236
  /**
@@ -201,9 +241,11 @@ class PlaidClient {
201
241
  * @param {any} configValue - Configuration value to set
202
242
  */
203
243
  setConfig: (id, namespace, configKey, configValue, auditMessage) =>
204
- this._request('PUT', `/api/v1/vocab-layers/${id}/config/${namespace}/${configKey}`, { auditMessage,
205
- rawBody: configValue, skipResponseTransform: true,
206
- }),
244
+ this._request(
245
+ "PUT",
246
+ `/api/v1/vocab-layers/${id}/config/${namespace}/${configKey}`,
247
+ { auditMessage, rawBody: configValue, skipResponseTransform: true },
248
+ ),
207
249
  /**
208
250
  * Remove a configuration value for a layer.
209
251
  * @param {string} id - The resource ID
@@ -211,9 +253,11 @@ class PlaidClient {
211
253
  * @param {string} configKey - The config key
212
254
  */
213
255
  deleteConfig: (id, namespace, configKey, auditMessage) =>
214
- this._request('DELETE', `/api/v1/vocab-layers/${id}/config/${namespace}/${configKey}`, { auditMessage,
215
- skipResponseTransform: true,
216
- }),
256
+ this._request(
257
+ "DELETE",
258
+ `/api/v1/vocab-layers/${id}/config/${namespace}/${configKey}`,
259
+ { auditMessage, skipResponseTransform: true },
260
+ ),
217
261
  /**
218
262
  * List all vocab layers accessible to user. Transparently follows
219
263
  * pagination cursors and returns the full flat array.
@@ -221,7 +265,7 @@ class PlaidClient {
221
265
  * @param {string} [asOf] - Temporal query timestamp
222
266
  */
223
267
  list: (asOf) =>
224
- listAll(this, '/api/v1/vocab-layers', { query: { 'as-of': asOf } }),
268
+ listAll(this, "/api/v1/vocab-layers", { query: { "as-of": asOf } }),
225
269
  /**
226
270
  * Fetch a single page of vocab layers.
227
271
  * @param {object} [opts]
@@ -231,7 +275,11 @@ class PlaidClient {
231
275
  * @returns {Promise<{entries: Array, nextCursor: (string|null)}>}
232
276
  */
233
277
  listPage: ({ limit, cursor, asOf } = {}) =>
234
- listPage(this, '/api/v1/vocab-layers', { limit, cursor, query: { 'as-of': asOf } }),
278
+ listPage(this, "/api/v1/vocab-layers", {
279
+ limit,
280
+ cursor,
281
+ query: { "as-of": asOf },
282
+ }),
235
283
  /**
236
284
  * Async-iterate vocab layers page by page; yields each page's entries array.
237
285
  * @param {object} [opts]
@@ -241,13 +289,17 @@ class PlaidClient {
241
289
  * @returns {AsyncGenerator<Array>}
242
290
  */
243
291
  iterPages: ({ pageSize, asOf } = {}) =>
244
- iterPages(this, '/api/v1/vocab-layers', { pageSize, query: { 'as-of': asOf } }),
292
+ iterPages(this, "/api/v1/vocab-layers", {
293
+ pageSize,
294
+ query: { "as-of": asOf },
295
+ }),
245
296
  /**
246
297
  * Create a new vocab layer. Note: this also registers the user as a maintainer.
247
298
  * @param {string} name - The name
248
299
  */
249
300
  create: (name, auditMessage) =>
250
- this._request('POST', '/api/v1/vocab-layers', { auditMessage,
301
+ this._request("POST", "/api/v1/vocab-layers", {
302
+ auditMessage,
251
303
  body: bodyOf({ name }),
252
304
  }),
253
305
  /**
@@ -256,14 +308,22 @@ class PlaidClient {
256
308
  * @param {string} userId - The user ID
257
309
  */
258
310
  addMaintainer: (id, userId, auditMessage) =>
259
- this._request('POST', `/api/v1/vocab-layers/${id}/maintainers/${userId}`, { auditMessage }),
311
+ this._request(
312
+ "POST",
313
+ `/api/v1/vocab-layers/${id}/maintainers/${userId}`,
314
+ { auditMessage },
315
+ ),
260
316
  /**
261
317
  * Remove a user's maintainer privileges for this vocab layer.
262
318
  * @param {string} id - The resource ID
263
319
  * @param {string} userId - The user ID
264
320
  */
265
321
  removeMaintainer: (id, userId, auditMessage) =>
266
- this._request('DELETE', `/api/v1/vocab-layers/${id}/maintainers/${userId}`, { auditMessage }),
322
+ this._request(
323
+ "DELETE",
324
+ `/api/v1/vocab-layers/${id}/maintainers/${userId}`,
325
+ { auditMessage },
326
+ ),
267
327
  };
268
328
 
269
329
  this.relations = {
@@ -273,15 +333,18 @@ class PlaidClient {
273
333
  * @param {any} body - The request body
274
334
  */
275
335
  setMetadata: (relationId, body, auditMessage) =>
276
- this._request('PUT', `/api/v1/relations/${relationId}/metadata`, { auditMessage,
277
- rawBody: body, skipResponseTransform: true,
336
+ this._request("PUT", `/api/v1/relations/${relationId}/metadata`, {
337
+ auditMessage,
338
+ rawBody: body,
339
+ skipResponseTransform: true,
278
340
  }),
279
341
  /**
280
342
  * Remove all metadata from a relation.
281
343
  * @param {string} relationId - The relation ID
282
344
  */
283
345
  deleteMetadata: (relationId, auditMessage) =>
284
- this._request('DELETE', `/api/v1/relations/${relationId}/metadata`, { auditMessage,
346
+ this._request("DELETE", `/api/v1/relations/${relationId}/metadata`, {
347
+ auditMessage,
285
348
  skipResponseTransform: true,
286
349
  }),
287
350
  /**
@@ -290,8 +353,10 @@ class PlaidClient {
290
353
  * @param {any} body - The metadata patch
291
354
  */
292
355
  patchMetadata: (relationId, body, auditMessage) =>
293
- this._request('PATCH', `/api/v1/relations/${relationId}/metadata`, { auditMessage,
294
- rawBody: body, skipResponseTransform: true,
356
+ this._request("PATCH", `/api/v1/relations/${relationId}/metadata`, {
357
+ auditMessage,
358
+ rawBody: body,
359
+ skipResponseTransform: true,
295
360
  }),
296
361
  /**
297
362
  * Update the target span of a relation.
@@ -299,8 +364,9 @@ class PlaidClient {
299
364
  * @param {string} spanId - The span ID
300
365
  */
301
366
  setTarget: (relationId, spanId, auditMessage) =>
302
- this._request('PUT', `/api/v1/relations/${relationId}/target`, { auditMessage,
303
- body: bodyOf({ 'span-id': spanId }),
367
+ this._request("PUT", `/api/v1/relations/${relationId}/target`, {
368
+ auditMessage,
369
+ body: bodyOf({ "span-id": spanId }),
304
370
  }),
305
371
  /**
306
372
  * Get a relation by ID.
@@ -308,22 +374,25 @@ class PlaidClient {
308
374
  * @param {string} [asOf] - Temporal query timestamp
309
375
  */
310
376
  get: (relationId, asOf) =>
311
- this._request('GET', `/api/v1/relations/${relationId}`, {
312
- queryParams: { 'as-of': asOf },
377
+ this._request("GET", `/api/v1/relations/${relationId}`, {
378
+ queryParams: { "as-of": asOf },
313
379
  }),
314
380
  /**
315
381
  * Delete a relation.
316
382
  * @param {string} relationId - The relation ID
317
383
  */
318
384
  delete: (relationId, auditMessage) =>
319
- this._request('DELETE', `/api/v1/relations/${relationId}`, { auditMessage }),
385
+ this._request("DELETE", `/api/v1/relations/${relationId}`, {
386
+ auditMessage,
387
+ }),
320
388
  /**
321
389
  * Update a relation's value.
322
390
  * @param {string} relationId - The relation ID
323
391
  * @param {any} value - The value
324
392
  */
325
393
  update: (relationId, value, auditMessage) =>
326
- this._request('PATCH', `/api/v1/relations/${relationId}`, { auditMessage,
394
+ this._request("PATCH", `/api/v1/relations/${relationId}`, {
395
+ auditMessage,
327
396
  body: bodyOf({ value }),
328
397
  }),
329
398
  /**
@@ -332,8 +401,9 @@ class PlaidClient {
332
401
  * @param {string} spanId - The span ID
333
402
  */
334
403
  setSource: (relationId, spanId, auditMessage) =>
335
- this._request('PUT', `/api/v1/relations/${relationId}/source`, { auditMessage,
336
- body: bodyOf({ 'span-id': spanId }),
404
+ this._request("PUT", `/api/v1/relations/${relationId}/source`, {
405
+ auditMessage,
406
+ body: bodyOf({ "span-id": spanId }),
337
407
  }),
338
408
  /**
339
409
  * Create a new relation. A relation is a directed edge between two spans
@@ -346,8 +416,15 @@ class PlaidClient {
346
416
  * @param {any} [metadata] - Metadata map. Omit to leave unset; pass null to send JSON null.
347
417
  */
348
418
  create: (layerId, sourceId, targetId, value, metadata, auditMessage) =>
349
- this._request('POST', '/api/v1/relations', { auditMessage,
350
- body: bodyOf({ 'layer-id': layerId, 'source-id': sourceId, 'target-id': targetId, value, metadata }),
419
+ this._request("POST", "/api/v1/relations", {
420
+ auditMessage,
421
+ body: bodyOf({
422
+ "layer-id": layerId,
423
+ "source-id": sourceId,
424
+ "target-id": targetId,
425
+ value,
426
+ metadata,
427
+ }),
351
428
  }),
352
429
  /**
353
430
  * Create multiple relations in a single operation.
@@ -355,13 +432,16 @@ class PlaidClient {
355
432
  * @returns {Promise<{ids: string[]}>} The created entity IDs, in input order. (bulkDelete resolves to no value.)
356
433
  */
357
434
  bulkCreate: (body, auditMessage) =>
358
- this._request('POST', '/api/v1/relations/bulk', { auditMessage, body }),
435
+ this._request("POST", "/api/v1/relations/bulk", { auditMessage, body }),
359
436
  /**
360
437
  * Delete multiple relations in a single operation. Provide an array of IDs.
361
438
  * @param {Array} body - The request body
362
439
  */
363
440
  bulkDelete: (body, auditMessage) =>
364
- this._request('DELETE', '/api/v1/relations/bulk', { auditMessage, body }),
441
+ this._request("DELETE", "/api/v1/relations/bulk", {
442
+ auditMessage,
443
+ body,
444
+ }),
365
445
  };
366
446
 
367
447
  this.spanLayers = {
@@ -372,10 +452,18 @@ class PlaidClient {
372
452
  * @param {string} configKey - The config key
373
453
  * @param {any} configValue - Configuration value to set
374
454
  */
375
- setConfig: (spanLayerId, namespace, configKey, configValue, auditMessage) =>
376
- this._request('PUT', `/api/v1/span-layers/${spanLayerId}/config/${namespace}/${configKey}`, { auditMessage,
377
- rawBody: configValue, skipResponseTransform: true,
378
- }),
455
+ setConfig: (
456
+ spanLayerId,
457
+ namespace,
458
+ configKey,
459
+ configValue,
460
+ auditMessage,
461
+ ) =>
462
+ this._request(
463
+ "PUT",
464
+ `/api/v1/span-layers/${spanLayerId}/config/${namespace}/${configKey}`,
465
+ { auditMessage, rawBody: configValue, skipResponseTransform: true },
466
+ ),
379
467
  /**
380
468
  * Remove a configuration value for a layer.
381
469
  * @param {string} spanLayerId - The span layer ID
@@ -383,31 +471,36 @@ class PlaidClient {
383
471
  * @param {string} configKey - The config key
384
472
  */
385
473
  deleteConfig: (spanLayerId, namespace, configKey, auditMessage) =>
386
- this._request('DELETE', `/api/v1/span-layers/${spanLayerId}/config/${namespace}/${configKey}`, { auditMessage,
387
- skipResponseTransform: true,
388
- }),
474
+ this._request(
475
+ "DELETE",
476
+ `/api/v1/span-layers/${spanLayerId}/config/${namespace}/${configKey}`,
477
+ { auditMessage, skipResponseTransform: true },
478
+ ),
389
479
  /**
390
480
  * Get a span layer by ID.
391
481
  * @param {string} spanLayerId - The span layer ID
392
482
  * @param {string} [asOf] - Temporal query timestamp
393
483
  */
394
484
  get: (spanLayerId, asOf) =>
395
- this._request('GET', `/api/v1/span-layers/${spanLayerId}`, {
396
- queryParams: { 'as-of': asOf },
485
+ this._request("GET", `/api/v1/span-layers/${spanLayerId}`, {
486
+ queryParams: { "as-of": asOf },
397
487
  }),
398
488
  /**
399
489
  * Delete a span layer.
400
490
  * @param {string} spanLayerId - The span layer ID
401
491
  */
402
492
  delete: (spanLayerId, auditMessage) =>
403
- this._request('DELETE', `/api/v1/span-layers/${spanLayerId}`, { auditMessage }),
493
+ this._request("DELETE", `/api/v1/span-layers/${spanLayerId}`, {
494
+ auditMessage,
495
+ }),
404
496
  /**
405
497
  * Update a span layer's name.
406
498
  * @param {string} spanLayerId - The span layer ID
407
499
  * @param {string} name - The name
408
500
  */
409
501
  update: (spanLayerId, name, auditMessage) =>
410
- this._request('PATCH', `/api/v1/span-layers/${spanLayerId}`, { auditMessage,
502
+ this._request("PATCH", `/api/v1/span-layers/${spanLayerId}`, {
503
+ auditMessage,
411
504
  body: bodyOf({ name }),
412
505
  }),
413
506
  /**
@@ -416,8 +509,9 @@ class PlaidClient {
416
509
  * @param {string} name - The name
417
510
  */
418
511
  create: (tokenLayerId, name, auditMessage) =>
419
- this._request('POST', '/api/v1/span-layers', { auditMessage,
420
- body: bodyOf({ 'token-layer-id': tokenLayerId, name }),
512
+ this._request("POST", "/api/v1/span-layers", {
513
+ auditMessage,
514
+ body: bodyOf({ "token-layer-id": tokenLayerId, name }),
421
515
  }),
422
516
  /**
423
517
  * Shift a span layer's display order.
@@ -425,7 +519,8 @@ class PlaidClient {
425
519
  * @param {string} direction - The direction ("up" or "down")
426
520
  */
427
521
  shift: (spanLayerId, direction, auditMessage) =>
428
- this._request('POST', `/api/v1/span-layers/${spanLayerId}/shift`, { auditMessage,
522
+ this._request("POST", `/api/v1/span-layers/${spanLayerId}/shift`, {
523
+ auditMessage,
429
524
  body: bodyOf({ direction }),
430
525
  }),
431
526
  };
@@ -437,7 +532,8 @@ class PlaidClient {
437
532
  * @param {Array} tokens - The tokens
438
533
  */
439
534
  setTokens: (spanId, tokens, auditMessage) =>
440
- this._request('PUT', `/api/v1/spans/${spanId}/tokens`, { auditMessage,
535
+ this._request("PUT", `/api/v1/spans/${spanId}/tokens`, {
536
+ auditMessage,
441
537
  body: bodyOf({ tokens }),
442
538
  }),
443
539
  /**
@@ -449,8 +545,14 @@ class PlaidClient {
449
545
  * @param {any} [metadata] - Metadata map. Omit to leave unset; pass null to send JSON null.
450
546
  */
451
547
  create: (spanLayerId, tokens, value, metadata, auditMessage) =>
452
- this._request('POST', '/api/v1/spans', { auditMessage,
453
- body: bodyOf({ 'span-layer-id': spanLayerId, tokens, value, metadata }),
548
+ this._request("POST", "/api/v1/spans", {
549
+ auditMessage,
550
+ body: bodyOf({
551
+ "span-layer-id": spanLayerId,
552
+ tokens,
553
+ value,
554
+ metadata,
555
+ }),
454
556
  }),
455
557
  /**
456
558
  * Get a span by ID.
@@ -458,22 +560,23 @@ class PlaidClient {
458
560
  * @param {string} [asOf] - Temporal query timestamp
459
561
  */
460
562
  get: (spanId, asOf) =>
461
- this._request('GET', `/api/v1/spans/${spanId}`, {
462
- queryParams: { 'as-of': asOf },
563
+ this._request("GET", `/api/v1/spans/${spanId}`, {
564
+ queryParams: { "as-of": asOf },
463
565
  }),
464
566
  /**
465
567
  * Delete a span.
466
568
  * @param {string} spanId - The span ID
467
569
  */
468
570
  delete: (spanId, auditMessage) =>
469
- this._request('DELETE', `/api/v1/spans/${spanId}`, { auditMessage }),
571
+ this._request("DELETE", `/api/v1/spans/${spanId}`, { auditMessage }),
470
572
  /**
471
573
  * Update a span's value.
472
574
  * @param {string} spanId - The span ID
473
575
  * @param {any} value - The value
474
576
  */
475
577
  update: (spanId, value, auditMessage) =>
476
- this._request('PATCH', `/api/v1/spans/${spanId}`, { auditMessage,
578
+ this._request("PATCH", `/api/v1/spans/${spanId}`, {
579
+ auditMessage,
477
580
  body: bodyOf({ value }),
478
581
  }),
479
582
  /**
@@ -482,28 +585,31 @@ class PlaidClient {
482
585
  * @returns {Promise<{ids: string[]}>} The created entity IDs, in input order. (bulkDelete resolves to no value.)
483
586
  */
484
587
  bulkCreate: (body, auditMessage) =>
485
- this._request('POST', '/api/v1/spans/bulk', { auditMessage, body }),
588
+ this._request("POST", "/api/v1/spans/bulk", { auditMessage, body }),
486
589
  /**
487
590
  * Delete multiple spans in a single operation. Provide an array of IDs.
488
591
  * @param {Array} body - The request body
489
592
  */
490
593
  bulkDelete: (body, auditMessage) =>
491
- this._request('DELETE', '/api/v1/spans/bulk', { auditMessage, body }),
594
+ this._request("DELETE", "/api/v1/spans/bulk", { auditMessage, body }),
492
595
  /**
493
596
  * Replace all metadata for a span.
494
597
  * @param {string} spanId - The span ID
495
598
  * @param {any} body - The request body
496
599
  */
497
600
  setMetadata: (spanId, body, auditMessage) =>
498
- this._request('PUT', `/api/v1/spans/${spanId}/metadata`, { auditMessage,
499
- rawBody: body, skipResponseTransform: true,
601
+ this._request("PUT", `/api/v1/spans/${spanId}/metadata`, {
602
+ auditMessage,
603
+ rawBody: body,
604
+ skipResponseTransform: true,
500
605
  }),
501
606
  /**
502
607
  * Remove all metadata from a span.
503
608
  * @param {string} spanId - The span ID
504
609
  */
505
610
  deleteMetadata: (spanId, auditMessage) =>
506
- this._request('DELETE', `/api/v1/spans/${spanId}/metadata`, { auditMessage,
611
+ this._request("DELETE", `/api/v1/spans/${spanId}/metadata`, {
612
+ auditMessage,
507
613
  skipResponseTransform: true,
508
614
  }),
509
615
  /**
@@ -512,8 +618,10 @@ class PlaidClient {
512
618
  * @param {any} body - The metadata patch
513
619
  */
514
620
  patchMetadata: (spanId, body, auditMessage) =>
515
- this._request('PATCH', `/api/v1/spans/${spanId}/metadata`, { auditMessage,
516
- rawBody: body, skipResponseTransform: true,
621
+ this._request("PATCH", `/api/v1/spans/${spanId}/metadata`, {
622
+ auditMessage,
623
+ rawBody: body,
624
+ skipResponseTransform: true,
517
625
  }),
518
626
  };
519
627
 
@@ -524,8 +632,10 @@ class PlaidClient {
524
632
  * @param {Array} body - The request body
525
633
  */
526
634
  submit: (body, auditMessage) =>
527
- this._request('POST', '/api/v1/batch', { auditMessage,
528
- body, noBatch: true,
635
+ this._request("POST", "/api/v1/batch", {
636
+ auditMessage,
637
+ body,
638
+ noBatch: true,
529
639
  }),
530
640
  };
531
641
 
@@ -536,15 +646,18 @@ class PlaidClient {
536
646
  * @param {any} body - The request body
537
647
  */
538
648
  setMetadata: (textId, body, auditMessage) =>
539
- this._request('PUT', `/api/v1/texts/${textId}/metadata`, { auditMessage,
540
- rawBody: body, skipResponseTransform: true,
649
+ this._request("PUT", `/api/v1/texts/${textId}/metadata`, {
650
+ auditMessage,
651
+ rawBody: body,
652
+ skipResponseTransform: true,
541
653
  }),
542
654
  /**
543
655
  * Remove all metadata from a text.
544
656
  * @param {string} textId - The text ID
545
657
  */
546
658
  deleteMetadata: (textId, auditMessage) =>
547
- this._request('DELETE', `/api/v1/texts/${textId}/metadata`, { auditMessage,
659
+ this._request("DELETE", `/api/v1/texts/${textId}/metadata`, {
660
+ auditMessage,
548
661
  skipResponseTransform: true,
549
662
  }),
550
663
  /**
@@ -553,8 +666,10 @@ class PlaidClient {
553
666
  * @param {any} body - The metadata patch
554
667
  */
555
668
  patchMetadata: (textId, body, auditMessage) =>
556
- this._request('PATCH', `/api/v1/texts/${textId}/metadata`, { auditMessage,
557
- rawBody: body, skipResponseTransform: true,
669
+ this._request("PATCH", `/api/v1/texts/${textId}/metadata`, {
670
+ auditMessage,
671
+ rawBody: body,
672
+ skipResponseTransform: true,
558
673
  }),
559
674
  /**
560
675
  * Create a new text in a document's text layer. A text is a container for
@@ -565,8 +680,14 @@ class PlaidClient {
565
680
  * @param {any} [metadata] - Metadata map. Omit to leave unset; pass null to send JSON null.
566
681
  */
567
682
  create: (textLayerId, documentId, body, metadata, auditMessage) =>
568
- this._request('POST', '/api/v1/texts', { auditMessage,
569
- body: bodyOf({ 'text-layer-id': textLayerId, 'document-id': documentId, body, metadata }),
683
+ this._request("POST", "/api/v1/texts", {
684
+ auditMessage,
685
+ body: bodyOf({
686
+ "text-layer-id": textLayerId,
687
+ "document-id": documentId,
688
+ body,
689
+ metadata,
690
+ }),
570
691
  }),
571
692
  /**
572
693
  * Get a text.
@@ -574,24 +695,30 @@ class PlaidClient {
574
695
  * @param {string} [asOf] - Temporal query timestamp
575
696
  */
576
697
  get: (textId, asOf) =>
577
- this._request('GET', `/api/v1/texts/${textId}`, {
578
- queryParams: { 'as-of': asOf },
698
+ this._request("GET", `/api/v1/texts/${textId}`, {
699
+ queryParams: { "as-of": asOf },
579
700
  }),
580
701
  /**
581
702
  * Delete a text and all dependent data.
582
703
  * @param {string} textId - The text ID
583
704
  */
584
705
  delete: (textId, auditMessage) =>
585
- this._request('DELETE', `/api/v1/texts/${textId}`, { auditMessage }),
706
+ this._request("DELETE", `/api/v1/texts/${textId}`, { auditMessage }),
586
707
  /**
587
708
  * Update a text's body. A diff is computed and token indices are updated
588
709
  * so that tokens remain intact. Alternatively, `body` can be a list of
589
- * edit directives.
710
+ * edit directives (code-point indices, applied in order):
711
+ * {type: 'delete', index, value: count}
712
+ * {type: 'insert', index, value: string}
713
+ * {type: 'replace', index, length, value: string} — unlike
714
+ * delete+insert, a token covering the whole range is resized to keep
715
+ * it (respell a word in place without losing its annotations).
590
716
  * @param {string} textId - The text ID
591
717
  * @param {any} body - The request body
592
718
  */
593
719
  update: (textId, body, auditMessage) =>
594
- this._request('PATCH', `/api/v1/texts/${textId}`, { auditMessage,
720
+ this._request("PATCH", `/api/v1/texts/${textId}`, {
721
+ auditMessage,
595
722
  body: bodyOf({ body }),
596
723
  }),
597
724
  };
@@ -602,42 +729,58 @@ class PlaidClient {
602
729
  * returns the full flat array. Admin-or-maintainer only.
603
730
  * Cannot be used inside a batch (auto-paginates across requests); throws if called while batching — use listPage() for a single page in a batch.
604
731
  * @param {object} [opts]
605
- * @param {string} [opts.q] - Filter to usernames containing this text (case-insensitive)
732
+ * @param {string} [opts.q] - Filter to users whose display name or email contains this text (case-insensitive)
606
733
  * @param {string} [opts.asOf] - Temporal query timestamp
607
734
  */
608
735
  list: ({ q, asOf } = {}) =>
609
- listAll(this, '/api/v1/users', { query: { q, 'as-of': asOf } }),
736
+ listAll(this, "/api/v1/users", { query: { q, "as-of": asOf } }),
610
737
  /**
611
738
  * Fetch a single page of users (optionally filtered by `q`).
612
739
  * @param {object} [opts]
613
- * @param {string} [opts.q] - Filter to usernames containing this text (case-insensitive)
740
+ * @param {string} [opts.q] - Filter to users whose display name or email contains this text (case-insensitive)
614
741
  * @param {number} [opts.limit] - Page size (1..1000; server default 100)
615
742
  * @param {string} [opts.cursor] - Opaque cursor from a previous page
616
743
  * @param {string} [opts.asOf] - Temporal query timestamp
617
744
  * @returns {Promise<{entries: Array, nextCursor: (string|null)}>}
618
745
  */
619
746
  listPage: ({ q, limit, cursor, asOf } = {}) =>
620
- listPage(this, '/api/v1/users', { limit, cursor, query: { q, 'as-of': asOf } }),
747
+ listPage(this, "/api/v1/users", {
748
+ limit,
749
+ cursor,
750
+ query: { q, "as-of": asOf },
751
+ }),
621
752
  /**
622
753
  * Async-iterate users page by page; yields each page's entries array.
623
754
  * @param {object} [opts]
624
- * @param {string} [opts.q] - Filter to usernames containing this text (case-insensitive)
755
+ * @param {string} [opts.q] - Filter to users whose display name or email contains this text (case-insensitive)
625
756
  * @param {number} [opts.pageSize] - Per-request page size
626
757
  * @param {string} [opts.asOf] - Temporal query timestamp
627
758
  * Cannot be used inside a batch (auto-paginates across requests); throws on first iteration if called while batching — use listPage() for a single page in a batch.
628
759
  * @returns {AsyncGenerator<Array>}
629
760
  */
630
761
  iterPages: ({ q, pageSize, asOf } = {}) =>
631
- iterPages(this, '/api/v1/users', { pageSize, query: { q, 'as-of': asOf } }),
762
+ iterPages(this, "/api/v1/users", {
763
+ pageSize,
764
+ query: { q, "as-of": asOf },
765
+ }),
632
766
  /**
633
- * Create a new user
634
- * @param {string} username - The username
767
+ * Create a new user.
768
+ * @param {string} email - The account's email address. It becomes the
769
+ * user's id and is what they log in with; it can never be changed.
635
770
  * @param {string} password - The password
636
771
  * @param {boolean} isAdmin - Whether the user is an admin
772
+ * @param {string} [displayName] - How the user is shown in the UI.
773
+ * Defaults to the local part of the email.
637
774
  */
638
- create: (username, password, isAdmin, auditMessage) =>
639
- this._request('POST', '/api/v1/users', { auditMessage,
640
- body: bodyOf({ username, password, 'is-admin': isAdmin }),
775
+ create: (email, password, isAdmin, displayName, auditMessage) =>
776
+ this._request("POST", "/api/v1/users", {
777
+ auditMessage,
778
+ body: bodyOf({
779
+ email,
780
+ password,
781
+ "is-admin": isAdmin,
782
+ "display-name": displayName,
783
+ }),
641
784
  }),
642
785
  /**
643
786
  * Get audit log for a user's actions. Transparently follows pagination
@@ -655,10 +798,10 @@ class PlaidClient {
655
798
  audit: (userId, startTime, endTime, asOf, opTypes) =>
656
799
  listAll(this, `/api/v1/users/${userId}/audit`, {
657
800
  query: {
658
- 'start-time': startTime,
659
- 'end-time': endTime,
660
- 'as-of': asOf,
661
- 'op-types': opTypesParam(opTypes),
801
+ "start-time": startTime,
802
+ "end-time": endTime,
803
+ "as-of": asOf,
804
+ "op-types": opTypesParam(opTypes),
662
805
  },
663
806
  }),
664
807
  /**
@@ -667,8 +810,8 @@ class PlaidClient {
667
810
  * @param {string} [asOf] - Temporal query timestamp
668
811
  */
669
812
  get: (id, asOf) =>
670
- this._request('GET', `/api/v1/users/${id}`, {
671
- queryParams: { 'as-of': asOf },
813
+ this._request("GET", `/api/v1/users/${id}`, {
814
+ queryParams: { "as-of": asOf },
672
815
  }),
673
816
  /**
674
817
  * Deactivate a user. Users are never hard-deleted: deactivation
@@ -679,7 +822,7 @@ class PlaidClient {
679
822
  * @param {string} id - The resource ID
680
823
  */
681
824
  delete: (id, auditMessage) =>
682
- this._request('DELETE', `/api/v1/users/${id}`, { auditMessage }),
825
+ this._request("DELETE", `/api/v1/users/${id}`, { auditMessage }),
683
826
  /**
684
827
  * Reactivate a deactivated user, restoring their ability to log in.
685
828
  * Project memberships, vocab maintainerships, and API tokens removed
@@ -687,19 +830,27 @@ class PlaidClient {
687
830
  * @param {string} id - The resource ID
688
831
  */
689
832
  activate: (id, auditMessage) =>
690
- this._request('POST', `/api/v1/users/${id}/activate`, { auditMessage }),
833
+ this._request("POST", `/api/v1/users/${id}/activate`, { auditMessage }),
691
834
  /**
692
- * Modify a user. Admins may change the username, password, and admin
693
- * status of any user. All other users may only modify their own username
694
- * or password.
695
- * @param {string} id - The resource ID
835
+ * Modify a user. Admins may change the display name, password, and admin
836
+ * status of any user. All other users may only modify their own display
837
+ * name or password.
838
+ *
839
+ * A user's id is their email address and is fixed for the life of the
840
+ * account — it is what they log in with, so nothing can change it.
841
+ * @param {string} id - The resource ID (the user's email address)
696
842
  * @param {string} [password] - New password
697
- * @param {string} [username] - New username
843
+ * @param {string} [displayName] - New display name
698
844
  * @param {boolean} [isAdmin] - New admin status
699
845
  */
700
- update: (id, password, username, isAdmin, auditMessage) =>
701
- this._request('PATCH', `/api/v1/users/${id}`, { auditMessage,
702
- body: bodyOf({ password, username, 'is-admin': isAdmin }),
846
+ update: (id, password, displayName, isAdmin, auditMessage) =>
847
+ this._request("PATCH", `/api/v1/users/${id}`, {
848
+ auditMessage,
849
+ body: bodyOf({
850
+ password,
851
+ "display-name": displayName,
852
+ "is-admin": isAdmin,
853
+ }),
703
854
  }),
704
855
  /**
705
856
  * Build a URL for a user's profile picture, suitable for use directly as
@@ -719,7 +870,7 @@ class PlaidClient {
719
870
  avatarUrl: (id, avatarHash) => {
720
871
  if (avatarHash === null) return null;
721
872
  const params = new URLSearchParams({ token: this.token });
722
- if (avatarHash) params.set('v', avatarHash);
873
+ if (avatarHash) params.set("v", avatarHash);
723
874
  return `${this.baseUrl}/api/v1/users/${id}/avatar?${params}`;
724
875
  },
725
876
  /**
@@ -728,7 +879,7 @@ class PlaidClient {
728
879
  * @param {string} id - The user ID
729
880
  */
730
881
  getAvatar: (id) =>
731
- this._request('GET', `/api/v1/users/${id}/avatar`, {
882
+ this._request("GET", `/api/v1/users/${id}/avatar`, {
732
883
  noBatch: true,
733
884
  binaryResponse: true,
734
885
  }),
@@ -742,9 +893,12 @@ class PlaidClient {
742
893
  */
743
894
  setAvatar: (id, file, auditMessage) => {
744
895
  const fd = new FormData();
745
- fd.append('file', file);
746
- return this._request('PUT', `/api/v1/users/${id}/avatar`, { auditMessage,
747
- body: fd, formData: true, noBatch: true,
896
+ fd.append("file", file);
897
+ return this._request("PUT", `/api/v1/users/${id}/avatar`, {
898
+ auditMessage,
899
+ body: fd,
900
+ formData: true,
901
+ noBatch: true,
748
902
  });
749
903
  },
750
904
  /**
@@ -752,11 +906,72 @@ class PlaidClient {
752
906
  * @param {string} id - The user ID
753
907
  */
754
908
  deleteAvatar: (id, auditMessage) =>
755
- this._request('DELETE', `/api/v1/users/${id}/avatar`, { auditMessage,
909
+ this._request("DELETE", `/api/v1/users/${id}/avatar`, {
910
+ auditMessage,
756
911
  noBatch: true,
757
912
  }),
758
913
  };
759
914
 
915
+ this.userData = {
916
+ /**
917
+ * List a user's private data entries ({key, updatedAt}, plus value when
918
+ * includeValues). Owner or admin only.
919
+ * @param {string} userId
920
+ * @param {object} [opts]
921
+ * @param {string} [opts.prefix] - Only keys starting with this prefix
922
+ * @param {boolean} [opts.includeValues] - Also return each entry's value
923
+ */
924
+ list: (userId, { prefix, includeValues } = {}) =>
925
+ this._request("GET", `/api/v1/users/${userId}/data`, {
926
+ queryParams: { prefix, "include-values": includeValues },
927
+ }),
928
+ /**
929
+ * Read one private data entry ({key, updatedAt, value}); 404 if absent.
930
+ * @param {string} userId
931
+ * @param {string} key
932
+ */
933
+ get: (userId, key) =>
934
+ this._request(
935
+ "GET",
936
+ `/api/v1/users/${userId}/data/${encodeURIComponent(key)}`,
937
+ ),
938
+ /**
939
+ * Create or replace one private data entry. `value` is any JSON (up to
940
+ * 1 MB), stored as sent. Not audited, not batchable.
941
+ *
942
+ * The server stores it verbatim, but this client recases object keys on
943
+ * the way out and back like any other body (`myKey` <-> `my-key`), so a
944
+ * value whose keys are camelCase round-trips unchanged while one keyed
945
+ * by arbitrary strings does not. Put such a map under a `metadata` key,
946
+ * which both clients pass through untouched.
947
+ * @param {string} userId
948
+ * @param {string} key
949
+ * @param {*} value
950
+ */
951
+ put: (userId, key, value) =>
952
+ this._request(
953
+ "PUT",
954
+ `/api/v1/users/${userId}/data/${encodeURIComponent(key)}`,
955
+ {
956
+ body: value,
957
+ noBatch: true,
958
+ },
959
+ ),
960
+ /**
961
+ * Delete one private data entry; 404 if absent.
962
+ * @param {string} userId
963
+ * @param {string} key
964
+ */
965
+ delete: (userId, key) =>
966
+ this._request(
967
+ "DELETE",
968
+ `/api/v1/users/${userId}/data/${encodeURIComponent(key)}`,
969
+ {
970
+ noBatch: true,
971
+ },
972
+ ),
973
+ };
974
+
760
975
  this.apiTokens = {
761
976
  /**
762
977
  * List a user's named API tokens. Never includes the signed token
@@ -765,8 +980,7 @@ class PlaidClient {
765
980
  * Cannot be used inside a batch (auto-paginates across requests); throws if called while batching — use listPage() for a single page in a batch.
766
981
  * @param {string} userId - The user ID who owns the tokens
767
982
  */
768
- list: (userId) =>
769
- listAll(this, `/api/v1/users/${userId}/tokens`),
983
+ list: (userId) => listAll(this, `/api/v1/users/${userId}/tokens`),
770
984
  /**
771
985
  * Fetch a single page of a user's named API tokens.
772
986
  * @param {string} userId - The user ID who owns the tokens
@@ -797,7 +1011,8 @@ class PlaidClient {
797
1011
  * @returns {Promise<{id: string, name: string, token: string}>}
798
1012
  */
799
1013
  create: (userId, name, auditMessage) =>
800
- this._request('POST', `/api/v1/users/${userId}/tokens`, { auditMessage,
1014
+ this._request("POST", `/api/v1/users/${userId}/tokens`, {
1015
+ auditMessage,
801
1016
  body: bodyOf({ name }),
802
1017
  }),
803
1018
  /**
@@ -806,7 +1021,9 @@ class PlaidClient {
806
1021
  * @param {string} tokenId - The token ID to revoke
807
1022
  */
808
1023
  revoke: (userId, tokenId, auditMessage) =>
809
- this._request('DELETE', `/api/v1/users/${userId}/tokens/${tokenId}`, { auditMessage }),
1024
+ this._request("DELETE", `/api/v1/users/${userId}/tokens/${tokenId}`, {
1025
+ auditMessage,
1026
+ }),
810
1027
  };
811
1028
 
812
1029
  this.invites = {
@@ -821,7 +1038,9 @@ class PlaidClient {
821
1038
  * @param {string} [opts.projectId] - List this project's invites instead of your own
822
1039
  */
823
1040
  list: ({ projectId } = {}) =>
824
- listAll(this, '/api/v1/invites', { query: { 'project-id': projectId } }),
1041
+ listAll(this, "/api/v1/invites", {
1042
+ query: { "project-id": projectId },
1043
+ }),
825
1044
  /**
826
1045
  * Fetch a single page of invites.
827
1046
  * @param {object} [opts]
@@ -831,7 +1050,11 @@ class PlaidClient {
831
1050
  * @returns {Promise<{entries: Array, nextCursor: (string|null)}>}
832
1051
  */
833
1052
  listPage: ({ projectId, limit, cursor } = {}) =>
834
- listPage(this, '/api/v1/invites', { limit, cursor, query: { 'project-id': projectId } }),
1053
+ listPage(this, "/api/v1/invites", {
1054
+ limit,
1055
+ cursor,
1056
+ query: { "project-id": projectId },
1057
+ }),
835
1058
  /**
836
1059
  * Async-iterate invites page by page; yields each page's entries array.
837
1060
  * @param {object} [opts]
@@ -841,7 +1064,10 @@ class PlaidClient {
841
1064
  * @returns {AsyncGenerator<Array>}
842
1065
  */
843
1066
  iterPages: ({ projectId, pageSize } = {}) =>
844
- iterPages(this, '/api/v1/invites', { pageSize, query: { 'project-id': projectId } }),
1067
+ iterPages(this, "/api/v1/invites", {
1068
+ pageSize,
1069
+ query: { "project-id": projectId },
1070
+ }),
845
1071
  /**
846
1072
  * Mint an invite. The returned `code` is shown ONLY here — it is never
847
1073
  * stored and cannot be recovered, so build and hand off the link now.
@@ -849,23 +1075,46 @@ class PlaidClient {
849
1075
  *
850
1076
  * Admins may mint anything. A project maintainer may mint role grants on
851
1077
  * projects they maintain, and nothing else: no admin grant, no grantless
852
- * invite, no password resets.
853
- * @param {object} opts
854
- * @param {string} [opts.projectId] - Project the redeemer joins (with projectRole)
855
- * @param {string} [opts.projectRole] - "reader" | "writer" | "maintainer"
1078
+ * invite, no password resets — so for a non-admin, projectId/projectRole
1079
+ * are required in practice (403 without them).
1080
+ *
1081
+ * EVERY option is optional; `create()` with no arguments mints a
1082
+ * single-use signup link granting nothing but an account. Two pairing
1083
+ * rules the server enforces with a 400: projectId and projectRole must be
1084
+ * given TOGETHER, and targetUserId may not be combined with projectId,
1085
+ * grantAdmin, or a maxUses above 1.
1086
+ * @param {object} [opts]
1087
+ * @param {string} [opts.projectId] - Project the redeemer joins (requires projectRole)
1088
+ * @param {string} [opts.projectRole] - "reader" | "writer" | "maintainer" (requires projectId)
856
1089
  * @param {boolean} [opts.grantAdmin] - Make the new account a global admin (admin only)
857
- * @param {string} [opts.targetUserId] - Make this a password reset for that user (admin only)
1090
+ * @param {string} [opts.targetUserId] - Password reset for that user instead of a signup; admin only, single-use, grants nothing
858
1091
  * @param {number} [opts.maxUses] - How many accounts this link may create (default 1)
859
1092
  * @param {number} [opts.ttlDays] - Days until it expires (default 14, max 365)
860
1093
  * @param {string} [opts.note] - Human label shown in your invite list
861
1094
  * @returns {Promise<{id: string, code: string, kind: string, status: string}>}
862
1095
  */
863
- create: ({ projectId, projectRole, grantAdmin, targetUserId, maxUses, ttlDays, note } = {}, auditMessage) =>
864
- this._request('POST', '/api/v1/invites', { auditMessage,
1096
+ create: (
1097
+ {
1098
+ projectId,
1099
+ projectRole,
1100
+ grantAdmin,
1101
+ targetUserId,
1102
+ maxUses,
1103
+ ttlDays,
1104
+ note,
1105
+ } = {},
1106
+ auditMessage,
1107
+ ) =>
1108
+ this._request("POST", "/api/v1/invites", {
1109
+ auditMessage,
865
1110
  body: bodyOf({
866
- 'project-id': projectId, 'project-role': projectRole,
867
- 'grant-admin': grantAdmin, 'target-user-id': targetUserId,
868
- 'max-uses': maxUses, 'ttl-days': ttlDays, note,
1111
+ "project-id": projectId,
1112
+ "project-role": projectRole,
1113
+ "grant-admin": grantAdmin,
1114
+ "target-user-id": targetUserId,
1115
+ "max-uses": maxUses,
1116
+ "ttl-days": ttlDays,
1117
+ note,
869
1118
  }),
870
1119
  }),
871
1120
  /**
@@ -874,7 +1123,7 @@ class PlaidClient {
874
1123
  * @param {string} id - The invite ID
875
1124
  */
876
1125
  revoke: (id, auditMessage) =>
877
- this._request('DELETE', `/api/v1/invites/${id}`, { auditMessage }),
1126
+ this._request("DELETE", `/api/v1/invites/${id}`, { auditMessage }),
878
1127
  };
879
1128
 
880
1129
  this.tokenLayers = {
@@ -884,7 +1133,8 @@ class PlaidClient {
884
1133
  * @param {string} direction - The direction ("up" or "down")
885
1134
  */
886
1135
  shift: (tokenLayerId, direction, auditMessage) =>
887
- this._request('POST', `/api/v1/token-layers/${tokenLayerId}/shift`, { auditMessage,
1136
+ this._request("POST", `/api/v1/token-layers/${tokenLayerId}/shift`, {
1137
+ auditMessage,
888
1138
  body: bodyOf({ direction }),
889
1139
  }),
890
1140
  /**
@@ -894,9 +1144,21 @@ class PlaidClient {
894
1144
  * @param {string} [overlapMode] - Per-layer, immutable token invariant: "any" (default), "non-overlapping", or "partitioning". On partitioning layers, single token create/update/delete are rejected; use bulkCreate plus split/merge/shift.
895
1145
  * @param {string} [parentTokenLayerId] - Optional immutable parent token layer. Tokens in this layer must nest within a parent-layer token; the parent layer must be in the same text layer and be "non-overlapping" or "partitioning" (an "any" parent is rejected). A nested layer may be "any" or "non-overlapping" but not "partitioning" (partitioning is only for root layers), e.g. words (non-overlapping, parent=sentences) within sentences (partitioning).
896
1146
  */
897
- create: (textLayerId, name, overlapMode, parentTokenLayerId, auditMessage) =>
898
- this._request('POST', '/api/v1/token-layers', { auditMessage,
899
- body: bodyOf({ 'text-layer-id': textLayerId, name, 'overlap-mode': overlapMode, 'parent-token-layer-id': parentTokenLayerId }),
1147
+ create: (
1148
+ textLayerId,
1149
+ name,
1150
+ overlapMode,
1151
+ parentTokenLayerId,
1152
+ auditMessage,
1153
+ ) =>
1154
+ this._request("POST", "/api/v1/token-layers", {
1155
+ auditMessage,
1156
+ body: bodyOf({
1157
+ "text-layer-id": textLayerId,
1158
+ name,
1159
+ "overlap-mode": overlapMode,
1160
+ "parent-token-layer-id": parentTokenLayerId,
1161
+ }),
900
1162
  }),
901
1163
  /**
902
1164
  * Set a configuration value for a layer in an editor namespace.
@@ -905,10 +1167,18 @@ class PlaidClient {
905
1167
  * @param {string} configKey - The config key
906
1168
  * @param {any} configValue - Configuration value to set
907
1169
  */
908
- setConfig: (tokenLayerId, namespace, configKey, configValue, auditMessage) =>
909
- this._request('PUT', `/api/v1/token-layers/${tokenLayerId}/config/${namespace}/${configKey}`, { auditMessage,
910
- rawBody: configValue, skipResponseTransform: true,
911
- }),
1170
+ setConfig: (
1171
+ tokenLayerId,
1172
+ namespace,
1173
+ configKey,
1174
+ configValue,
1175
+ auditMessage,
1176
+ ) =>
1177
+ this._request(
1178
+ "PUT",
1179
+ `/api/v1/token-layers/${tokenLayerId}/config/${namespace}/${configKey}`,
1180
+ { auditMessage, rawBody: configValue, skipResponseTransform: true },
1181
+ ),
912
1182
  /**
913
1183
  * Remove a configuration value for a layer.
914
1184
  * @param {string} tokenLayerId - The token layer ID
@@ -916,31 +1186,36 @@ class PlaidClient {
916
1186
  * @param {string} configKey - The config key
917
1187
  */
918
1188
  deleteConfig: (tokenLayerId, namespace, configKey, auditMessage) =>
919
- this._request('DELETE', `/api/v1/token-layers/${tokenLayerId}/config/${namespace}/${configKey}`, { auditMessage,
920
- skipResponseTransform: true,
921
- }),
1189
+ this._request(
1190
+ "DELETE",
1191
+ `/api/v1/token-layers/${tokenLayerId}/config/${namespace}/${configKey}`,
1192
+ { auditMessage, skipResponseTransform: true },
1193
+ ),
922
1194
  /**
923
1195
  * Get a token layer by ID.
924
1196
  * @param {string} tokenLayerId - The token layer ID
925
1197
  * @param {string} [asOf] - Temporal query timestamp
926
1198
  */
927
1199
  get: (tokenLayerId, asOf) =>
928
- this._request('GET', `/api/v1/token-layers/${tokenLayerId}`, {
929
- queryParams: { 'as-of': asOf },
1200
+ this._request("GET", `/api/v1/token-layers/${tokenLayerId}`, {
1201
+ queryParams: { "as-of": asOf },
930
1202
  }),
931
1203
  /**
932
1204
  * Delete a token layer.
933
1205
  * @param {string} tokenLayerId - The token layer ID
934
1206
  */
935
1207
  delete: (tokenLayerId, auditMessage) =>
936
- this._request('DELETE', `/api/v1/token-layers/${tokenLayerId}`, { auditMessage }),
1208
+ this._request("DELETE", `/api/v1/token-layers/${tokenLayerId}`, {
1209
+ auditMessage,
1210
+ }),
937
1211
  /**
938
1212
  * Update a token layer's name.
939
1213
  * @param {string} tokenLayerId - The token layer ID
940
1214
  * @param {string} name - The name
941
1215
  */
942
1216
  update: (tokenLayerId, name, auditMessage) =>
943
- this._request('PATCH', `/api/v1/token-layers/${tokenLayerId}`, { auditMessage,
1217
+ this._request("PATCH", `/api/v1/token-layers/${tokenLayerId}`, {
1218
+ auditMessage,
944
1219
  body: bodyOf({ name }),
945
1220
  }),
946
1221
  };
@@ -952,29 +1227,33 @@ class PlaidClient {
952
1227
  * @param {string} [asOf] - Temporal query timestamp
953
1228
  */
954
1229
  checkLock: (documentId, asOf) =>
955
- this._request('GET', `/api/v1/documents/${documentId}/lock`, {
956
- queryParams: { 'as-of': asOf },
1230
+ this._request("GET", `/api/v1/documents/${documentId}/lock`, {
1231
+ queryParams: { "as-of": asOf },
957
1232
  }),
958
1233
  /**
959
1234
  * Acquire or refresh a document lock
960
1235
  * @param {string} documentId - The document ID
961
1236
  */
962
1237
  acquireLock: (documentId, auditMessage) =>
963
- this._request('POST', `/api/v1/documents/${documentId}/lock`, { auditMessage }),
1238
+ this._request("POST", `/api/v1/documents/${documentId}/lock`, {
1239
+ auditMessage,
1240
+ }),
964
1241
  /**
965
1242
  * Release a document lock
966
1243
  * @param {string} documentId - The document ID
967
1244
  */
968
1245
  releaseLock: (documentId, auditMessage) =>
969
- this._request('DELETE', `/api/v1/documents/${documentId}/lock`, { auditMessage }),
1246
+ this._request("DELETE", `/api/v1/documents/${documentId}/lock`, {
1247
+ auditMessage,
1248
+ }),
970
1249
  /**
971
1250
  * Get media file for a document
972
1251
  * @param {string} documentId - The document ID
973
1252
  * @param {string} [asOf] - Temporal query timestamp
974
1253
  */
975
1254
  getMedia: (documentId, asOf) =>
976
- this._request('GET', `/api/v1/documents/${documentId}/media`, {
977
- queryParams: { 'as-of': asOf },
1255
+ this._request("GET", `/api/v1/documents/${documentId}/media`, {
1256
+ queryParams: { "as-of": asOf },
978
1257
  noBatch: true,
979
1258
  binaryResponse: true,
980
1259
  }),
@@ -985,9 +1264,12 @@ class PlaidClient {
985
1264
  */
986
1265
  uploadMedia: (documentId, file, auditMessage) => {
987
1266
  const fd = new FormData();
988
- fd.append('file', file);
989
- return this._request('PUT', `/api/v1/documents/${documentId}/media`, { auditMessage,
990
- body: fd, formData: true, noBatch: true,
1267
+ fd.append("file", file);
1268
+ return this._request("PUT", `/api/v1/documents/${documentId}/media`, {
1269
+ auditMessage,
1270
+ body: fd,
1271
+ formData: true,
1272
+ noBatch: true,
991
1273
  });
992
1274
  },
993
1275
  /**
@@ -995,7 +1277,8 @@ class PlaidClient {
995
1277
  * @param {string} documentId - The document ID
996
1278
  */
997
1279
  deleteMedia: (documentId, auditMessage) =>
998
- this._request('DELETE', `/api/v1/documents/${documentId}/media`, { auditMessage,
1280
+ this._request("DELETE", `/api/v1/documents/${documentId}/media`, {
1281
+ auditMessage,
999
1282
  noBatch: true,
1000
1283
  }),
1001
1284
  /**
@@ -1004,15 +1287,18 @@ class PlaidClient {
1004
1287
  * @param {any} body - The request body
1005
1288
  */
1006
1289
  setMetadata: (documentId, body, auditMessage) =>
1007
- this._request('PUT', `/api/v1/documents/${documentId}/metadata`, { auditMessage,
1008
- rawBody: body, skipResponseTransform: true,
1290
+ this._request("PUT", `/api/v1/documents/${documentId}/metadata`, {
1291
+ auditMessage,
1292
+ rawBody: body,
1293
+ skipResponseTransform: true,
1009
1294
  }),
1010
1295
  /**
1011
1296
  * Remove all metadata from a document.
1012
1297
  * @param {string} documentId - The document ID
1013
1298
  */
1014
1299
  deleteMetadata: (documentId, auditMessage) =>
1015
- this._request('DELETE', `/api/v1/documents/${documentId}/metadata`, { auditMessage,
1300
+ this._request("DELETE", `/api/v1/documents/${documentId}/metadata`, {
1301
+ auditMessage,
1016
1302
  skipResponseTransform: true,
1017
1303
  }),
1018
1304
  /**
@@ -1021,8 +1307,10 @@ class PlaidClient {
1021
1307
  * @param {any} body - The metadata patch
1022
1308
  */
1023
1309
  patchMetadata: (documentId, body, auditMessage) =>
1024
- this._request('PATCH', `/api/v1/documents/${documentId}/metadata`, { auditMessage,
1025
- rawBody: body, skipResponseTransform: true,
1310
+ this._request("PATCH", `/api/v1/documents/${documentId}/metadata`, {
1311
+ auditMessage,
1312
+ rawBody: body,
1313
+ skipResponseTransform: true,
1026
1314
  }),
1027
1315
  /**
1028
1316
  * Get audit log for a document. Transparently follows pagination cursors
@@ -1040,10 +1328,10 @@ class PlaidClient {
1040
1328
  audit: (documentId, startTime, endTime, asOf, opTypes) =>
1041
1329
  listAll(this, `/api/v1/documents/${documentId}/audit`, {
1042
1330
  query: {
1043
- 'start-time': startTime,
1044
- 'end-time': endTime,
1045
- 'as-of': asOf,
1046
- 'op-types': opTypesParam(opTypes),
1331
+ "start-time": startTime,
1332
+ "end-time": endTime,
1333
+ "as-of": asOf,
1334
+ "op-types": opTypesParam(opTypes),
1047
1335
  },
1048
1336
  }),
1049
1337
  /**
@@ -1062,10 +1350,10 @@ class PlaidClient {
1062
1350
  * @param {string[]|string} [layers] - Layer ids to restrict a body read to
1063
1351
  */
1064
1352
  get: (documentId, includeBody, asOf, layers) =>
1065
- this._request('GET', `/api/v1/documents/${documentId}`, {
1353
+ this._request("GET", `/api/v1/documents/${documentId}`, {
1066
1354
  queryParams: {
1067
- 'include-body': includeBody,
1068
- 'as-of': asOf,
1355
+ "include-body": includeBody,
1356
+ "as-of": asOf,
1069
1357
  layers: layersParam(layers),
1070
1358
  },
1071
1359
  }),
@@ -1074,14 +1362,17 @@ class PlaidClient {
1074
1362
  * @param {string} documentId - The document ID
1075
1363
  */
1076
1364
  delete: (documentId, auditMessage) =>
1077
- this._request('DELETE', `/api/v1/documents/${documentId}`, { auditMessage }),
1365
+ this._request("DELETE", `/api/v1/documents/${documentId}`, {
1366
+ auditMessage,
1367
+ }),
1078
1368
  /**
1079
1369
  * Update a document's name.
1080
1370
  * @param {string} documentId - The document ID
1081
1371
  * @param {string} name - The name
1082
1372
  */
1083
1373
  update: (documentId, name, auditMessage) =>
1084
- this._request('PATCH', `/api/v1/documents/${documentId}`, { auditMessage,
1374
+ this._request("PATCH", `/api/v1/documents/${documentId}`, {
1375
+ auditMessage,
1085
1376
  body: bodyOf({ name }),
1086
1377
  }),
1087
1378
  /**
@@ -1091,8 +1382,9 @@ class PlaidClient {
1091
1382
  * @param {any} [metadata] - Metadata map. Omit to leave unset; pass null to send JSON null.
1092
1383
  */
1093
1384
  create: (projectId, name, metadata, auditMessage) =>
1094
- this._request('POST', '/api/v1/documents', { auditMessage,
1095
- body: bodyOf({ 'project-id': projectId, name, metadata }),
1385
+ this._request("POST", "/api/v1/documents", {
1386
+ auditMessage,
1387
+ body: bodyOf({ "project-id": projectId, name, metadata }),
1096
1388
  }),
1097
1389
  };
1098
1390
 
@@ -1103,28 +1395,36 @@ class PlaidClient {
1103
1395
  * @param {string} userId - The user ID
1104
1396
  */
1105
1397
  addWriter: (id, userId, auditMessage) =>
1106
- this._request('POST', `/api/v1/projects/${id}/writers/${userId}`, { auditMessage }),
1398
+ this._request("POST", `/api/v1/projects/${id}/writers/${userId}`, {
1399
+ auditMessage,
1400
+ }),
1107
1401
  /**
1108
1402
  * Remove a user's writer privileges for this project.
1109
1403
  * @param {string} id - The resource ID
1110
1404
  * @param {string} userId - The user ID
1111
1405
  */
1112
1406
  removeWriter: (id, userId, auditMessage) =>
1113
- this._request('DELETE', `/api/v1/projects/${id}/writers/${userId}`, { auditMessage }),
1407
+ this._request("DELETE", `/api/v1/projects/${id}/writers/${userId}`, {
1408
+ auditMessage,
1409
+ }),
1114
1410
  /**
1115
1411
  * Set a user's access level to read-only for this project.
1116
1412
  * @param {string} id - The resource ID
1117
1413
  * @param {string} userId - The user ID
1118
1414
  */
1119
1415
  addReader: (id, userId, auditMessage) =>
1120
- this._request('POST', `/api/v1/projects/${id}/readers/${userId}`, { auditMessage }),
1416
+ this._request("POST", `/api/v1/projects/${id}/readers/${userId}`, {
1417
+ auditMessage,
1418
+ }),
1121
1419
  /**
1122
1420
  * Remove a user's reader privileges for this project.
1123
1421
  * @param {string} id - The resource ID
1124
1422
  * @param {string} userId - The user ID
1125
1423
  */
1126
1424
  removeReader: (id, userId, auditMessage) =>
1127
- this._request('DELETE', `/api/v1/projects/${id}/readers/${userId}`, { auditMessage }),
1425
+ this._request("DELETE", `/api/v1/projects/${id}/readers/${userId}`, {
1426
+ auditMessage,
1427
+ }),
1128
1428
  /**
1129
1429
  * Set a configuration value for a project in an editor namespace.
1130
1430
  * @param {string} id - The resource ID
@@ -1133,9 +1433,11 @@ class PlaidClient {
1133
1433
  * @param {any} configValue - Configuration value to set
1134
1434
  */
1135
1435
  setConfig: (id, namespace, configKey, configValue, auditMessage) =>
1136
- this._request('PUT', `/api/v1/projects/${id}/config/${namespace}/${configKey}`, { auditMessage,
1137
- rawBody: configValue, skipResponseTransform: true,
1138
- }),
1436
+ this._request(
1437
+ "PUT",
1438
+ `/api/v1/projects/${id}/config/${namespace}/${configKey}`,
1439
+ { auditMessage, rawBody: configValue, skipResponseTransform: true },
1440
+ ),
1139
1441
  /**
1140
1442
  * Remove a configuration value for a project.
1141
1443
  * @param {string} id - The resource ID
@@ -1143,23 +1445,31 @@ class PlaidClient {
1143
1445
  * @param {string} configKey - The config key
1144
1446
  */
1145
1447
  deleteConfig: (id, namespace, configKey, auditMessage) =>
1146
- this._request('DELETE', `/api/v1/projects/${id}/config/${namespace}/${configKey}`, { auditMessage,
1147
- skipResponseTransform: true,
1148
- }),
1448
+ this._request(
1449
+ "DELETE",
1450
+ `/api/v1/projects/${id}/config/${namespace}/${configKey}`,
1451
+ { auditMessage, skipResponseTransform: true },
1452
+ ),
1149
1453
  /**
1150
1454
  * Assign a user as a maintainer for this project.
1151
1455
  * @param {string} id - The resource ID
1152
1456
  * @param {string} userId - The user ID
1153
1457
  */
1154
1458
  addMaintainer: (id, userId, auditMessage) =>
1155
- this._request('POST', `/api/v1/projects/${id}/maintainers/${userId}`, { auditMessage }),
1459
+ this._request("POST", `/api/v1/projects/${id}/maintainers/${userId}`, {
1460
+ auditMessage,
1461
+ }),
1156
1462
  /**
1157
1463
  * Remove a user's maintainer privileges for this project.
1158
1464
  * @param {string} id - The resource ID
1159
1465
  * @param {string} userId - The user ID
1160
1466
  */
1161
1467
  removeMaintainer: (id, userId, auditMessage) =>
1162
- this._request('DELETE', `/api/v1/projects/${id}/maintainers/${userId}`, { auditMessage }),
1468
+ this._request(
1469
+ "DELETE",
1470
+ `/api/v1/projects/${id}/maintainers/${userId}`,
1471
+ { auditMessage },
1472
+ ),
1163
1473
  /**
1164
1474
  * Get audit log for a project. Transparently follows pagination cursors
1165
1475
  * and returns the full flat array.
@@ -1176,10 +1486,10 @@ class PlaidClient {
1176
1486
  audit: (projectId, startTime, endTime, asOf, opTypes) =>
1177
1487
  listAll(this, `/api/v1/projects/${projectId}/audit`, {
1178
1488
  query: {
1179
- 'start-time': startTime,
1180
- 'end-time': endTime,
1181
- 'as-of': asOf,
1182
- 'op-types': opTypesParam(opTypes),
1489
+ "start-time": startTime,
1490
+ "end-time": endTime,
1491
+ "as-of": asOf,
1492
+ "op-types": opTypesParam(opTypes),
1183
1493
  },
1184
1494
  }),
1185
1495
  /**
@@ -1188,14 +1498,18 @@ class PlaidClient {
1188
1498
  * @param {string} vocabId - The vocab layer ID
1189
1499
  */
1190
1500
  linkVocab: (id, vocabId, auditMessage) =>
1191
- this._request('POST', `/api/v1/projects/${id}/vocabs/${vocabId}`, { auditMessage }),
1501
+ this._request("POST", `/api/v1/projects/${id}/vocabs/${vocabId}`, {
1502
+ auditMessage,
1503
+ }),
1192
1504
  /**
1193
1505
  * Unlink a vocabulary from a project.
1194
1506
  * @param {string} id - The resource ID
1195
1507
  * @param {string} vocabId - The vocab layer ID
1196
1508
  */
1197
1509
  unlinkVocab: (id, vocabId, auditMessage) =>
1198
- this._request('DELETE', `/api/v1/projects/${id}/vocabs/${vocabId}`, { auditMessage }),
1510
+ this._request("DELETE", `/api/v1/projects/${id}/vocabs/${vocabId}`, {
1511
+ auditMessage,
1512
+ }),
1199
1513
  /**
1200
1514
  * Get a project by ID. To fetch the project's documents, use
1201
1515
  * listDocuments(id) — the include-documents flag has been removed.
@@ -1203,8 +1517,8 @@ class PlaidClient {
1203
1517
  * @param {string} [asOf] - Temporal query timestamp
1204
1518
  */
1205
1519
  get: (id, asOf) =>
1206
- this._request('GET', `/api/v1/projects/${id}`, {
1207
- queryParams: { 'as-of': asOf },
1520
+ this._request("GET", `/api/v1/projects/${id}`, {
1521
+ queryParams: { "as-of": asOf },
1208
1522
  }),
1209
1523
  /**
1210
1524
  * List all documents in a project. Transparently follows pagination
@@ -1215,8 +1529,7 @@ class PlaidClient {
1215
1529
  * server rejects `?as-of=` on the documents-list route with a 400.
1216
1530
  * @param {string} id - The project ID
1217
1531
  */
1218
- listDocuments: (id) =>
1219
- listAll(this, `/api/v1/projects/${id}/documents`),
1532
+ listDocuments: (id) => listAll(this, `/api/v1/projects/${id}/documents`),
1220
1533
  /**
1221
1534
  * Fetch a single page of a project's documents.
1222
1535
  *
@@ -1256,14 +1569,18 @@ class PlaidClient {
1256
1569
  * @param {number} [options.timeout=0] - Per-request timeout in ms (0/null disables)
1257
1570
  */
1258
1571
  delete: (id, auditMessage, { timeout = 0 } = {}) =>
1259
- this._request('DELETE', `/api/v1/projects/${id}`, { auditMessage, timeout }),
1572
+ this._request("DELETE", `/api/v1/projects/${id}`, {
1573
+ auditMessage,
1574
+ timeout,
1575
+ }),
1260
1576
  /**
1261
1577
  * Update a project's name.
1262
1578
  * @param {string} id - The resource ID
1263
1579
  * @param {string} name - The name
1264
1580
  */
1265
1581
  update: (id, name, auditMessage) =>
1266
- this._request('PATCH', `/api/v1/projects/${id}`, { auditMessage,
1582
+ this._request("PATCH", `/api/v1/projects/${id}`, {
1583
+ auditMessage,
1267
1584
  body: bodyOf({ name }),
1268
1585
  }),
1269
1586
  /**
@@ -1273,7 +1590,7 @@ class PlaidClient {
1273
1590
  * @param {string} [asOf] - Temporal query timestamp
1274
1591
  */
1275
1592
  list: (asOf) =>
1276
- listAll(this, '/api/v1/projects', { query: { 'as-of': asOf } }),
1593
+ listAll(this, "/api/v1/projects", { query: { "as-of": asOf } }),
1277
1594
  /**
1278
1595
  * Fetch a single page of projects.
1279
1596
  * @param {object} [opts]
@@ -1283,7 +1600,11 @@ class PlaidClient {
1283
1600
  * @returns {Promise<{entries: Array, nextCursor: (string|null)}>}
1284
1601
  */
1285
1602
  listPage: ({ limit, cursor, asOf } = {}) =>
1286
- listPage(this, '/api/v1/projects', { limit, cursor, query: { 'as-of': asOf } }),
1603
+ listPage(this, "/api/v1/projects", {
1604
+ limit,
1605
+ cursor,
1606
+ query: { "as-of": asOf },
1607
+ }),
1287
1608
  /**
1288
1609
  * Async-iterate projects page by page; yields each page's entries array.
1289
1610
  * @param {object} [opts]
@@ -1293,13 +1614,17 @@ class PlaidClient {
1293
1614
  * @returns {AsyncGenerator<Array>}
1294
1615
  */
1295
1616
  iterPages: ({ pageSize, asOf } = {}) =>
1296
- iterPages(this, '/api/v1/projects', { pageSize, query: { 'as-of': asOf } }),
1617
+ iterPages(this, "/api/v1/projects", {
1618
+ pageSize,
1619
+ query: { "as-of": asOf },
1620
+ }),
1297
1621
  /**
1298
1622
  * Create a new project. Note: this also registers the user as a maintainer.
1299
1623
  * @param {string} name - The name
1300
1624
  */
1301
1625
  create: (name, auditMessage) =>
1302
- this._request('POST', '/api/v1/projects', { auditMessage,
1626
+ this._request("POST", "/api/v1/projects", {
1627
+ auditMessage,
1303
1628
  body: bodyOf({ name }),
1304
1629
  }),
1305
1630
  };
@@ -1312,10 +1637,18 @@ class PlaidClient {
1312
1637
  * @param {string} configKey - The config key
1313
1638
  * @param {any} configValue - Configuration value to set
1314
1639
  */
1315
- setConfig: (textLayerId, namespace, configKey, configValue, auditMessage) =>
1316
- this._request('PUT', `/api/v1/text-layers/${textLayerId}/config/${namespace}/${configKey}`, { auditMessage,
1317
- rawBody: configValue, skipResponseTransform: true,
1318
- }),
1640
+ setConfig: (
1641
+ textLayerId,
1642
+ namespace,
1643
+ configKey,
1644
+ configValue,
1645
+ auditMessage,
1646
+ ) =>
1647
+ this._request(
1648
+ "PUT",
1649
+ `/api/v1/text-layers/${textLayerId}/config/${namespace}/${configKey}`,
1650
+ { auditMessage, rawBody: configValue, skipResponseTransform: true },
1651
+ ),
1319
1652
  /**
1320
1653
  * Remove a configuration value for a layer.
1321
1654
  * @param {string} textLayerId - The text layer ID
@@ -1323,31 +1656,36 @@ class PlaidClient {
1323
1656
  * @param {string} configKey - The config key
1324
1657
  */
1325
1658
  deleteConfig: (textLayerId, namespace, configKey, auditMessage) =>
1326
- this._request('DELETE', `/api/v1/text-layers/${textLayerId}/config/${namespace}/${configKey}`, { auditMessage,
1327
- skipResponseTransform: true,
1328
- }),
1659
+ this._request(
1660
+ "DELETE",
1661
+ `/api/v1/text-layers/${textLayerId}/config/${namespace}/${configKey}`,
1662
+ { auditMessage, skipResponseTransform: true },
1663
+ ),
1329
1664
  /**
1330
1665
  * Get a text layer by ID.
1331
1666
  * @param {string} textLayerId - The text layer ID
1332
1667
  * @param {string} [asOf] - Temporal query timestamp
1333
1668
  */
1334
1669
  get: (textLayerId, asOf) =>
1335
- this._request('GET', `/api/v1/text-layers/${textLayerId}`, {
1336
- queryParams: { 'as-of': asOf },
1670
+ this._request("GET", `/api/v1/text-layers/${textLayerId}`, {
1671
+ queryParams: { "as-of": asOf },
1337
1672
  }),
1338
1673
  /**
1339
1674
  * Delete a text layer.
1340
1675
  * @param {string} textLayerId - The text layer ID
1341
1676
  */
1342
1677
  delete: (textLayerId, auditMessage) =>
1343
- this._request('DELETE', `/api/v1/text-layers/${textLayerId}`, { auditMessage }),
1678
+ this._request("DELETE", `/api/v1/text-layers/${textLayerId}`, {
1679
+ auditMessage,
1680
+ }),
1344
1681
  /**
1345
1682
  * Update a text layer's name.
1346
1683
  * @param {string} textLayerId - The text layer ID
1347
1684
  * @param {string} name - The name
1348
1685
  */
1349
1686
  update: (textLayerId, name, auditMessage) =>
1350
- this._request('PATCH', `/api/v1/text-layers/${textLayerId}`, { auditMessage,
1687
+ this._request("PATCH", `/api/v1/text-layers/${textLayerId}`, {
1688
+ auditMessage,
1351
1689
  body: bodyOf({ name }),
1352
1690
  }),
1353
1691
  /**
@@ -1356,7 +1694,8 @@ class PlaidClient {
1356
1694
  * @param {string} direction - The direction ("up" or "down")
1357
1695
  */
1358
1696
  shift: (textLayerId, direction, auditMessage) =>
1359
- this._request('POST', `/api/v1/text-layers/${textLayerId}/shift`, { auditMessage,
1697
+ this._request("POST", `/api/v1/text-layers/${textLayerId}/shift`, {
1698
+ auditMessage,
1360
1699
  body: bodyOf({ direction }),
1361
1700
  }),
1362
1701
  /**
@@ -1365,8 +1704,9 @@ class PlaidClient {
1365
1704
  * @param {string} name - The name
1366
1705
  */
1367
1706
  create: (projectId, name, auditMessage) =>
1368
- this._request('POST', '/api/v1/text-layers', { auditMessage,
1369
- body: bodyOf({ 'project-id': projectId, name }),
1707
+ this._request("POST", "/api/v1/text-layers", {
1708
+ auditMessage,
1709
+ body: bodyOf({ "project-id": projectId, name }),
1370
1710
  }),
1371
1711
  };
1372
1712
 
@@ -1377,15 +1717,18 @@ class PlaidClient {
1377
1717
  * @param {any} body - The request body
1378
1718
  */
1379
1719
  setMetadata: (id, body, auditMessage) =>
1380
- this._request('PUT', `/api/v1/vocab-items/${id}/metadata`, { auditMessage,
1381
- rawBody: body, skipResponseTransform: true,
1720
+ this._request("PUT", `/api/v1/vocab-items/${id}/metadata`, {
1721
+ auditMessage,
1722
+ rawBody: body,
1723
+ skipResponseTransform: true,
1382
1724
  }),
1383
1725
  /**
1384
1726
  * Remove all metadata from a vocab item.
1385
1727
  * @param {string} id - The resource ID
1386
1728
  */
1387
1729
  deleteMetadata: (id, auditMessage) =>
1388
- this._request('DELETE', `/api/v1/vocab-items/${id}/metadata`, { auditMessage,
1730
+ this._request("DELETE", `/api/v1/vocab-items/${id}/metadata`, {
1731
+ auditMessage,
1389
1732
  skipResponseTransform: true,
1390
1733
  }),
1391
1734
  /**
@@ -1394,8 +1737,10 @@ class PlaidClient {
1394
1737
  * @param {any} body - The metadata patch
1395
1738
  */
1396
1739
  patchMetadata: (id, body, auditMessage) =>
1397
- this._request('PATCH', `/api/v1/vocab-items/${id}/metadata`, { auditMessage,
1398
- rawBody: body, skipResponseTransform: true,
1740
+ this._request("PATCH", `/api/v1/vocab-items/${id}/metadata`, {
1741
+ auditMessage,
1742
+ rawBody: body,
1743
+ skipResponseTransform: true,
1399
1744
  }),
1400
1745
  /**
1401
1746
  * Create a new vocab item
@@ -1404,8 +1749,9 @@ class PlaidClient {
1404
1749
  * @param {any} [metadata] - Metadata map. Omit to leave unset; pass null to send JSON null.
1405
1750
  */
1406
1751
  create: (vocabLayerId, form, metadata, auditMessage) =>
1407
- this._request('POST', '/api/v1/vocab-items', { auditMessage,
1408
- body: bodyOf({ 'vocab-layer-id': vocabLayerId, form, metadata }),
1752
+ this._request("POST", "/api/v1/vocab-items", {
1753
+ auditMessage,
1754
+ body: bodyOf({ "vocab-layer-id": vocabLayerId, form, metadata }),
1409
1755
  }),
1410
1756
  /**
1411
1757
  * Create multiple vocab items in a single operation. Entries may target
@@ -1413,36 +1759,43 @@ class PlaidClient {
1413
1759
  * @param {Array<{vocabLayerId: string, form: string, metadata?: any}>} body - The vocab items to create
1414
1760
  */
1415
1761
  bulkCreate: (body, auditMessage) =>
1416
- this._request('POST', '/api/v1/vocab-items/bulk', { auditMessage, body }),
1762
+ this._request("POST", "/api/v1/vocab-items/bulk", {
1763
+ auditMessage,
1764
+ body,
1765
+ }),
1417
1766
  /**
1418
1767
  * Delete multiple vocab items in a single operation. Each item's
1419
1768
  * descendant vocab links are deleted too. Provide an array of IDs.
1420
1769
  * @param {string[]} body - The vocab item IDs to delete
1421
1770
  */
1422
1771
  bulkDelete: (body, auditMessage) =>
1423
- this._request('DELETE', '/api/v1/vocab-items/bulk', { auditMessage, body }),
1772
+ this._request("DELETE", "/api/v1/vocab-items/bulk", {
1773
+ auditMessage,
1774
+ body,
1775
+ }),
1424
1776
  /**
1425
1777
  * Get a vocab item by ID
1426
1778
  * @param {string} id - The resource ID
1427
1779
  * @param {string} [asOf] - Temporal query timestamp
1428
1780
  */
1429
1781
  get: (id, asOf) =>
1430
- this._request('GET', `/api/v1/vocab-items/${id}`, {
1431
- queryParams: { 'as-of': asOf },
1782
+ this._request("GET", `/api/v1/vocab-items/${id}`, {
1783
+ queryParams: { "as-of": asOf },
1432
1784
  }),
1433
1785
  /**
1434
1786
  * Delete a vocab item
1435
1787
  * @param {string} id - The resource ID
1436
1788
  */
1437
1789
  delete: (id, auditMessage) =>
1438
- this._request('DELETE', `/api/v1/vocab-items/${id}`, { auditMessage }),
1790
+ this._request("DELETE", `/api/v1/vocab-items/${id}`, { auditMessage }),
1439
1791
  /**
1440
1792
  * Update a vocab item's form
1441
1793
  * @param {string} id - The resource ID
1442
1794
  * @param {string} form - The vocab item form
1443
1795
  */
1444
1796
  update: (id, form, auditMessage) =>
1445
- this._request('PATCH', `/api/v1/vocab-items/${id}`, { auditMessage,
1797
+ this._request("PATCH", `/api/v1/vocab-items/${id}`, {
1798
+ auditMessage,
1446
1799
  body: bodyOf({ form }),
1447
1800
  }),
1448
1801
  };
@@ -1454,17 +1807,20 @@ class PlaidClient {
1454
1807
  * @param {string} direction - The direction ("up" or "down")
1455
1808
  */
1456
1809
  shift: (relationLayerId, direction, auditMessage) =>
1457
- this._request('POST', `/api/v1/relation-layers/${relationLayerId}/shift`, { auditMessage,
1458
- body: bodyOf({ direction }),
1459
- }),
1810
+ this._request(
1811
+ "POST",
1812
+ `/api/v1/relation-layers/${relationLayerId}/shift`,
1813
+ { auditMessage, body: bodyOf({ direction }) },
1814
+ ),
1460
1815
  /**
1461
1816
  * Create a new relation layer.
1462
1817
  * @param {string} spanLayerId - The span layer ID
1463
1818
  * @param {string} name - The name
1464
1819
  */
1465
1820
  create: (spanLayerId, name, auditMessage) =>
1466
- this._request('POST', '/api/v1/relation-layers', { auditMessage,
1467
- body: bodyOf({ 'span-layer-id': spanLayerId, name }),
1821
+ this._request("POST", "/api/v1/relation-layers", {
1822
+ auditMessage,
1823
+ body: bodyOf({ "span-layer-id": spanLayerId, name }),
1468
1824
  }),
1469
1825
  /**
1470
1826
  * Set a configuration value for a layer in an editor namespace.
@@ -1473,10 +1829,18 @@ class PlaidClient {
1473
1829
  * @param {string} configKey - The config key
1474
1830
  * @param {any} configValue - Configuration value to set
1475
1831
  */
1476
- setConfig: (relationLayerId, namespace, configKey, configValue, auditMessage) =>
1477
- this._request('PUT', `/api/v1/relation-layers/${relationLayerId}/config/${namespace}/${configKey}`, { auditMessage,
1478
- rawBody: configValue, skipResponseTransform: true,
1479
- }),
1832
+ setConfig: (
1833
+ relationLayerId,
1834
+ namespace,
1835
+ configKey,
1836
+ configValue,
1837
+ auditMessage,
1838
+ ) =>
1839
+ this._request(
1840
+ "PUT",
1841
+ `/api/v1/relation-layers/${relationLayerId}/config/${namespace}/${configKey}`,
1842
+ { auditMessage, rawBody: configValue, skipResponseTransform: true },
1843
+ ),
1480
1844
  /**
1481
1845
  * Remove a configuration value for a layer.
1482
1846
  * @param {string} relationLayerId - The relation layer ID
@@ -1484,31 +1848,36 @@ class PlaidClient {
1484
1848
  * @param {string} configKey - The config key
1485
1849
  */
1486
1850
  deleteConfig: (relationLayerId, namespace, configKey, auditMessage) =>
1487
- this._request('DELETE', `/api/v1/relation-layers/${relationLayerId}/config/${namespace}/${configKey}`, { auditMessage,
1488
- skipResponseTransform: true,
1489
- }),
1851
+ this._request(
1852
+ "DELETE",
1853
+ `/api/v1/relation-layers/${relationLayerId}/config/${namespace}/${configKey}`,
1854
+ { auditMessage, skipResponseTransform: true },
1855
+ ),
1490
1856
  /**
1491
1857
  * Get a relation layer by ID.
1492
1858
  * @param {string} relationLayerId - The relation layer ID
1493
1859
  * @param {string} [asOf] - Temporal query timestamp
1494
1860
  */
1495
1861
  get: (relationLayerId, asOf) =>
1496
- this._request('GET', `/api/v1/relation-layers/${relationLayerId}`, {
1497
- queryParams: { 'as-of': asOf },
1862
+ this._request("GET", `/api/v1/relation-layers/${relationLayerId}`, {
1863
+ queryParams: { "as-of": asOf },
1498
1864
  }),
1499
1865
  /**
1500
1866
  * Delete a relation layer.
1501
1867
  * @param {string} relationLayerId - The relation layer ID
1502
1868
  */
1503
1869
  delete: (relationLayerId, auditMessage) =>
1504
- this._request('DELETE', `/api/v1/relation-layers/${relationLayerId}`, { auditMessage }),
1870
+ this._request("DELETE", `/api/v1/relation-layers/${relationLayerId}`, {
1871
+ auditMessage,
1872
+ }),
1505
1873
  /**
1506
1874
  * Update a relation layer's name.
1507
1875
  * @param {string} relationLayerId - The relation layer ID
1508
1876
  * @param {string} name - The name
1509
1877
  */
1510
1878
  update: (relationLayerId, name, auditMessage) =>
1511
- this._request('PATCH', `/api/v1/relation-layers/${relationLayerId}`, { auditMessage,
1879
+ this._request("PATCH", `/api/v1/relation-layers/${relationLayerId}`, {
1880
+ auditMessage,
1512
1881
  body: bodyOf({ name }),
1513
1882
  }),
1514
1883
  };
@@ -1532,9 +1901,25 @@ class PlaidClient {
1532
1901
  * @param {number} [precedence] - Ordering precedence
1533
1902
  * @param {any} [metadata] - Metadata map. Omit to leave unset; pass null to send JSON null.
1534
1903
  */
1535
- create: (tokenLayerId, text, begin, end, precedence, metadata, auditMessage) =>
1536
- this._request('POST', '/api/v1/tokens', { auditMessage,
1537
- body: bodyOf({ 'token-layer-id': tokenLayerId, text, begin, end, precedence, metadata }),
1904
+ create: (
1905
+ tokenLayerId,
1906
+ text,
1907
+ begin,
1908
+ end,
1909
+ precedence,
1910
+ metadata,
1911
+ auditMessage,
1912
+ ) =>
1913
+ this._request("POST", "/api/v1/tokens", {
1914
+ auditMessage,
1915
+ body: bodyOf({
1916
+ "token-layer-id": tokenLayerId,
1917
+ text,
1918
+ begin,
1919
+ end,
1920
+ precedence,
1921
+ metadata,
1922
+ }),
1538
1923
  }),
1539
1924
  /**
1540
1925
  * Get a token.
@@ -1542,8 +1927,8 @@ class PlaidClient {
1542
1927
  * @param {string} [asOf] - Temporal query timestamp
1543
1928
  */
1544
1929
  get: (tokenId, asOf) =>
1545
- this._request('GET', `/api/v1/tokens/${tokenId}`, {
1546
- queryParams: { 'as-of': asOf },
1930
+ this._request("GET", `/api/v1/tokens/${tokenId}`, {
1931
+ queryParams: { "as-of": asOf },
1547
1932
  }),
1548
1933
  /**
1549
1934
  * Delete a token and remove it from any spans. If this causes a span to
@@ -1551,7 +1936,7 @@ class PlaidClient {
1551
1936
  * @param {string} tokenId - The token ID
1552
1937
  */
1553
1938
  delete: (tokenId, auditMessage) =>
1554
- this._request('DELETE', `/api/v1/tokens/${tokenId}`, { auditMessage }),
1939
+ this._request("DELETE", `/api/v1/tokens/${tokenId}`, { auditMessage }),
1555
1940
  /**
1556
1941
  * Update a token.
1557
1942
  * @param {string} tokenId - The token ID
@@ -1563,7 +1948,8 @@ class PlaidClient {
1563
1948
  * drops undefined, so the three cases map correctly to the server.
1564
1949
  */
1565
1950
  update: (tokenId, begin, end, precedence, auditMessage) =>
1566
- this._request('PATCH', `/api/v1/tokens/${tokenId}`, { auditMessage,
1951
+ this._request("PATCH", `/api/v1/tokens/${tokenId}`, {
1952
+ auditMessage,
1567
1953
  body: bodyOf({ begin, end, precedence }),
1568
1954
  }),
1569
1955
  /**
@@ -1572,13 +1958,13 @@ class PlaidClient {
1572
1958
  * @returns {Promise<{ids: string[]}>} The created entity IDs, in input order. (bulkDelete resolves to no value.)
1573
1959
  */
1574
1960
  bulkCreate: (body, auditMessage) =>
1575
- this._request('POST', '/api/v1/tokens/bulk', { auditMessage, body }),
1961
+ this._request("POST", "/api/v1/tokens/bulk", { auditMessage, body }),
1576
1962
  /**
1577
1963
  * Delete multiple tokens in a single operation. Provide an array of IDs.
1578
1964
  * @param {Array} body - The request body
1579
1965
  */
1580
1966
  bulkDelete: (body, auditMessage) =>
1581
- this._request('DELETE', '/api/v1/tokens/bulk', { auditMessage, body }),
1967
+ this._request("DELETE", "/api/v1/tokens/bulk", { auditMessage, body }),
1582
1968
  /**
1583
1969
  * Split a token at a Unicode code-point offset. The original token becomes the
1584
1970
  * left half (keeps its ID, spans, vocab-links); the new right token's ID is returned.
@@ -1586,7 +1972,8 @@ class PlaidClient {
1586
1972
  * @param {number} position - Code-point offset to split at (strictly between begin and end)
1587
1973
  */
1588
1974
  split: (tokenId, position, auditMessage) =>
1589
- this._request('POST', `/api/v1/tokens/${tokenId}/split`, { auditMessage,
1975
+ this._request("POST", `/api/v1/tokens/${tokenId}/split`, {
1976
+ auditMessage,
1590
1977
  body: bodyOf({ position }),
1591
1978
  }),
1592
1979
  /**
@@ -1598,8 +1985,9 @@ class PlaidClient {
1598
1985
  * @param {string} otherTokenId - The other token to merge in
1599
1986
  */
1600
1987
  merge: (tokenId, otherTokenId, auditMessage) =>
1601
- this._request('POST', `/api/v1/tokens/${tokenId}/merge`, { auditMessage,
1602
- body: bodyOf({ 'other-token-id': otherTokenId }),
1988
+ this._request("POST", `/api/v1/tokens/${tokenId}/merge`, {
1989
+ auditMessage,
1990
+ body: bodyOf({ "other-token-id": otherTokenId }),
1603
1991
  }),
1604
1992
  /**
1605
1993
  * Shift a token's boundary. On partitioning layers the adjacent token is
@@ -1610,7 +1998,8 @@ class PlaidClient {
1610
1998
  * @param {number} [end] - New end offset, exclusive (Unicode code points)
1611
1999
  */
1612
2000
  shift: (tokenId, begin, end, auditMessage) =>
1613
- this._request('POST', `/api/v1/tokens/${tokenId}/shift`, { auditMessage,
2001
+ this._request("POST", `/api/v1/tokens/${tokenId}/shift`, {
2002
+ auditMessage,
1614
2003
  body: bodyOf({ begin, end }),
1615
2004
  }),
1616
2005
  /**
@@ -1619,15 +2008,18 @@ class PlaidClient {
1619
2008
  * @param {any} body - The request body
1620
2009
  */
1621
2010
  setMetadata: (tokenId, body, auditMessage) =>
1622
- this._request('PUT', `/api/v1/tokens/${tokenId}/metadata`, { auditMessage,
1623
- rawBody: body, skipResponseTransform: true,
2011
+ this._request("PUT", `/api/v1/tokens/${tokenId}/metadata`, {
2012
+ auditMessage,
2013
+ rawBody: body,
2014
+ skipResponseTransform: true,
1624
2015
  }),
1625
2016
  /**
1626
2017
  * Remove all metadata from a token.
1627
2018
  * @param {string} tokenId - The token ID
1628
2019
  */
1629
2020
  deleteMetadata: (tokenId, auditMessage) =>
1630
- this._request('DELETE', `/api/v1/tokens/${tokenId}/metadata`, { auditMessage,
2021
+ this._request("DELETE", `/api/v1/tokens/${tokenId}/metadata`, {
2022
+ auditMessage,
1631
2023
  skipResponseTransform: true,
1632
2024
  }),
1633
2025
  /**
@@ -1636,8 +2028,10 @@ class PlaidClient {
1636
2028
  * @param {any} body - The metadata patch
1637
2029
  */
1638
2030
  patchMetadata: (tokenId, body, auditMessage) =>
1639
- this._request('PATCH', `/api/v1/tokens/${tokenId}/metadata`, { auditMessage,
1640
- rawBody: body, skipResponseTransform: true,
2031
+ this._request("PATCH", `/api/v1/tokens/${tokenId}/metadata`, {
2032
+ auditMessage,
2033
+ rawBody: body,
2034
+ skipResponseTransform: true,
1641
2035
  }),
1642
2036
  };
1643
2037
 
@@ -1666,7 +2060,8 @@ class PlaidClient {
1666
2060
  * @returns {Promise<any>} Response from the send operation
1667
2061
  */
1668
2062
  sendMessage: (projectId, data, auditMessage) =>
1669
- this._request('POST', `/api/v1/projects/${projectId}/message`, { auditMessage,
2063
+ this._request("POST", `/api/v1/projects/${projectId}/message`, {
2064
+ auditMessage,
1670
2065
  rawBody: { body: data },
1671
2066
  }),
1672
2067
 
@@ -1677,8 +2072,7 @@ class PlaidClient {
1677
2072
  * @param {string} projectId - The UUID of the project to query
1678
2073
  * @returns {Promise<Array>} Array of discovered service information
1679
2074
  */
1680
- discoverServices: (projectId) =>
1681
- discoverServices(this, projectId),
2075
+ discoverServices: (projectId) => discoverServices(this, projectId),
1682
2076
 
1683
2077
  /**
1684
2078
  * Forget a previously-seen (offline) service. Maintainer-only; 409 if
@@ -1692,14 +2086,19 @@ class PlaidClient {
1692
2086
 
1693
2087
  /**
1694
2088
  * Register as a service and handle incoming work requests.
2089
+ *
2090
+ * The registration reopens its channel whenever it drops, so a server
2091
+ * restart needs no service restart.
1695
2092
  * @param {string} projectId - The UUID of the project to serve
1696
2093
  * @param {Object} serviceInfo - Service information {serviceId, serviceName, description}
1697
2094
  * @param {function} onServiceRequest - Callback (data, responseHelper)
1698
2095
  * @param {Object} [extras] - Optional additional service metadata
1699
- * @returns {Object} Service registration object with .stop() method
2096
+ * @param {function} [onStatus] - Optional callback (event, projectId, detail) for
2097
+ * connection transitions: 'registered', 'reconnected', 'disconnected'
2098
+ * @returns {Object} Service registration with .stop(), .isRunning(), .isConnected()
1700
2099
  */
1701
- serve: (projectId, serviceInfo, onServiceRequest, extras) =>
1702
- serve(this, projectId, serviceInfo, onServiceRequest, extras),
2100
+ serve: (projectId, serviceInfo, onServiceRequest, extras, onStatus) =>
2101
+ serve(this, projectId, serviceInfo, onServiceRequest, extras, onStatus),
1703
2102
 
1704
2103
  /**
1705
2104
  * Request a service to perform work and await its result.
@@ -1708,10 +2107,11 @@ class PlaidClient {
1708
2107
  * @param {any} data - The request data
1709
2108
  * @param {number} [timeout] - Timeout in milliseconds (default: 10000)
1710
2109
  * @param {function} [onProgress] - Called with each progress payload {percent, message}
2110
+ * @param {AbortSignal} [signal] - Abort to stop waiting; rejects with an AbortError
1711
2111
  * @returns {Promise<any>} Service response
1712
2112
  */
1713
- requestService: (projectId, serviceId, data, timeout, onProgress) =>
1714
- requestService(this, projectId, serviceId, data, timeout, onProgress),
2113
+ requestService: (projectId, serviceId, data, timeout, onProgress, signal) =>
2114
+ requestService(this, projectId, serviceId, data, timeout, onProgress, signal),
1715
2115
  };
1716
2116
 
1717
2117
  /**
@@ -1749,8 +2149,14 @@ class PlaidClient {
1749
2149
  * For 'count': {return: 'count', count}. Entity cells are full entity objects
1750
2150
  * (same shape as the GET endpoints).
1751
2151
  */
2152
+ // bypassBatch: a query is a read. `client.batched()` flips one flag on the
2153
+ // whole client, so a query issued by unrelated code while a batch is open
2154
+ // (the IGT island fetching precedent while a document reconciles) used to
2155
+ // be queued into it: the caller got `{batched: true}` instead of results,
2156
+ // and the server ran the query against the batch's tx Connection, which
2157
+ // 500s and rolls back every write in that batch.
1752
2158
  this.query = (body, auditMessage) =>
1753
- this._request('POST', '/api/v1/query', { auditMessage, body });
2159
+ this._request("POST", "/api/v1/query", { auditMessage, body, bypassBatch: true });
1754
2160
 
1755
2161
  // Logical-operation groups (audit-log grouping). There is no create: a
1756
2162
  // group row is made lazily by the first write carrying `?group-id=`
@@ -1760,15 +2166,130 @@ class PlaidClient {
1760
2166
  * Get a logical-operation group (its label + creator).
1761
2167
  * @param {string} id - The group id
1762
2168
  */
1763
- get: (id) =>
1764
- this._request('GET', `/api/v1/operation-groups/${id}`),
2169
+ get: (id) => this._request("GET", `/api/v1/operation-groups/${id}`),
1765
2170
  /**
1766
2171
  * Relabel a logical-operation group after the fact. Owner or admin only.
1767
2172
  * @param {string} id - The group id
1768
2173
  * @param {string|null} message - The new label
1769
2174
  */
1770
2175
  update: (id, message) =>
1771
- this._request('PATCH', `/api/v1/operation-groups/${id}`, { body: { message } }),
2176
+ this._request("PATCH", `/api/v1/operation-groups/${id}`, {
2177
+ body: { message },
2178
+ }),
2179
+ };
2180
+
2181
+ this.comments = {
2182
+ /**
2183
+ * Post a comment on an entity. Requires write access to the entity's
2184
+ * project; the author is the authenticated caller. Comments are not
2185
+ * audited and do not bump the document version.
2186
+ * @param {'document'|'text'|'token'|'span'|'relation'} entityType - What kind of thing is being commented on
2187
+ * @param {string} entityId - The commented entity's id
2188
+ * @param {string} body - The comment text (1..10000 characters)
2189
+ */
2190
+ create: (entityType, entityId, body) =>
2191
+ this._request("POST", "/api/v1/comments", {
2192
+ body: bodyOf({ "entity-type": entityType, "entity-id": entityId, body }),
2193
+ }),
2194
+ /**
2195
+ * Read one comment.
2196
+ * @param {string} id - The comment id
2197
+ */
2198
+ get: (id) => this._request("GET", `/api/v1/comments/${id}`),
2199
+ /**
2200
+ * Edit a comment's body. Only the comment's AUTHOR may do this - not
2201
+ * maintainers, not admins. Sets `edited` on the comment.
2202
+ * @param {string} id - The comment id
2203
+ * @param {string} body - The replacement text
2204
+ */
2205
+ update: (id, body) =>
2206
+ this._request("PATCH", `/api/v1/comments/${id}`, { body: { body } }),
2207
+ /**
2208
+ * Delete a comment. The author may delete their own; a project
2209
+ * maintainer (or admin) may delete any.
2210
+ * @param {string} id - The comment id
2211
+ */
2212
+ delete: (id) => this._request("DELETE", `/api/v1/comments/${id}`),
2213
+ /**
2214
+ * List comments in a project, oldest first. Transparently follows
2215
+ * pagination cursors and returns the full flat array.
2216
+ * Cannot be used inside a batch (auto-paginates across requests); throws if called while batching - use listPage() for a single page in a batch.
2217
+ * @param {string} projectId - The project to read
2218
+ * @param {object} [filters] - Narrow the scope
2219
+ * @param {string} [filters.documentId] - Every comment anywhere in one document
2220
+ * @param {string} [filters.entityType] - With entityId, one entity's thread
2221
+ * @param {string} [filters.entityId] - With entityType, one entity's thread
2222
+ */
2223
+ list: (projectId, { documentId, entityType, entityId } = {}) =>
2224
+ listAll(this, `/api/v1/projects/${projectId}/comments`, {
2225
+ query: {
2226
+ "document-id": documentId,
2227
+ "entity-type": entityType,
2228
+ "entity-id": entityId,
2229
+ },
2230
+ }),
2231
+ /**
2232
+ * Fetch a single page of a project's comments.
2233
+ * @param {string} projectId - The project to read
2234
+ * @param {object} [opts]
2235
+ * @param {number} [opts.limit] - Page size (1..1000; server default 100)
2236
+ * @param {string} [opts.cursor] - Opaque cursor from a previous page
2237
+ * @param {string} [opts.documentId] - Every comment anywhere in one document
2238
+ * @param {string} [opts.entityType] - With entityId, one entity's thread
2239
+ * @param {string} [opts.entityId] - With entityType, one entity's thread
2240
+ * @returns {Promise<{entries: Array, nextCursor: (string|null)}>}
2241
+ */
2242
+ listPage: (projectId, { limit, cursor, documentId, entityType, entityId } = {}) =>
2243
+ listPage(this, `/api/v1/projects/${projectId}/comments`, {
2244
+ limit,
2245
+ cursor,
2246
+ query: {
2247
+ "document-id": documentId,
2248
+ "entity-type": entityType,
2249
+ "entity-id": entityId,
2250
+ },
2251
+ }),
2252
+ /**
2253
+ * Async-iterate a project's comments page by page; yields each page's entries array.
2254
+ * Cannot be used inside a batch (auto-paginates across requests); throws on first iteration if called while batching - use listPage() for a single page in a batch.
2255
+ * @param {string} projectId - The project to read
2256
+ * @param {object} [opts]
2257
+ * @param {number} [opts.pageSize] - Per-request page size
2258
+ * @param {string} [opts.documentId] - Every comment anywhere in one document
2259
+ * @param {string} [opts.entityType] - With entityId, one entity's thread
2260
+ * @param {string} [opts.entityId] - With entityType, one entity's thread
2261
+ * @returns {AsyncGenerator<Array>}
2262
+ */
2263
+ iterPages: (projectId, { pageSize, documentId, entityType, entityId } = {}) =>
2264
+ iterPages(this, `/api/v1/projects/${projectId}/comments`, {
2265
+ pageSize,
2266
+ query: {
2267
+ "document-id": documentId,
2268
+ "entity-type": entityType,
2269
+ "entity-id": entityId,
2270
+ },
2271
+ }),
2272
+ /**
2273
+ * Comment counts per entity, as an `{entityId: n}` map, over the same
2274
+ * scope and filters as `list`. One cheap request paints a comment
2275
+ * indicator on every annotated item in a document without paging
2276
+ * through the bodies.
2277
+ *
2278
+ * The response is NOT key-transformed: its keys are entity ids, and
2279
+ * camelCasing would mangle the hyphens in a UUID.
2280
+ * @param {string} projectId - The project to read
2281
+ * @param {object} [filters] - Same filters as list()
2282
+ * @returns {Promise<Object<string, number>>}
2283
+ */
2284
+ counts: (projectId, { documentId, entityType, entityId } = {}) =>
2285
+ this._request("GET", `/api/v1/projects/${projectId}/comments/counts`, {
2286
+ queryParams: {
2287
+ "document-id": documentId,
2288
+ "entity-type": entityType,
2289
+ "entity-id": entityId,
2290
+ },
2291
+ skipResponseTransform: true,
2292
+ }),
1772
2293
  };
1773
2294
  }
1774
2295
 
@@ -1876,7 +2397,9 @@ class PlaidClient {
1876
2397
  async withOperation(message, fn) {
1877
2398
  this.beginOperation(message);
1878
2399
  const group = this.operationGroup;
1879
- const setMessage = (msg) => { if (group.depth === 1) group.refined = msg; };
2400
+ const setMessage = (msg) => {
2401
+ if (group.depth === 1) group.refined = msg;
2402
+ };
1880
2403
  try {
1881
2404
  return await fn(setMessage);
1882
2405
  } finally {
@@ -1900,7 +2423,7 @@ class PlaidClient {
1900
2423
  */
1901
2424
  async submitBatch() {
1902
2425
  if (!this.isBatching) {
1903
- throw new Error('No active batch. Call beginBatch() first.');
2426
+ throw new Error("No active batch. Call beginBatch() first.");
1904
2427
  }
1905
2428
 
1906
2429
  if (this.batchOperations.length === 0) {
@@ -1910,50 +2433,66 @@ class PlaidClient {
1910
2433
 
1911
2434
  try {
1912
2435
  let url = `${this.baseUrl}/api/v1/batch`;
1913
- const body = this.batchOperations.map(op => ({
2436
+ const body = this.batchOperations.map((op) => ({
1914
2437
  path: op.path,
1915
2438
  method: op.method.toUpperCase(),
1916
2439
  ...(op.body && { body: op.body }),
1917
2440
  }));
1918
2441
 
1919
2442
  const fetchOptions = {
1920
- method: 'POST',
2443
+ method: "POST",
1921
2444
  headers: {
1922
- 'Authorization': `Bearer ${this.token}`,
1923
- 'Content-Type': 'application/json',
2445
+ Authorization: `Bearer ${this.token}`,
2446
+ "Content-Type": "application/json",
1924
2447
  },
1925
2448
  body: JSON.stringify(body),
1926
2449
  };
1927
- const signal = timeoutSignal(this.timeout);
1928
- if (signal) fetchOptions.signal = signal;
1929
2450
 
1930
2451
  try {
1931
- const response = await fetch(url, fetchOptions);
1932
- if (!response.ok) {
1933
- throw makeHttpError(response, await parseErrorBody(response), url, 'POST');
1934
- }
2452
+ // Retry a 503: the batch is atomic, so a refused one wrote nothing and
2453
+ // repeating it is safe. A fresh timeout signal per attempt — an
2454
+ // AbortSignal.timeout stays aborted once it fires.
2455
+ const response = await retryWhileBusy(async () => {
2456
+ const signal = timeoutSignal(this.batchTimeout);
2457
+ const res = await fetch(
2458
+ url,
2459
+ signal ? { ...fetchOptions, signal } : fetchOptions,
2460
+ );
2461
+ if (!res.ok) {
2462
+ throw makeHttpError(res, await parseErrorBody(res), url, "POST");
2463
+ }
2464
+ return res;
2465
+ });
1935
2466
 
1936
2467
  const results = await response.json();
1937
2468
 
1938
2469
  // Extract document versions from each batch response
1939
2470
  for (const result of results) {
1940
- if (result.headers && result.headers['X-Document-Versions']) {
2471
+ if (result.headers && result.headers["X-Document-Versions"]) {
1941
2472
  try {
1942
- const versionsMap = JSON.parse(result.headers['X-Document-Versions']);
1943
- if (typeof versionsMap === 'object' && versionsMap !== null) {
2473
+ const versionsMap = JSON.parse(
2474
+ result.headers["X-Document-Versions"],
2475
+ );
2476
+ if (typeof versionsMap === "object" && versionsMap !== null) {
1944
2477
  // Clone once per response, then merge — not once per entry.
1945
- this.documentVersions = { ...this.documentVersions, ...versionsMap };
2478
+ this.documentVersions = {
2479
+ ...this.documentVersions,
2480
+ ...versionsMap,
2481
+ };
1946
2482
  }
1947
2483
  } catch (e) {
1948
- console.warn('Failed to parse document versions header from batch response:', e);
2484
+ console.warn(
2485
+ "Failed to parse document versions header from batch response:",
2486
+ e,
2487
+ );
1949
2488
  }
1950
2489
  }
1951
2490
  }
1952
2491
 
1953
- return results.map(result => transformResponse(result));
2492
+ return results.map((result) => transformResponse(result));
1954
2493
  } catch (error) {
1955
2494
  if (error.status) throw error;
1956
- throw makeNetworkError(error, url, 'POST');
2495
+ throw makeNetworkError(error, url, "POST");
1957
2496
  }
1958
2497
  } finally {
1959
2498
  this.isBatching = false;
@@ -2026,7 +2565,7 @@ class PlaidClient {
2026
2565
  * @returns {string}
2027
2566
  */
2028
2567
  static inviteUrl(appUrl, code) {
2029
- return `${appUrl.replace(/#.*$/, '').replace(/\/$/, '')}/#/invite/${encodeURIComponent(code)}`;
2568
+ return `${appUrl.replace(/#.*$/, "").replace(/\/$/, "")}/#/invite/${encodeURIComponent(code)}`;
2030
2569
  }
2031
2570
 
2032
2571
  /**
@@ -2040,63 +2579,90 @@ class PlaidClient {
2040
2579
  * @param {string} baseUrl - The API base URL
2041
2580
  * @param {string} code - The invite code
2042
2581
  * @param {object} [options]
2043
- * @returns {Promise<{kind: string, status: string, expiresAt: string, projectName?: string, projectRole?: string, username?: string, grantAdmin: boolean}>}
2582
+ * @returns {Promise<{kind: string, status: string, expiresAt: string, projectName?: string, projectRole?: string, email?: string, grantAdmin: boolean}>}
2044
2583
  */
2045
2584
  static async lookupInvite(baseUrl, code, options = {}) {
2046
- return anonymousPost(baseUrl, '/api/v1/invite-codes/lookup', { code }, options);
2585
+ return anonymousPost(
2586
+ baseUrl,
2587
+ "/api/v1/invite-codes/lookup",
2588
+ { code },
2589
+ options,
2590
+ );
2047
2591
  }
2048
2592
 
2049
2593
  /**
2050
2594
  * Redeem an invite code, with NO authentication.
2051
2595
  *
2052
- * For a signup invite, pass `username` and `password` to create the account;
2053
- * the invite's grants are applied in the same transaction. For a password
2054
- * reset link, pass `password` only. Resolves to a logged-in client, exactly
2055
- * like login() — the redeemer just chose these credentials, so there is no
2056
- * reason to send them to a login form to retype them.
2596
+ * For a signup invite, pass `email` and `password` to create the account
2597
+ * (and optionally `displayName`); the invite's grants are applied in the
2598
+ * same transaction. For a password reset link, pass `password` only.
2599
+ * Resolves to a logged-in client, exactly like login() — the redeemer just
2600
+ * chose these credentials, so there is no reason to send them to a login
2601
+ * form to retype them.
2057
2602
  * @param {string} baseUrl - The API base URL
2058
2603
  * @param {string} code - The invite code
2059
2604
  * @param {object} credentials
2060
- * @param {string} [credentials.username] - Desired username (signup only)
2605
+ * @param {string} [credentials.email] - The new account's email address,
2606
+ * which becomes its id and login (signup only)
2607
+ * @param {string} [credentials.displayName] - How the new user is shown in
2608
+ * the UI; defaults to the local part of the email (signup only)
2061
2609
  * @param {string} credentials.password - Desired password (min 8 characters)
2062
2610
  * @param {object} [options]
2063
2611
  * @returns {Promise<{client: PlaidClient, userId: string, kind: string}>}
2064
2612
  */
2065
- static async redeemInvite(baseUrl, code, { username, password } = {}, options = {}) {
2613
+ static async redeemInvite(
2614
+ baseUrl,
2615
+ code,
2616
+ { email, password, displayName } = {},
2617
+ options = {},
2618
+ ) {
2066
2619
  const data = await anonymousPost(
2067
- baseUrl, '/api/v1/invite-codes/redeem',
2068
- bodyOf({ code, username, password }), options,
2620
+ baseUrl,
2621
+ "/api/v1/invite-codes/redeem",
2622
+ bodyOf({ code, email, password, "display-name": displayName }),
2623
+ options,
2069
2624
  );
2070
2625
  return {
2071
- client: new PlaidClient(baseUrl.replace(/\/$/, ''), data.token || '', options),
2626
+ client: new PlaidClient(
2627
+ baseUrl.replace(/\/$/, ""),
2628
+ data.token || "",
2629
+ options,
2630
+ ),
2072
2631
  userId: data.userId,
2073
2632
  kind: data.kind,
2074
2633
  };
2075
2634
  }
2076
2635
 
2077
2636
  static async login(baseUrl, userId, password, options = {}) {
2078
- baseUrl = baseUrl.replace(/\/$/, '');
2637
+ baseUrl = baseUrl.replace(/\/$/, "");
2079
2638
  const url = `${baseUrl}/api/v1/login`;
2080
2639
  try {
2081
2640
  const fetchOptions = {
2082
- method: 'POST',
2083
- headers: { 'Content-Type': 'application/json' },
2084
- body: JSON.stringify({ 'user-id': userId, password }),
2641
+ method: "POST",
2642
+ headers: { "Content-Type": "application/json" },
2643
+ body: JSON.stringify({ "user-id": userId, password }),
2085
2644
  };
2086
- const signal = timeoutSignal(options.timeout !== undefined ? options.timeout : DEFAULT_TIMEOUT_MS);
2645
+ const signal = timeoutSignal(
2646
+ options.timeout !== undefined ? options.timeout : DEFAULT_TIMEOUT_MS,
2647
+ );
2087
2648
  if (signal) fetchOptions.signal = signal;
2088
2649
 
2089
2650
  const response = await fetch(url, fetchOptions);
2090
2651
  if (!response.ok) {
2091
- throw makeHttpError(response, await parseErrorBody(response), url, 'POST');
2652
+ throw makeHttpError(
2653
+ response,
2654
+ await parseErrorBody(response),
2655
+ url,
2656
+ "POST",
2657
+ );
2092
2658
  }
2093
2659
 
2094
2660
  const data = await response.json();
2095
- const token = data.token || '';
2661
+ const token = data.token || "";
2096
2662
  return new PlaidClient(baseUrl, token, options);
2097
2663
  } catch (error) {
2098
2664
  if (error.status) throw error;
2099
- throw makeNetworkError(error, url, 'POST');
2665
+ throw makeNetworkError(error, url, "POST");
2100
2666
  }
2101
2667
  }
2102
2668
  }
@@ -2106,8 +2672,21 @@ export { PlaidClient };
2106
2672
 
2107
2673
  // Unicode code-point helpers for text offsets (token begin/end are code-point
2108
2674
  // indices). See ./codepoint.js.
2109
- export { cpLength, cpSlice, cpSlicer, utf16ToCp, cpToUtf16, cpIndexOf } from './codepoint.js';
2110
- export { PLAID_NAMESPACE, ROLE_KEY, ROLES, readRole, findByRole } from './roles.js';
2675
+ export {
2676
+ cpLength,
2677
+ cpSlice,
2678
+ cpSlicer,
2679
+ utf16ToCp,
2680
+ cpToUtf16,
2681
+ cpIndexOf,
2682
+ } from "./codepoint.js";
2683
+ export {
2684
+ PLAID_NAMESPACE,
2685
+ ROLE_KEY,
2686
+ ROLES,
2687
+ readRole,
2688
+ findByRole,
2689
+ } from "./roles.js";
2111
2690
  // Service self-description helpers: filter discovered services by task, read a
2112
2691
  // service's parameter schema/summary, and build/coerce form values. See
2113
2692
  // ./serviceSchema.js.
@@ -2119,7 +2698,7 @@ export {
2119
2698
  getServiceSummary,
2120
2699
  buildDefaultValues,
2121
2700
  coerceParamValues,
2122
- } from './serviceSchema.js';
2701
+ } from "./serviceSchema.js";
2123
2702
  // Provenance: the cross-app convention for machine-provided vs human-labeled
2124
2703
  // information (flat prov/provSource/provConfirmed metadata; absence = human),
2125
2704
  // plus the machine-writer contract. See ./provenance.js and the manual,
@@ -2135,4 +2714,4 @@ export {
2135
2714
  isProtected,
2136
2715
  verifyOnEdit,
2137
2716
  serviceSource,
2138
- } from './provenance.js';
2717
+ } from "./provenance.js";