@allisall/sdk 0.0.0-stage → 0.2.0

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.
Files changed (70) hide show
  1. package/LICENSE +202 -0
  2. package/NOTICE +2 -0
  3. package/README.md +227 -2
  4. package/dist/client.d.ts +121 -0
  5. package/dist/client.js +193 -0
  6. package/dist/decimal.d.ts +20 -0
  7. package/dist/decimal.js +23 -0
  8. package/dist/errors.d.ts +79 -0
  9. package/dist/errors.js +98 -0
  10. package/dist/generated/openapi.d.ts +7724 -0
  11. package/dist/generated/openapi.js +4 -0
  12. package/dist/generated/operations.d.ts +37 -0
  13. package/dist/generated/operations.js +976 -0
  14. package/dist/index.d.ts +10 -0
  15. package/dist/index.js +5 -0
  16. package/dist/ingest.d.ts +28 -0
  17. package/dist/ingest.js +247 -0
  18. package/dist/money.d.ts +57 -0
  19. package/dist/money.js +284 -0
  20. package/dist/multipart.d.ts +27 -0
  21. package/dist/multipart.js +48 -0
  22. package/dist/options.d.ts +50 -0
  23. package/dist/options.js +73 -0
  24. package/dist/pagination.d.ts +55 -0
  25. package/dist/pagination.js +85 -0
  26. package/dist/request.d.ts +117 -0
  27. package/dist/request.js +363 -0
  28. package/dist/resources/agents.d.ts +51 -0
  29. package/dist/resources/agents.js +65 -0
  30. package/dist/resources/analytics.d.ts +42 -0
  31. package/dist/resources/analytics.js +68 -0
  32. package/dist/resources/api-keys.d.ts +54 -0
  33. package/dist/resources/api-keys.js +63 -0
  34. package/dist/resources/calculations.d.ts +78 -0
  35. package/dist/resources/calculations.js +111 -0
  36. package/dist/resources/clients.d.ts +65 -0
  37. package/dist/resources/clients.js +85 -0
  38. package/dist/resources/cost.d.ts +69 -0
  39. package/dist/resources/cost.js +89 -0
  40. package/dist/resources/dashboard.d.ts +24 -0
  41. package/dist/resources/dashboard.js +28 -0
  42. package/dist/resources/events.d.ts +47 -0
  43. package/dist/resources/events.js +69 -0
  44. package/dist/resources/health.d.ts +14 -0
  45. package/dist/resources/health.js +17 -0
  46. package/dist/resources/imports.d.ts +33 -0
  47. package/dist/resources/imports.js +37 -0
  48. package/dist/resources/outcome-types.d.ts +25 -0
  49. package/dist/resources/outcome-types.js +33 -0
  50. package/dist/resources/reports.d.ts +77 -0
  51. package/dist/resources/reports.js +103 -0
  52. package/dist/resources/value-models.d.ts +92 -0
  53. package/dist/resources/value-models.js +126 -0
  54. package/dist/retry.d.ts +18 -0
  55. package/dist/retry.js +105 -0
  56. package/dist/runtime.d.ts +19 -0
  57. package/dist/runtime.js +61 -0
  58. package/dist/share.d.ts +52 -0
  59. package/dist/share.js +60 -0
  60. package/dist/transport.d.ts +102 -0
  61. package/dist/transport.js +269 -0
  62. package/dist/types.d.ts +268 -0
  63. package/dist/types.js +89 -0
  64. package/dist/unicode.d.ts +2 -0
  65. package/dist/unicode.js +11 -0
  66. package/dist/uuid.d.ts +6 -0
  67. package/dist/uuid.js +20 -0
  68. package/dist/version.d.ts +2 -0
  69. package/dist/version.js +2 -0
  70. package/package.json +40 -4
