@larc-iu/plaid-client 0.2.0-alpha.1 → 0.2.0-alpha.11
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/index.d.ts +581 -105
- package/package.json +1 -1
- package/src/http.js +254 -35
- package/src/index.js +1171 -365
- package/src/provenance.js +259 -27
- package/src/serviceSchema.js +50 -30
- package/src/services.js +202 -37
- package/src/sse.js +51 -1
package/src/index.js
CHANGED
|
@@ -2,19 +2,46 @@
|
|
|
2
2
|
* plaid-client - JavaScript client for the Plaid annotation API
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import { transformRequest, transformResponse } from
|
|
5
|
+
import { transformRequest, transformResponse } from "./transforms.js";
|
|
6
6
|
import {
|
|
7
|
-
makeRequest,
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
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
|
-
|
|
24
|
+
attachServiceRequest,
|
|
25
|
+
cancelServiceRequest,
|
|
26
|
+
} from "./services.js";
|
|
27
|
+
|
|
28
|
+
// Helper: normalize a document-read `layers` filter to the wire's
|
|
29
|
+
// comma-separated form. Accepts an array of layer ids or a ready-made string;
|
|
30
|
+
// anything empty becomes undefined so no `?layers=` is sent at all.
|
|
31
|
+
function layersParam(layers) {
|
|
32
|
+
if (layers === undefined || layers === null) return undefined;
|
|
33
|
+
const joined = Array.isArray(layers) ? layers.join(",") : String(layers);
|
|
34
|
+
return joined.length > 0 ? joined : undefined;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Helper: normalize an audit `opTypes` filter to the wire's comma-separated
|
|
38
|
+
// form. Accepts an array of op types or a ready-made string; anything empty
|
|
39
|
+
// becomes undefined so no `?op-types=` is sent at all.
|
|
40
|
+
function opTypesParam(opTypes) {
|
|
41
|
+
if (opTypes === undefined || opTypes === null) return undefined;
|
|
42
|
+
const joined = Array.isArray(opTypes) ? opTypes.join(",") : String(opTypes);
|
|
43
|
+
return joined.length > 0 ? joined : undefined;
|
|
44
|
+
}
|
|
18
45
|
|
|
19
46
|
// Helper: build body object, filtering out undefined values
|
|
20
47
|
function bodyOf(obj) {
|
|
@@ -29,28 +56,41 @@ function bodyOf(obj) {
|
|
|
29
56
|
// and redemption). Deliberately does not go through PlaidClient._request: these
|
|
30
57
|
// are called before any client exists, which is the whole point.
|
|
31
58
|
async function anonymousPost(baseUrl, path, body, options = {}) {
|
|
32
|
-
const base = baseUrl.replace(/\/$/,
|
|
59
|
+
const base = baseUrl.replace(/\/$/, "");
|
|
33
60
|
const url = `${base}${path}`;
|
|
34
61
|
try {
|
|
35
62
|
const fetchOptions = {
|
|
36
|
-
method:
|
|
37
|
-
headers: {
|
|
63
|
+
method: "POST",
|
|
64
|
+
headers: { "Content-Type": "application/json" },
|
|
38
65
|
body: JSON.stringify(body),
|
|
39
66
|
};
|
|
40
|
-
const signal = timeoutSignal(
|
|
67
|
+
const signal = timeoutSignal(
|
|
68
|
+
options.timeout !== undefined ? options.timeout : DEFAULT_TIMEOUT_MS,
|
|
69
|
+
);
|
|
41
70
|
if (signal) fetchOptions.signal = signal;
|
|
42
71
|
|
|
43
72
|
const response = await fetch(url, fetchOptions);
|
|
44
73
|
if (!response.ok) {
|
|
45
|
-
throw makeHttpError(
|
|
74
|
+
throw makeHttpError(
|
|
75
|
+
response,
|
|
76
|
+
await parseErrorBody(response),
|
|
77
|
+
url,
|
|
78
|
+
"POST",
|
|
79
|
+
);
|
|
46
80
|
}
|
|
47
81
|
return transformResponse(await response.json());
|
|
48
82
|
} catch (error) {
|
|
49
83
|
if (error.status) throw error;
|
|
50
|
-
throw makeNetworkError(error, url,
|
|
84
|
+
throw makeNetworkError(error, url, "POST");
|
|
51
85
|
}
|
|
52
86
|
}
|
|
53
87
|
|
|
88
|
+
/**
|
|
89
|
+
* The server's cap on operations per batch request (plaid.rest-api.v1.batch).
|
|
90
|
+
* A batch queued past it is submitted as consecutive requests.
|
|
91
|
+
*/
|
|
92
|
+
const MAX_BATCH_OPS = 1000;
|
|
93
|
+
|
|
54
94
|
class PlaidClient {
|
|
55
95
|
/**
|
|
56
96
|
* Create a new PlaidClient instance
|
|
@@ -58,11 +98,24 @@ class PlaidClient {
|
|
|
58
98
|
* @param {string} token - The authentication token
|
|
59
99
|
* @param {object} [options] - Client options
|
|
60
100
|
* @param {number} [options.timeout=30000] - Per-request timeout in ms (0 or null disables it)
|
|
101
|
+
* @param {number} [options.batchTimeout=180000] - Timeout for batch submissions in ms (0 or null disables it)
|
|
61
102
|
*/
|
|
62
103
|
constructor(baseUrl, token, options = {}) {
|
|
63
|
-
this.baseUrl = baseUrl.replace(/\/$/,
|
|
104
|
+
this.baseUrl = baseUrl.replace(/\/$/, "");
|
|
64
105
|
this.token = token;
|
|
65
|
-
this.timeout =
|
|
106
|
+
this.timeout =
|
|
107
|
+
options.timeout !== undefined ? options.timeout : DEFAULT_TIMEOUT_MS;
|
|
108
|
+
// Batch submissions get a longer budget than a single request. Aborting a
|
|
109
|
+
// batch does NOT stop the server: it keeps running the transaction and
|
|
110
|
+
// holding the single SQLite write lock, so a client that gives up early
|
|
111
|
+
// just adds a retry on top of a write that is still in progress. Falls
|
|
112
|
+
// back to an explicit `timeout` when one was given.
|
|
113
|
+
this.batchTimeout =
|
|
114
|
+
options.batchTimeout !== undefined
|
|
115
|
+
? options.batchTimeout
|
|
116
|
+
: options.timeout !== undefined
|
|
117
|
+
? options.timeout
|
|
118
|
+
: DEFAULT_BATCH_TIMEOUT_MS;
|
|
66
119
|
this.isBatching = false;
|
|
67
120
|
this.batchOperations = [];
|
|
68
121
|
this.documentVersions = {};
|
|
@@ -88,8 +141,9 @@ class PlaidClient {
|
|
|
88
141
|
* @param {any} [metadata] - Metadata for the link. Omit to leave unset; pass null to send JSON null.
|
|
89
142
|
*/
|
|
90
143
|
create: (vocabItem, tokens, metadata, auditMessage) =>
|
|
91
|
-
this._request(
|
|
92
|
-
|
|
144
|
+
this._request("POST", "/api/v1/vocab-links", {
|
|
145
|
+
auditMessage,
|
|
146
|
+
body: bodyOf({ "vocab-item": vocabItem, tokens, metadata }),
|
|
93
147
|
}),
|
|
94
148
|
/**
|
|
95
149
|
* Create multiple vocab links in a single operation. Entries may
|
|
@@ -99,28 +153,37 @@ class PlaidClient {
|
|
|
99
153
|
* @returns {Promise<{ids: string[]}>} The created entity IDs, in input order. (bulkDelete resolves to no value.)
|
|
100
154
|
*/
|
|
101
155
|
bulkCreate: (body, auditMessage) =>
|
|
102
|
-
this._request(
|
|
156
|
+
this._request("POST", "/api/v1/vocab-links/bulk", {
|
|
157
|
+
auditMessage,
|
|
158
|
+
body,
|
|
159
|
+
}),
|
|
103
160
|
/**
|
|
104
161
|
* Delete multiple vocab links in a single operation. Provide an array of IDs.
|
|
105
162
|
* @param {string[]} body - The vocab link IDs to delete
|
|
106
163
|
*/
|
|
107
164
|
bulkDelete: (body, auditMessage) =>
|
|
108
|
-
this._request(
|
|
165
|
+
this._request("DELETE", "/api/v1/vocab-links/bulk", {
|
|
166
|
+
auditMessage,
|
|
167
|
+
body,
|
|
168
|
+
}),
|
|
109
169
|
/**
|
|
110
170
|
* Replace all metadata for a vocab link. The entire metadata map is replaced - existing metadata keys not included in the request will be removed.
|
|
111
171
|
* @param {string} id - The resource ID
|
|
112
172
|
* @param {any} body - The request body
|
|
113
173
|
*/
|
|
114
174
|
setMetadata: (id, body, auditMessage) =>
|
|
115
|
-
this._request(
|
|
116
|
-
|
|
175
|
+
this._request("PUT", `/api/v1/vocab-links/${id}/metadata`, {
|
|
176
|
+
auditMessage,
|
|
177
|
+
rawBody: body,
|
|
178
|
+
skipResponseTransform: true,
|
|
117
179
|
}),
|
|
118
180
|
/**
|
|
119
181
|
* Remove all metadata from a vocab link.
|
|
120
182
|
* @param {string} id - The resource ID
|
|
121
183
|
*/
|
|
122
184
|
deleteMetadata: (id, auditMessage) =>
|
|
123
|
-
this._request(
|
|
185
|
+
this._request("DELETE", `/api/v1/vocab-links/${id}/metadata`, {
|
|
186
|
+
auditMessage,
|
|
124
187
|
skipResponseTransform: true,
|
|
125
188
|
}),
|
|
126
189
|
/**
|
|
@@ -129,8 +192,10 @@ class PlaidClient {
|
|
|
129
192
|
* @param {any} body - The metadata patch
|
|
130
193
|
*/
|
|
131
194
|
patchMetadata: (id, body, auditMessage) =>
|
|
132
|
-
this._request(
|
|
133
|
-
|
|
195
|
+
this._request("PATCH", `/api/v1/vocab-links/${id}/metadata`, {
|
|
196
|
+
auditMessage,
|
|
197
|
+
rawBody: body,
|
|
198
|
+
skipResponseTransform: true,
|
|
134
199
|
}),
|
|
135
200
|
/**
|
|
136
201
|
* Get a vocab link by ID
|
|
@@ -138,15 +203,15 @@ class PlaidClient {
|
|
|
138
203
|
* @param {string} [asOf] - Temporal query timestamp
|
|
139
204
|
*/
|
|
140
205
|
get: (id, asOf) =>
|
|
141
|
-
this._request(
|
|
142
|
-
queryParams: {
|
|
206
|
+
this._request("GET", `/api/v1/vocab-links/${id}`, {
|
|
207
|
+
queryParams: { "as-of": asOf },
|
|
143
208
|
}),
|
|
144
209
|
/**
|
|
145
210
|
* Delete a vocab link
|
|
146
211
|
* @param {string} id - The resource ID
|
|
147
212
|
*/
|
|
148
213
|
delete: (id, auditMessage) =>
|
|
149
|
-
this._request(
|
|
214
|
+
this._request("DELETE", `/api/v1/vocab-links/${id}`, { auditMessage }),
|
|
150
215
|
};
|
|
151
216
|
|
|
152
217
|
this.vocabLayers = {
|
|
@@ -157,22 +222,23 @@ class PlaidClient {
|
|
|
157
222
|
* @param {string} [asOf] - Temporal query timestamp
|
|
158
223
|
*/
|
|
159
224
|
get: (id, includeItems, asOf) =>
|
|
160
|
-
this._request(
|
|
161
|
-
queryParams: {
|
|
225
|
+
this._request("GET", `/api/v1/vocab-layers/${id}`, {
|
|
226
|
+
queryParams: { "include-items": includeItems, "as-of": asOf },
|
|
162
227
|
}),
|
|
163
228
|
/**
|
|
164
229
|
* Delete a vocab layer.
|
|
165
230
|
* @param {string} id - The resource ID
|
|
166
231
|
*/
|
|
167
232
|
delete: (id, auditMessage) =>
|
|
168
|
-
this._request(
|
|
233
|
+
this._request("DELETE", `/api/v1/vocab-layers/${id}`, { auditMessage }),
|
|
169
234
|
/**
|
|
170
235
|
* Update a vocab layer's name.
|
|
171
236
|
* @param {string} id - The resource ID
|
|
172
237
|
* @param {string} name - The name
|
|
173
238
|
*/
|
|
174
239
|
update: (id, name, auditMessage) =>
|
|
175
|
-
this._request(
|
|
240
|
+
this._request("PATCH", `/api/v1/vocab-layers/${id}`, {
|
|
241
|
+
auditMessage,
|
|
176
242
|
body: bodyOf({ name }),
|
|
177
243
|
}),
|
|
178
244
|
/**
|
|
@@ -183,9 +249,11 @@ class PlaidClient {
|
|
|
183
249
|
* @param {any} configValue - Configuration value to set
|
|
184
250
|
*/
|
|
185
251
|
setConfig: (id, namespace, configKey, configValue, auditMessage) =>
|
|
186
|
-
this._request(
|
|
187
|
-
|
|
188
|
-
|
|
252
|
+
this._request(
|
|
253
|
+
"PUT",
|
|
254
|
+
`/api/v1/vocab-layers/${id}/config/${namespace}/${configKey}`,
|
|
255
|
+
{ auditMessage, rawBody: configValue, skipResponseTransform: true },
|
|
256
|
+
),
|
|
189
257
|
/**
|
|
190
258
|
* Remove a configuration value for a layer.
|
|
191
259
|
* @param {string} id - The resource ID
|
|
@@ -193,9 +261,11 @@ class PlaidClient {
|
|
|
193
261
|
* @param {string} configKey - The config key
|
|
194
262
|
*/
|
|
195
263
|
deleteConfig: (id, namespace, configKey, auditMessage) =>
|
|
196
|
-
this._request(
|
|
197
|
-
|
|
198
|
-
|
|
264
|
+
this._request(
|
|
265
|
+
"DELETE",
|
|
266
|
+
`/api/v1/vocab-layers/${id}/config/${namespace}/${configKey}`,
|
|
267
|
+
{ auditMessage, skipResponseTransform: true },
|
|
268
|
+
),
|
|
199
269
|
/**
|
|
200
270
|
* List all vocab layers accessible to user. Transparently follows
|
|
201
271
|
* pagination cursors and returns the full flat array.
|
|
@@ -203,7 +273,7 @@ class PlaidClient {
|
|
|
203
273
|
* @param {string} [asOf] - Temporal query timestamp
|
|
204
274
|
*/
|
|
205
275
|
list: (asOf) =>
|
|
206
|
-
listAll(this,
|
|
276
|
+
listAll(this, "/api/v1/vocab-layers", { query: { "as-of": asOf } }),
|
|
207
277
|
/**
|
|
208
278
|
* Fetch a single page of vocab layers.
|
|
209
279
|
* @param {object} [opts]
|
|
@@ -213,7 +283,11 @@ class PlaidClient {
|
|
|
213
283
|
* @returns {Promise<{entries: Array, nextCursor: (string|null)}>}
|
|
214
284
|
*/
|
|
215
285
|
listPage: ({ limit, cursor, asOf } = {}) =>
|
|
216
|
-
listPage(this,
|
|
286
|
+
listPage(this, "/api/v1/vocab-layers", {
|
|
287
|
+
limit,
|
|
288
|
+
cursor,
|
|
289
|
+
query: { "as-of": asOf },
|
|
290
|
+
}),
|
|
217
291
|
/**
|
|
218
292
|
* Async-iterate vocab layers page by page; yields each page's entries array.
|
|
219
293
|
* @param {object} [opts]
|
|
@@ -223,13 +297,17 @@ class PlaidClient {
|
|
|
223
297
|
* @returns {AsyncGenerator<Array>}
|
|
224
298
|
*/
|
|
225
299
|
iterPages: ({ pageSize, asOf } = {}) =>
|
|
226
|
-
iterPages(this,
|
|
300
|
+
iterPages(this, "/api/v1/vocab-layers", {
|
|
301
|
+
pageSize,
|
|
302
|
+
query: { "as-of": asOf },
|
|
303
|
+
}),
|
|
227
304
|
/**
|
|
228
305
|
* Create a new vocab layer. Note: this also registers the user as a maintainer.
|
|
229
306
|
* @param {string} name - The name
|
|
230
307
|
*/
|
|
231
308
|
create: (name, auditMessage) =>
|
|
232
|
-
this._request(
|
|
309
|
+
this._request("POST", "/api/v1/vocab-layers", {
|
|
310
|
+
auditMessage,
|
|
233
311
|
body: bodyOf({ name }),
|
|
234
312
|
}),
|
|
235
313
|
/**
|
|
@@ -238,14 +316,22 @@ class PlaidClient {
|
|
|
238
316
|
* @param {string} userId - The user ID
|
|
239
317
|
*/
|
|
240
318
|
addMaintainer: (id, userId, auditMessage) =>
|
|
241
|
-
this._request(
|
|
319
|
+
this._request(
|
|
320
|
+
"POST",
|
|
321
|
+
`/api/v1/vocab-layers/${id}/maintainers/${userId}`,
|
|
322
|
+
{ auditMessage },
|
|
323
|
+
),
|
|
242
324
|
/**
|
|
243
325
|
* Remove a user's maintainer privileges for this vocab layer.
|
|
244
326
|
* @param {string} id - The resource ID
|
|
245
327
|
* @param {string} userId - The user ID
|
|
246
328
|
*/
|
|
247
329
|
removeMaintainer: (id, userId, auditMessage) =>
|
|
248
|
-
this._request(
|
|
330
|
+
this._request(
|
|
331
|
+
"DELETE",
|
|
332
|
+
`/api/v1/vocab-layers/${id}/maintainers/${userId}`,
|
|
333
|
+
{ auditMessage },
|
|
334
|
+
),
|
|
249
335
|
};
|
|
250
336
|
|
|
251
337
|
this.relations = {
|
|
@@ -255,15 +341,18 @@ class PlaidClient {
|
|
|
255
341
|
* @param {any} body - The request body
|
|
256
342
|
*/
|
|
257
343
|
setMetadata: (relationId, body, auditMessage) =>
|
|
258
|
-
this._request(
|
|
259
|
-
|
|
344
|
+
this._request("PUT", `/api/v1/relations/${relationId}/metadata`, {
|
|
345
|
+
auditMessage,
|
|
346
|
+
rawBody: body,
|
|
347
|
+
skipResponseTransform: true,
|
|
260
348
|
}),
|
|
261
349
|
/**
|
|
262
350
|
* Remove all metadata from a relation.
|
|
263
351
|
* @param {string} relationId - The relation ID
|
|
264
352
|
*/
|
|
265
353
|
deleteMetadata: (relationId, auditMessage) =>
|
|
266
|
-
this._request(
|
|
354
|
+
this._request("DELETE", `/api/v1/relations/${relationId}/metadata`, {
|
|
355
|
+
auditMessage,
|
|
267
356
|
skipResponseTransform: true,
|
|
268
357
|
}),
|
|
269
358
|
/**
|
|
@@ -272,8 +361,10 @@ class PlaidClient {
|
|
|
272
361
|
* @param {any} body - The metadata patch
|
|
273
362
|
*/
|
|
274
363
|
patchMetadata: (relationId, body, auditMessage) =>
|
|
275
|
-
this._request(
|
|
276
|
-
|
|
364
|
+
this._request("PATCH", `/api/v1/relations/${relationId}/metadata`, {
|
|
365
|
+
auditMessage,
|
|
366
|
+
rawBody: body,
|
|
367
|
+
skipResponseTransform: true,
|
|
277
368
|
}),
|
|
278
369
|
/**
|
|
279
370
|
* Update the target span of a relation.
|
|
@@ -281,8 +372,9 @@ class PlaidClient {
|
|
|
281
372
|
* @param {string} spanId - The span ID
|
|
282
373
|
*/
|
|
283
374
|
setTarget: (relationId, spanId, auditMessage) =>
|
|
284
|
-
this._request(
|
|
285
|
-
|
|
375
|
+
this._request("PUT", `/api/v1/relations/${relationId}/target`, {
|
|
376
|
+
auditMessage,
|
|
377
|
+
body: bodyOf({ "span-id": spanId }),
|
|
286
378
|
}),
|
|
287
379
|
/**
|
|
288
380
|
* Get a relation by ID.
|
|
@@ -290,22 +382,25 @@ class PlaidClient {
|
|
|
290
382
|
* @param {string} [asOf] - Temporal query timestamp
|
|
291
383
|
*/
|
|
292
384
|
get: (relationId, asOf) =>
|
|
293
|
-
this._request(
|
|
294
|
-
queryParams: {
|
|
385
|
+
this._request("GET", `/api/v1/relations/${relationId}`, {
|
|
386
|
+
queryParams: { "as-of": asOf },
|
|
295
387
|
}),
|
|
296
388
|
/**
|
|
297
389
|
* Delete a relation.
|
|
298
390
|
* @param {string} relationId - The relation ID
|
|
299
391
|
*/
|
|
300
392
|
delete: (relationId, auditMessage) =>
|
|
301
|
-
this._request(
|
|
393
|
+
this._request("DELETE", `/api/v1/relations/${relationId}`, {
|
|
394
|
+
auditMessage,
|
|
395
|
+
}),
|
|
302
396
|
/**
|
|
303
397
|
* Update a relation's value.
|
|
304
398
|
* @param {string} relationId - The relation ID
|
|
305
399
|
* @param {any} value - The value
|
|
306
400
|
*/
|
|
307
401
|
update: (relationId, value, auditMessage) =>
|
|
308
|
-
this._request(
|
|
402
|
+
this._request("PATCH", `/api/v1/relations/${relationId}`, {
|
|
403
|
+
auditMessage,
|
|
309
404
|
body: bodyOf({ value }),
|
|
310
405
|
}),
|
|
311
406
|
/**
|
|
@@ -314,8 +409,9 @@ class PlaidClient {
|
|
|
314
409
|
* @param {string} spanId - The span ID
|
|
315
410
|
*/
|
|
316
411
|
setSource: (relationId, spanId, auditMessage) =>
|
|
317
|
-
this._request(
|
|
318
|
-
|
|
412
|
+
this._request("PUT", `/api/v1/relations/${relationId}/source`, {
|
|
413
|
+
auditMessage,
|
|
414
|
+
body: bodyOf({ "span-id": spanId }),
|
|
319
415
|
}),
|
|
320
416
|
/**
|
|
321
417
|
* Create a new relation. A relation is a directed edge between two spans
|
|
@@ -328,8 +424,15 @@ class PlaidClient {
|
|
|
328
424
|
* @param {any} [metadata] - Metadata map. Omit to leave unset; pass null to send JSON null.
|
|
329
425
|
*/
|
|
330
426
|
create: (layerId, sourceId, targetId, value, metadata, auditMessage) =>
|
|
331
|
-
this._request(
|
|
332
|
-
|
|
427
|
+
this._request("POST", "/api/v1/relations", {
|
|
428
|
+
auditMessage,
|
|
429
|
+
body: bodyOf({
|
|
430
|
+
"layer-id": layerId,
|
|
431
|
+
"source-id": sourceId,
|
|
432
|
+
"target-id": targetId,
|
|
433
|
+
value,
|
|
434
|
+
metadata,
|
|
435
|
+
}),
|
|
333
436
|
}),
|
|
334
437
|
/**
|
|
335
438
|
* Create multiple relations in a single operation.
|
|
@@ -337,13 +440,16 @@ class PlaidClient {
|
|
|
337
440
|
* @returns {Promise<{ids: string[]}>} The created entity IDs, in input order. (bulkDelete resolves to no value.)
|
|
338
441
|
*/
|
|
339
442
|
bulkCreate: (body, auditMessage) =>
|
|
340
|
-
this._request(
|
|
443
|
+
this._request("POST", "/api/v1/relations/bulk", { auditMessage, body }),
|
|
341
444
|
/**
|
|
342
445
|
* Delete multiple relations in a single operation. Provide an array of IDs.
|
|
343
446
|
* @param {Array} body - The request body
|
|
344
447
|
*/
|
|
345
448
|
bulkDelete: (body, auditMessage) =>
|
|
346
|
-
this._request(
|
|
449
|
+
this._request("DELETE", "/api/v1/relations/bulk", {
|
|
450
|
+
auditMessage,
|
|
451
|
+
body,
|
|
452
|
+
}),
|
|
347
453
|
};
|
|
348
454
|
|
|
349
455
|
this.spanLayers = {
|
|
@@ -354,10 +460,18 @@ class PlaidClient {
|
|
|
354
460
|
* @param {string} configKey - The config key
|
|
355
461
|
* @param {any} configValue - Configuration value to set
|
|
356
462
|
*/
|
|
357
|
-
setConfig: (
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
463
|
+
setConfig: (
|
|
464
|
+
spanLayerId,
|
|
465
|
+
namespace,
|
|
466
|
+
configKey,
|
|
467
|
+
configValue,
|
|
468
|
+
auditMessage,
|
|
469
|
+
) =>
|
|
470
|
+
this._request(
|
|
471
|
+
"PUT",
|
|
472
|
+
`/api/v1/span-layers/${spanLayerId}/config/${namespace}/${configKey}`,
|
|
473
|
+
{ auditMessage, rawBody: configValue, skipResponseTransform: true },
|
|
474
|
+
),
|
|
361
475
|
/**
|
|
362
476
|
* Remove a configuration value for a layer.
|
|
363
477
|
* @param {string} spanLayerId - The span layer ID
|
|
@@ -365,31 +479,36 @@ class PlaidClient {
|
|
|
365
479
|
* @param {string} configKey - The config key
|
|
366
480
|
*/
|
|
367
481
|
deleteConfig: (spanLayerId, namespace, configKey, auditMessage) =>
|
|
368
|
-
this._request(
|
|
369
|
-
|
|
370
|
-
|
|
482
|
+
this._request(
|
|
483
|
+
"DELETE",
|
|
484
|
+
`/api/v1/span-layers/${spanLayerId}/config/${namespace}/${configKey}`,
|
|
485
|
+
{ auditMessage, skipResponseTransform: true },
|
|
486
|
+
),
|
|
371
487
|
/**
|
|
372
488
|
* Get a span layer by ID.
|
|
373
489
|
* @param {string} spanLayerId - The span layer ID
|
|
374
490
|
* @param {string} [asOf] - Temporal query timestamp
|
|
375
491
|
*/
|
|
376
492
|
get: (spanLayerId, asOf) =>
|
|
377
|
-
this._request(
|
|
378
|
-
queryParams: {
|
|
493
|
+
this._request("GET", `/api/v1/span-layers/${spanLayerId}`, {
|
|
494
|
+
queryParams: { "as-of": asOf },
|
|
379
495
|
}),
|
|
380
496
|
/**
|
|
381
497
|
* Delete a span layer.
|
|
382
498
|
* @param {string} spanLayerId - The span layer ID
|
|
383
499
|
*/
|
|
384
500
|
delete: (spanLayerId, auditMessage) =>
|
|
385
|
-
this._request(
|
|
501
|
+
this._request("DELETE", `/api/v1/span-layers/${spanLayerId}`, {
|
|
502
|
+
auditMessage,
|
|
503
|
+
}),
|
|
386
504
|
/**
|
|
387
505
|
* Update a span layer's name.
|
|
388
506
|
* @param {string} spanLayerId - The span layer ID
|
|
389
507
|
* @param {string} name - The name
|
|
390
508
|
*/
|
|
391
509
|
update: (spanLayerId, name, auditMessage) =>
|
|
392
|
-
this._request(
|
|
510
|
+
this._request("PATCH", `/api/v1/span-layers/${spanLayerId}`, {
|
|
511
|
+
auditMessage,
|
|
393
512
|
body: bodyOf({ name }),
|
|
394
513
|
}),
|
|
395
514
|
/**
|
|
@@ -398,8 +517,9 @@ class PlaidClient {
|
|
|
398
517
|
* @param {string} name - The name
|
|
399
518
|
*/
|
|
400
519
|
create: (tokenLayerId, name, auditMessage) =>
|
|
401
|
-
this._request(
|
|
402
|
-
|
|
520
|
+
this._request("POST", "/api/v1/span-layers", {
|
|
521
|
+
auditMessage,
|
|
522
|
+
body: bodyOf({ "token-layer-id": tokenLayerId, name }),
|
|
403
523
|
}),
|
|
404
524
|
/**
|
|
405
525
|
* Shift a span layer's display order.
|
|
@@ -407,7 +527,8 @@ class PlaidClient {
|
|
|
407
527
|
* @param {string} direction - The direction ("up" or "down")
|
|
408
528
|
*/
|
|
409
529
|
shift: (spanLayerId, direction, auditMessage) =>
|
|
410
|
-
this._request(
|
|
530
|
+
this._request("POST", `/api/v1/span-layers/${spanLayerId}/shift`, {
|
|
531
|
+
auditMessage,
|
|
411
532
|
body: bodyOf({ direction }),
|
|
412
533
|
}),
|
|
413
534
|
};
|
|
@@ -419,7 +540,8 @@ class PlaidClient {
|
|
|
419
540
|
* @param {Array} tokens - The tokens
|
|
420
541
|
*/
|
|
421
542
|
setTokens: (spanId, tokens, auditMessage) =>
|
|
422
|
-
this._request(
|
|
543
|
+
this._request("PUT", `/api/v1/spans/${spanId}/tokens`, {
|
|
544
|
+
auditMessage,
|
|
423
545
|
body: bodyOf({ tokens }),
|
|
424
546
|
}),
|
|
425
547
|
/**
|
|
@@ -431,8 +553,14 @@ class PlaidClient {
|
|
|
431
553
|
* @param {any} [metadata] - Metadata map. Omit to leave unset; pass null to send JSON null.
|
|
432
554
|
*/
|
|
433
555
|
create: (spanLayerId, tokens, value, metadata, auditMessage) =>
|
|
434
|
-
this._request(
|
|
435
|
-
|
|
556
|
+
this._request("POST", "/api/v1/spans", {
|
|
557
|
+
auditMessage,
|
|
558
|
+
body: bodyOf({
|
|
559
|
+
"span-layer-id": spanLayerId,
|
|
560
|
+
tokens,
|
|
561
|
+
value,
|
|
562
|
+
metadata,
|
|
563
|
+
}),
|
|
436
564
|
}),
|
|
437
565
|
/**
|
|
438
566
|
* Get a span by ID.
|
|
@@ -440,22 +568,23 @@ class PlaidClient {
|
|
|
440
568
|
* @param {string} [asOf] - Temporal query timestamp
|
|
441
569
|
*/
|
|
442
570
|
get: (spanId, asOf) =>
|
|
443
|
-
this._request(
|
|
444
|
-
queryParams: {
|
|
571
|
+
this._request("GET", `/api/v1/spans/${spanId}`, {
|
|
572
|
+
queryParams: { "as-of": asOf },
|
|
445
573
|
}),
|
|
446
574
|
/**
|
|
447
575
|
* Delete a span.
|
|
448
576
|
* @param {string} spanId - The span ID
|
|
449
577
|
*/
|
|
450
578
|
delete: (spanId, auditMessage) =>
|
|
451
|
-
this._request(
|
|
579
|
+
this._request("DELETE", `/api/v1/spans/${spanId}`, { auditMessage }),
|
|
452
580
|
/**
|
|
453
581
|
* Update a span's value.
|
|
454
582
|
* @param {string} spanId - The span ID
|
|
455
583
|
* @param {any} value - The value
|
|
456
584
|
*/
|
|
457
585
|
update: (spanId, value, auditMessage) =>
|
|
458
|
-
this._request(
|
|
586
|
+
this._request("PATCH", `/api/v1/spans/${spanId}`, {
|
|
587
|
+
auditMessage,
|
|
459
588
|
body: bodyOf({ value }),
|
|
460
589
|
}),
|
|
461
590
|
/**
|
|
@@ -464,28 +593,31 @@ class PlaidClient {
|
|
|
464
593
|
* @returns {Promise<{ids: string[]}>} The created entity IDs, in input order. (bulkDelete resolves to no value.)
|
|
465
594
|
*/
|
|
466
595
|
bulkCreate: (body, auditMessage) =>
|
|
467
|
-
this._request(
|
|
596
|
+
this._request("POST", "/api/v1/spans/bulk", { auditMessage, body }),
|
|
468
597
|
/**
|
|
469
598
|
* Delete multiple spans in a single operation. Provide an array of IDs.
|
|
470
599
|
* @param {Array} body - The request body
|
|
471
600
|
*/
|
|
472
601
|
bulkDelete: (body, auditMessage) =>
|
|
473
|
-
this._request(
|
|
602
|
+
this._request("DELETE", "/api/v1/spans/bulk", { auditMessage, body }),
|
|
474
603
|
/**
|
|
475
604
|
* Replace all metadata for a span.
|
|
476
605
|
* @param {string} spanId - The span ID
|
|
477
606
|
* @param {any} body - The request body
|
|
478
607
|
*/
|
|
479
608
|
setMetadata: (spanId, body, auditMessage) =>
|
|
480
|
-
this._request(
|
|
481
|
-
|
|
609
|
+
this._request("PUT", `/api/v1/spans/${spanId}/metadata`, {
|
|
610
|
+
auditMessage,
|
|
611
|
+
rawBody: body,
|
|
612
|
+
skipResponseTransform: true,
|
|
482
613
|
}),
|
|
483
614
|
/**
|
|
484
615
|
* Remove all metadata from a span.
|
|
485
616
|
* @param {string} spanId - The span ID
|
|
486
617
|
*/
|
|
487
618
|
deleteMetadata: (spanId, auditMessage) =>
|
|
488
|
-
this._request(
|
|
619
|
+
this._request("DELETE", `/api/v1/spans/${spanId}/metadata`, {
|
|
620
|
+
auditMessage,
|
|
489
621
|
skipResponseTransform: true,
|
|
490
622
|
}),
|
|
491
623
|
/**
|
|
@@ -494,8 +626,10 @@ class PlaidClient {
|
|
|
494
626
|
* @param {any} body - The metadata patch
|
|
495
627
|
*/
|
|
496
628
|
patchMetadata: (spanId, body, auditMessage) =>
|
|
497
|
-
this._request(
|
|
498
|
-
|
|
629
|
+
this._request("PATCH", `/api/v1/spans/${spanId}/metadata`, {
|
|
630
|
+
auditMessage,
|
|
631
|
+
rawBody: body,
|
|
632
|
+
skipResponseTransform: true,
|
|
499
633
|
}),
|
|
500
634
|
};
|
|
501
635
|
|
|
@@ -506,8 +640,10 @@ class PlaidClient {
|
|
|
506
640
|
* @param {Array} body - The request body
|
|
507
641
|
*/
|
|
508
642
|
submit: (body, auditMessage) =>
|
|
509
|
-
this._request(
|
|
510
|
-
|
|
643
|
+
this._request("POST", "/api/v1/batch", {
|
|
644
|
+
auditMessage,
|
|
645
|
+
body,
|
|
646
|
+
noBatch: true,
|
|
511
647
|
}),
|
|
512
648
|
};
|
|
513
649
|
|
|
@@ -518,15 +654,18 @@ class PlaidClient {
|
|
|
518
654
|
* @param {any} body - The request body
|
|
519
655
|
*/
|
|
520
656
|
setMetadata: (textId, body, auditMessage) =>
|
|
521
|
-
this._request(
|
|
522
|
-
|
|
657
|
+
this._request("PUT", `/api/v1/texts/${textId}/metadata`, {
|
|
658
|
+
auditMessage,
|
|
659
|
+
rawBody: body,
|
|
660
|
+
skipResponseTransform: true,
|
|
523
661
|
}),
|
|
524
662
|
/**
|
|
525
663
|
* Remove all metadata from a text.
|
|
526
664
|
* @param {string} textId - The text ID
|
|
527
665
|
*/
|
|
528
666
|
deleteMetadata: (textId, auditMessage) =>
|
|
529
|
-
this._request(
|
|
667
|
+
this._request("DELETE", `/api/v1/texts/${textId}/metadata`, {
|
|
668
|
+
auditMessage,
|
|
530
669
|
skipResponseTransform: true,
|
|
531
670
|
}),
|
|
532
671
|
/**
|
|
@@ -535,8 +674,10 @@ class PlaidClient {
|
|
|
535
674
|
* @param {any} body - The metadata patch
|
|
536
675
|
*/
|
|
537
676
|
patchMetadata: (textId, body, auditMessage) =>
|
|
538
|
-
this._request(
|
|
539
|
-
|
|
677
|
+
this._request("PATCH", `/api/v1/texts/${textId}/metadata`, {
|
|
678
|
+
auditMessage,
|
|
679
|
+
rawBody: body,
|
|
680
|
+
skipResponseTransform: true,
|
|
540
681
|
}),
|
|
541
682
|
/**
|
|
542
683
|
* Create a new text in a document's text layer. A text is a container for
|
|
@@ -547,8 +688,14 @@ class PlaidClient {
|
|
|
547
688
|
* @param {any} [metadata] - Metadata map. Omit to leave unset; pass null to send JSON null.
|
|
548
689
|
*/
|
|
549
690
|
create: (textLayerId, documentId, body, metadata, auditMessage) =>
|
|
550
|
-
this._request(
|
|
551
|
-
|
|
691
|
+
this._request("POST", "/api/v1/texts", {
|
|
692
|
+
auditMessage,
|
|
693
|
+
body: bodyOf({
|
|
694
|
+
"text-layer-id": textLayerId,
|
|
695
|
+
"document-id": documentId,
|
|
696
|
+
body,
|
|
697
|
+
metadata,
|
|
698
|
+
}),
|
|
552
699
|
}),
|
|
553
700
|
/**
|
|
554
701
|
* Get a text.
|
|
@@ -556,24 +703,30 @@ class PlaidClient {
|
|
|
556
703
|
* @param {string} [asOf] - Temporal query timestamp
|
|
557
704
|
*/
|
|
558
705
|
get: (textId, asOf) =>
|
|
559
|
-
this._request(
|
|
560
|
-
queryParams: {
|
|
706
|
+
this._request("GET", `/api/v1/texts/${textId}`, {
|
|
707
|
+
queryParams: { "as-of": asOf },
|
|
561
708
|
}),
|
|
562
709
|
/**
|
|
563
710
|
* Delete a text and all dependent data.
|
|
564
711
|
* @param {string} textId - The text ID
|
|
565
712
|
*/
|
|
566
713
|
delete: (textId, auditMessage) =>
|
|
567
|
-
this._request(
|
|
714
|
+
this._request("DELETE", `/api/v1/texts/${textId}`, { auditMessage }),
|
|
568
715
|
/**
|
|
569
716
|
* Update a text's body. A diff is computed and token indices are updated
|
|
570
717
|
* so that tokens remain intact. Alternatively, `body` can be a list of
|
|
571
|
-
* edit directives
|
|
718
|
+
* edit directives (code-point indices, applied in order):
|
|
719
|
+
* {type: 'delete', index, value: count}
|
|
720
|
+
* {type: 'insert', index, value: string}
|
|
721
|
+
* {type: 'replace', index, length, value: string} — unlike
|
|
722
|
+
* delete+insert, a token covering the whole range is resized to keep
|
|
723
|
+
* it (respell a word in place without losing its annotations).
|
|
572
724
|
* @param {string} textId - The text ID
|
|
573
725
|
* @param {any} body - The request body
|
|
574
726
|
*/
|
|
575
727
|
update: (textId, body, auditMessage) =>
|
|
576
|
-
this._request(
|
|
728
|
+
this._request("PATCH", `/api/v1/texts/${textId}`, {
|
|
729
|
+
auditMessage,
|
|
577
730
|
body: bodyOf({ body }),
|
|
578
731
|
}),
|
|
579
732
|
};
|
|
@@ -584,42 +737,58 @@ class PlaidClient {
|
|
|
584
737
|
* returns the full flat array. Admin-or-maintainer only.
|
|
585
738
|
* Cannot be used inside a batch (auto-paginates across requests); throws if called while batching — use listPage() for a single page in a batch.
|
|
586
739
|
* @param {object} [opts]
|
|
587
|
-
* @param {string} [opts.q] - Filter to
|
|
740
|
+
* @param {string} [opts.q] - Filter to users whose display name or email contains this text (case-insensitive)
|
|
588
741
|
* @param {string} [opts.asOf] - Temporal query timestamp
|
|
589
742
|
*/
|
|
590
743
|
list: ({ q, asOf } = {}) =>
|
|
591
|
-
listAll(this,
|
|
744
|
+
listAll(this, "/api/v1/users", { query: { q, "as-of": asOf } }),
|
|
592
745
|
/**
|
|
593
746
|
* Fetch a single page of users (optionally filtered by `q`).
|
|
594
747
|
* @param {object} [opts]
|
|
595
|
-
* @param {string} [opts.q] - Filter to
|
|
748
|
+
* @param {string} [opts.q] - Filter to users whose display name or email contains this text (case-insensitive)
|
|
596
749
|
* @param {number} [opts.limit] - Page size (1..1000; server default 100)
|
|
597
750
|
* @param {string} [opts.cursor] - Opaque cursor from a previous page
|
|
598
751
|
* @param {string} [opts.asOf] - Temporal query timestamp
|
|
599
752
|
* @returns {Promise<{entries: Array, nextCursor: (string|null)}>}
|
|
600
753
|
*/
|
|
601
754
|
listPage: ({ q, limit, cursor, asOf } = {}) =>
|
|
602
|
-
listPage(this,
|
|
755
|
+
listPage(this, "/api/v1/users", {
|
|
756
|
+
limit,
|
|
757
|
+
cursor,
|
|
758
|
+
query: { q, "as-of": asOf },
|
|
759
|
+
}),
|
|
603
760
|
/**
|
|
604
761
|
* Async-iterate users page by page; yields each page's entries array.
|
|
605
762
|
* @param {object} [opts]
|
|
606
|
-
* @param {string} [opts.q] - Filter to
|
|
763
|
+
* @param {string} [opts.q] - Filter to users whose display name or email contains this text (case-insensitive)
|
|
607
764
|
* @param {number} [opts.pageSize] - Per-request page size
|
|
608
765
|
* @param {string} [opts.asOf] - Temporal query timestamp
|
|
609
766
|
* 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.
|
|
610
767
|
* @returns {AsyncGenerator<Array>}
|
|
611
768
|
*/
|
|
612
769
|
iterPages: ({ q, pageSize, asOf } = {}) =>
|
|
613
|
-
iterPages(this,
|
|
770
|
+
iterPages(this, "/api/v1/users", {
|
|
771
|
+
pageSize,
|
|
772
|
+
query: { q, "as-of": asOf },
|
|
773
|
+
}),
|
|
614
774
|
/**
|
|
615
|
-
* Create a new user
|
|
616
|
-
* @param {string}
|
|
775
|
+
* Create a new user.
|
|
776
|
+
* @param {string} email - The account's email address. It becomes the
|
|
777
|
+
* user's id and is what they log in with; it can never be changed.
|
|
617
778
|
* @param {string} password - The password
|
|
618
779
|
* @param {boolean} isAdmin - Whether the user is an admin
|
|
780
|
+
* @param {string} [displayName] - How the user is shown in the UI.
|
|
781
|
+
* Defaults to the local part of the email.
|
|
619
782
|
*/
|
|
620
|
-
create: (
|
|
621
|
-
this._request(
|
|
622
|
-
|
|
783
|
+
create: (email, password, isAdmin, displayName, auditMessage) =>
|
|
784
|
+
this._request("POST", "/api/v1/users", {
|
|
785
|
+
auditMessage,
|
|
786
|
+
body: bodyOf({
|
|
787
|
+
email,
|
|
788
|
+
password,
|
|
789
|
+
"is-admin": isAdmin,
|
|
790
|
+
"display-name": displayName,
|
|
791
|
+
}),
|
|
623
792
|
}),
|
|
624
793
|
/**
|
|
625
794
|
* Get audit log for a user's actions. Transparently follows pagination
|
|
@@ -629,10 +798,19 @@ class PlaidClient {
|
|
|
629
798
|
* @param {string} [startTime] - Start of time range
|
|
630
799
|
* @param {string} [endTime] - End of time range
|
|
631
800
|
* @param {string} [asOf] - Temporal query timestamp
|
|
801
|
+
* @param {string[]|string} [opTypes] - Only return operations of these
|
|
802
|
+
* types, spelled as in an entry's `op/type` (e.g.
|
|
803
|
+
* `['span-layer/create', 'span-layer/delete']`). An entry appears when
|
|
804
|
+
* one of its operations matches, carrying only the ones that did.
|
|
632
805
|
*/
|
|
633
|
-
audit: (userId, startTime, endTime, asOf) =>
|
|
806
|
+
audit: (userId, startTime, endTime, asOf, opTypes) =>
|
|
634
807
|
listAll(this, `/api/v1/users/${userId}/audit`, {
|
|
635
|
-
query: {
|
|
808
|
+
query: {
|
|
809
|
+
"start-time": startTime,
|
|
810
|
+
"end-time": endTime,
|
|
811
|
+
"as-of": asOf,
|
|
812
|
+
"op-types": opTypesParam(opTypes),
|
|
813
|
+
},
|
|
636
814
|
}),
|
|
637
815
|
/**
|
|
638
816
|
* Get a user by ID
|
|
@@ -640,8 +818,8 @@ class PlaidClient {
|
|
|
640
818
|
* @param {string} [asOf] - Temporal query timestamp
|
|
641
819
|
*/
|
|
642
820
|
get: (id, asOf) =>
|
|
643
|
-
this._request(
|
|
644
|
-
queryParams: {
|
|
821
|
+
this._request("GET", `/api/v1/users/${id}`, {
|
|
822
|
+
queryParams: { "as-of": asOf },
|
|
645
823
|
}),
|
|
646
824
|
/**
|
|
647
825
|
* Deactivate a user. Users are never hard-deleted: deactivation
|
|
@@ -652,7 +830,7 @@ class PlaidClient {
|
|
|
652
830
|
* @param {string} id - The resource ID
|
|
653
831
|
*/
|
|
654
832
|
delete: (id, auditMessage) =>
|
|
655
|
-
this._request(
|
|
833
|
+
this._request("DELETE", `/api/v1/users/${id}`, { auditMessage }),
|
|
656
834
|
/**
|
|
657
835
|
* Reactivate a deactivated user, restoring their ability to log in.
|
|
658
836
|
* Project memberships, vocab maintainerships, and API tokens removed
|
|
@@ -660,19 +838,27 @@ class PlaidClient {
|
|
|
660
838
|
* @param {string} id - The resource ID
|
|
661
839
|
*/
|
|
662
840
|
activate: (id, auditMessage) =>
|
|
663
|
-
this._request(
|
|
841
|
+
this._request("POST", `/api/v1/users/${id}/activate`, { auditMessage }),
|
|
664
842
|
/**
|
|
665
|
-
* Modify a user. Admins may change the
|
|
666
|
-
* status of any user. All other users may only modify their own
|
|
667
|
-
* or password.
|
|
668
|
-
*
|
|
843
|
+
* Modify a user. Admins may change the display name, password, and admin
|
|
844
|
+
* status of any user. All other users may only modify their own display
|
|
845
|
+
* name or password.
|
|
846
|
+
*
|
|
847
|
+
* A user's id is their email address and is fixed for the life of the
|
|
848
|
+
* account — it is what they log in with, so nothing can change it.
|
|
849
|
+
* @param {string} id - The resource ID (the user's email address)
|
|
669
850
|
* @param {string} [password] - New password
|
|
670
|
-
* @param {string} [
|
|
851
|
+
* @param {string} [displayName] - New display name
|
|
671
852
|
* @param {boolean} [isAdmin] - New admin status
|
|
672
853
|
*/
|
|
673
|
-
update: (id, password,
|
|
674
|
-
this._request(
|
|
675
|
-
|
|
854
|
+
update: (id, password, displayName, isAdmin, auditMessage) =>
|
|
855
|
+
this._request("PATCH", `/api/v1/users/${id}`, {
|
|
856
|
+
auditMessage,
|
|
857
|
+
body: bodyOf({
|
|
858
|
+
password,
|
|
859
|
+
"display-name": displayName,
|
|
860
|
+
"is-admin": isAdmin,
|
|
861
|
+
}),
|
|
676
862
|
}),
|
|
677
863
|
/**
|
|
678
864
|
* Build a URL for a user's profile picture, suitable for use directly as
|
|
@@ -692,7 +878,7 @@ class PlaidClient {
|
|
|
692
878
|
avatarUrl: (id, avatarHash) => {
|
|
693
879
|
if (avatarHash === null) return null;
|
|
694
880
|
const params = new URLSearchParams({ token: this.token });
|
|
695
|
-
if (avatarHash) params.set(
|
|
881
|
+
if (avatarHash) params.set("v", avatarHash);
|
|
696
882
|
return `${this.baseUrl}/api/v1/users/${id}/avatar?${params}`;
|
|
697
883
|
},
|
|
698
884
|
/**
|
|
@@ -701,7 +887,7 @@ class PlaidClient {
|
|
|
701
887
|
* @param {string} id - The user ID
|
|
702
888
|
*/
|
|
703
889
|
getAvatar: (id) =>
|
|
704
|
-
this._request(
|
|
890
|
+
this._request("GET", `/api/v1/users/${id}/avatar`, {
|
|
705
891
|
noBatch: true,
|
|
706
892
|
binaryResponse: true,
|
|
707
893
|
}),
|
|
@@ -715,9 +901,12 @@ class PlaidClient {
|
|
|
715
901
|
*/
|
|
716
902
|
setAvatar: (id, file, auditMessage) => {
|
|
717
903
|
const fd = new FormData();
|
|
718
|
-
fd.append(
|
|
719
|
-
return this._request(
|
|
720
|
-
|
|
904
|
+
fd.append("file", file);
|
|
905
|
+
return this._request("PUT", `/api/v1/users/${id}/avatar`, {
|
|
906
|
+
auditMessage,
|
|
907
|
+
body: fd,
|
|
908
|
+
formData: true,
|
|
909
|
+
noBatch: true,
|
|
721
910
|
});
|
|
722
911
|
},
|
|
723
912
|
/**
|
|
@@ -725,11 +914,72 @@ class PlaidClient {
|
|
|
725
914
|
* @param {string} id - The user ID
|
|
726
915
|
*/
|
|
727
916
|
deleteAvatar: (id, auditMessage) =>
|
|
728
|
-
this._request(
|
|
917
|
+
this._request("DELETE", `/api/v1/users/${id}/avatar`, {
|
|
918
|
+
auditMessage,
|
|
729
919
|
noBatch: true,
|
|
730
920
|
}),
|
|
731
921
|
};
|
|
732
922
|
|
|
923
|
+
this.userData = {
|
|
924
|
+
/**
|
|
925
|
+
* List a user's private data entries ({key, updatedAt}, plus value when
|
|
926
|
+
* includeValues). Owner or admin only.
|
|
927
|
+
* @param {string} userId
|
|
928
|
+
* @param {object} [opts]
|
|
929
|
+
* @param {string} [opts.prefix] - Only keys starting with this prefix
|
|
930
|
+
* @param {boolean} [opts.includeValues] - Also return each entry's value
|
|
931
|
+
*/
|
|
932
|
+
list: (userId, { prefix, includeValues } = {}) =>
|
|
933
|
+
this._request("GET", `/api/v1/users/${userId}/data`, {
|
|
934
|
+
queryParams: { prefix, "include-values": includeValues },
|
|
935
|
+
}),
|
|
936
|
+
/**
|
|
937
|
+
* Read one private data entry ({key, updatedAt, value}); 404 if absent.
|
|
938
|
+
* @param {string} userId
|
|
939
|
+
* @param {string} key
|
|
940
|
+
*/
|
|
941
|
+
get: (userId, key) =>
|
|
942
|
+
this._request(
|
|
943
|
+
"GET",
|
|
944
|
+
`/api/v1/users/${userId}/data/${encodeURIComponent(key)}`,
|
|
945
|
+
),
|
|
946
|
+
/**
|
|
947
|
+
* Create or replace one private data entry. `value` is any JSON (up to
|
|
948
|
+
* 1 MB), stored as sent. Not audited, not batchable.
|
|
949
|
+
*
|
|
950
|
+
* The server stores it verbatim, but this client recases object keys on
|
|
951
|
+
* the way out and back like any other body (`myKey` <-> `my-key`), so a
|
|
952
|
+
* value whose keys are camelCase round-trips unchanged while one keyed
|
|
953
|
+
* by arbitrary strings does not. Put such a map under a `metadata` key,
|
|
954
|
+
* which both clients pass through untouched.
|
|
955
|
+
* @param {string} userId
|
|
956
|
+
* @param {string} key
|
|
957
|
+
* @param {*} value
|
|
958
|
+
*/
|
|
959
|
+
put: (userId, key, value) =>
|
|
960
|
+
this._request(
|
|
961
|
+
"PUT",
|
|
962
|
+
`/api/v1/users/${userId}/data/${encodeURIComponent(key)}`,
|
|
963
|
+
{
|
|
964
|
+
body: value,
|
|
965
|
+
noBatch: true,
|
|
966
|
+
},
|
|
967
|
+
),
|
|
968
|
+
/**
|
|
969
|
+
* Delete one private data entry; 404 if absent.
|
|
970
|
+
* @param {string} userId
|
|
971
|
+
* @param {string} key
|
|
972
|
+
*/
|
|
973
|
+
delete: (userId, key) =>
|
|
974
|
+
this._request(
|
|
975
|
+
"DELETE",
|
|
976
|
+
`/api/v1/users/${userId}/data/${encodeURIComponent(key)}`,
|
|
977
|
+
{
|
|
978
|
+
noBatch: true,
|
|
979
|
+
},
|
|
980
|
+
),
|
|
981
|
+
};
|
|
982
|
+
|
|
733
983
|
this.apiTokens = {
|
|
734
984
|
/**
|
|
735
985
|
* List a user's named API tokens. Never includes the signed token
|
|
@@ -738,8 +988,7 @@ class PlaidClient {
|
|
|
738
988
|
* Cannot be used inside a batch (auto-paginates across requests); throws if called while batching — use listPage() for a single page in a batch.
|
|
739
989
|
* @param {string} userId - The user ID who owns the tokens
|
|
740
990
|
*/
|
|
741
|
-
list: (userId) =>
|
|
742
|
-
listAll(this, `/api/v1/users/${userId}/tokens`),
|
|
991
|
+
list: (userId) => listAll(this, `/api/v1/users/${userId}/tokens`),
|
|
743
992
|
/**
|
|
744
993
|
* Fetch a single page of a user's named API tokens.
|
|
745
994
|
* @param {string} userId - The user ID who owns the tokens
|
|
@@ -770,7 +1019,8 @@ class PlaidClient {
|
|
|
770
1019
|
* @returns {Promise<{id: string, name: string, token: string}>}
|
|
771
1020
|
*/
|
|
772
1021
|
create: (userId, name, auditMessage) =>
|
|
773
|
-
this._request(
|
|
1022
|
+
this._request("POST", `/api/v1/users/${userId}/tokens`, {
|
|
1023
|
+
auditMessage,
|
|
774
1024
|
body: bodyOf({ name }),
|
|
775
1025
|
}),
|
|
776
1026
|
/**
|
|
@@ -779,7 +1029,9 @@ class PlaidClient {
|
|
|
779
1029
|
* @param {string} tokenId - The token ID to revoke
|
|
780
1030
|
*/
|
|
781
1031
|
revoke: (userId, tokenId, auditMessage) =>
|
|
782
|
-
this._request(
|
|
1032
|
+
this._request("DELETE", `/api/v1/users/${userId}/tokens/${tokenId}`, {
|
|
1033
|
+
auditMessage,
|
|
1034
|
+
}),
|
|
783
1035
|
};
|
|
784
1036
|
|
|
785
1037
|
this.invites = {
|
|
@@ -794,7 +1046,9 @@ class PlaidClient {
|
|
|
794
1046
|
* @param {string} [opts.projectId] - List this project's invites instead of your own
|
|
795
1047
|
*/
|
|
796
1048
|
list: ({ projectId } = {}) =>
|
|
797
|
-
listAll(this,
|
|
1049
|
+
listAll(this, "/api/v1/invites", {
|
|
1050
|
+
query: { "project-id": projectId },
|
|
1051
|
+
}),
|
|
798
1052
|
/**
|
|
799
1053
|
* Fetch a single page of invites.
|
|
800
1054
|
* @param {object} [opts]
|
|
@@ -804,7 +1058,11 @@ class PlaidClient {
|
|
|
804
1058
|
* @returns {Promise<{entries: Array, nextCursor: (string|null)}>}
|
|
805
1059
|
*/
|
|
806
1060
|
listPage: ({ projectId, limit, cursor } = {}) =>
|
|
807
|
-
listPage(this,
|
|
1061
|
+
listPage(this, "/api/v1/invites", {
|
|
1062
|
+
limit,
|
|
1063
|
+
cursor,
|
|
1064
|
+
query: { "project-id": projectId },
|
|
1065
|
+
}),
|
|
808
1066
|
/**
|
|
809
1067
|
* Async-iterate invites page by page; yields each page's entries array.
|
|
810
1068
|
* @param {object} [opts]
|
|
@@ -814,7 +1072,10 @@ class PlaidClient {
|
|
|
814
1072
|
* @returns {AsyncGenerator<Array>}
|
|
815
1073
|
*/
|
|
816
1074
|
iterPages: ({ projectId, pageSize } = {}) =>
|
|
817
|
-
iterPages(this,
|
|
1075
|
+
iterPages(this, "/api/v1/invites", {
|
|
1076
|
+
pageSize,
|
|
1077
|
+
query: { "project-id": projectId },
|
|
1078
|
+
}),
|
|
818
1079
|
/**
|
|
819
1080
|
* Mint an invite. The returned `code` is shown ONLY here — it is never
|
|
820
1081
|
* stored and cannot be recovered, so build and hand off the link now.
|
|
@@ -822,23 +1083,46 @@ class PlaidClient {
|
|
|
822
1083
|
*
|
|
823
1084
|
* Admins may mint anything. A project maintainer may mint role grants on
|
|
824
1085
|
* projects they maintain, and nothing else: no admin grant, no grantless
|
|
825
|
-
* invite, no password resets
|
|
826
|
-
*
|
|
827
|
-
*
|
|
828
|
-
*
|
|
1086
|
+
* invite, no password resets — so for a non-admin, projectId/projectRole
|
|
1087
|
+
* are required in practice (403 without them).
|
|
1088
|
+
*
|
|
1089
|
+
* EVERY option is optional; `create()` with no arguments mints a
|
|
1090
|
+
* single-use signup link granting nothing but an account. Two pairing
|
|
1091
|
+
* rules the server enforces with a 400: projectId and projectRole must be
|
|
1092
|
+
* given TOGETHER, and targetUserId may not be combined with projectId,
|
|
1093
|
+
* grantAdmin, or a maxUses above 1.
|
|
1094
|
+
* @param {object} [opts]
|
|
1095
|
+
* @param {string} [opts.projectId] - Project the redeemer joins (requires projectRole)
|
|
1096
|
+
* @param {string} [opts.projectRole] - "reader" | "writer" | "maintainer" (requires projectId)
|
|
829
1097
|
* @param {boolean} [opts.grantAdmin] - Make the new account a global admin (admin only)
|
|
830
|
-
* @param {string} [opts.targetUserId] -
|
|
1098
|
+
* @param {string} [opts.targetUserId] - Password reset for that user instead of a signup; admin only, single-use, grants nothing
|
|
831
1099
|
* @param {number} [opts.maxUses] - How many accounts this link may create (default 1)
|
|
832
1100
|
* @param {number} [opts.ttlDays] - Days until it expires (default 14, max 365)
|
|
833
1101
|
* @param {string} [opts.note] - Human label shown in your invite list
|
|
834
1102
|
* @returns {Promise<{id: string, code: string, kind: string, status: string}>}
|
|
835
1103
|
*/
|
|
836
|
-
create: (
|
|
837
|
-
|
|
1104
|
+
create: (
|
|
1105
|
+
{
|
|
1106
|
+
projectId,
|
|
1107
|
+
projectRole,
|
|
1108
|
+
grantAdmin,
|
|
1109
|
+
targetUserId,
|
|
1110
|
+
maxUses,
|
|
1111
|
+
ttlDays,
|
|
1112
|
+
note,
|
|
1113
|
+
} = {},
|
|
1114
|
+
auditMessage,
|
|
1115
|
+
) =>
|
|
1116
|
+
this._request("POST", "/api/v1/invites", {
|
|
1117
|
+
auditMessage,
|
|
838
1118
|
body: bodyOf({
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
1119
|
+
"project-id": projectId,
|
|
1120
|
+
"project-role": projectRole,
|
|
1121
|
+
"grant-admin": grantAdmin,
|
|
1122
|
+
"target-user-id": targetUserId,
|
|
1123
|
+
"max-uses": maxUses,
|
|
1124
|
+
"ttl-days": ttlDays,
|
|
1125
|
+
note,
|
|
842
1126
|
}),
|
|
843
1127
|
}),
|
|
844
1128
|
/**
|
|
@@ -847,7 +1131,7 @@ class PlaidClient {
|
|
|
847
1131
|
* @param {string} id - The invite ID
|
|
848
1132
|
*/
|
|
849
1133
|
revoke: (id, auditMessage) =>
|
|
850
|
-
this._request(
|
|
1134
|
+
this._request("DELETE", `/api/v1/invites/${id}`, { auditMessage }),
|
|
851
1135
|
};
|
|
852
1136
|
|
|
853
1137
|
this.tokenLayers = {
|
|
@@ -857,7 +1141,8 @@ class PlaidClient {
|
|
|
857
1141
|
* @param {string} direction - The direction ("up" or "down")
|
|
858
1142
|
*/
|
|
859
1143
|
shift: (tokenLayerId, direction, auditMessage) =>
|
|
860
|
-
this._request(
|
|
1144
|
+
this._request("POST", `/api/v1/token-layers/${tokenLayerId}/shift`, {
|
|
1145
|
+
auditMessage,
|
|
861
1146
|
body: bodyOf({ direction }),
|
|
862
1147
|
}),
|
|
863
1148
|
/**
|
|
@@ -867,9 +1152,21 @@ class PlaidClient {
|
|
|
867
1152
|
* @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.
|
|
868
1153
|
* @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).
|
|
869
1154
|
*/
|
|
870
|
-
create: (
|
|
871
|
-
|
|
872
|
-
|
|
1155
|
+
create: (
|
|
1156
|
+
textLayerId,
|
|
1157
|
+
name,
|
|
1158
|
+
overlapMode,
|
|
1159
|
+
parentTokenLayerId,
|
|
1160
|
+
auditMessage,
|
|
1161
|
+
) =>
|
|
1162
|
+
this._request("POST", "/api/v1/token-layers", {
|
|
1163
|
+
auditMessage,
|
|
1164
|
+
body: bodyOf({
|
|
1165
|
+
"text-layer-id": textLayerId,
|
|
1166
|
+
name,
|
|
1167
|
+
"overlap-mode": overlapMode,
|
|
1168
|
+
"parent-token-layer-id": parentTokenLayerId,
|
|
1169
|
+
}),
|
|
873
1170
|
}),
|
|
874
1171
|
/**
|
|
875
1172
|
* Set a configuration value for a layer in an editor namespace.
|
|
@@ -878,10 +1175,18 @@ class PlaidClient {
|
|
|
878
1175
|
* @param {string} configKey - The config key
|
|
879
1176
|
* @param {any} configValue - Configuration value to set
|
|
880
1177
|
*/
|
|
881
|
-
setConfig: (
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
1178
|
+
setConfig: (
|
|
1179
|
+
tokenLayerId,
|
|
1180
|
+
namespace,
|
|
1181
|
+
configKey,
|
|
1182
|
+
configValue,
|
|
1183
|
+
auditMessage,
|
|
1184
|
+
) =>
|
|
1185
|
+
this._request(
|
|
1186
|
+
"PUT",
|
|
1187
|
+
`/api/v1/token-layers/${tokenLayerId}/config/${namespace}/${configKey}`,
|
|
1188
|
+
{ auditMessage, rawBody: configValue, skipResponseTransform: true },
|
|
1189
|
+
),
|
|
885
1190
|
/**
|
|
886
1191
|
* Remove a configuration value for a layer.
|
|
887
1192
|
* @param {string} tokenLayerId - The token layer ID
|
|
@@ -889,31 +1194,36 @@ class PlaidClient {
|
|
|
889
1194
|
* @param {string} configKey - The config key
|
|
890
1195
|
*/
|
|
891
1196
|
deleteConfig: (tokenLayerId, namespace, configKey, auditMessage) =>
|
|
892
|
-
this._request(
|
|
893
|
-
|
|
894
|
-
|
|
1197
|
+
this._request(
|
|
1198
|
+
"DELETE",
|
|
1199
|
+
`/api/v1/token-layers/${tokenLayerId}/config/${namespace}/${configKey}`,
|
|
1200
|
+
{ auditMessage, skipResponseTransform: true },
|
|
1201
|
+
),
|
|
895
1202
|
/**
|
|
896
1203
|
* Get a token layer by ID.
|
|
897
1204
|
* @param {string} tokenLayerId - The token layer ID
|
|
898
1205
|
* @param {string} [asOf] - Temporal query timestamp
|
|
899
1206
|
*/
|
|
900
1207
|
get: (tokenLayerId, asOf) =>
|
|
901
|
-
this._request(
|
|
902
|
-
queryParams: {
|
|
1208
|
+
this._request("GET", `/api/v1/token-layers/${tokenLayerId}`, {
|
|
1209
|
+
queryParams: { "as-of": asOf },
|
|
903
1210
|
}),
|
|
904
1211
|
/**
|
|
905
1212
|
* Delete a token layer.
|
|
906
1213
|
* @param {string} tokenLayerId - The token layer ID
|
|
907
1214
|
*/
|
|
908
1215
|
delete: (tokenLayerId, auditMessage) =>
|
|
909
|
-
this._request(
|
|
1216
|
+
this._request("DELETE", `/api/v1/token-layers/${tokenLayerId}`, {
|
|
1217
|
+
auditMessage,
|
|
1218
|
+
}),
|
|
910
1219
|
/**
|
|
911
1220
|
* Update a token layer's name.
|
|
912
1221
|
* @param {string} tokenLayerId - The token layer ID
|
|
913
1222
|
* @param {string} name - The name
|
|
914
1223
|
*/
|
|
915
1224
|
update: (tokenLayerId, name, auditMessage) =>
|
|
916
|
-
this._request(
|
|
1225
|
+
this._request("PATCH", `/api/v1/token-layers/${tokenLayerId}`, {
|
|
1226
|
+
auditMessage,
|
|
917
1227
|
body: bodyOf({ name }),
|
|
918
1228
|
}),
|
|
919
1229
|
};
|
|
@@ -925,29 +1235,33 @@ class PlaidClient {
|
|
|
925
1235
|
* @param {string} [asOf] - Temporal query timestamp
|
|
926
1236
|
*/
|
|
927
1237
|
checkLock: (documentId, asOf) =>
|
|
928
|
-
this._request(
|
|
929
|
-
queryParams: {
|
|
1238
|
+
this._request("GET", `/api/v1/documents/${documentId}/lock`, {
|
|
1239
|
+
queryParams: { "as-of": asOf },
|
|
930
1240
|
}),
|
|
931
1241
|
/**
|
|
932
1242
|
* Acquire or refresh a document lock
|
|
933
1243
|
* @param {string} documentId - The document ID
|
|
934
1244
|
*/
|
|
935
1245
|
acquireLock: (documentId, auditMessage) =>
|
|
936
|
-
this._request(
|
|
1246
|
+
this._request("POST", `/api/v1/documents/${documentId}/lock`, {
|
|
1247
|
+
auditMessage,
|
|
1248
|
+
}),
|
|
937
1249
|
/**
|
|
938
1250
|
* Release a document lock
|
|
939
1251
|
* @param {string} documentId - The document ID
|
|
940
1252
|
*/
|
|
941
1253
|
releaseLock: (documentId, auditMessage) =>
|
|
942
|
-
this._request(
|
|
1254
|
+
this._request("DELETE", `/api/v1/documents/${documentId}/lock`, {
|
|
1255
|
+
auditMessage,
|
|
1256
|
+
}),
|
|
943
1257
|
/**
|
|
944
|
-
* Get media file for a document
|
|
1258
|
+
* Get the media file for a document. Media is not versioned, so there is
|
|
1259
|
+
* no as-of form: the route refuses the parameter. Prefer the document's
|
|
1260
|
+
* own `mediaUrl`, which carries the file's version for caching.
|
|
945
1261
|
* @param {string} documentId - The document ID
|
|
946
|
-
* @param {string} [asOf] - Temporal query timestamp
|
|
947
1262
|
*/
|
|
948
|
-
getMedia: (documentId
|
|
949
|
-
this._request(
|
|
950
|
-
queryParams: { 'as-of': asOf },
|
|
1263
|
+
getMedia: (documentId) =>
|
|
1264
|
+
this._request("GET", `/api/v1/documents/${documentId}/media`, {
|
|
951
1265
|
noBatch: true,
|
|
952
1266
|
binaryResponse: true,
|
|
953
1267
|
}),
|
|
@@ -955,12 +1269,18 @@ class PlaidClient {
|
|
|
955
1269
|
* Upload a media file for a document. Uses Apache Tika for content validation.
|
|
956
1270
|
* @param {string} documentId - The document ID
|
|
957
1271
|
* @param {File} file - The file to upload
|
|
1272
|
+
* @param {string} [auditMessage] - Custom audit-log message for this write
|
|
1273
|
+
* @param {object} [options] - `{ onProgress }`: called with `{ loaded, total }` (bytes) as the file goes up. In a browser the upload then travels by XMLHttpRequest, and the request timeout only fires when the upload stalls, not on total time.
|
|
958
1274
|
*/
|
|
959
|
-
uploadMedia: (documentId, file, auditMessage) => {
|
|
1275
|
+
uploadMedia: (documentId, file, auditMessage, { onProgress } = {}) => {
|
|
960
1276
|
const fd = new FormData();
|
|
961
|
-
fd.append(
|
|
962
|
-
return this._request(
|
|
963
|
-
|
|
1277
|
+
fd.append("file", file);
|
|
1278
|
+
return this._request("PUT", `/api/v1/documents/${documentId}/media`, {
|
|
1279
|
+
auditMessage,
|
|
1280
|
+
body: fd,
|
|
1281
|
+
formData: true,
|
|
1282
|
+
noBatch: true,
|
|
1283
|
+
onUploadProgress: onProgress,
|
|
964
1284
|
});
|
|
965
1285
|
},
|
|
966
1286
|
/**
|
|
@@ -968,7 +1288,8 @@ class PlaidClient {
|
|
|
968
1288
|
* @param {string} documentId - The document ID
|
|
969
1289
|
*/
|
|
970
1290
|
deleteMedia: (documentId, auditMessage) =>
|
|
971
|
-
this._request(
|
|
1291
|
+
this._request("DELETE", `/api/v1/documents/${documentId}/media`, {
|
|
1292
|
+
auditMessage,
|
|
972
1293
|
noBatch: true,
|
|
973
1294
|
}),
|
|
974
1295
|
/**
|
|
@@ -977,15 +1298,18 @@ class PlaidClient {
|
|
|
977
1298
|
* @param {any} body - The request body
|
|
978
1299
|
*/
|
|
979
1300
|
setMetadata: (documentId, body, auditMessage) =>
|
|
980
|
-
this._request(
|
|
981
|
-
|
|
1301
|
+
this._request("PUT", `/api/v1/documents/${documentId}/metadata`, {
|
|
1302
|
+
auditMessage,
|
|
1303
|
+
rawBody: body,
|
|
1304
|
+
skipResponseTransform: true,
|
|
982
1305
|
}),
|
|
983
1306
|
/**
|
|
984
1307
|
* Remove all metadata from a document.
|
|
985
1308
|
* @param {string} documentId - The document ID
|
|
986
1309
|
*/
|
|
987
1310
|
deleteMetadata: (documentId, auditMessage) =>
|
|
988
|
-
this._request(
|
|
1311
|
+
this._request("DELETE", `/api/v1/documents/${documentId}/metadata`, {
|
|
1312
|
+
auditMessage,
|
|
989
1313
|
skipResponseTransform: true,
|
|
990
1314
|
}),
|
|
991
1315
|
/**
|
|
@@ -994,8 +1318,10 @@ class PlaidClient {
|
|
|
994
1318
|
* @param {any} body - The metadata patch
|
|
995
1319
|
*/
|
|
996
1320
|
patchMetadata: (documentId, body, auditMessage) =>
|
|
997
|
-
this._request(
|
|
998
|
-
|
|
1321
|
+
this._request("PATCH", `/api/v1/documents/${documentId}/metadata`, {
|
|
1322
|
+
auditMessage,
|
|
1323
|
+
rawBody: body,
|
|
1324
|
+
skipResponseTransform: true,
|
|
999
1325
|
}),
|
|
1000
1326
|
/**
|
|
1001
1327
|
* Get audit log for a document. Transparently follows pagination cursors
|
|
@@ -1005,34 +1331,78 @@ class PlaidClient {
|
|
|
1005
1331
|
* @param {string} [startTime] - Start of time range
|
|
1006
1332
|
* @param {string} [endTime] - End of time range
|
|
1007
1333
|
* @param {string} [asOf] - Temporal query timestamp
|
|
1334
|
+
* @param {string[]|string} [opTypes] - Only return operations of these
|
|
1335
|
+
* types, spelled as in an entry's `op/type` (e.g.
|
|
1336
|
+
* `['span-layer/create', 'span-layer/delete']`). An entry appears when
|
|
1337
|
+
* one of its operations matches, carrying only the ones that did.
|
|
1008
1338
|
*/
|
|
1009
|
-
audit: (documentId, startTime, endTime, asOf) =>
|
|
1339
|
+
audit: (documentId, startTime, endTime, asOf, opTypes) =>
|
|
1010
1340
|
listAll(this, `/api/v1/documents/${documentId}/audit`, {
|
|
1011
|
-
query: {
|
|
1341
|
+
query: {
|
|
1342
|
+
"start-time": startTime,
|
|
1343
|
+
"end-time": endTime,
|
|
1344
|
+
"as-of": asOf,
|
|
1345
|
+
"op-types": opTypesParam(opTypes),
|
|
1346
|
+
},
|
|
1347
|
+
}),
|
|
1348
|
+
/**
|
|
1349
|
+
* Restore a document to its state at an earlier time, as one
|
|
1350
|
+
* operation: what was deleted since then comes back under its original
|
|
1351
|
+
* id, what was added since is removed, and what changed is set back,
|
|
1352
|
+
* across every layer. A layer deleted since then, or a vocabulary entry
|
|
1353
|
+
* that no longer exists, is skipped and reported under `skipped`.
|
|
1354
|
+
* Resolves to a summary of the changes. Maintainers only.
|
|
1355
|
+
* @param {string} documentId - The document ID
|
|
1356
|
+
* @param {string} asOf - The moment to go back to (ISO-8601 instant),
|
|
1357
|
+
* typically a history entry's `endTime`
|
|
1358
|
+
* @param {object} [options] - `{ dryRun }`: with `dryRun` true nothing
|
|
1359
|
+
* is written and the summary says what would change
|
|
1360
|
+
* @param {string} [auditMessage] - Custom audit message for this operation
|
|
1361
|
+
*/
|
|
1362
|
+
restore: (documentId, asOf, { dryRun } = {}, auditMessage) =>
|
|
1363
|
+
this._request("POST", `/api/v1/documents/${documentId}/restore`, {
|
|
1364
|
+
queryParams: { "as-of": asOf, "dry-run": dryRun ? "true" : undefined },
|
|
1365
|
+
auditMessage,
|
|
1012
1366
|
}),
|
|
1013
1367
|
/**
|
|
1014
1368
|
* Get a document. Set `includeBody` to true to include all data.
|
|
1369
|
+
*
|
|
1370
|
+
* `layers` narrows a body read to the layers you name (ids of any kind:
|
|
1371
|
+
* text, token, span, or relation). A layer comes back when it is named
|
|
1372
|
+
* or is an ancestor of a named layer, and carries its own
|
|
1373
|
+
* texts/tokens/spans/relations/vocabs only when it is itself named — so
|
|
1374
|
+
* name the text layer too if you also want the text body. An id that is
|
|
1375
|
+
* not a layer of this document's project is an error, not a quietly
|
|
1376
|
+
* smaller response. Requires `includeBody`.
|
|
1015
1377
|
* @param {string} documentId - The document ID
|
|
1016
1378
|
* @param {boolean} [includeBody] - Include document body data
|
|
1017
1379
|
* @param {string} [asOf] - Temporal query timestamp
|
|
1380
|
+
* @param {string[]|string} [layers] - Layer ids to restrict a body read to
|
|
1018
1381
|
*/
|
|
1019
|
-
get: (documentId, includeBody, asOf) =>
|
|
1020
|
-
this._request(
|
|
1021
|
-
queryParams: {
|
|
1382
|
+
get: (documentId, includeBody, asOf, layers) =>
|
|
1383
|
+
this._request("GET", `/api/v1/documents/${documentId}`, {
|
|
1384
|
+
queryParams: {
|
|
1385
|
+
"include-body": includeBody,
|
|
1386
|
+
"as-of": asOf,
|
|
1387
|
+
layers: layersParam(layers),
|
|
1388
|
+
},
|
|
1022
1389
|
}),
|
|
1023
1390
|
/**
|
|
1024
1391
|
* Delete a document and all data contained.
|
|
1025
1392
|
* @param {string} documentId - The document ID
|
|
1026
1393
|
*/
|
|
1027
1394
|
delete: (documentId, auditMessage) =>
|
|
1028
|
-
this._request(
|
|
1395
|
+
this._request("DELETE", `/api/v1/documents/${documentId}`, {
|
|
1396
|
+
auditMessage,
|
|
1397
|
+
}),
|
|
1029
1398
|
/**
|
|
1030
1399
|
* Update a document's name.
|
|
1031
1400
|
* @param {string} documentId - The document ID
|
|
1032
1401
|
* @param {string} name - The name
|
|
1033
1402
|
*/
|
|
1034
1403
|
update: (documentId, name, auditMessage) =>
|
|
1035
|
-
this._request(
|
|
1404
|
+
this._request("PATCH", `/api/v1/documents/${documentId}`, {
|
|
1405
|
+
auditMessage,
|
|
1036
1406
|
body: bodyOf({ name }),
|
|
1037
1407
|
}),
|
|
1038
1408
|
/**
|
|
@@ -1042,8 +1412,9 @@ class PlaidClient {
|
|
|
1042
1412
|
* @param {any} [metadata] - Metadata map. Omit to leave unset; pass null to send JSON null.
|
|
1043
1413
|
*/
|
|
1044
1414
|
create: (projectId, name, metadata, auditMessage) =>
|
|
1045
|
-
this._request(
|
|
1046
|
-
|
|
1415
|
+
this._request("POST", "/api/v1/documents", {
|
|
1416
|
+
auditMessage,
|
|
1417
|
+
body: bodyOf({ "project-id": projectId, name, metadata }),
|
|
1047
1418
|
}),
|
|
1048
1419
|
};
|
|
1049
1420
|
|
|
@@ -1054,28 +1425,36 @@ class PlaidClient {
|
|
|
1054
1425
|
* @param {string} userId - The user ID
|
|
1055
1426
|
*/
|
|
1056
1427
|
addWriter: (id, userId, auditMessage) =>
|
|
1057
|
-
this._request(
|
|
1428
|
+
this._request("POST", `/api/v1/projects/${id}/writers/${userId}`, {
|
|
1429
|
+
auditMessage,
|
|
1430
|
+
}),
|
|
1058
1431
|
/**
|
|
1059
1432
|
* Remove a user's writer privileges for this project.
|
|
1060
1433
|
* @param {string} id - The resource ID
|
|
1061
1434
|
* @param {string} userId - The user ID
|
|
1062
1435
|
*/
|
|
1063
1436
|
removeWriter: (id, userId, auditMessage) =>
|
|
1064
|
-
this._request(
|
|
1437
|
+
this._request("DELETE", `/api/v1/projects/${id}/writers/${userId}`, {
|
|
1438
|
+
auditMessage,
|
|
1439
|
+
}),
|
|
1065
1440
|
/**
|
|
1066
1441
|
* Set a user's access level to read-only for this project.
|
|
1067
1442
|
* @param {string} id - The resource ID
|
|
1068
1443
|
* @param {string} userId - The user ID
|
|
1069
1444
|
*/
|
|
1070
1445
|
addReader: (id, userId, auditMessage) =>
|
|
1071
|
-
this._request(
|
|
1446
|
+
this._request("POST", `/api/v1/projects/${id}/readers/${userId}`, {
|
|
1447
|
+
auditMessage,
|
|
1448
|
+
}),
|
|
1072
1449
|
/**
|
|
1073
1450
|
* Remove a user's reader privileges for this project.
|
|
1074
1451
|
* @param {string} id - The resource ID
|
|
1075
1452
|
* @param {string} userId - The user ID
|
|
1076
1453
|
*/
|
|
1077
1454
|
removeReader: (id, userId, auditMessage) =>
|
|
1078
|
-
this._request(
|
|
1455
|
+
this._request("DELETE", `/api/v1/projects/${id}/readers/${userId}`, {
|
|
1456
|
+
auditMessage,
|
|
1457
|
+
}),
|
|
1079
1458
|
/**
|
|
1080
1459
|
* Set a configuration value for a project in an editor namespace.
|
|
1081
1460
|
* @param {string} id - The resource ID
|
|
@@ -1084,9 +1463,11 @@ class PlaidClient {
|
|
|
1084
1463
|
* @param {any} configValue - Configuration value to set
|
|
1085
1464
|
*/
|
|
1086
1465
|
setConfig: (id, namespace, configKey, configValue, auditMessage) =>
|
|
1087
|
-
this._request(
|
|
1088
|
-
|
|
1089
|
-
|
|
1466
|
+
this._request(
|
|
1467
|
+
"PUT",
|
|
1468
|
+
`/api/v1/projects/${id}/config/${namespace}/${configKey}`,
|
|
1469
|
+
{ auditMessage, rawBody: configValue, skipResponseTransform: true },
|
|
1470
|
+
),
|
|
1090
1471
|
/**
|
|
1091
1472
|
* Remove a configuration value for a project.
|
|
1092
1473
|
* @param {string} id - The resource ID
|
|
@@ -1094,23 +1475,31 @@ class PlaidClient {
|
|
|
1094
1475
|
* @param {string} configKey - The config key
|
|
1095
1476
|
*/
|
|
1096
1477
|
deleteConfig: (id, namespace, configKey, auditMessage) =>
|
|
1097
|
-
this._request(
|
|
1098
|
-
|
|
1099
|
-
|
|
1478
|
+
this._request(
|
|
1479
|
+
"DELETE",
|
|
1480
|
+
`/api/v1/projects/${id}/config/${namespace}/${configKey}`,
|
|
1481
|
+
{ auditMessage, skipResponseTransform: true },
|
|
1482
|
+
),
|
|
1100
1483
|
/**
|
|
1101
1484
|
* Assign a user as a maintainer for this project.
|
|
1102
1485
|
* @param {string} id - The resource ID
|
|
1103
1486
|
* @param {string} userId - The user ID
|
|
1104
1487
|
*/
|
|
1105
1488
|
addMaintainer: (id, userId, auditMessage) =>
|
|
1106
|
-
this._request(
|
|
1489
|
+
this._request("POST", `/api/v1/projects/${id}/maintainers/${userId}`, {
|
|
1490
|
+
auditMessage,
|
|
1491
|
+
}),
|
|
1107
1492
|
/**
|
|
1108
1493
|
* Remove a user's maintainer privileges for this project.
|
|
1109
1494
|
* @param {string} id - The resource ID
|
|
1110
1495
|
* @param {string} userId - The user ID
|
|
1111
1496
|
*/
|
|
1112
1497
|
removeMaintainer: (id, userId, auditMessage) =>
|
|
1113
|
-
this._request(
|
|
1498
|
+
this._request(
|
|
1499
|
+
"DELETE",
|
|
1500
|
+
`/api/v1/projects/${id}/maintainers/${userId}`,
|
|
1501
|
+
{ auditMessage },
|
|
1502
|
+
),
|
|
1114
1503
|
/**
|
|
1115
1504
|
* Get audit log for a project. Transparently follows pagination cursors
|
|
1116
1505
|
* and returns the full flat array.
|
|
@@ -1119,10 +1508,33 @@ class PlaidClient {
|
|
|
1119
1508
|
* @param {string} [startTime] - Start of time range
|
|
1120
1509
|
* @param {string} [endTime] - End of time range
|
|
1121
1510
|
* @param {string} [asOf] - Temporal query timestamp
|
|
1511
|
+
* @param {string[]|string} [opTypes] - Only return operations of these
|
|
1512
|
+
* types, spelled as in an entry's `op/type` (e.g.
|
|
1513
|
+
* `['span-layer/create', 'span-layer/delete']`). An entry appears when
|
|
1514
|
+
* one of its operations matches, carrying only the ones that did.
|
|
1122
1515
|
*/
|
|
1123
|
-
audit: (projectId, startTime, endTime, asOf) =>
|
|
1516
|
+
audit: (projectId, startTime, endTime, asOf, opTypes) =>
|
|
1124
1517
|
listAll(this, `/api/v1/projects/${projectId}/audit`, {
|
|
1125
|
-
query: {
|
|
1518
|
+
query: {
|
|
1519
|
+
"start-time": startTime,
|
|
1520
|
+
"end-time": endTime,
|
|
1521
|
+
"as-of": asOf,
|
|
1522
|
+
"op-types": opTypesParam(opTypes),
|
|
1523
|
+
},
|
|
1524
|
+
}),
|
|
1525
|
+
/**
|
|
1526
|
+
* When the calling user last wrote to each document in a project, as a
|
|
1527
|
+
* `{documentId: timestamp}` map. Documents they have never written to
|
|
1528
|
+
* are absent. One request covers a whole document list.
|
|
1529
|
+
*
|
|
1530
|
+
* The response is NOT key-transformed: its keys are document ids, and
|
|
1531
|
+
* camelCasing would mangle the hyphens in a UUID.
|
|
1532
|
+
* @param {string} projectId - The project ID
|
|
1533
|
+
* @returns {Promise<Object<string, string>>}
|
|
1534
|
+
*/
|
|
1535
|
+
myLastEdits: (projectId) =>
|
|
1536
|
+
this._request("GET", `/api/v1/projects/${projectId}/audit/last-edits`, {
|
|
1537
|
+
skipResponseTransform: true,
|
|
1126
1538
|
}),
|
|
1127
1539
|
/**
|
|
1128
1540
|
* Link a vocabulary to a project.
|
|
@@ -1130,14 +1542,18 @@ class PlaidClient {
|
|
|
1130
1542
|
* @param {string} vocabId - The vocab layer ID
|
|
1131
1543
|
*/
|
|
1132
1544
|
linkVocab: (id, vocabId, auditMessage) =>
|
|
1133
|
-
this._request(
|
|
1545
|
+
this._request("POST", `/api/v1/projects/${id}/vocabs/${vocabId}`, {
|
|
1546
|
+
auditMessage,
|
|
1547
|
+
}),
|
|
1134
1548
|
/**
|
|
1135
1549
|
* Unlink a vocabulary from a project.
|
|
1136
1550
|
* @param {string} id - The resource ID
|
|
1137
1551
|
* @param {string} vocabId - The vocab layer ID
|
|
1138
1552
|
*/
|
|
1139
1553
|
unlinkVocab: (id, vocabId, auditMessage) =>
|
|
1140
|
-
this._request(
|
|
1554
|
+
this._request("DELETE", `/api/v1/projects/${id}/vocabs/${vocabId}`, {
|
|
1555
|
+
auditMessage,
|
|
1556
|
+
}),
|
|
1141
1557
|
/**
|
|
1142
1558
|
* Get a project by ID. To fetch the project's documents, use
|
|
1143
1559
|
* listDocuments(id) — the include-documents flag has been removed.
|
|
@@ -1145,8 +1561,8 @@ class PlaidClient {
|
|
|
1145
1561
|
* @param {string} [asOf] - Temporal query timestamp
|
|
1146
1562
|
*/
|
|
1147
1563
|
get: (id, asOf) =>
|
|
1148
|
-
this._request(
|
|
1149
|
-
queryParams: {
|
|
1564
|
+
this._request("GET", `/api/v1/projects/${id}`, {
|
|
1565
|
+
queryParams: { "as-of": asOf },
|
|
1150
1566
|
}),
|
|
1151
1567
|
/**
|
|
1152
1568
|
* List all documents in a project. Transparently follows pagination
|
|
@@ -1157,8 +1573,7 @@ class PlaidClient {
|
|
|
1157
1573
|
* server rejects `?as-of=` on the documents-list route with a 400.
|
|
1158
1574
|
* @param {string} id - The project ID
|
|
1159
1575
|
*/
|
|
1160
|
-
listDocuments: (id) =>
|
|
1161
|
-
listAll(this, `/api/v1/projects/${id}/documents`),
|
|
1576
|
+
listDocuments: (id) => listAll(this, `/api/v1/projects/${id}/documents`),
|
|
1162
1577
|
/**
|
|
1163
1578
|
* Fetch a single page of a project's documents.
|
|
1164
1579
|
*
|
|
@@ -1198,14 +1613,18 @@ class PlaidClient {
|
|
|
1198
1613
|
* @param {number} [options.timeout=0] - Per-request timeout in ms (0/null disables)
|
|
1199
1614
|
*/
|
|
1200
1615
|
delete: (id, auditMessage, { timeout = 0 } = {}) =>
|
|
1201
|
-
this._request(
|
|
1616
|
+
this._request("DELETE", `/api/v1/projects/${id}`, {
|
|
1617
|
+
auditMessage,
|
|
1618
|
+
timeout,
|
|
1619
|
+
}),
|
|
1202
1620
|
/**
|
|
1203
1621
|
* Update a project's name.
|
|
1204
1622
|
* @param {string} id - The resource ID
|
|
1205
1623
|
* @param {string} name - The name
|
|
1206
1624
|
*/
|
|
1207
1625
|
update: (id, name, auditMessage) =>
|
|
1208
|
-
this._request(
|
|
1626
|
+
this._request("PATCH", `/api/v1/projects/${id}`, {
|
|
1627
|
+
auditMessage,
|
|
1209
1628
|
body: bodyOf({ name }),
|
|
1210
1629
|
}),
|
|
1211
1630
|
/**
|
|
@@ -1215,7 +1634,7 @@ class PlaidClient {
|
|
|
1215
1634
|
* @param {string} [asOf] - Temporal query timestamp
|
|
1216
1635
|
*/
|
|
1217
1636
|
list: (asOf) =>
|
|
1218
|
-
listAll(this,
|
|
1637
|
+
listAll(this, "/api/v1/projects", { query: { "as-of": asOf } }),
|
|
1219
1638
|
/**
|
|
1220
1639
|
* Fetch a single page of projects.
|
|
1221
1640
|
* @param {object} [opts]
|
|
@@ -1225,7 +1644,11 @@ class PlaidClient {
|
|
|
1225
1644
|
* @returns {Promise<{entries: Array, nextCursor: (string|null)}>}
|
|
1226
1645
|
*/
|
|
1227
1646
|
listPage: ({ limit, cursor, asOf } = {}) =>
|
|
1228
|
-
listPage(this,
|
|
1647
|
+
listPage(this, "/api/v1/projects", {
|
|
1648
|
+
limit,
|
|
1649
|
+
cursor,
|
|
1650
|
+
query: { "as-of": asOf },
|
|
1651
|
+
}),
|
|
1229
1652
|
/**
|
|
1230
1653
|
* Async-iterate projects page by page; yields each page's entries array.
|
|
1231
1654
|
* @param {object} [opts]
|
|
@@ -1235,13 +1658,17 @@ class PlaidClient {
|
|
|
1235
1658
|
* @returns {AsyncGenerator<Array>}
|
|
1236
1659
|
*/
|
|
1237
1660
|
iterPages: ({ pageSize, asOf } = {}) =>
|
|
1238
|
-
iterPages(this,
|
|
1661
|
+
iterPages(this, "/api/v1/projects", {
|
|
1662
|
+
pageSize,
|
|
1663
|
+
query: { "as-of": asOf },
|
|
1664
|
+
}),
|
|
1239
1665
|
/**
|
|
1240
1666
|
* Create a new project. Note: this also registers the user as a maintainer.
|
|
1241
1667
|
* @param {string} name - The name
|
|
1242
1668
|
*/
|
|
1243
1669
|
create: (name, auditMessage) =>
|
|
1244
|
-
this._request(
|
|
1670
|
+
this._request("POST", "/api/v1/projects", {
|
|
1671
|
+
auditMessage,
|
|
1245
1672
|
body: bodyOf({ name }),
|
|
1246
1673
|
}),
|
|
1247
1674
|
};
|
|
@@ -1254,10 +1681,18 @@ class PlaidClient {
|
|
|
1254
1681
|
* @param {string} configKey - The config key
|
|
1255
1682
|
* @param {any} configValue - Configuration value to set
|
|
1256
1683
|
*/
|
|
1257
|
-
setConfig: (
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1684
|
+
setConfig: (
|
|
1685
|
+
textLayerId,
|
|
1686
|
+
namespace,
|
|
1687
|
+
configKey,
|
|
1688
|
+
configValue,
|
|
1689
|
+
auditMessage,
|
|
1690
|
+
) =>
|
|
1691
|
+
this._request(
|
|
1692
|
+
"PUT",
|
|
1693
|
+
`/api/v1/text-layers/${textLayerId}/config/${namespace}/${configKey}`,
|
|
1694
|
+
{ auditMessage, rawBody: configValue, skipResponseTransform: true },
|
|
1695
|
+
),
|
|
1261
1696
|
/**
|
|
1262
1697
|
* Remove a configuration value for a layer.
|
|
1263
1698
|
* @param {string} textLayerId - The text layer ID
|
|
@@ -1265,31 +1700,36 @@ class PlaidClient {
|
|
|
1265
1700
|
* @param {string} configKey - The config key
|
|
1266
1701
|
*/
|
|
1267
1702
|
deleteConfig: (textLayerId, namespace, configKey, auditMessage) =>
|
|
1268
|
-
this._request(
|
|
1269
|
-
|
|
1270
|
-
|
|
1703
|
+
this._request(
|
|
1704
|
+
"DELETE",
|
|
1705
|
+
`/api/v1/text-layers/${textLayerId}/config/${namespace}/${configKey}`,
|
|
1706
|
+
{ auditMessage, skipResponseTransform: true },
|
|
1707
|
+
),
|
|
1271
1708
|
/**
|
|
1272
1709
|
* Get a text layer by ID.
|
|
1273
1710
|
* @param {string} textLayerId - The text layer ID
|
|
1274
1711
|
* @param {string} [asOf] - Temporal query timestamp
|
|
1275
1712
|
*/
|
|
1276
1713
|
get: (textLayerId, asOf) =>
|
|
1277
|
-
this._request(
|
|
1278
|
-
queryParams: {
|
|
1714
|
+
this._request("GET", `/api/v1/text-layers/${textLayerId}`, {
|
|
1715
|
+
queryParams: { "as-of": asOf },
|
|
1279
1716
|
}),
|
|
1280
1717
|
/**
|
|
1281
1718
|
* Delete a text layer.
|
|
1282
1719
|
* @param {string} textLayerId - The text layer ID
|
|
1283
1720
|
*/
|
|
1284
1721
|
delete: (textLayerId, auditMessage) =>
|
|
1285
|
-
this._request(
|
|
1722
|
+
this._request("DELETE", `/api/v1/text-layers/${textLayerId}`, {
|
|
1723
|
+
auditMessage,
|
|
1724
|
+
}),
|
|
1286
1725
|
/**
|
|
1287
1726
|
* Update a text layer's name.
|
|
1288
1727
|
* @param {string} textLayerId - The text layer ID
|
|
1289
1728
|
* @param {string} name - The name
|
|
1290
1729
|
*/
|
|
1291
1730
|
update: (textLayerId, name, auditMessage) =>
|
|
1292
|
-
this._request(
|
|
1731
|
+
this._request("PATCH", `/api/v1/text-layers/${textLayerId}`, {
|
|
1732
|
+
auditMessage,
|
|
1293
1733
|
body: bodyOf({ name }),
|
|
1294
1734
|
}),
|
|
1295
1735
|
/**
|
|
@@ -1298,7 +1738,8 @@ class PlaidClient {
|
|
|
1298
1738
|
* @param {string} direction - The direction ("up" or "down")
|
|
1299
1739
|
*/
|
|
1300
1740
|
shift: (textLayerId, direction, auditMessage) =>
|
|
1301
|
-
this._request(
|
|
1741
|
+
this._request("POST", `/api/v1/text-layers/${textLayerId}/shift`, {
|
|
1742
|
+
auditMessage,
|
|
1302
1743
|
body: bodyOf({ direction }),
|
|
1303
1744
|
}),
|
|
1304
1745
|
/**
|
|
@@ -1307,8 +1748,9 @@ class PlaidClient {
|
|
|
1307
1748
|
* @param {string} name - The name
|
|
1308
1749
|
*/
|
|
1309
1750
|
create: (projectId, name, auditMessage) =>
|
|
1310
|
-
this._request(
|
|
1311
|
-
|
|
1751
|
+
this._request("POST", "/api/v1/text-layers", {
|
|
1752
|
+
auditMessage,
|
|
1753
|
+
body: bodyOf({ "project-id": projectId, name }),
|
|
1312
1754
|
}),
|
|
1313
1755
|
};
|
|
1314
1756
|
|
|
@@ -1319,15 +1761,18 @@ class PlaidClient {
|
|
|
1319
1761
|
* @param {any} body - The request body
|
|
1320
1762
|
*/
|
|
1321
1763
|
setMetadata: (id, body, auditMessage) =>
|
|
1322
|
-
this._request(
|
|
1323
|
-
|
|
1764
|
+
this._request("PUT", `/api/v1/vocab-items/${id}/metadata`, {
|
|
1765
|
+
auditMessage,
|
|
1766
|
+
rawBody: body,
|
|
1767
|
+
skipResponseTransform: true,
|
|
1324
1768
|
}),
|
|
1325
1769
|
/**
|
|
1326
1770
|
* Remove all metadata from a vocab item.
|
|
1327
1771
|
* @param {string} id - The resource ID
|
|
1328
1772
|
*/
|
|
1329
1773
|
deleteMetadata: (id, auditMessage) =>
|
|
1330
|
-
this._request(
|
|
1774
|
+
this._request("DELETE", `/api/v1/vocab-items/${id}/metadata`, {
|
|
1775
|
+
auditMessage,
|
|
1331
1776
|
skipResponseTransform: true,
|
|
1332
1777
|
}),
|
|
1333
1778
|
/**
|
|
@@ -1336,8 +1781,10 @@ class PlaidClient {
|
|
|
1336
1781
|
* @param {any} body - The metadata patch
|
|
1337
1782
|
*/
|
|
1338
1783
|
patchMetadata: (id, body, auditMessage) =>
|
|
1339
|
-
this._request(
|
|
1340
|
-
|
|
1784
|
+
this._request("PATCH", `/api/v1/vocab-items/${id}/metadata`, {
|
|
1785
|
+
auditMessage,
|
|
1786
|
+
rawBody: body,
|
|
1787
|
+
skipResponseTransform: true,
|
|
1341
1788
|
}),
|
|
1342
1789
|
/**
|
|
1343
1790
|
* Create a new vocab item
|
|
@@ -1346,8 +1793,9 @@ class PlaidClient {
|
|
|
1346
1793
|
* @param {any} [metadata] - Metadata map. Omit to leave unset; pass null to send JSON null.
|
|
1347
1794
|
*/
|
|
1348
1795
|
create: (vocabLayerId, form, metadata, auditMessage) =>
|
|
1349
|
-
this._request(
|
|
1350
|
-
|
|
1796
|
+
this._request("POST", "/api/v1/vocab-items", {
|
|
1797
|
+
auditMessage,
|
|
1798
|
+
body: bodyOf({ "vocab-layer-id": vocabLayerId, form, metadata }),
|
|
1351
1799
|
}),
|
|
1352
1800
|
/**
|
|
1353
1801
|
* Create multiple vocab items in a single operation. Entries may target
|
|
@@ -1355,36 +1803,43 @@ class PlaidClient {
|
|
|
1355
1803
|
* @param {Array<{vocabLayerId: string, form: string, metadata?: any}>} body - The vocab items to create
|
|
1356
1804
|
*/
|
|
1357
1805
|
bulkCreate: (body, auditMessage) =>
|
|
1358
|
-
this._request(
|
|
1806
|
+
this._request("POST", "/api/v1/vocab-items/bulk", {
|
|
1807
|
+
auditMessage,
|
|
1808
|
+
body,
|
|
1809
|
+
}),
|
|
1359
1810
|
/**
|
|
1360
1811
|
* Delete multiple vocab items in a single operation. Each item's
|
|
1361
1812
|
* descendant vocab links are deleted too. Provide an array of IDs.
|
|
1362
1813
|
* @param {string[]} body - The vocab item IDs to delete
|
|
1363
1814
|
*/
|
|
1364
1815
|
bulkDelete: (body, auditMessage) =>
|
|
1365
|
-
this._request(
|
|
1816
|
+
this._request("DELETE", "/api/v1/vocab-items/bulk", {
|
|
1817
|
+
auditMessage,
|
|
1818
|
+
body,
|
|
1819
|
+
}),
|
|
1366
1820
|
/**
|
|
1367
1821
|
* Get a vocab item by ID
|
|
1368
1822
|
* @param {string} id - The resource ID
|
|
1369
1823
|
* @param {string} [asOf] - Temporal query timestamp
|
|
1370
1824
|
*/
|
|
1371
1825
|
get: (id, asOf) =>
|
|
1372
|
-
this._request(
|
|
1373
|
-
queryParams: {
|
|
1826
|
+
this._request("GET", `/api/v1/vocab-items/${id}`, {
|
|
1827
|
+
queryParams: { "as-of": asOf },
|
|
1374
1828
|
}),
|
|
1375
1829
|
/**
|
|
1376
1830
|
* Delete a vocab item
|
|
1377
1831
|
* @param {string} id - The resource ID
|
|
1378
1832
|
*/
|
|
1379
1833
|
delete: (id, auditMessage) =>
|
|
1380
|
-
this._request(
|
|
1834
|
+
this._request("DELETE", `/api/v1/vocab-items/${id}`, { auditMessage }),
|
|
1381
1835
|
/**
|
|
1382
1836
|
* Update a vocab item's form
|
|
1383
1837
|
* @param {string} id - The resource ID
|
|
1384
1838
|
* @param {string} form - The vocab item form
|
|
1385
1839
|
*/
|
|
1386
1840
|
update: (id, form, auditMessage) =>
|
|
1387
|
-
this._request(
|
|
1841
|
+
this._request("PATCH", `/api/v1/vocab-items/${id}`, {
|
|
1842
|
+
auditMessage,
|
|
1388
1843
|
body: bodyOf({ form }),
|
|
1389
1844
|
}),
|
|
1390
1845
|
};
|
|
@@ -1396,17 +1851,20 @@ class PlaidClient {
|
|
|
1396
1851
|
* @param {string} direction - The direction ("up" or "down")
|
|
1397
1852
|
*/
|
|
1398
1853
|
shift: (relationLayerId, direction, auditMessage) =>
|
|
1399
|
-
this._request(
|
|
1400
|
-
|
|
1401
|
-
|
|
1854
|
+
this._request(
|
|
1855
|
+
"POST",
|
|
1856
|
+
`/api/v1/relation-layers/${relationLayerId}/shift`,
|
|
1857
|
+
{ auditMessage, body: bodyOf({ direction }) },
|
|
1858
|
+
),
|
|
1402
1859
|
/**
|
|
1403
1860
|
* Create a new relation layer.
|
|
1404
1861
|
* @param {string} spanLayerId - The span layer ID
|
|
1405
1862
|
* @param {string} name - The name
|
|
1406
1863
|
*/
|
|
1407
1864
|
create: (spanLayerId, name, auditMessage) =>
|
|
1408
|
-
this._request(
|
|
1409
|
-
|
|
1865
|
+
this._request("POST", "/api/v1/relation-layers", {
|
|
1866
|
+
auditMessage,
|
|
1867
|
+
body: bodyOf({ "span-layer-id": spanLayerId, name }),
|
|
1410
1868
|
}),
|
|
1411
1869
|
/**
|
|
1412
1870
|
* Set a configuration value for a layer in an editor namespace.
|
|
@@ -1415,10 +1873,18 @@ class PlaidClient {
|
|
|
1415
1873
|
* @param {string} configKey - The config key
|
|
1416
1874
|
* @param {any} configValue - Configuration value to set
|
|
1417
1875
|
*/
|
|
1418
|
-
setConfig: (
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1876
|
+
setConfig: (
|
|
1877
|
+
relationLayerId,
|
|
1878
|
+
namespace,
|
|
1879
|
+
configKey,
|
|
1880
|
+
configValue,
|
|
1881
|
+
auditMessage,
|
|
1882
|
+
) =>
|
|
1883
|
+
this._request(
|
|
1884
|
+
"PUT",
|
|
1885
|
+
`/api/v1/relation-layers/${relationLayerId}/config/${namespace}/${configKey}`,
|
|
1886
|
+
{ auditMessage, rawBody: configValue, skipResponseTransform: true },
|
|
1887
|
+
),
|
|
1422
1888
|
/**
|
|
1423
1889
|
* Remove a configuration value for a layer.
|
|
1424
1890
|
* @param {string} relationLayerId - The relation layer ID
|
|
@@ -1426,31 +1892,36 @@ class PlaidClient {
|
|
|
1426
1892
|
* @param {string} configKey - The config key
|
|
1427
1893
|
*/
|
|
1428
1894
|
deleteConfig: (relationLayerId, namespace, configKey, auditMessage) =>
|
|
1429
|
-
this._request(
|
|
1430
|
-
|
|
1431
|
-
|
|
1895
|
+
this._request(
|
|
1896
|
+
"DELETE",
|
|
1897
|
+
`/api/v1/relation-layers/${relationLayerId}/config/${namespace}/${configKey}`,
|
|
1898
|
+
{ auditMessage, skipResponseTransform: true },
|
|
1899
|
+
),
|
|
1432
1900
|
/**
|
|
1433
1901
|
* Get a relation layer by ID.
|
|
1434
1902
|
* @param {string} relationLayerId - The relation layer ID
|
|
1435
1903
|
* @param {string} [asOf] - Temporal query timestamp
|
|
1436
1904
|
*/
|
|
1437
1905
|
get: (relationLayerId, asOf) =>
|
|
1438
|
-
this._request(
|
|
1439
|
-
queryParams: {
|
|
1906
|
+
this._request("GET", `/api/v1/relation-layers/${relationLayerId}`, {
|
|
1907
|
+
queryParams: { "as-of": asOf },
|
|
1440
1908
|
}),
|
|
1441
1909
|
/**
|
|
1442
1910
|
* Delete a relation layer.
|
|
1443
1911
|
* @param {string} relationLayerId - The relation layer ID
|
|
1444
1912
|
*/
|
|
1445
1913
|
delete: (relationLayerId, auditMessage) =>
|
|
1446
|
-
this._request(
|
|
1914
|
+
this._request("DELETE", `/api/v1/relation-layers/${relationLayerId}`, {
|
|
1915
|
+
auditMessage,
|
|
1916
|
+
}),
|
|
1447
1917
|
/**
|
|
1448
1918
|
* Update a relation layer's name.
|
|
1449
1919
|
* @param {string} relationLayerId - The relation layer ID
|
|
1450
1920
|
* @param {string} name - The name
|
|
1451
1921
|
*/
|
|
1452
1922
|
update: (relationLayerId, name, auditMessage) =>
|
|
1453
|
-
this._request(
|
|
1923
|
+
this._request("PATCH", `/api/v1/relation-layers/${relationLayerId}`, {
|
|
1924
|
+
auditMessage,
|
|
1454
1925
|
body: bodyOf({ name }),
|
|
1455
1926
|
}),
|
|
1456
1927
|
};
|
|
@@ -1474,9 +1945,25 @@ class PlaidClient {
|
|
|
1474
1945
|
* @param {number} [precedence] - Ordering precedence
|
|
1475
1946
|
* @param {any} [metadata] - Metadata map. Omit to leave unset; pass null to send JSON null.
|
|
1476
1947
|
*/
|
|
1477
|
-
create: (
|
|
1478
|
-
|
|
1479
|
-
|
|
1948
|
+
create: (
|
|
1949
|
+
tokenLayerId,
|
|
1950
|
+
text,
|
|
1951
|
+
begin,
|
|
1952
|
+
end,
|
|
1953
|
+
precedence,
|
|
1954
|
+
metadata,
|
|
1955
|
+
auditMessage,
|
|
1956
|
+
) =>
|
|
1957
|
+
this._request("POST", "/api/v1/tokens", {
|
|
1958
|
+
auditMessage,
|
|
1959
|
+
body: bodyOf({
|
|
1960
|
+
"token-layer-id": tokenLayerId,
|
|
1961
|
+
text,
|
|
1962
|
+
begin,
|
|
1963
|
+
end,
|
|
1964
|
+
precedence,
|
|
1965
|
+
metadata,
|
|
1966
|
+
}),
|
|
1480
1967
|
}),
|
|
1481
1968
|
/**
|
|
1482
1969
|
* Get a token.
|
|
@@ -1484,8 +1971,8 @@ class PlaidClient {
|
|
|
1484
1971
|
* @param {string} [asOf] - Temporal query timestamp
|
|
1485
1972
|
*/
|
|
1486
1973
|
get: (tokenId, asOf) =>
|
|
1487
|
-
this._request(
|
|
1488
|
-
queryParams: {
|
|
1974
|
+
this._request("GET", `/api/v1/tokens/${tokenId}`, {
|
|
1975
|
+
queryParams: { "as-of": asOf },
|
|
1489
1976
|
}),
|
|
1490
1977
|
/**
|
|
1491
1978
|
* Delete a token and remove it from any spans. If this causes a span to
|
|
@@ -1493,7 +1980,7 @@ class PlaidClient {
|
|
|
1493
1980
|
* @param {string} tokenId - The token ID
|
|
1494
1981
|
*/
|
|
1495
1982
|
delete: (tokenId, auditMessage) =>
|
|
1496
|
-
this._request(
|
|
1983
|
+
this._request("DELETE", `/api/v1/tokens/${tokenId}`, { auditMessage }),
|
|
1497
1984
|
/**
|
|
1498
1985
|
* Update a token.
|
|
1499
1986
|
* @param {string} tokenId - The token ID
|
|
@@ -1505,7 +1992,8 @@ class PlaidClient {
|
|
|
1505
1992
|
* drops undefined, so the three cases map correctly to the server.
|
|
1506
1993
|
*/
|
|
1507
1994
|
update: (tokenId, begin, end, precedence, auditMessage) =>
|
|
1508
|
-
this._request(
|
|
1995
|
+
this._request("PATCH", `/api/v1/tokens/${tokenId}`, {
|
|
1996
|
+
auditMessage,
|
|
1509
1997
|
body: bodyOf({ begin, end, precedence }),
|
|
1510
1998
|
}),
|
|
1511
1999
|
/**
|
|
@@ -1514,13 +2002,13 @@ class PlaidClient {
|
|
|
1514
2002
|
* @returns {Promise<{ids: string[]}>} The created entity IDs, in input order. (bulkDelete resolves to no value.)
|
|
1515
2003
|
*/
|
|
1516
2004
|
bulkCreate: (body, auditMessage) =>
|
|
1517
|
-
this._request(
|
|
2005
|
+
this._request("POST", "/api/v1/tokens/bulk", { auditMessage, body }),
|
|
1518
2006
|
/**
|
|
1519
2007
|
* Delete multiple tokens in a single operation. Provide an array of IDs.
|
|
1520
2008
|
* @param {Array} body - The request body
|
|
1521
2009
|
*/
|
|
1522
2010
|
bulkDelete: (body, auditMessage) =>
|
|
1523
|
-
this._request(
|
|
2011
|
+
this._request("DELETE", "/api/v1/tokens/bulk", { auditMessage, body }),
|
|
1524
2012
|
/**
|
|
1525
2013
|
* Split a token at a Unicode code-point offset. The original token becomes the
|
|
1526
2014
|
* left half (keeps its ID, spans, vocab-links); the new right token's ID is returned.
|
|
@@ -1528,7 +2016,8 @@ class PlaidClient {
|
|
|
1528
2016
|
* @param {number} position - Code-point offset to split at (strictly between begin and end)
|
|
1529
2017
|
*/
|
|
1530
2018
|
split: (tokenId, position, auditMessage) =>
|
|
1531
|
-
this._request(
|
|
2019
|
+
this._request("POST", `/api/v1/tokens/${tokenId}/split`, {
|
|
2020
|
+
auditMessage,
|
|
1532
2021
|
body: bodyOf({ position }),
|
|
1533
2022
|
}),
|
|
1534
2023
|
/**
|
|
@@ -1540,8 +2029,9 @@ class PlaidClient {
|
|
|
1540
2029
|
* @param {string} otherTokenId - The other token to merge in
|
|
1541
2030
|
*/
|
|
1542
2031
|
merge: (tokenId, otherTokenId, auditMessage) =>
|
|
1543
|
-
this._request(
|
|
1544
|
-
|
|
2032
|
+
this._request("POST", `/api/v1/tokens/${tokenId}/merge`, {
|
|
2033
|
+
auditMessage,
|
|
2034
|
+
body: bodyOf({ "other-token-id": otherTokenId }),
|
|
1545
2035
|
}),
|
|
1546
2036
|
/**
|
|
1547
2037
|
* Shift a token's boundary. On partitioning layers the adjacent token is
|
|
@@ -1552,7 +2042,8 @@ class PlaidClient {
|
|
|
1552
2042
|
* @param {number} [end] - New end offset, exclusive (Unicode code points)
|
|
1553
2043
|
*/
|
|
1554
2044
|
shift: (tokenId, begin, end, auditMessage) =>
|
|
1555
|
-
this._request(
|
|
2045
|
+
this._request("POST", `/api/v1/tokens/${tokenId}/shift`, {
|
|
2046
|
+
auditMessage,
|
|
1556
2047
|
body: bodyOf({ begin, end }),
|
|
1557
2048
|
}),
|
|
1558
2049
|
/**
|
|
@@ -1561,15 +2052,18 @@ class PlaidClient {
|
|
|
1561
2052
|
* @param {any} body - The request body
|
|
1562
2053
|
*/
|
|
1563
2054
|
setMetadata: (tokenId, body, auditMessage) =>
|
|
1564
|
-
this._request(
|
|
1565
|
-
|
|
2055
|
+
this._request("PUT", `/api/v1/tokens/${tokenId}/metadata`, {
|
|
2056
|
+
auditMessage,
|
|
2057
|
+
rawBody: body,
|
|
2058
|
+
skipResponseTransform: true,
|
|
1566
2059
|
}),
|
|
1567
2060
|
/**
|
|
1568
2061
|
* Remove all metadata from a token.
|
|
1569
2062
|
* @param {string} tokenId - The token ID
|
|
1570
2063
|
*/
|
|
1571
2064
|
deleteMetadata: (tokenId, auditMessage) =>
|
|
1572
|
-
this._request(
|
|
2065
|
+
this._request("DELETE", `/api/v1/tokens/${tokenId}/metadata`, {
|
|
2066
|
+
auditMessage,
|
|
1573
2067
|
skipResponseTransform: true,
|
|
1574
2068
|
}),
|
|
1575
2069
|
/**
|
|
@@ -1578,8 +2072,10 @@ class PlaidClient {
|
|
|
1578
2072
|
* @param {any} body - The metadata patch
|
|
1579
2073
|
*/
|
|
1580
2074
|
patchMetadata: (tokenId, body, auditMessage) =>
|
|
1581
|
-
this._request(
|
|
1582
|
-
|
|
2075
|
+
this._request("PATCH", `/api/v1/tokens/${tokenId}/metadata`, {
|
|
2076
|
+
auditMessage,
|
|
2077
|
+
rawBody: body,
|
|
2078
|
+
skipResponseTransform: true,
|
|
1583
2079
|
}),
|
|
1584
2080
|
};
|
|
1585
2081
|
|
|
@@ -1595,14 +2091,22 @@ class PlaidClient {
|
|
|
1595
2091
|
createSSEConnection(this, projectId, onEvent, path),
|
|
1596
2092
|
|
|
1597
2093
|
/**
|
|
1598
|
-
* Send a message to project listeners
|
|
2094
|
+
* Send a message to project listeners.
|
|
2095
|
+
*
|
|
2096
|
+
* `data` may be any JSON value and is sent VERBATIM (`rawBody`): a
|
|
2097
|
+
* message payload is opaque application data, like `metadata` and
|
|
2098
|
+
* `config`, so its keys must not be re-cased on the way out. Without
|
|
2099
|
+
* this a key such as `case-marker` would reach listeners as
|
|
2100
|
+
* `caseMarker` in JS and `case_marker` in Python. `listen` restores it
|
|
2101
|
+
* verbatim on the way in.
|
|
1599
2102
|
* @param {string} projectId - The UUID of the project to send to
|
|
1600
2103
|
* @param {any} data - The message data to send
|
|
1601
2104
|
* @returns {Promise<any>} Response from the send operation
|
|
1602
2105
|
*/
|
|
1603
2106
|
sendMessage: (projectId, data, auditMessage) =>
|
|
1604
|
-
this._request(
|
|
1605
|
-
|
|
2107
|
+
this._request("POST", `/api/v1/projects/${projectId}/message`, {
|
|
2108
|
+
auditMessage,
|
|
2109
|
+
rawBody: { body: data },
|
|
1606
2110
|
}),
|
|
1607
2111
|
|
|
1608
2112
|
/**
|
|
@@ -1612,8 +2116,7 @@ class PlaidClient {
|
|
|
1612
2116
|
* @param {string} projectId - The UUID of the project to query
|
|
1613
2117
|
* @returns {Promise<Array>} Array of discovered service information
|
|
1614
2118
|
*/
|
|
1615
|
-
discoverServices: (projectId) =>
|
|
1616
|
-
discoverServices(this, projectId),
|
|
2119
|
+
discoverServices: (projectId) => discoverServices(this, projectId),
|
|
1617
2120
|
|
|
1618
2121
|
/**
|
|
1619
2122
|
* Forget a previously-seen (offline) service. Maintainer-only; 409 if
|
|
@@ -1627,26 +2130,70 @@ class PlaidClient {
|
|
|
1627
2130
|
|
|
1628
2131
|
/**
|
|
1629
2132
|
* Register as a service and handle incoming work requests.
|
|
2133
|
+
*
|
|
2134
|
+
* The registration reopens its channel whenever it drops, so a server
|
|
2135
|
+
* restart needs no service restart.
|
|
1630
2136
|
* @param {string} projectId - The UUID of the project to serve
|
|
1631
2137
|
* @param {Object} serviceInfo - Service information {serviceId, serviceName, description}
|
|
1632
2138
|
* @param {function} onServiceRequest - Callback (data, responseHelper)
|
|
1633
2139
|
* @param {Object} [extras] - Optional additional service metadata
|
|
1634
|
-
* @
|
|
2140
|
+
* @param {function} [onStatus] - Optional callback (event, projectId, detail) for
|
|
2141
|
+
* connection transitions: 'registered', 'reconnected', 'disconnected'
|
|
2142
|
+
* @returns {Object} Service registration with .stop(), .isRunning(), .isConnected()
|
|
1635
2143
|
*/
|
|
1636
|
-
serve: (projectId, serviceInfo, onServiceRequest, extras) =>
|
|
1637
|
-
serve(this, projectId, serviceInfo, onServiceRequest, extras),
|
|
2144
|
+
serve: (projectId, serviceInfo, onServiceRequest, extras, onStatus) =>
|
|
2145
|
+
serve(this, projectId, serviceInfo, onServiceRequest, extras, onStatus),
|
|
1638
2146
|
|
|
1639
2147
|
/**
|
|
1640
2148
|
* Request a service to perform work and await its result.
|
|
2149
|
+
*
|
|
2150
|
+
* The request outlives this call: after a timeout, an abort, or a
|
|
2151
|
+
* dropped connection the service goes on, and `attachServiceRequest`
|
|
2152
|
+
* collects the result given the request id, which `opts.onAccepted`
|
|
2153
|
+
* receives as soon as the server has taken the request. Pass
|
|
2154
|
+
* `opts.requestId` (a UUID you mint) to know the id before submitting;
|
|
2155
|
+
* submitting an id that names a request you already made rejoins it
|
|
2156
|
+
* instead of starting another.
|
|
1641
2157
|
* @param {string} projectId - The UUID of the project
|
|
1642
2158
|
* @param {string} serviceId - The ID of the service to request
|
|
1643
2159
|
* @param {any} data - The request data
|
|
1644
|
-
* @param {number} [timeout] - Timeout in
|
|
2160
|
+
* @param {number} [timeout=10000] - Timeout in ms
|
|
1645
2161
|
* @param {function} [onProgress] - Called with each progress payload {percent, message}
|
|
1646
|
-
* @
|
|
2162
|
+
* @param {AbortSignal} [signal] - Abort to stop waiting; rejects with an AbortError
|
|
2163
|
+
* @param {Object} [opts] - {requestId, onAccepted}
|
|
2164
|
+
* @returns {Promise<any>} The service's result
|
|
2165
|
+
*/
|
|
2166
|
+
requestService: (projectId, serviceId, data, timeout, onProgress, signal, opts) =>
|
|
2167
|
+
requestService(this, projectId, serviceId, data, timeout, onProgress, signal, opts),
|
|
2168
|
+
|
|
2169
|
+
/**
|
|
2170
|
+
* Rejoin a service request made earlier and await its result: the
|
|
2171
|
+
* latest progress is replayed, then the result comes, or at once if the
|
|
2172
|
+
* request already finished. Only the user who submitted it (or an
|
|
2173
|
+
* admin). Rejects with an error whose `status` is 404 when the request
|
|
2174
|
+
* is unknown or expired (a finished request's result is kept for a
|
|
2175
|
+
* while, not forever).
|
|
2176
|
+
* @param {string} projectId - The UUID of the project
|
|
2177
|
+
* @param {string} requestId - The request id
|
|
2178
|
+
* @param {number} [timeout=10000] - Timeout in ms
|
|
2179
|
+
* @param {function} [onProgress] - Called with each progress payload
|
|
2180
|
+
* @param {AbortSignal} [signal] - Abort to stop waiting
|
|
2181
|
+
* @returns {Promise<any>} The service's result
|
|
2182
|
+
*/
|
|
2183
|
+
attachServiceRequest: (projectId, requestId, timeout, onProgress, signal) =>
|
|
2184
|
+
attachServiceRequest(this, projectId, requestId, timeout, onProgress, signal),
|
|
2185
|
+
|
|
2186
|
+
/**
|
|
2187
|
+
* Ask the service to stop a request made earlier. The request still
|
|
2188
|
+
* ends with whatever the service then reports, on the stream of whoever
|
|
2189
|
+
* is awaiting it. Rejects with 404 if unknown or expired, 409 once
|
|
2190
|
+
* finished.
|
|
2191
|
+
* @param {string} projectId - The UUID of the project
|
|
2192
|
+
* @param {string} requestId - The request id
|
|
2193
|
+
* @returns {Promise<void>}
|
|
1647
2194
|
*/
|
|
1648
|
-
|
|
1649
|
-
|
|
2195
|
+
cancelServiceRequest: (projectId, requestId) =>
|
|
2196
|
+
cancelServiceRequest(this, projectId, requestId),
|
|
1650
2197
|
};
|
|
1651
2198
|
|
|
1652
2199
|
/**
|
|
@@ -1684,8 +2231,14 @@ class PlaidClient {
|
|
|
1684
2231
|
* For 'count': {return: 'count', count}. Entity cells are full entity objects
|
|
1685
2232
|
* (same shape as the GET endpoints).
|
|
1686
2233
|
*/
|
|
2234
|
+
// bypassBatch: a query is a read. `client.batched()` flips one flag on the
|
|
2235
|
+
// whole client, so a query issued by unrelated code while a batch is open
|
|
2236
|
+
// (the IGT island fetching precedent while a document reconciles) used to
|
|
2237
|
+
// be queued into it: the caller got `{batched: true}` instead of results,
|
|
2238
|
+
// and the server ran the query against the batch's tx Connection, which
|
|
2239
|
+
// 500s and rolls back every write in that batch.
|
|
1687
2240
|
this.query = (body, auditMessage) =>
|
|
1688
|
-
this._request(
|
|
2241
|
+
this._request("POST", "/api/v1/query", { auditMessage, body, bypassBatch: true });
|
|
1689
2242
|
|
|
1690
2243
|
// Logical-operation groups (audit-log grouping). There is no create: a
|
|
1691
2244
|
// group row is made lazily by the first write carrying `?group-id=`
|
|
@@ -1695,15 +2248,183 @@ class PlaidClient {
|
|
|
1695
2248
|
* Get a logical-operation group (its label + creator).
|
|
1696
2249
|
* @param {string} id - The group id
|
|
1697
2250
|
*/
|
|
1698
|
-
get: (id) =>
|
|
1699
|
-
this._request('GET', `/api/v1/operation-groups/${id}`),
|
|
2251
|
+
get: (id) => this._request("GET", `/api/v1/operation-groups/${id}`),
|
|
1700
2252
|
/**
|
|
1701
2253
|
* Relabel a logical-operation group after the fact. Owner or admin only.
|
|
1702
2254
|
* @param {string} id - The group id
|
|
1703
2255
|
* @param {string|null} message - The new label
|
|
1704
2256
|
*/
|
|
1705
2257
|
update: (id, message) =>
|
|
1706
|
-
this._request(
|
|
2258
|
+
this._request("PATCH", `/api/v1/operation-groups/${id}`, {
|
|
2259
|
+
body: { message },
|
|
2260
|
+
}),
|
|
2261
|
+
};
|
|
2262
|
+
|
|
2263
|
+
this.comments = {
|
|
2264
|
+
/**
|
|
2265
|
+
* Post a comment on an entity. Requires write access to the entity's
|
|
2266
|
+
* project, or to the vocabulary for a vocab-item; the author is the
|
|
2267
|
+
* authenticated caller. Comments are not audited and do not bump the
|
|
2268
|
+
* document version.
|
|
2269
|
+
*
|
|
2270
|
+
* A comment outlives its anchor: deleting the entity does not delete
|
|
2271
|
+
* the comment. `anchorLabel` is the caption shown once that happens
|
|
2272
|
+
* ("Gloss of ktab, sentence 4"), so pass what the comment is about.
|
|
2273
|
+
* @param {'document'|'text'|'token'|'span'|'relation'|'vocab-item'} entityType - What kind of thing is being commented on
|
|
2274
|
+
* @param {string} entityId - The commented entity's id
|
|
2275
|
+
* @param {string} body - The comment text (1..10000 characters)
|
|
2276
|
+
* @param {object} [opts]
|
|
2277
|
+
* @param {string} [opts.anchorLabel] - What the comment is about, in words (at most 200 characters)
|
|
2278
|
+
*/
|
|
2279
|
+
create: (entityType, entityId, body, { anchorLabel } = {}) =>
|
|
2280
|
+
this._request("POST", "/api/v1/comments", {
|
|
2281
|
+
body: bodyOf({
|
|
2282
|
+
"entity-type": entityType,
|
|
2283
|
+
"entity-id": entityId,
|
|
2284
|
+
body,
|
|
2285
|
+
"anchor-label": anchorLabel,
|
|
2286
|
+
}),
|
|
2287
|
+
}),
|
|
2288
|
+
/**
|
|
2289
|
+
* Read one comment.
|
|
2290
|
+
* @param {string} id - The comment id
|
|
2291
|
+
*/
|
|
2292
|
+
get: (id) => this._request("GET", `/api/v1/comments/${id}`),
|
|
2293
|
+
/**
|
|
2294
|
+
* Edit a comment's body. Only the comment's AUTHOR may do this - not
|
|
2295
|
+
* maintainers, not admins. Sets `edited` on the comment.
|
|
2296
|
+
* @param {string} id - The comment id
|
|
2297
|
+
* @param {string} body - The replacement text
|
|
2298
|
+
*/
|
|
2299
|
+
update: (id, body) =>
|
|
2300
|
+
this._request("PATCH", `/api/v1/comments/${id}`, { body: { body } }),
|
|
2301
|
+
/**
|
|
2302
|
+
* Delete a comment. The author may delete their own; a project
|
|
2303
|
+
* maintainer (or admin) may delete any.
|
|
2304
|
+
* @param {string} id - The comment id
|
|
2305
|
+
*/
|
|
2306
|
+
delete: (id) => this._request("DELETE", `/api/v1/comments/${id}`),
|
|
2307
|
+
/**
|
|
2308
|
+
* List comments in a project, oldest first. Transparently follows
|
|
2309
|
+
* pagination cursors and returns the full flat array.
|
|
2310
|
+
* Cannot be used inside a batch (auto-paginates across requests); throws if called while batching - use listPage() for a single page in a batch.
|
|
2311
|
+
* @param {string} projectId - The project to read
|
|
2312
|
+
* @param {object} [filters] - Narrow the scope
|
|
2313
|
+
* @param {string} [filters.documentId] - Every comment anywhere in one document
|
|
2314
|
+
* @param {string} [filters.entityType] - With entityId, one entity's thread
|
|
2315
|
+
* @param {string} [filters.entityId] - With entityType, one entity's thread
|
|
2316
|
+
*/
|
|
2317
|
+
list: (projectId, { documentId, entityType, entityId } = {}) =>
|
|
2318
|
+
listAll(this, `/api/v1/projects/${projectId}/comments`, {
|
|
2319
|
+
query: {
|
|
2320
|
+
"document-id": documentId,
|
|
2321
|
+
"entity-type": entityType,
|
|
2322
|
+
"entity-id": entityId,
|
|
2323
|
+
},
|
|
2324
|
+
}),
|
|
2325
|
+
/**
|
|
2326
|
+
* Fetch a single page of a project's comments.
|
|
2327
|
+
* @param {string} projectId - The project to read
|
|
2328
|
+
* @param {object} [opts]
|
|
2329
|
+
* @param {number} [opts.limit] - Page size (1..1000; server default 100)
|
|
2330
|
+
* @param {string} [opts.cursor] - Opaque cursor from a previous page
|
|
2331
|
+
* @param {string} [opts.documentId] - Every comment anywhere in one document
|
|
2332
|
+
* @param {string} [opts.entityType] - With entityId, one entity's thread
|
|
2333
|
+
* @param {string} [opts.entityId] - With entityType, one entity's thread
|
|
2334
|
+
* @returns {Promise<{entries: Array, nextCursor: (string|null)}>}
|
|
2335
|
+
*/
|
|
2336
|
+
listPage: (projectId, { limit, cursor, documentId, entityType, entityId } = {}) =>
|
|
2337
|
+
listPage(this, `/api/v1/projects/${projectId}/comments`, {
|
|
2338
|
+
limit,
|
|
2339
|
+
cursor,
|
|
2340
|
+
query: {
|
|
2341
|
+
"document-id": documentId,
|
|
2342
|
+
"entity-type": entityType,
|
|
2343
|
+
"entity-id": entityId,
|
|
2344
|
+
},
|
|
2345
|
+
}),
|
|
2346
|
+
/**
|
|
2347
|
+
* Async-iterate a project's comments page by page; yields each page's entries array.
|
|
2348
|
+
* 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.
|
|
2349
|
+
* @param {string} projectId - The project to read
|
|
2350
|
+
* @param {object} [opts]
|
|
2351
|
+
* @param {number} [opts.pageSize] - Per-request page size
|
|
2352
|
+
* @param {string} [opts.documentId] - Every comment anywhere in one document
|
|
2353
|
+
* @param {string} [opts.entityType] - With entityId, one entity's thread
|
|
2354
|
+
* @param {string} [opts.entityId] - With entityType, one entity's thread
|
|
2355
|
+
* @returns {AsyncGenerator<Array>}
|
|
2356
|
+
*/
|
|
2357
|
+
iterPages: (projectId, { pageSize, documentId, entityType, entityId } = {}) =>
|
|
2358
|
+
iterPages(this, `/api/v1/projects/${projectId}/comments`, {
|
|
2359
|
+
pageSize,
|
|
2360
|
+
query: {
|
|
2361
|
+
"document-id": documentId,
|
|
2362
|
+
"entity-type": entityType,
|
|
2363
|
+
"entity-id": entityId,
|
|
2364
|
+
},
|
|
2365
|
+
}),
|
|
2366
|
+
/**
|
|
2367
|
+
* Comment counts per entity, as an `{entityId: n}` map, over the same
|
|
2368
|
+
* scope and filters as `list`. One cheap request paints a comment
|
|
2369
|
+
* indicator on every annotated item in a document without paging
|
|
2370
|
+
* through the bodies.
|
|
2371
|
+
*
|
|
2372
|
+
* The response is NOT key-transformed: its keys are entity ids, and
|
|
2373
|
+
* camelCasing would mangle the hyphens in a UUID.
|
|
2374
|
+
* @param {string} projectId - The project to read
|
|
2375
|
+
* @param {object} [filters] - Same filters as list()
|
|
2376
|
+
* @returns {Promise<Object<string, number>>}
|
|
2377
|
+
*/
|
|
2378
|
+
counts: (projectId, { documentId, entityType, entityId } = {}) =>
|
|
2379
|
+
this._request("GET", `/api/v1/projects/${projectId}/comments/counts`, {
|
|
2380
|
+
queryParams: {
|
|
2381
|
+
"document-id": documentId,
|
|
2382
|
+
"entity-type": entityType,
|
|
2383
|
+
"entity-id": entityId,
|
|
2384
|
+
},
|
|
2385
|
+
skipResponseTransform: true,
|
|
2386
|
+
}),
|
|
2387
|
+
/**
|
|
2388
|
+
* List the comments on a vocabulary's entries, oldest first. Requires
|
|
2389
|
+
* read access to the vocabulary. Transparently follows pagination
|
|
2390
|
+
* cursors and returns the full flat array.
|
|
2391
|
+
* Cannot be used inside a batch (auto-paginates across requests); throws if called while batching - use listInVocabPage() for a single page in a batch.
|
|
2392
|
+
* @param {string} vocabId - The vocab layer to read
|
|
2393
|
+
* @param {object} [filters]
|
|
2394
|
+
* @param {string} [filters.entityId] - One entry's thread
|
|
2395
|
+
*/
|
|
2396
|
+
listInVocab: (vocabId, { entityId } = {}) =>
|
|
2397
|
+
listAll(this, `/api/v1/vocab-layers/${vocabId}/comments`, {
|
|
2398
|
+
query: { "entity-id": entityId },
|
|
2399
|
+
}),
|
|
2400
|
+
/**
|
|
2401
|
+
* Fetch a single page of a vocabulary's comments.
|
|
2402
|
+
* @param {string} vocabId - The vocab layer to read
|
|
2403
|
+
* @param {object} [opts]
|
|
2404
|
+
* @param {number} [opts.limit] - Page size (1..1000; server default 100)
|
|
2405
|
+
* @param {string} [opts.cursor] - Opaque cursor from a previous page
|
|
2406
|
+
* @param {string} [opts.entityId] - One entry's thread
|
|
2407
|
+
* @returns {Promise<{entries: Array, nextCursor: (string|null)}>}
|
|
2408
|
+
*/
|
|
2409
|
+
listInVocabPage: (vocabId, { limit, cursor, entityId } = {}) =>
|
|
2410
|
+
listPage(this, `/api/v1/vocab-layers/${vocabId}/comments`, {
|
|
2411
|
+
limit,
|
|
2412
|
+
cursor,
|
|
2413
|
+
query: { "entity-id": entityId },
|
|
2414
|
+
}),
|
|
2415
|
+
/**
|
|
2416
|
+
* Comment counts per entry of a vocabulary, as an `{entityId: n}` map.
|
|
2417
|
+
* The response is NOT key-transformed: its keys are entry ids.
|
|
2418
|
+
* @param {string} vocabId - The vocab layer to read
|
|
2419
|
+
* @param {object} [filters]
|
|
2420
|
+
* @param {string} [filters.entityId] - One entry only
|
|
2421
|
+
* @returns {Promise<Object<string, number>>}
|
|
2422
|
+
*/
|
|
2423
|
+
countsInVocab: (vocabId, { entityId } = {}) =>
|
|
2424
|
+
this._request("GET", `/api/v1/vocab-layers/${vocabId}/comments/counts`, {
|
|
2425
|
+
queryParams: { "entity-id": entityId },
|
|
2426
|
+
skipResponseTransform: true,
|
|
2427
|
+
}),
|
|
1707
2428
|
};
|
|
1708
2429
|
}
|
|
1709
2430
|
|
|
@@ -1811,7 +2532,9 @@ class PlaidClient {
|
|
|
1811
2532
|
async withOperation(message, fn) {
|
|
1812
2533
|
this.beginOperation(message);
|
|
1813
2534
|
const group = this.operationGroup;
|
|
1814
|
-
const setMessage = (msg) => {
|
|
2535
|
+
const setMessage = (msg) => {
|
|
2536
|
+
if (group.depth === 1) group.refined = msg;
|
|
2537
|
+
};
|
|
1815
2538
|
try {
|
|
1816
2539
|
return await fn(setMessage);
|
|
1817
2540
|
} finally {
|
|
@@ -1835,7 +2558,7 @@ class PlaidClient {
|
|
|
1835
2558
|
*/
|
|
1836
2559
|
async submitBatch() {
|
|
1837
2560
|
if (!this.isBatching) {
|
|
1838
|
-
throw new Error(
|
|
2561
|
+
throw new Error("No active batch. Call beginBatch() first.");
|
|
1839
2562
|
}
|
|
1840
2563
|
|
|
1841
2564
|
if (this.batchOperations.length === 0) {
|
|
@@ -1844,55 +2567,84 @@ class PlaidClient {
|
|
|
1844
2567
|
}
|
|
1845
2568
|
|
|
1846
2569
|
try {
|
|
1847
|
-
|
|
1848
|
-
const
|
|
2570
|
+
const url = `${this.baseUrl}/api/v1/batch`;
|
|
2571
|
+
const ops = this.batchOperations.map((op) => ({
|
|
1849
2572
|
path: op.path,
|
|
1850
2573
|
method: op.method.toUpperCase(),
|
|
1851
2574
|
...(op.body && { body: op.body }),
|
|
1852
2575
|
}));
|
|
2576
|
+
// The server caps a batch at MAX_BATCH_OPS so one transaction cannot
|
|
2577
|
+
// hold the write lock without bound. A larger batch goes as consecutive
|
|
2578
|
+
// requests, results concatenated in queue order: it could not have been
|
|
2579
|
+
// one transaction anyway, and a repair or bulk edit over a big document
|
|
2580
|
+
// must not fail on its size alone.
|
|
2581
|
+
const results = [];
|
|
2582
|
+
for (let i = 0; i < ops.length; i += MAX_BATCH_OPS) {
|
|
2583
|
+
results.push(...(await this._postBatch(url, ops.slice(i, i + MAX_BATCH_OPS))));
|
|
2584
|
+
}
|
|
2585
|
+
return results;
|
|
2586
|
+
} finally {
|
|
2587
|
+
this.isBatching = false;
|
|
2588
|
+
this.batchOperations = [];
|
|
2589
|
+
}
|
|
2590
|
+
}
|
|
1853
2591
|
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
}
|
|
1860
|
-
|
|
1861
|
-
}
|
|
1862
|
-
|
|
1863
|
-
|
|
2592
|
+
/** POST one batch request (at most MAX_BATCH_OPS operations); resolves to its transformed results. */
|
|
2593
|
+
async _postBatch(url, body) {
|
|
2594
|
+
const fetchOptions = {
|
|
2595
|
+
method: "POST",
|
|
2596
|
+
headers: {
|
|
2597
|
+
Authorization: `Bearer ${this.token}`,
|
|
2598
|
+
"Content-Type": "application/json",
|
|
2599
|
+
},
|
|
2600
|
+
body: JSON.stringify(body),
|
|
2601
|
+
};
|
|
1864
2602
|
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
2603
|
+
try {
|
|
2604
|
+
// Retry a 503: the batch is atomic, so a refused one wrote nothing and
|
|
2605
|
+
// repeating it is safe. A fresh timeout signal per attempt — an
|
|
2606
|
+
// AbortSignal.timeout stays aborted once it fires.
|
|
2607
|
+
const response = await retryWhileBusy(async () => {
|
|
2608
|
+
const signal = timeoutSignal(this.batchTimeout);
|
|
2609
|
+
const res = await fetch(
|
|
2610
|
+
url,
|
|
2611
|
+
signal ? { ...fetchOptions, signal } : fetchOptions,
|
|
2612
|
+
);
|
|
2613
|
+
if (!res.ok) {
|
|
2614
|
+
throw makeHttpError(res, await parseErrorBody(res), url, "POST");
|
|
1869
2615
|
}
|
|
2616
|
+
return res;
|
|
2617
|
+
});
|
|
2618
|
+
|
|
2619
|
+
const results = await response.json();
|
|
1870
2620
|
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
2621
|
+
// Extract document versions from each batch response
|
|
2622
|
+
for (const result of results) {
|
|
2623
|
+
if (result.headers && result.headers["X-Document-Versions"]) {
|
|
2624
|
+
try {
|
|
2625
|
+
const versionsMap = JSON.parse(
|
|
2626
|
+
result.headers["X-Document-Versions"],
|
|
2627
|
+
);
|
|
2628
|
+
if (typeof versionsMap === "object" && versionsMap !== null) {
|
|
2629
|
+
// Clone once per response, then merge — not once per entry.
|
|
2630
|
+
this.documentVersions = {
|
|
2631
|
+
...this.documentVersions,
|
|
2632
|
+
...versionsMap,
|
|
2633
|
+
};
|
|
1884
2634
|
}
|
|
2635
|
+
} catch (e) {
|
|
2636
|
+
console.warn(
|
|
2637
|
+
"Failed to parse document versions header from batch response:",
|
|
2638
|
+
e,
|
|
2639
|
+
);
|
|
1885
2640
|
}
|
|
1886
2641
|
}
|
|
1887
|
-
|
|
1888
|
-
return results.map(result => transformResponse(result));
|
|
1889
|
-
} catch (error) {
|
|
1890
|
-
if (error.status) throw error;
|
|
1891
|
-
throw makeNetworkError(error, url, 'POST');
|
|
1892
2642
|
}
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
2643
|
+
|
|
2644
|
+
return results.map((result) => transformResponse(result));
|
|
2645
|
+
} catch (error) {
|
|
2646
|
+
if (error.status) throw error;
|
|
2647
|
+
throw makeNetworkError(error, url, "POST");
|
|
1896
2648
|
}
|
|
1897
2649
|
}
|
|
1898
2650
|
|
|
@@ -1961,7 +2713,7 @@ class PlaidClient {
|
|
|
1961
2713
|
* @returns {string}
|
|
1962
2714
|
*/
|
|
1963
2715
|
static inviteUrl(appUrl, code) {
|
|
1964
|
-
return `${appUrl.replace(/#.*$/,
|
|
2716
|
+
return `${appUrl.replace(/#.*$/, "").replace(/\/$/, "")}/#/invite/${encodeURIComponent(code)}`;
|
|
1965
2717
|
}
|
|
1966
2718
|
|
|
1967
2719
|
/**
|
|
@@ -1975,63 +2727,90 @@ class PlaidClient {
|
|
|
1975
2727
|
* @param {string} baseUrl - The API base URL
|
|
1976
2728
|
* @param {string} code - The invite code
|
|
1977
2729
|
* @param {object} [options]
|
|
1978
|
-
* @returns {Promise<{kind: string, status: string, expiresAt: string, projectName?: string, projectRole?: string,
|
|
2730
|
+
* @returns {Promise<{kind: string, status: string, expiresAt: string, projectName?: string, projectRole?: string, email?: string, grantAdmin: boolean}>}
|
|
1979
2731
|
*/
|
|
1980
2732
|
static async lookupInvite(baseUrl, code, options = {}) {
|
|
1981
|
-
return anonymousPost(
|
|
2733
|
+
return anonymousPost(
|
|
2734
|
+
baseUrl,
|
|
2735
|
+
"/api/v1/invite-codes/lookup",
|
|
2736
|
+
{ code },
|
|
2737
|
+
options,
|
|
2738
|
+
);
|
|
1982
2739
|
}
|
|
1983
2740
|
|
|
1984
2741
|
/**
|
|
1985
2742
|
* Redeem an invite code, with NO authentication.
|
|
1986
2743
|
*
|
|
1987
|
-
* For a signup invite, pass `
|
|
1988
|
-
* the invite's grants are applied in the
|
|
1989
|
-
* reset link, pass `password` only.
|
|
1990
|
-
* like login() — the redeemer just
|
|
1991
|
-
* reason to send them to a login
|
|
2744
|
+
* For a signup invite, pass `email` and `password` to create the account
|
|
2745
|
+
* (and optionally `displayName`); the invite's grants are applied in the
|
|
2746
|
+
* same transaction. For a password reset link, pass `password` only.
|
|
2747
|
+
* Resolves to a logged-in client, exactly like login() — the redeemer just
|
|
2748
|
+
* chose these credentials, so there is no reason to send them to a login
|
|
2749
|
+
* form to retype them.
|
|
1992
2750
|
* @param {string} baseUrl - The API base URL
|
|
1993
2751
|
* @param {string} code - The invite code
|
|
1994
2752
|
* @param {object} credentials
|
|
1995
|
-
* @param {string} [credentials.
|
|
2753
|
+
* @param {string} [credentials.email] - The new account's email address,
|
|
2754
|
+
* which becomes its id and login (signup only)
|
|
2755
|
+
* @param {string} [credentials.displayName] - How the new user is shown in
|
|
2756
|
+
* the UI; defaults to the local part of the email (signup only)
|
|
1996
2757
|
* @param {string} credentials.password - Desired password (min 8 characters)
|
|
1997
2758
|
* @param {object} [options]
|
|
1998
2759
|
* @returns {Promise<{client: PlaidClient, userId: string, kind: string}>}
|
|
1999
2760
|
*/
|
|
2000
|
-
static async redeemInvite(
|
|
2761
|
+
static async redeemInvite(
|
|
2762
|
+
baseUrl,
|
|
2763
|
+
code,
|
|
2764
|
+
{ email, password, displayName } = {},
|
|
2765
|
+
options = {},
|
|
2766
|
+
) {
|
|
2001
2767
|
const data = await anonymousPost(
|
|
2002
|
-
baseUrl,
|
|
2003
|
-
|
|
2768
|
+
baseUrl,
|
|
2769
|
+
"/api/v1/invite-codes/redeem",
|
|
2770
|
+
bodyOf({ code, email, password, "display-name": displayName }),
|
|
2771
|
+
options,
|
|
2004
2772
|
);
|
|
2005
2773
|
return {
|
|
2006
|
-
client: new PlaidClient(
|
|
2774
|
+
client: new PlaidClient(
|
|
2775
|
+
baseUrl.replace(/\/$/, ""),
|
|
2776
|
+
data.token || "",
|
|
2777
|
+
options,
|
|
2778
|
+
),
|
|
2007
2779
|
userId: data.userId,
|
|
2008
2780
|
kind: data.kind,
|
|
2009
2781
|
};
|
|
2010
2782
|
}
|
|
2011
2783
|
|
|
2012
2784
|
static async login(baseUrl, userId, password, options = {}) {
|
|
2013
|
-
baseUrl = baseUrl.replace(/\/$/,
|
|
2785
|
+
baseUrl = baseUrl.replace(/\/$/, "");
|
|
2014
2786
|
const url = `${baseUrl}/api/v1/login`;
|
|
2015
2787
|
try {
|
|
2016
2788
|
const fetchOptions = {
|
|
2017
|
-
method:
|
|
2018
|
-
headers: {
|
|
2019
|
-
body: JSON.stringify({
|
|
2789
|
+
method: "POST",
|
|
2790
|
+
headers: { "Content-Type": "application/json" },
|
|
2791
|
+
body: JSON.stringify({ "user-id": userId, password }),
|
|
2020
2792
|
};
|
|
2021
|
-
const signal = timeoutSignal(
|
|
2793
|
+
const signal = timeoutSignal(
|
|
2794
|
+
options.timeout !== undefined ? options.timeout : DEFAULT_TIMEOUT_MS,
|
|
2795
|
+
);
|
|
2022
2796
|
if (signal) fetchOptions.signal = signal;
|
|
2023
2797
|
|
|
2024
2798
|
const response = await fetch(url, fetchOptions);
|
|
2025
2799
|
if (!response.ok) {
|
|
2026
|
-
throw makeHttpError(
|
|
2800
|
+
throw makeHttpError(
|
|
2801
|
+
response,
|
|
2802
|
+
await parseErrorBody(response),
|
|
2803
|
+
url,
|
|
2804
|
+
"POST",
|
|
2805
|
+
);
|
|
2027
2806
|
}
|
|
2028
2807
|
|
|
2029
2808
|
const data = await response.json();
|
|
2030
|
-
const token = data.token ||
|
|
2809
|
+
const token = data.token || "";
|
|
2031
2810
|
return new PlaidClient(baseUrl, token, options);
|
|
2032
2811
|
} catch (error) {
|
|
2033
2812
|
if (error.status) throw error;
|
|
2034
|
-
throw makeNetworkError(error, url,
|
|
2813
|
+
throw makeNetworkError(error, url, "POST");
|
|
2035
2814
|
}
|
|
2036
2815
|
}
|
|
2037
2816
|
}
|
|
@@ -2041,8 +2820,21 @@ export { PlaidClient };
|
|
|
2041
2820
|
|
|
2042
2821
|
// Unicode code-point helpers for text offsets (token begin/end are code-point
|
|
2043
2822
|
// indices). See ./codepoint.js.
|
|
2044
|
-
export {
|
|
2045
|
-
|
|
2823
|
+
export {
|
|
2824
|
+
cpLength,
|
|
2825
|
+
cpSlice,
|
|
2826
|
+
cpSlicer,
|
|
2827
|
+
utf16ToCp,
|
|
2828
|
+
cpToUtf16,
|
|
2829
|
+
cpIndexOf,
|
|
2830
|
+
} from "./codepoint.js";
|
|
2831
|
+
export {
|
|
2832
|
+
PLAID_NAMESPACE,
|
|
2833
|
+
ROLE_KEY,
|
|
2834
|
+
ROLES,
|
|
2835
|
+
readRole,
|
|
2836
|
+
findByRole,
|
|
2837
|
+
} from "./roles.js";
|
|
2046
2838
|
// Service self-description helpers: filter discovered services by task, read a
|
|
2047
2839
|
// service's parameter schema/summary, and build/coerce form values. See
|
|
2048
2840
|
// ./serviceSchema.js.
|
|
@@ -2054,20 +2846,34 @@ export {
|
|
|
2054
2846
|
getServiceSummary,
|
|
2055
2847
|
buildDefaultValues,
|
|
2056
2848
|
coerceParamValues,
|
|
2057
|
-
} from
|
|
2058
|
-
// Provenance: the cross-app convention for
|
|
2059
|
-
//
|
|
2060
|
-
//
|
|
2061
|
-
// "Provenance".
|
|
2849
|
+
} from "./serviceSchema.js";
|
|
2850
|
+
// Provenance: the cross-app convention for who made an annotation (flat
|
|
2851
|
+
// prov/provSource/provConfirmed metadata; absence = a verifier; 'inferred' =
|
|
2852
|
+
// a machine; 'contributed' = a person whose work is reviewed), plus the
|
|
2853
|
+
// machine-writer contract. See ./provenance.js and the manual, "Provenance".
|
|
2062
2854
|
export {
|
|
2063
2855
|
PROV,
|
|
2064
2856
|
PROV_STATES,
|
|
2065
2857
|
PROV_CONFIRMED,
|
|
2066
2858
|
stampInferred,
|
|
2067
2859
|
confirmedInferred,
|
|
2860
|
+
stampContributed,
|
|
2068
2861
|
provState,
|
|
2862
|
+
provOrigin,
|
|
2069
2863
|
isMachine,
|
|
2070
2864
|
isProtected,
|
|
2865
|
+
needsReview,
|
|
2071
2866
|
verifyOnEdit,
|
|
2867
|
+
contributeOnEdit,
|
|
2868
|
+
mergeMetadata,
|
|
2072
2869
|
serviceSource,
|
|
2073
|
-
|
|
2870
|
+
userSource,
|
|
2871
|
+
REVIEW_KEY,
|
|
2872
|
+
PROJECT_ROLES,
|
|
2873
|
+
readReview,
|
|
2874
|
+
projectRole,
|
|
2875
|
+
isReviewed,
|
|
2876
|
+
withReviewedUser,
|
|
2877
|
+
writerPolicy,
|
|
2878
|
+
} from "./provenance.js";
|
|
2879
|
+
export { MAX_BATCH_OPS };
|