@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.
- package/LICENSE +202 -0
- package/NOTICE +2 -0
- package/README.md +227 -2
- package/dist/client.d.ts +121 -0
- package/dist/client.js +193 -0
- package/dist/decimal.d.ts +20 -0
- package/dist/decimal.js +23 -0
- package/dist/errors.d.ts +79 -0
- package/dist/errors.js +98 -0
- package/dist/generated/openapi.d.ts +7724 -0
- package/dist/generated/openapi.js +4 -0
- package/dist/generated/operations.d.ts +37 -0
- package/dist/generated/operations.js +976 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +5 -0
- package/dist/ingest.d.ts +28 -0
- package/dist/ingest.js +247 -0
- package/dist/money.d.ts +57 -0
- package/dist/money.js +284 -0
- package/dist/multipart.d.ts +27 -0
- package/dist/multipart.js +48 -0
- package/dist/options.d.ts +50 -0
- package/dist/options.js +73 -0
- package/dist/pagination.d.ts +55 -0
- package/dist/pagination.js +85 -0
- package/dist/request.d.ts +117 -0
- package/dist/request.js +363 -0
- package/dist/resources/agents.d.ts +51 -0
- package/dist/resources/agents.js +65 -0
- package/dist/resources/analytics.d.ts +42 -0
- package/dist/resources/analytics.js +68 -0
- package/dist/resources/api-keys.d.ts +54 -0
- package/dist/resources/api-keys.js +63 -0
- package/dist/resources/calculations.d.ts +78 -0
- package/dist/resources/calculations.js +111 -0
- package/dist/resources/clients.d.ts +65 -0
- package/dist/resources/clients.js +85 -0
- package/dist/resources/cost.d.ts +69 -0
- package/dist/resources/cost.js +89 -0
- package/dist/resources/dashboard.d.ts +24 -0
- package/dist/resources/dashboard.js +28 -0
- package/dist/resources/events.d.ts +47 -0
- package/dist/resources/events.js +69 -0
- package/dist/resources/health.d.ts +14 -0
- package/dist/resources/health.js +17 -0
- package/dist/resources/imports.d.ts +33 -0
- package/dist/resources/imports.js +37 -0
- package/dist/resources/outcome-types.d.ts +25 -0
- package/dist/resources/outcome-types.js +33 -0
- package/dist/resources/reports.d.ts +77 -0
- package/dist/resources/reports.js +103 -0
- package/dist/resources/value-models.d.ts +92 -0
- package/dist/resources/value-models.js +126 -0
- package/dist/retry.d.ts +18 -0
- package/dist/retry.js +105 -0
- package/dist/runtime.d.ts +19 -0
- package/dist/runtime.js +61 -0
- package/dist/share.d.ts +52 -0
- package/dist/share.js +60 -0
- package/dist/transport.d.ts +102 -0
- package/dist/transport.js +269 -0
- package/dist/types.d.ts +268 -0
- package/dist/types.js +89 -0
- package/dist/unicode.d.ts +2 -0
- package/dist/unicode.js +11 -0
- package/dist/uuid.d.ts +6 -0
- package/dist/uuid.js +20 -0
- package/dist/version.d.ts +2 -0
- package/dist/version.js +2 -0
- package/package.json +40 -4
package/dist/client.js
ADDED
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
// The client: its options, and how the credential and the base URL are
|
|
2
|
+
// resolved at construction.
|
|
3
|
+
import { AllisallError } from "./errors.js";
|
|
4
|
+
import { DEFAULT_MAX_RETRIES, DEFAULT_TIMEOUT_MS, resolveHeaders, resolveMaxRetries, resolveTimeout, } from "./options.js";
|
|
5
|
+
import { Agents } from "./resources/agents.js";
|
|
6
|
+
import { Analytics } from "./resources/analytics.js";
|
|
7
|
+
import { ApiKeys } from "./resources/api-keys.js";
|
|
8
|
+
import { Calculations } from "./resources/calculations.js";
|
|
9
|
+
import { Clients } from "./resources/clients.js";
|
|
10
|
+
import { Cost } from "./resources/cost.js";
|
|
11
|
+
import { DashboardOperations } from "./resources/dashboard.js";
|
|
12
|
+
import { Events } from "./resources/events.js";
|
|
13
|
+
import { HealthOperations } from "./resources/health.js";
|
|
14
|
+
import { Imports } from "./resources/imports.js";
|
|
15
|
+
import { OutcomeTypes } from "./resources/outcome-types.js";
|
|
16
|
+
import { Reports } from "./resources/reports.js";
|
|
17
|
+
import { ValueModels } from "./resources/value-models.js";
|
|
18
|
+
import { globalValue, isBrowser, readEnv, userAgent } from "./runtime.js";
|
|
19
|
+
import { BROWSER_KEY_MESSAGE, isPrintableCredential, } from "./transport.js";
|
|
20
|
+
const DEFAULT_BASE_URL = "https://api.allisai.ai";
|
|
21
|
+
function resolveCredential(options) {
|
|
22
|
+
const { apiKey, tokenProvider } = options;
|
|
23
|
+
if (apiKey !== undefined && tokenProvider !== undefined) {
|
|
24
|
+
throw new AllisallError("allisall: pass either apiKey or tokenProvider, not both");
|
|
25
|
+
}
|
|
26
|
+
if (tokenProvider !== undefined) {
|
|
27
|
+
if (typeof tokenProvider !== "function") {
|
|
28
|
+
throw new AllisallError("allisall: tokenProvider must be a function");
|
|
29
|
+
}
|
|
30
|
+
return { kind: "provider", provider: tokenProvider };
|
|
31
|
+
}
|
|
32
|
+
if (apiKey !== undefined) {
|
|
33
|
+
const key = typeof apiKey === "string" ? apiKey.trim() : "";
|
|
34
|
+
if (key === "") {
|
|
35
|
+
throw new AllisallError("allisall: apiKey is empty");
|
|
36
|
+
}
|
|
37
|
+
if (!isPrintableCredential(key)) {
|
|
38
|
+
throw new AllisallError("allisall: apiKey holds a character other than printable ASCII, which cannot be sent");
|
|
39
|
+
}
|
|
40
|
+
return { kind: "apiKey", apiKey: key };
|
|
41
|
+
}
|
|
42
|
+
// A variable of white space alone counts as unset.
|
|
43
|
+
const fromEnv = readEnv("AIA_API_KEY")?.trim();
|
|
44
|
+
if (fromEnv !== undefined && fromEnv !== "") {
|
|
45
|
+
if (!isPrintableCredential(fromEnv)) {
|
|
46
|
+
throw new AllisallError("allisall: AIA_API_KEY holds a character other than printable ASCII, which cannot be sent");
|
|
47
|
+
}
|
|
48
|
+
return { kind: "apiKey", apiKey: fromEnv };
|
|
49
|
+
}
|
|
50
|
+
throw new AllisallError("allisall: no credential; pass apiKey or tokenProvider, or set AIA_API_KEY");
|
|
51
|
+
}
|
|
52
|
+
/** Reads `globalThis.location.href`, where it exists. */
|
|
53
|
+
function pageAddress() {
|
|
54
|
+
const location = globalValue("location");
|
|
55
|
+
if (typeof location !== "object" || location === null)
|
|
56
|
+
return undefined;
|
|
57
|
+
const href = Reflect.get(location, "href");
|
|
58
|
+
return typeof href === "string" ? href : undefined;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Resolves the base URL: the option, else `AIA_BASE_URL`, else the API's
|
|
62
|
+
* own host. In a browser, a path starting with a single `/` is resolved
|
|
63
|
+
* against the page's address and must keep its origin.
|
|
64
|
+
*
|
|
65
|
+
* @throws {AllisallError} for a base URL the client refuses.
|
|
66
|
+
*/
|
|
67
|
+
function resolveBaseURL(option, browser) {
|
|
68
|
+
const raw = option ?? readEnv("AIA_BASE_URL") ?? DEFAULT_BASE_URL;
|
|
69
|
+
// A path on the page's own origin, such as "/api". A leading "//" names
|
|
70
|
+
// another host, so it is not a path.
|
|
71
|
+
const pathOnly = typeof raw === "string" && raw.startsWith("/") && !raw.startsWith("//");
|
|
72
|
+
const page = browser && pathOnly ? pageAddress() : undefined;
|
|
73
|
+
let url;
|
|
74
|
+
try {
|
|
75
|
+
url = page === undefined ? new URL(raw) : new URL(raw, page);
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
throw new AllisallError(pathOnly && browser
|
|
79
|
+
? `allisall: the base URL ${JSON.stringify(raw)} is a path, and the page's address could not be read to resolve it`
|
|
80
|
+
: `allisall: the base URL ${JSON.stringify(raw)} is not an absolute URL`);
|
|
81
|
+
}
|
|
82
|
+
if (url.protocol !== "http:" && url.protocol !== "https:") {
|
|
83
|
+
throw new AllisallError(`allisall: the base URL ${JSON.stringify(raw)} is not http or https`);
|
|
84
|
+
}
|
|
85
|
+
// URL parsing reads a backslash as "/" and drops tabs and newlines, so a
|
|
86
|
+
// value such as "/\other.example/api" passes the "//" check above and
|
|
87
|
+
// still names another host. Only the resolved origin settles it.
|
|
88
|
+
if (page !== undefined && url.origin !== new URL(page).origin) {
|
|
89
|
+
throw new AllisallError(`allisall: the base URL ${JSON.stringify(raw)} is a path, but resolves to another origin, ${url.origin}`);
|
|
90
|
+
}
|
|
91
|
+
return url;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Resolves what every request needs apart from its credential and default
|
|
95
|
+
* headers: the base URL, timeout, retries, `fetch` and `User-Agent`, which
|
|
96
|
+
* a browser does not send.
|
|
97
|
+
*
|
|
98
|
+
* @throws {AllisallError} for a base URL, timeout or `maxRetries` the
|
|
99
|
+
* client refuses.
|
|
100
|
+
*/
|
|
101
|
+
export function transportSettings(options, browser) {
|
|
102
|
+
return {
|
|
103
|
+
baseURL: resolveBaseURL(options.baseURL, browser),
|
|
104
|
+
timeout: resolveTimeout(options.timeout, DEFAULT_TIMEOUT_MS),
|
|
105
|
+
maxRetries: resolveMaxRetries(options.maxRetries, DEFAULT_MAX_RETRIES),
|
|
106
|
+
fetch: options.fetch,
|
|
107
|
+
userAgent: userAgent(),
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Checks the client's options and fixes everything a request needs.
|
|
112
|
+
*
|
|
113
|
+
* @throws {AllisallError} for an option the client refuses.
|
|
114
|
+
* @throws {TypeError} when `defaultHeaders` is not a plain object of
|
|
115
|
+
* header names and string values, names a header the SDK sets, or holds a
|
|
116
|
+
* name or value the platform cannot send.
|
|
117
|
+
*/
|
|
118
|
+
export function transportConfig(options) {
|
|
119
|
+
const credential = resolveCredential(options);
|
|
120
|
+
const browser = isBrowser();
|
|
121
|
+
const refuseApiKeys = browser && options.dangerouslyAllowBrowser !== true;
|
|
122
|
+
if (refuseApiKeys && credential.kind === "apiKey") {
|
|
123
|
+
throw new AllisallError(BROWSER_KEY_MESSAGE);
|
|
124
|
+
}
|
|
125
|
+
return {
|
|
126
|
+
...transportSettings(options, browser),
|
|
127
|
+
credential,
|
|
128
|
+
refuseApiKeys,
|
|
129
|
+
defaultHeaders: resolveHeaders(options.defaultHeaders, "defaultHeaders"),
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* The allisall API client. Construct one and reuse it.
|
|
134
|
+
*
|
|
135
|
+
* Its operations are grouped by what they act on, one property per group,
|
|
136
|
+
* such as `client.clients.list()`. A failed call rejects with an `ApiError`
|
|
137
|
+
* for an error response, or a `ConnectionError` when no response arrived.
|
|
138
|
+
*/
|
|
139
|
+
export class Allisall {
|
|
140
|
+
/** Events: ingest, and the events behind a client's totals. */
|
|
141
|
+
events;
|
|
142
|
+
/** CSV imports of events. */
|
|
143
|
+
imports;
|
|
144
|
+
/** Clients, and the agents assigned to each. */
|
|
145
|
+
clients;
|
|
146
|
+
/** Agents. */
|
|
147
|
+
agents;
|
|
148
|
+
/** Value models, by their own id or by their client's, and value templates. */
|
|
149
|
+
valueModels;
|
|
150
|
+
/** Outcome types, for the workspace or for one client. */
|
|
151
|
+
outcomeTypes;
|
|
152
|
+
/** Cost line items and the price table. */
|
|
153
|
+
cost;
|
|
154
|
+
/** A client's value, cost, ROI and anomalies over a period. */
|
|
155
|
+
analytics;
|
|
156
|
+
/** Calculations, and the human steps that validate, publish and reopen them. */
|
|
157
|
+
calculations;
|
|
158
|
+
/** Reports on calculations, and the human steps that share and revoke them. */
|
|
159
|
+
reports;
|
|
160
|
+
/** The workspace's month, and renewal readiness. */
|
|
161
|
+
dashboard;
|
|
162
|
+
/** API keys, managed with a session token. */
|
|
163
|
+
apiKeys;
|
|
164
|
+
/** The API's liveness. */
|
|
165
|
+
health;
|
|
166
|
+
/**
|
|
167
|
+
* @throws {AllisallError} when there is no credential, or both an API key
|
|
168
|
+
* and a token provider; when the base URL is neither an absolute `http`
|
|
169
|
+
* or `https` URL nor, in a browser, a path starting with a single `/`
|
|
170
|
+
* that resolves to the page's own origin; when `maxRetries` is negative
|
|
171
|
+
* or `timeout` is not positive; or when an API key is used in a browser
|
|
172
|
+
* without `dangerouslyAllowBrowser`.
|
|
173
|
+
* @throws {TypeError} when `defaultHeaders` is not a plain object of
|
|
174
|
+
* header names and string values, names a header the SDK sets, or holds a
|
|
175
|
+
* name or value the platform cannot send.
|
|
176
|
+
*/
|
|
177
|
+
constructor(options = {}) {
|
|
178
|
+
const config = transportConfig(options);
|
|
179
|
+
this.events = new Events(config);
|
|
180
|
+
this.imports = new Imports(config);
|
|
181
|
+
this.clients = new Clients(config);
|
|
182
|
+
this.agents = new Agents(config);
|
|
183
|
+
this.valueModels = new ValueModels(config);
|
|
184
|
+
this.outcomeTypes = new OutcomeTypes(config);
|
|
185
|
+
this.cost = new Cost(config);
|
|
186
|
+
this.analytics = new Analytics(config);
|
|
187
|
+
this.calculations = new Calculations(config);
|
|
188
|
+
this.reports = new Reports(config);
|
|
189
|
+
this.dashboard = new DashboardOperations(config);
|
|
190
|
+
this.apiKeys = new ApiKeys(config);
|
|
191
|
+
this.health = new HealthOperations(config);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
declare const decimalBrand: unique symbol;
|
|
2
|
+
/**
|
|
3
|
+
* An exact decimal amount, such as a `cost`. It is a string at run time,
|
|
4
|
+
* branded so that only `decimal()` produces one. The SDK writes its text
|
|
5
|
+
* into the request unchanged, as a JSON number, so no binary float ever
|
|
6
|
+
* rounds it.
|
|
7
|
+
*/
|
|
8
|
+
export type Decimal = string & {
|
|
9
|
+
readonly [decimalBrand]: true;
|
|
10
|
+
};
|
|
11
|
+
/** Reports whether `text` has the syntax of a `Decimal`. */
|
|
12
|
+
export declare function isDecimalText(text: string): boolean;
|
|
13
|
+
/**
|
|
14
|
+
* Makes a `Decimal` from its text, such as `decimal("0.3683")`.
|
|
15
|
+
*
|
|
16
|
+
* @throws {TypeError} when `text` is not an optional `-`, digits without a
|
|
17
|
+
* leading zero (or a single `0`), and optional decimal places after a `.`.
|
|
18
|
+
*/
|
|
19
|
+
export declare function decimal(text: string): Decimal;
|
|
20
|
+
export {};
|
package/dist/decimal.js
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The syntax a `Decimal` accepts: an optional `-`, digits without a leading
|
|
3
|
+
* zero (or a single `0`), and optional decimal places after a `.`. Every
|
|
4
|
+
* string it accepts is a valid JSON number.
|
|
5
|
+
*/
|
|
6
|
+
const DECIMAL_SYNTAX = /^-?(?:0|[1-9][0-9]*)(?:\.[0-9]+)?$/;
|
|
7
|
+
/** Reports whether `text` has the syntax of a `Decimal`. */
|
|
8
|
+
export function isDecimalText(text) {
|
|
9
|
+
return DECIMAL_SYNTAX.test(text);
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Makes a `Decimal` from its text, such as `decimal("0.3683")`.
|
|
13
|
+
*
|
|
14
|
+
* @throws {TypeError} when `text` is not an optional `-`, digits without a
|
|
15
|
+
* leading zero (or a single `0`), and optional decimal places after a `.`.
|
|
16
|
+
*/
|
|
17
|
+
export function decimal(text) {
|
|
18
|
+
if (typeof text !== "string" || !isDecimalText(text)) {
|
|
19
|
+
throw new TypeError(`allisall: ${JSON.stringify(text)} is not a decimal; write it as digits with an optional "-" and decimal places, such as "12.5"`);
|
|
20
|
+
}
|
|
21
|
+
// The syntax check above is the invariant the brand stands for.
|
|
22
|
+
return text;
|
|
23
|
+
}
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import type { ErrorCode, EventInput, IngestSummary, Problem } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* The base of every error the SDK throws. Catch it to handle any SDK
|
|
4
|
+
* failure; catch `ApiError`, `ConnectionError` or `IngestError` to handle
|
|
5
|
+
* one condition.
|
|
6
|
+
*/
|
|
7
|
+
export declare class AllisallError extends Error {
|
|
8
|
+
name: string;
|
|
9
|
+
}
|
|
10
|
+
/** The members of an `ApiError`. */
|
|
11
|
+
export interface ApiErrorInit {
|
|
12
|
+
status: number;
|
|
13
|
+
problem?: Problem | undefined;
|
|
14
|
+
requestId?: string | undefined;
|
|
15
|
+
retryAfter?: number | undefined;
|
|
16
|
+
headers: Headers;
|
|
17
|
+
message?: string | undefined;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* An error response from the API, or a successful response whose body was
|
|
21
|
+
* not the expected shape. Branch on `code`; for a code you do not
|
|
22
|
+
* recognise, fall back on `status`.
|
|
23
|
+
*/
|
|
24
|
+
export declare class ApiError extends AllisallError {
|
|
25
|
+
name: string;
|
|
26
|
+
/** The HTTP status. */
|
|
27
|
+
readonly status: number;
|
|
28
|
+
/** The problem's `code`. Absent when the body was not a problem document. */
|
|
29
|
+
readonly code: ErrorCode | undefined;
|
|
30
|
+
/** The whole problem document. Absent when the body was not one. */
|
|
31
|
+
readonly problem: Problem | undefined;
|
|
32
|
+
/** The problem's `request_id`, or else the response's `X-Request-Id`. */
|
|
33
|
+
readonly requestId: string | undefined;
|
|
34
|
+
/**
|
|
35
|
+
* The response's `Retry-After`, in milliseconds from when the response
|
|
36
|
+
* arrived. Absent when the response had none, or one that did not parse
|
|
37
|
+
* or named a time in the past.
|
|
38
|
+
*/
|
|
39
|
+
readonly retryAfter: number | undefined;
|
|
40
|
+
/** The response headers. */
|
|
41
|
+
readonly headers: Headers;
|
|
42
|
+
constructor(init: ApiErrorInit);
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* A request that got no response: the connection failed, was reset, or the
|
|
46
|
+
* attempt timed out. `cause` holds the underlying error.
|
|
47
|
+
*/
|
|
48
|
+
export declare class ConnectionError extends AllisallError {
|
|
49
|
+
name: string;
|
|
50
|
+
/** The `X-Request-Id` the SDK sent on the last attempt, to quote when reporting it. */
|
|
51
|
+
readonly requestId: string;
|
|
52
|
+
constructor(requestId: string, cause: unknown);
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* A batch of an `ingest` call failed, so the call stopped and sent nothing
|
|
56
|
+
* after it. `cause` holds what failed the batch: an `ApiError`, a
|
|
57
|
+
* `ConnectionError`, the caller's cancellation, or the error from getting
|
|
58
|
+
* the token: the token provider's own error, unchanged, or the
|
|
59
|
+
* `AllisallError` refusing a provider's API key in a browser. To recover,
|
|
60
|
+
* send `remaining` again: every event in it keeps the `event_id` it was
|
|
61
|
+
* sent with, so any the failed batch stored come back as duplicates.
|
|
62
|
+
*/
|
|
63
|
+
export declare class IngestError extends AllisallError {
|
|
64
|
+
name: string;
|
|
65
|
+
/** The combined outcome of the batches that succeeded before the failed one. */
|
|
66
|
+
readonly summary: IngestSummary;
|
|
67
|
+
/**
|
|
68
|
+
* Copies of every event from the failed batch onward, each with its
|
|
69
|
+
* `event_id`, less any event too large to send: those are rows of
|
|
70
|
+
* `summary.errors` and never in `remaining`. To map `remaining` back to
|
|
71
|
+
* your list, walk it from `remainingFrom` and skip the `index` of every
|
|
72
|
+
* `summary.errors` row at or past `remainingFrom`. With no such row,
|
|
73
|
+
* `remaining[i]` is your event `remainingFrom + i`.
|
|
74
|
+
*/
|
|
75
|
+
readonly remaining: EventInput[];
|
|
76
|
+
/** The index, in the list passed to `ingest`, of the first event in `remaining`. */
|
|
77
|
+
readonly remainingFrom: number;
|
|
78
|
+
constructor(cause: unknown, summary: IngestSummary, remaining: EventInput[], remainingFrom: number);
|
|
79
|
+
}
|
package/dist/errors.js
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The base of every error the SDK throws. Catch it to handle any SDK
|
|
3
|
+
* failure; catch `ApiError`, `ConnectionError` or `IngestError` to handle
|
|
4
|
+
* one condition.
|
|
5
|
+
*/
|
|
6
|
+
export class AllisallError extends Error {
|
|
7
|
+
name = "AllisallError";
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* An error response from the API, or a successful response whose body was
|
|
11
|
+
* not the expected shape. Branch on `code`; for a code you do not
|
|
12
|
+
* recognise, fall back on `status`.
|
|
13
|
+
*/
|
|
14
|
+
export class ApiError extends AllisallError {
|
|
15
|
+
name = "ApiError";
|
|
16
|
+
/** The HTTP status. */
|
|
17
|
+
status;
|
|
18
|
+
/** The problem's `code`. Absent when the body was not a problem document. */
|
|
19
|
+
code;
|
|
20
|
+
/** The whole problem document. Absent when the body was not one. */
|
|
21
|
+
problem;
|
|
22
|
+
/** The problem's `request_id`, or else the response's `X-Request-Id`. */
|
|
23
|
+
requestId;
|
|
24
|
+
/**
|
|
25
|
+
* The response's `Retry-After`, in milliseconds from when the response
|
|
26
|
+
* arrived. Absent when the response had none, or one that did not parse
|
|
27
|
+
* or named a time in the past.
|
|
28
|
+
*/
|
|
29
|
+
retryAfter;
|
|
30
|
+
/** The response headers. */
|
|
31
|
+
headers;
|
|
32
|
+
constructor(init) {
|
|
33
|
+
super(init.message ?? apiErrorMessage(init.status, init.problem));
|
|
34
|
+
this.status = init.status;
|
|
35
|
+
this.problem = init.problem;
|
|
36
|
+
this.code = init.problem?.code;
|
|
37
|
+
const problemId = init.problem?.request_id;
|
|
38
|
+
this.requestId =
|
|
39
|
+
problemId !== undefined && problemId !== "" ? problemId : init.requestId;
|
|
40
|
+
this.retryAfter = init.retryAfter;
|
|
41
|
+
this.headers = init.headers;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
function apiErrorMessage(status, problem) {
|
|
45
|
+
const parts = [`allisall: the API answered ${status}`];
|
|
46
|
+
if (problem?.code !== undefined)
|
|
47
|
+
parts.push(problem.code);
|
|
48
|
+
if (problem?.detail !== undefined)
|
|
49
|
+
parts.push(problem.detail);
|
|
50
|
+
return parts.join(": ");
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* A request that got no response: the connection failed, was reset, or the
|
|
54
|
+
* attempt timed out. `cause` holds the underlying error.
|
|
55
|
+
*/
|
|
56
|
+
export class ConnectionError extends AllisallError {
|
|
57
|
+
name = "ConnectionError";
|
|
58
|
+
/** The `X-Request-Id` the SDK sent on the last attempt, to quote when reporting it. */
|
|
59
|
+
requestId;
|
|
60
|
+
constructor(requestId, cause) {
|
|
61
|
+
super(`allisall: no response from the API (request ${requestId}): ${causeText(cause)}`, { cause });
|
|
62
|
+
this.requestId = requestId;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
function causeText(cause) {
|
|
66
|
+
return cause instanceof Error ? cause.message : String(cause);
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* A batch of an `ingest` call failed, so the call stopped and sent nothing
|
|
70
|
+
* after it. `cause` holds what failed the batch: an `ApiError`, a
|
|
71
|
+
* `ConnectionError`, the caller's cancellation, or the error from getting
|
|
72
|
+
* the token: the token provider's own error, unchanged, or the
|
|
73
|
+
* `AllisallError` refusing a provider's API key in a browser. To recover,
|
|
74
|
+
* send `remaining` again: every event in it keeps the `event_id` it was
|
|
75
|
+
* sent with, so any the failed batch stored come back as duplicates.
|
|
76
|
+
*/
|
|
77
|
+
export class IngestError extends AllisallError {
|
|
78
|
+
name = "IngestError";
|
|
79
|
+
/** The combined outcome of the batches that succeeded before the failed one. */
|
|
80
|
+
summary;
|
|
81
|
+
/**
|
|
82
|
+
* Copies of every event from the failed batch onward, each with its
|
|
83
|
+
* `event_id`, less any event too large to send: those are rows of
|
|
84
|
+
* `summary.errors` and never in `remaining`. To map `remaining` back to
|
|
85
|
+
* your list, walk it from `remainingFrom` and skip the `index` of every
|
|
86
|
+
* `summary.errors` row at or past `remainingFrom`. With no such row,
|
|
87
|
+
* `remaining[i]` is your event `remainingFrom + i`.
|
|
88
|
+
*/
|
|
89
|
+
remaining;
|
|
90
|
+
/** The index, in the list passed to `ingest`, of the first event in `remaining`. */
|
|
91
|
+
remainingFrom;
|
|
92
|
+
constructor(cause, summary, remaining, remainingFrom) {
|
|
93
|
+
super(`allisall: an ingest batch failed and the call stopped; send the ${remaining.length} event(s) in remaining, from index ${remainingFrom}, again: ${causeText(cause)}`, { cause });
|
|
94
|
+
this.summary = summary;
|
|
95
|
+
this.remaining = remaining;
|
|
96
|
+
this.remainingFrom = remainingFrom;
|
|
97
|
+
}
|
|
98
|
+
}
|