@larc-iu/plaid-client 0.1.0-alpha.9 → 0.2.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/index.js CHANGED
@@ -11,6 +11,7 @@ import { listAll, listPage, iterPages } from './pagination.js';
11
11
  import { createSSEConnection } from './sse.js';
12
12
  import {
13
13
  discoverServices,
14
+ discardService,
14
15
  serve,
15
16
  requestService,
16
17
  } from './services.js';
@@ -40,6 +41,14 @@ class PlaidClient {
40
41
  this.batchOperations = [];
41
42
  this.documentVersions = {};
42
43
  this.strictModeDocumentId = null;
44
+ // Ambient custom audit-log message applied to write requests; null = use
45
+ // the server's auto-generated description. See setAuditMessage / withAuditMessage.
46
+ this.auditMessage = null;
47
+ // Optional callback fired once (per client) when any request returns HTTP
48
+ // 401 — i.e. the token is missing/expired/invalid. Apps use it to discard
49
+ // the stored token and route back to login. See makeRequest in http.js.
50
+ this.onAuthError = options.onAuthError || null;
51
+ this._authErrorFired = false;
43
52
 
44
53
  // --- API Bundles ---
45
54
 
@@ -50,25 +59,40 @@ class PlaidClient {
50
59
  * @param {Array} tokens - The tokens to link
51
60
  * @param {any} [metadata] - Metadata for the link. Omit to leave unset; pass null to send JSON null.
52
61
  */
53
- create: (vocabItem, tokens, metadata) =>
54
- this._request('POST', '/api/v1/vocab-links', {
62
+ create: (vocabItem, tokens, metadata, auditMessage) =>
63
+ this._request('POST', '/api/v1/vocab-links', { auditMessage,
55
64
  body: bodyOf({ 'vocab-item': vocabItem, tokens, metadata }),
56
65
  }),
66
+ /**
67
+ * Create multiple vocab links in a single operation. Entries may
68
+ * reference different vocab items, but all tokens across the call must
69
+ * belong to one document.
70
+ * @param {Array<{vocabItem: string, tokens: string[], metadata?: any}>} body - The vocab links to create
71
+ * @returns {Promise<{ids: string[]}>} The created entity IDs, in input order. (bulkDelete resolves to no value.)
72
+ */
73
+ bulkCreate: (body, auditMessage) =>
74
+ this._request('POST', '/api/v1/vocab-links/bulk', { auditMessage, body }),
75
+ /**
76
+ * Delete multiple vocab links in a single operation. Provide an array of IDs.
77
+ * @param {string[]} body - The vocab link IDs to delete
78
+ */
79
+ bulkDelete: (body, auditMessage) =>
80
+ this._request('DELETE', '/api/v1/vocab-links/bulk', { auditMessage, body }),
57
81
  /**
58
82
  * Replace all metadata for a vocab link. The entire metadata map is replaced - existing metadata keys not included in the request will be removed.
59
83
  * @param {string} id - The resource ID
60
84
  * @param {any} body - The request body
61
85
  */
62
- setMetadata: (id, body) =>
63
- this._request('PUT', `/api/v1/vocab-links/${id}/metadata`, {
86
+ setMetadata: (id, body, auditMessage) =>
87
+ this._request('PUT', `/api/v1/vocab-links/${id}/metadata`, { auditMessage,
64
88
  rawBody: body, skipResponseTransform: true,
65
89
  }),
66
90
  /**
67
91
  * Remove all metadata from a vocab link.
68
92
  * @param {string} id - The resource ID
69
93
  */
70
- deleteMetadata: (id) =>
71
- this._request('DELETE', `/api/v1/vocab-links/${id}/metadata`, {
94
+ deleteMetadata: (id, auditMessage) =>
95
+ this._request('DELETE', `/api/v1/vocab-links/${id}/metadata`, { auditMessage,
72
96
  skipResponseTransform: true,
73
97
  }),
74
98
  /**
@@ -76,8 +100,8 @@ class PlaidClient {
76
100
  * @param {string} id - The resource ID
77
101
  * @param {any} body - The metadata patch
78
102
  */
79
- patchMetadata: (id, body) =>
80
- this._request('PATCH', `/api/v1/vocab-links/${id}/metadata`, {
103
+ patchMetadata: (id, body, auditMessage) =>
104
+ this._request('PATCH', `/api/v1/vocab-links/${id}/metadata`, { auditMessage,
81
105
  rawBody: body, skipResponseTransform: true,
82
106
  }),
83
107
  /**
@@ -93,8 +117,8 @@ class PlaidClient {
93
117
  * Delete a vocab link
94
118
  * @param {string} id - The resource ID
95
119
  */
96
- delete: (id) =>
97
- this._request('DELETE', `/api/v1/vocab-links/${id}`),
120
+ delete: (id, auditMessage) =>
121
+ this._request('DELETE', `/api/v1/vocab-links/${id}`, { auditMessage }),
98
122
  };
99
123
 
100
124
  this.vocabLayers = {
@@ -112,15 +136,15 @@ class PlaidClient {
112
136
  * Delete a vocab layer.
113
137
  * @param {string} id - The resource ID
114
138
  */
115
- delete: (id) =>
116
- this._request('DELETE', `/api/v1/vocab-layers/${id}`),
139
+ delete: (id, auditMessage) =>
140
+ this._request('DELETE', `/api/v1/vocab-layers/${id}`, { auditMessage }),
117
141
  /**
118
142
  * Update a vocab layer's name.
119
143
  * @param {string} id - The resource ID
120
144
  * @param {string} name - The name
121
145
  */
122
- update: (id, name) =>
123
- this._request('PATCH', `/api/v1/vocab-layers/${id}`, {
146
+ update: (id, name, auditMessage) =>
147
+ this._request('PATCH', `/api/v1/vocab-layers/${id}`, { auditMessage,
124
148
  body: bodyOf({ name }),
125
149
  }),
126
150
  /**
@@ -130,8 +154,8 @@ class PlaidClient {
130
154
  * @param {string} configKey - The config key
131
155
  * @param {any} configValue - Configuration value to set
132
156
  */
133
- setConfig: (id, namespace, configKey, configValue) =>
134
- this._request('PUT', `/api/v1/vocab-layers/${id}/config/${namespace}/${configKey}`, {
157
+ setConfig: (id, namespace, configKey, configValue, auditMessage) =>
158
+ this._request('PUT', `/api/v1/vocab-layers/${id}/config/${namespace}/${configKey}`, { auditMessage,
135
159
  rawBody: configValue, skipResponseTransform: true,
136
160
  }),
137
161
  /**
@@ -140,8 +164,8 @@ class PlaidClient {
140
164
  * @param {string} namespace - The config namespace
141
165
  * @param {string} configKey - The config key
142
166
  */
143
- deleteConfig: (id, namespace, configKey) =>
144
- this._request('DELETE', `/api/v1/vocab-layers/${id}/config/${namespace}/${configKey}`, {
167
+ deleteConfig: (id, namespace, configKey, auditMessage) =>
168
+ this._request('DELETE', `/api/v1/vocab-layers/${id}/config/${namespace}/${configKey}`, { auditMessage,
145
169
  skipResponseTransform: true,
146
170
  }),
147
171
  /**
@@ -176,8 +200,8 @@ class PlaidClient {
176
200
  * Create a new vocab layer. Note: this also registers the user as a maintainer.
177
201
  * @param {string} name - The name
178
202
  */
179
- create: (name) =>
180
- this._request('POST', '/api/v1/vocab-layers', {
203
+ create: (name, auditMessage) =>
204
+ this._request('POST', '/api/v1/vocab-layers', { auditMessage,
181
205
  body: bodyOf({ name }),
182
206
  }),
183
207
  /**
@@ -185,15 +209,15 @@ class PlaidClient {
185
209
  * @param {string} id - The resource ID
186
210
  * @param {string} userId - The user ID
187
211
  */
188
- addMaintainer: (id, userId) =>
189
- this._request('POST', `/api/v1/vocab-layers/${id}/maintainers/${userId}`),
212
+ addMaintainer: (id, userId, auditMessage) =>
213
+ this._request('POST', `/api/v1/vocab-layers/${id}/maintainers/${userId}`, { auditMessage }),
190
214
  /**
191
215
  * Remove a user's maintainer privileges for this vocab layer.
192
216
  * @param {string} id - The resource ID
193
217
  * @param {string} userId - The user ID
194
218
  */
195
- removeMaintainer: (id, userId) =>
196
- this._request('DELETE', `/api/v1/vocab-layers/${id}/maintainers/${userId}`),
219
+ removeMaintainer: (id, userId, auditMessage) =>
220
+ this._request('DELETE', `/api/v1/vocab-layers/${id}/maintainers/${userId}`, { auditMessage }),
197
221
  };
198
222
 
199
223
  this.relations = {
@@ -202,16 +226,16 @@ class PlaidClient {
202
226
  * @param {string} relationId - The relation ID
203
227
  * @param {any} body - The request body
204
228
  */
205
- setMetadata: (relationId, body) =>
206
- this._request('PUT', `/api/v1/relations/${relationId}/metadata`, {
229
+ setMetadata: (relationId, body, auditMessage) =>
230
+ this._request('PUT', `/api/v1/relations/${relationId}/metadata`, { auditMessage,
207
231
  rawBody: body, skipResponseTransform: true,
208
232
  }),
209
233
  /**
210
234
  * Remove all metadata from a relation.
211
235
  * @param {string} relationId - The relation ID
212
236
  */
213
- deleteMetadata: (relationId) =>
214
- this._request('DELETE', `/api/v1/relations/${relationId}/metadata`, {
237
+ deleteMetadata: (relationId, auditMessage) =>
238
+ this._request('DELETE', `/api/v1/relations/${relationId}/metadata`, { auditMessage,
215
239
  skipResponseTransform: true,
216
240
  }),
217
241
  /**
@@ -219,8 +243,8 @@ class PlaidClient {
219
243
  * @param {string} relationId - The relation ID
220
244
  * @param {any} body - The metadata patch
221
245
  */
222
- patchMetadata: (relationId, body) =>
223
- this._request('PATCH', `/api/v1/relations/${relationId}/metadata`, {
246
+ patchMetadata: (relationId, body, auditMessage) =>
247
+ this._request('PATCH', `/api/v1/relations/${relationId}/metadata`, { auditMessage,
224
248
  rawBody: body, skipResponseTransform: true,
225
249
  }),
226
250
  /**
@@ -228,8 +252,8 @@ class PlaidClient {
228
252
  * @param {string} relationId - The relation ID
229
253
  * @param {string} spanId - The span ID
230
254
  */
231
- setTarget: (relationId, spanId) =>
232
- this._request('PUT', `/api/v1/relations/${relationId}/target`, {
255
+ setTarget: (relationId, spanId, auditMessage) =>
256
+ this._request('PUT', `/api/v1/relations/${relationId}/target`, { auditMessage,
233
257
  body: bodyOf({ 'span-id': spanId }),
234
258
  }),
235
259
  /**
@@ -245,15 +269,15 @@ class PlaidClient {
245
269
  * Delete a relation.
246
270
  * @param {string} relationId - The relation ID
247
271
  */
248
- delete: (relationId) =>
249
- this._request('DELETE', `/api/v1/relations/${relationId}`),
272
+ delete: (relationId, auditMessage) =>
273
+ this._request('DELETE', `/api/v1/relations/${relationId}`, { auditMessage }),
250
274
  /**
251
275
  * Update a relation's value.
252
276
  * @param {string} relationId - The relation ID
253
277
  * @param {any} value - The value
254
278
  */
255
- update: (relationId, value) =>
256
- this._request('PATCH', `/api/v1/relations/${relationId}`, {
279
+ update: (relationId, value, auditMessage) =>
280
+ this._request('PATCH', `/api/v1/relations/${relationId}`, { auditMessage,
257
281
  body: bodyOf({ value }),
258
282
  }),
259
283
  /**
@@ -261,8 +285,8 @@ class PlaidClient {
261
285
  * @param {string} relationId - The relation ID
262
286
  * @param {string} spanId - The span ID
263
287
  */
264
- setSource: (relationId, spanId) =>
265
- this._request('PUT', `/api/v1/relations/${relationId}/source`, {
288
+ setSource: (relationId, spanId, auditMessage) =>
289
+ this._request('PUT', `/api/v1/relations/${relationId}/source`, { auditMessage,
266
290
  body: bodyOf({ 'span-id': spanId }),
267
291
  }),
268
292
  /**
@@ -275,22 +299,23 @@ class PlaidClient {
275
299
  * @param {any} value - The value
276
300
  * @param {any} [metadata] - Metadata map. Omit to leave unset; pass null to send JSON null.
277
301
  */
278
- create: (layerId, sourceId, targetId, value, metadata) =>
279
- this._request('POST', '/api/v1/relations', {
302
+ create: (layerId, sourceId, targetId, value, metadata, auditMessage) =>
303
+ this._request('POST', '/api/v1/relations', { auditMessage,
280
304
  body: bodyOf({ 'layer-id': layerId, 'source-id': sourceId, 'target-id': targetId, value, metadata }),
281
305
  }),
282
306
  /**
283
307
  * Create multiple relations in a single operation.
284
308
  * @param {Array} body - The request body
309
+ * @returns {Promise<{ids: string[]}>} The created entity IDs, in input order. (bulkDelete resolves to no value.)
285
310
  */
286
- bulkCreate: (body) =>
287
- this._request('POST', '/api/v1/relations/bulk', { body }),
311
+ bulkCreate: (body, auditMessage) =>
312
+ this._request('POST', '/api/v1/relations/bulk', { auditMessage, body }),
288
313
  /**
289
314
  * Delete multiple relations in a single operation. Provide an array of IDs.
290
315
  * @param {Array} body - The request body
291
316
  */
292
- bulkDelete: (body) =>
293
- this._request('DELETE', '/api/v1/relations/bulk', { body }),
317
+ bulkDelete: (body, auditMessage) =>
318
+ this._request('DELETE', '/api/v1/relations/bulk', { auditMessage, body }),
294
319
  };
295
320
 
296
321
  this.spanLayers = {
@@ -301,8 +326,8 @@ class PlaidClient {
301
326
  * @param {string} configKey - The config key
302
327
  * @param {any} configValue - Configuration value to set
303
328
  */
304
- setConfig: (spanLayerId, namespace, configKey, configValue) =>
305
- this._request('PUT', `/api/v1/span-layers/${spanLayerId}/config/${namespace}/${configKey}`, {
329
+ setConfig: (spanLayerId, namespace, configKey, configValue, auditMessage) =>
330
+ this._request('PUT', `/api/v1/span-layers/${spanLayerId}/config/${namespace}/${configKey}`, { auditMessage,
306
331
  rawBody: configValue, skipResponseTransform: true,
307
332
  }),
308
333
  /**
@@ -311,8 +336,8 @@ class PlaidClient {
311
336
  * @param {string} namespace - The config namespace
312
337
  * @param {string} configKey - The config key
313
338
  */
314
- deleteConfig: (spanLayerId, namespace, configKey) =>
315
- this._request('DELETE', `/api/v1/span-layers/${spanLayerId}/config/${namespace}/${configKey}`, {
339
+ deleteConfig: (spanLayerId, namespace, configKey, auditMessage) =>
340
+ this._request('DELETE', `/api/v1/span-layers/${spanLayerId}/config/${namespace}/${configKey}`, { auditMessage,
316
341
  skipResponseTransform: true,
317
342
  }),
318
343
  /**
@@ -328,15 +353,15 @@ class PlaidClient {
328
353
  * Delete a span layer.
329
354
  * @param {string} spanLayerId - The span layer ID
330
355
  */
331
- delete: (spanLayerId) =>
332
- this._request('DELETE', `/api/v1/span-layers/${spanLayerId}`),
356
+ delete: (spanLayerId, auditMessage) =>
357
+ this._request('DELETE', `/api/v1/span-layers/${spanLayerId}`, { auditMessage }),
333
358
  /**
334
359
  * Update a span layer's name.
335
360
  * @param {string} spanLayerId - The span layer ID
336
361
  * @param {string} name - The name
337
362
  */
338
- update: (spanLayerId, name) =>
339
- this._request('PATCH', `/api/v1/span-layers/${spanLayerId}`, {
363
+ update: (spanLayerId, name, auditMessage) =>
364
+ this._request('PATCH', `/api/v1/span-layers/${spanLayerId}`, { auditMessage,
340
365
  body: bodyOf({ name }),
341
366
  }),
342
367
  /**
@@ -344,8 +369,8 @@ class PlaidClient {
344
369
  * @param {string} tokenLayerId - The token layer ID
345
370
  * @param {string} name - The name
346
371
  */
347
- create: (tokenLayerId, name) =>
348
- this._request('POST', '/api/v1/span-layers', {
372
+ create: (tokenLayerId, name, auditMessage) =>
373
+ this._request('POST', '/api/v1/span-layers', { auditMessage,
349
374
  body: bodyOf({ 'token-layer-id': tokenLayerId, name }),
350
375
  }),
351
376
  /**
@@ -353,8 +378,8 @@ class PlaidClient {
353
378
  * @param {string} spanLayerId - The span layer ID
354
379
  * @param {string} direction - The direction ("up" or "down")
355
380
  */
356
- shift: (spanLayerId, direction) =>
357
- this._request('POST', `/api/v1/span-layers/${spanLayerId}/shift`, {
381
+ shift: (spanLayerId, direction, auditMessage) =>
382
+ this._request('POST', `/api/v1/span-layers/${spanLayerId}/shift`, { auditMessage,
358
383
  body: bodyOf({ direction }),
359
384
  }),
360
385
  };
@@ -365,8 +390,8 @@ class PlaidClient {
365
390
  * @param {string} spanId - The span ID
366
391
  * @param {Array} tokens - The tokens
367
392
  */
368
- setTokens: (spanId, tokens) =>
369
- this._request('PUT', `/api/v1/spans/${spanId}/tokens`, {
393
+ setTokens: (spanId, tokens, auditMessage) =>
394
+ this._request('PUT', `/api/v1/spans/${spanId}/tokens`, { auditMessage,
370
395
  body: bodyOf({ tokens }),
371
396
  }),
372
397
  /**
@@ -377,8 +402,8 @@ class PlaidClient {
377
402
  * @param {any} value - The value
378
403
  * @param {any} [metadata] - Metadata map. Omit to leave unset; pass null to send JSON null.
379
404
  */
380
- create: (spanLayerId, tokens, value, metadata) =>
381
- this._request('POST', '/api/v1/spans', {
405
+ create: (spanLayerId, tokens, value, metadata, auditMessage) =>
406
+ this._request('POST', '/api/v1/spans', { auditMessage,
382
407
  body: bodyOf({ 'span-layer-id': spanLayerId, tokens, value, metadata }),
383
408
  }),
384
409
  /**
@@ -394,44 +419,45 @@ class PlaidClient {
394
419
  * Delete a span.
395
420
  * @param {string} spanId - The span ID
396
421
  */
397
- delete: (spanId) =>
398
- this._request('DELETE', `/api/v1/spans/${spanId}`),
422
+ delete: (spanId, auditMessage) =>
423
+ this._request('DELETE', `/api/v1/spans/${spanId}`, { auditMessage }),
399
424
  /**
400
425
  * Update a span's value.
401
426
  * @param {string} spanId - The span ID
402
427
  * @param {any} value - The value
403
428
  */
404
- update: (spanId, value) =>
405
- this._request('PATCH', `/api/v1/spans/${spanId}`, {
429
+ update: (spanId, value, auditMessage) =>
430
+ this._request('PATCH', `/api/v1/spans/${spanId}`, { auditMessage,
406
431
  body: bodyOf({ value }),
407
432
  }),
408
433
  /**
409
434
  * Create multiple spans in a single operation.
410
435
  * @param {Array} body - The request body
436
+ * @returns {Promise<{ids: string[]}>} The created entity IDs, in input order. (bulkDelete resolves to no value.)
411
437
  */
412
- bulkCreate: (body) =>
413
- this._request('POST', '/api/v1/spans/bulk', { body }),
438
+ bulkCreate: (body, auditMessage) =>
439
+ this._request('POST', '/api/v1/spans/bulk', { auditMessage, body }),
414
440
  /**
415
441
  * Delete multiple spans in a single operation. Provide an array of IDs.
416
442
  * @param {Array} body - The request body
417
443
  */
418
- bulkDelete: (body) =>
419
- this._request('DELETE', '/api/v1/spans/bulk', { body }),
444
+ bulkDelete: (body, auditMessage) =>
445
+ this._request('DELETE', '/api/v1/spans/bulk', { auditMessage, body }),
420
446
  /**
421
447
  * Replace all metadata for a span.
422
448
  * @param {string} spanId - The span ID
423
449
  * @param {any} body - The request body
424
450
  */
425
- setMetadata: (spanId, body) =>
426
- this._request('PUT', `/api/v1/spans/${spanId}/metadata`, {
451
+ setMetadata: (spanId, body, auditMessage) =>
452
+ this._request('PUT', `/api/v1/spans/${spanId}/metadata`, { auditMessage,
427
453
  rawBody: body, skipResponseTransform: true,
428
454
  }),
429
455
  /**
430
456
  * Remove all metadata from a span.
431
457
  * @param {string} spanId - The span ID
432
458
  */
433
- deleteMetadata: (spanId) =>
434
- this._request('DELETE', `/api/v1/spans/${spanId}/metadata`, {
459
+ deleteMetadata: (spanId, auditMessage) =>
460
+ this._request('DELETE', `/api/v1/spans/${spanId}/metadata`, { auditMessage,
435
461
  skipResponseTransform: true,
436
462
  }),
437
463
  /**
@@ -439,8 +465,8 @@ class PlaidClient {
439
465
  * @param {string} spanId - The span ID
440
466
  * @param {any} body - The metadata patch
441
467
  */
442
- patchMetadata: (spanId, body) =>
443
- this._request('PATCH', `/api/v1/spans/${spanId}/metadata`, {
468
+ patchMetadata: (spanId, body, auditMessage) =>
469
+ this._request('PATCH', `/api/v1/spans/${spanId}/metadata`, { auditMessage,
444
470
  rawBody: body, skipResponseTransform: true,
445
471
  }),
446
472
  };
@@ -451,8 +477,8 @@ class PlaidClient {
451
477
  * changes are rolled back.
452
478
  * @param {Array} body - The request body
453
479
  */
454
- submit: (body) =>
455
- this._request('POST', '/api/v1/batch', {
480
+ submit: (body, auditMessage) =>
481
+ this._request('POST', '/api/v1/batch', { auditMessage,
456
482
  body, noBatch: true,
457
483
  }),
458
484
  };
@@ -463,16 +489,16 @@ class PlaidClient {
463
489
  * @param {string} textId - The text ID
464
490
  * @param {any} body - The request body
465
491
  */
466
- setMetadata: (textId, body) =>
467
- this._request('PUT', `/api/v1/texts/${textId}/metadata`, {
492
+ setMetadata: (textId, body, auditMessage) =>
493
+ this._request('PUT', `/api/v1/texts/${textId}/metadata`, { auditMessage,
468
494
  rawBody: body, skipResponseTransform: true,
469
495
  }),
470
496
  /**
471
497
  * Remove all metadata from a text.
472
498
  * @param {string} textId - The text ID
473
499
  */
474
- deleteMetadata: (textId) =>
475
- this._request('DELETE', `/api/v1/texts/${textId}/metadata`, {
500
+ deleteMetadata: (textId, auditMessage) =>
501
+ this._request('DELETE', `/api/v1/texts/${textId}/metadata`, { auditMessage,
476
502
  skipResponseTransform: true,
477
503
  }),
478
504
  /**
@@ -480,8 +506,8 @@ class PlaidClient {
480
506
  * @param {string} textId - The text ID
481
507
  * @param {any} body - The metadata patch
482
508
  */
483
- patchMetadata: (textId, body) =>
484
- this._request('PATCH', `/api/v1/texts/${textId}/metadata`, {
509
+ patchMetadata: (textId, body, auditMessage) =>
510
+ this._request('PATCH', `/api/v1/texts/${textId}/metadata`, { auditMessage,
485
511
  rawBody: body, skipResponseTransform: true,
486
512
  }),
487
513
  /**
@@ -492,8 +518,8 @@ class PlaidClient {
492
518
  * @param {string} body - The request body
493
519
  * @param {any} [metadata] - Metadata map. Omit to leave unset; pass null to send JSON null.
494
520
  */
495
- create: (textLayerId, documentId, body, metadata) =>
496
- this._request('POST', '/api/v1/texts', {
521
+ create: (textLayerId, documentId, body, metadata, auditMessage) =>
522
+ this._request('POST', '/api/v1/texts', { auditMessage,
497
523
  body: bodyOf({ 'text-layer-id': textLayerId, 'document-id': documentId, body, metadata }),
498
524
  }),
499
525
  /**
@@ -509,8 +535,8 @@ class PlaidClient {
509
535
  * Delete a text and all dependent data.
510
536
  * @param {string} textId - The text ID
511
537
  */
512
- delete: (textId) =>
513
- this._request('DELETE', `/api/v1/texts/${textId}`),
538
+ delete: (textId, auditMessage) =>
539
+ this._request('DELETE', `/api/v1/texts/${textId}`, { auditMessage }),
514
540
  /**
515
541
  * Update a text's body. A diff is computed and token indices are updated
516
542
  * so that tokens remain intact. Alternatively, `body` can be a list of
@@ -518,8 +544,8 @@ class PlaidClient {
518
544
  * @param {string} textId - The text ID
519
545
  * @param {any} body - The request body
520
546
  */
521
- update: (textId, body) =>
522
- this._request('PATCH', `/api/v1/texts/${textId}`, {
547
+ update: (textId, body, auditMessage) =>
548
+ this._request('PATCH', `/api/v1/texts/${textId}`, { auditMessage,
523
549
  body: bodyOf({ body }),
524
550
  }),
525
551
  };
@@ -563,8 +589,8 @@ class PlaidClient {
563
589
  * @param {string} password - The password
564
590
  * @param {boolean} isAdmin - Whether the user is an admin
565
591
  */
566
- create: (username, password, isAdmin) =>
567
- this._request('POST', '/api/v1/users', {
592
+ create: (username, password, isAdmin, auditMessage) =>
593
+ this._request('POST', '/api/v1/users', { auditMessage,
568
594
  body: bodyOf({ username, password, 'is-admin': isAdmin }),
569
595
  }),
570
596
  /**
@@ -597,16 +623,16 @@ class PlaidClient {
597
623
  * Reversible via activate(), which restores login only.
598
624
  * @param {string} id - The resource ID
599
625
  */
600
- delete: (id) =>
601
- this._request('DELETE', `/api/v1/users/${id}`),
626
+ delete: (id, auditMessage) =>
627
+ this._request('DELETE', `/api/v1/users/${id}`, { auditMessage }),
602
628
  /**
603
629
  * Reactivate a deactivated user, restoring their ability to log in.
604
630
  * Project memberships, vocab maintainerships, and API tokens removed
605
631
  * at deactivation are NOT restored — re-grant them deliberately.
606
632
  * @param {string} id - The resource ID
607
633
  */
608
- activate: (id) =>
609
- this._request('POST', `/api/v1/users/${id}/activate`),
634
+ activate: (id, auditMessage) =>
635
+ this._request('POST', `/api/v1/users/${id}/activate`, { auditMessage }),
610
636
  /**
611
637
  * Modify a user. Admins may change the username, password, and admin
612
638
  * status of any user. All other users may only modify their own username
@@ -616,8 +642,8 @@ class PlaidClient {
616
642
  * @param {string} [username] - New username
617
643
  * @param {boolean} [isAdmin] - New admin status
618
644
  */
619
- update: (id, password, username, isAdmin) =>
620
- this._request('PATCH', `/api/v1/users/${id}`, {
645
+ update: (id, password, username, isAdmin, auditMessage) =>
646
+ this._request('PATCH', `/api/v1/users/${id}`, { auditMessage,
621
647
  body: bodyOf({ password, username, 'is-admin': isAdmin }),
622
648
  }),
623
649
  };
@@ -661,8 +687,8 @@ class PlaidClient {
661
687
  * @param {string} name - A human label, e.g. "Stanza Parser"
662
688
  * @returns {Promise<{id: string, name: string, token: string}>}
663
689
  */
664
- create: (userId, name) =>
665
- this._request('POST', `/api/v1/users/${userId}/tokens`, {
690
+ create: (userId, name, auditMessage) =>
691
+ this._request('POST', `/api/v1/users/${userId}/tokens`, { auditMessage,
666
692
  body: bodyOf({ name }),
667
693
  }),
668
694
  /**
@@ -670,8 +696,8 @@ class PlaidClient {
670
696
  * @param {string} userId - The user ID who owns the token
671
697
  * @param {string} tokenId - The token ID to revoke
672
698
  */
673
- revoke: (userId, tokenId) =>
674
- this._request('DELETE', `/api/v1/users/${userId}/tokens/${tokenId}`),
699
+ revoke: (userId, tokenId, auditMessage) =>
700
+ this._request('DELETE', `/api/v1/users/${userId}/tokens/${tokenId}`, { auditMessage }),
675
701
  };
676
702
 
677
703
  this.tokenLayers = {
@@ -680,8 +706,8 @@ class PlaidClient {
680
706
  * @param {string} tokenLayerId - The token layer ID
681
707
  * @param {string} direction - The direction ("up" or "down")
682
708
  */
683
- shift: (tokenLayerId, direction) =>
684
- this._request('POST', `/api/v1/token-layers/${tokenLayerId}/shift`, {
709
+ shift: (tokenLayerId, direction, auditMessage) =>
710
+ this._request('POST', `/api/v1/token-layers/${tokenLayerId}/shift`, { auditMessage,
685
711
  body: bodyOf({ direction }),
686
712
  }),
687
713
  /**
@@ -691,8 +717,8 @@ class PlaidClient {
691
717
  * @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.
692
718
  * @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).
693
719
  */
694
- create: (textLayerId, name, overlapMode, parentTokenLayerId) =>
695
- this._request('POST', '/api/v1/token-layers', {
720
+ create: (textLayerId, name, overlapMode, parentTokenLayerId, auditMessage) =>
721
+ this._request('POST', '/api/v1/token-layers', { auditMessage,
696
722
  body: bodyOf({ 'text-layer-id': textLayerId, name, 'overlap-mode': overlapMode, 'parent-token-layer-id': parentTokenLayerId }),
697
723
  }),
698
724
  /**
@@ -702,8 +728,8 @@ class PlaidClient {
702
728
  * @param {string} configKey - The config key
703
729
  * @param {any} configValue - Configuration value to set
704
730
  */
705
- setConfig: (tokenLayerId, namespace, configKey, configValue) =>
706
- this._request('PUT', `/api/v1/token-layers/${tokenLayerId}/config/${namespace}/${configKey}`, {
731
+ setConfig: (tokenLayerId, namespace, configKey, configValue, auditMessage) =>
732
+ this._request('PUT', `/api/v1/token-layers/${tokenLayerId}/config/${namespace}/${configKey}`, { auditMessage,
707
733
  rawBody: configValue, skipResponseTransform: true,
708
734
  }),
709
735
  /**
@@ -712,8 +738,8 @@ class PlaidClient {
712
738
  * @param {string} namespace - The config namespace
713
739
  * @param {string} configKey - The config key
714
740
  */
715
- deleteConfig: (tokenLayerId, namespace, configKey) =>
716
- this._request('DELETE', `/api/v1/token-layers/${tokenLayerId}/config/${namespace}/${configKey}`, {
741
+ deleteConfig: (tokenLayerId, namespace, configKey, auditMessage) =>
742
+ this._request('DELETE', `/api/v1/token-layers/${tokenLayerId}/config/${namespace}/${configKey}`, { auditMessage,
717
743
  skipResponseTransform: true,
718
744
  }),
719
745
  /**
@@ -729,15 +755,15 @@ class PlaidClient {
729
755
  * Delete a token layer.
730
756
  * @param {string} tokenLayerId - The token layer ID
731
757
  */
732
- delete: (tokenLayerId) =>
733
- this._request('DELETE', `/api/v1/token-layers/${tokenLayerId}`),
758
+ delete: (tokenLayerId, auditMessage) =>
759
+ this._request('DELETE', `/api/v1/token-layers/${tokenLayerId}`, { auditMessage }),
734
760
  /**
735
761
  * Update a token layer's name.
736
762
  * @param {string} tokenLayerId - The token layer ID
737
763
  * @param {string} name - The name
738
764
  */
739
- update: (tokenLayerId, name) =>
740
- this._request('PATCH', `/api/v1/token-layers/${tokenLayerId}`, {
765
+ update: (tokenLayerId, name, auditMessage) =>
766
+ this._request('PATCH', `/api/v1/token-layers/${tokenLayerId}`, { auditMessage,
741
767
  body: bodyOf({ name }),
742
768
  }),
743
769
  };
@@ -756,14 +782,14 @@ class PlaidClient {
756
782
  * Acquire or refresh a document lock
757
783
  * @param {string} documentId - The document ID
758
784
  */
759
- acquireLock: (documentId) =>
760
- this._request('POST', `/api/v1/documents/${documentId}/lock`),
785
+ acquireLock: (documentId, auditMessage) =>
786
+ this._request('POST', `/api/v1/documents/${documentId}/lock`, { auditMessage }),
761
787
  /**
762
788
  * Release a document lock
763
789
  * @param {string} documentId - The document ID
764
790
  */
765
- releaseLock: (documentId) =>
766
- this._request('DELETE', `/api/v1/documents/${documentId}/lock`),
791
+ releaseLock: (documentId, auditMessage) =>
792
+ this._request('DELETE', `/api/v1/documents/${documentId}/lock`, { auditMessage }),
767
793
  /**
768
794
  * Get media file for a document
769
795
  * @param {string} documentId - The document ID
@@ -780,10 +806,10 @@ class PlaidClient {
780
806
  * @param {string} documentId - The document ID
781
807
  * @param {File} file - The file to upload
782
808
  */
783
- uploadMedia: (documentId, file) => {
809
+ uploadMedia: (documentId, file, auditMessage) => {
784
810
  const fd = new FormData();
785
811
  fd.append('file', file);
786
- return this._request('PUT', `/api/v1/documents/${documentId}/media`, {
812
+ return this._request('PUT', `/api/v1/documents/${documentId}/media`, { auditMessage,
787
813
  body: fd, formData: true, noBatch: true,
788
814
  });
789
815
  },
@@ -791,8 +817,8 @@ class PlaidClient {
791
817
  * Delete media file for a document
792
818
  * @param {string} documentId - The document ID
793
819
  */
794
- deleteMedia: (documentId) =>
795
- this._request('DELETE', `/api/v1/documents/${documentId}/media`, {
820
+ deleteMedia: (documentId, auditMessage) =>
821
+ this._request('DELETE', `/api/v1/documents/${documentId}/media`, { auditMessage,
796
822
  noBatch: true,
797
823
  }),
798
824
  /**
@@ -800,16 +826,16 @@ class PlaidClient {
800
826
  * @param {string} documentId - The document ID
801
827
  * @param {any} body - The request body
802
828
  */
803
- setMetadata: (documentId, body) =>
804
- this._request('PUT', `/api/v1/documents/${documentId}/metadata`, {
829
+ setMetadata: (documentId, body, auditMessage) =>
830
+ this._request('PUT', `/api/v1/documents/${documentId}/metadata`, { auditMessage,
805
831
  rawBody: body, skipResponseTransform: true,
806
832
  }),
807
833
  /**
808
834
  * Remove all metadata from a document.
809
835
  * @param {string} documentId - The document ID
810
836
  */
811
- deleteMetadata: (documentId) =>
812
- this._request('DELETE', `/api/v1/documents/${documentId}/metadata`, {
837
+ deleteMetadata: (documentId, auditMessage) =>
838
+ this._request('DELETE', `/api/v1/documents/${documentId}/metadata`, { auditMessage,
813
839
  skipResponseTransform: true,
814
840
  }),
815
841
  /**
@@ -817,8 +843,8 @@ class PlaidClient {
817
843
  * @param {string} documentId - The document ID
818
844
  * @param {any} body - The metadata patch
819
845
  */
820
- patchMetadata: (documentId, body) =>
821
- this._request('PATCH', `/api/v1/documents/${documentId}/metadata`, {
846
+ patchMetadata: (documentId, body, auditMessage) =>
847
+ this._request('PATCH', `/api/v1/documents/${documentId}/metadata`, { auditMessage,
822
848
  rawBody: body, skipResponseTransform: true,
823
849
  }),
824
850
  /**
@@ -848,15 +874,15 @@ class PlaidClient {
848
874
  * Delete a document and all data contained.
849
875
  * @param {string} documentId - The document ID
850
876
  */
851
- delete: (documentId) =>
852
- this._request('DELETE', `/api/v1/documents/${documentId}`),
877
+ delete: (documentId, auditMessage) =>
878
+ this._request('DELETE', `/api/v1/documents/${documentId}`, { auditMessage }),
853
879
  /**
854
880
  * Update a document's name.
855
881
  * @param {string} documentId - The document ID
856
882
  * @param {string} name - The name
857
883
  */
858
- update: (documentId, name) =>
859
- this._request('PATCH', `/api/v1/documents/${documentId}`, {
884
+ update: (documentId, name, auditMessage) =>
885
+ this._request('PATCH', `/api/v1/documents/${documentId}`, { auditMessage,
860
886
  body: bodyOf({ name }),
861
887
  }),
862
888
  /**
@@ -865,8 +891,8 @@ class PlaidClient {
865
891
  * @param {string} name - The name
866
892
  * @param {any} [metadata] - Metadata map. Omit to leave unset; pass null to send JSON null.
867
893
  */
868
- create: (projectId, name, metadata) =>
869
- this._request('POST', '/api/v1/documents', {
894
+ create: (projectId, name, metadata, auditMessage) =>
895
+ this._request('POST', '/api/v1/documents', { auditMessage,
870
896
  body: bodyOf({ 'project-id': projectId, name, metadata }),
871
897
  }),
872
898
  };
@@ -877,29 +903,29 @@ class PlaidClient {
877
903
  * @param {string} id - The resource ID
878
904
  * @param {string} userId - The user ID
879
905
  */
880
- addWriter: (id, userId) =>
881
- this._request('POST', `/api/v1/projects/${id}/writers/${userId}`),
906
+ addWriter: (id, userId, auditMessage) =>
907
+ this._request('POST', `/api/v1/projects/${id}/writers/${userId}`, { auditMessage }),
882
908
  /**
883
909
  * Remove a user's writer privileges for this project.
884
910
  * @param {string} id - The resource ID
885
911
  * @param {string} userId - The user ID
886
912
  */
887
- removeWriter: (id, userId) =>
888
- this._request('DELETE', `/api/v1/projects/${id}/writers/${userId}`),
913
+ removeWriter: (id, userId, auditMessage) =>
914
+ this._request('DELETE', `/api/v1/projects/${id}/writers/${userId}`, { auditMessage }),
889
915
  /**
890
916
  * Set a user's access level to read-only for this project.
891
917
  * @param {string} id - The resource ID
892
918
  * @param {string} userId - The user ID
893
919
  */
894
- addReader: (id, userId) =>
895
- this._request('POST', `/api/v1/projects/${id}/readers/${userId}`),
920
+ addReader: (id, userId, auditMessage) =>
921
+ this._request('POST', `/api/v1/projects/${id}/readers/${userId}`, { auditMessage }),
896
922
  /**
897
923
  * Remove a user's reader privileges for this project.
898
924
  * @param {string} id - The resource ID
899
925
  * @param {string} userId - The user ID
900
926
  */
901
- removeReader: (id, userId) =>
902
- this._request('DELETE', `/api/v1/projects/${id}/readers/${userId}`),
927
+ removeReader: (id, userId, auditMessage) =>
928
+ this._request('DELETE', `/api/v1/projects/${id}/readers/${userId}`, { auditMessage }),
903
929
  /**
904
930
  * Set a configuration value for a project in an editor namespace.
905
931
  * @param {string} id - The resource ID
@@ -907,8 +933,8 @@ class PlaidClient {
907
933
  * @param {string} configKey - The config key
908
934
  * @param {any} configValue - Configuration value to set
909
935
  */
910
- setConfig: (id, namespace, configKey, configValue) =>
911
- this._request('PUT', `/api/v1/projects/${id}/config/${namespace}/${configKey}`, {
936
+ setConfig: (id, namespace, configKey, configValue, auditMessage) =>
937
+ this._request('PUT', `/api/v1/projects/${id}/config/${namespace}/${configKey}`, { auditMessage,
912
938
  rawBody: configValue, skipResponseTransform: true,
913
939
  }),
914
940
  /**
@@ -917,8 +943,8 @@ class PlaidClient {
917
943
  * @param {string} namespace - The config namespace
918
944
  * @param {string} configKey - The config key
919
945
  */
920
- deleteConfig: (id, namespace, configKey) =>
921
- this._request('DELETE', `/api/v1/projects/${id}/config/${namespace}/${configKey}`, {
946
+ deleteConfig: (id, namespace, configKey, auditMessage) =>
947
+ this._request('DELETE', `/api/v1/projects/${id}/config/${namespace}/${configKey}`, { auditMessage,
922
948
  skipResponseTransform: true,
923
949
  }),
924
950
  /**
@@ -926,15 +952,15 @@ class PlaidClient {
926
952
  * @param {string} id - The resource ID
927
953
  * @param {string} userId - The user ID
928
954
  */
929
- addMaintainer: (id, userId) =>
930
- this._request('POST', `/api/v1/projects/${id}/maintainers/${userId}`),
955
+ addMaintainer: (id, userId, auditMessage) =>
956
+ this._request('POST', `/api/v1/projects/${id}/maintainers/${userId}`, { auditMessage }),
931
957
  /**
932
958
  * Remove a user's maintainer privileges for this project.
933
959
  * @param {string} id - The resource ID
934
960
  * @param {string} userId - The user ID
935
961
  */
936
- removeMaintainer: (id, userId) =>
937
- this._request('DELETE', `/api/v1/projects/${id}/maintainers/${userId}`),
962
+ removeMaintainer: (id, userId, auditMessage) =>
963
+ this._request('DELETE', `/api/v1/projects/${id}/maintainers/${userId}`, { auditMessage }),
938
964
  /**
939
965
  * Get audit log for a project. Transparently follows pagination cursors
940
966
  * and returns the full flat array.
@@ -953,15 +979,15 @@ class PlaidClient {
953
979
  * @param {string} id - The resource ID
954
980
  * @param {string} vocabId - The vocab layer ID
955
981
  */
956
- linkVocab: (id, vocabId) =>
957
- this._request('POST', `/api/v1/projects/${id}/vocabs/${vocabId}`),
982
+ linkVocab: (id, vocabId, auditMessage) =>
983
+ this._request('POST', `/api/v1/projects/${id}/vocabs/${vocabId}`, { auditMessage }),
958
984
  /**
959
985
  * Unlink a vocabulary from a project.
960
986
  * @param {string} id - The resource ID
961
987
  * @param {string} vocabId - The vocab layer ID
962
988
  */
963
- unlinkVocab: (id, vocabId) =>
964
- this._request('DELETE', `/api/v1/projects/${id}/vocabs/${vocabId}`),
989
+ unlinkVocab: (id, vocabId, auditMessage) =>
990
+ this._request('DELETE', `/api/v1/projects/${id}/vocabs/${vocabId}`, { auditMessage }),
965
991
  /**
966
992
  * Get a project by ID. To fetch the project's documents, use
967
993
  * listDocuments(id) — the include-documents flag has been removed.
@@ -1011,18 +1037,25 @@ class PlaidClient {
1011
1037
  iterDocuments: (id, { pageSize } = {}) =>
1012
1038
  iterPages(this, `/api/v1/projects/${id}/documents`, { pageSize }),
1013
1039
  /**
1014
- * Delete a project.
1040
+ * Delete a project and everything in it. This is irrecoverable.
1041
+ *
1042
+ * For a large project this can take a long time, so the client's
1043
+ * per-request timeout is DISABLED by default. Pass `{ timeout }` to
1044
+ * impose a finite bound.
1015
1045
  * @param {string} id - The resource ID
1046
+ * @param {string} [auditMessage] - Custom audit-log message
1047
+ * @param {object} [options]
1048
+ * @param {number} [options.timeout=0] - Per-request timeout in ms (0/null disables)
1016
1049
  */
1017
- delete: (id) =>
1018
- this._request('DELETE', `/api/v1/projects/${id}`),
1050
+ delete: (id, auditMessage, { timeout = 0 } = {}) =>
1051
+ this._request('DELETE', `/api/v1/projects/${id}`, { auditMessage, timeout }),
1019
1052
  /**
1020
1053
  * Update a project's name.
1021
1054
  * @param {string} id - The resource ID
1022
1055
  * @param {string} name - The name
1023
1056
  */
1024
- update: (id, name) =>
1025
- this._request('PATCH', `/api/v1/projects/${id}`, {
1057
+ update: (id, name, auditMessage) =>
1058
+ this._request('PATCH', `/api/v1/projects/${id}`, { auditMessage,
1026
1059
  body: bodyOf({ name }),
1027
1060
  }),
1028
1061
  /**
@@ -1057,8 +1090,8 @@ class PlaidClient {
1057
1090
  * Create a new project. Note: this also registers the user as a maintainer.
1058
1091
  * @param {string} name - The name
1059
1092
  */
1060
- create: (name) =>
1061
- this._request('POST', '/api/v1/projects', {
1093
+ create: (name, auditMessage) =>
1094
+ this._request('POST', '/api/v1/projects', { auditMessage,
1062
1095
  body: bodyOf({ name }),
1063
1096
  }),
1064
1097
  };
@@ -1071,8 +1104,8 @@ class PlaidClient {
1071
1104
  * @param {string} configKey - The config key
1072
1105
  * @param {any} configValue - Configuration value to set
1073
1106
  */
1074
- setConfig: (textLayerId, namespace, configKey, configValue) =>
1075
- this._request('PUT', `/api/v1/text-layers/${textLayerId}/config/${namespace}/${configKey}`, {
1107
+ setConfig: (textLayerId, namespace, configKey, configValue, auditMessage) =>
1108
+ this._request('PUT', `/api/v1/text-layers/${textLayerId}/config/${namespace}/${configKey}`, { auditMessage,
1076
1109
  rawBody: configValue, skipResponseTransform: true,
1077
1110
  }),
1078
1111
  /**
@@ -1081,8 +1114,8 @@ class PlaidClient {
1081
1114
  * @param {string} namespace - The config namespace
1082
1115
  * @param {string} configKey - The config key
1083
1116
  */
1084
- deleteConfig: (textLayerId, namespace, configKey) =>
1085
- this._request('DELETE', `/api/v1/text-layers/${textLayerId}/config/${namespace}/${configKey}`, {
1117
+ deleteConfig: (textLayerId, namespace, configKey, auditMessage) =>
1118
+ this._request('DELETE', `/api/v1/text-layers/${textLayerId}/config/${namespace}/${configKey}`, { auditMessage,
1086
1119
  skipResponseTransform: true,
1087
1120
  }),
1088
1121
  /**
@@ -1098,15 +1131,15 @@ class PlaidClient {
1098
1131
  * Delete a text layer.
1099
1132
  * @param {string} textLayerId - The text layer ID
1100
1133
  */
1101
- delete: (textLayerId) =>
1102
- this._request('DELETE', `/api/v1/text-layers/${textLayerId}`),
1134
+ delete: (textLayerId, auditMessage) =>
1135
+ this._request('DELETE', `/api/v1/text-layers/${textLayerId}`, { auditMessage }),
1103
1136
  /**
1104
1137
  * Update a text layer's name.
1105
1138
  * @param {string} textLayerId - The text layer ID
1106
1139
  * @param {string} name - The name
1107
1140
  */
1108
- update: (textLayerId, name) =>
1109
- this._request('PATCH', `/api/v1/text-layers/${textLayerId}`, {
1141
+ update: (textLayerId, name, auditMessage) =>
1142
+ this._request('PATCH', `/api/v1/text-layers/${textLayerId}`, { auditMessage,
1110
1143
  body: bodyOf({ name }),
1111
1144
  }),
1112
1145
  /**
@@ -1114,8 +1147,8 @@ class PlaidClient {
1114
1147
  * @param {string} textLayerId - The text layer ID
1115
1148
  * @param {string} direction - The direction ("up" or "down")
1116
1149
  */
1117
- shift: (textLayerId, direction) =>
1118
- this._request('POST', `/api/v1/text-layers/${textLayerId}/shift`, {
1150
+ shift: (textLayerId, direction, auditMessage) =>
1151
+ this._request('POST', `/api/v1/text-layers/${textLayerId}/shift`, { auditMessage,
1119
1152
  body: bodyOf({ direction }),
1120
1153
  }),
1121
1154
  /**
@@ -1123,8 +1156,8 @@ class PlaidClient {
1123
1156
  * @param {string} projectId - The project ID
1124
1157
  * @param {string} name - The name
1125
1158
  */
1126
- create: (projectId, name) =>
1127
- this._request('POST', '/api/v1/text-layers', {
1159
+ create: (projectId, name, auditMessage) =>
1160
+ this._request('POST', '/api/v1/text-layers', { auditMessage,
1128
1161
  body: bodyOf({ 'project-id': projectId, name }),
1129
1162
  }),
1130
1163
  };
@@ -1135,16 +1168,16 @@ class PlaidClient {
1135
1168
  * @param {string} id - The resource ID
1136
1169
  * @param {any} body - The request body
1137
1170
  */
1138
- setMetadata: (id, body) =>
1139
- this._request('PUT', `/api/v1/vocab-items/${id}/metadata`, {
1171
+ setMetadata: (id, body, auditMessage) =>
1172
+ this._request('PUT', `/api/v1/vocab-items/${id}/metadata`, { auditMessage,
1140
1173
  rawBody: body, skipResponseTransform: true,
1141
1174
  }),
1142
1175
  /**
1143
1176
  * Remove all metadata from a vocab item.
1144
1177
  * @param {string} id - The resource ID
1145
1178
  */
1146
- deleteMetadata: (id) =>
1147
- this._request('DELETE', `/api/v1/vocab-items/${id}/metadata`, {
1179
+ deleteMetadata: (id, auditMessage) =>
1180
+ this._request('DELETE', `/api/v1/vocab-items/${id}/metadata`, { auditMessage,
1148
1181
  skipResponseTransform: true,
1149
1182
  }),
1150
1183
  /**
@@ -1152,8 +1185,8 @@ class PlaidClient {
1152
1185
  * @param {string} id - The resource ID
1153
1186
  * @param {any} body - The metadata patch
1154
1187
  */
1155
- patchMetadata: (id, body) =>
1156
- this._request('PATCH', `/api/v1/vocab-items/${id}/metadata`, {
1188
+ patchMetadata: (id, body, auditMessage) =>
1189
+ this._request('PATCH', `/api/v1/vocab-items/${id}/metadata`, { auditMessage,
1157
1190
  rawBody: body, skipResponseTransform: true,
1158
1191
  }),
1159
1192
  /**
@@ -1162,10 +1195,24 @@ class PlaidClient {
1162
1195
  * @param {string} form - The vocab item form
1163
1196
  * @param {any} [metadata] - Metadata map. Omit to leave unset; pass null to send JSON null.
1164
1197
  */
1165
- create: (vocabLayerId, form, metadata) =>
1166
- this._request('POST', '/api/v1/vocab-items', {
1198
+ create: (vocabLayerId, form, metadata, auditMessage) =>
1199
+ this._request('POST', '/api/v1/vocab-items', { auditMessage,
1167
1200
  body: bodyOf({ 'vocab-layer-id': vocabLayerId, form, metadata }),
1168
1201
  }),
1202
+ /**
1203
+ * Create multiple vocab items in a single operation. Entries may target
1204
+ * different vocab layers; the user must have write access to each.
1205
+ * @param {Array<{vocabLayerId: string, form: string, metadata?: any}>} body - The vocab items to create
1206
+ */
1207
+ bulkCreate: (body, auditMessage) =>
1208
+ this._request('POST', '/api/v1/vocab-items/bulk', { auditMessage, body }),
1209
+ /**
1210
+ * Delete multiple vocab items in a single operation. Each item's
1211
+ * descendant vocab links are deleted too. Provide an array of IDs.
1212
+ * @param {string[]} body - The vocab item IDs to delete
1213
+ */
1214
+ bulkDelete: (body, auditMessage) =>
1215
+ this._request('DELETE', '/api/v1/vocab-items/bulk', { auditMessage, body }),
1169
1216
  /**
1170
1217
  * Get a vocab item by ID
1171
1218
  * @param {string} id - The resource ID
@@ -1179,15 +1226,15 @@ class PlaidClient {
1179
1226
  * Delete a vocab item
1180
1227
  * @param {string} id - The resource ID
1181
1228
  */
1182
- delete: (id) =>
1183
- this._request('DELETE', `/api/v1/vocab-items/${id}`),
1229
+ delete: (id, auditMessage) =>
1230
+ this._request('DELETE', `/api/v1/vocab-items/${id}`, { auditMessage }),
1184
1231
  /**
1185
1232
  * Update a vocab item's form
1186
1233
  * @param {string} id - The resource ID
1187
1234
  * @param {string} form - The vocab item form
1188
1235
  */
1189
- update: (id, form) =>
1190
- this._request('PATCH', `/api/v1/vocab-items/${id}`, {
1236
+ update: (id, form, auditMessage) =>
1237
+ this._request('PATCH', `/api/v1/vocab-items/${id}`, { auditMessage,
1191
1238
  body: bodyOf({ form }),
1192
1239
  }),
1193
1240
  };
@@ -1198,8 +1245,8 @@ class PlaidClient {
1198
1245
  * @param {string} relationLayerId - The relation layer ID
1199
1246
  * @param {string} direction - The direction ("up" or "down")
1200
1247
  */
1201
- shift: (relationLayerId, direction) =>
1202
- this._request('POST', `/api/v1/relation-layers/${relationLayerId}/shift`, {
1248
+ shift: (relationLayerId, direction, auditMessage) =>
1249
+ this._request('POST', `/api/v1/relation-layers/${relationLayerId}/shift`, { auditMessage,
1203
1250
  body: bodyOf({ direction }),
1204
1251
  }),
1205
1252
  /**
@@ -1207,8 +1254,8 @@ class PlaidClient {
1207
1254
  * @param {string} spanLayerId - The span layer ID
1208
1255
  * @param {string} name - The name
1209
1256
  */
1210
- create: (spanLayerId, name) =>
1211
- this._request('POST', '/api/v1/relation-layers', {
1257
+ create: (spanLayerId, name, auditMessage) =>
1258
+ this._request('POST', '/api/v1/relation-layers', { auditMessage,
1212
1259
  body: bodyOf({ 'span-layer-id': spanLayerId, name }),
1213
1260
  }),
1214
1261
  /**
@@ -1218,8 +1265,8 @@ class PlaidClient {
1218
1265
  * @param {string} configKey - The config key
1219
1266
  * @param {any} configValue - Configuration value to set
1220
1267
  */
1221
- setConfig: (relationLayerId, namespace, configKey, configValue) =>
1222
- this._request('PUT', `/api/v1/relation-layers/${relationLayerId}/config/${namespace}/${configKey}`, {
1268
+ setConfig: (relationLayerId, namespace, configKey, configValue, auditMessage) =>
1269
+ this._request('PUT', `/api/v1/relation-layers/${relationLayerId}/config/${namespace}/${configKey}`, { auditMessage,
1223
1270
  rawBody: configValue, skipResponseTransform: true,
1224
1271
  }),
1225
1272
  /**
@@ -1228,8 +1275,8 @@ class PlaidClient {
1228
1275
  * @param {string} namespace - The config namespace
1229
1276
  * @param {string} configKey - The config key
1230
1277
  */
1231
- deleteConfig: (relationLayerId, namespace, configKey) =>
1232
- this._request('DELETE', `/api/v1/relation-layers/${relationLayerId}/config/${namespace}/${configKey}`, {
1278
+ deleteConfig: (relationLayerId, namespace, configKey, auditMessage) =>
1279
+ this._request('DELETE', `/api/v1/relation-layers/${relationLayerId}/config/${namespace}/${configKey}`, { auditMessage,
1233
1280
  skipResponseTransform: true,
1234
1281
  }),
1235
1282
  /**
@@ -1245,15 +1292,15 @@ class PlaidClient {
1245
1292
  * Delete a relation layer.
1246
1293
  * @param {string} relationLayerId - The relation layer ID
1247
1294
  */
1248
- delete: (relationLayerId) =>
1249
- this._request('DELETE', `/api/v1/relation-layers/${relationLayerId}`),
1295
+ delete: (relationLayerId, auditMessage) =>
1296
+ this._request('DELETE', `/api/v1/relation-layers/${relationLayerId}`, { auditMessage }),
1250
1297
  /**
1251
1298
  * Update a relation layer's name.
1252
1299
  * @param {string} relationLayerId - The relation layer ID
1253
1300
  * @param {string} name - The name
1254
1301
  */
1255
- update: (relationLayerId, name) =>
1256
- this._request('PATCH', `/api/v1/relation-layers/${relationLayerId}`, {
1302
+ update: (relationLayerId, name, auditMessage) =>
1303
+ this._request('PATCH', `/api/v1/relation-layers/${relationLayerId}`, { auditMessage,
1257
1304
  body: bodyOf({ name }),
1258
1305
  }),
1259
1306
  };
@@ -1277,8 +1324,8 @@ class PlaidClient {
1277
1324
  * @param {number} [precedence] - Ordering precedence
1278
1325
  * @param {any} [metadata] - Metadata map. Omit to leave unset; pass null to send JSON null.
1279
1326
  */
1280
- create: (tokenLayerId, text, begin, end, precedence, metadata) =>
1281
- this._request('POST', '/api/v1/tokens', {
1327
+ create: (tokenLayerId, text, begin, end, precedence, metadata, auditMessage) =>
1328
+ this._request('POST', '/api/v1/tokens', { auditMessage,
1282
1329
  body: bodyOf({ 'token-layer-id': tokenLayerId, text, begin, end, precedence, metadata }),
1283
1330
  }),
1284
1331
  /**
@@ -1295,8 +1342,8 @@ class PlaidClient {
1295
1342
  * have no remaining tokens, the span will also be deleted.
1296
1343
  * @param {string} tokenId - The token ID
1297
1344
  */
1298
- delete: (tokenId) =>
1299
- this._request('DELETE', `/api/v1/tokens/${tokenId}`),
1345
+ delete: (tokenId, auditMessage) =>
1346
+ this._request('DELETE', `/api/v1/tokens/${tokenId}`, { auditMessage }),
1300
1347
  /**
1301
1348
  * Update a token.
1302
1349
  * @param {string} tokenId - The token ID
@@ -1307,30 +1354,31 @@ class PlaidClient {
1307
1354
  * CLEAR it (revert to no explicit ordering). bodyOf keeps null but
1308
1355
  * drops undefined, so the three cases map correctly to the server.
1309
1356
  */
1310
- update: (tokenId, begin, end, precedence) =>
1311
- this._request('PATCH', `/api/v1/tokens/${tokenId}`, {
1357
+ update: (tokenId, begin, end, precedence, auditMessage) =>
1358
+ this._request('PATCH', `/api/v1/tokens/${tokenId}`, { auditMessage,
1312
1359
  body: bodyOf({ begin, end, precedence }),
1313
1360
  }),
1314
1361
  /**
1315
1362
  * Create multiple tokens in a single operation.
1316
1363
  * @param {Array} body - The request body
1364
+ * @returns {Promise<{ids: string[]}>} The created entity IDs, in input order. (bulkDelete resolves to no value.)
1317
1365
  */
1318
- bulkCreate: (body) =>
1319
- this._request('POST', '/api/v1/tokens/bulk', { body }),
1366
+ bulkCreate: (body, auditMessage) =>
1367
+ this._request('POST', '/api/v1/tokens/bulk', { auditMessage, body }),
1320
1368
  /**
1321
1369
  * Delete multiple tokens in a single operation. Provide an array of IDs.
1322
1370
  * @param {Array} body - The request body
1323
1371
  */
1324
- bulkDelete: (body) =>
1325
- this._request('DELETE', '/api/v1/tokens/bulk', { body }),
1372
+ bulkDelete: (body, auditMessage) =>
1373
+ this._request('DELETE', '/api/v1/tokens/bulk', { auditMessage, body }),
1326
1374
  /**
1327
1375
  * Split a token at a Unicode code-point offset. The original token becomes the
1328
1376
  * left half (keeps its ID, spans, vocab-links); the new right token's ID is returned.
1329
1377
  * @param {string} tokenId - The token ID
1330
1378
  * @param {number} position - Code-point offset to split at (strictly between begin and end)
1331
1379
  */
1332
- split: (tokenId, position) =>
1333
- this._request('POST', `/api/v1/tokens/${tokenId}/split`, {
1380
+ split: (tokenId, position, auditMessage) =>
1381
+ this._request('POST', `/api/v1/tokens/${tokenId}/split`, { auditMessage,
1334
1382
  body: bodyOf({ position }),
1335
1383
  }),
1336
1384
  /**
@@ -1341,8 +1389,8 @@ class PlaidClient {
1341
1389
  * @param {string} tokenId - The anchor token ID
1342
1390
  * @param {string} otherTokenId - The other token to merge in
1343
1391
  */
1344
- merge: (tokenId, otherTokenId) =>
1345
- this._request('POST', `/api/v1/tokens/${tokenId}/merge`, {
1392
+ merge: (tokenId, otherTokenId, auditMessage) =>
1393
+ this._request('POST', `/api/v1/tokens/${tokenId}/merge`, { auditMessage,
1346
1394
  body: bodyOf({ 'other-token-id': otherTokenId }),
1347
1395
  }),
1348
1396
  /**
@@ -1353,8 +1401,8 @@ class PlaidClient {
1353
1401
  * @param {number} [begin] - New start offset, inclusive (Unicode code points)
1354
1402
  * @param {number} [end] - New end offset, exclusive (Unicode code points)
1355
1403
  */
1356
- shift: (tokenId, begin, end) =>
1357
- this._request('POST', `/api/v1/tokens/${tokenId}/shift`, {
1404
+ shift: (tokenId, begin, end, auditMessage) =>
1405
+ this._request('POST', `/api/v1/tokens/${tokenId}/shift`, { auditMessage,
1358
1406
  body: bodyOf({ begin, end }),
1359
1407
  }),
1360
1408
  /**
@@ -1362,16 +1410,16 @@ class PlaidClient {
1362
1410
  * @param {string} tokenId - The token ID
1363
1411
  * @param {any} body - The request body
1364
1412
  */
1365
- setMetadata: (tokenId, body) =>
1366
- this._request('PUT', `/api/v1/tokens/${tokenId}/metadata`, {
1413
+ setMetadata: (tokenId, body, auditMessage) =>
1414
+ this._request('PUT', `/api/v1/tokens/${tokenId}/metadata`, { auditMessage,
1367
1415
  rawBody: body, skipResponseTransform: true,
1368
1416
  }),
1369
1417
  /**
1370
1418
  * Remove all metadata from a token.
1371
1419
  * @param {string} tokenId - The token ID
1372
1420
  */
1373
- deleteMetadata: (tokenId) =>
1374
- this._request('DELETE', `/api/v1/tokens/${tokenId}/metadata`, {
1421
+ deleteMetadata: (tokenId, auditMessage) =>
1422
+ this._request('DELETE', `/api/v1/tokens/${tokenId}/metadata`, { auditMessage,
1375
1423
  skipResponseTransform: true,
1376
1424
  }),
1377
1425
  /**
@@ -1379,8 +1427,8 @@ class PlaidClient {
1379
1427
  * @param {string} tokenId - The token ID
1380
1428
  * @param {any} body - The metadata patch
1381
1429
  */
1382
- patchMetadata: (tokenId, body) =>
1383
- this._request('PATCH', `/api/v1/tokens/${tokenId}/metadata`, {
1430
+ patchMetadata: (tokenId, body, auditMessage) =>
1431
+ this._request('PATCH', `/api/v1/tokens/${tokenId}/metadata`, { auditMessage,
1384
1432
  rawBody: body, skipResponseTransform: true,
1385
1433
  }),
1386
1434
  };
@@ -1402,19 +1450,30 @@ class PlaidClient {
1402
1450
  * @param {any} data - The message data to send
1403
1451
  * @returns {Promise<any>} Response from the send operation
1404
1452
  */
1405
- sendMessage: (projectId, data) =>
1406
- this._request('POST', `/api/v1/projects/${projectId}/message`, {
1453
+ sendMessage: (projectId, data, auditMessage) =>
1454
+ this._request('POST', `/api/v1/projects/${projectId}/message`, { auditMessage,
1407
1455
  body: { body: data },
1408
1456
  }),
1409
1457
 
1410
1458
  /**
1411
- * Discover the services currently connected to a project (synchronous GET).
1459
+ * Discover the services seen on a project (synchronous GET). Currently
1460
+ * connected services carry `online: true`; previously-seen offline ones
1461
+ * carry `online: false` plus a `lastSeenAt` stamp.
1412
1462
  * @param {string} projectId - The UUID of the project to query
1413
- * @param {number} [timeout] - Ignored; kept for back-compat
1414
1463
  * @returns {Promise<Array>} Array of discovered service information
1415
1464
  */
1416
- discoverServices: (projectId, timeout) =>
1417
- discoverServices(this, projectId, timeout),
1465
+ discoverServices: (projectId) =>
1466
+ discoverServices(this, projectId),
1467
+
1468
+ /**
1469
+ * Forget a previously-seen (offline) service. Maintainer-only; 409 if
1470
+ * the service is currently connected.
1471
+ * @param {string} projectId - The UUID of the project
1472
+ * @param {string} serviceId - The ID of the service to forget
1473
+ * @returns {Promise<void>}
1474
+ */
1475
+ discardService: (projectId, serviceId) =>
1476
+ discardService(this, projectId, serviceId),
1418
1477
 
1419
1478
  /**
1420
1479
  * Register as a service and handle incoming work requests.
@@ -1475,8 +1534,8 @@ class PlaidClient {
1475
1534
  * For 'count': {return: 'count', count}. Entity cells are full entity objects
1476
1535
  * (same shape as the GET endpoints).
1477
1536
  */
1478
- this.query = (body) =>
1479
- this._request('POST', '/api/v1/query', { body });
1537
+ this.query = (body, auditMessage) =>
1538
+ this._request('POST', '/api/v1/query', { auditMessage, body });
1480
1539
  }
1481
1540
 
1482
1541
  // --- Core methods ---
@@ -1499,10 +1558,62 @@ class PlaidClient {
1499
1558
  this.strictModeDocumentId = null;
1500
1559
  }
1501
1560
 
1561
+ /**
1562
+ * Set a custom audit-log message applied to every subsequent write request,
1563
+ * OVERRIDING the server's auto-generated description (e.g. "Patch metadata
1564
+ * on span X"). The message may template the endpoint's own path/query/body
1565
+ * params with `{param}` placeholders, resolved server-side — e.g.
1566
+ * `"Approve span {spanId}"`. Placeholder names are case/separator-insensitive
1567
+ * (`{spanId}` == `{span-id}` == `{span_id}`), so use the camelCase names this
1568
+ * client uses. Applies to GET-less requests
1569
+ * only, including every operation queued in a batch.
1570
+ * @param {string} message - The custom message (template).
1571
+ */
1572
+ setAuditMessage(message) {
1573
+ this.auditMessage = message;
1574
+ return this;
1575
+ }
1576
+
1577
+ /** Clear the ambient custom audit-log message (revert to auto-generated). */
1578
+ clearAuditMessage() {
1579
+ this.auditMessage = null;
1580
+ return this;
1581
+ }
1582
+
1583
+ /**
1584
+ * Run `fn` with a custom audit-log message in effect, restoring the previous
1585
+ * message afterward (supports nesting). Use it to scope ONE call (per-call
1586
+ * precision) or MANY (a logical unit):
1587
+ *
1588
+ * await client.withAuditMessage('Approve span {spanId}', () =>
1589
+ * client.spans.update(spanId, ...));
1590
+ *
1591
+ * await client.withAuditMessage('Import sentence', async () => {
1592
+ * await client.tokens.create(...);
1593
+ * await client.spans.create(...);
1594
+ * });
1595
+ *
1596
+ * @param {string} message - The custom message (template).
1597
+ * @param {() => (Promise<any>|any)} fn - The work to run with the message set.
1598
+ * @returns {Promise<any>} Whatever `fn` resolves to.
1599
+ */
1600
+ async withAuditMessage(message, fn) {
1601
+ const prev = this.auditMessage;
1602
+ this.auditMessage = message;
1603
+ try {
1604
+ return await fn();
1605
+ } finally {
1606
+ this.auditMessage = prev;
1607
+ }
1608
+ }
1609
+
1502
1610
  /** Begin a batch of operations. Subsequent API calls will be queued. */
1503
1611
  beginBatch() {
1504
1612
  this.isBatching = true;
1505
1613
  this.batchOperations = [];
1614
+ // Strict mode stamps the expected document-version on the FIRST write of
1615
+ // the batch only (see _request) — reset the marker per batch.
1616
+ this.batchVersionStamped = false;
1506
1617
  }
1507
1618
 
1508
1619
  /**
@@ -1587,6 +1698,38 @@ class PlaidClient {
1587
1698
  return this.isBatching;
1588
1699
  }
1589
1700
 
1701
+ /**
1702
+ * Run `fn` with a batch open, then submit all queued ops as ONE atomic
1703
+ * request — or abort the batch if `fn` throws, so a half-open batch can never
1704
+ * silently swallow later non-batch calls. `fn` makes the (queued) client
1705
+ * calls; it must NOT call submitBatch itself. Resolves to the batch results
1706
+ * array (`[]` if `fn` queued nothing).
1707
+ *
1708
+ * const [sentRes, wordRes] = await client.batched(async () => {
1709
+ * client.tokens.bulkCreate(sentenceOps);
1710
+ * client.tokens.bulkCreate(wordOps);
1711
+ * });
1712
+ *
1713
+ * Server-side a batch runs sequentially in one transaction (a child op sees
1714
+ * parents created earlier in the same `fn`; any op's failure rolls the whole
1715
+ * batch back). Not nestable. Named `batched()` because `client.batch` is the
1716
+ * low-level batch resource.
1717
+ * @param {() => (void | Promise<void>)} fn
1718
+ * @returns {Promise<Array>}
1719
+ */
1720
+ async batched(fn) {
1721
+ this.beginBatch();
1722
+ try {
1723
+ await fn();
1724
+ } catch (e) {
1725
+ // fn failed: drop the queued ops so the client leaves batch mode and
1726
+ // later plain calls don't queue into a never-submitted batch.
1727
+ if (this.isBatchMode()) this.abortBatch();
1728
+ throw e;
1729
+ }
1730
+ return this.submitBatch();
1731
+ }
1732
+
1590
1733
  /**
1591
1734
  * Authenticate and return a new client instance with token. This is the
1592
1735
  * single auth entry point — there is no `client.login` resource.
@@ -1642,3 +1785,17 @@ export {
1642
1785
  buildDefaultValues,
1643
1786
  coerceParamValues,
1644
1787
  } from './serviceSchema.js';
1788
+ // Provenance: the cross-app convention for machine-provided vs human-labeled
1789
+ // information (flat prov/provSource/provConfirmed metadata; absence = human),
1790
+ // plus the machine-writer contract. See ./provenance.js and the manual,
1791
+ // "Provenance".
1792
+ export {
1793
+ PROV,
1794
+ PROV_STATES,
1795
+ stampInferred,
1796
+ confirmedInferred,
1797
+ provState,
1798
+ isProtected,
1799
+ verifyOnEdit,
1800
+ serviceSource,
1801
+ } from './provenance.js';