@@ -0,0 +1,363 @@
1
+ // One operation, driven by the operation table: the URL and its query, the
2
+ // headers, the body encoded once, the retries the operation is eligible
3
+ // for, and the decoded response. Every resource method calls `request` or
4
+ // `requestPage`; the ingest helper keeps its own path.
5
+ import { AllisallError } from "./errors.js";
6
+ import { OPERATIONS, } from "./generated/operations.js";
7
+ import { decodeJson, encodeJson } from "./money.js";
8
+ import { formOf } from "./multipart.js";
9
+ import { mergeHeaders, resolveHeaders, resolveMaxRetries, resolveTimeout, } from "./options.js";
10
+ import { Page, PagePromise } from "./pagination.js";
11
+ import { joinURL, send, } from "./transport.js";
12
+ import { hasLoneSurrogate } from "./unicode.js";
13
+ import { uuidv4 } from "./uuid.js";
14
+ const CONTENT_TYPES = {
15
+ json: "application/json",
16
+ "merge-patch": "application/merge-patch+json",
17
+ };
18
+ const PATH_PARAMETER = /\{([^{}]+)\}/g;
19
+ /** Fills the path template, each parameter percent-encoded as one segment. */
20
+ function fillPath(template, values) {
21
+ return template.replace(PATH_PARAMETER, (_, name) => {
22
+ const value = values[name];
23
+ if (typeof value !== "string") {
24
+ throw new TypeError(`allisall: the path parameter ${name} must be a string`);
25
+ }
26
+ // These cannot travel as one segment: a URL resolves "." and ".." as
27
+ // steps through the path, whether or not they are percent-encoded, and
28
+ // an empty segment changes which path is meant.
29
+ if (value === "" || value === "." || value === "..") {
30
+ throw new TypeError(`allisall: the path parameter ${name} is ${JSON.stringify(value)}, which cannot be sent as a path segment`);
31
+ }
32
+ // encodeURIComponent would throw a URIError naming nothing.
33
+ if (hasLoneSurrogate(value)) {
34
+ throw new TypeError(`allisall: the path parameter ${name} is not valid Unicode (a lone surrogate)`);
35
+ }
36
+ return encodeURIComponent(value);
37
+ });
38
+ }
39
+ /**
40
+ * A query value's text. A string holding a lone surrogate is refused: the
41
+ * URL would carry U+FFFD in its place.
42
+ */
43
+ function queryText(name, value) {
44
+ if (hasLoneSurrogate(name)) {
45
+ throw new TypeError("allisall: a query parameter name is not valid Unicode (a lone surrogate)");
46
+ }
47
+ if (value instanceof Date) {
48
+ if (Number.isNaN(value.getTime())) {
49
+ throw new TypeError(`allisall: the query parameter ${name} is an invalid Date`);
50
+ }
51
+ return value.toISOString();
52
+ }
53
+ if (typeof value === "string") {
54
+ if (hasLoneSurrogate(value)) {
55
+ throw new TypeError(`allisall: the query parameter ${name} is not valid Unicode (a lone surrogate)`);
56
+ }
57
+ return value;
58
+ }
59
+ if (typeof value === "number" || typeof value === "bigint") {
60
+ return String(value);
61
+ }
62
+ throw new TypeError(`allisall: the query parameter ${name} is ${value === null ? "null" : `a ${typeof value}`}; it must be a string, a number or a Date`);
63
+ }
64
+ /** Builds the URL: the base, the filled path, and the query in the caller's order. */
65
+ function buildURL(config, operation, path, query) {
66
+ const url = new URL(joinURL(config.baseURL, fillPath(operation.path, path)));
67
+ if (query !== undefined) {
68
+ for (const [name, value] of Object.entries(query)) {
69
+ // An absent member is left out; the SDK writes no parameter of its own.
70
+ if (value === undefined)
71
+ continue;
72
+ url.searchParams.append(name, queryText(name, value));
73
+ }
74
+ }
75
+ return url.href;
76
+ }
77
+ const utf8 = new TextEncoder();
78
+ /** Encodes the body once, before the first attempt. */
79
+ function encodeBody(operation, body) {
80
+ switch (operation.body) {
81
+ case "none":
82
+ // The API refuses any body here, so one passed is a mistake, not
83
+ // something to drop in silence.
84
+ if (body !== undefined) {
85
+ throw new TypeError("allisall: this operation takes no request body, but one was passed");
86
+ }
87
+ return { body: undefined, contentType: undefined };
88
+ case "json":
89
+ case "merge-patch":
90
+ return {
91
+ body: utf8.encode(encodeJson(body, operation.requestMoney)),
92
+ contentType: CONTENT_TYPES[operation.body],
93
+ };
94
+ case "multipart":
95
+ // The form's own boundary is written by fetch, with its Content-Type.
96
+ return {
97
+ // The operation table's multipart operations take an ImportUpload;
98
+ // the methods calling them are typed so.
99
+ body: formOf(body),
100
+ contentType: undefined,
101
+ };
102
+ }
103
+ }
104
+ function isRecord(value) {
105
+ return typeof value === "object" && value !== null && !Array.isArray(value);
106
+ }
107
+ /**
108
+ * Reads a success body: decoded with exact money, and a JSON object. A
109
+ * body `accept` refuses is unreadable, as a breached envelope is.
110
+ */
111
+ function readerFor(operation, accept = () => true) {
112
+ if (operation.status === 204)
113
+ return () => ({ value: undefined });
114
+ return (text) => {
115
+ let value;
116
+ try {
117
+ value = decodeJson(text, operation.responseMoney);
118
+ }
119
+ catch (err) {
120
+ if (err instanceof SyntaxError)
121
+ return undefined;
122
+ throw err;
123
+ }
124
+ if (!isRecord(value))
125
+ return undefined;
126
+ if (operation.list !== null && !isListBody(value))
127
+ return undefined;
128
+ if (!accept(value))
129
+ return undefined;
130
+ return { value };
131
+ };
132
+ }
133
+ /**
134
+ * Checks a list's envelope: an array `data`, a boolean `has_more`, and a
135
+ * `next_cursor` that is a string or `null`, and a non-empty string when
136
+ * `has_more` is true.
137
+ */
138
+ function isListBody(value) {
139
+ const { data, has_more, next_cursor } = value;
140
+ if (!Array.isArray(data) || typeof has_more !== "boolean")
141
+ return false;
142
+ if (next_cursor !== null && typeof next_cursor !== "string")
143
+ return false;
144
+ return !has_more || (typeof next_cursor === "string" && next_cursor !== "");
145
+ }
146
+ /**
147
+ * The one `PUT` a retry cannot repeat safely. Its `version` guard refuses a
148
+ * repeat of a write that already landed, as a stale version, so a retry
149
+ * after a lost response would report a failure for a write that succeeded.
150
+ */
151
+ const VERSION_GUARDED_PUT = "setValueModelLineItems";
152
+ /**
153
+ * Whether a retry cannot apply the request twice: a method RFC 9110 defines
154
+ * as idempotent, an operation sent with an `Idempotency-Key`, or ingest,
155
+ * whose `event_id`s deduplicate. The version-guarded `PUT` is the exception.
156
+ */
157
+ export function isEligible(id, operation) {
158
+ switch (operation.method) {
159
+ case "GET":
160
+ case "DELETE":
161
+ return true;
162
+ case "PUT":
163
+ return id !== VERSION_GUARDED_PUT;
164
+ case "PATCH":
165
+ return false;
166
+ case "POST":
167
+ return operation.idempotent || id === "ingestEvents";
168
+ }
169
+ }
170
+ /**
171
+ * What one call may do: its operation's retry eligibility, and the call's
172
+ * options resolved over the client's.
173
+ *
174
+ * @throws {AllisallError} for a `timeout` or `maxRetries` the client would refuse.
175
+ * @throws {TypeError} for headers that are not a plain object of headers, or
176
+ * that name a header the SDK sets.
177
+ */
178
+ export function policyOf(config, id, operation, options) {
179
+ return {
180
+ timeout: resolveTimeout(options.timeout, config.timeout),
181
+ maxRetries: resolveMaxRetries(options.maxRetries, config.maxRetries),
182
+ headers: resolveHeaders(options.headers, "headers"),
183
+ signal: options.signal,
184
+ eligible: isEligible(id, operation),
185
+ retryKeyInUse: operation.idempotent,
186
+ };
187
+ }
188
+ function outgoing(config, operation, args, options) {
189
+ return {
190
+ method: operation.method,
191
+ url: buildURL(config, operation, args.path ?? {}, args.query),
192
+ authorization: authorizationFor(operation, args.shareToken),
193
+ ...encodeBody(operation, args.body),
194
+ // One key per call, the same on every attempt.
195
+ idempotencyKey: operation.idempotent
196
+ ? (checkedKey(options.idempotencyKey) ?? uuidv4())
197
+ : undefined,
198
+ };
199
+ }
200
+ /**
201
+ * The credential an operation's access policy calls for. A shared report
202
+ * takes its share token, and only its own function passes one: the client's
203
+ * credential never reaches it, and a share token reaches nothing else.
204
+ *
205
+ * @throws {AllisallError} for a shared report without a share token, or a
206
+ * share token passed to any other operation.
207
+ */
208
+ function authorizationFor(operation, shareToken) {
209
+ if (operation.access === "ShareToken") {
210
+ if (shareToken === undefined) {
211
+ throw new AllisallError("allisall: a shared report is read with its share token, not with the client's credential");
212
+ }
213
+ return { report: shareToken };
214
+ }
215
+ if (shareToken !== undefined) {
216
+ throw new AllisallError("allisall: a share token is sent only to read a shared report");
217
+ }
218
+ return operation.access === "Public" ? "none" : "bearer";
219
+ }
220
+ /**
221
+ * A caller's `Idempotency-Key`, checked only as far as the platform can
222
+ * send it. Its syntax is the API's to judge. A key `fetch` cannot send
223
+ * would fail every attempt before sending, and each failure would read as
224
+ * a connection error worth retrying.
225
+ *
226
+ * @throws {TypeError} when the key is not a string, or not a valid header value.
227
+ */
228
+ function checkedKey(key) {
229
+ if (key === undefined)
230
+ return undefined;
231
+ if (typeof key !== "string") {
232
+ throw new TypeError(`allisall: idempotencyKey must be a string, not ${key === null ? "null" : `a ${typeof key}`}`);
233
+ }
234
+ try {
235
+ new Headers({ "Idempotency-Key": key });
236
+ }
237
+ catch {
238
+ throw new TypeError("allisall: idempotencyKey holds a character a header value cannot carry, such as a newline or a character above U+00FF");
239
+ }
240
+ return key;
241
+ }
242
+ /**
243
+ * Calls one operation and resolves with its decoded success body.
244
+ *
245
+ * Everything the call sends is fixed before the first attempt: its URL, its
246
+ * body's bytes and its `Idempotency-Key`. Retries follow the operation's
247
+ * eligibility. A `204` resolves with `undefined`.
248
+ */
249
+ export function request(config, id, args = {}) {
250
+ return requestAccepting(config, id, args, undefined);
251
+ }
252
+ /** `request`, with a check of the success body beyond the operation's own. */
253
+ async function requestAccepting(config, id, args, accept) {
254
+ const operation = OPERATIONS[id];
255
+ const options = args.options ?? {};
256
+ const policy = policyOf(config, id, operation, options);
257
+ const out = outgoing(config, operation, args, options);
258
+ const value = await send(config, out, readerFor(operation, accept), policy);
259
+ // The reader checked what the SDK relies on: a JSON object, a list's
260
+ // envelope, and money decoded at the operation's money paths. The rest
261
+ // is the server's to keep to the generated type.
262
+ return value;
263
+ }
264
+ /**
265
+ * Calls a list operation lazily: nothing is sent until the result is
266
+ * awaited or iterated. Each following page sends the same query with
267
+ * `cursor` set to the previous page's `next_cursor` and without `page`.
268
+ *
269
+ * The walk remembers every cursor it has sent since the list call, with
270
+ * the position of the page each requested; a cursor the caller's own query
271
+ * held requested the first. A page with `has_more` whose `next_cursor` was
272
+ * sent for a page at another position would walk in a cycle, so it is
273
+ * unreadable: an `ApiError` with the page's status and no problem. Walking
274
+ * again from an earlier page sends each cursor for its own position, and is
275
+ * not refused.
276
+ */
277
+ export function requestPage(config, id, args = {}) {
278
+ if (OPERATIONS[id].list === null) {
279
+ throw new TypeError(`allisall: ${id} is not a list operation`);
280
+ }
281
+ // The call's options apply to every page; an override passed to
282
+ // getNextPage applies to that one request, over them.
283
+ const callOptions = args.options ?? {};
284
+ // Each cursor sent, with the position of the page it requested: 0 for
285
+ // the first page, 1 for the next, and so on.
286
+ const sent = new Map();
287
+ // A next cursor that requested a page at another position would walk in
288
+ // a cycle. One recorded at the same position is the same page requested
289
+ // again, as when a walk restarts from an earlier page.
290
+ const breaksNoCycle = (nextPosition) => (value) => {
291
+ if (value.has_more !== true || typeof value.next_cursor !== "string") {
292
+ return true;
293
+ }
294
+ const position = sent.get(value.next_cursor);
295
+ return position === undefined || position === nextPosition;
296
+ };
297
+ const load = async (query, override, position) => {
298
+ const options = override === undefined ? callOptions : overlay(callOptions, override);
299
+ const cursor = query === undefined ? undefined : Reflect.get(query, "cursor");
300
+ if (typeof cursor === "string" && !sent.has(cursor)) {
301
+ sent.set(cursor, position);
302
+ }
303
+ const body = await requestAccepting(config, id, pageArgs(args, query, options), breaksNoCycle(position + 1));
304
+ // A list operation's reader checked the envelope.
305
+ const list = body;
306
+ const next = list.has_more && typeof list.next_cursor === "string"
307
+ ? nextQuery(query, list.next_cursor)
308
+ : undefined;
309
+ return new Page(list, next === undefined
310
+ ? undefined
311
+ : (nextOverride) => load(next, nextOverride, position + 1));
312
+ };
313
+ return new PagePromise(() => load(args.query, undefined, 0));
314
+ }
315
+ /**
316
+ * The arguments of one page's request: the call's own, with the query and
317
+ * options paging sets for that page. Every other member is carried forward.
318
+ */
319
+ export function pageArgs(args, query, options) {
320
+ return { ...args, query, options };
321
+ }
322
+ /**
323
+ * Lays one request's options over the call's. A member left out, or set to
324
+ * `undefined`, keeps the call's; `headers` are laid over the call's
325
+ * headers name by name, as a call's are over the client's.
326
+ *
327
+ * @throws {TypeError} when either set of headers is not a plain object of
328
+ * headers, or names a header the SDK sets.
329
+ */
330
+ function overlay(call, override) {
331
+ const merged = { ...call };
332
+ if (override.signal !== undefined)
333
+ merged.signal = override.signal;
334
+ if (override.timeout !== undefined)
335
+ merged.timeout = override.timeout;
336
+ if (override.maxRetries !== undefined) {
337
+ merged.maxRetries = override.maxRetries;
338
+ }
339
+ if (override.headers !== undefined) {
340
+ const headers = { ...resolveHeaders(call.headers, "headers") };
341
+ mergeHeaders(headers, resolveHeaders(override.headers, "headers"));
342
+ merged.headers = headers;
343
+ }
344
+ return merged;
345
+ }
346
+ /** The query of the next page: the same members, `page` dropped, `cursor` set. */
347
+ function nextQuery(query, cursor) {
348
+ const next = {};
349
+ for (const [name, value] of Object.entries(query ?? {})) {
350
+ if (name !== "page")
351
+ next[name] = value;
352
+ }
353
+ next.cursor = cursor;
354
+ return next;
355
+ }
356
+ /** Calls one operation with arguments typed for it; see `request`. */
357
+ export function call(config, id, args) {
358
+ return request(config, id, args);
359
+ }
360
+ /** Calls one list operation with arguments typed for it; see `requestPage`. */
361
+ export function callPage(config, id, args) {
362
+ return requestPage(config, id, args);
363
+ }
@@ -0,0 +1,51 @@
1
+ import type { IdempotentRequestOptions, RequestOptions } from "../options.js";
2
+ import type { PagePromise } from "../pagination.js";
3
+ import type { TransportConfig } from "../transport.js";
4
+ import type { Agent, AgentCreate, AgentDetail, AgentList, AgentListItem, AgentPatch, GetAgentQuery, ListAgentsQuery } from "../types.js";
5
+ /** The `agents` operations. */
6
+ export declare class Agents {
7
+ #private;
8
+ constructor(config: TransportConfig);
9
+ /**
10
+ * Lists agents. Await the result for one page; iterate it with
11
+ * `for await` for every agent of every page.
12
+ *
13
+ * Needs the `read` scope. Operation `listAgents`.
14
+ */
15
+ list(query?: ListAgentsQuery, options?: RequestOptions): PagePromise<AgentListItem, AgentList>;
16
+ /**
17
+ * Creates an agent.
18
+ *
19
+ * Every attempt of the call sends one `Idempotency-Key`, so a retry
20
+ * cannot create a second agent.
21
+ *
22
+ * Needs the `write` scope. Operation `createAgent`.
23
+ */
24
+ create(body: AgentCreate, options?: IdempotentRequestOptions): Promise<Agent>;
25
+ /**
26
+ * Reads an agent, with its statistics. `from` and `to` bound the
27
+ * statistics only; absent bounds mean all time.
28
+ *
29
+ * Needs the `read` scope. Operation `getAgent`.
30
+ */
31
+ get(id: string, query?: GetAgentQuery, options?: RequestOptions): Promise<AgentDetail>;
32
+ /**
33
+ * Updates an agent with a merge patch: a member left out keeps its value,
34
+ * `null` clears it, and any other value sets it.
35
+ *
36
+ * Never retried.
37
+ *
38
+ * Needs the `write` scope. Operation `updateAgent`.
39
+ */
40
+ update(id: string, patch: AgentPatch, options?: RequestOptions): Promise<Agent>;
41
+ /**
42
+ * Deletes an agent. Refused while events reference the agent; set its
43
+ * status to `retired` instead.
44
+ *
45
+ * A retry after a lost response can answer `404` for a delete that
46
+ * succeeded.
47
+ *
48
+ * Needs the `write` scope. Operation `deleteAgent`.
49
+ */
50
+ delete(id: string, options?: RequestOptions): Promise<void>;
51
+ }
@@ -0,0 +1,65 @@
1
+ // The `agents` operations.
2
+ import { call, callPage } from "../request.js";
3
+ /** The `agents` operations. */
4
+ export class Agents {
5
+ #config;
6
+ constructor(config) {
7
+ this.#config = config;
8
+ }
9
+ /**
10
+ * Lists agents. Await the result for one page; iterate it with
11
+ * `for await` for every agent of every page.
12
+ *
13
+ * Needs the `read` scope. Operation `listAgents`.
14
+ */
15
+ list(query, options) {
16
+ return callPage(this.#config, "listAgents", { query, options });
17
+ }
18
+ /**
19
+ * Creates an agent.
20
+ *
21
+ * Every attempt of the call sends one `Idempotency-Key`, so a retry
22
+ * cannot create a second agent.
23
+ *
24
+ * Needs the `write` scope. Operation `createAgent`.
25
+ */
26
+ create(body, options) {
27
+ return call(this.#config, "createAgent", { body, options });
28
+ }
29
+ /**
30
+ * Reads an agent, with its statistics. `from` and `to` bound the
31
+ * statistics only; absent bounds mean all time.
32
+ *
33
+ * Needs the `read` scope. Operation `getAgent`.
34
+ */
35
+ get(id, query, options) {
36
+ return call(this.#config, "getAgent", { path: { id }, query, options });
37
+ }
38
+ /**
39
+ * Updates an agent with a merge patch: a member left out keeps its value,
40
+ * `null` clears it, and any other value sets it.
41
+ *
42
+ * Never retried.
43
+ *
44
+ * Needs the `write` scope. Operation `updateAgent`.
45
+ */
46
+ update(id, patch, options) {
47
+ return call(this.#config, "updateAgent", {
48
+ path: { id },
49
+ body: patch,
50
+ options,
51
+ });
52
+ }
53
+ /**
54
+ * Deletes an agent. Refused while events reference the agent; set its
55
+ * status to `retired` instead.
56
+ *
57
+ * A retry after a lost response can answer `404` for a delete that
58
+ * succeeded.
59
+ *
60
+ * Needs the `write` scope. Operation `deleteAgent`.
61
+ */
62
+ delete(id, options) {
63
+ return call(this.#config, "deleteAgent", { path: { id }, options });
64
+ }
65
+ }
@@ -0,0 +1,42 @@
1
+ import type { RequestOptions } from "../options.js";
2
+ import type { TransportConfig } from "../transport.js";
3
+ import type { Anomalies, ClientCost, ClientValue, GetClientAnomaliesQuery, GetClientCostQuery, GetClientRoiQuery, GetClientValueQuery, RoiResult } from "../types.js";
4
+ /** The `analytics` operations. */
5
+ export declare class Analytics {
6
+ #private;
7
+ constructor(config: TransportConfig);
8
+ /**
9
+ * Computes a client's value.
10
+ *
11
+ * Needs the `read` scope. Operation `getClientValue`.
12
+ *
13
+ * @param clientId - the client's id.
14
+ */
15
+ getValueForClient(clientId: string, query?: GetClientValueQuery, options?: RequestOptions): Promise<ClientValue>;
16
+ /**
17
+ * Computes a client's cost over a period. Both bounds are required:
18
+ * standing charges are prorated day by day, so an open `from` would
19
+ * prorate each charge from its own start date, however long ago.
20
+ *
21
+ * Needs the `read` scope. Operation `getClientCost`.
22
+ *
23
+ * @param clientId - the client's id.
24
+ */
25
+ getCostForClient(clientId: string, query: GetClientCostQuery, options?: RequestOptions): Promise<ClientCost>;
26
+ /**
27
+ * Computes a client's ROI over a period.
28
+ *
29
+ * Needs the `read` scope. Operation `getClientRoi`.
30
+ *
31
+ * @param clientId - the client's id.
32
+ */
33
+ getRoiForClient(clientId: string, query: GetClientRoiQuery, options?: RequestOptions): Promise<RoiResult>;
34
+ /**
35
+ * Flags anomalies in a client's period.
36
+ *
37
+ * Needs the `read` scope. Operation `getClientAnomalies`.
38
+ *
39
+ * @param clientId - the client's id.
40
+ */
41
+ getAnomaliesForClient(clientId: string, query: GetClientAnomaliesQuery, options?: RequestOptions): Promise<Anomalies>;
42
+ }
@@ -0,0 +1,68 @@
1
+ // The `analytics` operations: a client's value, cost, ROI and anomalies
2
+ // over a period.
3
+ import { call } from "../request.js";
4
+ /** The `analytics` operations. */
5
+ export class Analytics {
6
+ #config;
7
+ constructor(config) {
8
+ this.#config = config;
9
+ }
10
+ /**
11
+ * Computes a client's value.
12
+ *
13
+ * Needs the `read` scope. Operation `getClientValue`.
14
+ *
15
+ * @param clientId - the client's id.
16
+ */
17
+ getValueForClient(clientId, query, options) {
18
+ return call(this.#config, "getClientValue", {
19
+ path: { id: clientId },
20
+ query,
21
+ options,
22
+ });
23
+ }
24
+ /**
25
+ * Computes a client's cost over a period. Both bounds are required:
26
+ * standing charges are prorated day by day, so an open `from` would
27
+ * prorate each charge from its own start date, however long ago.
28
+ *
29
+ * Needs the `read` scope. Operation `getClientCost`.
30
+ *
31
+ * @param clientId - the client's id.
32
+ */
33
+ getCostForClient(clientId, query, options) {
34
+ return call(this.#config, "getClientCost", {
35
+ path: { id: clientId },
36
+ query,
37
+ options,
38
+ });
39
+ }
40
+ /**
41
+ * Computes a client's ROI over a period.
42
+ *
43
+ * Needs the `read` scope. Operation `getClientRoi`.
44
+ *
45
+ * @param clientId - the client's id.
46
+ */
47
+ getRoiForClient(clientId, query, options) {
48
+ return call(this.#config, "getClientRoi", {
49
+ path: { id: clientId },
50
+ query,
51
+ options,
52
+ });
53
+ }
54
+ /**
55
+ * Flags anomalies in a client's period.
56
+ *
57
+ * Needs the `read` scope. Operation `getClientAnomalies`.
58
+ *
59
+ * @param clientId - the client's id.
60
+ */
61
+ getAnomaliesForClient(clientId, query, options) {
62
+ return call(this.#config, "getClientAnomalies", {
63
+ path: { id: clientId },
64
+ query,
65
+ options,
66
+ });
67
+ }
68
+ }
@@ -0,0 +1,54 @@
1
+ import type { RequestOptions } from "../options.js";
2
+ import type { PagePromise } from "../pagination.js";
3
+ import type { TransportConfig } from "../transport.js";
4
+ import type { ApiKey, ApiKeyCreate, ApiKeyList, ApiKeyWithToken, ListApiKeysQuery } from "../types.js";
5
+ /** The `apiKeys` operations. */
6
+ export declare class ApiKeys {
7
+ #private;
8
+ constructor(config: TransportConfig);
9
+ /**
10
+ * Creates an API key, and returns its complete token once. Store the
11
+ * token at once: no later call returns it, because the API keeps only a
12
+ * hash.
13
+ *
14
+ * Never retried, because a retried create would make a second key. On a
15
+ * `ConnectionError`, list the keys to learn whether it was created.
16
+ *
17
+ * Needs a session token: an API key cannot create a key. An API key is
18
+ * refused with `403` `session_required`, as an `ApiError`.
19
+ *
20
+ * Operation `createApiKey`.
21
+ */
22
+ create(body: ApiKeyCreate, options?: RequestOptions): Promise<ApiKeyWithToken>;
23
+ /**
24
+ * Lists API keys. Await the result for one page; iterate it with
25
+ * `for await` for every key of every page.
26
+ *
27
+ * Needs a session token. An API key is refused with `403`
28
+ * `session_required`, as an `ApiError`.
29
+ *
30
+ * Operation `listApiKeys`.
31
+ */
32
+ list(query?: ListApiKeysQuery, options?: RequestOptions): PagePromise<ApiKey, ApiKeyList>;
33
+ /**
34
+ * Reads an API key. Its token is never returned.
35
+ *
36
+ * Needs a session token. An API key is refused with `403`
37
+ * `session_required`, as an `ApiError`.
38
+ *
39
+ * Operation `getApiKey`.
40
+ */
41
+ get(id: string, options?: RequestOptions): Promise<ApiKey>;
42
+ /**
43
+ * Revokes an API key. The next request bearing the key is refused with
44
+ * `401`.
45
+ *
46
+ * Needs a session token. An API key is refused with `403`
47
+ * `session_required`, as an `ApiError`. Never retried.
48
+ *
49
+ * Operation `revokeApiKey`.
50
+ *
51
+ * @param id - the key's `id`, not its token.
52
+ */
53
+ revoke(id: string, options?: RequestOptions): Promise<ApiKey>;
54
+ }