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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.d.ts CHANGED
@@ -54,6 +54,10 @@ interface DiscoveredService {
54
54
  serviceName: string;
55
55
  description: string;
56
56
  extras: ServiceExtras;
57
+ /** true while the service holds an open request channel; false for previously-seen offline services. */
58
+ online: boolean;
59
+ /** ISO-8601 stamp of when the service was last seen alive, or null/undefined if never persisted. */
60
+ lastSeenAt?: string | null;
57
61
  }
58
62
 
59
63
  interface ServiceRegistration {
@@ -75,226 +79,326 @@ interface SSEConnection {
75
79
  }
76
80
 
77
81
  interface VocabLinksBundle {
78
- create(vocabItem: string, tokens: any[], metadata?: any): Promise<any>;
79
- setMetadata(id: string, body: any): Promise<any>;
80
- deleteMetadata(id: string): Promise<any>;
81
- patchMetadata(id: string, body: any): Promise<any>;
82
+ create(vocabItem: string, tokens: any[], metadata?: any, auditMessage?: string): Promise<any>;
83
+ bulkCreate(body: any[], auditMessage?: string): Promise<{ ids: string[] }>;
84
+ bulkDelete(body: any[], auditMessage?: string): Promise<void>;
85
+ setMetadata(id: string, body: any, auditMessage?: string): Promise<any>;
86
+ deleteMetadata(id: string, auditMessage?: string): Promise<any>;
87
+ patchMetadata(id: string, body: any, auditMessage?: string): Promise<any>;
82
88
  get(id: string, asOf?: string): Promise<any>;
83
- delete(id: string): Promise<any>;
89
+ delete(id: string, auditMessage?: string): Promise<any>;
84
90
  }
85
91
 
86
92
  interface VocabLayersBundle {
87
93
  get(id: string, includeItems?: boolean, asOf?: string): Promise<any>;
88
- delete(id: string): Promise<any>;
89
- update(id: string, name: string): Promise<any>;
90
- setConfig(id: string, namespace: string, configKey: string, configValue: any): Promise<any>;
91
- deleteConfig(id: string, namespace: string, configKey: string): Promise<any>;
94
+ delete(id: string, auditMessage?: string): Promise<any>;
95
+ update(id: string, name: string, auditMessage?: string): Promise<any>;
96
+ setConfig(id: string, namespace: string, configKey: string, configValue: any, auditMessage?: string): Promise<any>;
97
+ deleteConfig(id: string, namespace: string, configKey: string, auditMessage?: string): Promise<any>;
92
98
  list(asOf?: string): Promise<any[]>;
93
99
  listPage(opts?: { limit?: number; cursor?: string; asOf?: string }): Promise<Page>;
94
100
  iterPages(opts?: { pageSize?: number; asOf?: string }): AsyncGenerator<any[]>;
95
- create(name: string): Promise<any>;
96
- addMaintainer(id: string, userId: string): Promise<any>;
97
- removeMaintainer(id: string, userId: string): Promise<any>;
101
+ create(name: string, auditMessage?: string): Promise<any>;
102
+ addMaintainer(id: string, userId: string, auditMessage?: string): Promise<any>;
103
+ removeMaintainer(id: string, userId: string, auditMessage?: string): Promise<any>;
98
104
  }
99
105
 
100
106
  interface RelationsBundle {
101
- setMetadata(relationId: string, body: any): Promise<any>;
102
- deleteMetadata(relationId: string): Promise<any>;
103
- patchMetadata(relationId: string, body: any): Promise<any>;
104
- setTarget(relationId: string, spanId: string): Promise<any>;
107
+ setMetadata(relationId: string, body: any, auditMessage?: string): Promise<any>;
108
+ deleteMetadata(relationId: string, auditMessage?: string): Promise<any>;
109
+ patchMetadata(relationId: string, body: any, auditMessage?: string): Promise<any>;
110
+ setTarget(relationId: string, spanId: string, auditMessage?: string): Promise<any>;
105
111
  get(relationId: string, asOf?: string): Promise<any>;
106
- delete(relationId: string): Promise<any>;
107
- update(relationId: string, value: any): Promise<any>;
108
- setSource(relationId: string, spanId: string): Promise<any>;
109
- create(layerId: string, sourceId: string, targetId: string, value: any, metadata?: any): Promise<any>;
110
- bulkCreate(body: any[]): Promise<any>;
111
- bulkDelete(body: any[]): Promise<any>;
112
+ delete(relationId: string, auditMessage?: string): Promise<any>;
113
+ update(relationId: string, value: any, auditMessage?: string): Promise<any>;
114
+ setSource(relationId: string, spanId: string, auditMessage?: string): Promise<any>;
115
+ create(layerId: string, sourceId: string, targetId: string, value: any, metadata?: any, auditMessage?: string): Promise<any>;
116
+ bulkCreate(body: any[], auditMessage?: string): Promise<{ ids: string[] }>;
117
+ bulkDelete(body: any[], auditMessage?: string): Promise<void>;
112
118
  }
113
119
 
114
120
  interface SpanLayersBundle {
115
- setConfig(spanLayerId: string, namespace: string, configKey: string, configValue: any): Promise<any>;
116
- deleteConfig(spanLayerId: string, namespace: string, configKey: string): Promise<any>;
121
+ setConfig(spanLayerId: string, namespace: string, configKey: string, configValue: any, auditMessage?: string): Promise<any>;
122
+ deleteConfig(spanLayerId: string, namespace: string, configKey: string, auditMessage?: string): Promise<any>;
117
123
  get(spanLayerId: string, asOf?: string): Promise<any>;
118
- delete(spanLayerId: string): Promise<any>;
119
- update(spanLayerId: string, name: string): Promise<any>;
120
- create(tokenLayerId: string, name: string): Promise<any>;
121
- shift(spanLayerId: string, direction: string): Promise<any>;
124
+ delete(spanLayerId: string, auditMessage?: string): Promise<any>;
125
+ update(spanLayerId: string, name: string, auditMessage?: string): Promise<any>;
126
+ create(tokenLayerId: string, name: string, auditMessage?: string): Promise<any>;
127
+ shift(spanLayerId: string, direction: string, auditMessage?: string): Promise<any>;
122
128
  }
123
129
 
124
130
  interface SpansBundle {
125
- setTokens(spanId: string, tokens: any[]): Promise<any>;
126
- create(spanLayerId: string, tokens: any[], value: any, metadata?: any): Promise<any>;
131
+ setTokens(spanId: string, tokens: any[], auditMessage?: string): Promise<any>;
132
+ create(spanLayerId: string, tokens: any[], value: any, metadata?: any, auditMessage?: string): Promise<any>;
127
133
  get(spanId: string, asOf?: string): Promise<any>;
128
- delete(spanId: string): Promise<any>;
129
- update(spanId: string, value: any): Promise<any>;
130
- bulkCreate(body: any[]): Promise<any>;
131
- bulkDelete(body: any[]): Promise<any>;
132
- setMetadata(spanId: string, body: any): Promise<any>;
133
- deleteMetadata(spanId: string): Promise<any>;
134
- patchMetadata(spanId: string, body: any): Promise<any>;
134
+ delete(spanId: string, auditMessage?: string): Promise<any>;
135
+ update(spanId: string, value: any, auditMessage?: string): Promise<any>;
136
+ bulkCreate(body: any[], auditMessage?: string): Promise<{ ids: string[] }>;
137
+ bulkDelete(body: any[], auditMessage?: string): Promise<void>;
138
+ setMetadata(spanId: string, body: any, auditMessage?: string): Promise<any>;
139
+ deleteMetadata(spanId: string, auditMessage?: string): Promise<any>;
140
+ patchMetadata(spanId: string, body: any, auditMessage?: string): Promise<any>;
135
141
  }
136
142
 
137
143
  interface BatchBundle {
138
- submit(body: any[]): Promise<any>;
144
+ submit(body: any[], auditMessage?: string): Promise<any>;
139
145
  }
140
146
 
141
147
  interface TextsBundle {
142
- setMetadata(textId: string, body: any): Promise<any>;
143
- deleteMetadata(textId: string): Promise<any>;
144
- patchMetadata(textId: string, body: any): Promise<any>;
145
- create(textLayerId: string, documentId: string, body: string, metadata?: any): Promise<any>;
148
+ setMetadata(textId: string, body: any, auditMessage?: string): Promise<any>;
149
+ deleteMetadata(textId: string, auditMessage?: string): Promise<any>;
150
+ patchMetadata(textId: string, body: any, auditMessage?: string): Promise<any>;
151
+ create(textLayerId: string, documentId: string, body: string, metadata?: any, auditMessage?: string): Promise<any>;
146
152
  get(textId: string, asOf?: string): Promise<any>;
147
- delete(textId: string): Promise<any>;
148
- update(textId: string, body: any): Promise<any>;
153
+ delete(textId: string, auditMessage?: string): Promise<any>;
154
+ update(textId: string, body: any, auditMessage?: string): Promise<any>;
149
155
  }
150
156
 
151
157
  interface UsersBundle {
152
158
  list(asOf?: string): Promise<any[]>;
153
159
  listPage(opts?: { limit?: number; cursor?: string; asOf?: string }): Promise<Page>;
154
160
  iterPages(opts?: { pageSize?: number; asOf?: string }): AsyncGenerator<any[]>;
155
- create(username: string, password: string, isAdmin: boolean): Promise<any>;
161
+ create(username: string, password: string, isAdmin: boolean, auditMessage?: string): Promise<any>;
156
162
  audit(userId: string, startTime?: string, endTime?: string, asOf?: string): Promise<any[]>;
157
163
  get(id: string, asOf?: string): Promise<any>;
158
- delete(id: string): Promise<any>;
159
- update(id: string, password?: string, username?: string, isAdmin?: boolean): Promise<any>;
164
+ delete(id: string, auditMessage?: string): Promise<any>;
165
+ activate(id: string, auditMessage?: string): Promise<any>;
166
+ update(id: string, password?: string, username?: string, isAdmin?: boolean, auditMessage?: string): Promise<any>;
167
+ /** URL for a user's profile picture, usable as an <img> src. Null when avatarHash is explicitly null. */
168
+ avatarUrl(id: string, avatarHash?: string | null): string | null;
169
+ getAvatar(id: string): Promise<any>;
170
+ setAvatar(id: string, file: File | Blob, auditMessage?: string): Promise<any>;
171
+ deleteAvatar(id: string, auditMessage?: string): Promise<any>;
160
172
  }
161
173
 
162
174
  interface ApiTokensBundle {
163
175
  list(userId: string): Promise<any[]>;
164
176
  listPage(userId: string, opts?: { limit?: number; cursor?: string }): Promise<Page>;
165
177
  iterPages(userId: string, opts?: { pageSize?: number }): AsyncGenerator<any[]>;
166
- create(userId: string, name: string): Promise<{ id: string; name: string; token: string }>;
167
- revoke(userId: string, tokenId: string): Promise<any>;
178
+ create(userId: string, name: string, auditMessage?: string): Promise<{ id: string; name: string; token: string }>;
179
+ revoke(userId: string, tokenId: string, auditMessage?: string): Promise<any>;
180
+ }
181
+
182
+ interface Invite {
183
+ id: string;
184
+ /** "signup" | "password-reset" */
185
+ kind: string;
186
+ /** "active" | "used" | "expired" | "revoked" */
187
+ status: string;
188
+ createdBy: string;
189
+ createdAt: string;
190
+ expiresAt: string;
191
+ maxUses: number;
192
+ uses: number;
193
+ revokedAt: string | null;
194
+ note: string | null;
195
+ targetUserId: string | null;
196
+ grantAdmin: boolean;
197
+ projectId: string | null;
198
+ projectRole: string | null;
199
+ }
200
+
201
+ interface InvitePreview {
202
+ /** "signup" | "password-reset" */
203
+ kind: string;
204
+ /** "active" | "used" | "expired" | "revoked" */
205
+ status: string;
206
+ expiresAt: string;
207
+ grantAdmin: boolean;
208
+ projectName?: string;
209
+ projectRole?: string;
210
+ /** Present only for a password reset: whose account the link belongs to. */
211
+ username?: string;
212
+ }
213
+
214
+ interface CreateInviteOptions {
215
+ projectId?: string;
216
+ /** "reader" | "writer" | "maintainer" */
217
+ projectRole?: string;
218
+ grantAdmin?: boolean;
219
+ /** Makes this a password reset for that user (admin only). */
220
+ targetUserId?: string;
221
+ maxUses?: number;
222
+ ttlDays?: number;
223
+ note?: string;
224
+ }
225
+
226
+ interface InvitesBundle {
227
+ list(opts?: { projectId?: string }): Promise<Invite[]>;
228
+ listPage(opts?: { projectId?: string; limit?: number; cursor?: string }): Promise<Page>;
229
+ iterPages(opts?: { projectId?: string; pageSize?: number }): AsyncGenerator<Invite[]>;
230
+ /** The `code` is returned ONCE and is not recoverable afterward. */
231
+ create(opts?: CreateInviteOptions, auditMessage?: string): Promise<Invite & { code: string }>;
232
+ revoke(id: string, auditMessage?: string): Promise<any>;
168
233
  }
169
234
 
170
235
  interface TokenLayersBundle {
171
- shift(tokenLayerId: string, direction: string): Promise<any>;
172
- create(textLayerId: string, name: string, overlapMode?: string, parentTokenLayerId?: string): Promise<any>;
173
- setConfig(tokenLayerId: string, namespace: string, configKey: string, configValue: any): Promise<any>;
174
- deleteConfig(tokenLayerId: string, namespace: string, configKey: string): Promise<any>;
236
+ shift(tokenLayerId: string, direction: string, auditMessage?: string): Promise<any>;
237
+ create(textLayerId: string, name: string, overlapMode?: string, parentTokenLayerId?: string, auditMessage?: string): Promise<any>;
238
+ setConfig(tokenLayerId: string, namespace: string, configKey: string, configValue: any, auditMessage?: string): Promise<any>;
239
+ deleteConfig(tokenLayerId: string, namespace: string, configKey: string, auditMessage?: string): Promise<any>;
175
240
  get(tokenLayerId: string, asOf?: string): Promise<any>;
176
- delete(tokenLayerId: string): Promise<any>;
177
- update(tokenLayerId: string, name: string): Promise<any>;
241
+ delete(tokenLayerId: string, auditMessage?: string): Promise<any>;
242
+ update(tokenLayerId: string, name: string, auditMessage?: string): Promise<any>;
178
243
  }
179
244
 
180
245
  interface DocumentsBundle {
181
246
  checkLock(documentId: string, asOf?: string): Promise<any>;
182
- acquireLock(documentId: string): Promise<any>;
183
- releaseLock(documentId: string): Promise<any>;
247
+ acquireLock(documentId: string, auditMessage?: string): Promise<any>;
248
+ releaseLock(documentId: string, auditMessage?: string): Promise<any>;
184
249
  getMedia(documentId: string, asOf?: string): Promise<ArrayBuffer>;
185
- uploadMedia(documentId: string, file: File): Promise<any>;
186
- deleteMedia(documentId: string): Promise<any>;
187
- setMetadata(documentId: string, body: any): Promise<any>;
188
- deleteMetadata(documentId: string): Promise<any>;
189
- patchMetadata(documentId: string, body: any): Promise<any>;
250
+ uploadMedia(documentId: string, file: File, auditMessage?: string): Promise<any>;
251
+ deleteMedia(documentId: string, auditMessage?: string): Promise<any>;
252
+ setMetadata(documentId: string, body: any, auditMessage?: string): Promise<any>;
253
+ deleteMetadata(documentId: string, auditMessage?: string): Promise<any>;
254
+ patchMetadata(documentId: string, body: any, auditMessage?: string): Promise<any>;
190
255
  audit(documentId: string, startTime?: string, endTime?: string, asOf?: string): Promise<any[]>;
191
256
  get(documentId: string, includeBody?: boolean, asOf?: string): Promise<any>;
192
- delete(documentId: string): Promise<any>;
193
- update(documentId: string, name: string): Promise<any>;
194
- create(projectId: string, name: string, metadata?: any): Promise<any>;
257
+ delete(documentId: string, auditMessage?: string): Promise<any>;
258
+ update(documentId: string, name: string, auditMessage?: string): Promise<any>;
259
+ create(projectId: string, name: string, metadata?: any, auditMessage?: string): Promise<any>;
195
260
  }
196
261
 
197
262
  interface MessagesBundle {
198
- sendMessage(projectId: string, data: any): Promise<any>;
263
+ sendMessage(projectId: string, data: any, auditMessage?: string): Promise<any>;
199
264
  listen(projectId: string, onEvent: (eventType: string, data: any) => void | boolean, path?: string): SSEConnection;
200
- /** Discover the services currently connected to a project. `timeout` is ignored (kept for back-compat). */
201
- discoverServices(projectId: string, timeout?: number): Promise<DiscoveredService[]>;
265
+ /** Discover the services seen on a project: online ones plus previously-seen offline ones (check `online`). */
266
+ discoverServices(projectId: string): Promise<DiscoveredService[]>;
267
+ /** Forget a previously-seen (offline) service. Maintainer-only; 409 if currently connected. */
268
+ discardService(projectId: string, serviceId: string): Promise<void>;
202
269
  serve(projectId: string, serviceInfo: ServiceInfo, onServiceRequest: (data: any, responseHelper: ResponseHelper) => void, extras?: any): ServiceRegistration;
203
270
  /** Submit work to a service; streams progress to `onProgress`, resolves with the result. */
204
271
  requestService(projectId: string, serviceId: string, data: any, timeout?: number, onProgress?: (progress: any) => void): Promise<any>;
205
272
  }
206
273
 
207
274
  interface ProjectsBundle {
208
- addWriter(id: string, userId: string): Promise<any>;
209
- removeWriter(id: string, userId: string): Promise<any>;
210
- addReader(id: string, userId: string): Promise<any>;
211
- removeReader(id: string, userId: string): Promise<any>;
212
- setConfig(id: string, namespace: string, configKey: string, configValue: any): Promise<any>;
213
- deleteConfig(id: string, namespace: string, configKey: string): Promise<any>;
214
- addMaintainer(id: string, userId: string): Promise<any>;
215
- removeMaintainer(id: string, userId: string): Promise<any>;
275
+ addWriter(id: string, userId: string, auditMessage?: string): Promise<any>;
276
+ removeWriter(id: string, userId: string, auditMessage?: string): Promise<any>;
277
+ addReader(id: string, userId: string, auditMessage?: string): Promise<any>;
278
+ removeReader(id: string, userId: string, auditMessage?: string): Promise<any>;
279
+ setConfig(id: string, namespace: string, configKey: string, configValue: any, auditMessage?: string): Promise<any>;
280
+ deleteConfig(id: string, namespace: string, configKey: string, auditMessage?: string): Promise<any>;
281
+ addMaintainer(id: string, userId: string, auditMessage?: string): Promise<any>;
282
+ removeMaintainer(id: string, userId: string, auditMessage?: string): Promise<any>;
216
283
  audit(projectId: string, startTime?: string, endTime?: string, asOf?: string): Promise<any[]>;
217
- linkVocab(id: string, vocabId: string): Promise<any>;
218
- unlinkVocab(id: string, vocabId: string): Promise<any>;
284
+ linkVocab(id: string, vocabId: string, auditMessage?: string): Promise<any>;
285
+ unlinkVocab(id: string, vocabId: string, auditMessage?: string): Promise<any>;
219
286
  get(id: string, asOf?: string): Promise<any>;
220
287
  listDocuments(id: string): Promise<any[]>;
221
288
  listDocumentsPage(id: string, opts?: { limit?: number; cursor?: string }): Promise<Page>;
222
289
  iterDocuments(id: string, opts?: { pageSize?: number }): AsyncGenerator<any[]>;
223
- delete(id: string): Promise<any>;
224
- update(id: string, name: string): Promise<any>;
290
+ delete(id: string, auditMessage?: string): Promise<any>;
291
+ update(id: string, name: string, auditMessage?: string): Promise<any>;
225
292
  list(asOf?: string): Promise<any[]>;
226
293
  listPage(opts?: { limit?: number; cursor?: string; asOf?: string }): Promise<Page>;
227
294
  iterPages(opts?: { pageSize?: number; asOf?: string }): AsyncGenerator<any[]>;
228
- create(name: string): Promise<any>;
295
+ create(name: string, auditMessage?: string): Promise<any>;
229
296
  }
230
297
 
231
298
  interface TextLayersBundle {
232
- setConfig(textLayerId: string, namespace: string, configKey: string, configValue: any): Promise<any>;
233
- deleteConfig(textLayerId: string, namespace: string, configKey: string): Promise<any>;
299
+ setConfig(textLayerId: string, namespace: string, configKey: string, configValue: any, auditMessage?: string): Promise<any>;
300
+ deleteConfig(textLayerId: string, namespace: string, configKey: string, auditMessage?: string): Promise<any>;
234
301
  get(textLayerId: string, asOf?: string): Promise<any>;
235
- delete(textLayerId: string): Promise<any>;
236
- update(textLayerId: string, name: string): Promise<any>;
237
- shift(textLayerId: string, direction: string): Promise<any>;
238
- create(projectId: string, name: string): Promise<any>;
302
+ delete(textLayerId: string, auditMessage?: string): Promise<any>;
303
+ update(textLayerId: string, name: string, auditMessage?: string): Promise<any>;
304
+ shift(textLayerId: string, direction: string, auditMessage?: string): Promise<any>;
305
+ create(projectId: string, name: string, auditMessage?: string): Promise<any>;
239
306
  }
240
307
 
241
308
  interface VocabItemsBundle {
242
- setMetadata(id: string, body: any): Promise<any>;
243
- deleteMetadata(id: string): Promise<any>;
244
- patchMetadata(id: string, body: any): Promise<any>;
245
- create(vocabLayerId: string, form: string, metadata?: any): Promise<any>;
309
+ setMetadata(id: string, body: any, auditMessage?: string): Promise<any>;
310
+ deleteMetadata(id: string, auditMessage?: string): Promise<any>;
311
+ patchMetadata(id: string, body: any, auditMessage?: string): Promise<any>;
312
+ create(vocabLayerId: string, form: string, metadata?: any, auditMessage?: string): Promise<any>;
313
+ bulkCreate(body: any[], auditMessage?: string): Promise<{ ids: string[] }>;
314
+ bulkDelete(body: any[], auditMessage?: string): Promise<void>;
246
315
  get(id: string, asOf?: string): Promise<any>;
247
- delete(id: string): Promise<any>;
248
- update(id: string, form: string): Promise<any>;
316
+ delete(id: string, auditMessage?: string): Promise<any>;
317
+ update(id: string, form: string, auditMessage?: string): Promise<any>;
249
318
  }
250
319
 
251
320
  interface RelationLayersBundle {
252
- shift(relationLayerId: string, direction: string): Promise<any>;
253
- create(spanLayerId: string, name: string): Promise<any>;
254
- setConfig(relationLayerId: string, namespace: string, configKey: string, configValue: any): Promise<any>;
255
- deleteConfig(relationLayerId: string, namespace: string, configKey: string): Promise<any>;
321
+ shift(relationLayerId: string, direction: string, auditMessage?: string): Promise<any>;
322
+ create(spanLayerId: string, name: string, auditMessage?: string): Promise<any>;
323
+ setConfig(relationLayerId: string, namespace: string, configKey: string, configValue: any, auditMessage?: string): Promise<any>;
324
+ deleteConfig(relationLayerId: string, namespace: string, configKey: string, auditMessage?: string): Promise<any>;
256
325
  get(relationLayerId: string, asOf?: string): Promise<any>;
257
- delete(relationLayerId: string): Promise<any>;
258
- update(relationLayerId: string, name: string): Promise<any>;
326
+ delete(relationLayerId: string, auditMessage?: string): Promise<any>;
327
+ update(relationLayerId: string, name: string, auditMessage?: string): Promise<any>;
259
328
  }
260
329
 
261
330
  interface TokensBundle {
262
- create(tokenLayerId: string, text: string, begin: number, end: number, precedence?: number | null, metadata?: any): Promise<any>;
331
+ create(tokenLayerId: string, text: string, begin: number, end: number, precedence?: number | null, metadata?: any, auditMessage?: string): Promise<any>;
263
332
  get(tokenId: string, asOf?: string): Promise<any>;
264
- delete(tokenId: string): Promise<any>;
265
- update(tokenId: string, begin?: number, end?: number, precedence?: number | null): Promise<any>;
266
- bulkCreate(body: any[]): Promise<any>;
267
- bulkDelete(body: any[]): Promise<any>;
268
- split(tokenId: string, position: number): Promise<any>;
269
- merge(tokenId: string, otherTokenId: string): Promise<any>;
270
- shift(tokenId: string, begin?: number, end?: number): Promise<any>;
271
- setMetadata(tokenId: string, body: any): Promise<any>;
272
- deleteMetadata(tokenId: string): Promise<any>;
273
- patchMetadata(tokenId: string, body: any): Promise<any>;
333
+ delete(tokenId: string, auditMessage?: string): Promise<any>;
334
+ update(tokenId: string, begin?: number, end?: number, precedence?: number | null, auditMessage?: string): Promise<any>;
335
+ bulkCreate(body: any[], auditMessage?: string): Promise<{ ids: string[] }>;
336
+ bulkDelete(body: any[], auditMessage?: string): Promise<void>;
337
+ split(tokenId: string, position: number, auditMessage?: string): Promise<any>;
338
+ merge(tokenId: string, otherTokenId: string, auditMessage?: string): Promise<any>;
339
+ shift(tokenId: string, begin?: number, end?: number, auditMessage?: string): Promise<any>;
340
+ setMetadata(tokenId: string, body: any, auditMessage?: string): Promise<any>;
341
+ deleteMetadata(tokenId: string, auditMessage?: string): Promise<any>;
342
+ patchMetadata(tokenId: string, body: any, auditMessage?: string): Promise<any>;
274
343
  }
275
344
 
276
345
  interface PlaidClientOptions {
277
346
  /** Per-request timeout in ms (default 30000; 0 or null disables it). */
278
347
  timeout?: number | null;
348
+ /**
349
+ * Fired once when a request returns HTTP 401 (missing/expired/invalid token).
350
+ * Use it to discard the stored token and route back to login. 403 (forbidden)
351
+ * does NOT trigger it.
352
+ */
353
+ onAuthError?: ((error: Error) => void) | null;
354
+ }
355
+
356
+ export interface OperationGroupsBundle {
357
+ get(id: string): Promise<any>;
358
+ update(id: string, message: string | null): Promise<any>;
279
359
  }
280
360
 
281
361
  export declare class PlaidClient {
282
362
  constructor(baseUrl: string, token: string, options?: PlaidClientOptions);
283
363
  static login(baseUrl: string, userId: string, password: string, options?: PlaidClientOptions): Promise<PlaidClient>;
364
+ /** Build the link to hand someone for an invite code. */
365
+ static inviteUrl(appUrl: string, code: string): string;
366
+ /** Describe an invite code with no authentication (for a signup page). */
367
+ static lookupInvite(baseUrl: string, code: string, options?: PlaidClientOptions): Promise<InvitePreview>;
368
+ /** Redeem an invite code with no authentication; resolves to a logged-in client. */
369
+ static redeemInvite(
370
+ baseUrl: string,
371
+ code: string,
372
+ credentials: { username?: string; password: string },
373
+ options?: PlaidClientOptions,
374
+ ): Promise<{ client: PlaidClient; userId: string; kind: string }>;
284
375
  timeout: number | null;
376
+ /** Fired once on HTTP 401 (see PlaidClientOptions.onAuthError). */
377
+ onAuthError: ((error: Error) => void) | null;
285
378
 
286
379
  // Batch control methods
287
380
  beginBatch(): void;
288
381
  submitBatch(): Promise<any[]>;
289
382
  abortBatch(): void;
290
383
  isBatchMode(): boolean;
384
+ /** Run `fn` with a batch open, then submit atomically (or abort if `fn` throws). Resolves to the results array. */
385
+ batched(fn: () => void | Promise<void>): Promise<any[]>;
291
386
 
292
387
  // Strict mode methods
293
388
  enterStrictMode(documentId: string): void;
294
389
  exitStrictMode(): void;
295
390
 
391
+ // Logical operations (audit-log grouping). While one is open every write is
392
+ // stamped with its group id so the audit log folds them into one entry.
393
+ // Not atomic; nesting flattens into the outer operation.
394
+ operationGroup: { id: string; message: string | null } | null;
395
+ beginOperation(message: string, opts?: { id?: string }): string;
396
+ endOperation(message?: string): Promise<void>;
397
+ withOperation<T>(message: string, fn: (setMessage: (msg: string) => void) => Promise<T> | T): Promise<T>;
398
+ operationGroups: OperationGroupsBundle;
399
+
296
400
  // Query
297
- query(body: any): Promise<any>;
401
+ query(body: any, auditMessage?: string): Promise<any>;
298
402
 
299
403
  vocabLinks: VocabLinksBundle;
300
404
  vocabLayers: VocabLayersBundle;
@@ -305,6 +409,7 @@ export declare class PlaidClient {
305
409
  texts: TextsBundle;
306
410
  users: UsersBundle;
307
411
  apiTokens: ApiTokensBundle;
412
+ invites: InvitesBundle;
308
413
  tokenLayers: TokenLayersBundle;
309
414
  documents: DocumentsBundle;
310
415
  messages: MessagesBundle;
@@ -377,3 +482,50 @@ export function getServiceSummary(service: DiscoveredService): string;
377
482
  export function buildDefaultValues(schema: ServiceParam[]): Record<string, any>;
378
483
  /** Coerce/validate raw form values against the schema. */
379
484
  export function coerceParamValues(schema: ServiceParam[], raw: Record<string, any>): { values: Record<string, any>; errors: Record<string, string> };
485
+
486
+ // --- Provenance ---------------------------------------------------------------
487
+ // Cross-app convention for machine-provided vs human-labeled information,
488
+ // expressed as flat metadata keys on annotation entities. Absent keys = human;
489
+ // { prov: 'inferred', provSource } = machine-made, unverified;
490
+ // + { provConfirmed: true } = machine-made, human-verified. Machine writers may
491
+ // replace unverified machine material but must never touch human/verified
492
+ // material without an explicit overwrite opt-in; any human edit verifies.
493
+ // See the manual, "Provenance".
494
+ type ProvState = 'human' | 'machine' | 'verified';
495
+ export const PROV: {
496
+ readonly key: 'prov';
497
+ readonly sourceKey: 'provSource';
498
+ readonly confirmedKey: 'provConfirmed';
499
+ readonly probKey: 'provProb';
500
+ readonly detailKey: 'provDetail';
501
+ readonly INFERRED: 'inferred';
502
+ };
503
+ export const PROV_STATES: {
504
+ readonly HUMAN: 'human';
505
+ readonly MACHINE: 'machine';
506
+ readonly VERIFIED: 'verified';
507
+ };
508
+ /** Optional prediction extras: prob = a probability in [0,1] for the chosen value
509
+ * (flat + queryable; omit unless it honestly is one); detail = an open map of
510
+ * producer extras (top-k alternatives, model version, raw scores; keep it small).
511
+ * Both describe the ORIGINAL prediction — check provConfirmed before presenting
512
+ * provProb as confidence in the current value. */
513
+ interface ProvExtras { prob?: number; detail?: Record<string, any> }
514
+ /** The metadata fragment a machine writer merges into everything it creates. */
515
+ export function stampInferred(source: string, extras?: ProvExtras):
516
+ { prov: 'inferred'; provSource: string; provProb?: number; provDetail?: Record<string, any> };
517
+ /** stampInferred + provConfirmed — for machine material born verified (e.g. imports with upstream approval). */
518
+ export function confirmedInferred(source: string, extras?: ProvExtras):
519
+ { prov: 'inferred'; provSource: string; provConfirmed: true; provProb?: number; provDetail?: Record<string, any> };
520
+ /** Classify an entity's metadata into one of the three provenance states. */
521
+ export function provState(metadata: object | null | undefined): ProvState;
522
+ /** The verifying fragment, { provConfirmed: true }: PATCH it over existing metadata. */
523
+ export const PROV_CONFIRMED: { readonly provConfirmed: true };
524
+ /** Machine-made and not yet human-verified (needs review, replaceable, confirmable). */
525
+ export function isMachine(metadata: object | null | undefined): boolean;
526
+ /** Whether a machine writer must leave this entity alone (human or verified). !isMachine. */
527
+ export function isProtected(metadata: object | null | undefined): boolean;
528
+ /** The fragment a HUMAN edit should merge in: PROV_CONFIRMED iff machine-unverified, else null. */
529
+ export function verifyOnEdit(metadata: object | null | undefined): { readonly provConfirmed: true } | null;
530
+ /** Canonical provSource for a service: 'service:<serviceId>'. */
531
+ export function serviceSource(serviceId: string): string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@larc-iu/plaid-client",
3
- "version": "0.1.0-alpha.9",
3
+ "version": "0.2.0-alpha.1",
4
4
  "description": "JavaScript client for the Plaid annotation API",
5
5
  "type": "module",
6
6
  "repository": {
package/src/http.js CHANGED
@@ -94,6 +94,9 @@ export function timeoutSignal(timeout) {
94
94
  * skipResponseTransform - Return raw parsed JSON (no transformResponse)
95
95
  * noAuth - Skip Authorization header
96
96
  * binaryResponse - Return arrayBuffer instead of JSON/text
97
+ * timeout - Per-request timeout in ms overriding client.timeout
98
+ * for this call (0/null disables). Used for known-long
99
+ * ops like project delete.
97
100
  */
98
101
  export async function makeRequest(client, method, path, options = {}) {
99
102
  const {
@@ -105,6 +108,8 @@ export async function makeRequest(client, method, path, options = {}) {
105
108
  skipResponseTransform,
106
109
  noAuth,
107
110
  binaryResponse,
111
+ auditMessage,
112
+ timeout,
108
113
  } = options;
109
114
 
110
115
  // Build URL
@@ -135,16 +140,44 @@ export async function makeRequest(client, method, path, options = {}) {
135
140
  requestBody = transformRequest(body);
136
141
  }
137
142
 
138
- // Strict mode: append document-version for non-GET requests
139
- if (client.strictModeDocumentId && method !== 'GET') {
143
+ // Strict mode: append document-version for non-GET requests.
144
+ // Inside a batch, stamp ONLY the first write: batches run atomically
145
+ // server-side, so a version check on the first op gives whole-batch OCC
146
+ // semantics, while stamping every op would 409 the second op against the
147
+ // version bump the first op itself caused (every queued op captures the
148
+ // same pre-batch version).
149
+ if (client.strictModeDocumentId && method !== 'GET'
150
+ && !(client.isBatching && client.batchVersionStamped)) {
140
151
  const docId = client.strictModeDocumentId;
141
152
  if (client.documentVersions[docId]) {
142
153
  const docVersion = client.documentVersions[docId];
143
154
  const separator = url.includes('?') ? '&' : '?';
144
155
  url += `${separator}document-version=${encodeURIComponent(docVersion)}`;
156
+ if (client.isBatching) client.batchVersionStamped = true;
145
157
  }
146
158
  }
147
159
 
160
+ // Per-call custom audit-log message (overrides the auto-generated
161
+ // description of THIS write). Unlike document-version this has no OCC
162
+ // self-conflict, so it is stamped on every queued batch op, not just the
163
+ // first. The server templates `{param}` placeholders against the endpoint's
164
+ // own path/query/body params.
165
+ if (auditMessage && method !== 'GET') {
166
+ const separator = url.includes('?') ? '&' : '?';
167
+ url += `${separator}audit-message=${encodeURIComponent(auditMessage)}`;
168
+ }
169
+
170
+ // Logical-operation group (see client.beginOperation): stamp every write
171
+ // with the group id; the message rides along too so the server can label
172
+ // the group lazily on whichever tagged write lands first.
173
+ if (client.operationGroup && method !== 'GET') {
174
+ const group = client.operationGroup;
175
+ const separator = url.includes('?') ? '&' : '?';
176
+ url += `${separator}group-id=${encodeURIComponent(group.id)}`;
177
+ if (group.message) url += `&group-message=${encodeURIComponent(group.message)}`;
178
+ group.written = true;
179
+ }
180
+
148
181
  // Batch mode
149
182
  if (client.isBatching) {
150
183
  if (noBatch) {
@@ -174,14 +207,22 @@ export async function makeRequest(client, method, path, options = {}) {
174
207
  if (requestBody !== undefined) {
175
208
  fetchOptions.body = formData ? requestBody : JSON.stringify(requestBody);
176
209
  }
177
- const signal = timeoutSignal(client.timeout);
210
+ const signal = timeoutSignal(timeout !== undefined ? timeout : client.timeout);
178
211
  if (signal) fetchOptions.signal = signal;
179
212
 
180
213
  try {
181
214
  const response = await fetch(url, fetchOptions);
182
215
 
183
216
  if (!response.ok) {
184
- throw makeHttpError(response, await parseErrorBody(response), url, method);
217
+ const error = makeHttpError(response, await parseErrorBody(response), url, method);
218
+ // 401 means the token is missing/expired/invalid. Fire the app's auth-error
219
+ // handler once (it discards the token and routes back to login). 403
220
+ // (forbidden — authenticated but not permitted) deliberately does NOT.
221
+ if (response.status === 401 && typeof client.onAuthError === 'function' && !client._authErrorFired) {
222
+ client._authErrorFired = true;
223
+ try { client.onAuthError(error); } catch (_) { /* handler must not mask the original error */ }
224
+ }
225
+ throw error;
185
226
  }
186
227
 
187
228
  // Binary response (getMedia)