@larc-iu/plaid-client 0.2.0-alpha.13 → 0.2.0-alpha.14
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 +132 -3
- package/package.json +1 -1
- package/src/documentLock.js +299 -0
- package/src/http.js +87 -14
- package/src/index.js +234 -50
- package/src/pagination.js +23 -35
- package/src/services.js +145 -21
package/src/index.js
CHANGED
|
@@ -15,6 +15,7 @@ import {
|
|
|
15
15
|
DEFAULT_BATCH_TIMEOUT_MS,
|
|
16
16
|
} from "./http.js";
|
|
17
17
|
import { listAll, listPage, iterPages } from "./pagination.js";
|
|
18
|
+
import { withDocumentLock } from "./documentLock.js";
|
|
18
19
|
import { createSSEConnection } from "./sse.js";
|
|
19
20
|
import {
|
|
20
21
|
discoverServices,
|
|
@@ -145,6 +146,10 @@ class PlaidClient {
|
|
|
145
146
|
this.batchOperations = [];
|
|
146
147
|
this.documentVersions = {};
|
|
147
148
|
this.strictModeDocumentId = null;
|
|
149
|
+
// Set to a DocumentLockLost while a `documents.locked()` block's keep-alive
|
|
150
|
+
// has failed. Every write throws it until the block exits; see
|
|
151
|
+
// documentLock.js.
|
|
152
|
+
this.documentLockLost = null;
|
|
148
153
|
// The open logical operation (audit-log group), or null. While set, every
|
|
149
154
|
// write is stamped with `?group-id=` (+ `group-message`) so the audit log
|
|
150
155
|
// folds them into ONE expandable entry. See beginOperation / withOperation.
|
|
@@ -229,6 +234,7 @@ class PlaidClient {
|
|
|
229
234
|
*/
|
|
230
235
|
get: (id, asOf) =>
|
|
231
236
|
this._request("GET", `/api/v1/vocab-links/${id}`, {
|
|
237
|
+
bypassBatch: true,
|
|
232
238
|
queryParams: { "as-of": asOf },
|
|
233
239
|
}),
|
|
234
240
|
/**
|
|
@@ -248,6 +254,7 @@ class PlaidClient {
|
|
|
248
254
|
*/
|
|
249
255
|
get: (id, includeItems, asOf) =>
|
|
250
256
|
this._request("GET", `/api/v1/vocab-layers/${id}`, {
|
|
257
|
+
bypassBatch: true,
|
|
251
258
|
queryParams: { "include-items": includeItems, "as-of": asOf },
|
|
252
259
|
}),
|
|
253
260
|
/**
|
|
@@ -294,7 +301,6 @@ class PlaidClient {
|
|
|
294
301
|
/**
|
|
295
302
|
* List all vocab layers accessible to user. Transparently follows
|
|
296
303
|
* pagination cursors and returns the full flat array.
|
|
297
|
-
* Cannot be used inside a batch (auto-paginates across requests); throws if called while batching — use listPage() for a single page in a batch.
|
|
298
304
|
* @param {string} [asOf] - Temporal query timestamp
|
|
299
305
|
*/
|
|
300
306
|
list: (asOf) =>
|
|
@@ -318,7 +324,6 @@ class PlaidClient {
|
|
|
318
324
|
* @param {object} [opts]
|
|
319
325
|
* @param {number} [opts.pageSize] - Per-request page size
|
|
320
326
|
* @param {string} [opts.asOf] - Temporal query timestamp
|
|
321
|
-
* 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.
|
|
322
327
|
* @returns {AsyncGenerator<Array>}
|
|
323
328
|
*/
|
|
324
329
|
iterPages: ({ pageSize, asOf } = {}) =>
|
|
@@ -408,6 +413,7 @@ class PlaidClient {
|
|
|
408
413
|
*/
|
|
409
414
|
get: (relationId, asOf) =>
|
|
410
415
|
this._request("GET", `/api/v1/relations/${relationId}`, {
|
|
416
|
+
bypassBatch: true,
|
|
411
417
|
queryParams: { "as-of": asOf },
|
|
412
418
|
}),
|
|
413
419
|
/**
|
|
@@ -477,7 +483,7 @@ class PlaidClient {
|
|
|
477
483
|
}),
|
|
478
484
|
/**
|
|
479
485
|
* Update many relations in a single operation: set values and/or patch metadata.
|
|
480
|
-
* @param {Array} body - Objects of the shape `{id, value?, metadata?}`. `value` is set only when the key is present (null sends JSON null); `metadata` is a patch, a null value deleting that key. The relations may lie in several documents of one project; every document touched has its version bumped. An unknown id refuses the whole update.
|
|
486
|
+
* @param {Array} body - Objects of the shape `{id, value?, metadata?}`. `value` is set only when the key is present (null sends JSON null); `metadata` is a patch, a null value deleting that key. The relations may lie in several documents of one project; every document touched has its version bumped and every new version comes back in `X-Document-Versions`. A `document-version` precondition is accepted only when every entry lies in one document. An unknown id refuses the whole update.
|
|
481
487
|
* @returns {Promise<{count: number}>} How many relations were updated.
|
|
482
488
|
*/
|
|
483
489
|
bulkUpdate: (body, auditMessage) =>
|
|
@@ -526,6 +532,7 @@ class PlaidClient {
|
|
|
526
532
|
*/
|
|
527
533
|
get: (spanLayerId, asOf) =>
|
|
528
534
|
this._request("GET", `/api/v1/span-layers/${spanLayerId}`, {
|
|
535
|
+
bypassBatch: true,
|
|
529
536
|
queryParams: { "as-of": asOf },
|
|
530
537
|
}),
|
|
531
538
|
/**
|
|
@@ -604,6 +611,7 @@ class PlaidClient {
|
|
|
604
611
|
*/
|
|
605
612
|
get: (spanId, asOf) =>
|
|
606
613
|
this._request("GET", `/api/v1/spans/${spanId}`, {
|
|
614
|
+
bypassBatch: true,
|
|
607
615
|
queryParams: { "as-of": asOf },
|
|
608
616
|
}),
|
|
609
617
|
/**
|
|
@@ -637,7 +645,7 @@ class PlaidClient {
|
|
|
637
645
|
this._request("DELETE", "/api/v1/spans/bulk", { auditMessage, body }),
|
|
638
646
|
/**
|
|
639
647
|
* Update many spans in a single operation: set values and/or patch metadata.
|
|
640
|
-
* @param {Array} body - Objects of the shape `{id, value?, metadata?}`. `value` is set only when the key is present (null sends JSON null); `metadata` is a patch, a null value deleting that key. The spans may lie in several documents of one project; every document touched has its version bumped. An unknown id refuses the whole update.
|
|
648
|
+
* @param {Array} body - Objects of the shape `{id, value?, metadata?}`. `value` is set only when the key is present (null sends JSON null); `metadata` is a patch, a null value deleting that key. The spans may lie in several documents of one project; every document touched has its version bumped and every new version comes back in `X-Document-Versions`. A `document-version` precondition is accepted only when every entry lies in one document. An unknown id refuses the whole update.
|
|
641
649
|
* @returns {Promise<{count: number}>} How many spans were updated.
|
|
642
650
|
*/
|
|
643
651
|
bulkUpdate: (body, auditMessage) =>
|
|
@@ -785,6 +793,7 @@ class PlaidClient {
|
|
|
785
793
|
*/
|
|
786
794
|
get: (textId, asOf) =>
|
|
787
795
|
this._request("GET", `/api/v1/texts/${textId}`, {
|
|
796
|
+
bypassBatch: true,
|
|
788
797
|
queryParams: { "as-of": asOf },
|
|
789
798
|
}),
|
|
790
799
|
/**
|
|
@@ -816,7 +825,6 @@ class PlaidClient {
|
|
|
816
825
|
/**
|
|
817
826
|
* List (or search) users. Transparently follows pagination cursors and
|
|
818
827
|
* returns the full flat array. Admin-or-maintainer only.
|
|
819
|
-
* Cannot be used inside a batch (auto-paginates across requests); throws if called while batching — use listPage() for a single page in a batch.
|
|
820
828
|
* @param {object} [opts]
|
|
821
829
|
* @param {string} [opts.q] - Filter to users whose display name or email contains this text (case-insensitive)
|
|
822
830
|
* @param {string} [opts.asOf] - Temporal query timestamp
|
|
@@ -844,7 +852,6 @@ class PlaidClient {
|
|
|
844
852
|
* @param {string} [opts.q] - Filter to users whose display name or email contains this text (case-insensitive)
|
|
845
853
|
* @param {number} [opts.pageSize] - Per-request page size
|
|
846
854
|
* @param {string} [opts.asOf] - Temporal query timestamp
|
|
847
|
-
* 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.
|
|
848
855
|
* @returns {AsyncGenerator<Array>}
|
|
849
856
|
*/
|
|
850
857
|
iterPages: ({ q, pageSize, asOf } = {}) =>
|
|
@@ -874,7 +881,6 @@ class PlaidClient {
|
|
|
874
881
|
/**
|
|
875
882
|
* Get audit log for a user's actions. Transparently follows pagination
|
|
876
883
|
* cursors and returns the full flat array.
|
|
877
|
-
* Cannot be used inside a batch (auto-paginates across requests); throws if called while batching — use listPage() for a single page in a batch.
|
|
878
884
|
* @param {string} userId - The user ID
|
|
879
885
|
* @param {string} [startTime] - Start of time range
|
|
880
886
|
* @param {string} [endTime] - End of time range
|
|
@@ -925,6 +931,7 @@ class PlaidClient {
|
|
|
925
931
|
*/
|
|
926
932
|
get: (id, asOf) =>
|
|
927
933
|
this._request("GET", `/api/v1/users/${id}`, {
|
|
934
|
+
bypassBatch: true,
|
|
928
935
|
queryParams: { "as-of": asOf },
|
|
929
936
|
}),
|
|
930
937
|
/**
|
|
@@ -994,7 +1001,7 @@ class PlaidClient {
|
|
|
994
1001
|
*/
|
|
995
1002
|
getAvatar: (id) =>
|
|
996
1003
|
this._request("GET", `/api/v1/users/${id}/avatar`, {
|
|
997
|
-
|
|
1004
|
+
bypassBatch: true,
|
|
998
1005
|
binaryResponse: true,
|
|
999
1006
|
}),
|
|
1000
1007
|
/**
|
|
@@ -1019,32 +1026,86 @@ class PlaidClient {
|
|
|
1019
1026
|
* Remove a profile picture. Your own, or anyone's if you are an admin.
|
|
1020
1027
|
* @param {string} id - The user ID
|
|
1021
1028
|
*/
|
|
1029
|
+
// No flag: the upload beside this one is multipart and cannot be
|
|
1030
|
+
// batched, but a DELETE carries no blob, so the batch transport takes
|
|
1031
|
+
// it. It is an ordinary audited write and queues like any other.
|
|
1022
1032
|
deleteAvatar: (id, auditMessage) =>
|
|
1023
1033
|
this._request("DELETE", `/api/v1/users/${id}/avatar`, {
|
|
1024
1034
|
auditMessage,
|
|
1025
|
-
noBatch: true,
|
|
1026
1035
|
}),
|
|
1027
1036
|
};
|
|
1028
1037
|
|
|
1029
1038
|
this.userData = {
|
|
1030
1039
|
/**
|
|
1031
1040
|
* List a user's private data entries ({key, updatedAt}, plus value when
|
|
1032
|
-
* includeValues). Owner or admin only.
|
|
1041
|
+
* includeValues), ordered by key. Owner or admin only. Transparently
|
|
1042
|
+
* follows pagination cursors and returns the full flat array.
|
|
1033
1043
|
*
|
|
1034
1044
|
* Narrow with `prefix` (the literal head of a key) and/or `pattern`, a
|
|
1035
1045
|
* GLOB over the whole key (`*` any run, `?` one character) — the way to
|
|
1036
1046
|
* ask for a key convention identified by a segment in the middle, e.g.
|
|
1037
1047
|
* `igt:assistant:*:meta:*` for every conversation's sidebar entry across
|
|
1038
1048
|
* every project without dragging down the transcripts beside them.
|
|
1049
|
+
*
|
|
1050
|
+
* `pageSize` is exposed here, and defaults lower than elsewhere, because
|
|
1051
|
+
* one value runs to 1 MB: a page of them with `includeValues` is the
|
|
1052
|
+
* largest response this API can be asked for. Raise it when the listing
|
|
1053
|
+
* is keys, or the values are known to be small.
|
|
1054
|
+
* @param {string} userId
|
|
1055
|
+
* @param {object} [opts]
|
|
1056
|
+
* @param {string} [opts.prefix] - Only keys starting with this prefix
|
|
1057
|
+
* @param {string} [opts.pattern] - Only keys matching this GLOB
|
|
1058
|
+
* @param {boolean} [opts.includeValues] - Also return each entry's value
|
|
1059
|
+
* @param {number} [opts.pageSize=100] - Entries per request (1..1000)
|
|
1060
|
+
*/
|
|
1061
|
+
list: (userId, { prefix, pattern, includeValues, pageSize = 100 } = {}) =>
|
|
1062
|
+
// Every page carries bypassBatch (the pagination helpers set it): a
|
|
1063
|
+
// read belongs to whoever asked for it, not to whatever batch happens
|
|
1064
|
+
// to be open on this shared client. The assistant panel is app chrome
|
|
1065
|
+
// in both SPAs, so it reads this store while an import or a bulk edit
|
|
1066
|
+
// holds a batch open. Queued, the read answered `{batched: true}` (the
|
|
1067
|
+
// sidebar then threw on `.map`) and took a slot in the batch's
|
|
1068
|
+
// results, shifting every index the caller counted on.
|
|
1069
|
+
listAll(this, `/api/v1/users/${userId}/data`, {
|
|
1070
|
+
pageSize,
|
|
1071
|
+
query: { prefix, pattern, "include-values": includeValues },
|
|
1072
|
+
}),
|
|
1073
|
+
/**
|
|
1074
|
+
* One page of a user's private data entries, ordered by key.
|
|
1075
|
+
* @param {string} userId
|
|
1076
|
+
* @param {object} [opts]
|
|
1077
|
+
* @param {string} [opts.prefix] - Only keys starting with this prefix
|
|
1078
|
+
* @param {string} [opts.pattern] - Only keys matching this GLOB
|
|
1079
|
+
* @param {boolean} [opts.includeValues] - Also return each entry's value
|
|
1080
|
+
* @param {number} [opts.limit] - Page size (1..1000; server default 100)
|
|
1081
|
+
* @param {string} [opts.cursor] - Opaque cursor from a previous page
|
|
1082
|
+
* @returns {Promise<{entries: Array, nextCursor: (string|null)}>}
|
|
1083
|
+
*/
|
|
1084
|
+
listPage: (
|
|
1085
|
+
userId,
|
|
1086
|
+
{ prefix, pattern, includeValues, limit, cursor } = {},
|
|
1087
|
+
) =>
|
|
1088
|
+
listPage(this, `/api/v1/users/${userId}/data`, {
|
|
1089
|
+
limit,
|
|
1090
|
+
cursor,
|
|
1091
|
+
query: { prefix, pattern, "include-values": includeValues },
|
|
1092
|
+
}),
|
|
1093
|
+
/**
|
|
1094
|
+
* Async generator over a user's private data entries, one page at a time.
|
|
1039
1095
|
* @param {string} userId
|
|
1040
1096
|
* @param {object} [opts]
|
|
1041
1097
|
* @param {string} [opts.prefix] - Only keys starting with this prefix
|
|
1042
1098
|
* @param {string} [opts.pattern] - Only keys matching this GLOB
|
|
1043
1099
|
* @param {boolean} [opts.includeValues] - Also return each entry's value
|
|
1100
|
+
* @param {number} [opts.pageSize=100] - Entries per request (1..1000)
|
|
1044
1101
|
*/
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1102
|
+
iterPages: (
|
|
1103
|
+
userId,
|
|
1104
|
+
{ prefix, pattern, includeValues, pageSize = 100 } = {},
|
|
1105
|
+
) =>
|
|
1106
|
+
iterPages(this, `/api/v1/users/${userId}/data`, {
|
|
1107
|
+
pageSize,
|
|
1108
|
+
query: { prefix, pattern, "include-values": includeValues },
|
|
1048
1109
|
}),
|
|
1049
1110
|
/**
|
|
1050
1111
|
* Read one private data entry ({key, updatedAt, value}); 404 if absent.
|
|
@@ -1052,9 +1113,11 @@ class PlaidClient {
|
|
|
1052
1113
|
* @param {string} key
|
|
1053
1114
|
*/
|
|
1054
1115
|
get: (userId, key) =>
|
|
1116
|
+
// bypassBatch for the same reason as list() above.
|
|
1055
1117
|
this._request(
|
|
1056
1118
|
"GET",
|
|
1057
1119
|
`/api/v1/users/${userId}/data/${encodeURIComponent(key)}`,
|
|
1120
|
+
{ bypassBatch: true },
|
|
1058
1121
|
),
|
|
1059
1122
|
/**
|
|
1060
1123
|
* Create or replace one private data entry. `value` is any JSON (up to
|
|
@@ -1098,7 +1161,6 @@ class PlaidClient {
|
|
|
1098
1161
|
* List a user's named API tokens. Never includes the signed token
|
|
1099
1162
|
* string itself — that is only returned once, by create().
|
|
1100
1163
|
* Transparently follows pagination cursors and returns the full flat array.
|
|
1101
|
-
* Cannot be used inside a batch (auto-paginates across requests); throws if called while batching — use listPage() for a single page in a batch.
|
|
1102
1164
|
* @param {string} userId - The user ID who owns the tokens
|
|
1103
1165
|
*/
|
|
1104
1166
|
list: (userId) => listAll(this, `/api/v1/users/${userId}/tokens`),
|
|
@@ -1118,7 +1180,6 @@ class PlaidClient {
|
|
|
1118
1180
|
* @param {string} userId - The user ID who owns the tokens
|
|
1119
1181
|
* @param {object} [opts]
|
|
1120
1182
|
* @param {number} [opts.pageSize] - Per-request page size
|
|
1121
|
-
* 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.
|
|
1122
1183
|
* @returns {AsyncGenerator<Array>}
|
|
1123
1184
|
*/
|
|
1124
1185
|
iterPages: (userId, { pageSize } = {}) =>
|
|
@@ -1154,7 +1215,6 @@ class PlaidClient {
|
|
|
1154
1215
|
* maintainer or admin on it. Never includes invite codes — the code is
|
|
1155
1216
|
* returned once, by create(), and is not recoverable afterward.
|
|
1156
1217
|
* Transparently follows pagination cursors and returns the full flat array.
|
|
1157
|
-
* Cannot be used inside a batch (auto-paginates across requests); throws if called while batching — use listPage() for a single page in a batch.
|
|
1158
1218
|
* @param {object} [opts]
|
|
1159
1219
|
* @param {string} [opts.projectId] - List this project's invites instead of your own
|
|
1160
1220
|
* @param {boolean} [opts.all] - List every invite on the server (admin only)
|
|
@@ -1184,7 +1244,6 @@ class PlaidClient {
|
|
|
1184
1244
|
* @param {string} [opts.projectId] - List this project's invites instead of your own
|
|
1185
1245
|
* @param {boolean} [opts.all] - List every invite on the server (admin only)
|
|
1186
1246
|
* @param {number} [opts.pageSize] - Per-request page size
|
|
1187
|
-
* 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.
|
|
1188
1247
|
* @returns {AsyncGenerator<Array>}
|
|
1189
1248
|
*/
|
|
1190
1249
|
iterPages: ({ projectId, all, pageSize } = {}) =>
|
|
@@ -1259,35 +1318,48 @@ class PlaidClient {
|
|
|
1259
1318
|
* walks the media directory, so open it, do not poll it. Admin only.
|
|
1260
1319
|
* @returns {Promise<{version: string, jvm: object, database: object, media: object, backup: object, settings: object}>}
|
|
1261
1320
|
*/
|
|
1262
|
-
server: () =>
|
|
1321
|
+
server: () =>
|
|
1322
|
+
this._request("GET", "/api/v1/admin/server", { bypassBatch: true }),
|
|
1263
1323
|
/**
|
|
1264
1324
|
* Take a database backup right now, outside the nightly schedule.
|
|
1265
1325
|
* Resolves to the backup block with `ok` reporting whether the snapshot
|
|
1266
1326
|
* succeeded. Uses VACUUM INTO, which only reads, so it is safe while
|
|
1267
1327
|
* people are working. Admin only.
|
|
1268
1328
|
* @returns {Promise<{ok: boolean, directory: string, backups: Array}>}
|
|
1329
|
+
*
|
|
1330
|
+
* Goes over the wire even while a batch is open, as every admin action
|
|
1331
|
+
* on the server itself does: none of them writes project data, and a
|
|
1332
|
+
* backup taken inside somebody's open write transaction is not what the
|
|
1333
|
+
* caller asked for.
|
|
1269
1334
|
*/
|
|
1270
|
-
backup: () =>
|
|
1335
|
+
backup: () =>
|
|
1336
|
+
this._request("POST", "/api/v1/admin/backup", { bypassBatch: true }),
|
|
1271
1337
|
/**
|
|
1272
1338
|
* Documents currently held by an editing lock, with who holds each and
|
|
1273
1339
|
* when it expires on its own. Admin only.
|
|
1274
1340
|
* @returns {Promise<{entries: Array<{documentId: string, userId: string, expiresAt: number}>}>}
|
|
1275
1341
|
*/
|
|
1276
|
-
locks: () =>
|
|
1342
|
+
locks: () =>
|
|
1343
|
+
this._request("GET", "/api/v1/admin/locks", { bypassBatch: true }),
|
|
1277
1344
|
/**
|
|
1278
1345
|
* Drop the lock on a document whoever holds it. Idempotent. For a client
|
|
1279
1346
|
* that went away without releasing one. Admin only.
|
|
1280
1347
|
* @param {string} documentId - The document ID
|
|
1281
1348
|
*/
|
|
1282
1349
|
releaseLock: (documentId) =>
|
|
1283
|
-
this._request("DELETE", `/api/v1/admin/locks/${documentId}
|
|
1350
|
+
this._request("DELETE", `/api/v1/admin/locks/${documentId}`, {
|
|
1351
|
+
bypassBatch: true,
|
|
1352
|
+
}),
|
|
1284
1353
|
/**
|
|
1285
1354
|
* Live login and invite rate-limit buckets: the address, the account
|
|
1286
1355
|
* where there is one, failures inside the window, the limit, and whether
|
|
1287
1356
|
* it is currently blocking. Admin only.
|
|
1288
1357
|
* @returns {Promise<{windowMs: number, logins: Array, ips: Array, invites: Array}>}
|
|
1289
1358
|
*/
|
|
1290
|
-
rateLimits: () =>
|
|
1359
|
+
rateLimits: () =>
|
|
1360
|
+
this._request("GET", "/api/v1/admin/rate-limits", {
|
|
1361
|
+
bypassBatch: true,
|
|
1362
|
+
}),
|
|
1291
1363
|
/**
|
|
1292
1364
|
* Forget recorded rate-limit failures. With `ip`, clears that address,
|
|
1293
1365
|
* narrowed to one account with `userId`. With neither, clears every
|
|
@@ -1298,18 +1370,45 @@ class PlaidClient {
|
|
|
1298
1370
|
*/
|
|
1299
1371
|
clearRateLimits: ({ ip, userId } = {}) =>
|
|
1300
1372
|
this._request("DELETE", "/api/v1/admin/rate-limits", {
|
|
1373
|
+
bypassBatch: true,
|
|
1301
1374
|
queryParams: { ip, "user-id": userId },
|
|
1302
1375
|
}),
|
|
1303
1376
|
/**
|
|
1304
|
-
*
|
|
1305
|
-
*
|
|
1306
|
-
*
|
|
1377
|
+
* What the server has logged, structured and filtered, from an in-memory
|
|
1378
|
+
* buffer kept whether or not a log file is configured. `requests` is one
|
|
1379
|
+
* entry per HTTP request (method, path, status, duration, and who made
|
|
1380
|
+
* it), `events` is everything else, with a stack trace where there was
|
|
1381
|
+
* one. They are buffered separately so a burst of requests cannot evict
|
|
1382
|
+
* an error. Both come newest first, `matched` counts what passed the
|
|
1383
|
+
* filters, and request `stats` describe the filtered set. Covers Plaid's
|
|
1384
|
+
* own log stream since the last restart: for library messages and older
|
|
1385
|
+
* history, see `logFile`. Admin only.
|
|
1386
|
+
* @param {object} [opts]
|
|
1387
|
+
* @param {number} [opts.limit] - Max entries per kind (default 200, max 2000)
|
|
1388
|
+
* @param {string} [opts.q] - Substring of any field, case-insensitive
|
|
1389
|
+
* @param {string} [opts.level] - Minimum level for events, e.g. "warn"
|
|
1390
|
+
* @param {string} [opts.status] - "2xx".."5xx", an exact code, or "failures"
|
|
1391
|
+
* @param {string} [opts.user] - Only requests made by this account
|
|
1392
|
+
* @param {string} [opts.method] - Only requests with this HTTP method
|
|
1393
|
+
* @returns {Promise<{requests: object, events: object, file: (string|null)}>}
|
|
1394
|
+
*/
|
|
1395
|
+
logs: ({ limit, q, level, status, user, method } = {}) =>
|
|
1396
|
+
this._request("GET", "/api/v1/admin/logs", {
|
|
1397
|
+
bypassBatch: true,
|
|
1398
|
+
queryParams: { limit, q, level, status, user, method },
|
|
1399
|
+
}),
|
|
1400
|
+
/**
|
|
1401
|
+
* The tail of the configured log file, as text lines. The only place
|
|
1402
|
+
* third-party library messages and anything from before the last restart
|
|
1403
|
+
* can be read. Resolves with an `error` string instead of lines when no
|
|
1404
|
+
* log file is configured or it does not exist yet. Admin only.
|
|
1307
1405
|
* @param {object} [opts]
|
|
1308
1406
|
* @param {number} [opts.lines] - How many lines (default 200, max 2000)
|
|
1309
1407
|
* @returns {Promise<{file: (string|null), lines: string[], error?: string}>}
|
|
1310
1408
|
*/
|
|
1311
|
-
|
|
1312
|
-
this._request("GET", "/api/v1/admin/logs", {
|
|
1409
|
+
logFile: ({ lines } = {}) =>
|
|
1410
|
+
this._request("GET", "/api/v1/admin/logs/file", {
|
|
1411
|
+
bypassBatch: true,
|
|
1313
1412
|
queryParams: { lines },
|
|
1314
1413
|
}),
|
|
1315
1414
|
/**
|
|
@@ -1323,7 +1422,6 @@ class PlaidClient {
|
|
|
1323
1422
|
* ask for a key convention identified by a segment in the middle, e.g.
|
|
1324
1423
|
* `igt:assistant:*:meta:*`. Values come only with `includeValues`, and
|
|
1325
1424
|
* are recased like any other body (see `userData.put`).
|
|
1326
|
-
* Cannot be used inside a batch (auto-paginates across requests); throws if called while batching — use userDataPage() for a single page in a batch.
|
|
1327
1425
|
* @param {object} [opts]
|
|
1328
1426
|
* @param {string} [opts.prefix] - Only keys starting with this
|
|
1329
1427
|
* @param {string} [opts.pattern] - Only keys matching this GLOB
|
|
@@ -1367,7 +1465,6 @@ class PlaidClient {
|
|
|
1367
1465
|
* and op-type filter as the per-project read, with the entity scope
|
|
1368
1466
|
* dropped. Admin only. Transparently follows pagination cursors and
|
|
1369
1467
|
* returns the full flat array.
|
|
1370
|
-
* Cannot be used inside a batch (auto-paginates across requests); throws if called while batching — use listPage() for a single page in a batch.
|
|
1371
1468
|
* @param {object} [opts]
|
|
1372
1469
|
* @param {string} [opts.startTime] - Only operations at or after this instant
|
|
1373
1470
|
* @param {string} [opts.endTime] - Only operations at or before this instant
|
|
@@ -1405,7 +1502,6 @@ class PlaidClient {
|
|
|
1405
1502
|
}),
|
|
1406
1503
|
/**
|
|
1407
1504
|
* Async-iterate the instance-wide audit log page by page. Admin only.
|
|
1408
|
-
* 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.
|
|
1409
1505
|
* @returns {AsyncGenerator<Array>}
|
|
1410
1506
|
*/
|
|
1411
1507
|
iterPages: ({ startTime, endTime, opTypes, pageSize } = {}) =>
|
|
@@ -1440,6 +1536,7 @@ class PlaidClient {
|
|
|
1440
1536
|
? `/api/v1/projects/${projectId}/audit/tally`
|
|
1441
1537
|
: "/api/v1/audit/tally";
|
|
1442
1538
|
const result = await this._request("GET", path, {
|
|
1539
|
+
bypassBatch: true,
|
|
1443
1540
|
queryParams: {
|
|
1444
1541
|
"start-time": startTime,
|
|
1445
1542
|
"end-time": endTime,
|
|
@@ -1522,6 +1619,7 @@ class PlaidClient {
|
|
|
1522
1619
|
*/
|
|
1523
1620
|
get: (tokenLayerId, asOf) =>
|
|
1524
1621
|
this._request("GET", `/api/v1/token-layers/${tokenLayerId}`, {
|
|
1622
|
+
bypassBatch: true,
|
|
1525
1623
|
queryParams: { "as-of": asOf },
|
|
1526
1624
|
}),
|
|
1527
1625
|
/**
|
|
@@ -1552,24 +1650,72 @@ class PlaidClient {
|
|
|
1552
1650
|
*/
|
|
1553
1651
|
checkLock: (documentId, asOf) =>
|
|
1554
1652
|
this._request("GET", `/api/v1/documents/${documentId}/lock`, {
|
|
1653
|
+
bypassBatch: true,
|
|
1555
1654
|
queryParams: { "as-of": asOf },
|
|
1556
1655
|
}),
|
|
1557
1656
|
/**
|
|
1558
|
-
* Acquire or refresh a document lock
|
|
1657
|
+
* Acquire or refresh a document lock.
|
|
1658
|
+
*
|
|
1659
|
+
* Goes over the wire even while a batch is open. The lock is an
|
|
1660
|
+
* out-of-band signal, not project data: a queued acquire is taken only
|
|
1661
|
+
* when the batch submits, which is after every write it was meant to
|
|
1662
|
+
* guard, and until then it answers success to a caller that does not
|
|
1663
|
+
* hold it and cannot see the 423 saying somebody else does.
|
|
1559
1664
|
* @param {string} documentId - The document ID
|
|
1560
1665
|
*/
|
|
1561
1666
|
acquireLock: (documentId, auditMessage) =>
|
|
1562
1667
|
this._request("POST", `/api/v1/documents/${documentId}/lock`, {
|
|
1563
1668
|
auditMessage,
|
|
1669
|
+
bypassBatch: true,
|
|
1564
1670
|
}),
|
|
1565
1671
|
/**
|
|
1566
|
-
* Release a document lock
|
|
1672
|
+
* Release a document lock. Goes over the wire even while a batch is
|
|
1673
|
+
* open, for the same reason as acquireLock: queued, the lock is held
|
|
1674
|
+
* until the batch submits, and not released at all if it aborts.
|
|
1567
1675
|
* @param {string} documentId - The document ID
|
|
1568
1676
|
*/
|
|
1569
1677
|
releaseLock: (documentId, auditMessage) =>
|
|
1570
1678
|
this._request("DELETE", `/api/v1/documents/${documentId}/lock`, {
|
|
1571
1679
|
auditMessage,
|
|
1680
|
+
bypassBatch: true,
|
|
1572
1681
|
}),
|
|
1682
|
+
/**
|
|
1683
|
+
* Hold this document's server-enforced lock for the length of `fn`,
|
|
1684
|
+
* releasing it on the way out (including on error). Resolves to what
|
|
1685
|
+
* `fn` returned.
|
|
1686
|
+
*
|
|
1687
|
+
* await client.documents.locked(docId, async () => {
|
|
1688
|
+
* // delete + recreate tokens
|
|
1689
|
+
* });
|
|
1690
|
+
*
|
|
1691
|
+
* Wrap any multi-step, server-side mutation of a document that must not
|
|
1692
|
+
* interleave with a human editor or another service, e.g. a parser or
|
|
1693
|
+
* tokenizer that deletes and recreates a document's tokens, spans and
|
|
1694
|
+
* relations. A single atomic call does not need it. While the lock is
|
|
1695
|
+
* held, writes to the document by ANOTHER user are refused with HTTP
|
|
1696
|
+
* 423; the holder's own writes pass and renew it. If another user
|
|
1697
|
+
* already holds it this rejects with a readable 423 and `fn` does not
|
|
1698
|
+
* run.
|
|
1699
|
+
*
|
|
1700
|
+
* The lock is renewed for as long as `fn` runs, so work that computes
|
|
1701
|
+
* for minutes before it writes holds the lock the whole time rather than
|
|
1702
|
+
* only for its first minute. If a renewal fails the lock is gone: every
|
|
1703
|
+
* later write from this client throws `DocumentLockLost`, and a block
|
|
1704
|
+
* that got to the end anyway ends with that error rather than reporting
|
|
1705
|
+
* success. `fn` receives a lock handle and may read `lock.lost` (or call
|
|
1706
|
+
* `lock.raiseIfLost()`) to give up sooner.
|
|
1707
|
+
*
|
|
1708
|
+
* NOT re-entrant: nesting two `locked()` blocks on one document would
|
|
1709
|
+
* release on the inner exit and leave the outer unprotected. Lock at
|
|
1710
|
+
* exactly one level per call path. A lost lock is recorded on the
|
|
1711
|
+
* CLIENT, like batch and strict mode, so it stops every write the client
|
|
1712
|
+
* makes and not only the ones this block makes.
|
|
1713
|
+
* @param {string} documentId - The document ID
|
|
1714
|
+
* @param {(lock: DocumentLock) => any} fn - The work to run while holding it
|
|
1715
|
+
* @param {object} [options] - `{ keepAlive }`: renew on a timer (default true)
|
|
1716
|
+
*/
|
|
1717
|
+
locked: (documentId, fn, options) =>
|
|
1718
|
+
withDocumentLock(this, documentId, fn, options),
|
|
1573
1719
|
/**
|
|
1574
1720
|
* Get the media file for a document. Media is not versioned, so there is
|
|
1575
1721
|
* no as-of form: the route refuses the parameter. Prefer the document's
|
|
@@ -1578,7 +1724,7 @@ class PlaidClient {
|
|
|
1578
1724
|
*/
|
|
1579
1725
|
getMedia: (documentId) =>
|
|
1580
1726
|
this._request("GET", `/api/v1/documents/${documentId}/media`, {
|
|
1581
|
-
|
|
1727
|
+
bypassBatch: true,
|
|
1582
1728
|
binaryResponse: true,
|
|
1583
1729
|
}),
|
|
1584
1730
|
/**
|
|
@@ -1603,10 +1749,14 @@ class PlaidClient {
|
|
|
1603
1749
|
* Delete media file for a document
|
|
1604
1750
|
* @param {string} documentId - The document ID
|
|
1605
1751
|
*/
|
|
1752
|
+
// No flag: the upload above is multipart and cannot be batched, but a
|
|
1753
|
+
// DELETE carries no blob, so the batch transport takes it. It is a write
|
|
1754
|
+
// of the document's own data and queues like any other. Note that the
|
|
1755
|
+
// file removal happens outside the server's transaction, so a batch that
|
|
1756
|
+
// aborts after this op does not bring the file back.
|
|
1606
1757
|
deleteMedia: (documentId, auditMessage) =>
|
|
1607
1758
|
this._request("DELETE", `/api/v1/documents/${documentId}/media`, {
|
|
1608
1759
|
auditMessage,
|
|
1609
|
-
noBatch: true,
|
|
1610
1760
|
}),
|
|
1611
1761
|
/**
|
|
1612
1762
|
* Replace all metadata for a document.
|
|
@@ -1642,7 +1792,6 @@ class PlaidClient {
|
|
|
1642
1792
|
/**
|
|
1643
1793
|
* Get audit log for a document. Transparently follows pagination cursors
|
|
1644
1794
|
* and returns the full flat array.
|
|
1645
|
-
* Cannot be used inside a batch (auto-paginates across requests); throws if called while batching — use listPage() for a single page in a batch.
|
|
1646
1795
|
* @param {string} documentId - The document ID
|
|
1647
1796
|
* @param {string} [startTime] - Start of time range
|
|
1648
1797
|
* @param {string} [endTime] - End of time range
|
|
@@ -1725,6 +1874,7 @@ class PlaidClient {
|
|
|
1725
1874
|
*/
|
|
1726
1875
|
get: (documentId, includeBody, asOf, layers) =>
|
|
1727
1876
|
this._request("GET", `/api/v1/documents/${documentId}`, {
|
|
1877
|
+
bypassBatch: true,
|
|
1728
1878
|
queryParams: {
|
|
1729
1879
|
"include-body": includeBody,
|
|
1730
1880
|
"as-of": asOf,
|
|
@@ -1866,7 +2016,6 @@ class PlaidClient {
|
|
|
1866
2016
|
/**
|
|
1867
2017
|
* Get audit log for a project. Transparently follows pagination cursors
|
|
1868
2018
|
* and returns the full flat array.
|
|
1869
|
-
* Cannot be used inside a batch (auto-paginates across requests); throws if called while batching — use listPage() for a single page in a batch.
|
|
1870
2019
|
* @param {string} projectId - The project ID
|
|
1871
2020
|
* @param {string} [startTime] - Start of time range
|
|
1872
2021
|
* @param {string} [endTime] - End of time range
|
|
@@ -1922,6 +2071,7 @@ class PlaidClient {
|
|
|
1922
2071
|
*/
|
|
1923
2072
|
myLastEdits: (projectId) =>
|
|
1924
2073
|
this._request("GET", `/api/v1/projects/${projectId}/audit/last-edits`, {
|
|
2074
|
+
bypassBatch: true,
|
|
1925
2075
|
skipResponseTransform: true,
|
|
1926
2076
|
}),
|
|
1927
2077
|
/**
|
|
@@ -1950,12 +2100,12 @@ class PlaidClient {
|
|
|
1950
2100
|
*/
|
|
1951
2101
|
get: (id, asOf) =>
|
|
1952
2102
|
this._request("GET", `/api/v1/projects/${id}`, {
|
|
2103
|
+
bypassBatch: true,
|
|
1953
2104
|
queryParams: { "as-of": asOf },
|
|
1954
2105
|
}),
|
|
1955
2106
|
/**
|
|
1956
2107
|
* List all documents in a project. Transparently follows pagination
|
|
1957
2108
|
* cursors and returns the full flat array.
|
|
1958
|
-
* Cannot be used inside a batch (auto-paginates across requests); throws if called while batching — use listPage() for a single page in a batch.
|
|
1959
2109
|
*
|
|
1960
2110
|
* Note: this endpoint does not support temporal (`as-of`) queries; the
|
|
1961
2111
|
* server rejects `?as-of=` on the documents-list route with a 400.
|
|
@@ -1984,7 +2134,6 @@ class PlaidClient {
|
|
|
1984
2134
|
* @param {string} id - The project ID
|
|
1985
2135
|
* @param {object} [opts]
|
|
1986
2136
|
* @param {number} [opts.pageSize] - Per-request page size
|
|
1987
|
-
* 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.
|
|
1988
2137
|
* @returns {AsyncGenerator<Array>}
|
|
1989
2138
|
*/
|
|
1990
2139
|
iterDocuments: (id, { pageSize } = {}) =>
|
|
@@ -2018,7 +2167,6 @@ class PlaidClient {
|
|
|
2018
2167
|
/**
|
|
2019
2168
|
* List all projects accessible to user. Transparently follows pagination
|
|
2020
2169
|
* cursors and returns the full flat array.
|
|
2021
|
-
* Cannot be used inside a batch (auto-paginates across requests); throws if called while batching — use listPage() for a single page in a batch.
|
|
2022
2170
|
* @param {string} [asOf] - Temporal query timestamp
|
|
2023
2171
|
*/
|
|
2024
2172
|
list: (asOf) =>
|
|
@@ -2042,7 +2190,6 @@ class PlaidClient {
|
|
|
2042
2190
|
* @param {object} [opts]
|
|
2043
2191
|
* @param {number} [opts.pageSize] - Per-request page size
|
|
2044
2192
|
* @param {string} [opts.asOf] - Temporal query timestamp
|
|
2045
|
-
* 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.
|
|
2046
2193
|
* @returns {AsyncGenerator<Array>}
|
|
2047
2194
|
*/
|
|
2048
2195
|
iterPages: ({ pageSize, asOf } = {}) =>
|
|
@@ -2100,6 +2247,7 @@ class PlaidClient {
|
|
|
2100
2247
|
*/
|
|
2101
2248
|
get: (textLayerId, asOf) =>
|
|
2102
2249
|
this._request("GET", `/api/v1/text-layers/${textLayerId}`, {
|
|
2250
|
+
bypassBatch: true,
|
|
2103
2251
|
queryParams: { "as-of": asOf },
|
|
2104
2252
|
}),
|
|
2105
2253
|
/**
|
|
@@ -2212,6 +2360,7 @@ class PlaidClient {
|
|
|
2212
2360
|
*/
|
|
2213
2361
|
get: (id, asOf) =>
|
|
2214
2362
|
this._request("GET", `/api/v1/vocab-items/${id}`, {
|
|
2363
|
+
bypassBatch: true,
|
|
2215
2364
|
queryParams: { "as-of": asOf },
|
|
2216
2365
|
}),
|
|
2217
2366
|
/**
|
|
@@ -2292,6 +2441,7 @@ class PlaidClient {
|
|
|
2292
2441
|
*/
|
|
2293
2442
|
get: (relationLayerId, asOf) =>
|
|
2294
2443
|
this._request("GET", `/api/v1/relation-layers/${relationLayerId}`, {
|
|
2444
|
+
bypassBatch: true,
|
|
2295
2445
|
queryParams: { "as-of": asOf },
|
|
2296
2446
|
}),
|
|
2297
2447
|
/**
|
|
@@ -2360,6 +2510,7 @@ class PlaidClient {
|
|
|
2360
2510
|
*/
|
|
2361
2511
|
get: (tokenId, asOf) =>
|
|
2362
2512
|
this._request("GET", `/api/v1/tokens/${tokenId}`, {
|
|
2513
|
+
bypassBatch: true,
|
|
2363
2514
|
queryParams: { "as-of": asOf },
|
|
2364
2515
|
}),
|
|
2365
2516
|
/**
|
|
@@ -2399,7 +2550,7 @@ class PlaidClient {
|
|
|
2399
2550
|
this._request("DELETE", "/api/v1/tokens/bulk", { auditMessage, body }),
|
|
2400
2551
|
/**
|
|
2401
2552
|
* Update many tokens in a single operation: patch metadata.
|
|
2402
|
-
* @param {Array} body - Objects of the shape `{id, metadata}`. `metadata` is a patch, a null value deleting that key. The tokens may lie in several documents of one project; every document touched has its version bumped. An unknown id refuses the whole update.
|
|
2553
|
+
* @param {Array} body - Objects of the shape `{id, metadata}`. `metadata` is a patch, a null value deleting that key. The tokens may lie in several documents of one project; every document touched has its version bumped and every new version comes back in `X-Document-Versions`. A `document-version` precondition is accepted only when every entry lies in one document. An unknown id refuses the whole update.
|
|
2403
2554
|
* @returns {Promise<{count: number}>} How many tokens were updated.
|
|
2404
2555
|
*/
|
|
2405
2556
|
bulkUpdate: (body, auditMessage) =>
|
|
@@ -2510,7 +2661,8 @@ class PlaidClient {
|
|
|
2510
2661
|
/**
|
|
2511
2662
|
* Discover the services seen on a project (synchronous GET). Currently
|
|
2512
2663
|
* connected services carry `online: true`; previously-seen offline ones
|
|
2513
|
-
* carry `online: false` plus a `lastSeenAt` stamp.
|
|
2664
|
+
* carry `online: false` plus a `lastSeenAt` stamp. Goes over the wire
|
|
2665
|
+
* even while a batch is open on the client.
|
|
2514
2666
|
* @param {string} projectId - The UUID of the project to query
|
|
2515
2667
|
* @returns {Promise<Array>} Array of discovered service information
|
|
2516
2668
|
*/
|
|
@@ -2680,7 +2832,10 @@ class PlaidClient {
|
|
|
2680
2832
|
* Get a logical-operation group (its label + creator).
|
|
2681
2833
|
* @param {string} id - The group id
|
|
2682
2834
|
*/
|
|
2683
|
-
get: (id) =>
|
|
2835
|
+
get: (id) =>
|
|
2836
|
+
this._request("GET", `/api/v1/operation-groups/${id}`, {
|
|
2837
|
+
bypassBatch: true,
|
|
2838
|
+
}),
|
|
2684
2839
|
/**
|
|
2685
2840
|
* Relabel a logical-operation group after the fact. Owner or admin only.
|
|
2686
2841
|
* @param {string} id - The group id
|
|
@@ -2721,7 +2876,8 @@ class PlaidClient {
|
|
|
2721
2876
|
* Read one comment.
|
|
2722
2877
|
* @param {string} id - The comment id
|
|
2723
2878
|
*/
|
|
2724
|
-
get: (id) =>
|
|
2879
|
+
get: (id) =>
|
|
2880
|
+
this._request("GET", `/api/v1/comments/${id}`, { bypassBatch: true }),
|
|
2725
2881
|
/**
|
|
2726
2882
|
* Edit a comment's body. Only the comment's AUTHOR may do this - not
|
|
2727
2883
|
* maintainers, not admins. Sets `edited` on the comment.
|
|
@@ -2739,7 +2895,6 @@ class PlaidClient {
|
|
|
2739
2895
|
/**
|
|
2740
2896
|
* List comments in a project, oldest first. Transparently follows
|
|
2741
2897
|
* pagination cursors and returns the full flat array.
|
|
2742
|
-
* Cannot be used inside a batch (auto-paginates across requests); throws if called while batching - use listPage() for a single page in a batch.
|
|
2743
2898
|
* @param {string} projectId - The project to read
|
|
2744
2899
|
* @param {object} [filters] - Narrow the scope
|
|
2745
2900
|
* @param {string} [filters.documentId] - Every comment anywhere in one document
|
|
@@ -2780,7 +2935,6 @@ class PlaidClient {
|
|
|
2780
2935
|
}),
|
|
2781
2936
|
/**
|
|
2782
2937
|
* Async-iterate a project's comments page by page; yields each page's entries array.
|
|
2783
|
-
* 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.
|
|
2784
2938
|
* @param {string} projectId - The project to read
|
|
2785
2939
|
* @param {object} [opts]
|
|
2786
2940
|
* @param {number} [opts.pageSize] - Per-request page size
|
|
@@ -2815,6 +2969,7 @@ class PlaidClient {
|
|
|
2815
2969
|
*/
|
|
2816
2970
|
counts: (projectId, { documentId, entityType, entityId } = {}) =>
|
|
2817
2971
|
this._request("GET", `/api/v1/projects/${projectId}/comments/counts`, {
|
|
2972
|
+
bypassBatch: true,
|
|
2818
2973
|
queryParams: {
|
|
2819
2974
|
"document-id": documentId,
|
|
2820
2975
|
"entity-type": entityType,
|
|
@@ -2826,7 +2981,6 @@ class PlaidClient {
|
|
|
2826
2981
|
* List the comments on a vocabulary's entries, oldest first. Requires
|
|
2827
2982
|
* read access to the vocabulary. Transparently follows pagination
|
|
2828
2983
|
* cursors and returns the full flat array.
|
|
2829
|
-
* Cannot be used inside a batch (auto-paginates across requests); throws if called while batching - use listInVocabPage() for a single page in a batch.
|
|
2830
2984
|
* @param {string} vocabId - The vocab layer to read
|
|
2831
2985
|
* @param {object} [filters]
|
|
2832
2986
|
* @param {string} [filters.entityId] - One entry's thread
|
|
@@ -2863,6 +3017,7 @@ class PlaidClient {
|
|
|
2863
3017
|
"GET",
|
|
2864
3018
|
`/api/v1/vocab-layers/${vocabId}/comments/counts`,
|
|
2865
3019
|
{
|
|
3020
|
+
bypassBatch: true,
|
|
2866
3021
|
queryParams: { "entity-id": entityId },
|
|
2867
3022
|
skipResponseTransform: true,
|
|
2868
3023
|
},
|
|
@@ -2909,6 +3064,12 @@ class PlaidClient {
|
|
|
2909
3064
|
* write, so an operation that is never ended (crash, closed tab) is still
|
|
2910
3065
|
* labeled in the log.
|
|
2911
3066
|
*
|
|
3067
|
+
* "Every write" is the writes of project data. Reads never join, and neither
|
|
3068
|
+
* do the out-of-band signals shaped like a write (a document lock taken or
|
|
3069
|
+
* renewed, a stopped service request, a service reporting itself, an admin
|
|
3070
|
+
* control): none of them is audited, so there would be nothing under the
|
|
3071
|
+
* label.
|
|
3072
|
+
*
|
|
2912
3073
|
* @param {string} message - Human label for the operation.
|
|
2913
3074
|
* @param {object} [opts] - Optional `{ id }`: adopt an existing group id instead of minting one (a service joining the requester's operation; `requestService` propagates an open operation to the service automatically).
|
|
2914
3075
|
* @returns {string} The operation's group id.
|
|
@@ -2984,12 +3145,15 @@ class PlaidClient {
|
|
|
2984
3145
|
}
|
|
2985
3146
|
}
|
|
2986
3147
|
|
|
2987
|
-
/**
|
|
3148
|
+
/**
|
|
3149
|
+
* Begin a batch of operations. Subsequent WRITES are queued; reads and
|
|
3150
|
+
* out-of-band signals still go over the wire (see `batched`).
|
|
3151
|
+
*/
|
|
2988
3152
|
beginBatch() {
|
|
2989
3153
|
this.isBatching = true;
|
|
2990
3154
|
this.batchOperations = [];
|
|
2991
|
-
// Strict mode stamps the expected document-version on the FIRST
|
|
2992
|
-
// the batch only (see _request)
|
|
3155
|
+
// Strict mode stamps the expected document-version on the FIRST QUEUED
|
|
3156
|
+
// write of the batch only (see _request), so reset the marker per batch.
|
|
2993
3157
|
this.batchVersionStamped = false;
|
|
2994
3158
|
}
|
|
2995
3159
|
|
|
@@ -3122,6 +3286,18 @@ class PlaidClient {
|
|
|
3122
3286
|
* parents created earlier in the same `fn`; any op's failure rolls the whole
|
|
3123
3287
|
* batch back). Not nestable. Named `batched()` because `client.batch` is the
|
|
3124
3288
|
* low-level batch resource.
|
|
3289
|
+
*
|
|
3290
|
+
* WRITES are what a batch queues, and batch mode is one flag on the whole
|
|
3291
|
+
* client, so it catches every write made while it is open, including writes
|
|
3292
|
+
* made by code that knows nothing about this batch. READS are never caught:
|
|
3293
|
+
* every read method goes over the wire while a batch is open and is answered
|
|
3294
|
+
* from the state the batch has not committed yet, so a read cannot come back
|
|
3295
|
+
* as a batch marker and cannot take a slot in the results array. Neither are
|
|
3296
|
+
* the calls that signal something out of band rather than write project data:
|
|
3297
|
+
* stopping a service request, a service reporting its progress or result,
|
|
3298
|
+
* taking and dropping a document lock, and the admin actions on the server
|
|
3299
|
+
* itself. See the note at the top of `http.js` for which column a new
|
|
3300
|
+
* endpoint belongs in.
|
|
3125
3301
|
* @param {() => (void | Promise<void>)} fn
|
|
3126
3302
|
* @returns {Promise<Array>}
|
|
3127
3303
|
*/
|
|
@@ -3313,6 +3489,14 @@ export {
|
|
|
3313
3489
|
// request, and `critical()` holds that off around writes. See ./services.js
|
|
3314
3490
|
// and the manual, "Stopping a request".
|
|
3315
3491
|
export { ServiceCancelled, createCancelScope } from "./services.js";
|
|
3492
|
+
// Document locks: `client.documents.locked()` holds one for a block of work and
|
|
3493
|
+
// renews it while the block runs. DocumentLockLost is what a write throws once
|
|
3494
|
+
// a renewal has failed. See ./documentLock.js.
|
|
3495
|
+
export {
|
|
3496
|
+
DOCUMENT_LOCK_TTL_MS,
|
|
3497
|
+
DocumentLock,
|
|
3498
|
+
DocumentLockLost,
|
|
3499
|
+
} from "./documentLock.js";
|
|
3316
3500
|
// Provenance: the cross-app convention for who made an annotation (flat
|
|
3317
3501
|
// prov/provSource/provConfirmed metadata; absence = a verifier; 'inferred' =
|
|
3318
3502
|
// a machine; 'contributed' = a person whose work is reviewed), plus the
|