@larc-iu/plaid-client 0.2.0-alpha.29 → 0.2.0-alpha.30
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/package.json +3 -2
- package/src/apiAnnotations.d.ts +508 -0
- package/src/apiAnnotations.js +543 -0
- package/src/apiDocuments.d.ts +569 -0
- package/src/apiDocuments.js +551 -0
- package/src/apiLayers.d.ts +369 -0
- package/src/apiLayers.js +222 -0
- package/src/apiMessages.d.ts +293 -0
- package/src/apiMessages.js +265 -0
- package/src/apiPeople.d.ts +626 -0
- package/src/apiPeople.js +698 -0
- package/src/apiProject.d.ts +761 -0
- package/src/apiProject.js +774 -0
- package/src/apiServer.d.ts +455 -0
- package/src/apiServer.js +422 -0
- package/src/apiVocab.d.ts +456 -0
- package/src/apiVocab.js +425 -0
- package/src/batch.d.ts +54 -0
- package/src/batch.js +323 -0
- package/src/client.d.ts +1321 -0
- package/src/client.js +743 -0
- package/src/constraints.d.ts +8 -0
- package/src/constraints.js +14 -0
- package/src/documentLock.d.ts +18 -4
- package/src/documentLock.js +43 -9
- package/src/entryForms.d.ts +63 -0
- package/src/entryForms.js +152 -0
- package/src/events.js +2 -1
- package/src/families.d.ts +349 -0
- package/src/families.js +396 -0
- package/src/http.d.ts +39 -18
- package/src/http.js +127 -87
- package/src/index.d.ts +90 -4557
- package/src/index.js +113 -5172
- package/src/operations.d.ts +36 -0
- package/src/operations.js +164 -0
- package/src/provenance.d.ts +47 -4
- package/src/provenance.js +168 -12
- package/src/roles.d.ts +39 -0
- package/src/roles.js +44 -0
- package/src/serviceSchema.d.ts +19 -13
- package/src/serviceSchema.js +30 -15
- package/src/services.d.ts +20 -3
- package/src/services.js +45 -8
- package/src/sse.js +10 -1
- package/src/testing.d.ts +128 -0
- package/src/testing.js +379 -0
- package/src/types.d.ts +867 -0
- package/src/types.js +663 -0
package/src/serviceSchema.d.ts
CHANGED
|
@@ -22,6 +22,9 @@
|
|
|
22
22
|
* @property {"Sentence" | "Word" | "Morpheme"} [scope] `field` only: the
|
|
23
23
|
* scope of the project's annotation fields the value names one of. A
|
|
24
24
|
* `field` value is a string everywhere else.
|
|
25
|
+
* @property {string} [role] `field` only: the lexicon role whose paired field,
|
|
26
|
+
* or the sentence role whose field, fills the parameter when nothing else
|
|
27
|
+
* does.
|
|
25
28
|
*/
|
|
26
29
|
/**
|
|
27
30
|
* A service's standardized self-description (lives in `extras`).
|
|
@@ -106,17 +109,9 @@ export function getServiceSummary(service: {
|
|
|
106
109
|
* @returns {Record<string, any>} { [key]: defaultValue }
|
|
107
110
|
*/
|
|
108
111
|
export function buildDefaultValues(schema: ServiceParam[]): Record<string, any>;
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
* validation errors keyed by param key. Unknown keys in `raw` are dropped.
|
|
113
|
-
* @param {ServiceParam[]} schema getParamSchema(service)
|
|
114
|
-
* @param {Record<string, any>} raw current form values
|
|
115
|
-
* @returns {{values: Record<string, any>, errors: Record<string, string>}}
|
|
116
|
-
*/
|
|
117
|
-
export function coerceParamValues(schema: ServiceParam[], raw: Record<string, any>): {
|
|
118
|
-
values: Record<string, any>;
|
|
119
|
-
errors: Record<string, string>;
|
|
112
|
+
export function coerceParamValues(schema: any, raw: any): {
|
|
113
|
+
values: {};
|
|
114
|
+
errors: {};
|
|
120
115
|
};
|
|
121
116
|
/**
|
|
122
117
|
* Service self-description: tasks, summary, and a parameter schema.
|
|
@@ -143,13 +138,18 @@ export function coerceParamValues(schema: ServiceParam[], raw: Record<string, an
|
|
|
143
138
|
* options?: [{value, label}], // enum / multiselect
|
|
144
139
|
* min?, max?, step?, slider?, // number (slider: drag, don't type)
|
|
145
140
|
* placeholder?, multiline?, // string
|
|
146
|
-
* scope? }
|
|
141
|
+
* scope?, role? } // field: 'Sentence' | 'Word' | 'Morpheme'
|
|
147
142
|
* ]
|
|
148
143
|
* }
|
|
149
144
|
*
|
|
150
145
|
* A `field` parameter names one of the project's annotation fields at its
|
|
151
146
|
* `scope`. A UI that knows the project offers those fields to choose from; to
|
|
152
|
-
* everything here, and to a UI that does not, it is a string.
|
|
147
|
+
* everything here, and to a UI that does not, it is a string. Its optional
|
|
148
|
+
* `role` names a lexicon role ("gloss") or, at Sentence scope, a sentence
|
|
149
|
+
* field's role ("translation", "literalTranslation", "note"): a UI that knows
|
|
150
|
+
* the project fills the parameter with the one field at `scope` whose stored
|
|
151
|
+
* Lexicon field holds that role, or whose stored role it is. A field is never
|
|
152
|
+
* chosen by its name.
|
|
153
153
|
*
|
|
154
154
|
* A parameter's `key` is a string VALUE, so it passes over the wire verbatim;
|
|
155
155
|
* the UI sends `{ [param.key]: value }` in the request data. Declare each `key`
|
|
@@ -265,6 +265,12 @@ export type ServiceParam = {
|
|
|
265
265
|
* `field` value is a string everywhere else.
|
|
266
266
|
*/
|
|
267
267
|
scope?: "Sentence" | "Word" | "Morpheme";
|
|
268
|
+
/**
|
|
269
|
+
* `field` only: the lexicon role whose paired field,
|
|
270
|
+
* or the sentence role whose field, fills the parameter when nothing else
|
|
271
|
+
* does.
|
|
272
|
+
*/
|
|
273
|
+
role?: string;
|
|
268
274
|
};
|
|
269
275
|
/**
|
|
270
276
|
* A service's standardized self-description (lives in `extras`).
|
package/src/serviceSchema.js
CHANGED
|
@@ -23,13 +23,18 @@
|
|
|
23
23
|
* options?: [{value, label}], // enum / multiselect
|
|
24
24
|
* min?, max?, step?, slider?, // number (slider: drag, don't type)
|
|
25
25
|
* placeholder?, multiline?, // string
|
|
26
|
-
* scope? }
|
|
26
|
+
* scope?, role? } // field: 'Sentence' | 'Word' | 'Morpheme'
|
|
27
27
|
* ]
|
|
28
28
|
* }
|
|
29
29
|
*
|
|
30
30
|
* A `field` parameter names one of the project's annotation fields at its
|
|
31
31
|
* `scope`. A UI that knows the project offers those fields to choose from; to
|
|
32
|
-
* everything here, and to a UI that does not, it is a string.
|
|
32
|
+
* everything here, and to a UI that does not, it is a string. Its optional
|
|
33
|
+
* `role` names a lexicon role ("gloss") or, at Sentence scope, a sentence
|
|
34
|
+
* field's role ("translation", "literalTranslation", "note"): a UI that knows
|
|
35
|
+
* the project fills the parameter with the one field at `scope` whose stored
|
|
36
|
+
* Lexicon field holds that role, or whose stored role it is. A field is never
|
|
37
|
+
* chosen by its name.
|
|
33
38
|
*
|
|
34
39
|
* A parameter's `key` is a string VALUE, so it passes over the wire verbatim;
|
|
35
40
|
* the UI sends `{ [param.key]: value }` in the request data. Declare each `key`
|
|
@@ -117,6 +122,9 @@ export const TASKS = Object.freeze({
|
|
|
117
122
|
* @property {"Sentence" | "Word" | "Morpheme"} [scope] `field` only: the
|
|
118
123
|
* scope of the project's annotation fields the value names one of. A
|
|
119
124
|
* `field` value is a string everywhere else.
|
|
125
|
+
* @property {string} [role] `field` only: the lexicon role whose paired field,
|
|
126
|
+
* or the sentence role whose field, fills the parameter when nothing else
|
|
127
|
+
* does.
|
|
120
128
|
*/
|
|
121
129
|
|
|
122
130
|
/**
|
|
@@ -255,6 +263,20 @@ export function buildDefaultValues(schema) {
|
|
|
255
263
|
* @param {Record<string, any>} raw current form values
|
|
256
264
|
* @returns {{values: Record<string, any>, errors: Record<string, string>}}
|
|
257
265
|
*/
|
|
266
|
+
// A decimal number as a person types one: an optional sign, digits with an
|
|
267
|
+
// optional fraction (or a bare fraction), an optional exponent, with spaces
|
|
268
|
+
// around it allowed. ASCII whitespace only, as in Python (each language's \s
|
|
269
|
+
// holds characters the other's lacks).
|
|
270
|
+
const DECIMAL = /^[ \t\n\v\f\r]*[+-]?(?:\d+\.?\d*|\.\d+)(?:[eE][+-]?\d+)?[ \t\n\v\f\r]*$/;
|
|
271
|
+
|
|
272
|
+
/** `v` as a finite number when it is one or a decimal string, else null. */
|
|
273
|
+
function numberOf(v) {
|
|
274
|
+
let n = null;
|
|
275
|
+
if (typeof v === "number") n = v;
|
|
276
|
+
else if (typeof v === "string" && DECIMAL.test(v)) n = Number(v);
|
|
277
|
+
return n !== null && Number.isFinite(n) ? n : null;
|
|
278
|
+
}
|
|
279
|
+
|
|
258
280
|
export function coerceParamValues(schema, raw) {
|
|
259
281
|
const values = {};
|
|
260
282
|
const errors = {};
|
|
@@ -267,19 +289,12 @@ export function coerceParamValues(schema, raw) {
|
|
|
267
289
|
|
|
268
290
|
switch (param.type) {
|
|
269
291
|
case "number": {
|
|
270
|
-
//
|
|
271
|
-
//
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
(typeof v === "string" && v.trim() === "")
|
|
277
|
-
) {
|
|
278
|
-
n = defaultForParam(param);
|
|
279
|
-
} else {
|
|
280
|
-
n = typeof v === "number" ? v : Number(v);
|
|
281
|
-
if (Number.isNaN(n)) n = defaultForParam(param);
|
|
282
|
-
}
|
|
292
|
+
// A finite number, or a string holding a decimal one; anything else
|
|
293
|
+
// (blank, a boolean, a list, hex, an underscore, Infinity, a value too
|
|
294
|
+
// large to be finite) is the param's default. The Python client's
|
|
295
|
+
// `coerce` reads the same rule.
|
|
296
|
+
let n = numberOf(v);
|
|
297
|
+
if (n === null) n = defaultForParam(param);
|
|
283
298
|
if (typeof param.min === "number") n = Math.max(param.min, n);
|
|
284
299
|
if (typeof param.max === "number") n = Math.min(param.max, n);
|
|
285
300
|
v = n;
|
package/src/services.d.ts
CHANGED
|
@@ -38,12 +38,15 @@ export function serviceErrorMessage(error: any, serviceName?: string, secrets?:
|
|
|
38
38
|
* it, as the caller sees it: `runnerName` (the runner's display name),
|
|
39
39
|
* `runByYou`, and `servesYou`, whether it would take the caller's requests on
|
|
40
40
|
* this project. A delegating service serves members other than its runner
|
|
41
|
-
* only where the runner is a maintainer or an admin.
|
|
42
|
-
*
|
|
41
|
+
* only where the runner is a maintainer or an admin. Every entry whose id an
|
|
42
|
+
* account holds gives its display name in `claimedByName`. An admin also gets
|
|
43
|
+
* the account in `claimedBy` (see `releaseService`), and an entry with
|
|
44
|
+
* `seen: false` for each held id whose registration was forgotten. Goes over
|
|
45
|
+
* the wire even while a batch is open on the client.
|
|
43
46
|
*
|
|
44
47
|
* @param {Object} client - PlaidClient instance
|
|
45
48
|
* @param {string} projectId - Project UUID
|
|
46
|
-
* @returns {Promise<Array>} [{serviceId, serviceName, description, extras, online, lastSeenAt, runnerName, runByYou, servesYou}]
|
|
49
|
+
* @returns {Promise<Array>} [{serviceId, serviceName, description, extras, online, lastSeenAt, runnerName, runByYou, servesYou, claimedByName, claimedBy, seen}]
|
|
47
50
|
*/
|
|
48
51
|
export function discoverServices(client: any, projectId: string): Promise<any[]>;
|
|
49
52
|
/**
|
|
@@ -57,6 +60,20 @@ export function discoverServices(client: any, projectId: string): Promise<any[]>
|
|
|
57
60
|
* @returns {Promise<void>}
|
|
58
61
|
*/
|
|
59
62
|
export function discardService(client: any, projectId: string, serviceId: string): Promise<void>;
|
|
63
|
+
/**
|
|
64
|
+
* Release a service id from the account that first registered it on the
|
|
65
|
+
* project. A service id belongs to that account, and the server refuses any
|
|
66
|
+
* other account's registration (403) until an admin releases it. The next
|
|
67
|
+
* account to register it then claims it. Deactivating the account releases
|
|
68
|
+
* every id it holds. Admin-only; 409 while the service is connected, 404 when
|
|
69
|
+
* no account holds it.
|
|
70
|
+
*
|
|
71
|
+
* @param {Object} client - PlaidClient instance
|
|
72
|
+
* @param {string} projectId - Project UUID
|
|
73
|
+
* @param {string} serviceId - Service ID to release
|
|
74
|
+
* @returns {Promise<void>}
|
|
75
|
+
*/
|
|
76
|
+
export function releaseService(client: any, projectId: string, serviceId: string): Promise<void>;
|
|
60
77
|
/**
|
|
61
78
|
* POST a progress, result or error event for an in-flight request; the server
|
|
62
79
|
* relays it to the waiting requester. The Python twin is `_report_event`.
|
package/src/services.js
CHANGED
|
@@ -37,9 +37,12 @@ export const UNKNOWN_OUTCOME =
|
|
|
37
37
|
/** The server was never reached, so nothing was sent. */
|
|
38
38
|
export const UNREACHABLE = 'The Plaid server could not be reached.';
|
|
39
39
|
|
|
40
|
-
// A few reads travel as a POST,
|
|
41
|
-
//
|
|
42
|
-
|
|
40
|
+
// A few reads travel as a POST (a query, a token count, a layer rule check,
|
|
41
|
+
// the values a rule would refuse, signing in, looking an invite up), and saved
|
|
42
|
+
// nothing either way. The Python twin and plaid-ui's errors.js keep the same
|
|
43
|
+
// list (readPosts.test.js holds the three equal).
|
|
44
|
+
const READ_POSTS =
|
|
45
|
+
/\/api\/v1\/(?:query|query\/token-counts|login|invites\/lookup|(?:token|span|relation)-layers\/[^/?#]+\/constraints\/(?:check|refused-values))(?:[?#]|$)/;
|
|
43
46
|
|
|
44
47
|
// Node's fetch (undici) names a connection that never opened by its code: a
|
|
45
48
|
// refused port, a name that did not resolve, a connect timeout. Nothing was
|
|
@@ -136,12 +139,15 @@ export function serviceErrorMessage(error, serviceName = '', secrets = []) {
|
|
|
136
139
|
* it, as the caller sees it: `runnerName` (the runner's display name),
|
|
137
140
|
* `runByYou`, and `servesYou`, whether it would take the caller's requests on
|
|
138
141
|
* this project. A delegating service serves members other than its runner
|
|
139
|
-
* only where the runner is a maintainer or an admin.
|
|
140
|
-
*
|
|
142
|
+
* only where the runner is a maintainer or an admin. Every entry whose id an
|
|
143
|
+
* account holds gives its display name in `claimedByName`. An admin also gets
|
|
144
|
+
* the account in `claimedBy` (see `releaseService`), and an entry with
|
|
145
|
+
* `seen: false` for each held id whose registration was forgotten. Goes over
|
|
146
|
+
* the wire even while a batch is open on the client.
|
|
141
147
|
*
|
|
142
148
|
* @param {Object} client - PlaidClient instance
|
|
143
149
|
* @param {string} projectId - Project UUID
|
|
144
|
-
* @returns {Promise<Array>} [{serviceId, serviceName, description, extras, online, lastSeenAt, runnerName, runByYou, servesYou}]
|
|
150
|
+
* @returns {Promise<Array>} [{serviceId, serviceName, description, extras, online, lastSeenAt, runnerName, runByYou, servesYou, claimedByName, claimedBy, seen}]
|
|
145
151
|
*/
|
|
146
152
|
export function discoverServices(client, projectId) {
|
|
147
153
|
return client._request('GET', `/api/v1/projects/${projectId}/services`);
|
|
@@ -165,6 +171,27 @@ export function discardService(client, projectId, serviceId) {
|
|
|
165
171
|
});
|
|
166
172
|
}
|
|
167
173
|
|
|
174
|
+
/**
|
|
175
|
+
* Release a service id from the account that first registered it on the
|
|
176
|
+
* project. A service id belongs to that account, and the server refuses any
|
|
177
|
+
* other account's registration (403) until an admin releases it. The next
|
|
178
|
+
* account to register it then claims it. Deactivating the account releases
|
|
179
|
+
* every id it holds. Admin-only; 409 while the service is connected, 404 when
|
|
180
|
+
* no account holds it.
|
|
181
|
+
*
|
|
182
|
+
* @param {Object} client - PlaidClient instance
|
|
183
|
+
* @param {string} projectId - Project UUID
|
|
184
|
+
* @param {string} serviceId - Service ID to release
|
|
185
|
+
* @returns {Promise<void>}
|
|
186
|
+
*/
|
|
187
|
+
export function releaseService(client, projectId, serviceId) {
|
|
188
|
+
// outOfBand: the registry is not project data (see the note at the top of
|
|
189
|
+
// http.js).
|
|
190
|
+
return client._request('DELETE', `/api/v1/projects/${projectId}/services/${encodeURIComponent(serviceId)}/owner`, {
|
|
191
|
+
outOfBand: true,
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
|
|
168
195
|
/**
|
|
169
196
|
* POST a progress, result or error event for an in-flight request; the server
|
|
170
197
|
* relays it to the waiting requester. The Python twin is `_report_event`.
|
|
@@ -430,7 +457,14 @@ export function serve(client, projectId, serviceInfo, onServiceRequest, extras =
|
|
|
430
457
|
// What reaches the requester is the sanitized half: the raw message
|
|
431
458
|
// names the endpoint the client called, which is the operator's
|
|
432
459
|
// business. The console keeps the whole error.
|
|
433
|
-
|
|
460
|
+
// Somebody else holding the document is a refusal a service expects,
|
|
461
|
+
// which the lock acquire words itself (from the server's 423): one
|
|
462
|
+
// line, not the error and its cause.
|
|
463
|
+
if (error?.status === 423) {
|
|
464
|
+
console.error(`Service ${serviceId} failed request ${requestId}: ${error.message}`);
|
|
465
|
+
} else {
|
|
466
|
+
console.error(`Service ${serviceId} failed request ${requestId}:`, error);
|
|
467
|
+
}
|
|
434
468
|
responseHelper.error(serviceErrorMessage(error, serviceName));
|
|
435
469
|
}
|
|
436
470
|
};
|
|
@@ -468,7 +502,10 @@ export function serve(client, projectId, serviceInfo, onServiceRequest, extras =
|
|
|
468
502
|
if (PERMANENT_STATUSES.has(status)) {
|
|
469
503
|
noteDisconnected();
|
|
470
504
|
serviceRegistration.stop();
|
|
471
|
-
|
|
505
|
+
// The server's reason when it gave one (a service id another
|
|
506
|
+
// account holds says whose it is).
|
|
507
|
+
const why = connection.error?.responseData?.error;
|
|
508
|
+
report('stopped', typeof why === 'string' ? `HTTP ${status}: ${why}` : `HTTP ${status}`);
|
|
472
509
|
return;
|
|
473
510
|
}
|
|
474
511
|
noteDisconnected();
|
package/src/sse.js
CHANGED
|
@@ -145,8 +145,17 @@ export function createSSEConnection(client, projectId, onEvent, path) {
|
|
|
145
145
|
// takes over.
|
|
146
146
|
console.warn('Service registration rejected (409): another instance of this service is already connected; will retry');
|
|
147
147
|
}
|
|
148
|
-
|
|
148
|
+
// A refusal says why in its body (`{error}`), as on every other route.
|
|
149
|
+
let said = null;
|
|
150
|
+
try {
|
|
151
|
+
said = await response.json();
|
|
152
|
+
} catch {
|
|
153
|
+
said = null;
|
|
154
|
+
}
|
|
155
|
+
const why = typeof said?.error === 'string' ? `: ${said.error}` : '';
|
|
156
|
+
const refused = new Error(`HTTP ${response.status} ${response.statusText}${why}`);
|
|
149
157
|
refused.status = response.status;
|
|
158
|
+
if (said && typeof said === 'object') refused.responseData = said;
|
|
150
159
|
throw refused;
|
|
151
160
|
}
|
|
152
161
|
|
package/src/testing.d.ts
ADDED
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A request as `answer` is asked it: the bundle call that made it (`kind` and
|
|
3
|
+
* `args`), and the request as the server reads it.
|
|
4
|
+
* @typedef {{kind?: string, args: any[], method: string, path: string,
|
|
5
|
+
* query: Record<string, string>, body: any, batched: boolean}} FakeRequest
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* A round trip as `requests` holds it and `onRequest` hears it: a request,
|
|
9
|
+
* or a batch request with its `operations`.
|
|
10
|
+
* @typedef {{method: string, path: string, query: Record<string, string>, body: any,
|
|
11
|
+
* kind?: string, args?: any[], operations?: object[]}} RecordedRequest
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* An error as the client throws it for a refusal: `status`, and the
|
|
15
|
+
* server's answer as `responseData`.
|
|
16
|
+
* @param {number} status
|
|
17
|
+
* @param {object} [responseData]
|
|
18
|
+
* @returns {Error & {status: number, responseData: object}}
|
|
19
|
+
*/
|
|
20
|
+
export function refusal(status: number, responseData?: object): Error & {
|
|
21
|
+
status: number;
|
|
22
|
+
responseData: object;
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* What a request is answered with when `answer` gives nothing: the id a
|
|
26
|
+
* create minted (or a new one), the ids of a bulk create, an empty page for a
|
|
27
|
+
* read, and `{}` for anything else.
|
|
28
|
+
* @param {{kind?: string, method: string, body?: any}} request
|
|
29
|
+
* @returns {object}
|
|
30
|
+
*/
|
|
31
|
+
export function defaultAnswer({ kind, method, body }: {
|
|
32
|
+
kind?: string;
|
|
33
|
+
method: string;
|
|
34
|
+
body?: any;
|
|
35
|
+
}): object;
|
|
36
|
+
/**
|
|
37
|
+
* A real PlaidClient on a recording transport (see the module's note).
|
|
38
|
+
*
|
|
39
|
+
* `answer(request)` answers each request, `request` being `{kind, args,
|
|
40
|
+
* method, path, query, body, batched}`: the bundle call that made it (`kind`
|
|
41
|
+
* and `args`, any batch refs in them filled in, undefined for a request no
|
|
42
|
+
* bundle call made), and the request as the server reads it. It returns the
|
|
43
|
+
* answer as the client hands it back (camelCase), or a promise of it, or
|
|
44
|
+
* undefined for `defaultAnswer`'s. To refuse, it throws (see `refusal`). A
|
|
45
|
+
* refusal of any op of a batch refuses the whole batch, as the server's
|
|
46
|
+
* transaction does.
|
|
47
|
+
*
|
|
48
|
+
* @param {{answer?: (request: FakeRequest) => any,
|
|
49
|
+
* onRequest?: (request: RecordedRequest) => void, baseUrl?: string}} [options]
|
|
50
|
+
* @returns {PlaidClient & {calls: Array<{kind: string, args: any[]}>,
|
|
51
|
+
* requests: RecordedRequest[], operations: Array<{message: string, kind?: string, ref?: string}>}}
|
|
52
|
+
*/
|
|
53
|
+
export function fakeClient({ answer, onRequest, baseUrl, }?: {
|
|
54
|
+
answer?: (request: FakeRequest) => any;
|
|
55
|
+
onRequest?: (request: RecordedRequest) => void;
|
|
56
|
+
baseUrl?: string;
|
|
57
|
+
}): PlaidClient & {
|
|
58
|
+
calls: Array<{
|
|
59
|
+
kind: string;
|
|
60
|
+
args: any[];
|
|
61
|
+
}>;
|
|
62
|
+
requests: RecordedRequest[];
|
|
63
|
+
operations: Array<{
|
|
64
|
+
message: string;
|
|
65
|
+
kind?: string;
|
|
66
|
+
ref?: string;
|
|
67
|
+
}>;
|
|
68
|
+
};
|
|
69
|
+
/**
|
|
70
|
+
* Runs `f` and gives its value and the milliseconds it took. With `warm`,
|
|
71
|
+
* runs it that many times first, untimed, so the engine has compiled it.
|
|
72
|
+
* With `runs`, times that many runs and keeps the quickest, which a pause for
|
|
73
|
+
* garbage collection or another process touches least. Only for an `f` that
|
|
74
|
+
* can run again.
|
|
75
|
+
* @template T
|
|
76
|
+
* @param {() => T} f
|
|
77
|
+
* @param {{warm?: number, runs?: number}} [options]
|
|
78
|
+
* @returns {[T, number]}
|
|
79
|
+
*/
|
|
80
|
+
export function timed<T>(f: () => T, { warm, runs }?: {
|
|
81
|
+
warm?: number;
|
|
82
|
+
runs?: number;
|
|
83
|
+
}): [T, number];
|
|
84
|
+
/**
|
|
85
|
+
* Throws unless `bigMs` is under `factor` times `smallMs`, two cases timed on
|
|
86
|
+
* the same machine in the same run. A loaded runner slows both, so the bound
|
|
87
|
+
* holds where a fixed number of milliseconds fails. Pick the cases so that
|
|
88
|
+
* the fault the test guards against grows the ratio well past `factor`: a
|
|
89
|
+
* scan of every row per row goes from 10 to 100 when the big case is ten
|
|
90
|
+
* times the small one. `smallMs` counts as at least `floorMs` (default 1),
|
|
91
|
+
* so a case too quick to time cannot make the bound nothing.
|
|
92
|
+
* @param {number} factor
|
|
93
|
+
* @param {number} smallMs
|
|
94
|
+
* @param {number} bigMs
|
|
95
|
+
* @param {{floorMs?: number, label?: string}} [options]
|
|
96
|
+
* @returns {number} `bigMs`
|
|
97
|
+
*/
|
|
98
|
+
export function withinFactorOf(factor: number, smallMs: number, bigMs: number, { floorMs, label }?: {
|
|
99
|
+
floorMs?: number;
|
|
100
|
+
label?: string;
|
|
101
|
+
}): number;
|
|
102
|
+
/**
|
|
103
|
+
* A request as `answer` is asked it: the bundle call that made it (`kind` and
|
|
104
|
+
* `args`), and the request as the server reads it.
|
|
105
|
+
*/
|
|
106
|
+
export type FakeRequest = {
|
|
107
|
+
kind?: string;
|
|
108
|
+
args: any[];
|
|
109
|
+
method: string;
|
|
110
|
+
path: string;
|
|
111
|
+
query: Record<string, string>;
|
|
112
|
+
body: any;
|
|
113
|
+
batched: boolean;
|
|
114
|
+
};
|
|
115
|
+
/**
|
|
116
|
+
* A round trip as `requests` holds it and `onRequest` hears it: a request,
|
|
117
|
+
* or a batch request with its `operations`.
|
|
118
|
+
*/
|
|
119
|
+
export type RecordedRequest = {
|
|
120
|
+
method: string;
|
|
121
|
+
path: string;
|
|
122
|
+
query: Record<string, string>;
|
|
123
|
+
body: any;
|
|
124
|
+
kind?: string;
|
|
125
|
+
args?: any[];
|
|
126
|
+
operations?: object[];
|
|
127
|
+
};
|
|
128
|
+
import { PlaidClient } from "./client.js";
|