@elmohq/sdk 0.0.0-stage → 0.1.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 (129) hide show
  1. package/LICENSE.md +21 -0
  2. package/README.md +325 -2
  3. package/dist/calls/index.d.mts +288 -0
  4. package/dist/calls/index.d.mts.map +1 -0
  5. package/dist/calls/index.mjs +390 -0
  6. package/dist/calls/index.mjs.map +1 -0
  7. package/dist/index.d.mts +2 -0
  8. package/dist/index.mjs +1029 -0
  9. package/dist/index.mjs.map +1 -0
  10. package/dist/request-options-DWYI_Ldj.d.mts +1550 -0
  11. package/dist/request-options-DWYI_Ldj.d.mts.map +1 -0
  12. package/dist/tools-7Hs5J2xb.d.mts +1945 -0
  13. package/dist/tools-7Hs5J2xb.d.mts.map +1 -0
  14. package/dist/tools-SwP0sK8H.mjs +2458 -0
  15. package/dist/tools-SwP0sK8H.mjs.map +1 -0
  16. package/dist/types/index.d.mts +2 -0
  17. package/dist/types/index.mjs +1 -0
  18. package/package.json +67 -4
  19. package/src/calls/brands-analytics-get.ts +33 -0
  20. package/src/calls/brands-citations-domains-list.ts +36 -0
  21. package/src/calls/brands-citations-urls-list.ts +32 -0
  22. package/src/calls/brands-create.ts +19 -0
  23. package/src/calls/brands-get.ts +19 -0
  24. package/src/calls/brands-list.ts +18 -0
  25. package/src/calls/brands-opportunities-get.ts +42 -0
  26. package/src/calls/brands-prompt-performance-list.ts +39 -0
  27. package/src/calls/brands-query-fanout-get.ts +30 -0
  28. package/src/calls/brands-tags-list.ts +28 -0
  29. package/src/calls/brands-update.ts +20 -0
  30. package/src/calls/competitors-create.ts +23 -0
  31. package/src/calls/competitors-delete.ts +19 -0
  32. package/src/calls/competitors-get.ts +19 -0
  33. package/src/calls/competitors-list.ts +23 -0
  34. package/src/calls/competitors-update.ts +24 -0
  35. package/src/calls/index.ts +33 -0
  36. package/src/calls/me-get.ts +18 -0
  37. package/src/calls/models-list.ts +20 -0
  38. package/src/calls/organizations-billing-get.ts +37 -0
  39. package/src/calls/organizations-get.ts +24 -0
  40. package/src/calls/organizations-list.ts +27 -0
  41. package/src/calls/prompts-create.ts +27 -0
  42. package/src/calls/prompts-delete.ts +28 -0
  43. package/src/calls/prompts-get.ts +23 -0
  44. package/src/calls/prompts-list.ts +28 -0
  45. package/src/calls/prompts-runs-get.ts +27 -0
  46. package/src/calls/prompts-runs-list.ts +30 -0
  47. package/src/calls/prompts-snapshot-get.ts +28 -0
  48. package/src/calls/prompts-update.ts +29 -0
  49. package/src/calls/reports-create.ts +31 -0
  50. package/src/calls/reports-get.ts +27 -0
  51. package/src/calls/reports-list.ts +28 -0
  52. package/src/calls/tools-analyze.ts +26 -0
  53. package/src/client.ts +662 -0
  54. package/src/index.ts +21 -0
  55. package/src/internal/binding/rest/binding.ts +127 -0
  56. package/src/internal/binding/rest/errors.ts +107 -0
  57. package/src/internal/binding/rest/path.ts +9 -0
  58. package/src/internal/binding/rest/url.ts +97 -0
  59. package/src/internal/codec/json.ts +66 -0
  60. package/src/internal/codec/registry.ts +55 -0
  61. package/src/internal/core/backoff.ts +170 -0
  62. package/src/internal/core/body.ts +54 -0
  63. package/src/internal/core/browser.ts +11 -0
  64. package/src/internal/core/call-promise.ts +145 -0
  65. package/src/internal/core/callable.ts +11 -0
  66. package/src/internal/core/client.ts +89 -0
  67. package/src/internal/core/config.ts +84 -0
  68. package/src/internal/core/credentials.ts +40 -0
  69. package/src/internal/core/dispatch.ts +227 -0
  70. package/src/internal/core/env.ts +68 -0
  71. package/src/internal/core/errors.ts +431 -0
  72. package/src/internal/core/features.ts +60 -0
  73. package/src/internal/core/lazy-promise.ts +39 -0
  74. package/src/internal/core/metadata.ts +79 -0
  75. package/src/internal/core/params.ts +98 -0
  76. package/src/internal/core/protocol.ts +17 -0
  77. package/src/internal/core/read-reply.ts +7 -0
  78. package/src/internal/core/text.ts +7 -0
  79. package/src/internal/core/types.ts +556 -0
  80. package/src/internal/feature/auth.ts +201 -0
  81. package/src/internal/feature/interceptors.ts +36 -0
  82. package/src/internal/feature/logger.ts +222 -0
  83. package/src/internal/feature/retry.ts +165 -0
  84. package/src/internal/feature/rules.ts +54 -0
  85. package/src/internal/feature/timeout.ts +146 -0
  86. package/src/internal/feature/validate.ts +74 -0
  87. package/src/internal/page/page.ts +402 -0
  88. package/src/internal/transport/fetch.ts +82 -0
  89. package/src/resources/analytics.ts +363 -0
  90. package/src/resources/brands.ts +285 -0
  91. package/src/resources/competitors.ts +212 -0
  92. package/src/resources/identity.ts +48 -0
  93. package/src/resources/models.ts +32 -0
  94. package/src/resources/opportunities.ts +79 -0
  95. package/src/resources/organizations.ts +181 -0
  96. package/src/resources/prompts.ts +292 -0
  97. package/src/resources/reports.ts +211 -0
  98. package/src/resources/runs.ts +123 -0
  99. package/src/resources/shared/auth.ts +13 -0
  100. package/src/resources/shared/request-options.ts +26 -0
  101. package/src/resources/shared/resource.ts +23 -0
  102. package/src/resources/shared/rule.ts +25 -0
  103. package/src/resources/snapshots.ts +54 -0
  104. package/src/resources/tags.ts +46 -0
  105. package/src/resources/tools.ts +68 -0
  106. package/src/types/analytics.ts +497 -0
  107. package/src/types/brands.ts +228 -0
  108. package/src/types/competitors.ts +196 -0
  109. package/src/types/identity.ts +55 -0
  110. package/src/types/index.ts +163 -0
  111. package/src/types/models.ts +40 -0
  112. package/src/types/opportunities.ts +84 -0
  113. package/src/types/organizations.ts +157 -0
  114. package/src/types/prompts.ts +231 -0
  115. package/src/types/reports.ts +266 -0
  116. package/src/types/runs.ts +131 -0
  117. package/src/types/shared/brand-id-path.ts +2 -0
  118. package/src/types/shared/conflict-error.ts +7 -0
  119. package/src/types/shared/error.ts +29 -0
  120. package/src/types/shared/limit.ts +8 -0
  121. package/src/types/shared/mention-entry.ts +21 -0
  122. package/src/types/shared/model-filter.ts +15 -0
  123. package/src/types/shared/not-found-error.ts +4 -0
  124. package/src/types/shared/page.ts +7 -0
  125. package/src/types/shared/pagination.ts +7 -0
  126. package/src/types/shared/validation-error.ts +4 -0
  127. package/src/types/snapshots.ts +88 -0
  128. package/src/types/tags.ts +47 -0
  129. package/src/types/tools.ts +78 -0
