@larc-iu/plaid-client 0.2.0-alpha.22 → 0.2.0-alpha.26
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/README.md +39 -0
- package/package.json +11 -5
- package/src/batchRef.d.ts +30 -0
- package/src/codepoint.d.ts +94 -0
- package/src/codepoint.js +131 -1
- package/src/constraints.d.ts +77 -0
- package/src/constraints.js +26 -1
- package/src/created.d.ts +2 -0
- package/src/documentLock.d.ts +158 -0
- package/src/documentLock.js +29 -4
- package/src/events.d.ts +60 -0
- package/src/events.js +7 -3
- package/src/http.d.ts +212 -0
- package/src/http.js +7 -0
- package/src/ids.d.ts +26 -0
- package/src/ids.js +42 -0
- package/src/index.d.ts +3814 -0
- package/src/index.js +962 -704
- package/src/metadataOps.d.ts +15 -0
- package/src/metadataOps.js +13 -8
- package/src/pagination.d.ts +49 -0
- package/src/pagination.js +2 -19
- package/src/provenance.d.ts +200 -0
- package/src/provenance.js +34 -6
- package/src/replayed.d.ts +3 -0
- package/src/replayed.js +5 -1
- package/src/requester.d.ts +60 -0
- package/src/requester.js +21 -3
- package/src/roles.d.ts +65 -0
- package/src/roles.js +3 -2
- package/src/serviceSchema.d.ts +331 -0
- package/src/serviceSchema.js +75 -9
- package/src/services.d.ts +302 -0
- package/src/services.js +67 -10
- package/src/sse.d.ts +30 -0
- package/src/sse.js +11 -0
- package/src/textEdits.d.ts +59 -0
- package/src/textEdits.js +26 -1
- package/src/transforms.d.ts +25 -0
- package/index.d.ts +0 -2015
package/src/index.js
CHANGED
|
@@ -22,7 +22,7 @@ import {
|
|
|
22
22
|
DEFAULT_BATCH_TIMEOUT_MS,
|
|
23
23
|
queryTimeout,
|
|
24
24
|
} from "./http.js";
|
|
25
|
-
import { uuidv7 } from "./ids.js";
|
|
25
|
+
import { uuidv4, uuidv7, normalizeUserId } from "./ids.js";
|
|
26
26
|
import { constraintsBody } from "./constraints.js";
|
|
27
27
|
import { listAll, listPage, iterPages } from "./pagination.js";
|
|
28
28
|
import { recorderFor } from "./events.js";
|
|
@@ -39,6 +39,294 @@ import {
|
|
|
39
39
|
cancelServiceRequest,
|
|
40
40
|
} from "./services.js";
|
|
41
41
|
|
|
42
|
+
// ---- Types --------------------------------------------------------------
|
|
43
|
+
// The shapes the API answers with and takes, for editors and for the
|
|
44
|
+
// declarations `npm run types` generates from this JSDoc (index.d.ts).
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* @typedef {import("./textEdits.js").TextEditOp} TextEditOp
|
|
48
|
+
* @typedef {import("./textEdits.js").TextGap} TextGap
|
|
49
|
+
* @typedef {import("./metadataOps.js").MetadataOp} MetadataOp
|
|
50
|
+
* @typedef {import("./constraints.js").LayerConstraint} LayerConstraint
|
|
51
|
+
* @typedef {import("./constraints.js").ConstraintWriteOptions} ConstraintWriteOptions
|
|
52
|
+
* @typedef {import("./constraints.js").ConstraintViolation} ConstraintViolation
|
|
53
|
+
* @typedef {import("./requester.js").Requester} Requester
|
|
54
|
+
* @typedef {import("./batchRef.js").BatchRef} BatchRef
|
|
55
|
+
* @typedef {import("./serviceSchema.js").ServiceParam} ServiceParam
|
|
56
|
+
* @typedef {import("./serviceSchema.js").ServiceInfo} ServiceInfo
|
|
57
|
+
* @typedef {import("./serviceSchema.js").DiscoveredService} DiscoveredService
|
|
58
|
+
* @typedef {import("./services.js").ResponseHelper} ResponseHelper
|
|
59
|
+
* @typedef {import("./services.js").ServiceRegistration} ServiceRegistration
|
|
60
|
+
* @typedef {import("./services.js").ServiceStatusEvent} ServiceStatusEvent
|
|
61
|
+
* @typedef {PlaidClient["operationGroups"]} OperationGroupsBundle
|
|
62
|
+
*/
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* A single page of a cursor-paginated collection.
|
|
66
|
+
* @template [T=any]
|
|
67
|
+
* @typedef {{entries: T[], nextCursor: string | null}} Page
|
|
68
|
+
*/
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Client options.
|
|
72
|
+
* @typedef {object} PlaidClientOptions
|
|
73
|
+
* @property {number | null} [timeout] Per-request timeout in ms (default
|
|
74
|
+
* 30000, 0 or null disables it).
|
|
75
|
+
* @property {number | null} [batchTimeout] Timeout for batch submissions in
|
|
76
|
+
* ms (default 180000, 0 or null disables it). Aborting a batch does NOT
|
|
77
|
+
* stop the server, which keeps running the transaction and holding the
|
|
78
|
+
* write lock. Defaults to `timeout` when that is given and this is not.
|
|
79
|
+
* @property {number[]} [retryDelaysMs] Delays in ms before sending a keyed
|
|
80
|
+
* write again when its answer was lost (no response, 502 or 504). Default
|
|
81
|
+
* [1000, 3000, 9000].
|
|
82
|
+
* @property {((error: Error) => void) | null} [onAuthError] Fired once when
|
|
83
|
+
* a request returns HTTP 401 (missing, expired or invalid token). 403 does
|
|
84
|
+
* NOT trigger it.
|
|
85
|
+
*/
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* What kind of operation a logical-operation group is (`?group-kind=`).
|
|
89
|
+
* @typedef {"assistant-plan" | "service-run" | "import" | "bulk-edit"
|
|
90
|
+
* | "guess-adoption" | "repair" | "review"} OperationKind
|
|
91
|
+
*/
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Idempotency-Key seed for an operation run more than once (`client.keySeed()`).
|
|
95
|
+
* @typedef {{seed: string, stamps: Map<number, number | null>}} KeySeed
|
|
96
|
+
*/
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* A batch: the client's bundles, on which every write of project data queues
|
|
100
|
+
* until `submit()`. See `PlaidClient.batch()`. `submit()` resolves to one
|
|
101
|
+
* result per operation, in order. `ref(opIndex, index)` stands for the id a
|
|
102
|
+
* queued operation will create, in the body of a later write on this batch.
|
|
103
|
+
* @typedef {PlaidClient & {
|
|
104
|
+
* readonly client: PlaidClient,
|
|
105
|
+
* readonly operations: Array<{path: string, method: string, body?: any}>,
|
|
106
|
+
* submit(): Promise<any[]>,
|
|
107
|
+
* abort(): void,
|
|
108
|
+
* ref(opIndex?: number, index?: number): BatchRef,
|
|
109
|
+
* }} PlaidBatch
|
|
110
|
+
*/
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Options for a single page of any audit log. `kinds` keeps only the entries
|
|
114
|
+
* of operations of these kinds, each whole. `order: "desc"` pages newest
|
|
115
|
+
* first, and a cursor belongs to the direction that made it. `opsLimit` keeps
|
|
116
|
+
* only each entry's oldest N operations in `ops` (1..1000), and every entry
|
|
117
|
+
* has `opCount`. `entryId` reads only that entry rather than a page.
|
|
118
|
+
* @typedef {object} AuditPageOptions
|
|
119
|
+
* @property {string} [startTime]
|
|
120
|
+
* @property {string} [endTime]
|
|
121
|
+
* @property {string[] | string} [opTypes]
|
|
122
|
+
* @property {OperationKind[] | string} [kinds]
|
|
123
|
+
* @property {"asc" | "desc"} [order]
|
|
124
|
+
* @property {number} [limit]
|
|
125
|
+
* @property {string} [cursor]
|
|
126
|
+
* @property {number} [opsLimit]
|
|
127
|
+
* @property {string} [entryId]
|
|
128
|
+
*/
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* What `vocabLayers.restoreItem` did, or with `dryRun` would do.
|
|
132
|
+
* @typedef {object} VocabItemRestoreSummary
|
|
133
|
+
* @property {boolean} inserted The entry was gone and came back under its old id.
|
|
134
|
+
* @property {boolean} form A living entry's form was set back.
|
|
135
|
+
* @property {boolean} metadata A living entry's fields were set back.
|
|
136
|
+
* @property {number} total 0 when nothing changes.
|
|
137
|
+
*/
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* One private data entry. `version` is raised by one on every write of the
|
|
141
|
+
* entry, and a new entry is 1.
|
|
142
|
+
* @typedef {{key: string, updatedAt: string, version: number, value?: any}} UserDataEntry
|
|
143
|
+
*/
|
|
144
|
+
|
|
145
|
+
/** @typedef {UserDataEntry & {userId: string}} AdminUserDataEntry */
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* One user's activity over a scope and window (`audit.tally`).
|
|
149
|
+
* @typedef {object} ActivityTallyRow
|
|
150
|
+
* @property {{id: string, displayName?: string}} user
|
|
151
|
+
* @property {number} operations
|
|
152
|
+
* @property {number} changes
|
|
153
|
+
* @property {number} documents
|
|
154
|
+
* @property {string} firstTs
|
|
155
|
+
* @property {string} lastTs
|
|
156
|
+
* @property {Array<{date: string, changes: number}>} [byDay]
|
|
157
|
+
*/
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* What a constraint repair did in one document.
|
|
161
|
+
* @typedef {{document: string, constraint: string, deleted: number, joined: number}} ConstraintRepair
|
|
162
|
+
*/
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Entities that can carry a comment.
|
|
166
|
+
* @typedef {"document" | "text" | "token" | "span" | "relation" | "vocab-item"} CommentableType
|
|
167
|
+
*/
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* One comment. `projectId` and `documentId` are null for a comment on a
|
|
171
|
+
* vocabulary entry, and `vocabLayerId` is set only for one. `anchorLabel` is
|
|
172
|
+
* what the comment is about, in words, captured when it was posted: a
|
|
173
|
+
* comment outlives its anchor. `edited` is true once the body has been
|
|
174
|
+
* rewritten since it was posted.
|
|
175
|
+
* @typedef {object} Comment
|
|
176
|
+
* @property {string} id
|
|
177
|
+
* @property {string | null} projectId
|
|
178
|
+
* @property {string | null} documentId
|
|
179
|
+
* @property {string | null} vocabLayerId
|
|
180
|
+
* @property {CommentableType} entityType
|
|
181
|
+
* @property {string} entityId
|
|
182
|
+
* @property {string | null} anchorLabel
|
|
183
|
+
* @property {string} authorId
|
|
184
|
+
* @property {string} body
|
|
185
|
+
* @property {string} createdAt
|
|
186
|
+
* @property {string} updatedAt
|
|
187
|
+
* @property {boolean} edited
|
|
188
|
+
*/
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* One entry in a project's annotation manual. `body` is present on a single
|
|
192
|
+
* read and on a list made with `includeBodies`, `bodyChars` on a list made
|
|
193
|
+
* without. `pinned`: the assistant is given this one in full on every turn.
|
|
194
|
+
* @typedef {object} Guideline
|
|
195
|
+
* @property {string} id
|
|
196
|
+
* @property {string} projectId
|
|
197
|
+
* @property {string} title
|
|
198
|
+
* @property {string} [body]
|
|
199
|
+
* @property {number} [bodyChars]
|
|
200
|
+
* @property {boolean} pinned
|
|
201
|
+
* @property {string} createdAt
|
|
202
|
+
* @property {string} updatedAt
|
|
203
|
+
*/
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* A research-telemetry event type.
|
|
207
|
+
* @typedef {"suggestion.shown" | "suggestion.adopted" | "suggestion.dismissed" | "plan.opened"} ClientEventType
|
|
208
|
+
*/
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* One research-telemetry event as the server stores it.
|
|
212
|
+
* @typedef {object} ClientEvent
|
|
213
|
+
* @property {number} id
|
|
214
|
+
* @property {string} projectId
|
|
215
|
+
* @property {string | null} documentId
|
|
216
|
+
* @property {string} userId
|
|
217
|
+
* @property {ClientEventType} type
|
|
218
|
+
* @property {string | null} targetId
|
|
219
|
+
* @property {Record<string, any> | null} data
|
|
220
|
+
* @property {string | null} clientTs
|
|
221
|
+
* @property {string} ts
|
|
222
|
+
*/
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* An invite. `kind` is "signup" or "password-reset", `status` "active",
|
|
226
|
+
* "used", "expired", "revoked" or "inactive".
|
|
227
|
+
* @typedef {object} Invite
|
|
228
|
+
* @property {string} id
|
|
229
|
+
* @property {string} kind
|
|
230
|
+
* @property {string} status
|
|
231
|
+
* @property {string} createdBy
|
|
232
|
+
* @property {string} createdAt
|
|
233
|
+
* @property {string} expiresAt
|
|
234
|
+
* @property {number} maxUses
|
|
235
|
+
* @property {number} uses
|
|
236
|
+
* @property {string | null} revokedAt
|
|
237
|
+
* @property {string | null} note
|
|
238
|
+
* @property {string | null} targetUserId
|
|
239
|
+
* @property {boolean} grantAdmin
|
|
240
|
+
* @property {string | null} projectId
|
|
241
|
+
* @property {string | null} projectRole
|
|
242
|
+
*/
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* Server limits, as reported by /api/v1/info. An unset limit is absent.
|
|
246
|
+
* `passwordMinLength` is the shortest password the server accepts on any
|
|
247
|
+
* path, `lockExpirationMs` how long a document lock is held before it lapses.
|
|
248
|
+
* @typedef {object} ServerLimits
|
|
249
|
+
* @property {number} [mediaFileBytes]
|
|
250
|
+
* @property {number} [jsonBodyBytes]
|
|
251
|
+
* @property {number} [batchOperations]
|
|
252
|
+
* @property {number} [metadataDepth]
|
|
253
|
+
* @property {number} [metadataKeyCount]
|
|
254
|
+
* @property {number} [metadataStringLength]
|
|
255
|
+
* @property {number} [metadataTotalBytes]
|
|
256
|
+
* @property {number} [userDataValueBytes]
|
|
257
|
+
* @property {number} [guidelineTitleLength]
|
|
258
|
+
* @property {number} [guidelineBodyLength]
|
|
259
|
+
* @property {number} [passwordMinLength]
|
|
260
|
+
* @property {number} [lockExpirationMs]
|
|
261
|
+
*/
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* @typedef {object} ServerHealth
|
|
265
|
+
* @property {boolean} ok
|
|
266
|
+
* @property {string} version
|
|
267
|
+
* @property {number} uptimeMs
|
|
268
|
+
* @property {{dbSizeMb?: number, auditRows?: number, error?: string}} audit
|
|
269
|
+
*/
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* @typedef {{ip: string, userId?: string, failures: number, limit: number, blocked: boolean}} RateLimitBucket
|
|
273
|
+
*/
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* @typedef {object} RateLimitSnapshot
|
|
277
|
+
* @property {number} windowMs
|
|
278
|
+
* @property {RateLimitBucket[]} logins
|
|
279
|
+
* @property {RateLimitBucket[]} ips
|
|
280
|
+
* @property {RateLimitBucket[]} invites
|
|
281
|
+
*/
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* @typedef {object} BackupStatus
|
|
285
|
+
* @property {boolean} enabled
|
|
286
|
+
* @property {string} directory
|
|
287
|
+
* @property {number} retention
|
|
288
|
+
* @property {string} time
|
|
289
|
+
* @property {Array<{name: string, bytes: number, modified: string}>} backups
|
|
290
|
+
* @property {boolean} [ok]
|
|
291
|
+
*/
|
|
292
|
+
|
|
293
|
+
/**
|
|
294
|
+
* @typedef {object} ServerReport
|
|
295
|
+
* @property {string} version
|
|
296
|
+
* @property {{uptimeMs: number, startedAt: string, java: string, heapUsed: number, heapMax: number}} jvm
|
|
297
|
+
* @property {{path: string | null, bytes: number | null, walBytes: number | null,
|
|
298
|
+
* slowQueryThresholdMs?: number, journalMode?: string, maxPoolSize?: number,
|
|
299
|
+
* tables: Record<string, number | null>}} database
|
|
300
|
+
* @property {{directory: string, files: number, bytes: number, orphans: number, orphanBytes: number}} media
|
|
301
|
+
* @property {BackupStatus} backup
|
|
302
|
+
* @property {Record<string, any>} settings
|
|
303
|
+
*/
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* The live log. Requests and events are buffered separately, so a burst of
|
|
307
|
+
* requests cannot evict an error. In each, `matched` is how many passed the
|
|
308
|
+
* filters (which may exceed what `entries` holds) and `held` how many are
|
|
309
|
+
* buffered in total. `file` is the configured log file's absolute path, or
|
|
310
|
+
* null when logging to stdout.
|
|
311
|
+
* @typedef {object} LiveLog
|
|
312
|
+
* @property {{entries: object[], matched: number, held: number, capacity: number,
|
|
313
|
+
* stats: Record<string, number | null>}} requests
|
|
314
|
+
* @property {{entries: object[], matched: number, held: number, capacity: number,
|
|
315
|
+
* byLevel: Record<string, number>}} events
|
|
316
|
+
* @property {string | null} file
|
|
317
|
+
*/
|
|
318
|
+
|
|
319
|
+
/**
|
|
320
|
+
* An open server-sent-events stream. Once CLOSED, `error` says why: null when
|
|
321
|
+
* this side closed it. A refused stream's error carries the HTTP `status`,
|
|
322
|
+
* and one the server ended is named "StreamClosed".
|
|
323
|
+
* @typedef {object} SSEConnection
|
|
324
|
+
* @property {() => void} close
|
|
325
|
+
* @property {() => any} getStats
|
|
326
|
+
* @property {number} readyState
|
|
327
|
+
* @property {(Error & {status?: number}) | null} error
|
|
328
|
+
*/
|
|
329
|
+
|
|
42
330
|
// Helper: normalize a document-read `layers` filter to the wire's
|
|
43
331
|
// comma-separated form. Accepts an array of layer ids or a ready-made string;
|
|
44
332
|
// anything empty becomes undefined so no `?layers=` is sent at all.
|
|
@@ -70,18 +358,22 @@ function bodyOf(obj) {
|
|
|
70
358
|
return result;
|
|
71
359
|
}
|
|
72
360
|
|
|
73
|
-
//
|
|
74
|
-
// and
|
|
75
|
-
// are called before any client exists,
|
|
76
|
-
|
|
361
|
+
// A request with no Authorization header: login, invite lookup and redemption
|
|
362
|
+
// (POST, with a body), /health and /api/v1/info (GET). Deliberately does not
|
|
363
|
+
// go through PlaidClient._request: these are called before any client exists,
|
|
364
|
+
// which is the whole point.
|
|
365
|
+
async function anonymousRequest(method, baseUrl, path, body, options = {}) {
|
|
77
366
|
const base = baseUrl.replace(/\/$/, "");
|
|
78
367
|
const url = `${base}${path}`;
|
|
79
368
|
try {
|
|
80
|
-
const fetchOptions =
|
|
81
|
-
method
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
369
|
+
const fetchOptions =
|
|
370
|
+
method === "GET"
|
|
371
|
+
? { method }
|
|
372
|
+
: {
|
|
373
|
+
method,
|
|
374
|
+
headers: { "Content-Type": "application/json" },
|
|
375
|
+
body: JSON.stringify(body),
|
|
376
|
+
};
|
|
85
377
|
const signal = timeoutSignal(
|
|
86
378
|
options.timeout !== undefined ? options.timeout : DEFAULT_TIMEOUT_MS,
|
|
87
379
|
);
|
|
@@ -89,42 +381,12 @@ async function anonymousPost(baseUrl, path, body, options = {}) {
|
|
|
89
381
|
|
|
90
382
|
const response = await fetch(url, fetchOptions);
|
|
91
383
|
if (!response.ok) {
|
|
92
|
-
throw makeHttpError(
|
|
93
|
-
response,
|
|
94
|
-
await parseErrorBody(response),
|
|
95
|
-
url,
|
|
96
|
-
"POST",
|
|
97
|
-
);
|
|
384
|
+
throw makeHttpError(response, await parseErrorBody(response), url, method);
|
|
98
385
|
}
|
|
99
386
|
return transformResponse(await response.json());
|
|
100
387
|
} catch (error) {
|
|
101
388
|
if (error.status) throw error;
|
|
102
|
-
throw makeNetworkError(error, url,
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
/**
|
|
107
|
-
* GET a path with no authentication, for the two endpoints a client may need
|
|
108
|
-
* before it has a session: /health and /api/v1/info.
|
|
109
|
-
*/
|
|
110
|
-
async function anonymousGet(baseUrl, path, options = {}) {
|
|
111
|
-
const base = baseUrl.replace(/\/$/, "");
|
|
112
|
-
const url = `${base}${path}`;
|
|
113
|
-
try {
|
|
114
|
-
const fetchOptions = { method: "GET" };
|
|
115
|
-
const signal = timeoutSignal(
|
|
116
|
-
options.timeout !== undefined ? options.timeout : DEFAULT_TIMEOUT_MS,
|
|
117
|
-
);
|
|
118
|
-
if (signal) fetchOptions.signal = signal;
|
|
119
|
-
|
|
120
|
-
const response = await fetch(url, fetchOptions);
|
|
121
|
-
if (!response.ok) {
|
|
122
|
-
throw makeHttpError(response, await parseErrorBody(response), url, "GET");
|
|
123
|
-
}
|
|
124
|
-
return transformResponse(await response.json());
|
|
125
|
-
} catch (error) {
|
|
126
|
-
if (error.status) throw error;
|
|
127
|
-
throw makeNetworkError(error, url, "GET");
|
|
389
|
+
throw makeNetworkError(error, url, method);
|
|
128
390
|
}
|
|
129
391
|
}
|
|
130
392
|
|
|
@@ -155,6 +417,12 @@ const OPERATION_KINDS = [
|
|
|
155
417
|
*/
|
|
156
418
|
export const BACKUP_TIMEOUT_MS = 30 * 60 * 1000;
|
|
157
419
|
|
|
420
|
+
/** An avatar token is minted again once less than this is left of it. */
|
|
421
|
+
const AVATAR_TOKEN_RENEW_MS = 10 * 60 * 1000;
|
|
422
|
+
// An avatar token minted this recently is the renewal a caller asking for one
|
|
423
|
+
// wanted.
|
|
424
|
+
const AVATAR_TOKEN_FRESH_MS = 5 * 1000;
|
|
425
|
+
|
|
158
426
|
/**
|
|
159
427
|
* A batch is the client with a different `_request` (see `queueRequest`) and
|
|
160
428
|
* its own copy of the bundles. Everything else resolves to the client through
|
|
@@ -316,13 +584,12 @@ class PlaidClient {
|
|
|
316
584
|
* Create a new PlaidClient instance
|
|
317
585
|
* @param {string} baseUrl - The base URL for the API
|
|
318
586
|
* @param {string} token - The authentication token
|
|
319
|
-
* @param {
|
|
320
|
-
* @param {number} [options.timeout=30000] - Per-request timeout in ms (0 or null disables it)
|
|
321
|
-
* @param {number} [options.batchTimeout=180000] - Timeout for batch submissions in ms (0 or null disables it)
|
|
587
|
+
* @param {PlaidClientOptions} [options] - Client options
|
|
322
588
|
*/
|
|
323
589
|
constructor(baseUrl, token, options = {}) {
|
|
324
590
|
this.baseUrl = baseUrl.replace(/\/$/, "");
|
|
325
591
|
this.token = token;
|
|
592
|
+
/** @type {number | null} */
|
|
326
593
|
this.timeout =
|
|
327
594
|
options.timeout !== undefined ? options.timeout : DEFAULT_TIMEOUT_MS;
|
|
328
595
|
// Batch submissions get a longer budget than a single request. Aborting a
|
|
@@ -330,6 +597,7 @@ class PlaidClient {
|
|
|
330
597
|
// holding the single SQLite write lock, so a client that gives up early
|
|
331
598
|
// just adds a retry on top of a write that is still in progress. Falls
|
|
332
599
|
// back to an explicit `timeout` when one was given.
|
|
600
|
+
/** @type {number | null} */
|
|
333
601
|
this.batchTimeout =
|
|
334
602
|
options.batchTimeout !== undefined
|
|
335
603
|
? options.batchTimeout
|
|
@@ -338,33 +606,90 @@ class PlaidClient {
|
|
|
338
606
|
: DEFAULT_BATCH_TIMEOUT_MS;
|
|
339
607
|
// Delays (ms) before sending a keyed write again when its answer was lost
|
|
340
608
|
// (no response, 502, 504). See the Idempotency-Key note in http.js.
|
|
609
|
+
/** @type {number[] | undefined} */
|
|
341
610
|
this.retryDelaysMs = options.retryDelaysMs;
|
|
611
|
+
/**
|
|
612
|
+
* The latest version seen for each document written through this client,
|
|
613
|
+
* keyed by document id.
|
|
614
|
+
* @type {Record<string, number>}
|
|
615
|
+
*/
|
|
342
616
|
this.documentVersions = {};
|
|
617
|
+
/**
|
|
618
|
+
* True once a response left its version list out
|
|
619
|
+
* (X-Document-Versions-Omitted, past fifty documents). Every version held
|
|
620
|
+
* was then forgotten, and the strict-mode document's is read again before
|
|
621
|
+
* the next write.
|
|
622
|
+
* @type {boolean | undefined}
|
|
623
|
+
*/
|
|
624
|
+
this.documentVersionsOmitted = undefined;
|
|
343
625
|
// The server's clock minus this machine's, in ms, from the last response
|
|
344
626
|
// with a Date header (null before one). See serverNow().
|
|
627
|
+
/** @type {number | null} */
|
|
345
628
|
this.serverClockOffsetMs = null;
|
|
629
|
+
/**
|
|
630
|
+
* The document strict mode is entered for, or null.
|
|
631
|
+
* @type {string | null}
|
|
632
|
+
*/
|
|
346
633
|
this.strictModeDocumentId = null;
|
|
347
634
|
// Set to a DocumentLockLost while a `documents.locked()` block's keep-alive
|
|
348
635
|
// has failed. Every write throws it until the block exits; see
|
|
349
636
|
// documentLock.js.
|
|
637
|
+
/** @type {import("./documentLock.js").DocumentLockLost | null} */
|
|
350
638
|
this.documentLockLost = null;
|
|
351
639
|
// The open logical operation (audit-log group), or null. While set, every
|
|
352
640
|
// write is stamped with `?group-id=` (+ `group-message`) so the audit log
|
|
353
641
|
// folds them into ONE expandable entry. See beginOperation / withOperation.
|
|
354
642
|
// Shape: { id, message, depth, written, refined, frames }, where each of
|
|
355
643
|
// `frames` is { keys, count, minted, depth, owned } and the last numbers.
|
|
644
|
+
/**
|
|
645
|
+
* @type {{id: string, message: string | null, kind: OperationKind | null,
|
|
646
|
+
* ref: string | null, depth: number, written: boolean, refined: any,
|
|
647
|
+
* frames: object[]} | null}
|
|
648
|
+
*/
|
|
356
649
|
this.operationGroup = null;
|
|
357
650
|
// Optional callback fired once (per client) when any request returns HTTP
|
|
358
651
|
// 401 — i.e. the token is missing/expired/invalid. Apps use it to discard
|
|
359
652
|
// the stored token and route back to login. See makeRequest in http.js.
|
|
653
|
+
/** @type {((error: Error) => void) | null} */
|
|
360
654
|
this.onAuthError = options.onAuthError || null;
|
|
655
|
+
/** @private */
|
|
361
656
|
this._authErrorFired = false;
|
|
362
657
|
// Who hears that a request is being sent again (onRetry).
|
|
658
|
+
/** @private */
|
|
363
659
|
this._retryListeners = new Set();
|
|
660
|
+
// GET /info as last read (`server.info()`), and whether a stream of this
|
|
661
|
+
// client dropped since.
|
|
662
|
+
/** @private */
|
|
663
|
+
this._serverFacts = { info: null, stale: false };
|
|
664
|
+
// The key frame the last beginOperation opened, or null (withOperation).
|
|
665
|
+
/** @private @type {object | null} */
|
|
666
|
+
this._openedFrame = null;
|
|
364
667
|
|
|
365
668
|
this._installResources();
|
|
366
669
|
}
|
|
367
670
|
|
|
671
|
+
/**
|
|
672
|
+
* A stream of this client ended without being closed here: the server may
|
|
673
|
+
* have restarted, with other limits.
|
|
674
|
+
* @private
|
|
675
|
+
*/
|
|
676
|
+
_noteStreamDropped() {
|
|
677
|
+
this._serverFacts.stale = true;
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
/**
|
|
681
|
+
* A stream of this client is open. After a drop the limits are read again,
|
|
682
|
+
* once however many streams reopen.
|
|
683
|
+
* @private
|
|
684
|
+
*/
|
|
685
|
+
_noteStreamOpened() {
|
|
686
|
+
if (!this._serverFacts.stale) return;
|
|
687
|
+
this.server.refresh().catch(() => {
|
|
688
|
+
// The figures known before stand, and the next open asks again.
|
|
689
|
+
this._serverFacts.stale = true;
|
|
690
|
+
});
|
|
691
|
+
}
|
|
692
|
+
|
|
368
693
|
/**
|
|
369
694
|
* Hear every time a request is sent again: after a 503 (the database was
|
|
370
695
|
* busy), or for a keyed write after its answer was lost (no response, 502,
|
|
@@ -379,7 +704,10 @@ class PlaidClient {
|
|
|
379
704
|
return () => this._retryListeners.delete(listener);
|
|
380
705
|
}
|
|
381
706
|
|
|
382
|
-
/**
|
|
707
|
+
/**
|
|
708
|
+
* Tell every `onRetry` listener. A listener that throws is passed over.
|
|
709
|
+
* @private
|
|
710
|
+
*/
|
|
383
711
|
_noteRetry(info) {
|
|
384
712
|
for (const listener of this._retryListeners) {
|
|
385
713
|
try {
|
|
@@ -406,6 +734,7 @@ class PlaidClient {
|
|
|
406
734
|
* the client, and again on every batch it opens (see `batch()`): a batch is
|
|
407
735
|
* a view of the client with its own `_request`, so the same bundles built
|
|
408
736
|
* on it queue instead of sending.
|
|
737
|
+
* @private
|
|
409
738
|
*/
|
|
410
739
|
_installResources() {
|
|
411
740
|
this.vocabLinks = {
|
|
@@ -414,6 +743,9 @@ class PlaidClient {
|
|
|
414
743
|
* @param {string} vocabItem - The vocab item to link
|
|
415
744
|
* @param {Array} tokens - The tokens to link
|
|
416
745
|
* @param {any} [metadata] - Metadata for the link. Omit to leave unset; pass null to send JSON null.
|
|
746
|
+
* @param {string} [auditMessage] - Audit message for this write
|
|
747
|
+
* @param {object} [opts]
|
|
748
|
+
* @param {string} [opts.id] - The new entity's id, minted by the caller (see uuidv7)
|
|
417
749
|
*/
|
|
418
750
|
create: (vocabItem, tokens, metadata, auditMessage, { id } = {}) =>
|
|
419
751
|
this._request("POST", "/api/v1/vocab-links", {
|
|
@@ -425,6 +757,7 @@ class PlaidClient {
|
|
|
425
757
|
* reference different vocab items, but all tokens across the call must
|
|
426
758
|
* belong to one document.
|
|
427
759
|
* @param {Array<{vocabItem: string, tokens: string[], metadata?: any}>} body - The vocab links to create
|
|
760
|
+
* @param {string} [auditMessage] - Audit message for this write
|
|
428
761
|
* @returns {Promise<{ids: string[]}>} The created entity IDs, in input order. (bulkDelete resolves to no value.)
|
|
429
762
|
*/
|
|
430
763
|
bulkCreate: (body, auditMessage) =>
|
|
@@ -435,40 +768,15 @@ class PlaidClient {
|
|
|
435
768
|
/**
|
|
436
769
|
* Delete multiple vocab links in a single operation. Provide an array of IDs.
|
|
437
770
|
* @param {string[]} body - The vocab link IDs to delete
|
|
771
|
+
* @param {string} [auditMessage] - Audit message for this write
|
|
772
|
+
* @returns {Promise<void>}
|
|
438
773
|
*/
|
|
439
774
|
bulkDelete: (body, auditMessage) =>
|
|
440
775
|
this._request("DELETE", "/api/v1/vocab-links/bulk", {
|
|
441
776
|
auditMessage,
|
|
442
777
|
body,
|
|
443
778
|
}),
|
|
444
|
-
|
|
445
|
-
* Replace all metadata for a vocab link. The entire metadata map is replaced - existing metadata keys not included in the request will be removed.
|
|
446
|
-
* @param {string} id - The resource ID
|
|
447
|
-
* @param {any} body - The request body
|
|
448
|
-
*/
|
|
449
|
-
setMetadata: (id, body, auditMessage) =>
|
|
450
|
-
this._request("PUT", `/api/v1/vocab-links/${id}/metadata`, {
|
|
451
|
-
auditMessage,
|
|
452
|
-
rawBody: body,
|
|
453
|
-
}),
|
|
454
|
-
/**
|
|
455
|
-
* Remove all metadata from a vocab link.
|
|
456
|
-
* @param {string} id - The resource ID
|
|
457
|
-
*/
|
|
458
|
-
deleteMetadata: (id, auditMessage) =>
|
|
459
|
-
this._request("DELETE", `/api/v1/vocab-links/${id}/metadata`, {
|
|
460
|
-
auditMessage,
|
|
461
|
-
}),
|
|
462
|
-
/**
|
|
463
|
-
* Edit metadata for a vocab link with a list of ops applied in order, in one operation. `{op: 'set', path, value}` writes value at path, creating missing objects along it; `{op: 'delete', path}` removes the key at path (a no-op when absent). A path is a non-empty array of keys, the first a top-level key. A path through a non-object is refused (400). See metadataOps and applyMetadataOps.
|
|
464
|
-
* @param {string} id - The resource ID
|
|
465
|
-
* @param {Array<{op: string, path: string[], value?: any}>} body - The metadata ops
|
|
466
|
-
*/
|
|
467
|
-
patchMetadata: (id, body, auditMessage) =>
|
|
468
|
-
this._request("PATCH", `/api/v1/vocab-links/${id}/metadata`, {
|
|
469
|
-
auditMessage,
|
|
470
|
-
rawBody: body,
|
|
471
|
-
}),
|
|
779
|
+
...metadataMethods(this, "vocab-links"),
|
|
472
780
|
/**
|
|
473
781
|
* Get a vocab link by ID
|
|
474
782
|
* @param {string} id - The resource ID
|
|
@@ -478,6 +786,7 @@ class PlaidClient {
|
|
|
478
786
|
/**
|
|
479
787
|
* Delete a vocab link
|
|
480
788
|
* @param {string} id - The resource ID
|
|
789
|
+
* @param {string} [auditMessage] - Audit message for this write
|
|
481
790
|
*/
|
|
482
791
|
delete: (id, auditMessage) =>
|
|
483
792
|
this._request("DELETE", `/api/v1/vocab-links/${id}`, { auditMessage }),
|
|
@@ -541,6 +850,10 @@ class PlaidClient {
|
|
|
541
850
|
* that may be long: audit() walks every page before it resolves.
|
|
542
851
|
* @param {string} id - The vocabulary ID
|
|
543
852
|
* @param {object} [opts]
|
|
853
|
+
* @param {string} [opts.startTime] - Only entries at or after this instant
|
|
854
|
+
* @param {string} [opts.endTime] - Only entries at or before this instant
|
|
855
|
+
* @param {string[]|string} [opts.opTypes] - Only these op types
|
|
856
|
+
* @param {OperationKind[]|string} [opts.kinds] - Only the entries of operations of these kinds, each whole
|
|
544
857
|
* @param {"asc"|"desc"} [opts.order] - "desc" pages newest-first
|
|
545
858
|
* @param {number} [opts.limit] - Page size (1..1000; server default 100)
|
|
546
859
|
* @param {string} [opts.cursor] - Opaque cursor from a previous page
|
|
@@ -586,9 +899,10 @@ class PlaidClient {
|
|
|
586
899
|
* @param {string} itemId - The entry ID
|
|
587
900
|
* @param {string} asOf - The moment to go back to (ISO-8601 instant),
|
|
588
901
|
* typically a history entry's `endTime`
|
|
589
|
-
* @param {
|
|
902
|
+
* @param {{dryRun?: boolean}} [options] - `{ dryRun }`: with `dryRun` true nothing
|
|
590
903
|
* is written and the summary says what would change
|
|
591
904
|
* @param {string} [auditMessage] - Custom audit message for this operation
|
|
905
|
+
* @returns {Promise<VocabItemRestoreSummary>}
|
|
592
906
|
*/
|
|
593
907
|
restoreItem: (id, itemId, asOf, { dryRun } = {}, auditMessage) =>
|
|
594
908
|
this._request(
|
|
@@ -605,6 +919,7 @@ class PlaidClient {
|
|
|
605
919
|
/**
|
|
606
920
|
* Delete a vocab layer.
|
|
607
921
|
* @param {string} id - The resource ID
|
|
922
|
+
* @param {string} [auditMessage] - Audit message for this write
|
|
608
923
|
*/
|
|
609
924
|
delete: (id, auditMessage) =>
|
|
610
925
|
this._request("DELETE", `/api/v1/vocab-layers/${id}`, { auditMessage }),
|
|
@@ -612,42 +927,14 @@ class PlaidClient {
|
|
|
612
927
|
* Update a vocab layer's name.
|
|
613
928
|
* @param {string} id - The resource ID
|
|
614
929
|
* @param {string} name - The name
|
|
930
|
+
* @param {string} [auditMessage] - Audit message for this write
|
|
615
931
|
*/
|
|
616
932
|
update: (id, name, auditMessage) =>
|
|
617
933
|
this._request("PATCH", `/api/v1/vocab-layers/${id}`, {
|
|
618
934
|
auditMessage,
|
|
619
935
|
body: bodyOf({ name }),
|
|
620
936
|
}),
|
|
621
|
-
|
|
622
|
-
* Set a configuration value for a layer in an editor namespace.
|
|
623
|
-
* @param {string} id - The resource ID
|
|
624
|
-
* @param {string} namespace - The config namespace
|
|
625
|
-
* @param {string} configKey - The config key
|
|
626
|
-
* @param {any} configValue - Configuration value to set
|
|
627
|
-
* @param {string} [auditMessage] - Audit message for this write
|
|
628
|
-
* @param {{expected?: any}} [options] - `expected`: the value read for this key (null or undefined when it
|
|
629
|
-
* was absent). The write is then refused with a 409 when the stored value differs.
|
|
630
|
-
*/
|
|
631
|
-
setConfig: (id, namespace, configKey, configValue, auditMessage, options) =>
|
|
632
|
-
this._request(
|
|
633
|
-
"PUT",
|
|
634
|
-
`/api/v1/vocab-layers/${id}/config/${namespace}/${configKey}`,
|
|
635
|
-
configRequest(auditMessage, configValue, options),
|
|
636
|
-
),
|
|
637
|
-
/**
|
|
638
|
-
* Remove a configuration value for a layer.
|
|
639
|
-
* @param {string} id - The resource ID
|
|
640
|
-
* @param {string} namespace - The config namespace
|
|
641
|
-
* @param {string} configKey - The config key
|
|
642
|
-
* @param {string} [auditMessage] - Audit message for this write
|
|
643
|
-
* @param {{expected?: any}} [options] - `expected`, as on setConfig.
|
|
644
|
-
*/
|
|
645
|
-
deleteConfig: (id, namespace, configKey, auditMessage, options) =>
|
|
646
|
-
this._request(
|
|
647
|
-
"DELETE",
|
|
648
|
-
`/api/v1/vocab-layers/${id}/config/${namespace}/${configKey}`,
|
|
649
|
-
configRequest(auditMessage, undefined, options, true),
|
|
650
|
-
),
|
|
937
|
+
...configMethods(this, "vocab-layers"),
|
|
651
938
|
/**
|
|
652
939
|
* List all vocab layers accessible to user. Transparently follows
|
|
653
940
|
* pagination cursors and returns the full flat array.
|
|
@@ -678,6 +965,9 @@ class PlaidClient {
|
|
|
678
965
|
/**
|
|
679
966
|
* Create a new vocab layer. Note: this also registers the user as a maintainer.
|
|
680
967
|
* @param {string} name - The name
|
|
968
|
+
* @param {string} [auditMessage] - Audit message for this write
|
|
969
|
+
* @param {object} [opts]
|
|
970
|
+
* @param {string} [opts.id] - The new entity's id, minted by the caller (see uuidv7)
|
|
681
971
|
*/
|
|
682
972
|
create: (name, auditMessage, { id } = {}) =>
|
|
683
973
|
this._request("POST", "/api/v1/vocab-layers", {
|
|
@@ -688,6 +978,7 @@ class PlaidClient {
|
|
|
688
978
|
* Assign a user as a maintainer for this vocab layer.
|
|
689
979
|
* @param {string} id - The resource ID
|
|
690
980
|
* @param {string} userId - The user ID
|
|
981
|
+
* @param {string} [auditMessage] - Audit message for this write
|
|
691
982
|
*/
|
|
692
983
|
addMaintainer: (id, userId, auditMessage) =>
|
|
693
984
|
this._request(
|
|
@@ -699,6 +990,7 @@ class PlaidClient {
|
|
|
699
990
|
* Remove a user's maintainer privileges for this vocab layer.
|
|
700
991
|
* @param {string} id - The resource ID
|
|
701
992
|
* @param {string} userId - The user ID
|
|
993
|
+
* @param {string} [auditMessage] - Audit message for this write
|
|
702
994
|
*/
|
|
703
995
|
removeMaintainer: (id, userId, auditMessage) =>
|
|
704
996
|
this._request(
|
|
@@ -709,38 +1001,12 @@ class PlaidClient {
|
|
|
709
1001
|
};
|
|
710
1002
|
|
|
711
1003
|
this.relations = {
|
|
712
|
-
|
|
713
|
-
* Replace all metadata for a relation.
|
|
714
|
-
* @param {string} relationId - The relation ID
|
|
715
|
-
* @param {any} body - The request body
|
|
716
|
-
*/
|
|
717
|
-
setMetadata: (relationId, body, auditMessage) =>
|
|
718
|
-
this._request("PUT", `/api/v1/relations/${relationId}/metadata`, {
|
|
719
|
-
auditMessage,
|
|
720
|
-
rawBody: body,
|
|
721
|
-
}),
|
|
722
|
-
/**
|
|
723
|
-
* Remove all metadata from a relation.
|
|
724
|
-
* @param {string} relationId - The relation ID
|
|
725
|
-
*/
|
|
726
|
-
deleteMetadata: (relationId, auditMessage) =>
|
|
727
|
-
this._request("DELETE", `/api/v1/relations/${relationId}/metadata`, {
|
|
728
|
-
auditMessage,
|
|
729
|
-
}),
|
|
730
|
-
/**
|
|
731
|
-
* Edit metadata for a relation with a list of ops applied in order, in one operation. `{op: 'set', path, value}` writes value at path, creating missing objects along it; `{op: 'delete', path}` removes the key at path (a no-op when absent). A path is a non-empty array of keys, the first a top-level key. A path through a non-object is refused (400). See metadataOps and applyMetadataOps.
|
|
732
|
-
* @param {string} relationId - The relation ID
|
|
733
|
-
* @param {Array<{op: string, path: string[], value?: any}>} body - The metadata ops
|
|
734
|
-
*/
|
|
735
|
-
patchMetadata: (relationId, body, auditMessage) =>
|
|
736
|
-
this._request("PATCH", `/api/v1/relations/${relationId}/metadata`, {
|
|
737
|
-
auditMessage,
|
|
738
|
-
rawBody: body,
|
|
739
|
-
}),
|
|
1004
|
+
...metadataMethods(this, "relations"),
|
|
740
1005
|
/**
|
|
741
1006
|
* Update the target span of a relation.
|
|
742
1007
|
* @param {string} relationId - The relation ID
|
|
743
1008
|
* @param {string} spanId - The span ID
|
|
1009
|
+
* @param {string} [auditMessage] - Audit message for this write
|
|
744
1010
|
*/
|
|
745
1011
|
setTarget: (relationId, spanId, auditMessage) =>
|
|
746
1012
|
this._request("PUT", `/api/v1/relations/${relationId}/target`, {
|
|
@@ -756,6 +1022,7 @@ class PlaidClient {
|
|
|
756
1022
|
/**
|
|
757
1023
|
* Delete a relation.
|
|
758
1024
|
* @param {string} relationId - The relation ID
|
|
1025
|
+
* @param {string} [auditMessage] - Audit message for this write
|
|
759
1026
|
*/
|
|
760
1027
|
delete: (relationId, auditMessage) =>
|
|
761
1028
|
this._request("DELETE", `/api/v1/relations/${relationId}`, {
|
|
@@ -765,6 +1032,7 @@ class PlaidClient {
|
|
|
765
1032
|
* Update a relation's value.
|
|
766
1033
|
* @param {string} relationId - The relation ID
|
|
767
1034
|
* @param {any} value - The value
|
|
1035
|
+
* @param {string} [auditMessage] - Audit message for this write
|
|
768
1036
|
*/
|
|
769
1037
|
update: (relationId, value, auditMessage) =>
|
|
770
1038
|
this._request("PATCH", `/api/v1/relations/${relationId}`, {
|
|
@@ -775,6 +1043,7 @@ class PlaidClient {
|
|
|
775
1043
|
* Update the source span of a relation.
|
|
776
1044
|
* @param {string} relationId - The relation ID
|
|
777
1045
|
* @param {string} spanId - The span ID
|
|
1046
|
+
* @param {string} [auditMessage] - Audit message for this write
|
|
778
1047
|
*/
|
|
779
1048
|
setSource: (relationId, spanId, auditMessage) =>
|
|
780
1049
|
this._request("PUT", `/api/v1/relations/${relationId}/source`, {
|
|
@@ -790,6 +1059,9 @@ class PlaidClient {
|
|
|
790
1059
|
* @param {string} targetId - The target span ID
|
|
791
1060
|
* @param {any} value - The value
|
|
792
1061
|
* @param {any} [metadata] - Metadata map. Omit to leave unset; pass null to send JSON null.
|
|
1062
|
+
* @param {string} [auditMessage] - Audit message for this write
|
|
1063
|
+
* @param {object} [opts]
|
|
1064
|
+
* @param {string} [opts.id] - The new entity's id, minted by the caller (see uuidv7)
|
|
793
1065
|
*/
|
|
794
1066
|
create: (
|
|
795
1067
|
layerId,
|
|
@@ -814,6 +1086,7 @@ class PlaidClient {
|
|
|
814
1086
|
/**
|
|
815
1087
|
* Create multiple relations in a single operation.
|
|
816
1088
|
* @param {Array} body - The request body
|
|
1089
|
+
* @param {string} [auditMessage] - Audit message for this write
|
|
817
1090
|
* @returns {Promise<{ids: string[]}>} The created entity IDs, in input order. (bulkDelete resolves to no value.)
|
|
818
1091
|
*/
|
|
819
1092
|
bulkCreate: (body, auditMessage) =>
|
|
@@ -821,6 +1094,8 @@ class PlaidClient {
|
|
|
821
1094
|
/**
|
|
822
1095
|
* Delete multiple relations in a single operation. Provide an array of IDs.
|
|
823
1096
|
* @param {Array} body - The request body
|
|
1097
|
+
* @param {string} [auditMessage] - Audit message for this write
|
|
1098
|
+
* @returns {Promise<void>}
|
|
824
1099
|
*/
|
|
825
1100
|
bulkDelete: (body, auditMessage) =>
|
|
826
1101
|
this._request("DELETE", "/api/v1/relations/bulk", {
|
|
@@ -830,6 +1105,7 @@ class PlaidClient {
|
|
|
830
1105
|
/**
|
|
831
1106
|
* Update many relations in a single operation: set values and/or patch metadata.
|
|
832
1107
|
* @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 list of metadata ops, as for patchMetadata. 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` (past fifty documents, only their number, in `X-Document-Versions-Omitted`). A `document-version` precondition is accepted only when every entry lies in one document. An unknown id refuses the whole update.
|
|
1108
|
+
* @param {string} [auditMessage] - Audit message for this write
|
|
833
1109
|
* @returns {Promise<{count: number}>} How many relations were updated.
|
|
834
1110
|
*/
|
|
835
1111
|
bulkUpdate: (body, auditMessage) =>
|
|
@@ -840,81 +1116,22 @@ class PlaidClient {
|
|
|
840
1116
|
};
|
|
841
1117
|
|
|
842
1118
|
this.spanLayers = {
|
|
843
|
-
|
|
844
|
-
* Set a configuration value for a layer in an editor namespace.
|
|
845
|
-
* @param {string} spanLayerId - The span layer ID
|
|
846
|
-
* @param {string} namespace - The config namespace
|
|
847
|
-
* @param {string} configKey - The config key
|
|
848
|
-
* @param {any} configValue - Configuration value to set
|
|
849
|
-
* @param {string} [auditMessage] - Audit message for this write
|
|
850
|
-
* @param {{expected?: any}} [options] - `expected`: the value read for this key (null or undefined when it
|
|
851
|
-
* was absent). The write is then refused with a 409 when the stored value differs.
|
|
852
|
-
*/
|
|
853
|
-
setConfig: (spanLayerId, namespace, configKey, configValue, auditMessage, options) =>
|
|
854
|
-
this._request(
|
|
855
|
-
"PUT",
|
|
856
|
-
`/api/v1/span-layers/${spanLayerId}/config/${namespace}/${configKey}`,
|
|
857
|
-
configRequest(auditMessage, configValue, options),
|
|
858
|
-
),
|
|
859
|
-
/**
|
|
860
|
-
* Remove a configuration value for a layer.
|
|
861
|
-
* @param {string} spanLayerId - The span layer ID
|
|
862
|
-
* @param {string} namespace - The config namespace
|
|
863
|
-
* @param {string} configKey - The config key
|
|
864
|
-
* @param {string} [auditMessage] - Audit message for this write
|
|
865
|
-
* @param {{expected?: any}} [options] - `expected`, as on setConfig.
|
|
866
|
-
*/
|
|
867
|
-
deleteConfig: (spanLayerId, namespace, configKey, auditMessage, options) =>
|
|
868
|
-
this._request(
|
|
869
|
-
"DELETE",
|
|
870
|
-
`/api/v1/span-layers/${spanLayerId}/config/${namespace}/${configKey}`,
|
|
871
|
-
configRequest(auditMessage, undefined, options, true),
|
|
872
|
-
),
|
|
1119
|
+
...configMethods(this, "span-layers"),
|
|
873
1120
|
...constraintMethods(this, "span-layers"),
|
|
874
|
-
|
|
875
|
-
* Get a span layer by ID.
|
|
876
|
-
* @param {string} spanLayerId - The span layer ID
|
|
877
|
-
*/
|
|
878
|
-
get: (spanLayerId) =>
|
|
879
|
-
this._request("GET", `/api/v1/span-layers/${spanLayerId}`),
|
|
880
|
-
/**
|
|
881
|
-
* Delete a span layer.
|
|
882
|
-
* @param {string} spanLayerId - The span layer ID
|
|
883
|
-
*/
|
|
884
|
-
delete: (spanLayerId, auditMessage) =>
|
|
885
|
-
this._request("DELETE", `/api/v1/span-layers/${spanLayerId}`, {
|
|
886
|
-
auditMessage,
|
|
887
|
-
}),
|
|
888
|
-
/**
|
|
889
|
-
* Update a span layer's name.
|
|
890
|
-
* @param {string} spanLayerId - The span layer ID
|
|
891
|
-
* @param {string} name - The name
|
|
892
|
-
*/
|
|
893
|
-
update: (spanLayerId, name, auditMessage) =>
|
|
894
|
-
this._request("PATCH", `/api/v1/span-layers/${spanLayerId}`, {
|
|
895
|
-
auditMessage,
|
|
896
|
-
body: bodyOf({ name }),
|
|
897
|
-
}),
|
|
1121
|
+
...layerMethods(this, "span-layers"),
|
|
898
1122
|
/**
|
|
899
1123
|
* Create a new span layer.
|
|
900
1124
|
* @param {string} tokenLayerId - The token layer ID
|
|
901
1125
|
* @param {string} name - The name
|
|
1126
|
+
* @param {string} [auditMessage] - Audit message for this write
|
|
1127
|
+
* @param {object} [opts]
|
|
1128
|
+
* @param {string} [opts.id] - The new entity's id, minted by the caller (see uuidv7)
|
|
902
1129
|
*/
|
|
903
1130
|
create: (tokenLayerId, name, auditMessage, { id } = {}) =>
|
|
904
1131
|
this._request("POST", "/api/v1/span-layers", {
|
|
905
1132
|
auditMessage,
|
|
906
1133
|
body: bodyOf({ id, "token-layer-id": tokenLayerId, name }),
|
|
907
1134
|
}),
|
|
908
|
-
/**
|
|
909
|
-
* Shift a span layer's display order.
|
|
910
|
-
* @param {string} spanLayerId - The span layer ID
|
|
911
|
-
* @param {string} direction - The direction ("up" or "down")
|
|
912
|
-
*/
|
|
913
|
-
shift: (spanLayerId, direction, auditMessage) =>
|
|
914
|
-
this._request("POST", `/api/v1/span-layers/${spanLayerId}/shift`, {
|
|
915
|
-
auditMessage,
|
|
916
|
-
body: bodyOf({ direction }),
|
|
917
|
-
}),
|
|
918
1135
|
};
|
|
919
1136
|
|
|
920
1137
|
this.spans = {
|
|
@@ -922,6 +1139,7 @@ class PlaidClient {
|
|
|
922
1139
|
* Replace tokens for a span.
|
|
923
1140
|
* @param {string} spanId - The span ID
|
|
924
1141
|
* @param {Array} tokens - The tokens
|
|
1142
|
+
* @param {string} [auditMessage] - Audit message for this write
|
|
925
1143
|
*/
|
|
926
1144
|
setTokens: (spanId, tokens, auditMessage) =>
|
|
927
1145
|
this._request("PUT", `/api/v1/spans/${spanId}/tokens`, {
|
|
@@ -935,6 +1153,9 @@ class PlaidClient {
|
|
|
935
1153
|
* @param {Array} tokens - The tokens
|
|
936
1154
|
* @param {any} value - The value
|
|
937
1155
|
* @param {any} [metadata] - Metadata map. Omit to leave unset; pass null to send JSON null.
|
|
1156
|
+
* @param {string} [auditMessage] - Audit message for this write
|
|
1157
|
+
* @param {object} [opts]
|
|
1158
|
+
* @param {string} [opts.id] - The new entity's id, minted by the caller (see uuidv7)
|
|
938
1159
|
*/
|
|
939
1160
|
create: (spanLayerId, tokens, value, metadata, auditMessage, { id } = {}) =>
|
|
940
1161
|
this._request("POST", "/api/v1/spans", {
|
|
@@ -956,6 +1177,7 @@ class PlaidClient {
|
|
|
956
1177
|
/**
|
|
957
1178
|
* Delete a span.
|
|
958
1179
|
* @param {string} spanId - The span ID
|
|
1180
|
+
* @param {string} [auditMessage] - Audit message for this write
|
|
959
1181
|
*/
|
|
960
1182
|
delete: (spanId, auditMessage) =>
|
|
961
1183
|
this._request("DELETE", `/api/v1/spans/${spanId}`, { auditMessage }),
|
|
@@ -963,6 +1185,7 @@ class PlaidClient {
|
|
|
963
1185
|
* Update a span's value.
|
|
964
1186
|
* @param {string} spanId - The span ID
|
|
965
1187
|
* @param {any} value - The value
|
|
1188
|
+
* @param {string} [auditMessage] - Audit message for this write
|
|
966
1189
|
*/
|
|
967
1190
|
update: (spanId, value, auditMessage) =>
|
|
968
1191
|
this._request("PATCH", `/api/v1/spans/${spanId}`, {
|
|
@@ -972,6 +1195,7 @@ class PlaidClient {
|
|
|
972
1195
|
/**
|
|
973
1196
|
* Create multiple spans in a single operation.
|
|
974
1197
|
* @param {Array} body - The request body
|
|
1198
|
+
* @param {string} [auditMessage] - Audit message for this write
|
|
975
1199
|
* @returns {Promise<{ids: string[]}>} The created entity IDs, in input order. (bulkDelete resolves to no value.)
|
|
976
1200
|
*/
|
|
977
1201
|
bulkCreate: (body, auditMessage) =>
|
|
@@ -979,12 +1203,15 @@ class PlaidClient {
|
|
|
979
1203
|
/**
|
|
980
1204
|
* Delete multiple spans in a single operation. Provide an array of IDs.
|
|
981
1205
|
* @param {Array} body - The request body
|
|
1206
|
+
* @param {string} [auditMessage] - Audit message for this write
|
|
1207
|
+
* @returns {Promise<void>}
|
|
982
1208
|
*/
|
|
983
1209
|
bulkDelete: (body, auditMessage) =>
|
|
984
1210
|
this._request("DELETE", "/api/v1/spans/bulk", { auditMessage, body }),
|
|
985
1211
|
/**
|
|
986
1212
|
* Update many spans in a single operation: set values and/or patch metadata.
|
|
987
1213
|
* @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 list of metadata ops, as for patchMetadata. 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` (past fifty documents, only their number, in `X-Document-Versions-Omitted`). A `document-version` precondition is accepted only when every entry lies in one document. An unknown id refuses the whole update.
|
|
1214
|
+
* @param {string} [auditMessage] - Audit message for this write
|
|
988
1215
|
* @returns {Promise<{count: number}>} How many spans were updated.
|
|
989
1216
|
*/
|
|
990
1217
|
bulkUpdate: (body, auditMessage) =>
|
|
@@ -992,64 +1219,71 @@ class PlaidClient {
|
|
|
992
1219
|
auditMessage,
|
|
993
1220
|
body,
|
|
994
1221
|
}),
|
|
995
|
-
|
|
996
|
-
* Replace all metadata for a span.
|
|
997
|
-
* @param {string} spanId - The span ID
|
|
998
|
-
* @param {any} body - The request body
|
|
999
|
-
*/
|
|
1000
|
-
setMetadata: (spanId, body, auditMessage) =>
|
|
1001
|
-
this._request("PUT", `/api/v1/spans/${spanId}/metadata`, {
|
|
1002
|
-
auditMessage,
|
|
1003
|
-
rawBody: body,
|
|
1004
|
-
}),
|
|
1005
|
-
/**
|
|
1006
|
-
* Remove all metadata from a span.
|
|
1007
|
-
* @param {string} spanId - The span ID
|
|
1008
|
-
*/
|
|
1009
|
-
deleteMetadata: (spanId, auditMessage) =>
|
|
1010
|
-
this._request("DELETE", `/api/v1/spans/${spanId}/metadata`, {
|
|
1011
|
-
auditMessage,
|
|
1012
|
-
}),
|
|
1013
|
-
/**
|
|
1014
|
-
* Edit metadata for a span with a list of ops applied in order, in one operation. `{op: 'set', path, value}` writes value at path, creating missing objects along it; `{op: 'delete', path}` removes the key at path (a no-op when absent). A path is a non-empty array of keys, the first a top-level key. A path through a non-object is refused (400). See metadataOps and applyMetadataOps.
|
|
1015
|
-
* @param {string} spanId - The span ID
|
|
1016
|
-
* @param {Array<{op: string, path: string[], value?: any}>} body - The metadata ops
|
|
1017
|
-
*/
|
|
1018
|
-
patchMetadata: (spanId, body, auditMessage) =>
|
|
1019
|
-
this._request("PATCH", `/api/v1/spans/${spanId}/metadata`, {
|
|
1020
|
-
auditMessage,
|
|
1021
|
-
rawBody: body,
|
|
1022
|
-
}),
|
|
1222
|
+
...metadataMethods(this, "spans"),
|
|
1023
1223
|
};
|
|
1024
1224
|
|
|
1025
|
-
// Server-level facts.
|
|
1026
|
-
//
|
|
1027
|
-
//
|
|
1028
|
-
|
|
1225
|
+
// Server-level facts. Read once, and again only when they may have
|
|
1226
|
+
// changed: after this client's connection to the server was lost and came
|
|
1227
|
+
// back (a restart, the only way the limits change, always drops it), or
|
|
1228
|
+
// after the server refused a private data write as too large. A caller
|
|
1229
|
+
// asking "will this file be accepted" does not pay a round trip to find
|
|
1230
|
+
// out. The facts live on the client (`_serverFacts`), so a batch opened
|
|
1231
|
+
// on it reads the same.
|
|
1029
1232
|
this.server = {
|
|
1030
1233
|
/**
|
|
1031
1234
|
* This server's version and the limits it enforces, e.g.
|
|
1032
1235
|
* `{ limits: { mediaFileBytes, jsonBodyBytes, batchOperations, … } }`.
|
|
1033
1236
|
* Sizes are in bytes. Unauthenticated.
|
|
1237
|
+
* @returns {Promise<{limits: ServerLimits}>}
|
|
1034
1238
|
*/
|
|
1035
1239
|
info: () => {
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1240
|
+
const facts = this._serverFacts;
|
|
1241
|
+
if (!facts.info) {
|
|
1242
|
+
const asked = this._request("GET", "/api/v1/info").catch((err) => {
|
|
1243
|
+
// A failure must not be kept: a client that starts before the
|
|
1039
1244
|
// server is up would never see the limits at all.
|
|
1040
|
-
|
|
1245
|
+
if (facts.info === asked) facts.info = null;
|
|
1041
1246
|
throw err;
|
|
1042
1247
|
});
|
|
1248
|
+
facts.info = asked;
|
|
1043
1249
|
}
|
|
1044
|
-
return
|
|
1250
|
+
return facts.info;
|
|
1251
|
+
},
|
|
1252
|
+
/**
|
|
1253
|
+
* Read `GET /info` again and resolve to it. Until it answers, a reader
|
|
1254
|
+
* waits for it. The facts known before are kept when the server does
|
|
1255
|
+
* not answer, and the error is thrown.
|
|
1256
|
+
* @returns {Promise<{limits: ServerLimits}>}
|
|
1257
|
+
*/
|
|
1258
|
+
refresh: () => {
|
|
1259
|
+
const facts = this._serverFacts;
|
|
1260
|
+
const before = facts.info;
|
|
1261
|
+
facts.stale = false;
|
|
1262
|
+
const fresh = this._request("GET", "/api/v1/info");
|
|
1263
|
+
const held = fresh.catch((err) => {
|
|
1264
|
+
if (facts.info === held) facts.info = before;
|
|
1265
|
+
if (before) return before;
|
|
1266
|
+
throw err;
|
|
1267
|
+
});
|
|
1268
|
+
held.catch(() => {});
|
|
1269
|
+
facts.info = held;
|
|
1270
|
+
return fresh;
|
|
1271
|
+
},
|
|
1272
|
+
/**
|
|
1273
|
+
* Just the limits, which is what a caller almost always wants.
|
|
1274
|
+
* @returns {Promise<ServerLimits>}
|
|
1275
|
+
*/
|
|
1276
|
+
limits: async () => {
|
|
1277
|
+
// Through `self`: tsc types a bundle that names itself as
|
|
1278
|
+
// `this.server` in its own methods `any` in the declarations.
|
|
1279
|
+
const self = this;
|
|
1280
|
+
return (await self.server.info()).limits;
|
|
1045
1281
|
},
|
|
1046
|
-
/** Just the limits, which is what a caller almost always wants. */
|
|
1047
|
-
limits: async () => (await this.server.info()).limits,
|
|
1048
1282
|
/**
|
|
1049
1283
|
* Liveness, version and database size. Unauthenticated, and served
|
|
1050
1284
|
* outside the REST router at /health, so it answers even while the API
|
|
1051
1285
|
* is refusing requests. Never cached — the point is that it is current.
|
|
1052
|
-
* @returns {Promise<
|
|
1286
|
+
* @returns {Promise<ServerHealth>}
|
|
1053
1287
|
*/
|
|
1054
1288
|
health: () => PlaidClient.health(this.baseUrl, { timeout: this.timeout }),
|
|
1055
1289
|
};
|
|
@@ -1073,34 +1307,7 @@ class PlaidClient {
|
|
|
1073
1307
|
};
|
|
1074
1308
|
|
|
1075
1309
|
this.texts = {
|
|
1076
|
-
|
|
1077
|
-
* Replace all metadata for a text.
|
|
1078
|
-
* @param {string} textId - The text ID
|
|
1079
|
-
* @param {any} body - The request body
|
|
1080
|
-
*/
|
|
1081
|
-
setMetadata: (textId, body, auditMessage) =>
|
|
1082
|
-
this._request("PUT", `/api/v1/texts/${textId}/metadata`, {
|
|
1083
|
-
auditMessage,
|
|
1084
|
-
rawBody: body,
|
|
1085
|
-
}),
|
|
1086
|
-
/**
|
|
1087
|
-
* Remove all metadata from a text.
|
|
1088
|
-
* @param {string} textId - The text ID
|
|
1089
|
-
*/
|
|
1090
|
-
deleteMetadata: (textId, auditMessage) =>
|
|
1091
|
-
this._request("DELETE", `/api/v1/texts/${textId}/metadata`, {
|
|
1092
|
-
auditMessage,
|
|
1093
|
-
}),
|
|
1094
|
-
/**
|
|
1095
|
-
* Edit metadata for a text with a list of ops applied in order, in one operation. `{op: 'set', path, value}` writes value at path, creating missing objects along it; `{op: 'delete', path}` removes the key at path (a no-op when absent). A path is a non-empty array of keys, the first a top-level key. A path through a non-object is refused (400). See metadataOps and applyMetadataOps.
|
|
1096
|
-
* @param {string} textId - The text ID
|
|
1097
|
-
* @param {Array<{op: string, path: string[], value?: any}>} body - The metadata ops
|
|
1098
|
-
*/
|
|
1099
|
-
patchMetadata: (textId, body, auditMessage) =>
|
|
1100
|
-
this._request("PATCH", `/api/v1/texts/${textId}/metadata`, {
|
|
1101
|
-
auditMessage,
|
|
1102
|
-
rawBody: body,
|
|
1103
|
-
}),
|
|
1310
|
+
...metadataMethods(this, "texts"),
|
|
1104
1311
|
/**
|
|
1105
1312
|
* Create a new text in a document's text layer. A text is a container for
|
|
1106
1313
|
* one long string in `body` for a given layer.
|
|
@@ -1108,6 +1315,11 @@ class PlaidClient {
|
|
|
1108
1315
|
* @param {string} documentId - The document ID
|
|
1109
1316
|
* @param {string} body - The request body
|
|
1110
1317
|
* @param {any} [metadata] - Metadata map. Omit to leave unset; pass null to send JSON null.
|
|
1318
|
+
* @param {string} [auditMessage]
|
|
1319
|
+
* @param {{id?: string, tokenEdges?: number[]}} [options] - `id`: the new text's id, a UUIDv7
|
|
1320
|
+
* this client minted. `tokenEdges`: the code-point offsets where the tokens made next on
|
|
1321
|
+
* this text begin and end. The body is stored composed, except a character one of them
|
|
1322
|
+
* falls inside, which stays as sent (see composeText).
|
|
1111
1323
|
*/
|
|
1112
1324
|
create: (
|
|
1113
1325
|
textLayerId,
|
|
@@ -1115,7 +1327,7 @@ class PlaidClient {
|
|
|
1115
1327
|
body,
|
|
1116
1328
|
metadata,
|
|
1117
1329
|
auditMessage,
|
|
1118
|
-
{ id } = {},
|
|
1330
|
+
{ id, tokenEdges } = {},
|
|
1119
1331
|
) =>
|
|
1120
1332
|
this._request("POST", "/api/v1/texts", {
|
|
1121
1333
|
auditMessage,
|
|
@@ -1124,6 +1336,7 @@ class PlaidClient {
|
|
|
1124
1336
|
"text-layer-id": textLayerId,
|
|
1125
1337
|
"document-id": documentId,
|
|
1126
1338
|
body,
|
|
1339
|
+
"token-edges": tokenEdges,
|
|
1127
1340
|
metadata,
|
|
1128
1341
|
}),
|
|
1129
1342
|
}),
|
|
@@ -1136,6 +1349,7 @@ class PlaidClient {
|
|
|
1136
1349
|
/**
|
|
1137
1350
|
* Delete a text and all dependent data.
|
|
1138
1351
|
* @param {string} textId - The text ID
|
|
1352
|
+
* @param {string} [auditMessage] - Audit message for this write
|
|
1139
1353
|
*/
|
|
1140
1354
|
delete: (textId, auditMessage) =>
|
|
1141
1355
|
this._request("DELETE", `/api/v1/texts/${textId}`, { auditMessage }),
|
|
@@ -1195,14 +1409,14 @@ class PlaidClient {
|
|
|
1195
1409
|
* List (or search) users. Transparently follows pagination cursors and
|
|
1196
1410
|
* returns the full flat array. Admin-or-maintainer only.
|
|
1197
1411
|
* @param {object} [opts]
|
|
1198
|
-
* @param {string} [opts.q] - Filter to users whose display name contains this text, or whose email starts with it (contains it, when the text
|
|
1412
|
+
* @param {string} [opts.q] - Filter to users whose display name contains this text, or whose email starts with it (contains it, when the text holds an at sign), case-insensitive
|
|
1199
1413
|
*/
|
|
1200
1414
|
list: ({ q } = {}) =>
|
|
1201
1415
|
listAll(this, "/api/v1/users", { query: { q } }),
|
|
1202
1416
|
/**
|
|
1203
1417
|
* Fetch a single page of users (optionally filtered by `q`).
|
|
1204
1418
|
* @param {object} [opts]
|
|
1205
|
-
* @param {string} [opts.q] - Filter to users whose display name contains this text, or whose email starts with it (contains it, when the text
|
|
1419
|
+
* @param {string} [opts.q] - Filter to users whose display name contains this text, or whose email starts with it (contains it, when the text holds an at sign), case-insensitive
|
|
1206
1420
|
* @param {number} [opts.limit] - Page size (1..1000; server default 100)
|
|
1207
1421
|
* @param {string} [opts.cursor] - Opaque cursor from a previous page
|
|
1208
1422
|
* @returns {Promise<{entries: Array, nextCursor: (string|null)}>}
|
|
@@ -1216,7 +1430,7 @@ class PlaidClient {
|
|
|
1216
1430
|
/**
|
|
1217
1431
|
* Async-iterate users page by page; yields each page's entries array.
|
|
1218
1432
|
* @param {object} [opts]
|
|
1219
|
-
* @param {string} [opts.q] - Filter to users whose display name contains this text, or whose email starts with it (contains it, when the text
|
|
1433
|
+
* @param {string} [opts.q] - Filter to users whose display name contains this text, or whose email starts with it (contains it, when the text holds an at sign), case-insensitive
|
|
1220
1434
|
* @param {number} [opts.pageSize] - Per-request page size
|
|
1221
1435
|
* @returns {AsyncGenerator<Array>}
|
|
1222
1436
|
*/
|
|
@@ -1234,12 +1448,13 @@ class PlaidClient {
|
|
|
1234
1448
|
* @param {boolean} isAdmin - Whether the user is an admin
|
|
1235
1449
|
* @param {string} [displayName] - How the user is shown in the UI.
|
|
1236
1450
|
* Defaults to the local part of the email.
|
|
1451
|
+
* @param {string} [auditMessage] - Audit message for this write
|
|
1237
1452
|
*/
|
|
1238
1453
|
create: (email, password, isAdmin, displayName, auditMessage) =>
|
|
1239
1454
|
this._request("POST", "/api/v1/users", {
|
|
1240
1455
|
auditMessage,
|
|
1241
1456
|
body: bodyOf({
|
|
1242
|
-
email,
|
|
1457
|
+
email: normalizeUserId(email),
|
|
1243
1458
|
password,
|
|
1244
1459
|
"is-admin": isAdmin,
|
|
1245
1460
|
// Left out when not given (null too), so core gives the user the
|
|
@@ -1275,6 +1490,10 @@ class PlaidClient {
|
|
|
1275
1490
|
* that may be long: audit() walks every page before it resolves.
|
|
1276
1491
|
* @param {string} userId - The user ID
|
|
1277
1492
|
* @param {object} [opts]
|
|
1493
|
+
* @param {string} [opts.startTime] - Only entries at or after this instant
|
|
1494
|
+
* @param {string} [opts.endTime] - Only entries at or before this instant
|
|
1495
|
+
* @param {string[]|string} [opts.opTypes] - Only these op types
|
|
1496
|
+
* @param {OperationKind[]|string} [opts.kinds] - Only the entries of operations of these kinds, each whole
|
|
1278
1497
|
* @param {"asc"|"desc"} [opts.order] - "desc" pages newest-first
|
|
1279
1498
|
* @param {number} [opts.limit] - Page size (1..1000; server default 100)
|
|
1280
1499
|
* @param {string} [opts.cursor] - Opaque cursor from a previous page
|
|
@@ -1314,6 +1533,7 @@ class PlaidClient {
|
|
|
1314
1533
|
* stays visible in listings with a deactivated-at timestamp.
|
|
1315
1534
|
* Reversible via activate(), which restores login only.
|
|
1316
1535
|
* @param {string} id - The resource ID
|
|
1536
|
+
* @param {string} [auditMessage] - Audit message for this write
|
|
1317
1537
|
*/
|
|
1318
1538
|
delete: (id, auditMessage) =>
|
|
1319
1539
|
this._request("DELETE", `/api/v1/users/${id}`, { auditMessage }),
|
|
@@ -1322,6 +1542,7 @@ class PlaidClient {
|
|
|
1322
1542
|
* Project memberships, vocab maintainerships, and API tokens removed
|
|
1323
1543
|
* at deactivation are NOT restored — re-grant them deliberately.
|
|
1324
1544
|
* @param {string} id - The resource ID
|
|
1545
|
+
* @param {string} [auditMessage] - Audit message for this write
|
|
1325
1546
|
*/
|
|
1326
1547
|
activate: (id, auditMessage) =>
|
|
1327
1548
|
this._request("POST", `/api/v1/users/${id}/activate`, { auditMessage }),
|
|
@@ -1337,6 +1558,7 @@ class PlaidClient {
|
|
|
1337
1558
|
* @param {string} [password] - New password
|
|
1338
1559
|
* @param {string} [displayName] - New display name
|
|
1339
1560
|
* @param {boolean} [isAdmin] - New admin status
|
|
1561
|
+
* @param {string} [auditMessage] - Audit message for this write
|
|
1340
1562
|
*/
|
|
1341
1563
|
update: (id, password, displayName, isAdmin, auditMessage) =>
|
|
1342
1564
|
this._request("PATCH", `/api/v1/users/${id}`, {
|
|
@@ -1348,23 +1570,89 @@ class PlaidClient {
|
|
|
1348
1570
|
}),
|
|
1349
1571
|
}),
|
|
1350
1572
|
/**
|
|
1351
|
-
*
|
|
1352
|
-
* an `<img
|
|
1353
|
-
*
|
|
1354
|
-
*
|
|
1573
|
+
* A token that shows any user's profile picture without an
|
|
1574
|
+
* Authorization header, for an `<img>`, which cannot send one. Resolves
|
|
1575
|
+
* to `{ token, expiresAt }` (`expiresAt` an ISO-8601 instant, a day on by
|
|
1576
|
+
* default). The server refuses it on every route but the picture, and
|
|
1577
|
+
* it stops working when the user signs out or changes password.
|
|
1578
|
+
*
|
|
1579
|
+
* One token serves the whole client: it is kept and handed out again
|
|
1580
|
+
* until under ten minutes of it remain (half its life, for one minted
|
|
1581
|
+
* near the end of a login), calls made while one is being minted share
|
|
1582
|
+
* that request, and it is dropped when the client's token changes.
|
|
1583
|
+
* avatarUrl() uses it.
|
|
1584
|
+
* @param {{renew?: boolean}} [options] - `renew`: mint a new one
|
|
1585
|
+
* whatever is kept, unless one was minted in the last few seconds
|
|
1586
|
+
* (or is being minted), which is shared
|
|
1587
|
+
* @returns {Promise<{token: string, expiresAt: string}>}
|
|
1588
|
+
*/
|
|
1589
|
+
avatarToken: ({ renew = false } = {}) => {
|
|
1590
|
+
// A batch is a view of its client and shares the client's token.
|
|
1591
|
+
const owner = this.client ?? this;
|
|
1592
|
+
const cached = owner._avatarToken;
|
|
1593
|
+
if (cached && cached.forToken === owner.token) {
|
|
1594
|
+
if (cached.pending) return cached.pending;
|
|
1595
|
+
const now = owner.serverNow().getTime();
|
|
1596
|
+
// A renewal shares one minted a moment ago: every picture on a page
|
|
1597
|
+
// fails together when a token dies, and each asks.
|
|
1598
|
+
if (renew && now - cached.mintedAt < AVATAR_TOKEN_FRESH_MS) {
|
|
1599
|
+
return Promise.resolve(cached.link);
|
|
1600
|
+
}
|
|
1601
|
+
const expires = Date.parse(cached.link.expiresAt);
|
|
1602
|
+
// Renewed ten minutes before it runs out, or at half its life when
|
|
1603
|
+
// it was minted for less than twenty: the server caps it at the
|
|
1604
|
+
// login's own expiry, and near the end of a login every token it
|
|
1605
|
+
// mints runs out at that same moment, so a fixed ten minutes asked
|
|
1606
|
+
// for a new one on every call.
|
|
1607
|
+
const renewAt = Math.min(AVATAR_TOKEN_RENEW_MS, (expires - cached.mintedAt) / 2);
|
|
1608
|
+
if (!renew && expires - now > renewAt) return Promise.resolve(cached.link);
|
|
1609
|
+
}
|
|
1610
|
+
const entry = {
|
|
1611
|
+
forToken: owner.token,
|
|
1612
|
+
pending: null,
|
|
1613
|
+
link: null,
|
|
1614
|
+
mintedAt: owner.serverNow().getTime(),
|
|
1615
|
+
};
|
|
1616
|
+
entry.pending = owner
|
|
1617
|
+
._request("POST", "/api/v1/avatar-link", { outOfBand: true })
|
|
1618
|
+
.then(
|
|
1619
|
+
(link) => {
|
|
1620
|
+
entry.pending = null;
|
|
1621
|
+
entry.link = link;
|
|
1622
|
+
return link;
|
|
1623
|
+
},
|
|
1624
|
+
(e) => {
|
|
1625
|
+
if (owner._avatarToken === entry) owner._avatarToken = null;
|
|
1626
|
+
throw e;
|
|
1627
|
+
},
|
|
1628
|
+
);
|
|
1629
|
+
owner._avatarToken = entry;
|
|
1630
|
+
return entry.pending;
|
|
1631
|
+
},
|
|
1632
|
+
/**
|
|
1633
|
+
* Build a URL for a user's profile picture, for an `<img>` src. The
|
|
1634
|
+
* URL carries the client's avatar token (see avatarToken()), never the
|
|
1635
|
+
* login token.
|
|
1355
1636
|
*
|
|
1356
1637
|
* Pass the user record's `avatarHash` as the second argument whenever you
|
|
1357
1638
|
* have it: the URL then addresses that exact picture, so the browser can
|
|
1358
1639
|
* cache it indefinitely and still pick up a replacement the moment the
|
|
1359
|
-
* user changes it.
|
|
1360
|
-
* can fall back to initials without a
|
|
1640
|
+
* user changes it. Resolves to null when `avatarHash` is null (the user
|
|
1641
|
+
* has no picture), so callers can fall back to initials without a
|
|
1642
|
+
* wasted request.
|
|
1361
1643
|
* @param {string} id - The user ID
|
|
1362
|
-
* @param {string} [avatarHash] - The user record's `avatarHash`
|
|
1363
|
-
* @
|
|
1644
|
+
* @param {string|null} [avatarHash] - The user record's `avatarHash`
|
|
1645
|
+
* @param {{renew?: boolean}} [options] - `renew`: mint a new avatar
|
|
1646
|
+
* token first, for a picture its URL failed to load (the token
|
|
1647
|
+
* stops working when the login it was minted under ends)
|
|
1648
|
+
* @returns {Promise<string|null>}
|
|
1364
1649
|
*/
|
|
1365
|
-
avatarUrl: (id, avatarHash) => {
|
|
1650
|
+
avatarUrl: async (id, avatarHash, { renew = false } = {}) => {
|
|
1366
1651
|
if (avatarHash === null) return null;
|
|
1367
|
-
|
|
1652
|
+
// Through `self`, as in server.limits.
|
|
1653
|
+
const self = this;
|
|
1654
|
+
const { token } = await self.users.avatarToken({ renew });
|
|
1655
|
+
const params = new URLSearchParams({ "avatar-token": token });
|
|
1368
1656
|
if (avatarHash) params.set("v", avatarHash);
|
|
1369
1657
|
return `${this.baseUrl}/api/v1/users/${id}/avatar?${params}`;
|
|
1370
1658
|
},
|
|
@@ -1384,6 +1672,7 @@ class PlaidClient {
|
|
|
1384
1672
|
* PNG, JPEG, WebP, and GIF. Resolves to the updated user record.
|
|
1385
1673
|
* @param {string} id - The user ID
|
|
1386
1674
|
* @param {File} file - The image to upload
|
|
1675
|
+
* @param {string} [auditMessage] - Audit message for this write
|
|
1387
1676
|
*/
|
|
1388
1677
|
setAvatar: (id, file, auditMessage) => {
|
|
1389
1678
|
const fd = new FormData();
|
|
@@ -1398,6 +1687,7 @@ class PlaidClient {
|
|
|
1398
1687
|
/**
|
|
1399
1688
|
* Remove a profile picture. Your own, or anyone's if you are an admin.
|
|
1400
1689
|
* @param {string} id - The user ID
|
|
1690
|
+
* @param {string} [auditMessage] - Audit message for this write
|
|
1401
1691
|
*/
|
|
1402
1692
|
// No flag: the upload beside this one is multipart and cannot be
|
|
1403
1693
|
// batched, but a DELETE carries no blob, so the batch transport takes
|
|
@@ -1421,7 +1711,8 @@ class PlaidClient {
|
|
|
1421
1711
|
* every project without dragging down the transcripts beside them.
|
|
1422
1712
|
*
|
|
1423
1713
|
* `pageSize` is exposed here, and defaults lower than elsewhere, because
|
|
1424
|
-
* one value runs to
|
|
1714
|
+
* one value runs to megabytes (`userDataValueBytes` in
|
|
1715
|
+
* `server.limits()`): a page of them with `includeValues` is the
|
|
1425
1716
|
* largest response this API can be asked for. Raise it when the listing
|
|
1426
1717
|
* is keys, or the values are known to be small.
|
|
1427
1718
|
* @param {string} userId
|
|
@@ -1430,6 +1721,7 @@ class PlaidClient {
|
|
|
1430
1721
|
* @param {string} [opts.pattern] - Only keys matching this GLOB
|
|
1431
1722
|
* @param {boolean} [opts.includeValues] - Also return each entry's value
|
|
1432
1723
|
* @param {number} [opts.pageSize=100] - Entries per request (1..1000)
|
|
1724
|
+
* @returns {Promise<UserDataEntry[]>}
|
|
1433
1725
|
*/
|
|
1434
1726
|
list: (userId, { prefix, pattern, includeValues, pageSize = 100 } = {}) =>
|
|
1435
1727
|
listAll(this, `/api/v1/users/${userId}/data`, {
|
|
@@ -1445,7 +1737,7 @@ class PlaidClient {
|
|
|
1445
1737
|
* @param {boolean} [opts.includeValues] - Also return each entry's value
|
|
1446
1738
|
* @param {number} [opts.limit] - Page size (1..1000; server default 100)
|
|
1447
1739
|
* @param {string} [opts.cursor] - Opaque cursor from a previous page
|
|
1448
|
-
* @returns {Promise<
|
|
1740
|
+
* @returns {Promise<Page<UserDataEntry>>}
|
|
1449
1741
|
*/
|
|
1450
1742
|
listPage: (
|
|
1451
1743
|
userId,
|
|
@@ -1464,6 +1756,7 @@ class PlaidClient {
|
|
|
1464
1756
|
* @param {string} [opts.pattern] - Only keys matching this GLOB
|
|
1465
1757
|
* @param {boolean} [opts.includeValues] - Also return each entry's value
|
|
1466
1758
|
* @param {number} [opts.pageSize=100] - Entries per request (1..1000)
|
|
1759
|
+
* @returns {AsyncGenerator<UserDataEntry[]>}
|
|
1467
1760
|
*/
|
|
1468
1761
|
iterPages: (
|
|
1469
1762
|
userId,
|
|
@@ -1474,9 +1767,10 @@ class PlaidClient {
|
|
|
1474
1767
|
query: { prefix, pattern, "include-values": includeValues },
|
|
1475
1768
|
}),
|
|
1476
1769
|
/**
|
|
1477
|
-
* Read one private data entry ({key, updatedAt, value}); 404 if absent.
|
|
1770
|
+
* Read one private data entry ({key, updatedAt, version, value}); 404 if absent.
|
|
1478
1771
|
* @param {string} userId
|
|
1479
1772
|
* @param {string} key
|
|
1773
|
+
* @returns {Promise<UserDataEntry & {value: any}>}
|
|
1480
1774
|
*/
|
|
1481
1775
|
get: (userId, key) =>
|
|
1482
1776
|
this._request(
|
|
@@ -1484,27 +1778,51 @@ class PlaidClient {
|
|
|
1484
1778
|
`/api/v1/users/${userId}/data/${encodeURIComponent(key)}`,
|
|
1485
1779
|
),
|
|
1486
1780
|
/**
|
|
1487
|
-
* Create or replace one private data entry. `value` is any JSON
|
|
1488
|
-
*
|
|
1781
|
+
* Create or replace one private data entry. `value` is any JSON, up to
|
|
1782
|
+
* the server's `userDataValueBytes` (`server.limits()`, 5 MB by
|
|
1783
|
+
* default), and is refused with 413 over it, after which
|
|
1784
|
+
* `server.limits()` answers the figure the server has now. Not audited,
|
|
1785
|
+
* not batchable.
|
|
1489
1786
|
*
|
|
1490
1787
|
* The server stores it verbatim, but this client recases object keys on
|
|
1491
1788
|
* the way out and back like any other body (`myKey` <-> `my-key`), so a
|
|
1492
1789
|
* value whose keys are camelCase round-trips unchanged while one keyed
|
|
1493
1790
|
* by arbitrary strings does not. Put such a map under a `metadata` key,
|
|
1494
1791
|
* which both clients pass through untouched.
|
|
1792
|
+
*
|
|
1793
|
+
* Every write raises the entry's `version` by one, and reads answer it.
|
|
1794
|
+
* With `version`, the write lands only when the entry is still at that
|
|
1795
|
+
* version (0: only when there is no entry), and is otherwise refused with
|
|
1796
|
+
* 409, `error: "version-mismatch"`, and the stored `version` and
|
|
1797
|
+
* `updatedAt` on the error's `responseData`: read it again and make the
|
|
1798
|
+
* change on what is there.
|
|
1495
1799
|
* @param {string} userId
|
|
1496
1800
|
* @param {string} key
|
|
1497
1801
|
* @param {*} value
|
|
1802
|
+
* @param {object} [opts]
|
|
1803
|
+
* @param {number} [opts.version] - The version this write was made from
|
|
1804
|
+
* @returns {Promise<{key: string, updatedAt: string, version: number}>}
|
|
1498
1805
|
*/
|
|
1499
|
-
put: (userId, key, value) =>
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1806
|
+
put: async (userId, key, value, { version } = {}) => {
|
|
1807
|
+
try {
|
|
1808
|
+
return await this._request(
|
|
1809
|
+
"PUT",
|
|
1810
|
+
`/api/v1/users/${userId}/data/${encodeURIComponent(key)}`,
|
|
1811
|
+
{
|
|
1812
|
+
body: value,
|
|
1813
|
+
noBatch: true,
|
|
1814
|
+
queryParams: { version },
|
|
1815
|
+
},
|
|
1816
|
+
);
|
|
1817
|
+
} catch (err) {
|
|
1818
|
+
if (err?.status === 413) {
|
|
1819
|
+
// The cap may have changed since it was read: the caller deciding
|
|
1820
|
+
// what to do next reads the server's figure now.
|
|
1821
|
+
await this.server.refresh().catch(() => {});
|
|
1822
|
+
}
|
|
1823
|
+
throw err;
|
|
1824
|
+
}
|
|
1825
|
+
},
|
|
1508
1826
|
/**
|
|
1509
1827
|
* Delete one private data entry; 404 if absent.
|
|
1510
1828
|
* @param {string} userId
|
|
@@ -1556,6 +1874,7 @@ class PlaidClient {
|
|
|
1556
1874
|
* needs a sign-in token.
|
|
1557
1875
|
* @param {string} userId - The user ID who will own the token
|
|
1558
1876
|
* @param {string} name - A human label, e.g. "Stanza parser"
|
|
1877
|
+
* @param {string} [auditMessage] - Audit message for this write
|
|
1559
1878
|
* @returns {Promise<{id: string, name: string, token: string}>}
|
|
1560
1879
|
*/
|
|
1561
1880
|
create: (userId, name, auditMessage) =>
|
|
@@ -1572,6 +1891,7 @@ class PlaidClient {
|
|
|
1572
1891
|
* needs a sign-in token.
|
|
1573
1892
|
* @param {string} userId - The user ID who owns the token
|
|
1574
1893
|
* @param {string} tokenId - The token ID to revoke
|
|
1894
|
+
* @param {string} [auditMessage] - Audit message for this write
|
|
1575
1895
|
*/
|
|
1576
1896
|
revoke: (userId, tokenId, auditMessage) =>
|
|
1577
1897
|
this._request("DELETE", `/api/v1/users/${userId}/tokens/${tokenId}`, {
|
|
@@ -1589,6 +1909,7 @@ class PlaidClient {
|
|
|
1589
1909
|
* @param {object} [opts]
|
|
1590
1910
|
* @param {string} [opts.projectId] - List this project's invites instead of your own
|
|
1591
1911
|
* @param {boolean} [opts.all] - List every invite on the server (admin only)
|
|
1912
|
+
* @returns {Promise<Invite[]>}
|
|
1592
1913
|
*/
|
|
1593
1914
|
list: ({ projectId, all } = {}) =>
|
|
1594
1915
|
listAll(this, "/api/v1/invites", {
|
|
@@ -1601,7 +1922,7 @@ class PlaidClient {
|
|
|
1601
1922
|
* @param {boolean} [opts.all] - List every invite on the server (admin only)
|
|
1602
1923
|
* @param {number} [opts.limit] - Page size (1..1000; server default 100)
|
|
1603
1924
|
* @param {string} [opts.cursor] - Opaque cursor from a previous page
|
|
1604
|
-
* @returns {Promise<
|
|
1925
|
+
* @returns {Promise<Page<Invite>>}
|
|
1605
1926
|
*/
|
|
1606
1927
|
listPage: ({ projectId, all, limit, cursor } = {}) =>
|
|
1607
1928
|
listPage(this, "/api/v1/invites", {
|
|
@@ -1615,7 +1936,7 @@ class PlaidClient {
|
|
|
1615
1936
|
* @param {string} [opts.projectId] - List this project's invites instead of your own
|
|
1616
1937
|
* @param {boolean} [opts.all] - List every invite on the server (admin only)
|
|
1617
1938
|
* @param {number} [opts.pageSize] - Per-request page size
|
|
1618
|
-
* @returns {AsyncGenerator<
|
|
1939
|
+
* @returns {AsyncGenerator<Invite[]>}
|
|
1619
1940
|
*/
|
|
1620
1941
|
iterPages: ({ projectId, all, pageSize } = {}) =>
|
|
1621
1942
|
iterPages(this, "/api/v1/invites", {
|
|
@@ -1648,7 +1969,8 @@ class PlaidClient {
|
|
|
1648
1969
|
* @param {number} [opts.maxUses] - How many accounts this link may create (default 1)
|
|
1649
1970
|
* @param {number} [opts.ttlDays] - Days until it expires (default 14, max 365)
|
|
1650
1971
|
* @param {string} [opts.note] - Human label shown in your invite list
|
|
1651
|
-
* @
|
|
1972
|
+
* @param {string} [auditMessage] - Audit message for this write
|
|
1973
|
+
* @returns {Promise<Invite & {code: string}>}
|
|
1652
1974
|
*/
|
|
1653
1975
|
create: (
|
|
1654
1976
|
{
|
|
@@ -1681,6 +2003,7 @@ class PlaidClient {
|
|
|
1681
2003
|
* Revoke an invite, killing the link immediately. Idempotent. Allowed for
|
|
1682
2004
|
* the creator, an admin, or a maintainer of the invite's project.
|
|
1683
2005
|
* @param {string} id - The invite ID
|
|
2006
|
+
* @param {string} [auditMessage] - Audit message for this write
|
|
1684
2007
|
*/
|
|
1685
2008
|
revoke: (id, auditMessage) =>
|
|
1686
2009
|
this._request("DELETE", `/api/v1/invites/${id}`, { auditMessage }),
|
|
@@ -1693,7 +2016,7 @@ class PlaidClient {
|
|
|
1693
2016
|
* configuration and the backups on disk, and the settings an operator
|
|
1694
2017
|
* gets asked to confirm. Carries no secrets. Runs a count per table and
|
|
1695
2018
|
* walks the media directory, so open it, do not poll it. Admin only.
|
|
1696
|
-
* @returns {Promise<
|
|
2019
|
+
* @returns {Promise<ServerReport>}
|
|
1697
2020
|
*/
|
|
1698
2021
|
server: () => this._request("GET", "/api/v1/admin/server"),
|
|
1699
2022
|
/**
|
|
@@ -1707,7 +2030,7 @@ class PlaidClient {
|
|
|
1707
2030
|
* rather than the client's usual timeout. A proxy in front of the server
|
|
1708
2031
|
* may still give up first (a 504): the backup goes on, and its file
|
|
1709
2032
|
* shows in `server().backup.backups` once it is written.
|
|
1710
|
-
* @returns {Promise<
|
|
2033
|
+
* @returns {Promise<BackupStatus>}
|
|
1711
2034
|
*
|
|
1712
2035
|
* outOfBand, as every admin action on the server itself is: none of them
|
|
1713
2036
|
* writes project data (see the note at the top of http.js).
|
|
@@ -1727,6 +2050,7 @@ class PlaidClient {
|
|
|
1727
2050
|
* Drop the lock on a document whoever holds it. Idempotent. For a client
|
|
1728
2051
|
* that went away without releasing one. Admin only.
|
|
1729
2052
|
* @param {string} documentId - The document ID
|
|
2053
|
+
* @returns {Promise<{result: string}>}
|
|
1730
2054
|
*/
|
|
1731
2055
|
releaseLock: (documentId) =>
|
|
1732
2056
|
this._request("DELETE", `/api/v1/admin/locks/${documentId}`, {
|
|
@@ -1736,7 +2060,7 @@ class PlaidClient {
|
|
|
1736
2060
|
* Live login and invite rate-limit buckets: the address, the account
|
|
1737
2061
|
* where there is one, failures inside the window, the limit, and whether
|
|
1738
2062
|
* it is currently blocking. Admin only.
|
|
1739
|
-
* @returns {Promise<
|
|
2063
|
+
* @returns {Promise<RateLimitSnapshot>}
|
|
1740
2064
|
*/
|
|
1741
2065
|
rateLimits: () => this._request("GET", "/api/v1/admin/rate-limits"),
|
|
1742
2066
|
/**
|
|
@@ -1746,6 +2070,7 @@ class PlaidClient {
|
|
|
1746
2070
|
* @param {object} [opts]
|
|
1747
2071
|
* @param {string} [opts.ip] - Clear only this address
|
|
1748
2072
|
* @param {string} [opts.userId] - Narrow to one account on that address
|
|
2073
|
+
* @returns {Promise<{result: string}>}
|
|
1749
2074
|
*/
|
|
1750
2075
|
clearRateLimits: ({ ip, userId } = {}) =>
|
|
1751
2076
|
this._request("DELETE", "/api/v1/admin/rate-limits", {
|
|
@@ -1769,7 +2094,7 @@ class PlaidClient {
|
|
|
1769
2094
|
* @param {string} [opts.status] - "2xx".."5xx", an exact code, or "failures"
|
|
1770
2095
|
* @param {string} [opts.user] - Only requests made by this account
|
|
1771
2096
|
* @param {string} [opts.method] - Only requests with this HTTP method
|
|
1772
|
-
* @returns {Promise<
|
|
2097
|
+
* @returns {Promise<LiveLog>}
|
|
1773
2098
|
*/
|
|
1774
2099
|
logs: ({ limit, q, level, status, user, method } = {}) =>
|
|
1775
2100
|
this._request("GET", "/api/v1/admin/logs", {
|
|
@@ -1803,7 +2128,7 @@ class PlaidClient {
|
|
|
1803
2128
|
* @param {string} [opts.prefix] - Only keys starting with this
|
|
1804
2129
|
* @param {string} [opts.pattern] - Only keys matching this GLOB
|
|
1805
2130
|
* @param {boolean} [opts.includeValues] - Also return each entry's value
|
|
1806
|
-
* @returns {Promise<
|
|
2131
|
+
* @returns {Promise<AdminUserDataEntry[]>}
|
|
1807
2132
|
*/
|
|
1808
2133
|
userData: ({ prefix, pattern, includeValues } = {}) =>
|
|
1809
2134
|
listAll(this, "/api/v1/admin/user-data", {
|
|
@@ -1822,7 +2147,7 @@ class PlaidClient {
|
|
|
1822
2147
|
* @param {boolean} [opts.includeValues] - Also return each entry's value
|
|
1823
2148
|
* @param {number} [opts.limit] - Page size (1..1000; server default 100)
|
|
1824
2149
|
* @param {string} [opts.cursor] - Opaque cursor from a previous page
|
|
1825
|
-
* @returns {Promise<
|
|
2150
|
+
* @returns {Promise<Page<AdminUserDataEntry>>}
|
|
1826
2151
|
*/
|
|
1827
2152
|
userDataPage: ({ prefix, pattern, includeValues, limit, cursor } = {}) =>
|
|
1828
2153
|
listPage(this, "/api/v1/admin/user-data", {
|
|
@@ -1863,6 +2188,10 @@ class PlaidClient {
|
|
|
1863
2188
|
/**
|
|
1864
2189
|
* Fetch a single page of the instance-wide audit log. Admin only.
|
|
1865
2190
|
* @param {object} [opts]
|
|
2191
|
+
* @param {string} [opts.startTime] - Only entries at or after this instant
|
|
2192
|
+
* @param {string} [opts.endTime] - Only entries at or before this instant
|
|
2193
|
+
* @param {string[]|string} [opts.opTypes] - Only these op types
|
|
2194
|
+
* @param {OperationKind[]|string} [opts.kinds] - Only the entries of operations of these kinds, each whole
|
|
1866
2195
|
* @param {"asc"|"desc"} [opts.order] - "desc" pages newest-first, which
|
|
1867
2196
|
* is what a feed wants. A cursor belongs to the direction that made it.
|
|
1868
2197
|
* @param {number} [opts.limit] - Page size (1..1000; server default 100)
|
|
@@ -1889,6 +2218,12 @@ class PlaidClient {
|
|
|
1889
2218
|
}),
|
|
1890
2219
|
/**
|
|
1891
2220
|
* Async-iterate the instance-wide audit log page by page. Admin only.
|
|
2221
|
+
* @param {object} [opts]
|
|
2222
|
+
* @param {string} [opts.startTime] - Only entries at or after this instant
|
|
2223
|
+
* @param {string} [opts.endTime] - Only entries at or before this instant
|
|
2224
|
+
* @param {string[]|string} [opts.opTypes] - Only these op types
|
|
2225
|
+
* @param {OperationKind[]|string} [opts.kinds] - Only the entries of operations of these kinds, each whole
|
|
2226
|
+
* @param {number} [opts.pageSize] - Per-request page size
|
|
1892
2227
|
* @returns {AsyncGenerator<Array>}
|
|
1893
2228
|
*/
|
|
1894
2229
|
iterPages: ({ startTime, endTime, opTypes, kinds, pageSize } = {}) =>
|
|
@@ -1917,7 +2252,7 @@ class PlaidClient {
|
|
|
1917
2252
|
* @param {boolean} [opts.daily] - Also return `byDay`, a list of
|
|
1918
2253
|
* `{date, changes}` per user, oldest first, at the cost of a second
|
|
1919
2254
|
* grouped scan
|
|
1920
|
-
* @returns {Promise<
|
|
2255
|
+
* @returns {Promise<ActivityTallyRow[]>}
|
|
1921
2256
|
*/
|
|
1922
2257
|
tally: async ({ projectId, startTime, endTime, daily } = {}) => {
|
|
1923
2258
|
const path = projectId
|
|
@@ -1935,22 +2270,16 @@ class PlaidClient {
|
|
|
1935
2270
|
};
|
|
1936
2271
|
|
|
1937
2272
|
this.tokenLayers = {
|
|
1938
|
-
|
|
1939
|
-
* Shift a token layer's display order.
|
|
1940
|
-
* @param {string} tokenLayerId - The token layer ID
|
|
1941
|
-
* @param {string} direction - The direction ("up" or "down")
|
|
1942
|
-
*/
|
|
1943
|
-
shift: (tokenLayerId, direction, auditMessage) =>
|
|
1944
|
-
this._request("POST", `/api/v1/token-layers/${tokenLayerId}/shift`, {
|
|
1945
|
-
auditMessage,
|
|
1946
|
-
body: bodyOf({ direction }),
|
|
1947
|
-
}),
|
|
2273
|
+
...layerMethods(this, "token-layers"),
|
|
1948
2274
|
/**
|
|
1949
2275
|
* Create a new token layer.
|
|
1950
2276
|
* @param {string} textLayerId - The text layer ID
|
|
1951
2277
|
* @param {string} name - The name
|
|
1952
2278
|
* @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.
|
|
1953
2279
|
* @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).
|
|
2280
|
+
* @param {string} [auditMessage] - Audit message for this write
|
|
2281
|
+
* @param {object} [opts]
|
|
2282
|
+
* @param {string} [opts.id] - The new entity's id, minted by the caller (see uuidv7)
|
|
1954
2283
|
*/
|
|
1955
2284
|
create: (
|
|
1956
2285
|
textLayerId,
|
|
@@ -1960,71 +2289,18 @@ class PlaidClient {
|
|
|
1960
2289
|
auditMessage,
|
|
1961
2290
|
{ id } = {},
|
|
1962
2291
|
) =>
|
|
1963
|
-
this._request("POST", "/api/v1/token-layers", {
|
|
1964
|
-
auditMessage,
|
|
1965
|
-
body: bodyOf({
|
|
1966
|
-
id,
|
|
1967
|
-
"text-layer-id": textLayerId,
|
|
1968
|
-
name,
|
|
1969
|
-
"overlap-mode": overlapMode,
|
|
1970
|
-
"parent-token-layer-id": parentTokenLayerId,
|
|
1971
|
-
}),
|
|
1972
|
-
}),
|
|
1973
|
-
/**
|
|
1974
|
-
* Set a configuration value for a layer in an editor namespace.
|
|
1975
|
-
* @param {string} tokenLayerId - The token layer ID
|
|
1976
|
-
* @param {string} namespace - The config namespace
|
|
1977
|
-
* @param {string} configKey - The config key
|
|
1978
|
-
* @param {any} configValue - Configuration value to set
|
|
1979
|
-
* @param {string} [auditMessage] - Audit message for this write
|
|
1980
|
-
* @param {{expected?: any}} [options] - `expected`: the value read for this key (null or undefined when it
|
|
1981
|
-
* was absent). The write is then refused with a 409 when the stored value differs.
|
|
1982
|
-
*/
|
|
1983
|
-
setConfig: (tokenLayerId, namespace, configKey, configValue, auditMessage, options) =>
|
|
1984
|
-
this._request(
|
|
1985
|
-
"PUT",
|
|
1986
|
-
`/api/v1/token-layers/${tokenLayerId}/config/${namespace}/${configKey}`,
|
|
1987
|
-
configRequest(auditMessage, configValue, options),
|
|
1988
|
-
),
|
|
1989
|
-
/**
|
|
1990
|
-
* Remove a configuration value for a layer.
|
|
1991
|
-
* @param {string} tokenLayerId - The token layer ID
|
|
1992
|
-
* @param {string} namespace - The config namespace
|
|
1993
|
-
* @param {string} configKey - The config key
|
|
1994
|
-
* @param {string} [auditMessage] - Audit message for this write
|
|
1995
|
-
* @param {{expected?: any}} [options] - `expected`, as on setConfig.
|
|
1996
|
-
*/
|
|
1997
|
-
deleteConfig: (tokenLayerId, namespace, configKey, auditMessage, options) =>
|
|
1998
|
-
this._request(
|
|
1999
|
-
"DELETE",
|
|
2000
|
-
`/api/v1/token-layers/${tokenLayerId}/config/${namespace}/${configKey}`,
|
|
2001
|
-
configRequest(auditMessage, undefined, options, true),
|
|
2002
|
-
),
|
|
2003
|
-
...constraintMethods(this, "token-layers"),
|
|
2004
|
-
/**
|
|
2005
|
-
* Get a token layer by ID.
|
|
2006
|
-
* @param {string} tokenLayerId - The token layer ID
|
|
2007
|
-
*/
|
|
2008
|
-
get: (tokenLayerId) =>
|
|
2009
|
-
this._request("GET", `/api/v1/token-layers/${tokenLayerId}`),
|
|
2010
|
-
/**
|
|
2011
|
-
* Delete a token layer.
|
|
2012
|
-
* @param {string} tokenLayerId - The token layer ID
|
|
2013
|
-
*/
|
|
2014
|
-
delete: (tokenLayerId, auditMessage) =>
|
|
2015
|
-
this._request("DELETE", `/api/v1/token-layers/${tokenLayerId}`, {
|
|
2016
|
-
auditMessage,
|
|
2017
|
-
}),
|
|
2018
|
-
/**
|
|
2019
|
-
* Update a token layer's name.
|
|
2020
|
-
* @param {string} tokenLayerId - The token layer ID
|
|
2021
|
-
* @param {string} name - The name
|
|
2022
|
-
*/
|
|
2023
|
-
update: (tokenLayerId, name, auditMessage) =>
|
|
2024
|
-
this._request("PATCH", `/api/v1/token-layers/${tokenLayerId}`, {
|
|
2292
|
+
this._request("POST", "/api/v1/token-layers", {
|
|
2025
2293
|
auditMessage,
|
|
2026
|
-
body: bodyOf({
|
|
2294
|
+
body: bodyOf({
|
|
2295
|
+
id,
|
|
2296
|
+
"text-layer-id": textLayerId,
|
|
2297
|
+
name,
|
|
2298
|
+
"overlap-mode": overlapMode,
|
|
2299
|
+
"parent-token-layer-id": parentTokenLayerId,
|
|
2300
|
+
}),
|
|
2027
2301
|
}),
|
|
2302
|
+
...configMethods(this, "token-layers"),
|
|
2303
|
+
...constraintMethods(this, "token-layers"),
|
|
2028
2304
|
};
|
|
2029
2305
|
|
|
2030
2306
|
this.documents = {
|
|
@@ -2071,6 +2347,7 @@ class PlaidClient {
|
|
|
2071
2347
|
* outOfBand, for the same reason as acquireLock.
|
|
2072
2348
|
* @param {string} documentId - The document ID
|
|
2073
2349
|
* @param {string} lockId - The `lockId` acquireLock answered with
|
|
2350
|
+
* @param {string} [auditMessage] - Audit message for this write
|
|
2074
2351
|
*/
|
|
2075
2352
|
renewLock: (documentId, lockId, auditMessage) =>
|
|
2076
2353
|
this._request("POST", `/api/v1/documents/${documentId}/lock`, {
|
|
@@ -2085,6 +2362,7 @@ class PlaidClient {
|
|
|
2085
2362
|
* and not released at all if it aborts.
|
|
2086
2363
|
* @param {string} documentId - The document ID
|
|
2087
2364
|
* @param {string} lockId - The `lockId` acquireLock answered with
|
|
2365
|
+
* @param {string} [auditMessage] - Audit message for this write
|
|
2088
2366
|
*/
|
|
2089
2367
|
releaseLock: (documentId, lockId, auditMessage) =>
|
|
2090
2368
|
this._request("DELETE", `/api/v1/documents/${documentId}/lock`, {
|
|
@@ -2128,9 +2406,11 @@ class PlaidClient {
|
|
|
2128
2406
|
* lost lock is recorded on the CLIENT, like strict mode, so it stops
|
|
2129
2407
|
* every write the client makes (on any batch of it too) and not only the
|
|
2130
2408
|
* ones this block makes.
|
|
2409
|
+
* @template T
|
|
2131
2410
|
* @param {string} documentId - The document ID
|
|
2132
|
-
* @param {(lock: DocumentLock) =>
|
|
2133
|
-
* @param {
|
|
2411
|
+
* @param {(lock: import("./documentLock.js").DocumentLock) => T | Promise<T>} fn - The work to run while holding it
|
|
2412
|
+
* @param {{keepAlive?: boolean}} [options] - `{ keepAlive }`: renew on a timer (default true)
|
|
2413
|
+
* @returns {Promise<T>}
|
|
2134
2414
|
*/
|
|
2135
2415
|
locked: (documentId, fn, options) =>
|
|
2136
2416
|
withDocumentLock(this, documentId, fn, options),
|
|
@@ -2139,22 +2419,45 @@ class PlaidClient {
|
|
|
2139
2419
|
* no as-of form: the route refuses the parameter. Prefer the document's
|
|
2140
2420
|
* own `mediaUrl`, which carries the file's version for caching.
|
|
2141
2421
|
* @param {string} documentId - The document ID
|
|
2422
|
+
* @returns {Promise<ArrayBuffer>}
|
|
2142
2423
|
*/
|
|
2143
2424
|
getMedia: (documentId) =>
|
|
2144
2425
|
this._request("GET", `/api/v1/documents/${documentId}/media`, {
|
|
2145
2426
|
binaryResponse: true,
|
|
2146
2427
|
}),
|
|
2428
|
+
/**
|
|
2429
|
+
* Get a link that plays the document's recording without an
|
|
2430
|
+
* Authorization header, for an audio or video element's `src`, which
|
|
2431
|
+
* cannot send one. `url` is the document's media URL with a
|
|
2432
|
+
* `media-token` added, resolved against the client's base URL. The token
|
|
2433
|
+
* opens only this recording, for this user, and the server refuses it on
|
|
2434
|
+
* every other route. It expires at `expiresAt` (an ISO-8601 instant, six
|
|
2435
|
+
* hours on by default), and sooner when the user signs out, changes
|
|
2436
|
+
* password or loses access to the project: ask for a new link then. A
|
|
2437
|
+
* document with no recording is a 404. Writes nothing, so it takes no
|
|
2438
|
+
* Idempotency-Key and goes over the wire when made on a batch.
|
|
2439
|
+
* @param {string} documentId - The document ID
|
|
2440
|
+
* @returns {Promise<{url: string, expiresAt: string}>}
|
|
2441
|
+
*/
|
|
2442
|
+
mediaLink: async (documentId) => {
|
|
2443
|
+
const link = await this._request(
|
|
2444
|
+
"POST",
|
|
2445
|
+
`/api/v1/documents/${documentId}/media/link`,
|
|
2446
|
+
{ outOfBand: true },
|
|
2447
|
+
);
|
|
2448
|
+
return { ...link, url: `${this.baseUrl}${link.url}` };
|
|
2449
|
+
},
|
|
2147
2450
|
/**
|
|
2148
2451
|
* Upload a media file for a document. Uses Apache Tika for content validation.
|
|
2149
2452
|
* A document that already has a recording refuses it with a 409
|
|
2150
2453
|
* (`media-exists`, and the current `media-url`): delete that one first.
|
|
2151
|
-
* A WAV whose samples are not PCM
|
|
2152
|
-
* and the rest), which browsers cannot play,
|
|
2153
|
-
* whose `error` names its coding.
|
|
2454
|
+
* A WAV whose samples are not PCM, 32-bit float, A-law or mu-law (IMA or
|
|
2455
|
+
* MS ADPCM, GSM, 64-bit float and the rest), which browsers cannot play,
|
|
2456
|
+
* is refused with a 415 whose `error` names its coding.
|
|
2154
2457
|
* @param {string} documentId - The document ID
|
|
2155
2458
|
* @param {File} file - The file to upload
|
|
2156
2459
|
* @param {string} [auditMessage] - Custom audit-log message for this write
|
|
2157
|
-
* @param {
|
|
2460
|
+
* @param {{onProgress?: (progress: {loaded: number, total: number | null}) => void}} [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.
|
|
2158
2461
|
*/
|
|
2159
2462
|
uploadMedia: (documentId, file, auditMessage, { onProgress } = {}) => {
|
|
2160
2463
|
const fd = new FormData();
|
|
@@ -2186,37 +2489,14 @@ class PlaidClient {
|
|
|
2186
2489
|
auditMessage,
|
|
2187
2490
|
queryParams: { "media-version": mediaVersion },
|
|
2188
2491
|
}),
|
|
2189
|
-
|
|
2190
|
-
* Replace all metadata for a document.
|
|
2191
|
-
* @param {string} documentId - The document ID
|
|
2192
|
-
* @param {any} body - The request body
|
|
2193
|
-
*/
|
|
2194
|
-
setMetadata: (documentId, body, auditMessage) =>
|
|
2195
|
-
this._request("PUT", `/api/v1/documents/${documentId}/metadata`, {
|
|
2196
|
-
auditMessage,
|
|
2197
|
-
rawBody: body,
|
|
2198
|
-
}),
|
|
2199
|
-
/**
|
|
2200
|
-
* Remove all metadata from a document.
|
|
2201
|
-
* @param {string} documentId - The document ID
|
|
2202
|
-
*/
|
|
2203
|
-
deleteMetadata: (documentId, auditMessage) =>
|
|
2204
|
-
this._request("DELETE", `/api/v1/documents/${documentId}/metadata`, {
|
|
2205
|
-
auditMessage,
|
|
2206
|
-
}),
|
|
2207
|
-
/**
|
|
2208
|
-
* Edit metadata for a document with a list of ops applied in order, in one operation. `{op: 'set', path, value}` writes value at path, creating missing objects along it; `{op: 'delete', path}` removes the key at path (a no-op when absent). A path is a non-empty array of keys, the first a top-level key. A path through a non-object is refused (400). See metadataOps and applyMetadataOps.
|
|
2209
|
-
* @param {string} documentId - The document ID
|
|
2210
|
-
* @param {Array<{op: string, path: string[], value?: any}>} body - The metadata ops
|
|
2211
|
-
*/
|
|
2212
|
-
patchMetadata: (documentId, body, auditMessage) =>
|
|
2213
|
-
this._request("PATCH", `/api/v1/documents/${documentId}/metadata`, {
|
|
2214
|
-
auditMessage,
|
|
2215
|
-
rawBody: body,
|
|
2216
|
-
}),
|
|
2492
|
+
...metadataMethods(this, "documents"),
|
|
2217
2493
|
/**
|
|
2218
2494
|
* Get audit log for a document. Transparently follows pagination cursors
|
|
2219
|
-
* and returns the full flat array.
|
|
2495
|
+
* and returns the full flat array. Each entry, and each of its `ops`,
|
|
2496
|
+
* says what kind of credential made it as `credential`: `login`,
|
|
2497
|
+
* `named-token` or `delegated` (absent on older operations, `service`
|
|
2498
|
+
* on some from 2026-10-06 to 2026-10-08),
|
|
2499
|
+
* beside `apiToken` (the named token's id and name) when there was one.
|
|
2220
2500
|
* @param {string} documentId - The document ID
|
|
2221
2501
|
* @param {string} [startTime] - Start of time range
|
|
2222
2502
|
* @param {string} [endTime] - End of time range
|
|
@@ -2242,6 +2522,10 @@ class PlaidClient {
|
|
|
2242
2522
|
* that may be long: audit() walks every page before it resolves.
|
|
2243
2523
|
* @param {string} documentId - The document ID
|
|
2244
2524
|
* @param {object} [opts]
|
|
2525
|
+
* @param {string} [opts.startTime] - Only entries at or after this instant
|
|
2526
|
+
* @param {string} [opts.endTime] - Only entries at or before this instant
|
|
2527
|
+
* @param {string[]|string} [opts.opTypes] - Only these op types
|
|
2528
|
+
* @param {OperationKind[]|string} [opts.kinds] - Only the entries of operations of these kinds, each whole
|
|
2245
2529
|
* @param {"asc"|"desc"} [opts.order] - "desc" pages newest-first
|
|
2246
2530
|
* @param {number} [opts.limit] - Page size (1..1000; server default 100)
|
|
2247
2531
|
* @param {string} [opts.cursor] - Opaque cursor from a previous page
|
|
@@ -2278,7 +2562,7 @@ class PlaidClient {
|
|
|
2278
2562
|
* @param {string} documentId - The document ID
|
|
2279
2563
|
* @param {string} asOf - The moment to go back to (ISO-8601 instant),
|
|
2280
2564
|
* typically a history entry's `endTime`
|
|
2281
|
-
* @param {
|
|
2565
|
+
* @param {{dryRun?: boolean}} [options] - `{ dryRun }`: with `dryRun` true nothing
|
|
2282
2566
|
* is written and the summary says what would change
|
|
2283
2567
|
* @param {string} [auditMessage] - Custom audit message for this operation
|
|
2284
2568
|
*/
|
|
@@ -2316,6 +2600,7 @@ class PlaidClient {
|
|
|
2316
2600
|
/**
|
|
2317
2601
|
* Delete a document and all data contained.
|
|
2318
2602
|
* @param {string} documentId - The document ID
|
|
2603
|
+
* @param {string} [auditMessage] - Audit message for this write
|
|
2319
2604
|
*/
|
|
2320
2605
|
delete: (documentId, auditMessage) =>
|
|
2321
2606
|
this._request("DELETE", `/api/v1/documents/${documentId}`, {
|
|
@@ -2325,6 +2610,7 @@ class PlaidClient {
|
|
|
2325
2610
|
* Update a document's name.
|
|
2326
2611
|
* @param {string} documentId - The document ID
|
|
2327
2612
|
* @param {string} name - The name
|
|
2613
|
+
* @param {string} [auditMessage] - Audit message for this write
|
|
2328
2614
|
*/
|
|
2329
2615
|
update: (documentId, name, auditMessage) =>
|
|
2330
2616
|
this._request("PATCH", `/api/v1/documents/${documentId}`, {
|
|
@@ -2336,6 +2622,9 @@ class PlaidClient {
|
|
|
2336
2622
|
* @param {string} projectId - The project ID
|
|
2337
2623
|
* @param {string} name - The name
|
|
2338
2624
|
* @param {any} [metadata] - Metadata map. Omit to leave unset; pass null to send JSON null.
|
|
2625
|
+
* @param {string} [auditMessage] - Audit message for this write
|
|
2626
|
+
* @param {object} [opts]
|
|
2627
|
+
* @param {string} [opts.id] - The new entity's id, minted by the caller (see uuidv7)
|
|
2339
2628
|
*/
|
|
2340
2629
|
create: (projectId, name, metadata, auditMessage, { id } = {}) =>
|
|
2341
2630
|
this._request("POST", "/api/v1/documents", {
|
|
@@ -2352,9 +2641,10 @@ class PlaidClient {
|
|
|
2352
2641
|
* the source had media the copy could not take with it.
|
|
2353
2642
|
* @param {string} documentId - The document to copy
|
|
2354
2643
|
* @param {string} name - The new document's name
|
|
2355
|
-
* @param {
|
|
2644
|
+
* @param {{includeMedia?: boolean, id?: string}} [options] - `{ includeMedia }`: false leaves the media
|
|
2356
2645
|
* file behind
|
|
2357
2646
|
* @param {string} [auditMessage] - Custom audit message for this operation
|
|
2647
|
+
* @returns {Promise<{id: string, mediaError?: string}>}
|
|
2358
2648
|
*/
|
|
2359
2649
|
copy: (documentId, name, { includeMedia, id } = {}, auditMessage) =>
|
|
2360
2650
|
this._request("POST", `/api/v1/documents/${documentId}/copy`, {
|
|
@@ -2368,6 +2658,7 @@ class PlaidClient {
|
|
|
2368
2658
|
* Set a user's access level to read and write for this project.
|
|
2369
2659
|
* @param {string} id - The resource ID
|
|
2370
2660
|
* @param {string} userId - The user ID
|
|
2661
|
+
* @param {string} [auditMessage] - Audit message for this write
|
|
2371
2662
|
*/
|
|
2372
2663
|
addWriter: (id, userId, auditMessage) =>
|
|
2373
2664
|
this._request("POST", `/api/v1/projects/${id}/writers/${userId}`, {
|
|
@@ -2377,6 +2668,7 @@ class PlaidClient {
|
|
|
2377
2668
|
* Remove a user's writer privileges for this project.
|
|
2378
2669
|
* @param {string} id - The resource ID
|
|
2379
2670
|
* @param {string} userId - The user ID
|
|
2671
|
+
* @param {string} [auditMessage] - Audit message for this write
|
|
2380
2672
|
*/
|
|
2381
2673
|
removeWriter: (id, userId, auditMessage) =>
|
|
2382
2674
|
this._request("DELETE", `/api/v1/projects/${id}/writers/${userId}`, {
|
|
@@ -2386,6 +2678,7 @@ class PlaidClient {
|
|
|
2386
2678
|
* Set a user's access level to read-only for this project.
|
|
2387
2679
|
* @param {string} id - The resource ID
|
|
2388
2680
|
* @param {string} userId - The user ID
|
|
2681
|
+
* @param {string} [auditMessage] - Audit message for this write
|
|
2389
2682
|
*/
|
|
2390
2683
|
addReader: (id, userId, auditMessage) =>
|
|
2391
2684
|
this._request("POST", `/api/v1/projects/${id}/readers/${userId}`, {
|
|
@@ -2395,45 +2688,18 @@ class PlaidClient {
|
|
|
2395
2688
|
* Remove a user's reader privileges for this project.
|
|
2396
2689
|
* @param {string} id - The resource ID
|
|
2397
2690
|
* @param {string} userId - The user ID
|
|
2691
|
+
* @param {string} [auditMessage] - Audit message for this write
|
|
2398
2692
|
*/
|
|
2399
2693
|
removeReader: (id, userId, auditMessage) =>
|
|
2400
2694
|
this._request("DELETE", `/api/v1/projects/${id}/readers/${userId}`, {
|
|
2401
2695
|
auditMessage,
|
|
2402
2696
|
}),
|
|
2403
|
-
|
|
2404
|
-
* Set a configuration value for a project in an editor namespace.
|
|
2405
|
-
* @param {string} id - The resource ID
|
|
2406
|
-
* @param {string} namespace - The config namespace
|
|
2407
|
-
* @param {string} configKey - The config key
|
|
2408
|
-
* @param {any} configValue - Configuration value to set
|
|
2409
|
-
* @param {string} [auditMessage] - Audit message for this write
|
|
2410
|
-
* @param {{expected?: any}} [options] - `expected`: the value read for this key (null or undefined when it
|
|
2411
|
-
* was absent). The write is then refused with a 409 when the stored value differs.
|
|
2412
|
-
*/
|
|
2413
|
-
setConfig: (id, namespace, configKey, configValue, auditMessage, options) =>
|
|
2414
|
-
this._request(
|
|
2415
|
-
"PUT",
|
|
2416
|
-
`/api/v1/projects/${id}/config/${namespace}/${configKey}`,
|
|
2417
|
-
configRequest(auditMessage, configValue, options),
|
|
2418
|
-
),
|
|
2419
|
-
/**
|
|
2420
|
-
* Remove a configuration value for a project.
|
|
2421
|
-
* @param {string} id - The resource ID
|
|
2422
|
-
* @param {string} namespace - The config namespace
|
|
2423
|
-
* @param {string} configKey - The config key
|
|
2424
|
-
* @param {string} [auditMessage] - Audit message for this write
|
|
2425
|
-
* @param {{expected?: any}} [options] - `expected`, as on setConfig.
|
|
2426
|
-
*/
|
|
2427
|
-
deleteConfig: (id, namespace, configKey, auditMessage, options) =>
|
|
2428
|
-
this._request(
|
|
2429
|
-
"DELETE",
|
|
2430
|
-
`/api/v1/projects/${id}/config/${namespace}/${configKey}`,
|
|
2431
|
-
configRequest(auditMessage, undefined, options, true),
|
|
2432
|
-
),
|
|
2697
|
+
...configMethods(this, "projects"),
|
|
2433
2698
|
/**
|
|
2434
2699
|
* Assign a user as a maintainer for this project.
|
|
2435
2700
|
* @param {string} id - The resource ID
|
|
2436
2701
|
* @param {string} userId - The user ID
|
|
2702
|
+
* @param {string} [auditMessage] - Audit message for this write
|
|
2437
2703
|
*/
|
|
2438
2704
|
addMaintainer: (id, userId, auditMessage) =>
|
|
2439
2705
|
this._request("POST", `/api/v1/projects/${id}/maintainers/${userId}`, {
|
|
@@ -2443,6 +2709,7 @@ class PlaidClient {
|
|
|
2443
2709
|
* Remove a user's maintainer privileges for this project.
|
|
2444
2710
|
* @param {string} id - The resource ID
|
|
2445
2711
|
* @param {string} userId - The user ID
|
|
2712
|
+
* @param {string} [auditMessage] - Audit message for this write
|
|
2446
2713
|
*/
|
|
2447
2714
|
removeMaintainer: (id, userId, auditMessage) =>
|
|
2448
2715
|
this._request(
|
|
@@ -2452,7 +2719,11 @@ class PlaidClient {
|
|
|
2452
2719
|
),
|
|
2453
2720
|
/**
|
|
2454
2721
|
* Get audit log for a project. Transparently follows pagination cursors
|
|
2455
|
-
* and returns the full flat array.
|
|
2722
|
+
* and returns the full flat array. Each entry, and each of its `ops`,
|
|
2723
|
+
* says what kind of credential made it as `credential`: `login`,
|
|
2724
|
+
* `named-token` or `delegated` (absent on older operations, `service`
|
|
2725
|
+
* on some from 2026-10-06 to 2026-10-08),
|
|
2726
|
+
* beside `apiToken` (the named token's id and name) when there was one.
|
|
2456
2727
|
* @param {string} projectId - The project ID
|
|
2457
2728
|
* @param {string} [startTime] - Start of time range
|
|
2458
2729
|
* @param {string} [endTime] - End of time range
|
|
@@ -2478,6 +2749,10 @@ class PlaidClient {
|
|
|
2478
2749
|
* that may be long: audit() walks every page before it resolves.
|
|
2479
2750
|
* @param {string} projectId - The project ID
|
|
2480
2751
|
* @param {object} [opts]
|
|
2752
|
+
* @param {string} [opts.startTime] - Only entries at or after this instant
|
|
2753
|
+
* @param {string} [opts.endTime] - Only entries at or before this instant
|
|
2754
|
+
* @param {string[]|string} [opts.opTypes] - Only these op types
|
|
2755
|
+
* @param {OperationKind[]|string} [opts.kinds] - Only the entries of operations of these kinds, each whole
|
|
2481
2756
|
* @param {"asc"|"desc"} [opts.order] - "desc" pages newest-first
|
|
2482
2757
|
* @param {number} [opts.limit] - Page size (1..1000; server default 100)
|
|
2483
2758
|
* @param {string} [opts.cursor] - Opaque cursor from a previous page
|
|
@@ -2522,6 +2797,7 @@ class PlaidClient {
|
|
|
2522
2797
|
* Link a vocabulary to a project.
|
|
2523
2798
|
* @param {string} id - The resource ID
|
|
2524
2799
|
* @param {string} vocabId - The vocab layer ID
|
|
2800
|
+
* @param {string} [auditMessage] - Audit message for this write
|
|
2525
2801
|
*/
|
|
2526
2802
|
linkVocab: (id, vocabId, auditMessage) =>
|
|
2527
2803
|
this._request("POST", `/api/v1/projects/${id}/vocabs/${vocabId}`, {
|
|
@@ -2531,6 +2807,7 @@ class PlaidClient {
|
|
|
2531
2807
|
* Unlink a vocabulary from a project.
|
|
2532
2808
|
* @param {string} id - The resource ID
|
|
2533
2809
|
* @param {string} vocabId - The vocab layer ID
|
|
2810
|
+
* @param {string} [auditMessage] - Audit message for this write
|
|
2534
2811
|
*/
|
|
2535
2812
|
unlinkVocab: (id, vocabId, auditMessage) =>
|
|
2536
2813
|
this._request("DELETE", `/api/v1/projects/${id}/vocabs/${vocabId}`, {
|
|
@@ -2596,6 +2873,7 @@ class PlaidClient {
|
|
|
2596
2873
|
* Update a project's name.
|
|
2597
2874
|
* @param {string} id - The resource ID
|
|
2598
2875
|
* @param {string} name - The name
|
|
2876
|
+
* @param {string} [auditMessage] - Audit message for this write
|
|
2599
2877
|
*/
|
|
2600
2878
|
update: (id, name, auditMessage) =>
|
|
2601
2879
|
this._request("PATCH", `/api/v1/projects/${id}`, {
|
|
@@ -2632,6 +2910,9 @@ class PlaidClient {
|
|
|
2632
2910
|
/**
|
|
2633
2911
|
* Create a new project. Note: this also registers the user as a maintainer.
|
|
2634
2912
|
* @param {string} name - The name
|
|
2913
|
+
* @param {string} [auditMessage] - Audit message for this write
|
|
2914
|
+
* @param {object} [opts]
|
|
2915
|
+
* @param {string} [opts.id] - The new entity's id, minted by the caller (see uuidv7)
|
|
2635
2916
|
*/
|
|
2636
2917
|
create: (name, auditMessage, { id } = {}) =>
|
|
2637
2918
|
this._request("POST", "/api/v1/projects", {
|
|
@@ -2641,74 +2922,15 @@ class PlaidClient {
|
|
|
2641
2922
|
};
|
|
2642
2923
|
|
|
2643
2924
|
this.textLayers = {
|
|
2644
|
-
|
|
2645
|
-
|
|
2646
|
-
* @param {string} textLayerId - The text layer ID
|
|
2647
|
-
* @param {string} namespace - The config namespace
|
|
2648
|
-
* @param {string} configKey - The config key
|
|
2649
|
-
* @param {any} configValue - Configuration value to set
|
|
2650
|
-
* @param {string} [auditMessage] - Audit message for this write
|
|
2651
|
-
* @param {{expected?: any}} [options] - `expected`: the value read for this key (null or undefined when it
|
|
2652
|
-
* was absent). The write is then refused with a 409 when the stored value differs.
|
|
2653
|
-
*/
|
|
2654
|
-
setConfig: (textLayerId, namespace, configKey, configValue, auditMessage, options) =>
|
|
2655
|
-
this._request(
|
|
2656
|
-
"PUT",
|
|
2657
|
-
`/api/v1/text-layers/${textLayerId}/config/${namespace}/${configKey}`,
|
|
2658
|
-
configRequest(auditMessage, configValue, options),
|
|
2659
|
-
),
|
|
2660
|
-
/**
|
|
2661
|
-
* Remove a configuration value for a layer.
|
|
2662
|
-
* @param {string} textLayerId - The text layer ID
|
|
2663
|
-
* @param {string} namespace - The config namespace
|
|
2664
|
-
* @param {string} configKey - The config key
|
|
2665
|
-
* @param {string} [auditMessage] - Audit message for this write
|
|
2666
|
-
* @param {{expected?: any}} [options] - `expected`, as on setConfig.
|
|
2667
|
-
*/
|
|
2668
|
-
deleteConfig: (textLayerId, namespace, configKey, auditMessage, options) =>
|
|
2669
|
-
this._request(
|
|
2670
|
-
"DELETE",
|
|
2671
|
-
`/api/v1/text-layers/${textLayerId}/config/${namespace}/${configKey}`,
|
|
2672
|
-
configRequest(auditMessage, undefined, options, true),
|
|
2673
|
-
),
|
|
2674
|
-
/**
|
|
2675
|
-
* Get a text layer by ID.
|
|
2676
|
-
* @param {string} textLayerId - The text layer ID
|
|
2677
|
-
*/
|
|
2678
|
-
get: (textLayerId) =>
|
|
2679
|
-
this._request("GET", `/api/v1/text-layers/${textLayerId}`),
|
|
2680
|
-
/**
|
|
2681
|
-
* Delete a text layer.
|
|
2682
|
-
* @param {string} textLayerId - The text layer ID
|
|
2683
|
-
*/
|
|
2684
|
-
delete: (textLayerId, auditMessage) =>
|
|
2685
|
-
this._request("DELETE", `/api/v1/text-layers/${textLayerId}`, {
|
|
2686
|
-
auditMessage,
|
|
2687
|
-
}),
|
|
2688
|
-
/**
|
|
2689
|
-
* Update a text layer's name.
|
|
2690
|
-
* @param {string} textLayerId - The text layer ID
|
|
2691
|
-
* @param {string} name - The name
|
|
2692
|
-
*/
|
|
2693
|
-
update: (textLayerId, name, auditMessage) =>
|
|
2694
|
-
this._request("PATCH", `/api/v1/text-layers/${textLayerId}`, {
|
|
2695
|
-
auditMessage,
|
|
2696
|
-
body: bodyOf({ name }),
|
|
2697
|
-
}),
|
|
2698
|
-
/**
|
|
2699
|
-
* Shift a text layer's display order within the project.
|
|
2700
|
-
* @param {string} textLayerId - The text layer ID
|
|
2701
|
-
* @param {string} direction - The direction ("up" or "down")
|
|
2702
|
-
*/
|
|
2703
|
-
shift: (textLayerId, direction, auditMessage) =>
|
|
2704
|
-
this._request("POST", `/api/v1/text-layers/${textLayerId}/shift`, {
|
|
2705
|
-
auditMessage,
|
|
2706
|
-
body: bodyOf({ direction }),
|
|
2707
|
-
}),
|
|
2925
|
+
...configMethods(this, "text-layers"),
|
|
2926
|
+
...layerMethods(this, "text-layers"),
|
|
2708
2927
|
/**
|
|
2709
2928
|
* Create a new text layer for a project.
|
|
2710
2929
|
* @param {string} projectId - The project ID
|
|
2711
2930
|
* @param {string} name - The name
|
|
2931
|
+
* @param {string} [auditMessage] - Audit message for this write
|
|
2932
|
+
* @param {object} [opts]
|
|
2933
|
+
* @param {string} [opts.id] - The new entity's id, minted by the caller (see uuidv7)
|
|
2712
2934
|
*/
|
|
2713
2935
|
create: (projectId, name, auditMessage, { id } = {}) =>
|
|
2714
2936
|
this._request("POST", "/api/v1/text-layers", {
|
|
@@ -2718,39 +2940,15 @@ class PlaidClient {
|
|
|
2718
2940
|
};
|
|
2719
2941
|
|
|
2720
2942
|
this.vocabItems = {
|
|
2721
|
-
|
|
2722
|
-
* Replace all metadata for a vocab item.
|
|
2723
|
-
* @param {string} id - The resource ID
|
|
2724
|
-
* @param {any} body - The request body
|
|
2725
|
-
*/
|
|
2726
|
-
setMetadata: (id, body, auditMessage) =>
|
|
2727
|
-
this._request("PUT", `/api/v1/vocab-items/${id}/metadata`, {
|
|
2728
|
-
auditMessage,
|
|
2729
|
-
rawBody: body,
|
|
2730
|
-
}),
|
|
2731
|
-
/**
|
|
2732
|
-
* Remove all metadata from a vocab item.
|
|
2733
|
-
* @param {string} id - The resource ID
|
|
2734
|
-
*/
|
|
2735
|
-
deleteMetadata: (id, auditMessage) =>
|
|
2736
|
-
this._request("DELETE", `/api/v1/vocab-items/${id}/metadata`, {
|
|
2737
|
-
auditMessage,
|
|
2738
|
-
}),
|
|
2739
|
-
/**
|
|
2740
|
-
* Edit metadata for a vocab item with a list of ops applied in order, in one operation. `{op: 'set', path, value}` writes value at path, creating missing objects along it; `{op: 'delete', path}` removes the key at path (a no-op when absent). A path is a non-empty array of keys, the first a top-level key. A path through a non-object is refused (400). See metadataOps and applyMetadataOps.
|
|
2741
|
-
* @param {string} id - The resource ID
|
|
2742
|
-
* @param {Array<{op: string, path: string[], value?: any}>} body - The metadata ops
|
|
2743
|
-
*/
|
|
2744
|
-
patchMetadata: (id, body, auditMessage) =>
|
|
2745
|
-
this._request("PATCH", `/api/v1/vocab-items/${id}/metadata`, {
|
|
2746
|
-
auditMessage,
|
|
2747
|
-
rawBody: body,
|
|
2748
|
-
}),
|
|
2943
|
+
...metadataMethods(this, "vocab-items"),
|
|
2749
2944
|
/**
|
|
2750
2945
|
* Create a new vocab item
|
|
2751
2946
|
* @param {string} vocabLayerId - The vocab layer ID
|
|
2752
2947
|
* @param {string} form - The vocab item form
|
|
2753
2948
|
* @param {any} [metadata] - Metadata map. Omit to leave unset; pass null to send JSON null.
|
|
2949
|
+
* @param {string} [auditMessage] - Audit message for this write
|
|
2950
|
+
* @param {object} [opts]
|
|
2951
|
+
* @param {string} [opts.id] - The new entity's id, minted by the caller (see uuidv7)
|
|
2754
2952
|
*/
|
|
2755
2953
|
create: (vocabLayerId, form, metadata, auditMessage, { id } = {}) =>
|
|
2756
2954
|
this._request("POST", "/api/v1/vocab-items", {
|
|
@@ -2761,6 +2959,8 @@ class PlaidClient {
|
|
|
2761
2959
|
* Create multiple vocab items in a single operation. Entries may target
|
|
2762
2960
|
* different vocab layers; the user must have write access to each.
|
|
2763
2961
|
* @param {Array<{vocabLayerId: string, form: string, metadata?: any}>} body - The vocab items to create
|
|
2962
|
+
* @param {string} [auditMessage] - Audit message for this write
|
|
2963
|
+
* @returns {Promise<{ids: string[]}>}
|
|
2764
2964
|
*/
|
|
2765
2965
|
bulkCreate: (body, auditMessage) =>
|
|
2766
2966
|
this._request("POST", "/api/v1/vocab-items/bulk", {
|
|
@@ -2771,6 +2971,7 @@ class PlaidClient {
|
|
|
2771
2971
|
* Update many vocab items in a single operation: set forms and/or patch
|
|
2772
2972
|
* metadata.
|
|
2773
2973
|
* @param {Array<{id: string, form?: string, metadata?: Array<object>}>} body - `form` is set only when the key is present; `metadata` is a list of metadata ops, as for patchMetadata. The entries may lie in several vocab layers; the user must have write access to each. An unknown id refuses the whole update, and an id may appear only once. Only an entry whose form really changes restates the documents linking it, and a strict-mode client picks up their new versions from the response.
|
|
2974
|
+
* @param {string} [auditMessage] - Audit message for this write
|
|
2774
2975
|
* @returns {Promise<{count: number}>} How many vocab items were updated.
|
|
2775
2976
|
*/
|
|
2776
2977
|
bulkUpdate: (body, auditMessage) =>
|
|
@@ -2785,6 +2986,8 @@ class PlaidClient {
|
|
|
2785
2986
|
* Every document holding one of those links has its version bumped, and
|
|
2786
2987
|
* a strict-mode client picks up their new versions from the response.
|
|
2787
2988
|
* @param {string[]} body - The vocab item IDs to delete
|
|
2989
|
+
* @param {string} [auditMessage] - Audit message for this write
|
|
2990
|
+
* @returns {Promise<void>}
|
|
2788
2991
|
*/
|
|
2789
2992
|
bulkDelete: (body, auditMessage) =>
|
|
2790
2993
|
this._request("DELETE", "/api/v1/vocab-items/bulk", {
|
|
@@ -2827,6 +3030,7 @@ class PlaidClient {
|
|
|
2827
3030
|
* Needs maintainer rights on the vocabulary.
|
|
2828
3031
|
* @param {string} survivorId - The entry that stays
|
|
2829
3032
|
* @param {string[]} loserIds - The entries merged into it
|
|
3033
|
+
* @param {string} [auditMessage] - Audit message for this write
|
|
2830
3034
|
* @returns {Promise<{moved: number, duplicates: number, removed: string[]}>}
|
|
2831
3035
|
*/
|
|
2832
3036
|
merge: (survivorId, loserIds, auditMessage) =>
|
|
@@ -2841,6 +3045,7 @@ class PlaidClient {
|
|
|
2841
3045
|
* from the response.
|
|
2842
3046
|
* @param {string} id - The resource ID
|
|
2843
3047
|
* @param {string} form - The vocab item form
|
|
3048
|
+
* @param {string} [auditMessage] - Audit message for this write
|
|
2844
3049
|
*/
|
|
2845
3050
|
update: (id, form, auditMessage) =>
|
|
2846
3051
|
this._request("PATCH", `/api/v1/vocab-items/${id}`, {
|
|
@@ -2850,82 +3055,22 @@ class PlaidClient {
|
|
|
2850
3055
|
};
|
|
2851
3056
|
|
|
2852
3057
|
this.relationLayers = {
|
|
2853
|
-
|
|
2854
|
-
* Shift a relation layer's display order.
|
|
2855
|
-
* @param {string} relationLayerId - The relation layer ID
|
|
2856
|
-
* @param {string} direction - The direction ("up" or "down")
|
|
2857
|
-
*/
|
|
2858
|
-
shift: (relationLayerId, direction, auditMessage) =>
|
|
2859
|
-
this._request(
|
|
2860
|
-
"POST",
|
|
2861
|
-
`/api/v1/relation-layers/${relationLayerId}/shift`,
|
|
2862
|
-
{ auditMessage, body: bodyOf({ direction }) },
|
|
2863
|
-
),
|
|
3058
|
+
...layerMethods(this, "relation-layers"),
|
|
2864
3059
|
/**
|
|
2865
3060
|
* Create a new relation layer.
|
|
2866
3061
|
* @param {string} spanLayerId - The span layer ID
|
|
2867
3062
|
* @param {string} name - The name
|
|
3063
|
+
* @param {string} [auditMessage] - Audit message for this write
|
|
3064
|
+
* @param {object} [opts]
|
|
3065
|
+
* @param {string} [opts.id] - The new entity's id, minted by the caller (see uuidv7)
|
|
2868
3066
|
*/
|
|
2869
3067
|
create: (spanLayerId, name, auditMessage, { id } = {}) =>
|
|
2870
3068
|
this._request("POST", "/api/v1/relation-layers", {
|
|
2871
3069
|
auditMessage,
|
|
2872
3070
|
body: bodyOf({ id, "span-layer-id": spanLayerId, name }),
|
|
2873
3071
|
}),
|
|
2874
|
-
|
|
2875
|
-
* Set a configuration value for a layer in an editor namespace.
|
|
2876
|
-
* @param {string} relationLayerId - The relation layer ID
|
|
2877
|
-
* @param {string} namespace - The config namespace
|
|
2878
|
-
* @param {string} configKey - The config key
|
|
2879
|
-
* @param {any} configValue - Configuration value to set
|
|
2880
|
-
* @param {string} [auditMessage] - Audit message for this write
|
|
2881
|
-
* @param {{expected?: any}} [options] - `expected`: the value read for this key (null or undefined when it
|
|
2882
|
-
* was absent). The write is then refused with a 409 when the stored value differs.
|
|
2883
|
-
*/
|
|
2884
|
-
setConfig: (relationLayerId, namespace, configKey, configValue, auditMessage, options) =>
|
|
2885
|
-
this._request(
|
|
2886
|
-
"PUT",
|
|
2887
|
-
`/api/v1/relation-layers/${relationLayerId}/config/${namespace}/${configKey}`,
|
|
2888
|
-
configRequest(auditMessage, configValue, options),
|
|
2889
|
-
),
|
|
2890
|
-
/**
|
|
2891
|
-
* Remove a configuration value for a layer.
|
|
2892
|
-
* @param {string} relationLayerId - The relation layer ID
|
|
2893
|
-
* @param {string} namespace - The config namespace
|
|
2894
|
-
* @param {string} configKey - The config key
|
|
2895
|
-
* @param {string} [auditMessage] - Audit message for this write
|
|
2896
|
-
* @param {{expected?: any}} [options] - `expected`, as on setConfig.
|
|
2897
|
-
*/
|
|
2898
|
-
deleteConfig: (relationLayerId, namespace, configKey, auditMessage, options) =>
|
|
2899
|
-
this._request(
|
|
2900
|
-
"DELETE",
|
|
2901
|
-
`/api/v1/relation-layers/${relationLayerId}/config/${namespace}/${configKey}`,
|
|
2902
|
-
configRequest(auditMessage, undefined, options, true),
|
|
2903
|
-
),
|
|
3072
|
+
...configMethods(this, "relation-layers"),
|
|
2904
3073
|
...constraintMethods(this, "relation-layers"),
|
|
2905
|
-
/**
|
|
2906
|
-
* Get a relation layer by ID.
|
|
2907
|
-
* @param {string} relationLayerId - The relation layer ID
|
|
2908
|
-
*/
|
|
2909
|
-
get: (relationLayerId) =>
|
|
2910
|
-
this._request("GET", `/api/v1/relation-layers/${relationLayerId}`),
|
|
2911
|
-
/**
|
|
2912
|
-
* Delete a relation layer.
|
|
2913
|
-
* @param {string} relationLayerId - The relation layer ID
|
|
2914
|
-
*/
|
|
2915
|
-
delete: (relationLayerId, auditMessage) =>
|
|
2916
|
-
this._request("DELETE", `/api/v1/relation-layers/${relationLayerId}`, {
|
|
2917
|
-
auditMessage,
|
|
2918
|
-
}),
|
|
2919
|
-
/**
|
|
2920
|
-
* Update a relation layer's name.
|
|
2921
|
-
* @param {string} relationLayerId - The relation layer ID
|
|
2922
|
-
* @param {string} name - The name
|
|
2923
|
-
*/
|
|
2924
|
-
update: (relationLayerId, name, auditMessage) =>
|
|
2925
|
-
this._request("PATCH", `/api/v1/relation-layers/${relationLayerId}`, {
|
|
2926
|
-
auditMessage,
|
|
2927
|
-
body: bodyOf({ name }),
|
|
2928
|
-
}),
|
|
2929
3074
|
};
|
|
2930
3075
|
|
|
2931
3076
|
this.tokens = {
|
|
@@ -2946,6 +3091,9 @@ class PlaidClient {
|
|
|
2946
3091
|
* @param {number} end - End offset, exclusive (Unicode code points)
|
|
2947
3092
|
* @param {number} [precedence] - Ordering precedence
|
|
2948
3093
|
* @param {any} [metadata] - Metadata map. Omit to leave unset; pass null to send JSON null.
|
|
3094
|
+
* @param {string} [auditMessage] - Audit message for this write
|
|
3095
|
+
* @param {object} [opts]
|
|
3096
|
+
* @param {string} [opts.id] - The new entity's id, minted by the caller (see uuidv7)
|
|
2949
3097
|
*/
|
|
2950
3098
|
create: (
|
|
2951
3099
|
tokenLayerId,
|
|
@@ -2979,6 +3127,7 @@ class PlaidClient {
|
|
|
2979
3127
|
* Delete a token and remove it from any spans. If this causes a span to
|
|
2980
3128
|
* have no remaining tokens, the span will also be deleted.
|
|
2981
3129
|
* @param {string} tokenId - The token ID
|
|
3130
|
+
* @param {string} [auditMessage] - Audit message for this write
|
|
2982
3131
|
*/
|
|
2983
3132
|
delete: (tokenId, auditMessage) =>
|
|
2984
3133
|
this._request("DELETE", `/api/v1/tokens/${tokenId}`, { auditMessage }),
|
|
@@ -2991,6 +3140,7 @@ class PlaidClient {
|
|
|
2991
3140
|
* to leave unchanged; pass a number to set; pass null explicitly to
|
|
2992
3141
|
* CLEAR it (revert to no explicit ordering). bodyOf keeps null but
|
|
2993
3142
|
* drops undefined, so the three cases map correctly to the server.
|
|
3143
|
+
* @param {string} [auditMessage] - Audit message for this write
|
|
2994
3144
|
*/
|
|
2995
3145
|
update: (tokenId, begin, end, precedence, auditMessage) =>
|
|
2996
3146
|
this._request("PATCH", `/api/v1/tokens/${tokenId}`, {
|
|
@@ -3000,6 +3150,7 @@ class PlaidClient {
|
|
|
3000
3150
|
/**
|
|
3001
3151
|
* Create multiple tokens in a single operation.
|
|
3002
3152
|
* @param {Array} body - The request body
|
|
3153
|
+
* @param {string} [auditMessage] - Audit message for this write
|
|
3003
3154
|
* @returns {Promise<{ids: string[]}>} The created entity IDs, in input order. (bulkDelete resolves to no value.)
|
|
3004
3155
|
*/
|
|
3005
3156
|
bulkCreate: (body, auditMessage) =>
|
|
@@ -3007,12 +3158,15 @@ class PlaidClient {
|
|
|
3007
3158
|
/**
|
|
3008
3159
|
* Delete multiple tokens in a single operation. Provide an array of IDs.
|
|
3009
3160
|
* @param {Array} body - The request body
|
|
3161
|
+
* @param {string} [auditMessage] - Audit message for this write
|
|
3162
|
+
* @returns {Promise<void>}
|
|
3010
3163
|
*/
|
|
3011
3164
|
bulkDelete: (body, auditMessage) =>
|
|
3012
3165
|
this._request("DELETE", "/api/v1/tokens/bulk", { auditMessage, body }),
|
|
3013
3166
|
/**
|
|
3014
3167
|
* Update many tokens in a single operation: patch metadata.
|
|
3015
3168
|
* @param {Array} body - Objects of the shape `{id, metadata}`. `metadata` is a list of metadata ops, as for patchMetadata. 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` (past fifty documents, only their number, in `X-Document-Versions-Omitted`). A `document-version` precondition is accepted only when every entry lies in one document. An unknown id refuses the whole update.
|
|
3169
|
+
* @param {string} [auditMessage] - Audit message for this write
|
|
3016
3170
|
* @returns {Promise<{count: number}>} How many tokens were updated.
|
|
3017
3171
|
*/
|
|
3018
3172
|
bulkUpdate: (body, auditMessage) =>
|
|
@@ -3051,6 +3205,7 @@ class PlaidClient {
|
|
|
3051
3205
|
* merged extent must not engulf a third token.
|
|
3052
3206
|
* @param {string} tokenId - The anchor token ID
|
|
3053
3207
|
* @param {string} otherTokenId - The other token to merge in
|
|
3208
|
+
* @param {string} [auditMessage] - Audit message for this write
|
|
3054
3209
|
*/
|
|
3055
3210
|
merge: (tokenId, otherTokenId, auditMessage) =>
|
|
3056
3211
|
this._request("POST", `/api/v1/tokens/${tokenId}/merge`, {
|
|
@@ -3064,49 +3219,23 @@ class PlaidClient {
|
|
|
3064
3219
|
* @param {string} tokenId - The token ID
|
|
3065
3220
|
* @param {number} [begin] - New start offset, inclusive (Unicode code points)
|
|
3066
3221
|
* @param {number} [end] - New end offset, exclusive (Unicode code points)
|
|
3222
|
+
* @param {string} [auditMessage] - Audit message for this write
|
|
3067
3223
|
*/
|
|
3068
3224
|
shift: (tokenId, begin, end, auditMessage) =>
|
|
3069
3225
|
this._request("POST", `/api/v1/tokens/${tokenId}/shift`, {
|
|
3070
3226
|
auditMessage,
|
|
3071
3227
|
body: bodyOf({ begin, end }),
|
|
3072
3228
|
}),
|
|
3073
|
-
|
|
3074
|
-
* Replace all metadata for a token.
|
|
3075
|
-
* @param {string} tokenId - The token ID
|
|
3076
|
-
* @param {any} body - The request body
|
|
3077
|
-
*/
|
|
3078
|
-
setMetadata: (tokenId, body, auditMessage) =>
|
|
3079
|
-
this._request("PUT", `/api/v1/tokens/${tokenId}/metadata`, {
|
|
3080
|
-
auditMessage,
|
|
3081
|
-
rawBody: body,
|
|
3082
|
-
}),
|
|
3083
|
-
/**
|
|
3084
|
-
* Remove all metadata from a token.
|
|
3085
|
-
* @param {string} tokenId - The token ID
|
|
3086
|
-
*/
|
|
3087
|
-
deleteMetadata: (tokenId, auditMessage) =>
|
|
3088
|
-
this._request("DELETE", `/api/v1/tokens/${tokenId}/metadata`, {
|
|
3089
|
-
auditMessage,
|
|
3090
|
-
}),
|
|
3091
|
-
/**
|
|
3092
|
-
* Edit metadata for a token with a list of ops applied in order, in one operation. `{op: 'set', path, value}` writes value at path, creating missing objects along it; `{op: 'delete', path}` removes the key at path (a no-op when absent). A path is a non-empty array of keys, the first a top-level key. A path through a non-object is refused (400). See metadataOps and applyMetadataOps.
|
|
3093
|
-
* @param {string} tokenId - The token ID
|
|
3094
|
-
* @param {Array<{op: string, path: string[], value?: any}>} body - The metadata ops
|
|
3095
|
-
*/
|
|
3096
|
-
patchMetadata: (tokenId, body, auditMessage) =>
|
|
3097
|
-
this._request("PATCH", `/api/v1/tokens/${tokenId}/metadata`, {
|
|
3098
|
-
auditMessage,
|
|
3099
|
-
rawBody: body,
|
|
3100
|
-
}),
|
|
3229
|
+
...metadataMethods(this, "tokens"),
|
|
3101
3230
|
};
|
|
3102
3231
|
|
|
3103
3232
|
this.messages = {
|
|
3104
3233
|
/**
|
|
3105
3234
|
* Open a Server-Sent Events stream for a project.
|
|
3106
3235
|
* @param {string} projectId - The UUID of the project to listen to
|
|
3107
|
-
* @param {
|
|
3236
|
+
* @param {(eventType: string, data: any) => void | boolean} onEvent - Callback function that receives (eventType, data). If it returns true, listening will stop.
|
|
3108
3237
|
* @param {string} [path] - Stream path under baseUrl (defaults to the project /listen bus; service channels pass their own).
|
|
3109
|
-
* @returns {
|
|
3238
|
+
* @returns {SSEConnection} SSE connection object with .close() and .getStats() methods
|
|
3110
3239
|
*/
|
|
3111
3240
|
listen: (projectId, onEvent, path) =>
|
|
3112
3241
|
createSSEConnection(this, projectId, onEvent, path),
|
|
@@ -3139,7 +3268,7 @@ class PlaidClient {
|
|
|
3139
3268
|
* connected services carry `online: true`; previously-seen offline ones
|
|
3140
3269
|
* carry `online: false` plus a `lastSeenAt` stamp.
|
|
3141
3270
|
* @param {string} projectId - The UUID of the project to query
|
|
3142
|
-
* @returns {Promise<
|
|
3271
|
+
* @returns {Promise<DiscoveredService[]>} Array of discovered service information
|
|
3143
3272
|
*/
|
|
3144
3273
|
discoverServices: (projectId) => discoverServices(this, projectId),
|
|
3145
3274
|
|
|
@@ -3159,14 +3288,14 @@ class PlaidClient {
|
|
|
3159
3288
|
* The registration reopens its channel whenever it drops, so a server
|
|
3160
3289
|
* restart needs no service restart.
|
|
3161
3290
|
* @param {string} projectId - The UUID of the project to serve
|
|
3162
|
-
* @param {
|
|
3163
|
-
* @param {
|
|
3291
|
+
* @param {ServiceInfo} serviceInfo - Service information {serviceId, serviceName, description}
|
|
3292
|
+
* @param {(data: any, responseHelper: ResponseHelper) => void} onServiceRequest - Callback (data, responseHelper)
|
|
3164
3293
|
* @param {Object} [extras] - Optional additional service metadata
|
|
3165
|
-
* @param {
|
|
3294
|
+
* @param {(event: ServiceStatusEvent, projectId: string, detail?: string) => void} [onStatus] - Optional callback (event, projectId, detail) for
|
|
3166
3295
|
* connection transitions: 'registered', 'reconnected', 'disconnected',
|
|
3167
3296
|
* and 'stopped' when the server refuses the channel for good, which
|
|
3168
3297
|
* ends the registration
|
|
3169
|
-
* @returns {
|
|
3298
|
+
* @returns {ServiceRegistration} Service registration with .stop(), .isRunning(), .isConnected()
|
|
3170
3299
|
*/
|
|
3171
3300
|
serve: (projectId, serviceInfo, onServiceRequest, extras, onStatus) =>
|
|
3172
3301
|
serve(this, projectId, serviceInfo, onServiceRequest, extras, onStatus),
|
|
@@ -3187,7 +3316,7 @@ class PlaidClient {
|
|
|
3187
3316
|
* @param {number} [timeout=10000] - Timeout in ms
|
|
3188
3317
|
* @param {function} [onProgress] - Called with each progress payload {percent, message}
|
|
3189
3318
|
* @param {AbortSignal} [signal] - Abort to stop waiting; rejects with an AbortError
|
|
3190
|
-
* @param {
|
|
3319
|
+
* @param {{requestId?: string, onAccepted?: (requestId: string) => void, projectIds?: string[], noOperation?: boolean}} [opts] - {requestId, onAccepted, projectIds, noOperation}
|
|
3191
3320
|
* @returns {Promise<any>} The service's result
|
|
3192
3321
|
*/
|
|
3193
3322
|
requestService: (
|
|
@@ -3332,11 +3461,13 @@ class PlaidClient {
|
|
|
3332
3461
|
* A comment outlives its anchor: deleting the entity does not delete
|
|
3333
3462
|
* the comment. `anchorLabel` is the caption shown once that happens
|
|
3334
3463
|
* ("Gloss of ktab, sentence 4"), so pass what the comment is about.
|
|
3335
|
-
* @param {
|
|
3464
|
+
* @param {CommentableType} entityType - What kind of thing is being commented on
|
|
3336
3465
|
* @param {string} entityId - The commented entity's id
|
|
3337
3466
|
* @param {string} body - The comment text (1..10000 characters)
|
|
3338
3467
|
* @param {object} [opts]
|
|
3339
3468
|
* @param {string} [opts.anchorLabel] - What the comment is about, in words (at most 200 characters)
|
|
3469
|
+
* @param {string} [opts.id] - The new comment's id, minted by the caller (see uuidv7)
|
|
3470
|
+
* @returns {Promise<Comment>}
|
|
3340
3471
|
*/
|
|
3341
3472
|
create: (entityType, entityId, body, { anchorLabel, id } = {}) =>
|
|
3342
3473
|
this._request("POST", "/api/v1/comments", {
|
|
@@ -3354,6 +3485,7 @@ class PlaidClient {
|
|
|
3354
3485
|
/**
|
|
3355
3486
|
* Read one comment.
|
|
3356
3487
|
* @param {string} id - The comment id
|
|
3488
|
+
* @returns {Promise<Comment>}
|
|
3357
3489
|
*/
|
|
3358
3490
|
get: (id) => this._request("GET", `/api/v1/comments/${id}`),
|
|
3359
3491
|
/**
|
|
@@ -3361,6 +3493,7 @@ class PlaidClient {
|
|
|
3361
3493
|
* maintainers, not admins. Sets `edited` on the comment.
|
|
3362
3494
|
* @param {string} id - The comment id
|
|
3363
3495
|
* @param {string} body - The replacement text
|
|
3496
|
+
* @returns {Promise<Comment>}
|
|
3364
3497
|
*/
|
|
3365
3498
|
update: (id, body) =>
|
|
3366
3499
|
this._request("PATCH", `/api/v1/comments/${id}`, {
|
|
@@ -3382,6 +3515,7 @@ class PlaidClient {
|
|
|
3382
3515
|
* @param {string} [filters.documentId] - Every comment anywhere in one document
|
|
3383
3516
|
* @param {string} [filters.entityType] - With entityId, one entity's thread
|
|
3384
3517
|
* @param {string} [filters.entityId] - With entityType, one entity's thread
|
|
3518
|
+
* @returns {Promise<Comment[]>}
|
|
3385
3519
|
*/
|
|
3386
3520
|
list: (projectId, { documentId, entityType, entityId } = {}) =>
|
|
3387
3521
|
listAll(this, `/api/v1/projects/${projectId}/comments`, {
|
|
@@ -3400,7 +3534,7 @@ class PlaidClient {
|
|
|
3400
3534
|
* @param {string} [opts.documentId] - Every comment anywhere in one document
|
|
3401
3535
|
* @param {string} [opts.entityType] - With entityId, one entity's thread
|
|
3402
3536
|
* @param {string} [opts.entityId] - With entityType, one entity's thread
|
|
3403
|
-
* @returns {Promise<
|
|
3537
|
+
* @returns {Promise<Page<Comment>>}
|
|
3404
3538
|
*/
|
|
3405
3539
|
listPage: (
|
|
3406
3540
|
projectId,
|
|
@@ -3423,7 +3557,7 @@ class PlaidClient {
|
|
|
3423
3557
|
* @param {string} [opts.documentId] - Every comment anywhere in one document
|
|
3424
3558
|
* @param {string} [opts.entityType] - With entityId, one entity's thread
|
|
3425
3559
|
* @param {string} [opts.entityId] - With entityType, one entity's thread
|
|
3426
|
-
* @returns {AsyncGenerator<
|
|
3560
|
+
* @returns {AsyncGenerator<Comment[]>}
|
|
3427
3561
|
*/
|
|
3428
3562
|
iterPages: (
|
|
3429
3563
|
projectId,
|
|
@@ -3446,7 +3580,7 @@ class PlaidClient {
|
|
|
3446
3580
|
* The response is NOT key-transformed: its keys are entity ids, and
|
|
3447
3581
|
* camelCasing would mangle the hyphens in a UUID.
|
|
3448
3582
|
* @param {string} projectId - The project to read
|
|
3449
|
-
* @param {
|
|
3583
|
+
* @param {{documentId?: string, entityType?: CommentableType, entityId?: string}} [filters] - Same filters as list()
|
|
3450
3584
|
* @returns {Promise<Object<string, number>>}
|
|
3451
3585
|
*/
|
|
3452
3586
|
counts: (projectId, { documentId, entityType, entityId } = {}) =>
|
|
@@ -3465,6 +3599,7 @@ class PlaidClient {
|
|
|
3465
3599
|
* @param {string} vocabId - The vocab layer to read
|
|
3466
3600
|
* @param {object} [filters]
|
|
3467
3601
|
* @param {string} [filters.entityId] - One entry's thread
|
|
3602
|
+
* @returns {Promise<Comment[]>}
|
|
3468
3603
|
*/
|
|
3469
3604
|
listInVocab: (vocabId, { entityId } = {}) =>
|
|
3470
3605
|
listAll(this, `/api/v1/vocab-layers/${vocabId}/comments`, {
|
|
@@ -3477,7 +3612,7 @@ class PlaidClient {
|
|
|
3477
3612
|
* @param {number} [opts.limit] - Page size (1..1000; server default 100)
|
|
3478
3613
|
* @param {string} [opts.cursor] - Opaque cursor from a previous page
|
|
3479
3614
|
* @param {string} [opts.entityId] - One entry's thread
|
|
3480
|
-
* @returns {Promise<
|
|
3615
|
+
* @returns {Promise<Page<Comment>>}
|
|
3481
3616
|
*/
|
|
3482
3617
|
listInVocabPage: (vocabId, { limit, cursor, entityId } = {}) =>
|
|
3483
3618
|
listPage(this, `/api/v1/vocab-layers/${vocabId}/comments`, {
|
|
@@ -3492,7 +3627,7 @@ class PlaidClient {
|
|
|
3492
3627
|
* @param {object} [opts]
|
|
3493
3628
|
* @param {string} [opts.entityId] - One entry's thread
|
|
3494
3629
|
* @param {number} [opts.pageSize] - Per-request page size
|
|
3495
|
-
* @returns {AsyncGenerator<
|
|
3630
|
+
* @returns {AsyncGenerator<Comment[]>}
|
|
3496
3631
|
*/
|
|
3497
3632
|
iterInVocabPages: (vocabId, { entityId, pageSize } = {}) =>
|
|
3498
3633
|
iterPages(this, `/api/v1/vocab-layers/${vocabId}/comments`, {
|
|
@@ -3520,15 +3655,15 @@ class PlaidClient {
|
|
|
3520
3655
|
|
|
3521
3656
|
this.events = {
|
|
3522
3657
|
/**
|
|
3523
|
-
* Record one research-telemetry event (core
|
|
3524
|
-
*
|
|
3658
|
+
* Record one research-telemetry event (plaid-core sql/client_event.clj).
|
|
3659
|
+
* Fire and forget: the event is buffered and sent with
|
|
3525
3660
|
* others every ten seconds, at fifty events, and when the page is
|
|
3526
3661
|
* hidden. A batch that fails is dropped, nothing is retried, and
|
|
3527
3662
|
* nothing is ever thrown. Sends nothing for a project whose switch
|
|
3528
3663
|
* (`config.plaid.research.telemetry`) is off, which it reads from the
|
|
3529
3664
|
* project itself. `suggestion.shown` is recorded once per target,
|
|
3530
3665
|
* field and value in a page session.
|
|
3531
|
-
* @param {
|
|
3666
|
+
* @param {ClientEventType} type - The event type
|
|
3532
3667
|
* @param {object} fields
|
|
3533
3668
|
* @param {string} fields.projectId - The project it happened in
|
|
3534
3669
|
* @param {string} [fields.documentId] - The document it happened in
|
|
@@ -3539,6 +3674,7 @@ class PlaidClient {
|
|
|
3539
3674
|
record: (type, fields) => recorderFor(this).record(this, type, fields),
|
|
3540
3675
|
/**
|
|
3541
3676
|
* Send what the recorder holds now, rather than at its next interval.
|
|
3677
|
+
* @returns {void}
|
|
3542
3678
|
*/
|
|
3543
3679
|
flush: () => recorderFor(this).flush(),
|
|
3544
3680
|
/**
|
|
@@ -3546,6 +3682,7 @@ class PlaidClient {
|
|
|
3546
3682
|
* maintainer changed it. Turning it off drops what is buffered.
|
|
3547
3683
|
* @param {string} projectId - The project
|
|
3548
3684
|
* @param {boolean} on - Whether telemetry is on
|
|
3685
|
+
* @returns {void}
|
|
3549
3686
|
*/
|
|
3550
3687
|
setEnabled: (projectId, on) => recorderFor(this).setEnabled(projectId, on),
|
|
3551
3688
|
/**
|
|
@@ -3570,6 +3707,7 @@ class PlaidClient {
|
|
|
3570
3707
|
* @param {string|string[]} [filters.types] - Only these types
|
|
3571
3708
|
* @param {string} [filters.startTime] - Only events the server stamped at or after this instant
|
|
3572
3709
|
* @param {string} [filters.endTime] - Only events the server stamped at or before this instant
|
|
3710
|
+
* @returns {Promise<ClientEvent[]>}
|
|
3573
3711
|
*/
|
|
3574
3712
|
list: (projectId, { types, startTime, endTime } = {}) =>
|
|
3575
3713
|
listAll(this, `/api/v1/projects/${projectId}/events`, {
|
|
@@ -3584,7 +3722,7 @@ class PlaidClient {
|
|
|
3584
3722
|
* @param {string|string[]} [opts.types] - Only these types
|
|
3585
3723
|
* @param {string} [opts.startTime] - Only events at or after this instant
|
|
3586
3724
|
* @param {string} [opts.endTime] - Only events at or before this instant
|
|
3587
|
-
* @returns {Promise<
|
|
3725
|
+
* @returns {Promise<Page<ClientEvent>>}
|
|
3588
3726
|
*/
|
|
3589
3727
|
listPage: (
|
|
3590
3728
|
projectId,
|
|
@@ -3603,7 +3741,7 @@ class PlaidClient {
|
|
|
3603
3741
|
* @param {string|string[]} [opts.types] - Only these types
|
|
3604
3742
|
* @param {string} [opts.startTime] - Only events at or after this instant
|
|
3605
3743
|
* @param {string} [opts.endTime] - Only events at or before this instant
|
|
3606
|
-
* @returns {AsyncGenerator<
|
|
3744
|
+
* @returns {AsyncGenerator<ClientEvent[]>}
|
|
3607
3745
|
*/
|
|
3608
3746
|
iterPages: (projectId, { pageSize, types, startTime, endTime } = {}) =>
|
|
3609
3747
|
iterPages(this, `/api/v1/projects/${projectId}/events`, {
|
|
@@ -3624,6 +3762,9 @@ class PlaidClient {
|
|
|
3624
3762
|
* @param {object} [opts]
|
|
3625
3763
|
* @param {string} [opts.body] - The Markdown text (up to 20000 characters; may be empty)
|
|
3626
3764
|
* @param {boolean} [opts.pinned] - Send this one to the assistant in full on every turn
|
|
3765
|
+
* @param {string} [opts.id] - The new guideline's id, minted by the caller (see uuidv7)
|
|
3766
|
+
* @param {string} [auditMessage] - Audit message for this write
|
|
3767
|
+
* @returns {Promise<{id: string}>}
|
|
3627
3768
|
*/
|
|
3628
3769
|
create: (projectId, title, { body, pinned, id } = {}, auditMessage) =>
|
|
3629
3770
|
this._request("POST", `/api/v1/projects/${projectId}/guidelines`, {
|
|
@@ -3633,6 +3774,7 @@ class PlaidClient {
|
|
|
3633
3774
|
/**
|
|
3634
3775
|
* Read one guideline, Markdown body included.
|
|
3635
3776
|
* @param {string} id - The guideline id
|
|
3777
|
+
* @returns {Promise<Guideline>}
|
|
3636
3778
|
*/
|
|
3637
3779
|
get: (id) => this._request("GET", `/api/v1/guidelines/${id}`),
|
|
3638
3780
|
/**
|
|
@@ -3649,6 +3791,8 @@ class PlaidClient {
|
|
|
3649
3791
|
* @param {string} [changes.body] - The new Markdown text
|
|
3650
3792
|
* @param {boolean} [changes.pinned] - Whether the assistant always gets it in full
|
|
3651
3793
|
* @param {string} [changes.expectedUpdatedAt] - Write only if this is still the stored updatedAt
|
|
3794
|
+
* @param {string} [auditMessage] - Audit message for this write
|
|
3795
|
+
* @returns {Promise<Guideline>}
|
|
3652
3796
|
*/
|
|
3653
3797
|
update: (
|
|
3654
3798
|
id,
|
|
@@ -3663,6 +3807,7 @@ class PlaidClient {
|
|
|
3663
3807
|
/**
|
|
3664
3808
|
* Delete a guideline.
|
|
3665
3809
|
* @param {string} id - The guideline id
|
|
3810
|
+
* @param {string} [auditMessage] - Audit message for this write
|
|
3666
3811
|
*/
|
|
3667
3812
|
delete: (id, auditMessage) =>
|
|
3668
3813
|
this._request("DELETE", `/api/v1/guidelines/${id}`, { auditMessage }),
|
|
@@ -3677,6 +3822,7 @@ class PlaidClient {
|
|
|
3677
3822
|
* @param {string} projectId - The project to read
|
|
3678
3823
|
* @param {object} [opts]
|
|
3679
3824
|
* @param {boolean} [opts.includeBodies] - Return each body instead of its length
|
|
3825
|
+
* @returns {Promise<Guideline[]>}
|
|
3680
3826
|
*/
|
|
3681
3827
|
list: (projectId, { includeBodies } = {}) =>
|
|
3682
3828
|
listAll(this, `/api/v1/projects/${projectId}/guidelines`, {
|
|
@@ -3689,7 +3835,7 @@ class PlaidClient {
|
|
|
3689
3835
|
* @param {number} [opts.limit] - Page size (1..1000; server default 100)
|
|
3690
3836
|
* @param {string} [opts.cursor] - Opaque cursor from a previous page
|
|
3691
3837
|
* @param {boolean} [opts.includeBodies] - Return each body instead of its length
|
|
3692
|
-
* @returns {Promise<
|
|
3838
|
+
* @returns {Promise<Page<Guideline>>}
|
|
3693
3839
|
*/
|
|
3694
3840
|
listPage: (projectId, { limit, cursor, includeBodies } = {}) =>
|
|
3695
3841
|
listPage(this, `/api/v1/projects/${projectId}/guidelines`, {
|
|
@@ -3703,7 +3849,7 @@ class PlaidClient {
|
|
|
3703
3849
|
* @param {object} [opts]
|
|
3704
3850
|
* @param {number} [opts.pageSize] - Per-request page size
|
|
3705
3851
|
* @param {boolean} [opts.includeBodies] - Return each body instead of its length
|
|
3706
|
-
* @returns {AsyncGenerator<
|
|
3852
|
+
* @returns {AsyncGenerator<Guideline[]>}
|
|
3707
3853
|
*/
|
|
3708
3854
|
iterPages: (projectId, { pageSize, includeBodies } = {}) =>
|
|
3709
3855
|
iterPages(this, `/api/v1/projects/${projectId}/guidelines`, {
|
|
@@ -3715,6 +3861,7 @@ class PlaidClient {
|
|
|
3715
3861
|
|
|
3716
3862
|
// --- Core methods ---
|
|
3717
3863
|
|
|
3864
|
+
/** @private */
|
|
3718
3865
|
async _request(method, path, options = {}) {
|
|
3719
3866
|
return makeRequest(this, method, path, options);
|
|
3720
3867
|
}
|
|
@@ -3777,7 +3924,7 @@ class PlaidClient {
|
|
|
3777
3924
|
* matching end, and the outer numbering resumes after it.
|
|
3778
3925
|
*
|
|
3779
3926
|
* @param {string} message - Human label for the operation.
|
|
3780
|
-
* @param {
|
|
3927
|
+
* @param {{groupId?: string, kind?: OperationKind, ref?: string, keys?: KeySeed, minted?: Iterable<string>}} [opts] - Optional `{ groupId, kind, ref, keys, minted }`. `groupId` adopts an existing group id instead of minting one (a service joining the requester's operation; `requestService` propagates an open operation to the service automatically). Python's is `group_id`. `kind`, `ref` and `keys` are described above. `minted` is the ids the operation mints for what it creates: a create refused 409 id-taken for one of them was made by an earlier send of the operation, and answers as made.
|
|
3781
3928
|
* @returns {string} The operation's group id.
|
|
3782
3929
|
*/
|
|
3783
3930
|
beginOperation(message, { groupId, kind, ref, keys, minted } = {}) {
|
|
@@ -3809,7 +3956,7 @@ class PlaidClient {
|
|
|
3809
3956
|
return open.id;
|
|
3810
3957
|
}
|
|
3811
3958
|
this.operationGroup = {
|
|
3812
|
-
id: groupId ? String(groupId) :
|
|
3959
|
+
id: groupId ? String(groupId) : uuidv4(),
|
|
3813
3960
|
message: message == null ? null : String(message),
|
|
3814
3961
|
kind: kind == null ? null : String(kind),
|
|
3815
3962
|
ref: ref == null ? null : String(ref),
|
|
@@ -3826,7 +3973,7 @@ class PlaidClient {
|
|
|
3826
3973
|
* A seed for the Idempotency-Keys of a logical operation that may be run
|
|
3827
3974
|
* again from the top (see beginOperation's `keys`). Keep it with the work
|
|
3828
3975
|
* it belongs to and pass it to every run.
|
|
3829
|
-
* @returns {
|
|
3976
|
+
* @returns {KeySeed}
|
|
3830
3977
|
*/
|
|
3831
3978
|
keySeed() {
|
|
3832
3979
|
return { seed: uuidv7(), stamps: new Map() };
|
|
@@ -3881,10 +4028,11 @@ class PlaidClient {
|
|
|
3881
4028
|
*
|
|
3882
4029
|
* await client.withOperation('Import ELAN corpus', run, { kind: 'import', ref: 'format:elan' });
|
|
3883
4030
|
*
|
|
4031
|
+
* @template T
|
|
3884
4032
|
* @param {string} message - Human label for the operation.
|
|
3885
|
-
* @param {
|
|
3886
|
-
* @param {
|
|
3887
|
-
* @returns {Promise<
|
|
4033
|
+
* @param {(setMessage: (msg: string) => void) => T | Promise<T>} fn - The work to run; receives `setMessage(msg)` to refine the label once the outcome is known.
|
|
4034
|
+
* @param {{kind?: OperationKind, ref?: string, groupId?: string, keys?: KeySeed, minted?: Iterable<string>}} [opts] - Optional `{ kind, ref, groupId, keys, minted }`, as for beginOperation. `kind` is one of `assistant-plan`, `service-run`, `import`, `bulk-edit`, `guess-adoption`, `repair` or `review`, and any other throws before `fn` runs.
|
|
4035
|
+
* @returns {Promise<T>} Whatever `fn` resolves to.
|
|
3888
4036
|
*/
|
|
3889
4037
|
async withOperation(message, fn, { kind, ref, groupId, keys, minted } = {}) {
|
|
3890
4038
|
this.beginOperation(message, { kind, ref, groupId, keys, minted });
|
|
@@ -3939,7 +4087,7 @@ class PlaidClient {
|
|
|
3939
4087
|
* parents created earlier in the same batch, and any op's failure rolls the
|
|
3940
4088
|
* whole batch back. A batch is not nestable. Prefer `batched()`, which
|
|
3941
4089
|
* submits or aborts for you.
|
|
3942
|
-
* @returns {
|
|
4090
|
+
* @returns {PlaidBatch} the batch view
|
|
3943
4091
|
*/
|
|
3944
4092
|
batch() {
|
|
3945
4093
|
return openBatch(this);
|
|
@@ -3951,6 +4099,7 @@ class PlaidClient {
|
|
|
3951
4099
|
* recased: the headers keep the server's spelling. `key` is the request's
|
|
3952
4100
|
* Idempotency-Key: a batch whose answer is lost (no response, 502, 504) is
|
|
3953
4101
|
* sent again under it, and answered from the first send if that landed.
|
|
4102
|
+
* @private
|
|
3954
4103
|
*/
|
|
3955
4104
|
async _postBatch(url, body, { key = uuidv7() } = {}) {
|
|
3956
4105
|
const fetchOptions = {
|
|
@@ -4083,8 +4232,8 @@ class PlaidClient {
|
|
|
4083
4232
|
*
|
|
4084
4233
|
* A write made on `client` inside `fn` is not part of the batch: it goes
|
|
4085
4234
|
* over the wire at once, as it would anywhere else. See `batch()`.
|
|
4086
|
-
* @param {(batch:
|
|
4087
|
-
* @returns {Promise<
|
|
4235
|
+
* @param {(batch: PlaidBatch) => (void | Promise<void>)} fn
|
|
4236
|
+
* @returns {Promise<any[]>}
|
|
4088
4237
|
*/
|
|
4089
4238
|
async batched(fn) {
|
|
4090
4239
|
const batch = this.batch();
|
|
@@ -4102,20 +4251,22 @@ class PlaidClient {
|
|
|
4102
4251
|
* instance — for a launcher or status page checking whether a server is up
|
|
4103
4252
|
* before anyone logs in.
|
|
4104
4253
|
* @param {string} baseUrl - The API base URL
|
|
4105
|
-
* @param {
|
|
4254
|
+
* @param {{timeout?: number | null}} [options]
|
|
4255
|
+
* @returns {Promise<ServerHealth>}
|
|
4106
4256
|
*/
|
|
4107
4257
|
static async health(baseUrl, options = {}) {
|
|
4108
|
-
return
|
|
4258
|
+
return anonymousRequest("GET", baseUrl, "/health", undefined, options);
|
|
4109
4259
|
}
|
|
4110
4260
|
|
|
4111
4261
|
/**
|
|
4112
4262
|
* The limits this server enforces, with NO authentication and no client
|
|
4113
4263
|
* instance. See the instance method for the shape.
|
|
4114
4264
|
* @param {string} baseUrl - The API base URL
|
|
4115
|
-
* @param {
|
|
4265
|
+
* @param {{timeout?: number | null}} [options]
|
|
4266
|
+
* @returns {Promise<{limits: ServerLimits}>}
|
|
4116
4267
|
*/
|
|
4117
4268
|
static async info(baseUrl, options = {}) {
|
|
4118
|
-
return
|
|
4269
|
+
return anonymousRequest("GET", baseUrl, "/api/v1/info", undefined, options);
|
|
4119
4270
|
}
|
|
4120
4271
|
|
|
4121
4272
|
/**
|
|
@@ -4146,7 +4297,7 @@ class PlaidClient {
|
|
|
4146
4297
|
* @returns {Promise<{kind: string, status: string, expiresAt: string, projectName?: string, projectRole?: string, email?: string, grantAdmin: boolean}>}
|
|
4147
4298
|
*/
|
|
4148
4299
|
static async lookupInvite(baseUrl, code, options = {}) {
|
|
4149
|
-
return
|
|
4300
|
+
return anonymousRequest("POST", baseUrl, "/api/v1/invites/lookup", { code }, options);
|
|
4150
4301
|
}
|
|
4151
4302
|
|
|
4152
4303
|
/**
|
|
@@ -4175,10 +4326,16 @@ class PlaidClient {
|
|
|
4175
4326
|
{ email, password, displayName } = {},
|
|
4176
4327
|
options = {},
|
|
4177
4328
|
) {
|
|
4178
|
-
const data = await
|
|
4329
|
+
const data = await anonymousRequest(
|
|
4330
|
+
"POST",
|
|
4179
4331
|
baseUrl,
|
|
4180
4332
|
"/api/v1/invites/redeem",
|
|
4181
|
-
bodyOf({
|
|
4333
|
+
bodyOf({
|
|
4334
|
+
code,
|
|
4335
|
+
email: normalizeUserId(email),
|
|
4336
|
+
password,
|
|
4337
|
+
"display-name": displayName,
|
|
4338
|
+
}),
|
|
4182
4339
|
options,
|
|
4183
4340
|
);
|
|
4184
4341
|
return {
|
|
@@ -4203,35 +4360,14 @@ class PlaidClient {
|
|
|
4203
4360
|
*/
|
|
4204
4361
|
static async login(baseUrl, userId, password, options = {}) {
|
|
4205
4362
|
baseUrl = baseUrl.replace(/\/$/, "");
|
|
4206
|
-
const
|
|
4207
|
-
|
|
4208
|
-
|
|
4209
|
-
|
|
4210
|
-
|
|
4211
|
-
|
|
4212
|
-
|
|
4213
|
-
|
|
4214
|
-
options.timeout !== undefined ? options.timeout : DEFAULT_TIMEOUT_MS,
|
|
4215
|
-
);
|
|
4216
|
-
if (signal) fetchOptions.signal = signal;
|
|
4217
|
-
|
|
4218
|
-
const response = await fetch(url, fetchOptions);
|
|
4219
|
-
if (!response.ok) {
|
|
4220
|
-
throw makeHttpError(
|
|
4221
|
-
response,
|
|
4222
|
-
await parseErrorBody(response),
|
|
4223
|
-
url,
|
|
4224
|
-
"POST",
|
|
4225
|
-
);
|
|
4226
|
-
}
|
|
4227
|
-
|
|
4228
|
-
const data = await response.json();
|
|
4229
|
-
const token = data.token || "";
|
|
4230
|
-
return new PlaidClient(baseUrl, token, options);
|
|
4231
|
-
} catch (error) {
|
|
4232
|
-
if (error.status) throw error;
|
|
4233
|
-
throw makeNetworkError(error, url, "POST");
|
|
4234
|
-
}
|
|
4363
|
+
const data = await anonymousRequest(
|
|
4364
|
+
"POST",
|
|
4365
|
+
baseUrl,
|
|
4366
|
+
"/api/v1/login",
|
|
4367
|
+
{ "user-id": normalizeUserId(userId), password },
|
|
4368
|
+
options,
|
|
4369
|
+
);
|
|
4370
|
+
return new PlaidClient(baseUrl, data.token || "", options);
|
|
4235
4371
|
}
|
|
4236
4372
|
}
|
|
4237
4373
|
|
|
@@ -4259,9 +4395,129 @@ function configRequest(auditMessage, value, options, isDelete = false) {
|
|
|
4259
4395
|
};
|
|
4260
4396
|
}
|
|
4261
4397
|
|
|
4398
|
+
/**
|
|
4399
|
+
* The three metadata methods of a bundle whose entities carry metadata, on
|
|
4400
|
+
* `/api/v1/<kind>/<id>/metadata`. Metadata is opaque, so no body is re-cased.
|
|
4401
|
+
* @param {PlaidClient} client
|
|
4402
|
+
* @param {string} kind
|
|
4403
|
+
*/
|
|
4404
|
+
function metadataMethods(client, kind) {
|
|
4405
|
+
const path = (id) => `/api/v1/${kind}/${id}/metadata`;
|
|
4406
|
+
return {
|
|
4407
|
+
/**
|
|
4408
|
+
* Replace all metadata of an entity. Keys left out of the new map are removed.
|
|
4409
|
+
* @param {string} id - The entity's ID
|
|
4410
|
+
* @param {object} body - The new metadata map
|
|
4411
|
+
* @param {string} [auditMessage] - Audit message for this write
|
|
4412
|
+
*/
|
|
4413
|
+
setMetadata: (id, body, auditMessage) =>
|
|
4414
|
+
client._request("PUT", path(id), { auditMessage, rawBody: body }),
|
|
4415
|
+
/**
|
|
4416
|
+
* Remove all metadata from an entity.
|
|
4417
|
+
* @param {string} id - The entity's ID
|
|
4418
|
+
* @param {string} [auditMessage] - Audit message for this write
|
|
4419
|
+
*/
|
|
4420
|
+
deleteMetadata: (id, auditMessage) => client._request("DELETE", path(id), { auditMessage }),
|
|
4421
|
+
/**
|
|
4422
|
+
* Edit an entity's metadata with a list of ops applied in order, in one operation. `{op: 'set', path, value}` writes value at path, creating missing objects along it; `{op: 'delete', path}` removes the key at path (a no-op when absent). A path is a non-empty array of keys, the first a top-level key. A path through a non-object is refused (400). See metadataOps and applyMetadataOps.
|
|
4423
|
+
* @param {string} id - The entity's ID
|
|
4424
|
+
* @param {MetadataOp[]} body - The metadata ops
|
|
4425
|
+
* @param {string} [auditMessage] - Audit message for this write
|
|
4426
|
+
*/
|
|
4427
|
+
patchMetadata: (id, body, auditMessage) =>
|
|
4428
|
+
client._request("PATCH", path(id), { auditMessage, rawBody: body }),
|
|
4429
|
+
};
|
|
4430
|
+
}
|
|
4431
|
+
|
|
4432
|
+
/**
|
|
4433
|
+
* The two config methods of a bundle whose records carry editor config, on
|
|
4434
|
+
* `/api/v1/<kind>/<id>/config/<namespace>/<key>`.
|
|
4435
|
+
* @param {PlaidClient} client
|
|
4436
|
+
* @param {string} kind
|
|
4437
|
+
*/
|
|
4438
|
+
function configMethods(client, kind) {
|
|
4439
|
+
const path = (id, namespace, configKey) => `/api/v1/${kind}/${id}/config/${namespace}/${configKey}`;
|
|
4440
|
+
return {
|
|
4441
|
+
/**
|
|
4442
|
+
* Set a configuration value in an editor namespace.
|
|
4443
|
+
* @param {string} id - The record's ID
|
|
4444
|
+
* @param {string} namespace - The config namespace
|
|
4445
|
+
* @param {string} configKey - The config key
|
|
4446
|
+
* @param {any} configValue - Configuration value to set
|
|
4447
|
+
* @param {string} [auditMessage] - Audit message for this write
|
|
4448
|
+
* @param {{expected?: any}} [options] - `expected`: the value read for this key (null or undefined when it
|
|
4449
|
+
* was absent). The write is then refused with a 409 when the stored value differs.
|
|
4450
|
+
*/
|
|
4451
|
+
setConfig: (id, namespace, configKey, configValue, auditMessage, options) =>
|
|
4452
|
+
client._request(
|
|
4453
|
+
"PUT",
|
|
4454
|
+
path(id, namespace, configKey),
|
|
4455
|
+
configRequest(auditMessage, configValue, options),
|
|
4456
|
+
),
|
|
4457
|
+
/**
|
|
4458
|
+
* Remove a configuration value.
|
|
4459
|
+
* @param {string} id - The record's ID
|
|
4460
|
+
* @param {string} namespace - The config namespace
|
|
4461
|
+
* @param {string} configKey - The config key
|
|
4462
|
+
* @param {string} [auditMessage] - Audit message for this write
|
|
4463
|
+
* @param {{expected?: any}} [options] - `expected`, as on setConfig.
|
|
4464
|
+
*/
|
|
4465
|
+
deleteConfig: (id, namespace, configKey, auditMessage, options) =>
|
|
4466
|
+
client._request(
|
|
4467
|
+
"DELETE",
|
|
4468
|
+
path(id, namespace, configKey),
|
|
4469
|
+
configRequest(auditMessage, undefined, options, true),
|
|
4470
|
+
),
|
|
4471
|
+
};
|
|
4472
|
+
}
|
|
4473
|
+
|
|
4474
|
+
/**
|
|
4475
|
+
* The get, delete, update and shift methods of the four layer bundles, on
|
|
4476
|
+
* `/api/v1/<kind>/<layerId>`.
|
|
4477
|
+
* @param {PlaidClient} client
|
|
4478
|
+
* @param {string} kind
|
|
4479
|
+
*/
|
|
4480
|
+
function layerMethods(client, kind) {
|
|
4481
|
+
const path = (layerId) => `/api/v1/${kind}/${layerId}`;
|
|
4482
|
+
return {
|
|
4483
|
+
/**
|
|
4484
|
+
* Get a layer by ID.
|
|
4485
|
+
* @param {string} layerId - The layer ID
|
|
4486
|
+
*/
|
|
4487
|
+
get: (layerId) => client._request("GET", path(layerId)),
|
|
4488
|
+
/**
|
|
4489
|
+
* Delete a layer.
|
|
4490
|
+
* @param {string} layerId - The layer ID
|
|
4491
|
+
* @param {string} [auditMessage] - Audit message for this write
|
|
4492
|
+
*/
|
|
4493
|
+
delete: (layerId, auditMessage) => client._request("DELETE", path(layerId), { auditMessage }),
|
|
4494
|
+
/**
|
|
4495
|
+
* Rename a layer.
|
|
4496
|
+
* @param {string} layerId - The layer ID
|
|
4497
|
+
* @param {string} name - The new name
|
|
4498
|
+
* @param {string} [auditMessage] - Audit message for this write
|
|
4499
|
+
*/
|
|
4500
|
+
update: (layerId, name, auditMessage) =>
|
|
4501
|
+
client._request("PATCH", path(layerId), { auditMessage, body: bodyOf({ name }) }),
|
|
4502
|
+
/**
|
|
4503
|
+
* Move a layer one place in its display order.
|
|
4504
|
+
* @param {string} layerId - The layer ID
|
|
4505
|
+
* @param {string} direction - The direction ("up" or "down")
|
|
4506
|
+
* @param {string} [auditMessage] - Audit message for this write
|
|
4507
|
+
*/
|
|
4508
|
+
shift: (layerId, direction, auditMessage) =>
|
|
4509
|
+
client._request("POST", `${path(layerId)}/shift`, {
|
|
4510
|
+
auditMessage,
|
|
4511
|
+
body: bodyOf({ direction }),
|
|
4512
|
+
}),
|
|
4513
|
+
};
|
|
4514
|
+
}
|
|
4515
|
+
|
|
4262
4516
|
/**
|
|
4263
4517
|
* The four layer-constraint methods of a layer bundle, on `/api/v1/<kind>`.
|
|
4264
4518
|
* See constraints.js and the core manual, "Layer constraints".
|
|
4519
|
+
* @param {PlaidClient} client
|
|
4520
|
+
* @param {string} kind
|
|
4265
4521
|
*/
|
|
4266
4522
|
function constraintMethods(client, kind) {
|
|
4267
4523
|
const base = (layerId) => `/api/v1/${kind}/${layerId}/constraints`;
|
|
@@ -4272,12 +4528,12 @@ function constraintMethods(client, kind) {
|
|
|
4272
4528
|
* stored data breaks them (see violationsOf).
|
|
4273
4529
|
* @param {string} layerId - The layer ID
|
|
4274
4530
|
* @param {string} namespace - The declaring app's namespace, e.g. "igt"
|
|
4275
|
-
* @param {
|
|
4531
|
+
* @param {LayerConstraint[]} constraints - e.g. [{type: "single-span"}, {type: "value-set", values: ["N"]}]
|
|
4276
4532
|
* @param {string} [auditMessage] - Audit message for this write
|
|
4277
4533
|
* @param {{expected?: Array<object>|null}} [options] - `expected`: the list read for this
|
|
4278
4534
|
* namespace (null when it was absent). The write is then refused with a 409 when the stored
|
|
4279
4535
|
* list differs.
|
|
4280
|
-
* @returns {Promise<{constraints:
|
|
4536
|
+
* @returns {Promise<{constraints: Record<string, LayerConstraint[]>}>} the layer's whole constraint map
|
|
4281
4537
|
*/
|
|
4282
4538
|
setConstraints: (layerId, namespace, constraints, auditMessage, options) =>
|
|
4283
4539
|
client._request("PUT", `${base(layerId)}/${namespace}`, {
|
|
@@ -4302,8 +4558,8 @@ function constraintMethods(client, kind) {
|
|
|
4302
4558
|
* The violations the given constraints would meet in this layer's stored
|
|
4303
4559
|
* data. Writes nothing.
|
|
4304
4560
|
* @param {string} layerId - The layer ID
|
|
4305
|
-
* @param {
|
|
4306
|
-
* @returns {Promise<{violations:
|
|
4561
|
+
* @param {LayerConstraint[]} constraints - The list to check
|
|
4562
|
+
* @returns {Promise<{violations: ConstraintViolation[], violationCount: number}>}
|
|
4307
4563
|
*/
|
|
4308
4564
|
checkConstraints: (layerId, constraints) =>
|
|
4309
4565
|
client._request("POST", `${base(layerId)}/check`, { body: { constraints } }),
|
|
@@ -4315,10 +4571,10 @@ function constraintMethods(client, kind) {
|
|
|
4315
4571
|
* ask. A document another user holds the lock on is left as it is and
|
|
4316
4572
|
* listed under `locked`.
|
|
4317
4573
|
* @param {string} layerId - The layer ID
|
|
4318
|
-
* @param {
|
|
4574
|
+
* @param {LayerConstraint[]} constraints - The list to repair for
|
|
4319
4575
|
* @param {string} [auditMessage] - Audit message for this write
|
|
4320
4576
|
* @param {{document?: string}} [options]
|
|
4321
|
-
* @returns {Promise<{repaired:
|
|
4577
|
+
* @returns {Promise<{repaired: ConstraintRepair[], locked: Array<{document: string, lockedBy: string}>, violations: ConstraintViolation[], violationCount: number}>}
|
|
4322
4578
|
*/
|
|
4323
4579
|
repairConstraints: (layerId, constraints, auditMessage, options) =>
|
|
4324
4580
|
client._request("POST", `${base(layerId)}/repair`, {
|
|
@@ -4340,6 +4596,7 @@ export {
|
|
|
4340
4596
|
cpSlicer,
|
|
4341
4597
|
utf16ToCp,
|
|
4342
4598
|
cpIndexOf,
|
|
4599
|
+
composeText,
|
|
4343
4600
|
} from "./codepoint.js";
|
|
4344
4601
|
export { composeTextEdits, gapsToOps, applyTextOps } from "./textEdits.js";
|
|
4345
4602
|
export {
|
|
@@ -4412,7 +4669,8 @@ export {
|
|
|
4412
4669
|
// result. See ./created.js.
|
|
4413
4670
|
export { createdId, createdIds } from "./created.js";
|
|
4414
4671
|
// UUIDv7 ids for what a client creates. See ./ids.js and the manual,
|
|
4415
|
-
// "Retrying a write".
|
|
4416
|
-
|
|
4672
|
+
// "Retrying a write". uuidv4 works where crypto.randomUUID does not (a page
|
|
4673
|
+
// served over plain HTTP from any host but localhost).
|
|
4674
|
+
export { uuidv4, uuidv7, normalizeUserId } from "./ids.js";
|
|
4417
4675
|
export { wasReplayed } from "./replayed.js";
|
|
4418
4676
|
export { MAX_BATCH_OPS };
|