@@ -0,0 +1,2458 @@
1
+ //#region src/internal/core/backoff.ts
2
+ function jitterShare(jitter) {
3
+ if (typeof jitter === "number") return Math.min(1, Math.max(0, jitter));
4
+ if (jitter === "equal") return .5;
5
+ return jitter === true || jitter === "full" ? 1 : 0;
6
+ }
7
+ function backoffDelay(retry, options = {}) {
8
+ const { delay = 500, jitter = true, maxDelay = 3e4, strategy = "exponential" } = options;
9
+ const growth = strategy === "constant" ? delay : delay && delay * 2 ** retry;
10
+ const capped = Math.min(growth, maxDelay);
11
+ const share = jitterShare(jitter);
12
+ return share ? capped * (1 - share) + Math.random() * capped * share : capped;
13
+ }
14
+ function exceedsMaxRetryAfter(delay, max) {
15
+ return delay !== void 0 && delay > (max ?? 6e4);
16
+ }
17
+ const TIMER_LIMIT = 2147483647;
18
+ function sleep(ms, signal) {
19
+ if (signal?.aborted) return Promise.reject(signal.reason);
20
+ if (ms <= 0) return Promise.resolve();
21
+ return new Promise((resolve, reject) => {
22
+ const timer = setTimeout(() => {
23
+ signal?.removeEventListener("abort", onAbort);
24
+ resolve();
25
+ }, Math.min(ms, TIMER_LIMIT));
26
+ function onAbort() {
27
+ clearTimeout(timer);
28
+ reject(signal.reason);
29
+ }
30
+ signal?.addEventListener("abort", onAbort, { once: true });
31
+ });
32
+ }
33
+ const RETRY_AFTER_HEADERS = [
34
+ {
35
+ name: "retry-after-ms",
36
+ unit: "millisecond"
37
+ },
38
+ { name: "retry-after" },
39
+ { name: "x-ratelimit-reset-after" },
40
+ {
41
+ kind: "moment",
42
+ name: "x-ratelimit-reset"
43
+ },
44
+ {
45
+ kind: "moment",
46
+ name: "x-rate-limit-reset"
47
+ }
48
+ ];
49
+ const ASCTIME = /^[a-z]{3} ([a-z]{3}) +(\d\d?) (\d\d:\d\d:\d\d) (\d{4})$/i;
50
+ const MOMENT = /^(?:(\d{4})-(\d\d)-(\d\d)[t ]|(?:[a-z]+, ?)?(\d\d?)[ -]([a-z]{3})[ -](\d\d|\d{4}) )([01]\d|2[0-3]):([0-5]\d)(?::([0-5]\d|60)(?:\.(\d{1,3})\d*)?)? ?(?:z|gmt|utc?|([+-])([01]\d|2[0-3]):?([0-5]\d))$/i;
51
+ const MONTHS = "janfebmaraprmayjunjulaugsepoctnovdec";
52
+ function moment(value, now) {
53
+ const match = MOMENT.exec(value.replace(ASCTIME, "$2 $1 $4 $3 GMT"));
54
+ if (!match) return void 0;
55
+ const year = match[6] ?? match[1];
56
+ const day = +(match[4] ?? match[3]);
57
+ const month = match[2] ? +match[2] - 1 : MONTHS.indexOf(match[5].toLowerCase()) / 3;
58
+ let full = +year;
59
+ if (year.length < 3) {
60
+ const present = new Date(now).getUTCFullYear();
61
+ full += present - present % 100;
62
+ if (full > present + 50) full -= 100;
63
+ }
64
+ const date = /* @__PURE__ */ new Date(0);
65
+ date.setUTCFullYear(full, month, day);
66
+ if (!full || date.getUTCMonth() !== month || date.getUTCDate() !== day) return void 0;
67
+ const zone = (match[11] === "-" ? -1 : 1) * (+(match[12] ?? 0) * 60 + +(match[13] ?? 0));
68
+ const seconds = (+match[7] * 60 + +match[8] - zone) * 60 + +(match[9] ?? 0);
69
+ return date.getTime() + seconds * 1e3 + +(match[10] ?? "").padEnd(3, "0");
70
+ }
71
+ const NUMBER = /^[0-9]+(?:\.[0-9]+)?$/;
72
+ function parseRetryAfter(value, header = { name: "retry-after" }, now = Date.now()) {
73
+ if (!value) return void 0;
74
+ if (NUMBER.test(value)) {
75
+ const number = Number(value);
76
+ const ms = header.unit === "millisecond" ? number : number * 1e3;
77
+ return Math.max(0, header.kind === "moment" ? ms - now : ms);
78
+ }
79
+ const date = moment(value, now);
80
+ if (date === void 0) return void 0;
81
+ return Math.max(0, date - now);
82
+ }
83
+ function retryAfterDelay(response, headers = RETRY_AFTER_HEADERS, now = Date.now()) {
84
+ const clock = moment(response.headers.get("date") ?? "", now) ?? now;
85
+ for (const header of headers) {
86
+ const delay = parseRetryAfter(response.headers.get(header.name), header, clock);
87
+ if (delay !== void 0) return delay;
88
+ }
89
+ }
90
+ //#endregion
91
+ //#region src/internal/core/errors.ts
92
+ /** The base of every error this SDK throws, including one from a call that never arrived. */
93
+ var ElmoError = class extends Error {
94
+ /** The class's name. Compare it where `instanceof` fails, such as across two copies of this SDK. */
95
+ name = "ElmoError";
96
+ };
97
+ function refusedInput(held, rule, got) {
98
+ return new ElmoError(`${held} ${rule}, and got ${got}, so the request was not sent.`);
99
+ }
100
+ /** Thrown before the request goes out, when no credential satisfied the call. */
101
+ var MissingCredentialError = class extends ElmoError {
102
+ name = "MissingCredentialError";
103
+ /** Credential options that would have satisfied the call. */
104
+ schemes;
105
+ constructor(message, schemes = []) {
106
+ super(message);
107
+ this.schemes = schemes;
108
+ }
109
+ };
110
+ function unsendable(held) {
111
+ return `${held} holds a line break or another character a header cannot carry, so the request was not sent.`;
112
+ }
113
+ /**
114
+ * Thrown when the caller called the request off before the API answered.
115
+ *
116
+ * Not a {@link TransportError}, so code that retries or reports a failed
117
+ * connection leaves a call the caller cancelled alone.
118
+ */
119
+ var AbortError = class extends ElmoError {
120
+ constructor(cause) {
121
+ super("The request was called off before the API answered.", { cause });
122
+ this.name = "AbortError";
123
+ }
124
+ };
125
+ const TRANSPORT_MESSAGES = {
126
+ connect: "The request never reached the API.",
127
+ other: "The connection failed before the whole reply arrived.",
128
+ timeout: "The API did not answer in time."
129
+ };
130
+ /** Thrown when no whole answer arrived, so there is no reply to go on. */
131
+ var TransportError = class extends ElmoError {
132
+ kind;
133
+ /**
134
+ * Whether the API can have acted on the request. After `'no'`, the call is
135
+ * safe to send again, whatever its method.
136
+ */
137
+ reachedServer;
138
+ /** How far the request got. */
139
+ stage;
140
+ constructor(failure, cause, message) {
141
+ const unreached = failure === "connect";
142
+ const stated = typeof failure === "string" ? {
143
+ cause,
144
+ reachedServer: unreached ? "no" : "maybe",
145
+ stage: unreached ? "connect" : "receive"
146
+ } : failure;
147
+ const kind = typeof failure === "string" ? failure : failure.reachedServer === "no" ? "connect" : "other";
148
+ super(message ?? TRANSPORT_MESSAGES[kind], stated);
149
+ this.kind = kind;
150
+ this.name = "TransportError";
151
+ this.reachedServer = stated.reachedServer;
152
+ this.stage = stated.stage;
153
+ }
154
+ };
155
+ function calledOffWith(reason) {
156
+ return reason instanceof AbortError || reason instanceof TransportError ? reason : new AbortError(reason);
157
+ }
158
+ const TIMEOUT_CODES = ["ECONNABORTED", "ETIMEDOUT"];
159
+ function codeOf(error) {
160
+ let current = error;
161
+ for (let depth = 0; current instanceof Error && depth < 5; depth++) {
162
+ const { code } = current;
163
+ if (typeof code === "string") return code;
164
+ current = current.cause;
165
+ }
166
+ }
167
+ const UNREACHED = {
168
+ EAI_AGAIN: "resolve",
169
+ ECONNREFUSED: "connect",
170
+ ENOTFOUND: "resolve",
171
+ UND_ERR_CONNECT_TIMEOUT: "connect"
172
+ };
173
+ function failureOf(error) {
174
+ const stated = error ?? {};
175
+ if (stated.reachedServer && stated.stage) return stated;
176
+ const stage = UNREACHED[codeOf(error) ?? ""];
177
+ return {
178
+ aborted: error instanceof Error && error.name === "AbortError",
179
+ cause: error,
180
+ reachedServer: stage ? "no" : "maybe",
181
+ stage: stage ?? "receive"
182
+ };
183
+ }
184
+ function classifyError(error) {
185
+ if (error instanceof TransportError) return error.kind;
186
+ const failure = failureOf(error);
187
+ if (failure.aborted) return "abort";
188
+ if (error instanceof Error && error.name === "TimeoutError") return "timeout";
189
+ if (failure.reachedServer === "no") return "connect";
190
+ return TIMEOUT_CODES.includes(codeOf(error) ?? "") ? "timeout" : "other";
191
+ }
192
+ const USERINFO_RE = /^([a-z][a-z\d+.-]*:\/\/)[^/?#@]*@/i;
193
+ function safeAddress(url) {
194
+ return (url.split("?")[0] ?? "").replace(USERINFO_RE, "$1");
195
+ }
196
+ /**
197
+ * Thrown when a call waited on the API for as long as it allowed, from sending
198
+ * the request to the last byte of the reply.
199
+ *
200
+ * A reply with status 408 is an {@link APIError}, not one of these.
201
+ */
202
+ var TimeoutError = class extends TransportError {
203
+ /** Milliseconds the call was allowed to wait on the API. */
204
+ timeoutMs;
205
+ constructor(timeout, cause, target) {
206
+ super("timeout", cause, timeout === void 0 ? TRANSPORT_MESSAGES.timeout : `${target ?? "The request"} timed out after ${timeout} ms waiting on the API. Pass a larger \`timeout\` with the call, or \`timeout: false\` to wait as long as it takes.`);
207
+ this.name = "TimeoutError";
208
+ this.timeoutMs = timeout;
209
+ }
210
+ };
211
+ const CODE_KEYS = [
212
+ "code",
213
+ "error_code",
214
+ "errorCode",
215
+ "error_type",
216
+ "errorType"
217
+ ];
218
+ function statedCode(bag) {
219
+ for (const key of CODE_KEYS) {
220
+ const value = bag[key];
221
+ if (typeof value === "string" && value.trim()) return value.trim();
222
+ if (typeof value === "number") return value;
223
+ }
224
+ }
225
+ function describeCode(error) {
226
+ if (!error || typeof error !== "object") return void 0;
227
+ const body = error;
228
+ const direct = statedCode(body);
229
+ if (direct !== void 0) return direct;
230
+ for (const value of Object.values(body)) if (value && typeof value === "object" && !Array.isArray(value)) {
231
+ const nested = statedCode(value);
232
+ if (nested !== void 0) return nested;
233
+ }
234
+ }
235
+ const MAX_MESSAGE_BODY = 200;
236
+ function oneLine(text) {
237
+ return text.replace(/\s+/g, " ").trim();
238
+ }
239
+ function shorten(text) {
240
+ const line = oneLine(text);
241
+ if (line.length <= MAX_MESSAGE_BODY) return line;
242
+ const cut = line.slice(0, MAX_MESSAGE_BODY);
243
+ const space = cut.lastIndexOf(" ");
244
+ return `${(space > MAX_MESSAGE_BODY / 2 ? cut.slice(0, space) : cut).trimEnd()}…`;
245
+ }
246
+ const MESSAGE_KEYS = [
247
+ "message",
248
+ "error_message",
249
+ "errorMessage",
250
+ "error",
251
+ "detail",
252
+ "title",
253
+ "description"
254
+ ];
255
+ function statedMessage(bag) {
256
+ for (const key of MESSAGE_KEYS) {
257
+ const value = bag[key];
258
+ if (typeof value === "string" && value.trim()) return value.trim();
259
+ }
260
+ }
261
+ function describeStatedFailure(error) {
262
+ if (typeof error === "string") return shorten(error.trim()) || void 0;
263
+ if (!error || typeof error !== "object") return void 0;
264
+ const body = error;
265
+ const direct = statedMessage(body);
266
+ if (direct) return shorten(direct);
267
+ for (const value of Object.values(body)) if (value && typeof value === "object") {
268
+ const nested = statedMessage(value);
269
+ if (nested) return shorten(nested);
270
+ }
271
+ const json = JSON.stringify(error);
272
+ return json && json !== "{}" && json !== "[]" ? shorten(json) : void 0;
273
+ }
274
+ function isStructured(body) {
275
+ return typeof body === "object" && body !== null && !(body instanceof Blob);
276
+ }
277
+ const REQUEST_ID_FALLBACKS = ["x-correlation-id", "cf-ray"];
278
+ const REQUEST_ID_NAME = /(?:^|-)request-?id$/;
279
+ function requestIdOf(response) {
280
+ let named;
281
+ response.headers.forEach((value, name) => {
282
+ if (!named && value && REQUEST_ID_NAME.test(name)) named = value;
283
+ });
284
+ if (named) return named;
285
+ for (const header of REQUEST_ID_FALLBACKS) {
286
+ const value = response.headers.get(header);
287
+ if (value) return value;
288
+ }
289
+ }
290
+ /** A failure the API answered with, so there is a status and a reply to read. */
291
+ var APIError = class extends ElmoError {
292
+ /**
293
+ * The decoded failure body. `undefined` where the reply carried none, or
294
+ * carried text such as a proxy's page, which is in {@link APIError.text}.
295
+ */
296
+ body;
297
+ /** The API's own error code, read from the failure body. `undefined` where it carried none. */
298
+ code;
299
+ headers;
300
+ /** The request id to quote when reporting this failure. */
301
+ requestId;
302
+ /**
303
+ * The reply that carried this failure. Its body is already read, so take it
304
+ * from {@link APIError.body} or {@link APIError.text}.
305
+ */
306
+ response;
307
+ /** Milliseconds the API asked to wait before trying again. */
308
+ retryAfterMs;
309
+ status;
310
+ /**
311
+ * The failure body where the API sent text rather than JSON, such as a
312
+ * proxy's page. The message holds only its start.
313
+ */
314
+ text;
315
+ constructor(status, body, response, note) {
316
+ const reason = response.statusText ? `${status} ${response.statusText}` : `${status}`;
317
+ const requestId = requestIdOf(response);
318
+ const url = response.url ? ` for "${safeAddress(response.url)}"` : "";
319
+ const where = requestId ? `${url} (request id "${requestId}")` : url;
320
+ const said = describeStatedFailure(body);
321
+ const tail = note ? `. ${note}${said ? ` The API said: ${said}` : ""}` : said ? `: ${said}` : ".";
322
+ super(`The API answered ${reason}${where}${tail}`);
323
+ this.body = isStructured(body) ? body : void 0;
324
+ this.code = describeCode(body);
325
+ this.headers = response.headers;
326
+ this.name = "APIError";
327
+ this.requestId = requestId;
328
+ this.response = response;
329
+ this.retryAfterMs = retryAfterDelay(response);
330
+ this.status = status;
331
+ this.text = typeof body === "string" ? body : void 0;
332
+ }
333
+ };
334
+ var UnsupportedInteractionError = class extends ElmoError {
335
+ interaction;
336
+ transport;
337
+ constructor(transport, interaction) {
338
+ super(`Transport "${transport}" cannot send this call. It has no "${interaction}" method.`);
339
+ this.interaction = interaction;
340
+ this.name = "UnsupportedInteractionError";
341
+ this.transport = transport;
342
+ }
343
+ };
344
+ function unansweredError(error) {
345
+ if (error instanceof ElmoError) return error;
346
+ const kind = classifyError(error);
347
+ if (kind === "abort") return new AbortError(error);
348
+ if (kind === "timeout") return new TimeoutError(void 0, error);
349
+ return new TransportError(failureOf(error));
350
+ }
351
+ function unsendableHeader(name) {
352
+ return new ElmoError(unsendable(`Header \`${name}\``));
353
+ }
354
+ function unsendableAddress(address, problem, fix) {
355
+ return new ElmoError(`"${address}" ${problem}, so the request was not sent. ${fix}`);
356
+ }
357
+ /** A reply from the API that this SDK could not read, whatever its status. */
358
+ var DecodeError = class extends ElmoError {
359
+ /** Where the value sat, or absent where the whole reply failed. */
360
+ at;
361
+ /** The request id to quote when reporting this failure. */
362
+ requestId;
363
+ /** The reply. Its body is already read. */
364
+ response;
365
+ /** The reply's status. `undefined` where there is no {@link DecodeError.response}. */
366
+ status;
367
+ /** What the API sent. The message holds only a short form of it. */
368
+ value;
369
+ constructor(message, options = {}) {
370
+ const requestId = options.response && requestIdOf(options.response);
371
+ super(requestId ? `${message} The request id is "${requestId}".` : message, { cause: options.cause });
372
+ this.at = options.at;
373
+ this.name = "DecodeError";
374
+ this.requestId = requestId;
375
+ this.response = options.response;
376
+ this.status = options.response?.status;
377
+ this.value = options.value;
378
+ }
379
+ };
380
+ function emptyPathParameter(name, url) {
381
+ return new ElmoError(`Path parameter \`${name}\` is empty. \`${url}\` cannot be sent without it.`);
382
+ }
383
+ function sent(value) {
384
+ if (value === void 0) return "nothing";
385
+ if (typeof value === "string") return `"${shorten(value)}"`;
386
+ if (value === null || typeof value !== "object") return shorten(String(value));
387
+ try {
388
+ return shorten(JSON.stringify(value) ?? String(value));
389
+ } catch {
390
+ return shorten(String(value));
391
+ }
392
+ }
393
+ function unreadableValue(at, value, cause, response) {
394
+ return new DecodeError(`Could not read ${at === void 0 ? "the reply" : `\`${at}\` from the reply`}: the API sent ${sent(value)}.`, {
395
+ at,
396
+ cause,
397
+ response,
398
+ value
399
+ });
400
+ }
401
+ //#endregion
402
+ //#region src/internal/codec/registry.ts
403
+ function charsetOf(contentType) {
404
+ return contentType?.match(/;\s*charset\s*=\s*"?([^";\s]+)/i)?.[1];
405
+ }
406
+ function decoderFor(label, fatal) {
407
+ try {
408
+ return new TextDecoder(label, { fatal });
409
+ } catch {
410
+ return new TextDecoder("utf-8", { fatal });
411
+ }
412
+ }
413
+ async function readText(raw, json = false) {
414
+ return decoderFor(json ? void 0 : charsetOf(raw.headers.get("content-type")), raw.ok).decode(await raw.arrayBuffer());
415
+ }
416
+ function essenceOf(mediaType) {
417
+ return mediaType.split(";", 1)[0].trim().toLowerCase();
418
+ }
419
+ function selectCodec(codecs, mediaType) {
420
+ if (!mediaType) return void 0;
421
+ const essence = essenceOf(mediaType);
422
+ const format = essence.replace(/\/.*\+/, "/");
423
+ return codecs.find((codec) => codec.mediaTypes.some((candidate) => [essence, format].includes(essenceOf(candidate))));
424
+ }
425
+ function encodeNamedBody(codecs, mediaType, options) {
426
+ if (options.body === void 0) return void 0;
427
+ if (options.bodySerializer) return {
428
+ contentType: mediaType,
429
+ payload: options.bodySerializer(options.body)
430
+ };
431
+ if (options.bodySerializer === null) return {
432
+ contentType: mediaType,
433
+ payload: options.body
434
+ };
435
+ const codec = selectCodec(codecs, mediaType);
436
+ if (!codec) return {
437
+ contentType: mediaType,
438
+ payload: options.body
439
+ };
440
+ return {
441
+ contentType: codec.contentType,
442
+ payload: codec.encode(options.body)
443
+ };
444
+ }
445
+ //#endregion
446
+ //#region src/internal/core/text.ts
447
+ function scalarText(value) {
448
+ return value instanceof Date ? value.toISOString() : void 0;
449
+ }
450
+ function toText(value) {
451
+ return typeof value === "string" ? value : scalarText(value) ?? String(value);
452
+ }
453
+ //#endregion
454
+ //#region src/internal/core/metadata.ts
455
+ function entriesOf(source) {
456
+ if (typeof source[Symbol.iterator] === "function") return source;
457
+ return Object.entries(source);
458
+ }
459
+ function metadataText(value) {
460
+ if (Array.isArray(value)) return value.map(toText).join(",");
461
+ if (typeof value !== "object" || value === null || scalarText(value) !== void 0) return toText(value);
462
+ const pairs = [];
463
+ for (const [key, item] of Object.entries(value)) if (item !== void 0 && item !== null) pairs.push(key, toText(item));
464
+ return pairs.join(",");
465
+ }
466
+ function mergeMetadata(...sources) {
467
+ const merged = {};
468
+ for (const source of sources) {
469
+ if (!source) continue;
470
+ const seen = /* @__PURE__ */ new Set();
471
+ for (const [key, value] of entriesOf(source)) {
472
+ const name = key.toLowerCase();
473
+ if (value === void 0) continue;
474
+ if (value === null) {
475
+ delete merged[name];
476
+ seen.add(name);
477
+ continue;
478
+ }
479
+ const text = metadataText(value);
480
+ const held = seen.has(name) ? merged[name] : void 0;
481
+ seen.add(name);
482
+ if (held === void 0) merged[name] = text;
483
+ else merged[name] = Array.isArray(held) ? [...held, text] : [held, text];
484
+ }
485
+ }
486
+ return merged;
487
+ }
488
+ const FIELD_VALUE = /^[\t\x20-\x7e\x80-\xff]*$/;
489
+ function isFieldValue(value) {
490
+ return FIELD_VALUE.test(value);
491
+ }
492
+ function metadataPairs(meta) {
493
+ const pairs = [];
494
+ for (const [name, value] of Object.entries(meta)) {
495
+ if (value === void 0) continue;
496
+ if (Array.isArray(value)) {
497
+ for (const item of value) pairs.push([name, item]);
498
+ continue;
499
+ }
500
+ pairs.push([name, value]);
501
+ }
502
+ return pairs;
503
+ }
504
+ function unsendableName(meta) {
505
+ for (const [name, value] of metadataPairs(meta)) if (!isFieldValue(value)) return name;
506
+ }
507
+ function metadataHeaders(meta) {
508
+ const headers = new Headers();
509
+ for (const [name, value] of metadataPairs(meta)) headers.append(name, value);
510
+ return headers;
511
+ }
512
+ function metadataValue(value) {
513
+ if (value === void 0) return void 0;
514
+ return Array.isArray(value) ? value.join(", ") : value;
515
+ }
516
+ //#endregion
517
+ //#region src/internal/core/config.ts
518
+ function foldRetry(sources, merged) {
519
+ if (!sources.some((source) => source?.["retry"] !== void 0)) return merged;
520
+ let retry;
521
+ for (const source of sources) {
522
+ const own = source?.["retry"];
523
+ const count = source?.["maxRetries"];
524
+ const counted = typeof count === "number" && Number.isFinite(count);
525
+ if (own === false) retry = false;
526
+ else if (own !== void 0 || counted) {
527
+ const rules = {
528
+ ...typeof retry === "object" && retry,
529
+ ...typeof own === "object" && own
530
+ };
531
+ if (counted && (typeof own !== "object" || !own || !("maxRetries" in own))) rules["maxRetries"] = count;
532
+ retry = rules;
533
+ }
534
+ }
535
+ merged["retry"] = retry;
536
+ delete merged["maxRetries"];
537
+ return merged;
538
+ }
539
+ const MERGED_LAYERS = ["path", "query"];
540
+ function mergeLayers(sources, merged) {
541
+ for (const key of MERGED_LAYERS) {
542
+ const layers = sources.filter((source) => source?.[key]);
543
+ if (!layers.length) continue;
544
+ const layer = {};
545
+ for (const source of layers) for (const [name, value] of Object.entries(source[key])) if (value !== void 0) layer[name] = value;
546
+ merged[key] = layer;
547
+ }
548
+ return merged;
549
+ }
550
+ function merge(sources, keepAccessors) {
551
+ const merged = {};
552
+ for (const source of sources) {
553
+ if (!source) continue;
554
+ if (keepAccessors) {
555
+ for (const [key, held] of Object.entries(Object.getOwnPropertyDescriptors(source))) if (held.get || held.value !== void 0) Object.defineProperty(merged, key, held);
556
+ } else for (const key of Object.keys(source)) {
557
+ const value = source[key];
558
+ if (value !== void 0) merged[key] = value;
559
+ }
560
+ }
561
+ merged.headers = mergeMetadata(...sources.map((source) => source?.headers));
562
+ return foldRetry(sources, mergeLayers(sources, merged));
563
+ }
564
+ function mergeConfigs(...sources) {
565
+ return merge(sources, false);
566
+ }
567
+ function createConfig(overrides = {}) {
568
+ return mergeConfigs({
569
+ errors: "throw",
570
+ headers: {}
571
+ }, overrides);
572
+ }
573
+ function baseURLOf(options, fallback) {
574
+ return options.baseURL ?? fallback;
575
+ }
576
+ function mergeDefaults(...sources) {
577
+ return merge(sources, true);
578
+ }
579
+ //#endregion
580
+ //#region src/internal/core/credentials.ts
581
+ const LAYER_ALIASES = {
582
+ defaultHeaders: "headers",
583
+ defaultPath: "path",
584
+ defaultQuery: "query"
585
+ };
586
+ function applyAliases(config, aliases) {
587
+ let applied;
588
+ for (const [alias, canonical] of Object.entries(aliases ? {
589
+ ...LAYER_ALIASES,
590
+ ...aliases
591
+ } : LAYER_ALIASES)) {
592
+ if (!(alias in config)) continue;
593
+ applied ??= { ...config };
594
+ if (applied[canonical] === void 0) applied[canonical] = applied[alias];
595
+ delete applied[alias];
596
+ }
597
+ return applied ?? config;
598
+ }
599
+ function applyCredentials(config, credentials) {
600
+ if (!credentials) return config;
601
+ let applied;
602
+ for (const [name, spec] of Object.entries(credentials)) {
603
+ if (spec.option === false || config[name] !== void 0 || !(name in config)) continue;
604
+ applied ??= { ...config };
605
+ delete applied[name];
606
+ }
607
+ return applied ?? config;
608
+ }
609
+ //#endregion
610
+ //#region src/internal/core/body.ts
611
+ function discardBody(result) {
612
+ const { response } = result ?? {};
613
+ if (response && !response.bodyUsed) response.body?.cancel().catch(() => {});
614
+ }
615
+ function isStreamed(body) {
616
+ if (typeof body !== "object" || body === null) return false;
617
+ return typeof body.getReader === "function" || Symbol.asyncIterator in body;
618
+ }
619
+ function replyWith(body, response) {
620
+ const reply = new Response(body, {
621
+ headers: response.headers,
622
+ status: response.status,
623
+ statusText: response.statusText
624
+ });
625
+ Object.defineProperty(reply, "redirected", { value: response.redirected });
626
+ Object.defineProperty(reply, "url", { value: response.url });
627
+ return reply;
628
+ }
629
+ async function bufferReply(response, signal) {
630
+ if (response.body === null) return response;
631
+ const reader = response.body.getReader();
632
+ function cancel() {
633
+ reader.cancel(signal?.reason).catch(() => {});
634
+ }
635
+ if (signal?.aborted) cancel();
636
+ signal?.addEventListener("abort", cancel, { once: true });
637
+ const parts = [];
638
+ try {
639
+ for (;;) {
640
+ const step = await reader.read();
641
+ if (step.done) break;
642
+ parts.push(step.value);
643
+ }
644
+ } finally {
645
+ signal?.removeEventListener("abort", cancel);
646
+ }
647
+ if (signal?.aborted) throw signal.reason;
648
+ return replyWith(new ReadableStream({ start(controller) {
649
+ for (const part of parts) controller.enqueue(part);
650
+ controller.close();
651
+ } }), response);
652
+ }
653
+ //#endregion
654
+ //#region src/internal/core/features.ts
655
+ var FeatureRunner = class {
656
+ features;
657
+ constructor(features = []) {
658
+ this.features = features;
659
+ }
660
+ async options(options, callable, ctx) {
661
+ for (const feature of this.features) await feature.onOptions?.(options, callable, ctx);
662
+ }
663
+ async prepare(request, ctx) {
664
+ for (const feature of this.features) await feature.onPrepare?.(request, ctx);
665
+ }
666
+ async request(request, ctx) {
667
+ for (const feature of this.features) await feature.onRequest?.(request, ctx);
668
+ }
669
+ send(core, ctx, hook = "onSend") {
670
+ let next = core;
671
+ for (let i = this.features.length - 1; i >= 0; i--) {
672
+ const feature = this.features[i];
673
+ if (!feature[hook]) continue;
674
+ const downstream = next;
675
+ next = (request) => feature[hook](request, downstream, ctx);
676
+ }
677
+ return next;
678
+ }
679
+ async result(result, request, ctx) {
680
+ let current = result;
681
+ for (let i = this.features.length - 1; i >= 0; i--) current = await this.features[i].onResult?.(current, request, ctx) ?? current;
682
+ return current;
683
+ }
684
+ async error(error, request, ctx) {
685
+ let current = error;
686
+ for (let i = this.features.length - 1; i >= 0; i--) current = await this.features[i].onError?.(current, request, ctx) ?? current;
687
+ return current;
688
+ }
689
+ };
690
+ //#endregion
691
+ //#region src/internal/core/protocol.ts
692
+ function onlyProtocol(protocols, _interaction) {
693
+ return Object.values(protocols)[0];
694
+ }
695
+ //#endregion
696
+ //#region src/internal/core/dispatch.ts
697
+ async function readReply$1(setup, sent, request, from) {
698
+ const { binding, ctx, runner } = sent;
699
+ try {
700
+ const raw = from ?? sent.result.response;
701
+ let result = request.options.unread || !raw ? sent.result : await binding.readResult(raw, request, setup.codecs);
702
+ result = await runner.result(result, request, ctx);
703
+ if (request.options.unread) return result.response;
704
+ const failure = binding.readError?.(result, request) ?? result.error;
705
+ if (request.options.raw) return failure === void 0 ? result : {
706
+ ...result,
707
+ error: failure
708
+ };
709
+ if (failure !== void 0) {
710
+ if (request.options.errors !== "return" && !request.options.envelope) throw failure;
711
+ return {
712
+ data: void 0,
713
+ error: await runner.error(failure, request, ctx),
714
+ ok: false,
715
+ status: result.status
716
+ };
717
+ }
718
+ return request.options.errors === "return" || request.options.envelope ? {
719
+ data: result.data,
720
+ error: void 0,
721
+ ok: true,
722
+ status: result.status
723
+ } : result.data;
724
+ } catch (error) {
725
+ throw await runner.error(error, request, ctx);
726
+ }
727
+ }
728
+ function rejectUnsendable(transport, request) {
729
+ throw new UnsupportedInteractionError(transport.name, request.interaction);
730
+ }
731
+ function shellOf(request) {
732
+ if (request.options.unread) return request;
733
+ return {
734
+ ...request,
735
+ options: {
736
+ ...request.options,
737
+ unread: true
738
+ }
739
+ };
740
+ }
741
+ function transportFor(setup, named, fallback) {
742
+ if (named === void 0) return fallback;
743
+ if (typeof named !== "string") return named;
744
+ const found = setup.transports?.(named);
745
+ if (!found) throw new ElmoError(`This client carries no transport named "${named}".`);
746
+ return found;
747
+ }
748
+ async function sendRequest(setup, request) {
749
+ const protocol = onlyProtocol(setup.protocols, request.interaction);
750
+ const { binding } = protocol;
751
+ const transport = transportFor(setup, request.options["transport"], protocol.transport);
752
+ const runner = new FeatureRunner(setup.features);
753
+ const ctx = {
754
+ binding,
755
+ transport
756
+ };
757
+ const { unary } = transport;
758
+ if (request.interaction !== "unary" || !unary) rejectUnsendable(transport, request);
759
+ try {
760
+ if (!binding.readResult) throw new ElmoError(`The "${binding.name}" binding reads no reply, so it cannot answer this call.`);
761
+ const send = async (attempt) => {
762
+ await runner.request(attempt, ctx);
763
+ const unsendable = unsendableName(attempt.meta);
764
+ if (unsendable !== void 0) throw unsendableHeader(unsendable);
765
+ attempt.log?.sending();
766
+ let raw;
767
+ try {
768
+ raw = await unary.call(transport, attempt);
769
+ if (!request.options.unread) raw = await bufferReply(raw, attempt.signal);
770
+ } catch (error) {
771
+ throw unansweredError(error);
772
+ }
773
+ return binding.readResult(raw, shellOf(attempt), setup.codecs);
774
+ };
775
+ return {
776
+ binding,
777
+ ctx,
778
+ result: await runner.send(send, ctx)(request),
779
+ runner
780
+ };
781
+ } catch (error) {
782
+ throw await runner.error(error, request, ctx);
783
+ }
784
+ }
785
+ async function execute(setup, request) {
786
+ return readReply$1(setup, await sendRequest(setup, request), request);
787
+ }
788
+ function buildRequestWithoutCookies(setup, callable, resolved) {
789
+ const interaction = callable.interaction ?? "unary";
790
+ const { binding } = onlyProtocol(setup.protocols, interaction);
791
+ const encoded = encodeNamedBody(setup.codecs, callable.mediaType, resolved);
792
+ const meta = mergeMetadata(resolved.headers);
793
+ if (encoded?.contentType && meta["content-type"] === void 0) meta["content-type"] = encoded.contentType;
794
+ const accept = callable.accept ?? setup.accept ?? binding.accept;
795
+ if (accept && meta["accept"] === void 0) meta["accept"] = accept;
796
+ return {
797
+ address: binding.resolveAddress(callable, resolved),
798
+ body: encoded?.payload,
799
+ callable,
800
+ interaction,
801
+ meta,
802
+ options: resolved,
803
+ signal: resolved.signal
804
+ };
805
+ }
806
+ async function prepare(setup, callable, options = {}) {
807
+ const { binding, transport } = onlyProtocol(setup.protocols, callable.interaction);
808
+ const resolved = mergeConfigs(setup.defaults, applyCredentials(applyAliases(options, setup.aliases), setup.credentials));
809
+ const runner = new FeatureRunner(setup.features);
810
+ const ctx = {
811
+ binding,
812
+ transport
813
+ };
814
+ await runner.options(resolved, callable, ctx);
815
+ const request = buildRequestWithoutCookies(setup, callable, resolved);
816
+ await runner.prepare(request, ctx);
817
+ return request;
818
+ }
819
+ async function dispatch(setup, callable, options = {}) {
820
+ return execute(setup, await prepare(setup, callable, options));
821
+ }
822
+ async function exchange(setup, callable, options = {}) {
823
+ const request = await prepare(setup, callable, options);
824
+ const sent = await sendRequest(setup, request);
825
+ let read;
826
+ return {
827
+ read: (from) => read ??= readReply$1(setup, sent, request, from),
828
+ requestId: () => sent.result.response && requestIdOf(sent.result.response),
829
+ response: sent.result.response
830
+ };
831
+ }
832
+ function readEnv(name) {
833
+ const global = globalThis;
834
+ return (global.process?.env?.[name] ?? global.Deno?.env?.get?.(name))?.trim() || void 0;
835
+ }
836
+ function readable(credentials) {
837
+ return Object.keys(credentials).filter((name) => credentials[name].variable && credentials[name].option !== false);
838
+ }
839
+ function envDefaults(base, env = {}, credentials = {}) {
840
+ const reads = /* @__PURE__ */ new WeakMap();
841
+ const held = readable(credentials);
842
+ function resolve() {
843
+ const read = {};
844
+ for (const [option, variable] of Object.entries(env)) {
845
+ const value = readEnv(variable) ?? base[option];
846
+ if (value !== void 0) read[option] = value;
847
+ }
848
+ if (held.length) {
849
+ const tokens = {};
850
+ for (const name of held) tokens[name] = readEnv(credentials[name].variable);
851
+ Object.assign(read, tokens);
852
+ const environment = base.environment;
853
+ if (environment !== void 0) read.environment = environment;
854
+ }
855
+ return read;
856
+ }
857
+ function resolvedFor(holder) {
858
+ let read = reads.get(holder);
859
+ if (!read) {
860
+ read = resolve();
861
+ reads.set(holder, read);
862
+ }
863
+ return read;
864
+ }
865
+ const decided = [
866
+ ...Object.keys(env),
867
+ ...held,
868
+ ...held.length ? ["environment"] : []
869
+ ];
870
+ const defaults = { ...base };
871
+ for (const key of decided) Object.defineProperty(defaults, key, {
872
+ configurable: true,
873
+ enumerable: true,
874
+ get() {
875
+ return resolvedFor(this)[key];
876
+ }
877
+ });
878
+ return defaults;
879
+ }
880
+ //#endregion
881
+ //#region src/internal/core/client.ts
882
+ function clientOf(setup) {
883
+ return Object.defineProperty({
884
+ call(callable, options) {
885
+ return dispatch(setup, callable, options);
886
+ },
887
+ exchange(callable, options) {
888
+ return exchange(setup, callable, options);
889
+ },
890
+ prepare(callable, options = {}) {
891
+ return prepare(setup, callable, options);
892
+ },
893
+ resolveAddress(callable, options = {}) {
894
+ const { binding } = onlyProtocol(setup.protocols, callable.interaction);
895
+ return binding.resolveAddress(callable, mergeConfigs(setup.defaults, options));
896
+ }
897
+ }, "setup", { value: setup });
898
+ }
899
+ function createClient(setup) {
900
+ return clientOf({
901
+ ...setup,
902
+ defaults: envDefaults(setup.defaults, setup.env, setup.credentials)
903
+ });
904
+ }
905
+ function clientFor(args, fallback) {
906
+ const { client, key: _key, ...args_ } = args ?? {};
907
+ const base = client ?? fallback;
908
+ if (!base) throw new ElmoError("This SDK has no client of its own. Pass one as `client`.");
909
+ const config = applyCredentials(applyAliases(args_, base.setup.aliases), base.setup.credentials);
910
+ if (client && !Object.keys(config).length) return client;
911
+ const defaults = mergeDefaults(base.setup.defaults, config);
912
+ base.setup.guard?.(defaults);
913
+ return clientOf({
914
+ ...base.setup,
915
+ defaults
916
+ });
917
+ }
918
+ function withClient(source, client, key = "client") {
919
+ const derived = Object.create(Object.getPrototypeOf(source));
920
+ derived[key] = client;
921
+ return derived;
922
+ }
923
+ //#endregion
924
+ //#region src/internal/core/read-reply.ts
925
+ async function readReply(read, value, _response) {
926
+ return await read(value);
927
+ }
928
+ //#endregion
929
+ //#region src/internal/feature/validate.ts
930
+ async function runValidator(validate, value, options, response) {
931
+ if (!validate || options["validate"] === false) return value;
932
+ return await readReply(validate, value, response);
933
+ }
934
+ function validatorsOf(callable) {
935
+ return callable.validators;
936
+ }
937
+ function validateFeature() {
938
+ return {
939
+ name: "validate",
940
+ async onOptions(options, callable) {
941
+ const validate = validatorsOf(callable)?.request;
942
+ if (!validate || options["validate"] === false) return;
943
+ Object.assign(options, await validate(options));
944
+ },
945
+ async onResult(result, request) {
946
+ const validators = validatorsOf(request.callable);
947
+ if (!validators) return result;
948
+ if (result.error !== void 0 && result.error !== null) result.error = await runValidator(validators.error, result.error, request.options, result.response);
949
+ else if (result.data !== void 0) result.data = await runValidator(validators.response, result.data, request.options, result.response);
950
+ return result;
951
+ }
952
+ };
953
+ }
954
+ function decoded(at, value, read) {
955
+ let result;
956
+ try {
957
+ result = read(value);
958
+ } catch (cause) {
959
+ throw unreadableValue(at, value, cause);
960
+ }
961
+ if (result instanceof Date && Number.isNaN(result.getTime())) throw unreadableValue(at, value);
962
+ return result;
963
+ }
964
+ function reviving(revive) {
965
+ return (data) => {
966
+ if (data != null) revive(data);
967
+ return data;
968
+ };
969
+ }
970
+ //#endregion
971
+ //#region src/resources/shared/auth.ts
972
+ /**
973
+ * An instance admin key from `ADMIN_API_KEYS`, or an organization key (`elmo_…`) issued from the
974
+ * dashboard.
975
+ */
976
+ const apiKeyRequirements = [{
977
+ key: "apiKey",
978
+ scheme: "bearer",
979
+ type: "http"
980
+ }];
981
+ //#endregion
982
+ //#region src/resources/shared/resource.ts
983
+ var ElmoResource = class {
984
+ /** The client every call on this SDK dispatches through. */
985
+ client;
986
+ constructor(client) {
987
+ this.client = client;
988
+ }
989
+ /**
990
+ * The same calls, with different options.
991
+ *
992
+ * Options given here layer over the ones already in force. Headers, path
993
+ * parameters and query parameters merge per name. Everything else replaces.
994
+ * What this was called on does not change.
995
+ */
996
+ withOptions(options) {
997
+ return withClient(this, clientFor(options, this.client));
998
+ }
999
+ };
1000
+ //#endregion
1001
+ //#region src/internal/core/lazy-promise.ts
1002
+ var LazyPromise = class extends Promise {
1003
+ answer;
1004
+ constructor() {
1005
+ super(() => {});
1006
+ }
1007
+ answered() {
1008
+ return this.answer ??= this.settle();
1009
+ }
1010
+ then(onFulfilled, onRejected) {
1011
+ return this.answered().then(onFulfilled, onRejected);
1012
+ }
1013
+ catch(onRejected) {
1014
+ return this.answered().catch(onRejected);
1015
+ }
1016
+ finally(onFinally) {
1017
+ return this.answered().finally(onFinally);
1018
+ }
1019
+ static get [Symbol.species]() {
1020
+ return Promise;
1021
+ }
1022
+ };
1023
+ function unattended(promise) {
1024
+ promise.catch(() => {});
1025
+ return promise;
1026
+ }
1027
+ //#endregion
1028
+ //#region src/internal/core/call-promise.ts
1029
+ function awaitedResult(client, options, result) {
1030
+ if ((options.errors ?? client.setup.defaults.errors) === "return") return result;
1031
+ if (result.ok === false) throw result.error;
1032
+ return result.data;
1033
+ }
1034
+ /** A call already sent, whose reply is not yet read. */
1035
+ var CallPromise = class extends LazyPromise {
1036
+ client;
1037
+ exchange;
1038
+ options;
1039
+ envelope;
1040
+ constructor(client, callable, options = {}) {
1041
+ super();
1042
+ this.client = client;
1043
+ this.options = options;
1044
+ this.exchange = unattended(client.exchange(callable, {
1045
+ ...options,
1046
+ envelope: true
1047
+ }));
1048
+ }
1049
+ /**
1050
+ * The whole result envelope. A failure of the call is returned on it, not
1051
+ * thrown. What one of your own functions throws, such as a hook, is thrown
1052
+ * as it is.
1053
+ */
1054
+ result() {
1055
+ return this.envelope ??= this.read();
1056
+ }
1057
+ /** The payload alone, with a failure thrown rather than handed back. */
1058
+ async unwrap() {
1059
+ const result = await this.result();
1060
+ if (result.ok === false) throw result.error;
1061
+ return result.data;
1062
+ }
1063
+ async read() {
1064
+ try {
1065
+ return await this.decode();
1066
+ } catch (error) {
1067
+ if (!(error instanceof ElmoError)) throw error;
1068
+ return {
1069
+ error,
1070
+ ok: false
1071
+ };
1072
+ }
1073
+ }
1074
+ settle() {
1075
+ return this.result().then((result) => awaitedResult(this.client, this.options, result));
1076
+ }
1077
+ async decode() {
1078
+ return (await this.exchange).read();
1079
+ }
1080
+ };
1081
+ /** A call already sent, whose `Response` can be read as well as its payload. */
1082
+ var RestCallPromise = class extends CallPromise {
1083
+ claimed = false;
1084
+ unread;
1085
+ /**
1086
+ * The `Response` itself, with its body unread and yours to read once. An
1087
+ * error status does not throw here. A call that got no response does.
1088
+ */
1089
+ asResponse() {
1090
+ return this.unread ??= this.claim();
1091
+ }
1092
+ /** The decoded body, the `Response` that carried it, and the request id. */
1093
+ async withResponse() {
1094
+ const data = await this;
1095
+ const exchange = await this.exchange;
1096
+ return {
1097
+ data,
1098
+ requestId: exchange.requestId(),
1099
+ response: exchange.response
1100
+ };
1101
+ }
1102
+ async decode() {
1103
+ const exchange = await this.exchange;
1104
+ const { response } = exchange;
1105
+ if (!this.claimed || !response) return super.decode();
1106
+ if (!response.bodyUsed) return exchange.read(response.clone());
1107
+ throw new ElmoError("The body of this call was already read through asResponse(). Use withResponse() instead, which gives the body and the reply from one call.");
1108
+ }
1109
+ async claim() {
1110
+ const { response } = await this.exchange;
1111
+ if (!response) throw new ElmoError("This call was answered without a `Response`, so there is none to hand back.");
1112
+ if (!response.bodyUsed) this.claimed = true;
1113
+ return response;
1114
+ }
1115
+ };
1116
+ function callPromise(client, callable, options = {}) {
1117
+ return new RestCallPromise(client, callable, options);
1118
+ }
1119
+ //#endregion
1120
+ //#region src/internal/core/callable.ts
1121
+ function callable(descriptor) {
1122
+ return {
1123
+ interaction: "unary",
1124
+ ...descriptor
1125
+ };
1126
+ }
1127
+ //#endregion
1128
+ //#region src/internal/core/params.ts
1129
+ const LAYERS = ["path", "query"];
1130
+ function mergeParams(inputs, options) {
1131
+ const merged = {
1132
+ ...inputs,
1133
+ ...options
1134
+ };
1135
+ if (inputs && options) for (const layer of LAYERS) {
1136
+ const declared = inputs[layer];
1137
+ const given = options[layer];
1138
+ if (!declared || !given) continue;
1139
+ const both = { ...declared };
1140
+ for (const [name, value] of Object.entries(given)) if (value !== void 0) both[name] = value;
1141
+ merged[layer] = both;
1142
+ }
1143
+ return merged;
1144
+ }
1145
+ const placed = /* @__PURE__ */ new WeakMap();
1146
+ function placements(fields) {
1147
+ let known = placed.get(fields);
1148
+ if (!known) {
1149
+ const built = /* @__PURE__ */ new Map();
1150
+ for (const layer of Object.keys(fields)) {
1151
+ const names = fields[layer];
1152
+ if (typeof names === "string") built.set(names, {
1153
+ in: layer,
1154
+ map: names
1155
+ });
1156
+ else if (Array.isArray(names)) for (const key of names) built.set(key, {
1157
+ in: layer,
1158
+ map: key
1159
+ });
1160
+ else if (names) for (const [key, wire] of Object.entries(names)) built.set(key, {
1161
+ in: layer,
1162
+ map: wire
1163
+ });
1164
+ }
1165
+ known = built;
1166
+ placed.set(fields, built);
1167
+ }
1168
+ return known;
1169
+ }
1170
+ function placeParams(options, fields, extras) {
1171
+ const named = placements(fields);
1172
+ const grouped = {};
1173
+ const given = {};
1174
+ for (const [key, value] of Object.entries(options ?? {})) {
1175
+ const place = named.get(key);
1176
+ if (!place) {
1177
+ if (extras === void 0) given[key] = value;
1178
+ else (grouped[extras] ??= {})[key] = value;
1179
+ continue;
1180
+ }
1181
+ if (place.in === "whole") {
1182
+ grouped["body"] = value;
1183
+ continue;
1184
+ }
1185
+ (grouped[place.in] ??= {})[place.map] = value;
1186
+ }
1187
+ return mergeParams(grouped, given);
1188
+ }
1189
+ function groupParams(options, layer) {
1190
+ if (layer === void 0) return { ...options };
1191
+ if (!options || !Object.keys(options).length) return {};
1192
+ return { [layer]: { ...options } };
1193
+ }
1194
+ //#endregion
1195
+ //#region src/resources/analytics.ts
1196
+ const getBrandAnalyticsFields = { path: ["brandId"] };
1197
+ function reviveDateRange(value) {
1198
+ if (value.start != null) value.start = decoded("DateRange.start", value.start, (raw) => new Date(raw));
1199
+ if (value.end != null) value.end = decoded("DateRange.end", value.end, (raw) => new Date(raw));
1200
+ }
1201
+ function reviveBrandAnalytics(value) {
1202
+ if (value.range != null) reviveDateRange(value.range);
1203
+ }
1204
+ const getBrandAnalyticsDescriptor = /* @__PURE__ */ callable({
1205
+ address: "/brands/{brandId}/analytics",
1206
+ auth: apiKeyRequirements,
1207
+ method: "get",
1208
+ returns: "json",
1209
+ validators: { response: /* @__PURE__ */ reviving(reviveBrandAnalytics) }
1210
+ });
1211
+ const listBrandCitationDomainsFields = { path: ["brandId"] };
1212
+ function reviveCitationDomainList(value) {
1213
+ if (value.range != null) reviveDateRange(value.range);
1214
+ }
1215
+ const listBrandCitationDomainsDescriptor = /* @__PURE__ */ callable({
1216
+ address: "/brands/{brandId}/citations/domains",
1217
+ auth: apiKeyRequirements,
1218
+ method: "get",
1219
+ returns: "json",
1220
+ validators: { response: /* @__PURE__ */ reviving(reviveCitationDomainList) }
1221
+ });
1222
+ const listBrandCitationUrlsFields = { path: ["brandId"] };
1223
+ function reviveCitationUrlList(value) {
1224
+ if (value.range != null) reviveDateRange(value.range);
1225
+ }
1226
+ const listBrandCitationURLsDescriptor = /* @__PURE__ */ callable({
1227
+ address: "/brands/{brandId}/citations/urls",
1228
+ auth: apiKeyRequirements,
1229
+ method: "get",
1230
+ returns: "json",
1231
+ validators: { response: /* @__PURE__ */ reviving(reviveCitationUrlList) }
1232
+ });
1233
+ const listBrandPromptPerformanceFields = { path: ["brandId"] };
1234
+ function revivePromptPerformance(value) {
1235
+ if (value.lastRunAt != null) value.lastRunAt = decoded("PromptPerformance.lastRunAt", value.lastRunAt, (raw) => new Date(raw));
1236
+ if (value.firstEvaluatedAt != null) value.firstEvaluatedAt = decoded("PromptPerformance.firstEvaluatedAt", value.firstEvaluatedAt, (raw) => new Date(raw));
1237
+ }
1238
+ function revivePromptPerformanceList(value) {
1239
+ if (value.range != null) reviveDateRange(value.range);
1240
+ if (value.data != null) value.data.forEach((item) => {
1241
+ revivePromptPerformance(item);
1242
+ });
1243
+ }
1244
+ const listBrandPromptPerformanceDescriptor = /* @__PURE__ */ callable({
1245
+ address: "/brands/{brandId}/prompt-performance",
1246
+ auth: apiKeyRequirements,
1247
+ method: "get",
1248
+ returns: "json",
1249
+ validators: { response: /* @__PURE__ */ reviving(revivePromptPerformanceList) }
1250
+ });
1251
+ const getBrandQueryFanoutFields = { path: ["brandId"] };
1252
+ function reviveBrandQueryFanout(value) {
1253
+ if (value.range != null) reviveDateRange(value.range);
1254
+ }
1255
+ const getBrandQueryFanoutDescriptor = /* @__PURE__ */ callable({
1256
+ address: "/brands/{brandId}/query-fanout",
1257
+ auth: apiKeyRequirements,
1258
+ method: "get",
1259
+ returns: "json",
1260
+ validators: { response: /* @__PURE__ */ reviving(reviveBrandQueryFanout) }
1261
+ });
1262
+ /** Aggregated visibility, share of voice, citations, and query fan-out for a brand */
1263
+ var Analytics = class extends ElmoResource {
1264
+ /**
1265
+ * Get a brand's analytics
1266
+ *
1267
+ * Visibility, share of voice, the per-model breakdown and the citation totals for one window, in
1268
+ * one request.
1269
+ *
1270
+ * The long lists — cited domains and URLs, sub-queries, per-prompt results — are endpoints of
1271
+ * their own. Everything else is always included.
1272
+ *
1273
+ * @param brandId Brand identifier.
1274
+ */
1275
+ get(brandId, params, options) {
1276
+ return callPromise(options?.client ?? this.client, getBrandAnalyticsDescriptor, mergeParams(placeParams({
1277
+ ...params,
1278
+ brandId
1279
+ }, getBrandAnalyticsFields, "query"), options));
1280
+ }
1281
+ };
1282
+ /** Aggregated visibility, share of voice, citations, and query fan-out for a brand */
1283
+ var Domains = class extends ElmoResource {
1284
+ /**
1285
+ * List cited domains
1286
+ *
1287
+ * Domains the engines cited when answering this brand's prompts, categorized and compared against
1288
+ * the equal-length window immediately before this one.
1289
+ *
1290
+ * @param brandId Brand identifier.
1291
+ */
1292
+ list(brandId, params, options) {
1293
+ return callPromise(options?.client ?? this.client, listBrandCitationDomainsDescriptor, mergeParams(placeParams({
1294
+ ...params,
1295
+ brandId
1296
+ }, listBrandCitationDomainsFields, "query"), options));
1297
+ }
1298
+ };
1299
+ /** Aggregated visibility, share of voice, citations, and query fan-out for a brand */
1300
+ var URLs = class extends ElmoResource {
1301
+ /**
1302
+ * List cited URLs
1303
+ *
1304
+ * Individual pages the engines cited, with their category and page type.
1305
+ *
1306
+ * @param brandId Brand identifier.
1307
+ */
1308
+ list(brandId, params, options) {
1309
+ return callPromise(options?.client ?? this.client, listBrandCitationURLsDescriptor, mergeParams(placeParams({
1310
+ ...params,
1311
+ brandId
1312
+ }, listBrandCitationUrlsFields, "query"), options));
1313
+ }
1314
+ };
1315
+ var Citations = class extends ElmoResource {
1316
+ _domains;
1317
+ /** Aggregated visibility, share of voice, citations, and query fan-out for a brand */
1318
+ get domains() {
1319
+ return this._domains ??= new Domains(this.client);
1320
+ }
1321
+ _urls;
1322
+ /** Aggregated visibility, share of voice, citations, and query fan-out for a brand */
1323
+ get urls() {
1324
+ return this._urls ??= new URLs(this.client);
1325
+ }
1326
+ };
1327
+ /** Aggregated visibility, share of voice, citations, and query fan-out for a brand */
1328
+ var PromptPerformance = class extends ElmoResource {
1329
+ /**
1330
+ * List prompt performance
1331
+ *
1332
+ * Per-prompt mention rates over the window. The analytics counterpart to `GET /prompts?brandId=`,
1333
+ * which returns prompt configuration rather than results.
1334
+ *
1335
+ * A prompt the brand stopped tracking is not sampled, so it has no results over the window and
1336
+ * does not appear here.
1337
+ *
1338
+ * @param brandId Brand identifier.
1339
+ */
1340
+ list(brandId, params, options) {
1341
+ return callPromise(options?.client ?? this.client, listBrandPromptPerformanceDescriptor, mergeParams(placeParams({
1342
+ ...params,
1343
+ brandId
1344
+ }, listBrandPromptPerformanceFields, "query"), options));
1345
+ }
1346
+ };
1347
+ /** Aggregated visibility, share of voice, citations, and query fan-out for a brand */
1348
+ var QueryFanout = class extends ElmoResource {
1349
+ /**
1350
+ * Get query fan-out
1351
+ *
1352
+ * The searches engines ran while answering this brand's prompts. Engines that don't expose their
1353
+ * searches still contribute runs, so `coverageRate` is the honest denominator.
1354
+ *
1355
+ * @param brandId Brand identifier.
1356
+ */
1357
+ get(brandId, params, options) {
1358
+ return callPromise(options?.client ?? this.client, getBrandQueryFanoutDescriptor, mergeParams(placeParams({
1359
+ ...params,
1360
+ brandId
1361
+ }, getBrandQueryFanoutFields, "query"), options));
1362
+ }
1363
+ };
1364
+ //#endregion
1365
+ //#region src/resources/opportunities.ts
1366
+ const getBrandOpportunitiesFields = { path: ["brandId"] };
1367
+ function reviveBrandOpportunities(value) {
1368
+ if (value.generatedAt != null) value.generatedAt = decoded("BrandOpportunities.generatedAt", value.generatedAt, (raw) => new Date(raw));
1369
+ }
1370
+ const getBrandOpportunitiesDescriptor = /* @__PURE__ */ callable({
1371
+ address: "/brands/{brandId}/opportunities",
1372
+ auth: apiKeyRequirements,
1373
+ method: "get",
1374
+ returns: "json",
1375
+ validators: { response: /* @__PURE__ */ reviving(reviveBrandOpportunities) }
1376
+ });
1377
+ /** Where a brand could win more citations, and why */
1378
+ var Opportunities = class extends ElmoResource {
1379
+ /**
1380
+ * Get the latest opportunities report
1381
+ *
1382
+ * **Experimental — the response shape may still change.**
1383
+ *
1384
+ * The brand's Opportunities report: a prioritized set of ways to get cited more often, with the
1385
+ * tracked prompts and cited pages behind each one. The same analysis the dashboard shows, from
1386
+ * the same code.
1387
+ *
1388
+ * Generation is inline and synchronous. A stored report is served while it is fresh and
1389
+ * regenerated when it is not, so there is nothing to poll for and no way to be handed a stale one
1390
+ * — but a request that triggers a generation waits for it. The freshness window bounds the cost:
1391
+ * however many callers ask, one generation per brand per window. There is deliberately no `POST`,
1392
+ * which would spend provider budget with nothing metering it per call.
1393
+ *
1394
+ * @experimental
1395
+ * @param brandId Brand identifier.
1396
+ */
1397
+ get(brandId, options) {
1398
+ return callPromise(options?.client ?? this.client, getBrandOpportunitiesDescriptor, mergeParams(placeParams({ brandId }, getBrandOpportunitiesFields, "query"), options));
1399
+ }
1400
+ };
1401
+ //#endregion
1402
+ //#region src/resources/shared/rule.ts
1403
+ const nameRule = {
1404
+ min: 1,
1405
+ name: "name",
1406
+ of: "characters"
1407
+ };
1408
+ const domainsRule = {
1409
+ min: 1,
1410
+ name: "domains",
1411
+ of: "items"
1412
+ };
1413
+ const brandNameRule = {
1414
+ min: 1,
1415
+ name: "brandName",
1416
+ of: "characters"
1417
+ };
1418
+ const valueRule = {
1419
+ min: 1,
1420
+ name: "value",
1421
+ of: "characters"
1422
+ };
1423
+ //#endregion
1424
+ //#region src/resources/tags.ts
1425
+ const listBrandTagsFields = { path: ["brandId"] };
1426
+ const listBrandTagsDescriptor = /* @__PURE__ */ callable({
1427
+ address: "/brands/{brandId}/tags",
1428
+ auth: apiKeyRequirements,
1429
+ method: "get",
1430
+ returns: "json"
1431
+ });
1432
+ /** The tags in use on a brand's prompts */
1433
+ var Tags = class extends ElmoResource {
1434
+ /**
1435
+ * List a brand's tags
1436
+ *
1437
+ * Every tag in use on the brand's prompts, with how many carry each — enough to build the same
1438
+ * filter the dashboard shows without paging the whole prompt list to derive it.
1439
+ *
1440
+ * Tags are not a resource of their own: a tag exists exactly as long as some prompt carries it.
1441
+ * `branded` and `unbranded` are computed by Elmo and always listed.
1442
+ *
1443
+ * @param brandId Brand identifier.
1444
+ */
1445
+ list(brandId, options) {
1446
+ return callPromise(options?.client ?? this.client, listBrandTagsDescriptor, mergeParams(placeParams({ brandId }, listBrandTagsFields, "query"), options));
1447
+ }
1448
+ };
1449
+ //#endregion
1450
+ //#region src/internal/page/page.ts
1451
+ function readPath(value, path) {
1452
+ if (!path) return value;
1453
+ let current = value;
1454
+ for (const key of path.split(".")) {
1455
+ if (current === null || typeof current !== "object") return void 0;
1456
+ current = current[key];
1457
+ }
1458
+ return current;
1459
+ }
1460
+ function readItems(data, pagination) {
1461
+ const items = readPath(data, pagination.items);
1462
+ return Array.isArray(items) ? items : [];
1463
+ }
1464
+ function withPosition(options, pagination, value) {
1465
+ const name = pagination.param;
1466
+ if (!name) return options;
1467
+ if ((pagination.in ?? "query") === "body") return {
1468
+ ...options,
1469
+ body: {
1470
+ ...options.body,
1471
+ [name]: value
1472
+ }
1473
+ };
1474
+ return {
1475
+ ...options,
1476
+ query: {
1477
+ ...options.query,
1478
+ [name]: value
1479
+ }
1480
+ };
1481
+ }
1482
+ function resumeAt(walk, pagination, param) {
1483
+ if (pagination.style === "link") {
1484
+ const options = { ...walk.options };
1485
+ delete options.query;
1486
+ return {
1487
+ ...walk,
1488
+ descriptor: {
1489
+ ...walk.descriptor,
1490
+ address: param
1491
+ },
1492
+ options
1493
+ };
1494
+ }
1495
+ const options = withPosition(walk.options, pagination, param);
1496
+ if (pagination.style === "cursor") return {
1497
+ ...walk,
1498
+ cursor: param,
1499
+ options
1500
+ };
1501
+ return {
1502
+ ...walk,
1503
+ options,
1504
+ position: param
1505
+ };
1506
+ }
1507
+ function readCount(data, path) {
1508
+ if (!path) return void 0;
1509
+ const value = readPath(data, path);
1510
+ if (typeof value !== "number" || !Number.isFinite(value) || value < 0) return void 0;
1511
+ return value;
1512
+ }
1513
+ function startOf(pagination) {
1514
+ return pagination.start ?? (pagination.style === "page" ? 1 : 0);
1515
+ }
1516
+ function stepCounted(walk, pagination, result, count, limit) {
1517
+ if (!count) return void 0;
1518
+ const size = readCount(result.data, pagination.size) ?? limit;
1519
+ const position = walk.position + (pagination.style === "page" ? 1 : size || count);
1520
+ const start = startOf(pagination);
1521
+ const pages = pagination.style === "page" ? readCount(result.data, pagination.pages) : void 0;
1522
+ const total = readCount(result.data, pagination.total);
1523
+ if (pages === void 0 && total === void 0 && size !== void 0 && count < size) return;
1524
+ if (pages !== void 0 && position - start >= pages) return void 0;
1525
+ if (total !== void 0) {
1526
+ if ((pagination.style === "page" ? (position - start) * (size ?? count) : position) >= total) return void 0;
1527
+ }
1528
+ return position;
1529
+ }
1530
+ const STEPPERS = { page: stepCounted };
1531
+ const SCHEME_RE = /^[a-z][a-z\d+.-]*:/i;
1532
+ function pageURL(address) {
1533
+ if (typeof address !== "string") return void 0;
1534
+ try {
1535
+ const url = new URL(address, globalThis.location?.href);
1536
+ return url.origin === "null" ? void 0 : url;
1537
+ } catch {
1538
+ return;
1539
+ }
1540
+ }
1541
+ function followLink(client, walk, link) {
1542
+ const own = pageURL(client.resolveAddress(walk.descriptor, walk.options));
1543
+ if (!own) {
1544
+ if (!SCHEME_RE.test(link) && !link.startsWith("//")) return link;
1545
+ throw new ElmoError("Pagination stopped: the next page names a host, and no base URL says which host this client sends its credentials to.");
1546
+ }
1547
+ const target = new URL(link, own);
1548
+ if (target.origin !== own.origin) throw new ElmoError(`Pagination stopped: the next page is on ${target.origin}, and this client sends its credentials only to ${own.origin}.`);
1549
+ return SCHEME_RE.test(link) ? link : target.href;
1550
+ }
1551
+ function saysMore(data, pagination) {
1552
+ return !pagination.more || readPath(data, pagination.more) !== false;
1553
+ }
1554
+ function stepWalk(client, walk, pagination, result, count, limit) {
1555
+ const step = STEPPERS[pagination.style];
1556
+ if (!step) throw new ElmoError(`Cannot walk "${walk.descriptor.address}": this client does not page by "${pagination.style}".`);
1557
+ if (!saysMore(result.data, pagination)) return void 0;
1558
+ const next = step(walk, pagination, result, count, limit);
1559
+ return pagination.style === "link" && next !== void 0 ? followLink(client, walk, next) : next;
1560
+ }
1561
+ async function* walkFrom(page, maxPages) {
1562
+ let current = page;
1563
+ for (let index = 1;; index++) {
1564
+ for (const item of current.data) yield item;
1565
+ if (index >= maxPages || !current.hasNextPage()) return;
1566
+ current = await current.getNextPage();
1567
+ }
1568
+ }
1569
+ async function loadPage(client, walk, pagination, limit, maxPages) {
1570
+ const result = await client.call(walk.descriptor, walk.options);
1571
+ if (result.error !== void 0) throw result.error;
1572
+ const data = readItems(result.data, pagination);
1573
+ const param = stepWalk(client, walk, pagination, result, data.length, limit);
1574
+ const page = {
1575
+ [Symbol.asyncIterator]: () => walkFrom(page, maxPages),
1576
+ body: result.data,
1577
+ data,
1578
+ getNextPage: () => {
1579
+ if (param === void 0) return Promise.reject(new ElmoError(`"${walk.descriptor.address}" has no page after this one. Check \`hasNextPage()\` first.`));
1580
+ return loadPage(client, resumeAt(walk, pagination, param), pagination, limit, maxPages);
1581
+ },
1582
+ hasNextPage: () => param !== void 0,
1583
+ nextPageParam: param,
1584
+ status: result.status
1585
+ };
1586
+ return page;
1587
+ }
1588
+ function maxPagesFor(client, options) {
1589
+ return options["maxPages"] ?? client.setup.defaults["maxPages"] ?? 1e3;
1590
+ }
1591
+ function openedAt(options, pagination) {
1592
+ if (!pagination.param) return void 0;
1593
+ return options[pagination.in ?? "query"]?.[pagination.param];
1594
+ }
1595
+ function paginationOf(callable) {
1596
+ if (callable.pagination) return callable.pagination;
1597
+ throw new ElmoError(`"${callable.address}" is not a paged call, so it has no pages to walk.`);
1598
+ }
1599
+ function openWalk(callable, options) {
1600
+ const pagination = paginationOf(callable);
1601
+ const opened = openedAt(options, pagination);
1602
+ return {
1603
+ cursor: pagination.style === "cursor" ? opened : void 0,
1604
+ descriptor: callable,
1605
+ options: {
1606
+ ...options,
1607
+ raw: true
1608
+ },
1609
+ position: typeof opened === "number" && Number.isFinite(opened) ? opened : startOf(pagination)
1610
+ };
1611
+ }
1612
+ function pageStream(load, maxPages) {
1613
+ return { async *[Symbol.asyncIterator]() {
1614
+ let current = await load();
1615
+ for (let index = 1;; index++) {
1616
+ yield current;
1617
+ if (index >= maxPages || !current.hasNextPage()) return;
1618
+ current = await current.getNextPage();
1619
+ }
1620
+ } };
1621
+ }
1622
+ function requestedLimit(options, pagination) {
1623
+ if (!pagination.limitParam) return void 0;
1624
+ const layer = options[pagination.in ?? "query"];
1625
+ const limit = Number(layer?.[pagination.limitParam]);
1626
+ return Number.isFinite(limit) && limit > 0 ? limit : void 0;
1627
+ }
1628
+ /**
1629
+ * A paginated call. Awaiting it gives the first page, or its result envelope
1630
+ * under the `'return'` error mode. Iterating it gives every item on every page,
1631
+ * and throws on a failed page under either mode.
1632
+ */
1633
+ var PagePromise = class extends LazyPromise {
1634
+ envelope;
1635
+ callable;
1636
+ client;
1637
+ limit;
1638
+ maxPages;
1639
+ options;
1640
+ pagination;
1641
+ project;
1642
+ first;
1643
+ constructor(client, callable, options, project) {
1644
+ super();
1645
+ this.callable = callable;
1646
+ this.client = client;
1647
+ this.options = options;
1648
+ this.pagination = paginationOf(callable);
1649
+ this.limit = requestedLimit(options, this.pagination);
1650
+ this.maxPages = maxPagesFor(client, options);
1651
+ this.project = project;
1652
+ const opened = openWalk(this.callable, this.options);
1653
+ const param = options["pageParam"];
1654
+ this.first = unattended(loadPage(this.client, param === void 0 ? opened : resumeAt(opened, this.pagination, param), this.pagination, this.limit, this.maxPages));
1655
+ }
1656
+ /** Every item, page after page, up to `maxPages`. */
1657
+ async *[Symbol.asyncIterator]() {
1658
+ yield* walkFrom(await this.first, this.maxPages);
1659
+ }
1660
+ /** Every page, up to `maxPages`. */
1661
+ iterPages() {
1662
+ return pageStream(() => this.first, this.maxPages);
1663
+ }
1664
+ /**
1665
+ * The whole result envelope. A failure of the call is returned on it, not
1666
+ * thrown. What one of your own functions throws, such as a hook, is thrown
1667
+ * as it is.
1668
+ */
1669
+ result() {
1670
+ return this.envelope ??= this.read();
1671
+ }
1672
+ /** The page alone, with a failure thrown rather than handed back. */
1673
+ async unwrap() {
1674
+ const result = await this.result();
1675
+ if (result.ok === false) throw result.error;
1676
+ return result.data;
1677
+ }
1678
+ async read() {
1679
+ try {
1680
+ const page = await this.first;
1681
+ return {
1682
+ data: this.project(page),
1683
+ ok: true,
1684
+ status: page.status
1685
+ };
1686
+ } catch (error) {
1687
+ if (!(error instanceof ElmoError)) throw error;
1688
+ return {
1689
+ error,
1690
+ ok: false,
1691
+ status: error instanceof APIError ? error.status : void 0
1692
+ };
1693
+ }
1694
+ }
1695
+ settle() {
1696
+ return this.result().then((result) => awaitedResult(this.client, this.options, result));
1697
+ }
1698
+ };
1699
+ function pages(client, callable, options = {}) {
1700
+ return new PagePromise(client, callable, options, (page) => page);
1701
+ }
1702
+ //#endregion
1703
+ //#region src/resources/brands.ts
1704
+ function reviveBrand(value) {
1705
+ if (value.createdAt != null) value.createdAt = decoded("Brand.createdAt", value.createdAt, (raw) => new Date(raw));
1706
+ if (value.updatedAt != null) value.updatedAt = decoded("Brand.updatedAt", value.updatedAt, (raw) => new Date(raw));
1707
+ }
1708
+ function reviveBrandsList(value) {
1709
+ if (value.data != null) value.data.forEach((item) => {
1710
+ reviveBrand(item);
1711
+ });
1712
+ if (value.brands != null) value.brands.forEach((item) => {
1713
+ reviveBrand(item);
1714
+ });
1715
+ }
1716
+ const listBrandsDescriptor = /* @__PURE__ */ callable({
1717
+ address: "/brands",
1718
+ auth: apiKeyRequirements,
1719
+ method: "get",
1720
+ pagination: {
1721
+ items: "data",
1722
+ limitParam: "limit",
1723
+ pages: "pagination.totalPages",
1724
+ param: "page",
1725
+ size: "pagination.limit",
1726
+ style: "page",
1727
+ total: "pagination.total"
1728
+ },
1729
+ returns: "json",
1730
+ validators: { response: /* @__PURE__ */ reviving(reviveBrandsList) }
1731
+ });
1732
+ const createBrandDescriptor = /* @__PURE__ */ callable({
1733
+ address: "/brands",
1734
+ auth: apiKeyRequirements,
1735
+ mediaType: "application/json",
1736
+ method: "post",
1737
+ returns: "json",
1738
+ rules: [
1739
+ {
1740
+ min: 1,
1741
+ name: "id",
1742
+ of: "characters"
1743
+ },
1744
+ nameRule,
1745
+ domainsRule
1746
+ ],
1747
+ validators: { response: /* @__PURE__ */ reviving(reviveBrand) }
1748
+ });
1749
+ const getBrandFields = { path: ["brandId"] };
1750
+ const getBrandDescriptor = /* @__PURE__ */ callable({
1751
+ address: "/brands/{brandId}",
1752
+ auth: apiKeyRequirements,
1753
+ method: "get",
1754
+ returns: "json",
1755
+ validators: { response: /* @__PURE__ */ reviving(reviveBrand) }
1756
+ });
1757
+ const updateBrandFields = { path: ["brandId"] };
1758
+ const updateBrandDescriptor = /* @__PURE__ */ callable({
1759
+ address: "/brands/{brandId}",
1760
+ auth: apiKeyRequirements,
1761
+ mediaType: "application/json",
1762
+ method: "patch",
1763
+ returns: "json",
1764
+ rules: [brandNameRule, domainsRule],
1765
+ validators: { response: /* @__PURE__ */ reviving(reviveBrand) }
1766
+ });
1767
+ /** Manage brand records */
1768
+ var Brands = class extends ElmoResource {
1769
+ /** Create a brand */
1770
+ create(params, options) {
1771
+ return callPromise(options?.client ?? this.client, createBrandDescriptor, mergeParams(groupParams(params, "body"), options));
1772
+ }
1773
+ /**
1774
+ * Get a brand
1775
+ *
1776
+ * @param brandId Brand identifier
1777
+ */
1778
+ get(brandId, options) {
1779
+ return callPromise(options?.client ?? this.client, getBrandDescriptor, mergeParams(placeParams({ brandId }, getBrandFields, "query"), options));
1780
+ }
1781
+ list(params, options) {
1782
+ return pages(options?.client ?? this.client, listBrandsDescriptor, mergeParams(groupParams(params, "query"), options));
1783
+ }
1784
+ /**
1785
+ * Update a brand
1786
+ *
1787
+ * @param brandId Brand identifier
1788
+ */
1789
+ update(brandId, params, options) {
1790
+ return callPromise(options?.client ?? this.client, updateBrandDescriptor, mergeParams(placeParams({
1791
+ ...params,
1792
+ brandId
1793
+ }, updateBrandFields, "body"), options));
1794
+ }
1795
+ _analytics;
1796
+ /** Aggregated visibility, share of voice, citations, and query fan-out for a brand */
1797
+ get analytics() {
1798
+ return this._analytics ??= new Analytics(this.client);
1799
+ }
1800
+ _citations;
1801
+ get citations() {
1802
+ return this._citations ??= new Citations(this.client);
1803
+ }
1804
+ _opportunities;
1805
+ /** Where a brand could win more citations, and why */
1806
+ get opportunities() {
1807
+ return this._opportunities ??= new Opportunities(this.client);
1808
+ }
1809
+ _promptPerformance;
1810
+ /** Aggregated visibility, share of voice, citations, and query fan-out for a brand */
1811
+ get promptPerformance() {
1812
+ return this._promptPerformance ??= new PromptPerformance(this.client);
1813
+ }
1814
+ _queryFanout;
1815
+ /** Aggregated visibility, share of voice, citations, and query fan-out for a brand */
1816
+ get queryFanout() {
1817
+ return this._queryFanout ??= new QueryFanout(this.client);
1818
+ }
1819
+ _tags;
1820
+ /** The tags in use on a brand's prompts */
1821
+ get tags() {
1822
+ return this._tags ??= new Tags(this.client);
1823
+ }
1824
+ };
1825
+ //#endregion
1826
+ //#region src/resources/competitors.ts
1827
+ function reviveCompetitor(value) {
1828
+ if (value.createdAt != null) value.createdAt = decoded("Competitor.createdAt", value.createdAt, (raw) => new Date(raw));
1829
+ if (value.updatedAt != null) value.updatedAt = decoded("Competitor.updatedAt", value.updatedAt, (raw) => new Date(raw));
1830
+ }
1831
+ function reviveCompetitorsList(value) {
1832
+ if (value.data != null) value.data.forEach((item) => {
1833
+ reviveCompetitor(item);
1834
+ });
1835
+ if (value.competitors != null) value.competitors.forEach((item) => {
1836
+ reviveCompetitor(item);
1837
+ });
1838
+ }
1839
+ const listCompetitorsDescriptor = /* @__PURE__ */ callable({
1840
+ address: "/competitors",
1841
+ auth: apiKeyRequirements,
1842
+ method: "get",
1843
+ pagination: {
1844
+ items: "data",
1845
+ limitParam: "limit",
1846
+ pages: "pagination.totalPages",
1847
+ param: "page",
1848
+ size: "pagination.limit",
1849
+ style: "page",
1850
+ total: "pagination.total"
1851
+ },
1852
+ returns: "json",
1853
+ validators: { response: /* @__PURE__ */ reviving(reviveCompetitorsList) }
1854
+ });
1855
+ const createCompetitorDescriptor = /* @__PURE__ */ callable({
1856
+ address: "/competitors",
1857
+ auth: apiKeyRequirements,
1858
+ mediaType: "application/json",
1859
+ method: "post",
1860
+ returns: "json",
1861
+ rules: [{
1862
+ min: 1,
1863
+ name: "brandId",
1864
+ of: "characters"
1865
+ }, nameRule],
1866
+ validators: { response: /* @__PURE__ */ reviving(reviveCompetitor) }
1867
+ });
1868
+ const deleteCompetitorFields = { path: ["competitorId"] };
1869
+ const deleteCompetitorDescriptor = /* @__PURE__ */ callable({
1870
+ address: "/competitors/{competitorId}",
1871
+ auth: apiKeyRequirements,
1872
+ method: "delete",
1873
+ returns: "json",
1874
+ validators: { response: /* @__PURE__ */ reviving(reviveCompetitor) }
1875
+ });
1876
+ const getCompetitorFields = { path: ["competitorId"] };
1877
+ const getCompetitorDescriptor = /* @__PURE__ */ callable({
1878
+ address: "/competitors/{competitorId}",
1879
+ auth: apiKeyRequirements,
1880
+ method: "get",
1881
+ returns: "json",
1882
+ validators: { response: /* @__PURE__ */ reviving(reviveCompetitor) }
1883
+ });
1884
+ const updateCompetitorFields = { path: ["competitorId"] };
1885
+ const updateCompetitorDescriptor = /* @__PURE__ */ callable({
1886
+ address: "/competitors/{competitorId}",
1887
+ auth: apiKeyRequirements,
1888
+ mediaType: "application/json",
1889
+ method: "patch",
1890
+ returns: "json",
1891
+ rules: [nameRule],
1892
+ validators: { response: /* @__PURE__ */ reviving(reviveCompetitor) }
1893
+ });
1894
+ /** Manage brand competitors */
1895
+ var Competitors = class extends ElmoResource {
1896
+ /** Add a competitor */
1897
+ create(params, options) {
1898
+ return callPromise(options?.client ?? this.client, createCompetitorDescriptor, mergeParams(groupParams(params, "body"), options));
1899
+ }
1900
+ /**
1901
+ * Delete a competitor
1902
+ *
1903
+ * @param competitorId Competitor identifier (UUID)
1904
+ */
1905
+ delete(competitorId, options) {
1906
+ return callPromise(options?.client ?? this.client, deleteCompetitorDescriptor, mergeParams(placeParams({ competitorId }, deleteCompetitorFields, "query"), options));
1907
+ }
1908
+ /**
1909
+ * Get a competitor
1910
+ *
1911
+ * @param competitorId Competitor identifier (UUID)
1912
+ */
1913
+ get(competitorId, options) {
1914
+ return callPromise(options?.client ?? this.client, getCompetitorDescriptor, mergeParams(placeParams({ competitorId }, getCompetitorFields, "query"), options));
1915
+ }
1916
+ list(params, options) {
1917
+ return pages(options?.client ?? this.client, listCompetitorsDescriptor, mergeParams(groupParams(params, "query"), options));
1918
+ }
1919
+ /**
1920
+ * Update a competitor
1921
+ *
1922
+ * @param competitorId Competitor identifier (UUID)
1923
+ */
1924
+ update(competitorId, params, options) {
1925
+ return callPromise(options?.client ?? this.client, updateCompetitorDescriptor, mergeParams(placeParams({
1926
+ ...params,
1927
+ competitorId
1928
+ }, updateCompetitorFields, "body"), options));
1929
+ }
1930
+ };
1931
+ //#endregion
1932
+ //#region src/resources/identity.ts
1933
+ function reviveApiKeyIdentity(value) {
1934
+ if (value.createdAt != null) value.createdAt = decoded("ApiKeyIdentity.createdAt", value.createdAt, (raw) => new Date(raw));
1935
+ if (value.expiresAt != null) value.expiresAt = decoded("ApiKeyIdentity.expiresAt", value.expiresAt, (raw) => new Date(raw));
1936
+ if (value.lastUsedAt != null) value.lastUsedAt = decoded("ApiKeyIdentity.lastUsedAt", value.lastUsedAt, (raw) => new Date(raw));
1937
+ }
1938
+ const getMeDescriptor = /* @__PURE__ */ callable({
1939
+ address: "/me",
1940
+ auth: apiKeyRequirements,
1941
+ method: "get",
1942
+ returns: "json",
1943
+ validators: { response: /* @__PURE__ */ reviving(reviveApiKeyIdentity) }
1944
+ });
1945
+ /** What the calling key is and what it may reach */
1946
+ var Me = class extends ElmoResource {
1947
+ /**
1948
+ * Describe the calling key
1949
+ *
1950
+ * What this key is, which organization and brands it reaches, and which scopes it holds. Requires
1951
+ * no scope, so it is always safe to call first when wiring up an integration.
1952
+ */
1953
+ get(options) {
1954
+ return callPromise(options?.client ?? this.client, getMeDescriptor, options);
1955
+ }
1956
+ };
1957
+ //#endregion
1958
+ //#region src/resources/models.ts
1959
+ const listModelsDescriptor = /* @__PURE__ */ callable({
1960
+ address: "/models",
1961
+ auth: apiKeyRequirements,
1962
+ method: "get",
1963
+ returns: "json"
1964
+ });
1965
+ /** The answer engines this deployment can track */
1966
+ var Models = class extends ElmoResource {
1967
+ /**
1968
+ * List trackable models
1969
+ *
1970
+ * The answer engines this deployment can track, so a client can build a model filter without
1971
+ * hardcoding ids that differ between deployments.
1972
+ *
1973
+ * Requires no scope.
1974
+ */
1975
+ list(options) {
1976
+ return callPromise(options?.client ?? this.client, listModelsDescriptor, options);
1977
+ }
1978
+ };
1979
+ //#endregion
1980
+ //#region src/resources/organizations.ts
1981
+ const getOrganizationBillingFields = { path: ["organizationId"] };
1982
+ function reviveBillingPlan(value) {
1983
+ if (value.periodEnd != null) value.periodEnd = decoded("BillingPlan.periodEnd", value.periodEnd, (raw) => new Date(raw));
1984
+ }
1985
+ function reviveOrganizationBilling(value) {
1986
+ if (value.plan != null) reviveBillingPlan(value.plan);
1987
+ }
1988
+ const getOrganizationBillingDescriptor = /* @__PURE__ */ callable({
1989
+ address: "/organizations/{organizationId}/billing",
1990
+ auth: apiKeyRequirements,
1991
+ method: "get",
1992
+ returns: "json",
1993
+ validators: { response: /* @__PURE__ */ reviving(reviveOrganizationBilling) }
1994
+ });
1995
+ function reviveOrganization(value) {
1996
+ if (value.createdAt != null) value.createdAt = decoded("Organization.createdAt", value.createdAt, (raw) => new Date(raw));
1997
+ }
1998
+ function reviveOrganizationList(value) {
1999
+ if (value.data != null) value.data.forEach((item) => {
2000
+ reviveOrganization(item);
2001
+ });
2002
+ }
2003
+ const listOrganizationsDescriptor = /* @__PURE__ */ callable({
2004
+ address: "/organizations",
2005
+ auth: apiKeyRequirements,
2006
+ method: "get",
2007
+ pagination: {
2008
+ items: "data",
2009
+ limitParam: "limit",
2010
+ pages: "pagination.totalPages",
2011
+ param: "page",
2012
+ size: "pagination.limit",
2013
+ style: "page",
2014
+ total: "pagination.total"
2015
+ },
2016
+ returns: "json",
2017
+ validators: { response: /* @__PURE__ */ reviving(reviveOrganizationList) }
2018
+ });
2019
+ const getOrganizationFields = { path: ["organizationId"] };
2020
+ const getOrganizationDescriptor = /* @__PURE__ */ callable({
2021
+ address: "/organizations/{organizationId}",
2022
+ auth: apiKeyRequirements,
2023
+ method: "get",
2024
+ returns: "json",
2025
+ validators: { response: /* @__PURE__ */ reviving(reviveOrganization) }
2026
+ });
2027
+ /** Organizations, their plan limits, and their usage */
2028
+ var Billing = class extends ElmoResource {
2029
+ /**
2030
+ * Get billing state
2031
+ *
2032
+ * The organization's plan, its limits, and how much of each limit is already spent — enough for
2033
+ * an integration to know a write will be rejected before attempting it.
2034
+ *
2035
+ * This endpoint is read-only by construction. No API key of any kind can change a subscription,
2036
+ * an add-on quantity, or a payment method; there is no billing write endpoint and no billing
2037
+ * write scope. Stripe identifiers, invoices, and payment methods are never returned.
2038
+ *
2039
+ * Deployments without billing answer `200` with `billingEnabled: false`, a null plan, and null
2040
+ * limits, so callers need no special case.
2041
+ */
2042
+ get(organizationId, options) {
2043
+ return callPromise(options?.client ?? this.client, getOrganizationBillingDescriptor, mergeParams(placeParams({ organizationId }, getOrganizationBillingFields, "query"), options));
2044
+ }
2045
+ };
2046
+ /** Organizations, their plan limits, and their usage */
2047
+ var Organizations = class extends ElmoResource {
2048
+ /**
2049
+ * Get an organization
2050
+ *
2051
+ * No scope required. An organization outside the key's reach answers `404`, identically to one
2052
+ * that does not exist.
2053
+ */
2054
+ get(organizationId, options) {
2055
+ return callPromise(options?.client ?? this.client, getOrganizationDescriptor, mergeParams(placeParams({ organizationId }, getOrganizationFields, "query"), options));
2056
+ }
2057
+ /**
2058
+ * One entry for an organization key — the one it acts inside. Every organization for an instance
2059
+ * admin key. No scope required: a key can only ever see the organization it is already bound to.
2060
+ */
2061
+ list(params, options) {
2062
+ return pages(options?.client ?? this.client, listOrganizationsDescriptor, mergeParams(groupParams(params, "query"), options));
2063
+ }
2064
+ _billing;
2065
+ /** Organizations, their plan limits, and their usage */
2066
+ get billing() {
2067
+ return this._billing ??= new Billing(this.client);
2068
+ }
2069
+ };
2070
+ //#endregion
2071
+ //#region src/resources/runs.ts
2072
+ const listPromptRunsFields = { path: ["promptId"] };
2073
+ function reviveRunSummary(value) {
2074
+ if (value.createdAt != null) value.createdAt = decoded("RunSummary.createdAt", value.createdAt, (raw) => new Date(raw));
2075
+ }
2076
+ function reviveRunList(value) {
2077
+ if (value.data != null) value.data.forEach((item) => {
2078
+ reviveRunSummary(item);
2079
+ });
2080
+ }
2081
+ const listPromptRunsDescriptor = /* @__PURE__ */ callable({
2082
+ address: "/prompts/{promptId}/runs",
2083
+ auth: apiKeyRequirements,
2084
+ method: "get",
2085
+ pagination: {
2086
+ items: "data",
2087
+ limitParam: "limit",
2088
+ pages: "pagination.totalPages",
2089
+ param: "page",
2090
+ size: "pagination.limit",
2091
+ style: "page",
2092
+ total: "pagination.total"
2093
+ },
2094
+ returns: "json",
2095
+ validators: { response: /* @__PURE__ */ reviving(reviveRunList) }
2096
+ });
2097
+ const getRunFields = { path: ["promptId", "runId"] };
2098
+ function reviveRun(value) {
2099
+ if (value.createdAt != null) value.createdAt = decoded("Run.createdAt", value.createdAt, (raw) => new Date(raw));
2100
+ }
2101
+ const getRunDescriptor = /* @__PURE__ */ callable({
2102
+ address: "/prompts/{promptId}/runs/{runId}",
2103
+ auth: apiKeyRequirements,
2104
+ method: "get",
2105
+ returns: "json",
2106
+ validators: { response: /* @__PURE__ */ reviving(reviveRun) }
2107
+ });
2108
+ /** Individual model answers behind the aggregates */
2109
+ var Runs = class extends ElmoResource {
2110
+ /**
2111
+ * Get a run
2112
+ *
2113
+ * One model answer, with its text normalized out of the provider’s response and its citations in
2114
+ * the order the engine listed them. A run belonging to some other prompt answers `404`. The
2115
+ * provider’s raw payload is deliberately not exposed — its shape belongs to the provider, not to
2116
+ * this API.
2117
+ */
2118
+ get(promptId, runId, options) {
2119
+ return callPromise(options?.client ?? this.client, getRunDescriptor, mergeParams(placeParams({
2120
+ promptId,
2121
+ runId
2122
+ }, getRunFields, "query"), options));
2123
+ }
2124
+ /**
2125
+ * List runs for a prompt
2126
+ *
2127
+ * Individual model answers behind the aggregates, newest first, without their text — the list
2128
+ * stays small enough to page through. Fetch `prompts.runs.get()` for the answer itself.
2129
+ */
2130
+ list(promptId, params, options) {
2131
+ return pages(options?.client ?? this.client, listPromptRunsDescriptor, mergeParams(placeParams({
2132
+ ...params,
2133
+ promptId
2134
+ }, listPromptRunsFields, "query"), options));
2135
+ }
2136
+ };
2137
+ //#endregion
2138
+ //#region src/resources/snapshots.ts
2139
+ const getPromptSnapshotFields = { path: ["promptId"] };
2140
+ const getPromptSnapshotDescriptor = /* @__PURE__ */ callable({
2141
+ address: "/prompts/{promptId}/snapshot",
2142
+ auth: apiKeyRequirements,
2143
+ method: "get",
2144
+ returns: "json"
2145
+ });
2146
+ /** Aggregated analytics snapshots for prompts */
2147
+ var Snapshot = class extends ElmoResource {
2148
+ /**
2149
+ * Get an aggregated snapshot of mention and citation analytics for a specific prompt over a date
2150
+ * range. Use this to identify competitive gaps, track brand visibility trends, and discover top
2151
+ * cited URLs.
2152
+ *
2153
+ * @param promptId The ID of the prompt
2154
+ */
2155
+ get(promptId, params, options) {
2156
+ return callPromise(options?.client ?? this.client, getPromptSnapshotDescriptor, mergeParams(placeParams({
2157
+ ...params,
2158
+ promptId
2159
+ }, getPromptSnapshotFields, "query"), options));
2160
+ }
2161
+ };
2162
+ //#endregion
2163
+ //#region src/resources/prompts.ts
2164
+ function revivePrompt(value) {
2165
+ if (value.createdAt != null) value.createdAt = decoded("Prompt.createdAt", value.createdAt, (raw) => new Date(raw));
2166
+ if (value.updatedAt != null) value.updatedAt = decoded("Prompt.updatedAt", value.updatedAt, (raw) => new Date(raw));
2167
+ }
2168
+ const listPromptsDescriptor = /* @__PURE__ */ callable({
2169
+ address: "/prompts",
2170
+ auth: apiKeyRequirements,
2171
+ method: "get",
2172
+ pagination: {
2173
+ items: "data",
2174
+ limitParam: "limit",
2175
+ pages: "pagination.totalPages",
2176
+ param: "page",
2177
+ size: "pagination.limit",
2178
+ style: "page",
2179
+ total: "pagination.total"
2180
+ },
2181
+ returns: "json",
2182
+ validators: { response: (data) => {
2183
+ const value = data;
2184
+ if (value == null) return value;
2185
+ if (value.data != null) value.data.forEach((item) => {
2186
+ revivePrompt(item);
2187
+ });
2188
+ if (value.prompts != null) value.prompts.forEach((item) => {
2189
+ revivePrompt(item);
2190
+ });
2191
+ return value;
2192
+ } }
2193
+ });
2194
+ const createPromptDescriptor = /* @__PURE__ */ callable({
2195
+ address: "/prompts",
2196
+ auth: apiKeyRequirements,
2197
+ mediaType: "application/json",
2198
+ method: "post",
2199
+ returns: "json",
2200
+ rules: [valueRule],
2201
+ validators: { response: /* @__PURE__ */ reviving(revivePrompt) }
2202
+ });
2203
+ const deletePromptFields = { path: ["promptId"] };
2204
+ const deletePromptDescriptor = /* @__PURE__ */ callable({
2205
+ address: "/prompts/{promptId}",
2206
+ auth: apiKeyRequirements,
2207
+ method: "delete",
2208
+ returns: "json",
2209
+ validators: { response: (data) => {
2210
+ const value = data;
2211
+ if (value == null) return value;
2212
+ if (value.createdAt != null) value.createdAt = decoded("createdAt", value.createdAt, (raw) => new Date(raw));
2213
+ if (value.updatedAt != null) value.updatedAt = decoded("updatedAt", value.updatedAt, (raw) => new Date(raw));
2214
+ return value;
2215
+ } }
2216
+ });
2217
+ const getPromptFields = { path: ["promptId"] };
2218
+ const getPromptDescriptor = /* @__PURE__ */ callable({
2219
+ address: "/prompts/{promptId}",
2220
+ auth: apiKeyRequirements,
2221
+ method: "get",
2222
+ returns: "json",
2223
+ validators: { response: /* @__PURE__ */ reviving(revivePrompt) }
2224
+ });
2225
+ const updatePromptFields = { path: ["promptId"] };
2226
+ const updatePromptDescriptor = /* @__PURE__ */ callable({
2227
+ address: "/prompts/{promptId}",
2228
+ auth: apiKeyRequirements,
2229
+ mediaType: "application/json",
2230
+ method: "patch",
2231
+ returns: "json",
2232
+ rules: [valueRule],
2233
+ validators: { response: /* @__PURE__ */ reviving(revivePrompt) }
2234
+ });
2235
+ /** Manage brand prompts */
2236
+ var Prompts = class extends ElmoResource {
2237
+ /**
2238
+ * Create a new prompt
2239
+ *
2240
+ * Create a new prompt for a brand. This will automatically schedule the prompt for execution.
2241
+ */
2242
+ create(params, options) {
2243
+ return callPromise(options?.client ?? this.client, createPromptDescriptor, mergeParams(groupParams(params, "body"), options));
2244
+ }
2245
+ /**
2246
+ * Delete a prompt
2247
+ *
2248
+ * Permanently delete a prompt and cancel all related scheduled jobs. This will also cascade
2249
+ * delete all associated prompt runs.
2250
+ *
2251
+ * Requires an instance admin key; organization keys receive `403`. The dashboard has no delete
2252
+ * either — stop tracking a prompt with `prompts.update()` and `enabled: false`, which keeps its
2253
+ * history and frees the plan slot.
2254
+ *
2255
+ * @param promptId The ID of the prompt to delete
2256
+ */
2257
+ delete(promptId, options) {
2258
+ return callPromise(options?.client ?? this.client, deletePromptDescriptor, mergeParams(placeParams({ promptId }, deletePromptFields, "query"), options));
2259
+ }
2260
+ /**
2261
+ * Get a prompt
2262
+ *
2263
+ * Retrieve a specific prompt by ID
2264
+ *
2265
+ * @param promptId The ID of the prompt
2266
+ */
2267
+ get(promptId, options) {
2268
+ return callPromise(options?.client ?? this.client, getPromptDescriptor, mergeParams(placeParams({ promptId }, getPromptFields, "query"), options));
2269
+ }
2270
+ /**
2271
+ * List all prompts
2272
+ *
2273
+ * Retrieve a paginated list of all prompts across all brands
2274
+ */
2275
+ list(params, options) {
2276
+ return pages(options?.client ?? this.client, listPromptsDescriptor, mergeParams(groupParams(params, "query"), options));
2277
+ }
2278
+ /**
2279
+ * Update a prompt
2280
+ *
2281
+ * Update a prompt's properties. Only provided fields will be updated. Toggling `enabled`
2282
+ * schedules or unschedules the recurring run job.
2283
+ *
2284
+ * @param promptId The ID of the prompt to update
2285
+ */
2286
+ update(promptId, params, options) {
2287
+ return callPromise(options?.client ?? this.client, updatePromptDescriptor, mergeParams(placeParams({
2288
+ ...params,
2289
+ promptId
2290
+ }, updatePromptFields, "body"), options));
2291
+ }
2292
+ _runs;
2293
+ /** Individual model answers behind the aggregates */
2294
+ get runs() {
2295
+ return this._runs ??= new Runs(this.client);
2296
+ }
2297
+ _snapshot;
2298
+ /** Aggregated analytics snapshots for prompts */
2299
+ get snapshot() {
2300
+ return this._snapshot ??= new Snapshot(this.client);
2301
+ }
2302
+ };
2303
+ //#endregion
2304
+ //#region src/resources/reports.ts
2305
+ function reviveReportSummary(value) {
2306
+ if (value.createdAt != null) value.createdAt = decoded("ReportSummary.createdAt", value.createdAt, (raw) => new Date(raw));
2307
+ if (value.completedAt != null) value.completedAt = decoded("ReportSummary.completedAt", value.completedAt, (raw) => new Date(raw));
2308
+ }
2309
+ const listReportsDescriptor = /* @__PURE__ */ callable({
2310
+ address: "/reports",
2311
+ auth: apiKeyRequirements,
2312
+ method: "get",
2313
+ pagination: {
2314
+ items: "data",
2315
+ limitParam: "limit",
2316
+ pages: "pagination.totalPages",
2317
+ param: "page",
2318
+ size: "pagination.limit",
2319
+ style: "page",
2320
+ total: "pagination.total"
2321
+ },
2322
+ returns: "json",
2323
+ validators: { response: (data) => {
2324
+ const value = data;
2325
+ if (value == null) return value;
2326
+ if (value.data != null) value.data.forEach((item) => {
2327
+ reviveReportSummary(item);
2328
+ });
2329
+ if (value.reports != null) value.reports.forEach((item) => {
2330
+ reviveReportSummary(item);
2331
+ });
2332
+ return value;
2333
+ } }
2334
+ });
2335
+ const createReportDescriptor = /* @__PURE__ */ callable({
2336
+ address: "/reports",
2337
+ auth: apiKeyRequirements,
2338
+ mediaType: "application/json",
2339
+ method: "post",
2340
+ returns: "json",
2341
+ rules: [
2342
+ brandNameRule,
2343
+ {
2344
+ max: 10,
2345
+ name: "brandAliases",
2346
+ of: "items"
2347
+ },
2348
+ {
2349
+ min: 1,
2350
+ name: "brandWebsite",
2351
+ of: "characters"
2352
+ }
2353
+ ],
2354
+ validators: { response: (data) => {
2355
+ const value = data;
2356
+ if (value == null) return value;
2357
+ if (value.createdAt != null) value.createdAt = decoded("createdAt", value.createdAt, (raw) => new Date(raw));
2358
+ return value;
2359
+ } }
2360
+ });
2361
+ const getReportFields = { path: ["reportId"] };
2362
+ const getReportDescriptor = /* @__PURE__ */ callable({
2363
+ address: "/reports/{reportId}",
2364
+ auth: apiKeyRequirements,
2365
+ method: "get",
2366
+ returns: "json",
2367
+ validators: { response: (data) => {
2368
+ const value = data;
2369
+ if (value == null) return value;
2370
+ if (value.createdAt != null) value.createdAt = decoded("createdAt", value.createdAt, (raw) => new Date(raw));
2371
+ if (value.completedAt != null) value.completedAt = decoded("completedAt", value.completedAt, (raw) => new Date(raw));
2372
+ return value;
2373
+ } }
2374
+ });
2375
+ /** Generate and retrieve AI Share of Voice reports */
2376
+ var Reports = class extends ElmoResource {
2377
+ /**
2378
+ * Create a report
2379
+ *
2380
+ * Create a new AI Share of Voice report and queue it for generation. The report will evaluate the
2381
+ * brand across multiple AI engines (ChatGPT, Claude, Google AI) using generated and optional
2382
+ * custom prompts.
2383
+ *
2384
+ * Requires an instance admin key; organization keys receive `403`.
2385
+ */
2386
+ create(params, options) {
2387
+ return callPromise(options?.client ?? this.client, createReportDescriptor, mergeParams(groupParams(params, "body"), options));
2388
+ }
2389
+ /**
2390
+ * Get report status and data
2391
+ *
2392
+ * Poll a report's status. When completed, returns per-prompt snapshot data with raw mention
2393
+ * counts. Consumers are responsible for computing SoV and other derived metrics from the raw
2394
+ * data.
2395
+ *
2396
+ * Requires an instance admin key; organization keys receive `403`.
2397
+ *
2398
+ * @param reportId The ID of the report
2399
+ */
2400
+ get(reportId, params, options) {
2401
+ return callPromise(options?.client ?? this.client, getReportDescriptor, mergeParams(placeParams({
2402
+ ...params,
2403
+ reportId
2404
+ }, getReportFields, "query"), options));
2405
+ }
2406
+ /**
2407
+ * Retrieve a paginated list of all reports, ordered by creation date (newest first).
2408
+ *
2409
+ * Requires an instance admin key; organization keys receive `403`.
2410
+ */
2411
+ list(params, options) {
2412
+ return pages(options?.client ?? this.client, listReportsDescriptor, mergeParams(groupParams(params, "query"), options));
2413
+ }
2414
+ };
2415
+ //#endregion
2416
+ //#region src/resources/tools.ts
2417
+ const analyzeBrandDescriptor = /* @__PURE__ */ callable({
2418
+ address: "/tools/analyze",
2419
+ auth: apiKeyRequirements,
2420
+ mediaType: "application/json",
2421
+ method: "post",
2422
+ returns: "json",
2423
+ rules: [
2424
+ {
2425
+ min: 1,
2426
+ name: "website",
2427
+ of: "characters"
2428
+ },
2429
+ {
2430
+ max: 100,
2431
+ min: 0,
2432
+ name: "maxCompetitors"
2433
+ },
2434
+ {
2435
+ max: 100,
2436
+ min: 0,
2437
+ name: "maxPrompts"
2438
+ }
2439
+ ]
2440
+ });
2441
+ /** One-shot helpers (e.g. brand analysis) that don't persist anything */
2442
+ var Tools = class extends ElmoResource {
2443
+ /**
2444
+ * Analyze a website
2445
+ *
2446
+ * Run brand analysis without persisting anything. Returns suggested additional domains, aliases,
2447
+ * competitors, and prompts.
2448
+ *
2449
+ * Requires an instance admin key; organization keys receive `403`.
2450
+ */
2451
+ analyze(params, options) {
2452
+ return callPromise(options?.client ?? this.client, analyzeBrandDescriptor, mergeParams(groupParams(params, "body"), options));
2453
+ }
2454
+ };
2455
+ //#endregion
2456
+ export { getBrandOpportunitiesFields as $, listModelsDescriptor as A, selectCodec as At, updateCompetitorDescriptor as B, emptyPathParameter as Bt, Organizations as C, isFieldValue as Ct, getOrganizationFields as D, toText as Dt, getOrganizationDescriptor as E, scalarText as Et, deleteCompetitorDescriptor as F, MissingCredentialError as Ft, getBrandFields as G, unansweredError as Gt, Brands as H, isStructured as Ht, deleteCompetitorFields as I, TimeoutError as It, updateBrandFields as J, TIMER_LIMIT as Jt, listBrandsDescriptor as K, unsendable as Kt, getCompetitorDescriptor as L, TransportError as Lt, getMeDescriptor as M, AbortError as Mt, Competitors as N, DecodeError as Nt, listOrganizationsDescriptor as O, essenceOf as Ot, createCompetitorDescriptor as P, ElmoError as Pt, getBrandOpportunitiesDescriptor as Q, sleep as Qt, getCompetitorFields as R, calledOffWith as Rt, listPromptRunsFields as S, createConfig as St, getOrganizationBillingFields as T, metadataValue as Tt, createBrandDescriptor as U, refusedInput as Ut, updateCompetitorFields as V, failureOf as Vt, getBrandDescriptor as W, safeAddress as Wt, listBrandTagsDescriptor as X, exceedsMaxRetryAfter as Xt, pages as Y, backoffDelay as Yt, listBrandTagsFields as Z, retryAfterDelay as Zt, getPromptSnapshotDescriptor as _, createClient as _t, getReportDescriptor as a, listBrandCitationDomainsFields as at, getRunFields as b, replyWith as bt, Prompts as c, listBrandPromptPerformanceDescriptor as ct, deletePromptFields as d, mergeParams as dt, getBrandAnalyticsDescriptor as et, getPromptDescriptor as f, placeParams as ft, updatePromptFields as g, clientFor as gt, updatePromptDescriptor as h, validateFeature as ht, createReportDescriptor as i, listBrandCitationDomainsDescriptor as it, Me as j, APIError as jt, Models as k, readText as kt, createPromptDescriptor as l, listBrandPromptPerformanceFields as lt, listPromptsDescriptor as m, ElmoResource as mt, analyzeBrandDescriptor as n, getBrandQueryFanoutDescriptor as nt, getReportFields as o, listBrandCitationURLsDescriptor as ot, getPromptFields as p, callPromise as pt, updateBrandDescriptor as q, unsendableAddress as qt, Reports as r, getBrandQueryFanoutFields as rt, listReportsDescriptor as s, listBrandCitationUrlsFields as st, Tools as t, getBrandAnalyticsFields as tt, deletePromptDescriptor as u, groupParams as ut, getPromptSnapshotFields as v, discardBody as vt, getOrganizationBillingDescriptor as w, metadataHeaders as wt, listPromptRunsDescriptor as x, baseURLOf as xt, getRunDescriptor as y, isStreamed as yt, listCompetitorsDescriptor as z, classifyError as zt };
2457
+
2458
+ //# sourceMappingURL=tools-SwP0sK8H.mjs.map