mbase-sdk 0.0.6 → 0.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +113 -1
- package/dist/index.cjs +101 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +63 -1
- package/dist/index.d.ts +63 -1
- package/dist/index.js +100 -4
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -95,6 +95,8 @@ function serverTime(body) {
|
|
|
95
95
|
const parsed = new Date(at);
|
|
96
96
|
return Number.isNaN(parsed.getTime()) ? void 0 : parsed;
|
|
97
97
|
}
|
|
98
|
+
var WebhookVerificationError = class extends MeterbaseError {
|
|
99
|
+
};
|
|
98
100
|
|
|
99
101
|
// src/client.ts
|
|
100
102
|
var DEFAULT_BASE_URL = "https://api.meterbase.tech";
|
|
@@ -144,7 +146,7 @@ var Client = class {
|
|
|
144
146
|
const retryable = req.method === "GET" || req.method === "DELETE" || req.idempotent === true;
|
|
145
147
|
let lastError;
|
|
146
148
|
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
147
|
-
if (attempt > 0) await sleep(backoff(attempt, lastError));
|
|
149
|
+
if (attempt > 0) await sleep(backoff(attempt, lastError), req.signal);
|
|
148
150
|
try {
|
|
149
151
|
const response = await this.#send(req);
|
|
150
152
|
if (response.ok) return await parseBody(response);
|
|
@@ -158,6 +160,7 @@ var Client = class {
|
|
|
158
160
|
if (cause instanceof MeterbaseError && !(cause instanceof ConnectionError)) {
|
|
159
161
|
throw cause;
|
|
160
162
|
}
|
|
163
|
+
if (req.signal?.aborted) throw cause;
|
|
161
164
|
if (!retryable || attempt >= maxRetries) throw cause;
|
|
162
165
|
lastError = cause;
|
|
163
166
|
}
|
|
@@ -165,6 +168,7 @@ var Client = class {
|
|
|
165
168
|
throw lastError;
|
|
166
169
|
}
|
|
167
170
|
async #send(req) {
|
|
171
|
+
if (req.signal?.aborted) throw req.signal.reason;
|
|
168
172
|
const url = new URL(this.#baseUrl + req.path);
|
|
169
173
|
for (const [key, value] of Object.entries(req.query ?? {})) {
|
|
170
174
|
if (value !== void 0) url.searchParams.set(key, String(value));
|
|
@@ -213,8 +217,22 @@ function backoff(attempt, lastError) {
|
|
|
213
217
|
const ceiling = Math.min(500 * 2 ** (attempt - 1), MAX_BACKOFF);
|
|
214
218
|
return Math.random() * ceiling;
|
|
215
219
|
}
|
|
216
|
-
function sleep(ms) {
|
|
217
|
-
return new Promise((resolve) =>
|
|
220
|
+
function sleep(ms, signal) {
|
|
221
|
+
return new Promise((resolve, reject) => {
|
|
222
|
+
if (signal?.aborted) {
|
|
223
|
+
reject(signal.reason);
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
const onAbort = () => {
|
|
227
|
+
clearTimeout(timer);
|
|
228
|
+
reject(signal?.reason);
|
|
229
|
+
};
|
|
230
|
+
const timer = setTimeout(() => {
|
|
231
|
+
signal?.removeEventListener("abort", onAbort);
|
|
232
|
+
resolve();
|
|
233
|
+
}, ms);
|
|
234
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
235
|
+
});
|
|
218
236
|
}
|
|
219
237
|
async function parseBody(response) {
|
|
220
238
|
if (response.status === 204) return void 0;
|
|
@@ -686,6 +704,84 @@ var Plans = class {
|
|
|
686
704
|
}
|
|
687
705
|
};
|
|
688
706
|
|
|
707
|
+
// src/webhooks.ts
|
|
708
|
+
var SECRET_PREFIX = "whsec_";
|
|
709
|
+
var DEFAULT_TOLERANCE_SECONDS = 5 * 60;
|
|
710
|
+
async function verifyWebhook(params) {
|
|
711
|
+
const id = header(params.headers, "webhook-id");
|
|
712
|
+
const timestamp = header(params.headers, "webhook-timestamp");
|
|
713
|
+
const signatures = header(params.headers, "webhook-signature");
|
|
714
|
+
if (!id || !timestamp || !signatures) {
|
|
715
|
+
throw new WebhookVerificationError(
|
|
716
|
+
"Missing a webhook-id, webhook-timestamp or webhook-signature header."
|
|
717
|
+
);
|
|
718
|
+
}
|
|
719
|
+
const sentAt = Number(timestamp);
|
|
720
|
+
const tolerance = params.toleranceSeconds ?? DEFAULT_TOLERANCE_SECONDS;
|
|
721
|
+
if (!Number.isInteger(sentAt) || Math.abs(Date.now() / 1e3 - sentAt) > tolerance) {
|
|
722
|
+
throw new WebhookVerificationError(
|
|
723
|
+
"The webhook-timestamp is too far from now; this may be a replay."
|
|
724
|
+
);
|
|
725
|
+
}
|
|
726
|
+
const body = typeof params.payload === "string" ? new TextEncoder().encode(params.payload) : params.payload;
|
|
727
|
+
const signed = concat(new TextEncoder().encode(`${id}.${timestamp}.`), body);
|
|
728
|
+
const candidates = signatures.split(" ").filter((entry) => entry.startsWith("v1,")).map((entry) => fromBase64(entry.slice(3)));
|
|
729
|
+
const subtle = webCrypto();
|
|
730
|
+
const secrets = typeof params.secret === "string" ? [params.secret] : params.secret;
|
|
731
|
+
for (const secret of secrets) {
|
|
732
|
+
const raw = secret.startsWith(SECRET_PREFIX) ? fromBase64(secret.slice(SECRET_PREFIX.length)) : void 0;
|
|
733
|
+
if (!raw) {
|
|
734
|
+
throw new WebhookVerificationError(
|
|
735
|
+
"The secret should be whsec_ and base64: copy it from the endpoint's settings."
|
|
736
|
+
);
|
|
737
|
+
}
|
|
738
|
+
const key = await subtle.importKey(
|
|
739
|
+
"raw",
|
|
740
|
+
raw,
|
|
741
|
+
{ name: "HMAC", hash: "SHA-256" },
|
|
742
|
+
false,
|
|
743
|
+
["verify"]
|
|
744
|
+
);
|
|
745
|
+
for (const candidate of candidates) {
|
|
746
|
+
if (candidate && await subtle.verify("HMAC", key, candidate, signed)) {
|
|
747
|
+
return JSON.parse(new TextDecoder().decode(body));
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
throw new WebhookVerificationError(
|
|
752
|
+
"No signature matches: the body changed, or this is the wrong secret."
|
|
753
|
+
);
|
|
754
|
+
}
|
|
755
|
+
function header(headers, name) {
|
|
756
|
+
if (typeof headers.get === "function") {
|
|
757
|
+
return headers.get(name) ?? void 0;
|
|
758
|
+
}
|
|
759
|
+
const value = headers[name];
|
|
760
|
+
return Array.isArray(value) ? value[0] : value;
|
|
761
|
+
}
|
|
762
|
+
function webCrypto() {
|
|
763
|
+
const subtle = globalThis.crypto?.subtle;
|
|
764
|
+
if (!subtle) {
|
|
765
|
+
throw new MeterbaseError(
|
|
766
|
+
"No Web Crypto to verify a webhook with: run on Node 20+, Deno, Bun or a Worker."
|
|
767
|
+
);
|
|
768
|
+
}
|
|
769
|
+
return subtle;
|
|
770
|
+
}
|
|
771
|
+
function fromBase64(text) {
|
|
772
|
+
try {
|
|
773
|
+
return Uint8Array.from(atob(text), (char) => char.charCodeAt(0));
|
|
774
|
+
} catch {
|
|
775
|
+
return void 0;
|
|
776
|
+
}
|
|
777
|
+
}
|
|
778
|
+
function concat(head, tail) {
|
|
779
|
+
const out = new Uint8Array(head.length + tail.length);
|
|
780
|
+
out.set(head);
|
|
781
|
+
out.set(tail, head.length);
|
|
782
|
+
return out;
|
|
783
|
+
}
|
|
784
|
+
|
|
689
785
|
// src/index.ts
|
|
690
786
|
var Meterbase = class {
|
|
691
787
|
customers;
|
|
@@ -906,6 +1002,6 @@ function idempotencyKey(atMs) {
|
|
|
906
1002
|
].join("-");
|
|
907
1003
|
}
|
|
908
1004
|
|
|
909
|
-
export { APIError, AuthenticationError, ConflictError, ConnectionError, CycleChangeRequiresResetError, InvalidIdempotencyKeyError, InvalidRequestError, Meterbase, MeterbaseError, NotFoundError, PermissionDeniedError, RateLimitError, ReservationMismatchError, ServerError, TimeoutError, TooLateError, errorFromResponse };
|
|
1005
|
+
export { APIError, AuthenticationError, ConflictError, ConnectionError, CycleChangeRequiresResetError, InvalidIdempotencyKeyError, InvalidRequestError, Meterbase, MeterbaseError, NotFoundError, PermissionDeniedError, RateLimitError, ReservationMismatchError, ServerError, TimeoutError, TooLateError, WebhookVerificationError, errorFromResponse, verifyWebhook };
|
|
910
1006
|
//# sourceMappingURL=index.js.map
|
|
911
1007
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/errors.ts","../src/client.ts","../src/resources/customer-allowances.ts","../src/resources/customer-plan.ts","../src/resources/customers.ts","../src/resources/meters.ts","../src/resources/plans.ts","../src/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["// Every failure is a MeterbaseError, so a caller can catch one type and still\n// switch on the specific one. `code` is stable; `message` may change.\n\nexport class MeterbaseError extends Error {\n constructor(message: string, options?: { cause?: unknown }) {\n super(message, options)\n this.name = new.target.name\n }\n}\n\nexport class APIError extends MeterbaseError {\n readonly status: number\n readonly code: string\n /** From `X-Request-Id`, when the engine sends one. */\n readonly requestId: string | undefined\n readonly body: unknown\n\n constructor(args: {\n status: number\n code: string\n message: string\n requestId?: string | undefined\n body?: unknown\n }) {\n super(args.message)\n this.status = args.status\n this.code = args.code\n this.requestId = args.requestId\n this.body = args.body\n }\n}\n\nexport class AuthenticationError extends APIError {}\nexport class PermissionDeniedError extends APIError {}\nexport class NotFoundError extends APIError {}\nexport class ConflictError extends APIError {}\n\nexport class InvalidRequestError extends APIError {}\n\n/**\n * `422 invalid_idempotency_key`: the key was not a UUID version 7.\n * `crypto.randomUUID()` mints a v4, so omit `idempotency_key` and let this\n * SDK mint the right thing.\n */\nexport class InvalidIdempotencyKeyError extends InvalidRequestError {}\n\n/**\n * `422 too_late`: the key's timestamp is more than an hour from the engine's\n * clock, so a retry can no longer be told from a new event. **Nothing was\n * recorded** — the check runs before any write.\n *\n * The usual cause is this machine's clock. When this SDK minted the key it\n * corrects the offset from `serverTime` and retries once, so you only see\n * this for a key you supplied. If that key is a retry of a call made over an\n * hour ago, do not resend it under a new one: it may already be recorded.\n */\nexport class TooLateError extends InvalidRequestError {\n /** The engine's clock when it refused. */\n readonly serverTime: Date | undefined\n\n constructor(args: ConstructorParameters<typeof APIError>[0]) {\n super(args)\n this.serverTime = serverTime(args.body)\n }\n}\n\n/**\n * `422 reservation_mismatch`: the reservation id names a hold made for a\n * different customer or meter than the call sends. A caller bug, refused\n * before anything is written — nothing was recorded and the hold still\n * stands.\n */\nexport class ReservationMismatchError extends InvalidRequestError {}\n\n/**\n * `422 cycle_change_requires_reset`: the two plans measure different cycles,\n * so a `next_cycle` change has no shared boundary to wait for and a `prorate`\n * no shared period to weight. The move is `customers.plan.restart`, which\n * closes the current period and opens a fresh one on the new cycle — or\n * `changeNow` with the default `reconciliation: \"none\"` to keep the period\n * that is running. The engine's `message` says as much.\n *\n * An `InvalidRequestError` still, so an existing `catch` keeps working.\n */\nexport class CycleChangeRequiresResetError extends InvalidRequestError {}\nexport class RateLimitError extends APIError {\n /** Seconds to wait, from `Retry-After`, when the engine sends one. */\n readonly retryAfter: number | undefined\n\n constructor(\n args: ConstructorParameters<typeof APIError>[0] & {\n retryAfter?: number | undefined\n },\n ) {\n super(args)\n this.retryAfter = args.retryAfter\n }\n}\nexport class ServerError extends APIError {}\n\n// The request never produced an answer: DNS, TLS, a reset, an abort.\nexport class ConnectionError extends MeterbaseError {}\nexport class TimeoutError extends ConnectionError {}\n\nexport function errorFromResponse(args: {\n status: number\n code: string\n message: string\n requestId?: string | undefined\n retryAfter?: number | undefined\n body?: unknown\n}): APIError {\n switch (args.status) {\n case 401:\n return new AuthenticationError(args)\n case 403:\n return new PermissionDeniedError(args)\n case 404:\n return new NotFoundError(args)\n case 409:\n return new ConflictError(args)\n case 422:\n switch (args.code) {\n case \"cycle_change_requires_reset\":\n return new CycleChangeRequiresResetError(args)\n case \"invalid_idempotency_key\":\n return new InvalidIdempotencyKeyError(args)\n case \"reservation_mismatch\":\n return new ReservationMismatchError(args)\n case \"too_late\":\n return new TooLateError(args)\n default:\n return new InvalidRequestError(args)\n }\n case 429:\n return new RateLimitError(args)\n default:\n return args.status >= 500 ? new ServerError(args) : new APIError(args)\n }\n}\n\n/** The engine carries it beside `code` and `message`, inside `error`. */\nfunction serverTime(body: unknown): Date | undefined {\n if (typeof body !== \"object\" || body === null) return undefined\n\n const error = (body as { error?: unknown }).error\n if (typeof error !== \"object\" || error === null) return undefined\n\n const at = (error as { server_time?: unknown }).server_time\n if (typeof at !== \"string\") return undefined\n\n const parsed = new Date(at)\n return Number.isNaN(parsed.getTime()) ? undefined : parsed\n}\n","// Everything goes through `request`, so authentication, timeouts, retries and\n// error mapping are defined once.\n\nimport {\n ConnectionError,\n errorFromResponse,\n MeterbaseError,\n TimeoutError,\n} from \"./errors.js\"\n\nexport type MeterbaseOptions = {\n /** A secret key. It names its own workspace. */\n apiKey: string\n /** Defaults to the hosted engine. */\n baseUrl?: string\n /** Per attempt, not per call. */\n timeout?: number\n maxRetries?: number\n fetch?: typeof globalThis.fetch\n}\n\nexport type RequestOptions = {\n signal?: AbortSignal\n timeout?: number\n maxRetries?: number\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PATCH\" | \"DELETE\"\n\ntype Request = RequestOptions & {\n method: HttpMethod\n path: string\n query?: Record<string, string | number | boolean | undefined>\n body?: unknown\n /**\n * Replay this call even though its method is not safe. Only a route that\n * carries an idempotency key may set it, and the key has to be fixed before\n * `request` is called — the loop re-sends one body, so a key generated\n * per attempt would count the same usage twice.\n */\n idempotent?: boolean\n}\n\nconst DEFAULT_BASE_URL = \"https://api.meterbase.tech\"\nconst DEFAULT_TIMEOUT = 10_000\nconst DEFAULT_MAX_RETRIES = 2\nconst MAX_BACKOFF = 8_000\n\nexport class Client {\n readonly #apiKey: string\n readonly #baseUrl: string\n readonly #timeout: number\n readonly #maxRetries: number\n readonly #fetch: typeof globalThis.fetch\n\n /**\n * How far the engine's clock is ahead of this machine's, in milliseconds.\n * Idempotency keys are minted here and the engine refuses one dated more\n * than an hour from its own clock, so without this a device with a wrong\n * clock would fail every call forever.\n */\n #clockOffset = 0\n\n /** The engine's clock, as well as this client knows it. */\n now(): number {\n return Date.now() + this.#clockOffset\n }\n\n /** Off by up to one round trip, which a window in hours does not notice. */\n observeServerTime(at: Date): void {\n this.#clockOffset = at.getTime() - Date.now()\n }\n\n constructor(options: MeterbaseOptions) {\n if (!options.apiKey) {\n throw new MeterbaseError(\n \"An API key is required: new Meterbase({ apiKey: 'mb_sk_live_…' }).\",\n )\n }\n\n this.#apiKey = options.apiKey\n this.#baseUrl = (options.baseUrl ?? DEFAULT_BASE_URL).replace(/\\/+$/, \"\")\n this.#timeout = options.timeout ?? DEFAULT_TIMEOUT\n this.#maxRetries = options.maxRetries ?? DEFAULT_MAX_RETRIES\n this.#fetch = options.fetch ?? globalThis.fetch\n\n if (typeof this.#fetch !== \"function\") {\n throw new MeterbaseError(\n \"No fetch implementation: pass one as `fetch`, or run on Node 20+.\",\n )\n }\n }\n\n async request<T>(req: Request): Promise<T> {\n const maxRetries = req.maxRetries ?? this.#maxRetries\n // Safe methods, plus the routes that carry an idempotency key and say so.\n // Any other POST or PATCH could create a second row on a replay.\n const retryable =\n req.method === \"GET\" || req.method === \"DELETE\" || req.idempotent === true\n\n let lastError: unknown\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n if (attempt > 0) await sleep(backoff(attempt, lastError))\n\n try {\n const response = await this.#send(req)\n\n if (response.ok) return (await parseBody(response)) as T\n\n const error = await errorFrom(response)\n if (retryable && attempt < maxRetries && shouldRetry(response.status)) {\n lastError = error\n continue\n }\n throw error\n } catch (cause) {\n if (\n cause instanceof MeterbaseError &&\n !(cause instanceof ConnectionError)\n ) {\n throw cause\n }\n // A connection failure proves nothing about whether the server acted,\n // so it is replayed under the same idempotency rule.\n if (!retryable || attempt >= maxRetries) throw cause\n lastError = cause\n }\n }\n\n /* c8 ignore next 2 -- the loop always returns or throws */\n throw lastError\n }\n\n async #send(req: Request): Promise<Response> {\n const url = new URL(this.#baseUrl + req.path)\n for (const [key, value] of Object.entries(req.query ?? {})) {\n if (value !== undefined) url.searchParams.set(key, String(value))\n }\n\n const headers: Record<string, string> = {\n authorization: `Bearer ${this.#apiKey}`,\n accept: \"application/json\",\n }\n if (req.body !== undefined) headers[\"content-type\"] = \"application/json\"\n\n const timeout = req.timeout ?? this.#timeout\n const controller = new AbortController()\n const onAbort = () => controller.abort(req.signal?.reason)\n req.signal?.addEventListener(\"abort\", onAbort, { once: true })\n\n let timedOut = false\n const timer = setTimeout(() => {\n timedOut = true\n controller.abort()\n }, timeout)\n\n try {\n return await this.#fetch(url, {\n method: req.method,\n headers,\n body: req.body === undefined ? undefined : JSON.stringify(req.body),\n signal: controller.signal,\n })\n } catch (cause) {\n if (timedOut) {\n throw new TimeoutError(`Request timed out after ${timeout}ms.`, {\n cause,\n })\n }\n // A caller's own abort is theirs to handle, not ours to reclassify.\n if (req.signal?.aborted) throw cause\n throw new ConnectionError(`Could not reach ${url.origin}.`, { cause })\n } finally {\n clearTimeout(timer)\n req.signal?.removeEventListener(\"abort\", onAbort)\n }\n }\n}\n\nfunction shouldRetry(status: number): boolean {\n return status === 408 || status === 429 || status >= 500\n}\n\n/** Exponential backoff with full jitter, unless the engine named a delay. */\nfunction backoff(attempt: number, lastError: unknown): number {\n const retryAfter =\n lastError && typeof lastError === \"object\" && \"retryAfter\" in lastError\n ? (lastError as { retryAfter?: number }).retryAfter\n : undefined\n if (retryAfter !== undefined) return Math.min(retryAfter * 1000, MAX_BACKOFF)\n\n const ceiling = Math.min(500 * 2 ** (attempt - 1), MAX_BACKOFF)\n return Math.random() * ceiling\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms))\n}\n\nasync function parseBody(response: Response): Promise<unknown> {\n if (response.status === 204) return undefined\n\n const text = await response.text()\n if (text === \"\") return undefined\n\n try {\n return JSON.parse(text)\n } catch (cause) {\n throw new MeterbaseError(\"The engine returned a body that is not JSON.\", {\n cause,\n })\n }\n}\n\nasync function errorFrom(response: Response) {\n const body = await response.text()\n const parsed = parseErrorBody(body)\n const retryAfterHeader = response.headers.get(\"retry-after\")\n const retryAfter = retryAfterHeader ? Number(retryAfterHeader) : undefined\n\n return errorFromResponse({\n status: response.status,\n code: parsed?.code ?? `http_${response.status}`,\n message: parsed?.message ?? `The engine responded ${response.status}.`,\n requestId: response.headers.get(\"x-request-id\") ?? undefined,\n retryAfter:\n retryAfter !== undefined && Number.isFinite(retryAfter)\n ? retryAfter\n : undefined,\n body: body === \"\" ? undefined : (safeParse(body) ?? body),\n })\n}\n\nfunction parseErrorBody(body: string) {\n const parsed = safeParse(body) as\n { error?: { code?: string; message?: string } } | undefined\n const error = parsed?.error\n if (!error?.code || !error.message) return undefined\n\n return { code: error.code, message: error.message }\n}\n\nfunction safeParse(body: string): unknown {\n try {\n return JSON.parse(body)\n } catch {\n return undefined\n }\n}\n","import type { Client, RequestOptions } from \"../client.js\"\nimport type {\n Allowance,\n AllowanceGrantParams,\n AllowanceListParams,\n List,\n} from \"../types.js\"\n\n/**\n * Capacity handed to one customer on top of their plan. A grant with\n * `source: \"plan\"` is the engine's own, minted when a plan is assigned, and\n * cannot be created here.\n */\nexport class CustomerAllowances {\n readonly #client: Client\n\n constructor(client: Client) {\n this.#client = client\n }\n\n grant(\n customerId: string,\n params: AllowanceGrantParams,\n options?: RequestOptions,\n ): Promise<Allowance> {\n return this.#client.request({\n ...options,\n method: \"POST\",\n path: `/v1/customers/${encodeURIComponent(customerId)}/allowances`,\n body: params,\n })\n }\n\n /** Open grants only, unless `include_closed`. */\n list(\n customerId: string,\n params: AllowanceListParams = {},\n options?: RequestOptions,\n ): Promise<List<Allowance>> {\n return this.#client.request({\n ...options,\n method: \"GET\",\n path: `/v1/customers/${encodeURIComponent(customerId)}/allowances`,\n query: {\n meter_id: params.meter_id,\n include_closed: params.include_closed,\n },\n })\n }\n\n retrieve(\n customerId: string,\n allowanceId: string,\n options?: RequestOptions,\n ): Promise<Allowance> {\n return this.#client.request({\n ...options,\n method: \"GET\",\n path: `/v1/customers/${encodeURIComponent(customerId)}/allowances/${encodeURIComponent(allowanceId)}`,\n })\n }\n\n /** Withdraws what is left without erasing what was consumed. Idempotent. */\n revoke(\n customerId: string,\n allowanceId: string,\n options?: RequestOptions,\n ): Promise<Allowance> {\n return this.#client.request({\n ...options,\n method: \"DELETE\",\n path: `/v1/customers/${encodeURIComponent(customerId)}/allowances/${encodeURIComponent(allowanceId)}`,\n })\n }\n}\n","import type { Client, RequestOptions } from \"../client.js\"\nimport type {\n AssignPlanParams,\n Assignment,\n List,\n PlanChangeNowParams,\n PlanChangeParams,\n PlanMoveParams,\n} from \"../types.js\"\nimport { NotFoundError } from \"../errors.js\"\n\n/**\n * Which plan a customer holds. The history is append-only: there is no patch\n * and no delete, and moving a customer to a different plan is the same call as\n * their first.\n *\n * `assign` is that call, mirroring the wire. The rest name the four moves a\n * caller actually makes — later, now, now-and-start-over, and never mind — so\n * that picking one does not mean knowing what `effective` and `reconciliation`\n * do to a half-used period.\n */\nexport class CustomerPlan {\n readonly #client: Client\n\n constructor(client: Client) {\n this.#client = client\n }\n\n /**\n * Put a customer on a plan. This is the wire call, and the only one that\n * takes `cycle_anchor` — a first assignment's one chance to put their\n * periods on a date they already have.\n *\n * Returns the instruction as recorded, which is not always as asked: a first\n * plan is recorded `immediate` whatever `effective` said.\n */\n assign(\n customerId: string,\n params: AssignPlanParams,\n options?: RequestOptions,\n ): Promise<Assignment> {\n return this.#client.request({\n ...options,\n method: \"POST\",\n path: `/v1/customers/${encodeURIComponent(customerId)}/plan`,\n body: params,\n })\n }\n\n /**\n * Move a customer to a different plan, with both knobs in the open.\n * `effective` defaults to `next_cycle`; `reconciliation` applies only to an\n * `immediate` change and defaults to `none`.\n *\n * Reach for `changeAtNextCycle`, `changeNow` or `restart` when one of them\n * says what you mean — this is the form to fall back to when the two are\n * chosen at runtime.\n */\n change(\n customerId: string,\n params: PlanChangeParams,\n options?: RequestOptions,\n ): Promise<Assignment> {\n const { plan, ...rest } = params\n\n return this.assign(customerId, { plan_id: plan, ...rest }, options)\n }\n\n /**\n * Schedule the move for the end of the period they are in: they keep the\n * plan they are paying for until it runs out, and the new one starts at\n * their next boundary. Nothing is pro-rated, because nothing is split.\n *\n * Two plans on different cycles share no boundary, and this answers\n * `CycleChangeRequiresResetError` — use `restart` for that move.\n */\n changeAtNextCycle(\n customerId: string,\n params: PlanMoveParams,\n options?: RequestOptions,\n ): Promise<Assignment> {\n return this.change(\n customerId,\n { plan: params.plan, effective: \"next_cycle\" },\n options,\n )\n }\n\n /**\n * Move them now, inside the period already running. Their renewal day does\n * not move; what changes is this period's cap, and `reconciliation` says\n * how:\n *\n * - `none` (the default) — the new plan's amount governs the whole period.\n * Usage already spent still counts, so a downgrade can deny until the\n * period ends.\n * - `prorate` — each plan's amount weighted by the fraction of the period it\n * was held for. Refused between plans on different cycles, which share no\n * period to weight.\n *\n * To have the period itself start over instead, use `restart`.\n */\n changeNow(\n customerId: string,\n params: PlanChangeNowParams,\n options?: RequestOptions,\n ): Promise<Assignment> {\n return this.change(\n customerId,\n { ...params, effective: \"immediate\" },\n options,\n )\n }\n\n /**\n * Move them now and start a fresh period today: the period they were in\n * closes where the change lands, keeping the usage it had, and the new\n * plan's full amount opens immediately.\n *\n * This moves the customer's anchor, so their renewal day becomes today. It\n * is the move for a customer starting over — a new contract, a re-signup —\n * and the only one that can take a customer between plans whose cycles\n * differ.\n */\n restart(\n customerId: string,\n params: PlanMoveParams,\n options?: RequestOptions,\n ): Promise<Assignment> {\n return this.change(\n customerId,\n { plan: params.plan, effective: \"immediate\", reconciliation: \"reset\" },\n options,\n )\n }\n\n /**\n * Call off a change that has not landed yet, leaving the customer on the\n * plan they hold. Naming the plan already held is what supersedes a pending\n * instruction, so this reads the plan in force and names it back.\n *\n * Returns the assignment still in force, or `null` for a customer holding no\n * plan — who can have nothing pending, since a first assignment always lands\n * at once.\n */\n async cancelScheduledChange(\n customerId: string,\n options?: RequestOptions,\n ): Promise<Assignment | null> {\n const current = await this.retrieve(customerId, options)\n if (current === null) return null\n\n return this.assign(customerId, { plan_id: current.plan_id }, options)\n }\n\n /**\n * The plan in force now, which is not always the newest instruction: a\n * change dated ahead does not govern yet.\n *\n * `null` when the customer holds no plan. That is a default deny rather than\n * a failure — they are entitled to nothing — so it is an answer here and not\n * a thrown `NotFoundError`. A customer who does not exist at all still\n * throws one.\n */\n async retrieve(\n customerId: string,\n options?: RequestOptions,\n ): Promise<Assignment | null> {\n try {\n return await this.#client.request<Assignment>({\n ...options,\n method: \"GET\",\n path: `/v1/customers/${encodeURIComponent(customerId)}/plan`,\n })\n } catch (error) {\n if (error instanceof NotFoundError && error.code === \"no_plan_assigned\") {\n return null\n }\n throw error\n }\n }\n\n /**\n * The change waiting to land, or `null` when none is. At most one is ever\n * live: a newer instruction supersedes the one before it.\n *\n * Read against the assignment in force rather than against the local clock,\n * so a change landing seconds from now is not reported as already governing.\n */\n async pending(\n customerId: string,\n options?: RequestOptions,\n ): Promise<Assignment | null> {\n const [current, { data }] = await Promise.all([\n this.retrieve(customerId, options),\n this.history(customerId, options),\n ])\n\n const inForce =\n current === null ? -Infinity : Date.parse(current.effective_at)\n\n return (\n data.find(\n (a) => a.superseded_at === null && Date.parse(a.effective_at) > inForce,\n ) ?? null\n )\n }\n\n /** Every instruction, superseded ones included: it is the whole trail. */\n history(\n customerId: string,\n options?: RequestOptions,\n ): Promise<List<Assignment>> {\n return this.#client.request({\n ...options,\n method: \"GET\",\n path: `/v1/customers/${encodeURIComponent(customerId)}/plan/history`,\n })\n }\n}\n","import type { Client, RequestOptions } from \"../client.js\"\nimport { NotFoundError } from \"../errors.js\"\nimport type {\n Customer,\n CustomerCreateParams,\n CustomerEntitlement,\n CustomerListParams,\n CustomerUpdateParams,\n CustomerUsage,\n CustomerUsageParams,\n CustomerWithPlan,\n List,\n UsageDaysParams,\n UsagePeriodParams,\n} from \"../types.js\"\nimport { CustomerAllowances } from \"./customer-allowances.js\"\nimport { CustomerPlan } from \"./customer-plan.js\"\n\nexport class Customers {\n /** The plan they hold, and the trail of instructions that got them there. */\n readonly plan: CustomerPlan\n /** Grants, which sit on top of whatever the plan gives. */\n readonly allowances: CustomerAllowances\n\n readonly #client: Client\n\n constructor(client: Client) {\n this.#client = client\n this.plan = new CustomerPlan(client)\n this.allowances = new CustomerAllowances(client)\n }\n\n create(\n params: CustomerCreateParams,\n options?: RequestOptions,\n ): Promise<Customer> {\n return this.#client.request({\n ...options,\n method: \"POST\",\n path: \"/v1/customers\",\n body: params,\n })\n }\n\n /** Lean: a listing does not embed the plan. Read one customer for that. */\n list(\n params: CustomerListParams = {},\n options?: RequestOptions,\n ): Promise<List<Customer>> {\n return this.#client.request({\n ...options,\n method: \"GET\",\n path: \"/v1/customers\",\n query: { include_deleted: params.include_deleted },\n })\n }\n\n /**\n * One customer, with the plan they hold. `plan` is the one in force now and\n * `pending_plan` the change waiting to land, each `null` when there is\n * none — so knowing what a customer is on costs no second request.\n */\n retrieve(id: string, options?: RequestOptions): Promise<CustomerWithPlan> {\n return this.#client.request({\n ...options,\n method: \"GET\",\n path: `/v1/customers/${encodeURIComponent(id)}`,\n })\n }\n\n /**\n * Resolves the tenant's own identifier, or null, embedding the plan the way\n * `retrieve` does. The engine answers this as a filtered list, so a miss is\n * an empty collection rather than a 404.\n */\n async retrieveByExternalId(\n externalId: string,\n options?: RequestOptions,\n ): Promise<CustomerWithPlan | null> {\n const { data } = await this.#client.request<List<CustomerWithPlan>>({\n ...options,\n method: \"GET\",\n path: \"/v1/customers\",\n query: { external_id: externalId },\n })\n\n return data[0] ?? null\n }\n\n /** `null` for a customer holding no plan, as `plan.retrieve` answers. */\n async entitlement(\n id: string,\n options?: RequestOptions,\n ): Promise<CustomerEntitlement | null> {\n try {\n return await this.#client.request<CustomerEntitlement>({\n ...options,\n method: \"GET\",\n path: `/v1/customers/${encodeURIComponent(id)}/entitlement`,\n })\n } catch (error) {\n if (error instanceof NotFoundError && error.code === \"no_plan_assigned\") {\n return null\n }\n throw error\n }\n }\n\n /**\n * Usage per UTC day. A period the customer never had, holding no plan now\n * or none before this period, is `null`.\n */\n usage(\n id: string,\n params: UsageDaysParams,\n options?: RequestOptions,\n ): Promise<CustomerUsage>\n usage(\n id: string,\n params: UsagePeriodParams,\n options?: RequestOptions,\n ): Promise<CustomerUsage | null>\n async usage(\n id: string,\n params: CustomerUsageParams,\n options?: RequestOptions,\n ): Promise<CustomerUsage | null> {\n try {\n return await this.#client.request<CustomerUsage>({\n ...options,\n method: \"GET\",\n path: `/v1/customers/${encodeURIComponent(id)}/usage`,\n query: { days: params.days, period: params.period },\n })\n } catch (error) {\n if (\n error instanceof NotFoundError &&\n (error.code === \"no_plan_assigned\" ||\n error.code === \"no_previous_period\")\n ) {\n return null\n }\n throw error\n }\n }\n\n update(\n id: string,\n params: CustomerUpdateParams,\n options?: RequestOptions,\n ): Promise<Customer> {\n return this.#client.request({\n ...options,\n method: \"PATCH\",\n path: `/v1/customers/${encodeURIComponent(id)}`,\n body: params,\n })\n }\n\n /** Soft delete: usage and assignments keep referencing the customer. */\n delete(id: string, options?: RequestOptions): Promise<Customer> {\n return this.#client.request({\n ...options,\n method: \"DELETE\",\n path: `/v1/customers/${encodeURIComponent(id)}`,\n })\n }\n}\n","import type { Client, RequestOptions } from \"../client.js\"\nimport type {\n List,\n Meter,\n MeterCreateParams,\n MeterListParams,\n MeterUpdateParams,\n MeterUsageHistory,\n UsageDaysParams,\n} from \"../types.js\"\n\nexport class Meters {\n readonly #client: Client\n\n constructor(client: Client) {\n this.#client = client\n }\n\n create(params: MeterCreateParams, options?: RequestOptions): Promise<Meter> {\n return this.#client.request({\n ...options,\n method: \"POST\",\n path: \"/v1/meters\",\n body: params,\n })\n }\n\n list(\n params: MeterListParams = {},\n options?: RequestOptions,\n ): Promise<List<Meter>> {\n return this.#client.request({\n ...options,\n method: \"GET\",\n path: \"/v1/meters\",\n query: { include_archived: params.include_archived },\n })\n }\n\n retrieve(id: string, options?: RequestOptions): Promise<Meter> {\n return this.#client.request({\n ...options,\n method: \"GET\",\n path: `/v1/meters/${encodeURIComponent(id)}`,\n })\n }\n\n update(\n id: string,\n params: MeterUpdateParams,\n options?: RequestOptions,\n ): Promise<Meter> {\n return this.#client.request({\n ...options,\n method: \"PATCH\",\n path: `/v1/meters/${encodeURIComponent(id)}`,\n body: params,\n })\n }\n\n /** Every customer's usage of the meter per UTC day. */\n usage(\n id: string,\n params: UsageDaysParams,\n options?: RequestOptions,\n ): Promise<MeterUsageHistory> {\n return this.#client.request({\n ...options,\n method: \"GET\",\n path: `/v1/meters/${encodeURIComponent(id)}/usage`,\n query: { days: params.days },\n })\n }\n\n /** Soft delete: plans and usage keep referencing the meter. Idempotent. */\n archive(id: string, options?: RequestOptions): Promise<Meter> {\n return this.#client.request({\n ...options,\n method: \"DELETE\",\n path: `/v1/meters/${encodeURIComponent(id)}`,\n })\n }\n}\n","import type { Client, RequestOptions } from \"../client.js\"\nimport type {\n List,\n Plan,\n PlanAllowance,\n PlanAllowanceListParams,\n PlanAllowanceSetParams,\n PlanCreateParams,\n PlanListParams,\n PlanUpdateParams,\n} from \"../types.js\"\n\n/**\n * A plan's entitlement, versioned. There is no update and no delete: an edit\n * appends the next version, so which amount applied when stays derivable.\n */\nexport class PlanAllowances {\n readonly #client: Client\n\n constructor(client: Client) {\n this.#client = client\n }\n\n set(\n planId: string,\n params: PlanAllowanceSetParams,\n options?: RequestOptions,\n ): Promise<PlanAllowance> {\n return this.#client.request({\n ...options,\n method: \"POST\",\n path: `/v1/plans/${encodeURIComponent(planId)}/allowances`,\n body: params,\n })\n }\n\n /** Every version of every meter, newest first — history, not just current. */\n list(\n planId: string,\n params: PlanAllowanceListParams = {},\n options?: RequestOptions,\n ): Promise<List<PlanAllowance>> {\n return this.#client.request({\n ...options,\n method: \"GET\",\n path: `/v1/plans/${encodeURIComponent(planId)}/allowances`,\n query: { meter_id: params.meter_id },\n })\n }\n}\n\nexport class Plans {\n readonly allowances: PlanAllowances\n\n readonly #client: Client\n\n constructor(client: Client) {\n this.#client = client\n this.allowances = new PlanAllowances(client)\n }\n\n /** A new plan grants nothing; attach entitlement with `allowances.set`. */\n create(params: PlanCreateParams, options?: RequestOptions): Promise<Plan> {\n return this.#client.request({\n ...options,\n method: \"POST\",\n path: \"/v1/plans\",\n body: params,\n })\n }\n\n list(\n params: PlanListParams = {},\n options?: RequestOptions,\n ): Promise<List<Plan>> {\n return this.#client.request({\n ...options,\n method: \"GET\",\n path: \"/v1/plans\",\n query: { include_archived: params.include_archived },\n })\n }\n\n retrieve(id: string, options?: RequestOptions): Promise<Plan> {\n return this.#client.request({\n ...options,\n method: \"GET\",\n path: `/v1/plans/${encodeURIComponent(id)}`,\n })\n }\n\n update(\n id: string,\n params: PlanUpdateParams,\n options?: RequestOptions,\n ): Promise<Plan> {\n return this.#client.request({\n ...options,\n method: \"PATCH\",\n path: `/v1/plans/${encodeURIComponent(id)}`,\n body: params,\n })\n }\n\n /**\n * Stops new assignments without withdrawing capacity from anyone already on\n * the plan, which is why an archived plan still resolves by id. Idempotent.\n */\n archive(id: string, options?: RequestOptions): Promise<Plan> {\n return this.#client.request({\n ...options,\n method: \"DELETE\",\n path: `/v1/plans/${encodeURIComponent(id)}`,\n })\n }\n}\n","import { Client, type MeterbaseOptions, type RequestOptions } from \"./client.js\"\nimport { MeterbaseError, NotFoundError, TooLateError } from \"./errors.js\"\nimport type { CustomerAllowances as CustomerAllowancesResource } from \"./resources/customer-allowances.js\"\nimport type { CustomerPlan as CustomerPlanResource } from \"./resources/customer-plan.js\"\nimport { Customers as CustomersResource } from \"./resources/customers.js\"\nimport { Meters as MetersResource } from \"./resources/meters.js\"\nimport {\n Plans as PlansResource,\n type PlanAllowances as PlanAllowancesResource,\n} from \"./resources/plans.js\"\nimport type {\n CheckParams,\n CheckResult,\n ReleaseParams,\n ReleaseResult,\n ReserveParams,\n ReserveResponse,\n TrackParams,\n TrackResult,\n WhoAmI,\n} from \"./types.js\"\n\n/**\n * A granted hold, with the two calls that close it. `commit` is `track` under\n * the hold's own id; `release` gives the capacity back.\n */\nexport type Hold = ReserveResponse & {\n allowed: true\n reservation_id: string\n quantity: number\n expires_at: string\n /**\n * Records what the work actually cost and releases the rest. Omit the\n * quantity to record what was held.\n *\n * Warns when it runs after `expires_at`: the hold stopped holding anything\n * at that instant, so the work was no longer protected. That warning is the\n * only feedback there is on an `expires_in_seconds` guessed too short.\n */\n commit(quantity?: number, options?: RequestOptions): Promise<TrackResult>\n /**\n * Gives the hold back. Nothing is recorded.\n *\n * Resolves with `null` rather than throwing when there is nothing left to\n * release — already committed, already released. This is the one call meant\n * to run on the failure path, where throwing would mask the error the\n * caller is already handling, and \"nothing left to release\" is the outcome\n * a release wanted anyway. `meterbase.release` throws the 404, as every\n * other call does.\n */\n release(options?: RequestOptions): Promise<ReleaseResult | null>\n}\n\n/** A refused reserve holds nothing, so it carries no id and no expiry. */\nexport type ReserveRefused = ReserveResponse & {\n allowed: false\n reservation_id?: undefined\n expires_at?: undefined\n}\n\nexport type ReserveResult = Hold | ReserveRefused\n\nexport class Meterbase {\n readonly customers: Customers\n readonly meters: Meters\n readonly plans: Plans\n\n readonly #client: Client\n\n constructor(options: MeterbaseOptions) {\n this.#client = new Client(options)\n this.customers = new CustomersResource(this.#client)\n this.meters = new MetersResource(this.#client)\n this.plans = new PlansResource(this.#client)\n }\n\n /**\n * Asks whether a customer may consume `quantity` of a meter, named by the\n * tenant's own external id and the meter's key. Absence of entitlement is\n * not permission: a customer with no plan and no grant is denied.\n *\n * This is the gate, and the only call that ever refuses. Run it before the\n * work; record the work with `track` afterwards.\n *\n * Two gates answer it, and `allowed` needs both: the customer's capacity has\n * to cover the quantity, and every rate-limit window in force has to admit\n * it. `reason` names the one that said no. `rate_limits` reports each window\n * whether or not it refused, so a caller can ease off as its headroom closes\n * instead of discovering the ceiling by hitting it.\n */\n check(params: CheckParams, options?: RequestOptions): Promise<CheckResult> {\n return this.#client.request({\n ...options,\n method: \"POST\",\n path: \"/v1/check\",\n body: params,\n })\n }\n\n /**\n * Records usage that already happened — the tokens were spent, the image\n * was generated — so it never refuses on capacity. A quantity beyond the\n * customer's capacity is recorded, drives `available` to 0, and the next\n * `check` says no. The answer is a receipt, not a verdict.\n *\n * `idempotency_key` is a UUIDv7, generated when omitted, so retrying this\n * call — the SDK's own retries included — replays the original rather than\n * counting the same work twice. The engine keeps that claim for an hour,\n * which is how long a retry stays recognisable.\n */\n // `async` so that generating the key cannot throw synchronously out of a\n // method that otherwise only ever rejects: one call, one way to fail.\n async track(\n params: TrackParams,\n options?: RequestOptions,\n ): Promise<TrackResult> {\n return this.#keyed(IDEMPOTENCY_WINDOW_MS, params.idempotency_key, (key) =>\n this.#client.request<TrackResult>({\n ...options,\n method: \"POST\",\n path: \"/v1/usage/track\",\n // Fixed before the retry loop is entered: every attempt of this call\n // carries the same key, which is what makes replaying it safe.\n body: { ...params, idempotency_key: key },\n idempotent: true,\n }),\n )\n }\n\n /**\n * Holds capacity for work that cannot be done twice, or refuses. The same\n * decision `check` makes, and then a hold on the capacity until the work\n * is committed, released, or expires.\n *\n * The rule for choosing: can you afford to do the work twice? `check`. No?\n * `reserve`. A reserve costs a transaction where a check costs a cached\n * read, refusals included, so it is not a per-request gate on cheap work.\n *\n * Two concurrent reserves for the same customer and meter cannot both be\n * granted the same capacity; that is the whole point, and it is what\n * `check` → work → `track` could never promise.\n */\n async reserve(\n params: ReserveParams,\n options?: RequestOptions,\n ): Promise<ReserveResult> {\n const response = await this.#keyed(\n RESERVE_WINDOW_MS,\n params.reservation_id,\n (id) =>\n this.#client.request<ReserveResponse>({\n ...options,\n method: \"POST\",\n path: \"/v1/usage/reserve\",\n body: { ...params, reservation_id: id },\n // A retry under the same id finds the hold it already made rather\n // than making a second one.\n idempotent: true,\n }),\n )\n\n return this.#hold(params, response)\n }\n\n /**\n * Gives a hold back: the work did not happen, so nothing is recorded.\n *\n * Throws `NotFoundError` when the id names nothing — committed, released\n * already, or never made, which are one absence with one meaning. Prefer\n * `hold.release()`, which treats that as the success it is.\n */\n release(\n params: ReleaseParams,\n options?: RequestOptions,\n ): Promise<ReleaseResult> {\n return this.#client.request({\n ...options,\n method: \"POST\",\n path: \"/v1/usage/release\",\n body: params,\n })\n }\n\n /** Reports which workspace this key acts for. */\n whoami(options?: RequestOptions): Promise<WhoAmI> {\n return this.#client.request({\n ...options,\n method: \"GET\",\n path: \"/v1/whoami\",\n })\n }\n\n /**\n * Sends a call that carries a caller-minted UUIDv7, minting one when the\n * caller supplied none and re-minting once if this machine's clock put it\n * outside the engine's window.\n *\n * A key the caller supplied is never re-minted: this cannot know whether it\n * names work already recorded, and replacing it could count that work\n * twice.\n */\n async #keyed<T>(\n window: number,\n supplied: string | undefined,\n send: (key: string) => Promise<T>,\n ): Promise<T> {\n if (supplied !== undefined) return send(supplied)\n\n const key = idempotencyKey(this.#client.now())\n const startedAt = Date.now()\n\n try {\n return await send(key)\n } catch (error) {\n // The only failure this can fix by itself: a clock that disagrees with\n // the engine's.\n if (!(error instanceof TooLateError) || error.serverTime === undefined) {\n throw error\n }\n\n // Re-minting is safe only if no attempt under the old key can have\n // landed. `send` retries internally, so this 422 may have come from a\n // later attempt while an earlier one succeeded. If the key was already\n // outside the window when the call began, every attempt was refused.\n const elapsed = Date.now() - startedAt\n const serverAtStart = error.serverTime.getTime() - elapsed\n if (Math.abs(serverAtStart - mintedAtMs(key)) <= window) throw error\n\n this.#client.observeServerTime(error.serverTime)\n\n return await send(idempotencyKey(this.#client.now()))\n }\n }\n\n /** Puts `commit` and `release` on a granted hold; a refusal is left as it is. */\n #hold(params: ReserveParams, response: ReserveResponse): ReserveResult {\n if (!response.allowed) return response as ReserveRefused\n\n const id = response.reservation_id\n const expiresAt = response.expires_at\n\n // A grant without them is not a hold this can hand back: `allowed` would\n // narrow to the arm that carries `commit`, and the caller would find it\n // missing at the one moment they are relying on it. Louder here.\n if (id === undefined || expiresAt === undefined) {\n throw new MeterbaseError(\n \"The engine granted a reservation without an id or an expiry, so \" +\n \"there is no hold to commit or release. The capacity it set aside \" +\n \"comes back on its own.\",\n )\n }\n\n const expiresAtMs = Date.parse(expiresAt)\n\n return {\n ...response,\n allowed: true,\n reservation_id: id,\n quantity: response.quantity ?? params.quantity ?? 1,\n expires_at: expiresAt,\n\n commit: (quantity, commitOptions) => {\n if (\n Number.isFinite(expiresAtMs) &&\n this.#client.now() > expiresAtMs &&\n typeof globalThis.console?.warn === \"function\"\n ) {\n globalThis.console.warn(\n `Meterbase: committing reservation ${id} after it expired at ` +\n `${expiresAt}. The event is still recorded, but the capacity ` +\n `was no longer held — raise expires_in_seconds for this work.`,\n )\n }\n\n return this.track(\n {\n customer_id: params.customer_id,\n meter_id: params.meter_id,\n quantity,\n // The hold's own id, so the track commits it rather than\n // recording a second event beside it.\n idempotency_key: id,\n },\n commitOptions,\n )\n },\n\n release: async (releaseOptions) => {\n try {\n return await this.release({ reservation_id: id }, releaseOptions)\n } catch (error) {\n if (error instanceof NotFoundError) return null\n throw error\n }\n },\n }\n }\n}\n\n/**\n * The resource namespaces, type-only: none is constructible without the\n * unexported Client. Instance types rather than `export type { Customers }`,\n * which the declaration bundler re-emits as a value export — promising a\n * runtime binding the bundle never has.\n */\nexport type CustomerAllowances = InstanceType<typeof CustomerAllowancesResource>\nexport type CustomerPlan = InstanceType<typeof CustomerPlanResource>\nexport type Customers = InstanceType<typeof CustomersResource>\nexport type Meters = InstanceType<typeof MetersResource>\nexport type PlanAllowances = InstanceType<typeof PlanAllowancesResource>\nexport type Plans = InstanceType<typeof PlansResource>\nexport type { MeterbaseOptions, RequestOptions }\nexport * from \"./errors.js\"\nexport type * from \"./types.js\"\n\n/**\n * A UUIDv7: 48 bits of Unix milliseconds, then the version and variant, then\n * 74 random bits. `crypto.randomUUID()` mints a v4, which carries no time, so\n * this builds one from random bytes.\n *\n * `atMs` is the engine's clock as the client knows it, not this machine's: a\n * device an hour out would otherwise mint keys the engine refuses.\n */\n/** How far the engine lets a key's timestamp sit from its own clock. */\nconst IDEMPOTENCY_WINDOW_MS = 60 * 60 * 1000\n\n/**\n * The same guard for a reservation id, and narrower on purpose: the id is\n * minted at the call, and the engine has to leave room to commit the hold it\n * names long after.\n */\nconst RESERVE_WINDOW_MS = 30 * 60 * 1000\n\n/** The millisecond a v7 carries in its first 48 bits. */\nfunction mintedAtMs(key: string): number {\n return Number.parseInt(key.replace(/-/g, \"\").slice(0, 12), 16)\n}\n\nfunction idempotencyKey(atMs: number): string {\n // Structurally, not as `Crypto`: that lib type is the DOM's, and this\n // compiles without it so the SDK stays as portable as `fetch` is.\n const webcrypto = globalThis.crypto as\n { getRandomValues?: (array: Uint8Array) => Uint8Array } | undefined\n\n if (typeof webcrypto?.getRandomValues !== \"function\") {\n throw new MeterbaseError(\n \"No crypto to generate an idempotency key with: pass `idempotency_key` \" +\n \"yourself (a UUIDv7), or run somewhere `crypto.getRandomValues` exists.\",\n )\n }\n\n const bytes = webcrypto.getRandomValues(new Uint8Array(16))\n\n // Big-endian ms in the first six bytes, split in two so the arithmetic\n // stays 32-bit safe without BigInt.\n const ms = Math.max(0, Math.trunc(atMs))\n const high = Math.floor(ms / 0x1_0000_0000) // the top 16 bits of 48\n const low = ms >>> 0 // the bottom 32\n bytes[0] = (high >>> 8) & 0xff\n bytes[1] = high & 0xff\n bytes[2] = (low >>> 24) & 0xff\n bytes[3] = (low >>> 16) & 0xff\n bytes[4] = (low >>> 8) & 0xff\n bytes[5] = low & 0xff\n\n bytes[6] = (bytes[6]! & 0x0f) | 0x70 // version 7\n bytes[8] = (bytes[8]! & 0x3f) | 0x80 // variant 10\n\n const hex = Array.from(bytes, (b) => b.toString(16).padStart(2, \"0\")).join(\"\")\n\n return [\n hex.slice(0, 8),\n hex.slice(8, 12),\n hex.slice(12, 16),\n hex.slice(16, 20),\n hex.slice(20),\n ].join(\"-\")\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/errors.ts","../src/client.ts","../src/resources/customer-allowances.ts","../src/resources/customer-plan.ts","../src/resources/customers.ts","../src/resources/meters.ts","../src/resources/plans.ts","../src/webhooks.ts","../src/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["// Every failure is a MeterbaseError, so a caller can catch one type and still\n// switch on the specific one. `code` is stable; `message` may change.\n\nexport class MeterbaseError extends Error {\n constructor(message: string, options?: { cause?: unknown }) {\n super(message, options)\n this.name = new.target.name\n }\n}\n\nexport class APIError extends MeterbaseError {\n readonly status: number\n readonly code: string\n /** From `X-Request-Id`, when the engine sends one. */\n readonly requestId: string | undefined\n readonly body: unknown\n\n constructor(args: {\n status: number\n code: string\n message: string\n requestId?: string | undefined\n body?: unknown\n }) {\n super(args.message)\n this.status = args.status\n this.code = args.code\n this.requestId = args.requestId\n this.body = args.body\n }\n}\n\nexport class AuthenticationError extends APIError {}\nexport class PermissionDeniedError extends APIError {}\nexport class NotFoundError extends APIError {}\nexport class ConflictError extends APIError {}\n\nexport class InvalidRequestError extends APIError {}\n\n/**\n * `422 invalid_idempotency_key`: the key was not a UUID version 7.\n * `crypto.randomUUID()` mints a v4, so omit `idempotency_key` and let this\n * SDK mint the right thing.\n */\nexport class InvalidIdempotencyKeyError extends InvalidRequestError {}\n\n/**\n * `422 too_late`: the key's timestamp is more than an hour from the engine's\n * clock, so a retry can no longer be told from a new event. **Nothing was\n * recorded** — the check runs before any write.\n *\n * The usual cause is this machine's clock. When this SDK minted the key it\n * corrects the offset from `serverTime` and retries once, so you only see\n * this for a key you supplied. If that key is a retry of a call made over an\n * hour ago, do not resend it under a new one: it may already be recorded.\n */\nexport class TooLateError extends InvalidRequestError {\n /** The engine's clock when it refused. */\n readonly serverTime: Date | undefined\n\n constructor(args: ConstructorParameters<typeof APIError>[0]) {\n super(args)\n this.serverTime = serverTime(args.body)\n }\n}\n\n/**\n * `422 reservation_mismatch`: the reservation id names a hold made for a\n * different customer or meter than the call sends. A caller bug, refused\n * before anything is written — nothing was recorded and the hold still\n * stands.\n */\nexport class ReservationMismatchError extends InvalidRequestError {}\n\n/**\n * `422 cycle_change_requires_reset`: the two plans measure different cycles,\n * so a `next_cycle` change has no shared boundary to wait for and a `prorate`\n * no shared period to weight. The move is `customers.plan.restart`, which\n * closes the current period and opens a fresh one on the new cycle — or\n * `changeNow` with the default `reconciliation: \"none\"` to keep the period\n * that is running. The engine's `message` says as much.\n *\n * An `InvalidRequestError` still, so an existing `catch` keeps working.\n */\nexport class CycleChangeRequiresResetError extends InvalidRequestError {}\nexport class RateLimitError extends APIError {\n /** Seconds to wait, from `Retry-After`, when the engine sends one. */\n readonly retryAfter: number | undefined\n\n constructor(\n args: ConstructorParameters<typeof APIError>[0] & {\n retryAfter?: number | undefined\n },\n ) {\n super(args)\n this.retryAfter = args.retryAfter\n }\n}\nexport class ServerError extends APIError {}\n\n// The request never produced an answer: DNS, TLS, a reset, an abort.\nexport class ConnectionError extends MeterbaseError {}\nexport class TimeoutError extends ConnectionError {}\n\nexport function errorFromResponse(args: {\n status: number\n code: string\n message: string\n requestId?: string | undefined\n retryAfter?: number | undefined\n body?: unknown\n}): APIError {\n switch (args.status) {\n case 401:\n return new AuthenticationError(args)\n case 403:\n return new PermissionDeniedError(args)\n case 404:\n return new NotFoundError(args)\n case 409:\n return new ConflictError(args)\n case 422:\n switch (args.code) {\n case \"cycle_change_requires_reset\":\n return new CycleChangeRequiresResetError(args)\n case \"invalid_idempotency_key\":\n return new InvalidIdempotencyKeyError(args)\n case \"reservation_mismatch\":\n return new ReservationMismatchError(args)\n case \"too_late\":\n return new TooLateError(args)\n default:\n return new InvalidRequestError(args)\n }\n case 429:\n return new RateLimitError(args)\n default:\n return args.status >= 500 ? new ServerError(args) : new APIError(args)\n }\n}\n\n/** The engine carries it beside `code` and `message`, inside `error`. */\nfunction serverTime(body: unknown): Date | undefined {\n if (typeof body !== \"object\" || body === null) return undefined\n\n const error = (body as { error?: unknown }).error\n if (typeof error !== \"object\" || error === null) return undefined\n\n const at = (error as { server_time?: unknown }).server_time\n if (typeof at !== \"string\") return undefined\n\n const parsed = new Date(at)\n return Number.isNaN(parsed.getTime()) ? undefined : parsed\n}\n\n/** A webhook that is not one Meterbase signed recently: answer it with a 400. */\nexport class WebhookVerificationError extends MeterbaseError {}\n","// Everything goes through `request`, so authentication, timeouts, retries and\n// error mapping are defined once.\n\nimport {\n ConnectionError,\n errorFromResponse,\n MeterbaseError,\n TimeoutError,\n} from \"./errors.js\"\n\nexport type MeterbaseOptions = {\n /** A secret key. It names its own workspace. */\n apiKey: string\n /** Defaults to the hosted engine. */\n baseUrl?: string\n /** Per attempt, not per call. */\n timeout?: number\n maxRetries?: number\n fetch?: typeof globalThis.fetch\n}\n\nexport type RequestOptions = {\n signal?: AbortSignal\n timeout?: number\n maxRetries?: number\n}\n\ntype HttpMethod = \"GET\" | \"POST\" | \"PATCH\" | \"DELETE\"\n\ntype Request = RequestOptions & {\n method: HttpMethod\n path: string\n query?: Record<string, string | number | boolean | undefined>\n body?: unknown\n /**\n * Replay this call even though its method is not safe. Only a route that\n * carries an idempotency key may set it, and the key has to be fixed before\n * `request` is called — the loop re-sends one body, so a key generated\n * per attempt would count the same usage twice.\n */\n idempotent?: boolean\n}\n\nconst DEFAULT_BASE_URL = \"https://api.meterbase.tech\"\nconst DEFAULT_TIMEOUT = 10_000\nconst DEFAULT_MAX_RETRIES = 2\nconst MAX_BACKOFF = 8_000\n\nexport class Client {\n readonly #apiKey: string\n readonly #baseUrl: string\n readonly #timeout: number\n readonly #maxRetries: number\n readonly #fetch: typeof globalThis.fetch\n\n /**\n * How far the engine's clock is ahead of this machine's, in milliseconds.\n * Idempotency keys are minted here and the engine refuses one dated more\n * than an hour from its own clock, so without this a device with a wrong\n * clock would fail every call forever.\n */\n #clockOffset = 0\n\n /** The engine's clock, as well as this client knows it. */\n now(): number {\n return Date.now() + this.#clockOffset\n }\n\n /** Off by up to one round trip, which a window in hours does not notice. */\n observeServerTime(at: Date): void {\n this.#clockOffset = at.getTime() - Date.now()\n }\n\n constructor(options: MeterbaseOptions) {\n if (!options.apiKey) {\n throw new MeterbaseError(\n \"An API key is required: new Meterbase({ apiKey: 'mb_sk_live_…' }).\",\n )\n }\n\n this.#apiKey = options.apiKey\n this.#baseUrl = (options.baseUrl ?? DEFAULT_BASE_URL).replace(/\\/+$/, \"\")\n this.#timeout = options.timeout ?? DEFAULT_TIMEOUT\n this.#maxRetries = options.maxRetries ?? DEFAULT_MAX_RETRIES\n this.#fetch = options.fetch ?? globalThis.fetch\n\n if (typeof this.#fetch !== \"function\") {\n throw new MeterbaseError(\n \"No fetch implementation: pass one as `fetch`, or run on Node 20+.\",\n )\n }\n }\n\n async request<T>(req: Request): Promise<T> {\n const maxRetries = req.maxRetries ?? this.#maxRetries\n // Safe methods, plus the routes that carry an idempotency key and say so.\n // Any other POST or PATCH could create a second row on a replay.\n const retryable =\n req.method === \"GET\" || req.method === \"DELETE\" || req.idempotent === true\n\n let lastError: unknown\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n // The caller's signal ends the wait as well as the attempt: a backoff\n // can run to eight seconds, and a cancelled call should not sit it out.\n if (attempt > 0) await sleep(backoff(attempt, lastError), req.signal)\n\n try {\n const response = await this.#send(req)\n\n if (response.ok) return (await parseBody(response)) as T\n\n const error = await errorFrom(response)\n if (retryable && attempt < maxRetries && shouldRetry(response.status)) {\n lastError = error\n continue\n }\n throw error\n } catch (cause) {\n if (\n cause instanceof MeterbaseError &&\n !(cause instanceof ConnectionError)\n ) {\n throw cause\n }\n // The caller cancelled, so nothing is retried: a replay would do the\n // work they called off — for `track`, record usage they cancelled.\n // Decided on the signal rather than the error, since the reason they\n // aborted with can be any value at all.\n if (req.signal?.aborted) throw cause\n // A connection failure proves nothing about whether the server acted,\n // so it is replayed under the same idempotency rule.\n if (!retryable || attempt >= maxRetries) throw cause\n lastError = cause\n }\n }\n\n /* c8 ignore next 2 -- the loop always returns or throws */\n throw lastError\n }\n\n async #send(req: Request): Promise<Response> {\n // An `abort` event fires once. A listener added to a signal that has\n // already aborted never hears it, so without this check a retry — or a\n // call made with a signal the caller aborted earlier — would run to\n // completion as though it had never been cancelled.\n if (req.signal?.aborted) throw req.signal.reason\n\n const url = new URL(this.#baseUrl + req.path)\n for (const [key, value] of Object.entries(req.query ?? {})) {\n if (value !== undefined) url.searchParams.set(key, String(value))\n }\n\n const headers: Record<string, string> = {\n authorization: `Bearer ${this.#apiKey}`,\n accept: \"application/json\",\n }\n if (req.body !== undefined) headers[\"content-type\"] = \"application/json\"\n\n const timeout = req.timeout ?? this.#timeout\n const controller = new AbortController()\n const onAbort = () => controller.abort(req.signal?.reason)\n req.signal?.addEventListener(\"abort\", onAbort, { once: true })\n\n let timedOut = false\n const timer = setTimeout(() => {\n timedOut = true\n controller.abort()\n }, timeout)\n\n try {\n return await this.#fetch(url, {\n method: req.method,\n headers,\n body: req.body === undefined ? undefined : JSON.stringify(req.body),\n signal: controller.signal,\n })\n } catch (cause) {\n if (timedOut) {\n throw new TimeoutError(`Request timed out after ${timeout}ms.`, {\n cause,\n })\n }\n // A caller's own abort is theirs to handle, not ours to reclassify.\n if (req.signal?.aborted) throw cause\n throw new ConnectionError(`Could not reach ${url.origin}.`, { cause })\n } finally {\n clearTimeout(timer)\n req.signal?.removeEventListener(\"abort\", onAbort)\n }\n }\n}\n\nfunction shouldRetry(status: number): boolean {\n return status === 408 || status === 429 || status >= 500\n}\n\n/** Exponential backoff with full jitter, unless the engine named a delay. */\nfunction backoff(attempt: number, lastError: unknown): number {\n const retryAfter =\n lastError && typeof lastError === \"object\" && \"retryAfter\" in lastError\n ? (lastError as { retryAfter?: number }).retryAfter\n : undefined\n if (retryAfter !== undefined) return Math.min(retryAfter * 1000, MAX_BACKOFF)\n\n const ceiling = Math.min(500 * 2 ** (attempt - 1), MAX_BACKOFF)\n return Math.random() * ceiling\n}\n\n/** Resolves after `ms`, or rejects with the signal's reason if it aborts first. */\nfunction sleep(ms: number, signal?: AbortSignal): Promise<void> {\n return new Promise((resolve, reject) => {\n if (signal?.aborted) {\n reject(signal.reason)\n return\n }\n\n const onAbort = () => {\n clearTimeout(timer)\n reject(signal?.reason)\n }\n const timer = setTimeout(() => {\n // Callers reuse one signal across many calls; leaving a listener behind\n // on each backoff would pile them up on it.\n signal?.removeEventListener(\"abort\", onAbort)\n resolve()\n }, ms)\n signal?.addEventListener(\"abort\", onAbort, { once: true })\n })\n}\n\nasync function parseBody(response: Response): Promise<unknown> {\n if (response.status === 204) return undefined\n\n const text = await response.text()\n if (text === \"\") return undefined\n\n try {\n return JSON.parse(text)\n } catch (cause) {\n throw new MeterbaseError(\"The engine returned a body that is not JSON.\", {\n cause,\n })\n }\n}\n\nasync function errorFrom(response: Response) {\n const body = await response.text()\n const parsed = parseErrorBody(body)\n const retryAfterHeader = response.headers.get(\"retry-after\")\n const retryAfter = retryAfterHeader ? Number(retryAfterHeader) : undefined\n\n return errorFromResponse({\n status: response.status,\n code: parsed?.code ?? `http_${response.status}`,\n message: parsed?.message ?? `The engine responded ${response.status}.`,\n requestId: response.headers.get(\"x-request-id\") ?? undefined,\n retryAfter:\n retryAfter !== undefined && Number.isFinite(retryAfter)\n ? retryAfter\n : undefined,\n body: body === \"\" ? undefined : (safeParse(body) ?? body),\n })\n}\n\nfunction parseErrorBody(body: string) {\n const parsed = safeParse(body) as\n { error?: { code?: string; message?: string } } | undefined\n const error = parsed?.error\n if (!error?.code || !error.message) return undefined\n\n return { code: error.code, message: error.message }\n}\n\nfunction safeParse(body: string): unknown {\n try {\n return JSON.parse(body)\n } catch {\n return undefined\n }\n}\n","import type { Client, RequestOptions } from \"../client.js\"\nimport type {\n Allowance,\n AllowanceGrantParams,\n AllowanceListParams,\n List,\n} from \"../types.js\"\n\n/**\n * Capacity handed to one customer on top of their plan. A grant with\n * `source: \"plan\"` is the engine's own, minted when a plan is assigned, and\n * cannot be created here.\n */\nexport class CustomerAllowances {\n readonly #client: Client\n\n constructor(client: Client) {\n this.#client = client\n }\n\n grant(\n customerId: string,\n params: AllowanceGrantParams,\n options?: RequestOptions,\n ): Promise<Allowance> {\n return this.#client.request({\n ...options,\n method: \"POST\",\n path: `/v1/customers/${encodeURIComponent(customerId)}/allowances`,\n body: params,\n })\n }\n\n /** Open grants only, unless `include_closed`. */\n list(\n customerId: string,\n params: AllowanceListParams = {},\n options?: RequestOptions,\n ): Promise<List<Allowance>> {\n return this.#client.request({\n ...options,\n method: \"GET\",\n path: `/v1/customers/${encodeURIComponent(customerId)}/allowances`,\n query: {\n meter_id: params.meter_id,\n include_closed: params.include_closed,\n },\n })\n }\n\n retrieve(\n customerId: string,\n allowanceId: string,\n options?: RequestOptions,\n ): Promise<Allowance> {\n return this.#client.request({\n ...options,\n method: \"GET\",\n path: `/v1/customers/${encodeURIComponent(customerId)}/allowances/${encodeURIComponent(allowanceId)}`,\n })\n }\n\n /** Withdraws what is left without erasing what was consumed. Idempotent. */\n revoke(\n customerId: string,\n allowanceId: string,\n options?: RequestOptions,\n ): Promise<Allowance> {\n return this.#client.request({\n ...options,\n method: \"DELETE\",\n path: `/v1/customers/${encodeURIComponent(customerId)}/allowances/${encodeURIComponent(allowanceId)}`,\n })\n }\n}\n","import type { Client, RequestOptions } from \"../client.js\"\nimport type {\n AssignPlanParams,\n Assignment,\n List,\n PlanChangeNowParams,\n PlanChangeParams,\n PlanMoveParams,\n} from \"../types.js\"\nimport { NotFoundError } from \"../errors.js\"\n\n/**\n * Which plan a customer holds. The history is append-only: there is no patch\n * and no delete, and moving a customer to a different plan is the same call as\n * their first.\n *\n * `assign` is that call, mirroring the wire. The rest name the four moves a\n * caller actually makes — later, now, now-and-start-over, and never mind — so\n * that picking one does not mean knowing what `effective` and `reconciliation`\n * do to a half-used period.\n */\nexport class CustomerPlan {\n readonly #client: Client\n\n constructor(client: Client) {\n this.#client = client\n }\n\n /**\n * Put a customer on a plan. This is the wire call, and the only one that\n * takes `cycle_anchor` — a first assignment's one chance to put their\n * periods on a date they already have.\n *\n * Returns the instruction as recorded, which is not always as asked: a first\n * plan is recorded `immediate` whatever `effective` said.\n */\n assign(\n customerId: string,\n params: AssignPlanParams,\n options?: RequestOptions,\n ): Promise<Assignment> {\n return this.#client.request({\n ...options,\n method: \"POST\",\n path: `/v1/customers/${encodeURIComponent(customerId)}/plan`,\n body: params,\n })\n }\n\n /**\n * Move a customer to a different plan, with both knobs in the open.\n * `effective` defaults to `next_cycle`; `reconciliation` applies only to an\n * `immediate` change and defaults to `none`.\n *\n * Reach for `changeAtNextCycle`, `changeNow` or `restart` when one of them\n * says what you mean — this is the form to fall back to when the two are\n * chosen at runtime.\n */\n change(\n customerId: string,\n params: PlanChangeParams,\n options?: RequestOptions,\n ): Promise<Assignment> {\n const { plan, ...rest } = params\n\n return this.assign(customerId, { plan_id: plan, ...rest }, options)\n }\n\n /**\n * Schedule the move for the end of the period they are in: they keep the\n * plan they are paying for until it runs out, and the new one starts at\n * their next boundary. Nothing is pro-rated, because nothing is split.\n *\n * Two plans on different cycles share no boundary, and this answers\n * `CycleChangeRequiresResetError` — use `restart` for that move.\n */\n changeAtNextCycle(\n customerId: string,\n params: PlanMoveParams,\n options?: RequestOptions,\n ): Promise<Assignment> {\n return this.change(\n customerId,\n { plan: params.plan, effective: \"next_cycle\" },\n options,\n )\n }\n\n /**\n * Move them now, inside the period already running. Their renewal day does\n * not move; what changes is this period's cap, and `reconciliation` says\n * how:\n *\n * - `none` (the default) — the new plan's amount governs the whole period.\n * Usage already spent still counts, so a downgrade can deny until the\n * period ends.\n * - `prorate` — each plan's amount weighted by the fraction of the period it\n * was held for. Refused between plans on different cycles, which share no\n * period to weight.\n *\n * To have the period itself start over instead, use `restart`.\n */\n changeNow(\n customerId: string,\n params: PlanChangeNowParams,\n options?: RequestOptions,\n ): Promise<Assignment> {\n return this.change(\n customerId,\n { ...params, effective: \"immediate\" },\n options,\n )\n }\n\n /**\n * Move them now and start a fresh period today: the period they were in\n * closes where the change lands, keeping the usage it had, and the new\n * plan's full amount opens immediately.\n *\n * This moves the customer's anchor, so their renewal day becomes today. It\n * is the move for a customer starting over — a new contract, a re-signup —\n * and the only one that can take a customer between plans whose cycles\n * differ.\n */\n restart(\n customerId: string,\n params: PlanMoveParams,\n options?: RequestOptions,\n ): Promise<Assignment> {\n return this.change(\n customerId,\n { plan: params.plan, effective: \"immediate\", reconciliation: \"reset\" },\n options,\n )\n }\n\n /**\n * Call off a change that has not landed yet, leaving the customer on the\n * plan they hold. Naming the plan already held is what supersedes a pending\n * instruction, so this reads the plan in force and names it back.\n *\n * Returns the assignment still in force, or `null` for a customer holding no\n * plan — who can have nothing pending, since a first assignment always lands\n * at once.\n */\n async cancelScheduledChange(\n customerId: string,\n options?: RequestOptions,\n ): Promise<Assignment | null> {\n const current = await this.retrieve(customerId, options)\n if (current === null) return null\n\n return this.assign(customerId, { plan_id: current.plan_id }, options)\n }\n\n /**\n * The plan in force now, which is not always the newest instruction: a\n * change dated ahead does not govern yet.\n *\n * `null` when the customer holds no plan. That is a default deny rather than\n * a failure — they are entitled to nothing — so it is an answer here and not\n * a thrown `NotFoundError`. A customer who does not exist at all still\n * throws one.\n */\n async retrieve(\n customerId: string,\n options?: RequestOptions,\n ): Promise<Assignment | null> {\n try {\n return await this.#client.request<Assignment>({\n ...options,\n method: \"GET\",\n path: `/v1/customers/${encodeURIComponent(customerId)}/plan`,\n })\n } catch (error) {\n if (error instanceof NotFoundError && error.code === \"no_plan_assigned\") {\n return null\n }\n throw error\n }\n }\n\n /**\n * The change waiting to land, or `null` when none is. At most one is ever\n * live: a newer instruction supersedes the one before it.\n *\n * Read against the assignment in force rather than against the local clock,\n * so a change landing seconds from now is not reported as already governing.\n */\n async pending(\n customerId: string,\n options?: RequestOptions,\n ): Promise<Assignment | null> {\n const [current, { data }] = await Promise.all([\n this.retrieve(customerId, options),\n this.history(customerId, options),\n ])\n\n const inForce =\n current === null ? -Infinity : Date.parse(current.effective_at)\n\n return (\n data.find(\n (a) => a.superseded_at === null && Date.parse(a.effective_at) > inForce,\n ) ?? null\n )\n }\n\n /** Every instruction, superseded ones included: it is the whole trail. */\n history(\n customerId: string,\n options?: RequestOptions,\n ): Promise<List<Assignment>> {\n return this.#client.request({\n ...options,\n method: \"GET\",\n path: `/v1/customers/${encodeURIComponent(customerId)}/plan/history`,\n })\n }\n}\n","import type { Client, RequestOptions } from \"../client.js\"\nimport { NotFoundError } from \"../errors.js\"\nimport type {\n Customer,\n CustomerCreateParams,\n CustomerEntitlement,\n CustomerListParams,\n CustomerUpdateParams,\n CustomerUsage,\n CustomerUsageParams,\n CustomerWithPlan,\n List,\n UsageDaysParams,\n UsagePeriodParams,\n} from \"../types.js\"\nimport { CustomerAllowances } from \"./customer-allowances.js\"\nimport { CustomerPlan } from \"./customer-plan.js\"\n\nexport class Customers {\n /** The plan they hold, and the trail of instructions that got them there. */\n readonly plan: CustomerPlan\n /** Grants, which sit on top of whatever the plan gives. */\n readonly allowances: CustomerAllowances\n\n readonly #client: Client\n\n constructor(client: Client) {\n this.#client = client\n this.plan = new CustomerPlan(client)\n this.allowances = new CustomerAllowances(client)\n }\n\n create(\n params: CustomerCreateParams,\n options?: RequestOptions,\n ): Promise<Customer> {\n return this.#client.request({\n ...options,\n method: \"POST\",\n path: \"/v1/customers\",\n body: params,\n })\n }\n\n /** Lean: a listing does not embed the plan. Read one customer for that. */\n list(\n params: CustomerListParams = {},\n options?: RequestOptions,\n ): Promise<List<Customer>> {\n return this.#client.request({\n ...options,\n method: \"GET\",\n path: \"/v1/customers\",\n query: { include_deleted: params.include_deleted },\n })\n }\n\n /**\n * One customer, with the plan they hold. `plan` is the one in force now and\n * `pending_plan` the change waiting to land, each `null` when there is\n * none — so knowing what a customer is on costs no second request.\n */\n retrieve(id: string, options?: RequestOptions): Promise<CustomerWithPlan> {\n return this.#client.request({\n ...options,\n method: \"GET\",\n path: `/v1/customers/${encodeURIComponent(id)}`,\n })\n }\n\n /**\n * Resolves the tenant's own identifier, or null, embedding the plan the way\n * `retrieve` does. The engine answers this as a filtered list, so a miss is\n * an empty collection rather than a 404.\n */\n async retrieveByExternalId(\n externalId: string,\n options?: RequestOptions,\n ): Promise<CustomerWithPlan | null> {\n const { data } = await this.#client.request<List<CustomerWithPlan>>({\n ...options,\n method: \"GET\",\n path: \"/v1/customers\",\n query: { external_id: externalId },\n })\n\n return data[0] ?? null\n }\n\n /** `null` for a customer holding no plan, as `plan.retrieve` answers. */\n async entitlement(\n id: string,\n options?: RequestOptions,\n ): Promise<CustomerEntitlement | null> {\n try {\n return await this.#client.request<CustomerEntitlement>({\n ...options,\n method: \"GET\",\n path: `/v1/customers/${encodeURIComponent(id)}/entitlement`,\n })\n } catch (error) {\n if (error instanceof NotFoundError && error.code === \"no_plan_assigned\") {\n return null\n }\n throw error\n }\n }\n\n /**\n * Usage per UTC day. A period the customer never had, holding no plan now\n * or none before this period, is `null`.\n */\n usage(\n id: string,\n params: UsageDaysParams,\n options?: RequestOptions,\n ): Promise<CustomerUsage>\n usage(\n id: string,\n params: UsagePeriodParams,\n options?: RequestOptions,\n ): Promise<CustomerUsage | null>\n async usage(\n id: string,\n params: CustomerUsageParams,\n options?: RequestOptions,\n ): Promise<CustomerUsage | null> {\n try {\n return await this.#client.request<CustomerUsage>({\n ...options,\n method: \"GET\",\n path: `/v1/customers/${encodeURIComponent(id)}/usage`,\n query: { days: params.days, period: params.period },\n })\n } catch (error) {\n if (\n error instanceof NotFoundError &&\n (error.code === \"no_plan_assigned\" ||\n error.code === \"no_previous_period\")\n ) {\n return null\n }\n throw error\n }\n }\n\n update(\n id: string,\n params: CustomerUpdateParams,\n options?: RequestOptions,\n ): Promise<Customer> {\n return this.#client.request({\n ...options,\n method: \"PATCH\",\n path: `/v1/customers/${encodeURIComponent(id)}`,\n body: params,\n })\n }\n\n /** Soft delete: usage and assignments keep referencing the customer. */\n delete(id: string, options?: RequestOptions): Promise<Customer> {\n return this.#client.request({\n ...options,\n method: \"DELETE\",\n path: `/v1/customers/${encodeURIComponent(id)}`,\n })\n }\n}\n","import type { Client, RequestOptions } from \"../client.js\"\nimport type {\n List,\n Meter,\n MeterCreateParams,\n MeterListParams,\n MeterUpdateParams,\n MeterUsageHistory,\n UsageDaysParams,\n} from \"../types.js\"\n\nexport class Meters {\n readonly #client: Client\n\n constructor(client: Client) {\n this.#client = client\n }\n\n create(params: MeterCreateParams, options?: RequestOptions): Promise<Meter> {\n return this.#client.request({\n ...options,\n method: \"POST\",\n path: \"/v1/meters\",\n body: params,\n })\n }\n\n list(\n params: MeterListParams = {},\n options?: RequestOptions,\n ): Promise<List<Meter>> {\n return this.#client.request({\n ...options,\n method: \"GET\",\n path: \"/v1/meters\",\n query: { include_archived: params.include_archived },\n })\n }\n\n retrieve(id: string, options?: RequestOptions): Promise<Meter> {\n return this.#client.request({\n ...options,\n method: \"GET\",\n path: `/v1/meters/${encodeURIComponent(id)}`,\n })\n }\n\n update(\n id: string,\n params: MeterUpdateParams,\n options?: RequestOptions,\n ): Promise<Meter> {\n return this.#client.request({\n ...options,\n method: \"PATCH\",\n path: `/v1/meters/${encodeURIComponent(id)}`,\n body: params,\n })\n }\n\n /** Every customer's usage of the meter per UTC day. */\n usage(\n id: string,\n params: UsageDaysParams,\n options?: RequestOptions,\n ): Promise<MeterUsageHistory> {\n return this.#client.request({\n ...options,\n method: \"GET\",\n path: `/v1/meters/${encodeURIComponent(id)}/usage`,\n query: { days: params.days },\n })\n }\n\n /** Soft delete: plans and usage keep referencing the meter. Idempotent. */\n archive(id: string, options?: RequestOptions): Promise<Meter> {\n return this.#client.request({\n ...options,\n method: \"DELETE\",\n path: `/v1/meters/${encodeURIComponent(id)}`,\n })\n }\n}\n","import type { Client, RequestOptions } from \"../client.js\"\nimport type {\n List,\n Plan,\n PlanAllowance,\n PlanAllowanceListParams,\n PlanAllowanceSetParams,\n PlanCreateParams,\n PlanListParams,\n PlanUpdateParams,\n} from \"../types.js\"\n\n/**\n * A plan's entitlement, versioned. There is no update and no delete: an edit\n * appends the next version, so which amount applied when stays derivable.\n */\nexport class PlanAllowances {\n readonly #client: Client\n\n constructor(client: Client) {\n this.#client = client\n }\n\n set(\n planId: string,\n params: PlanAllowanceSetParams,\n options?: RequestOptions,\n ): Promise<PlanAllowance> {\n return this.#client.request({\n ...options,\n method: \"POST\",\n path: `/v1/plans/${encodeURIComponent(planId)}/allowances`,\n body: params,\n })\n }\n\n /** Every version of every meter, newest first — history, not just current. */\n list(\n planId: string,\n params: PlanAllowanceListParams = {},\n options?: RequestOptions,\n ): Promise<List<PlanAllowance>> {\n return this.#client.request({\n ...options,\n method: \"GET\",\n path: `/v1/plans/${encodeURIComponent(planId)}/allowances`,\n query: { meter_id: params.meter_id },\n })\n }\n}\n\nexport class Plans {\n readonly allowances: PlanAllowances\n\n readonly #client: Client\n\n constructor(client: Client) {\n this.#client = client\n this.allowances = new PlanAllowances(client)\n }\n\n /** A new plan grants nothing; attach entitlement with `allowances.set`. */\n create(params: PlanCreateParams, options?: RequestOptions): Promise<Plan> {\n return this.#client.request({\n ...options,\n method: \"POST\",\n path: \"/v1/plans\",\n body: params,\n })\n }\n\n list(\n params: PlanListParams = {},\n options?: RequestOptions,\n ): Promise<List<Plan>> {\n return this.#client.request({\n ...options,\n method: \"GET\",\n path: \"/v1/plans\",\n query: { include_archived: params.include_archived },\n })\n }\n\n retrieve(id: string, options?: RequestOptions): Promise<Plan> {\n return this.#client.request({\n ...options,\n method: \"GET\",\n path: `/v1/plans/${encodeURIComponent(id)}`,\n })\n }\n\n update(\n id: string,\n params: PlanUpdateParams,\n options?: RequestOptions,\n ): Promise<Plan> {\n return this.#client.request({\n ...options,\n method: \"PATCH\",\n path: `/v1/plans/${encodeURIComponent(id)}`,\n body: params,\n })\n }\n\n /**\n * Stops new assignments without withdrawing capacity from anyone already on\n * the plan, which is why an archived plan still resolves by id. Idempotent.\n */\n archive(id: string, options?: RequestOptions): Promise<Plan> {\n return this.#client.request({\n ...options,\n method: \"DELETE\",\n path: `/v1/plans/${encodeURIComponent(id)}`,\n })\n }\n}\n","import { MeterbaseError, WebhookVerificationError } from \"./errors.js\"\nimport type { WebhookEvent } from \"./types.js\"\n\n/** A `Headers` object, or Node's lowercase header record. */\nexport type WebhookHeaders =\n | { get(name: string): string | null }\n | Record<string, string | string[] | undefined>\n\nexport type VerifyWebhookParams = {\n /** The body exactly as received. Re-serialized JSON will not verify. */\n payload: string | Uint8Array\n headers: WebhookHeaders\n /** The endpoint's `whsec_…` secret; pass both while rotating. */\n secret: string | readonly string[]\n /** How far `webhook-timestamp` may be from now. Five minutes by default. */\n toleranceSeconds?: number\n}\n\ntype Subtle = {\n importKey(\n format: \"raw\",\n keyData: Uint8Array,\n algorithm: { name: \"HMAC\"; hash: \"SHA-256\" },\n extractable: false,\n usages: [\"verify\"],\n ): Promise<unknown>\n verify(\n algorithm: \"HMAC\",\n key: unknown,\n signature: Uint8Array,\n data: Uint8Array,\n ): Promise<boolean>\n}\n\nconst SECRET_PREFIX = \"whsec_\"\nconst DEFAULT_TOLERANCE_SECONDS = 5 * 60\n\n/**\n * Checks a delivery's signature and timestamp the Standard Webhooks way, then\n * returns the event. Throws `WebhookVerificationError` when it is not one\n * Meterbase signed recently.\n */\nexport async function verifyWebhook(\n params: VerifyWebhookParams,\n): Promise<WebhookEvent> {\n const id = header(params.headers, \"webhook-id\")\n const timestamp = header(params.headers, \"webhook-timestamp\")\n const signatures = header(params.headers, \"webhook-signature\")\n if (!id || !timestamp || !signatures) {\n throw new WebhookVerificationError(\n \"Missing a webhook-id, webhook-timestamp or webhook-signature header.\",\n )\n }\n\n const sentAt = Number(timestamp)\n const tolerance = params.toleranceSeconds ?? DEFAULT_TOLERANCE_SECONDS\n if (\n !Number.isInteger(sentAt) ||\n Math.abs(Date.now() / 1000 - sentAt) > tolerance\n ) {\n throw new WebhookVerificationError(\n \"The webhook-timestamp is too far from now; this may be a replay.\",\n )\n }\n\n const body =\n typeof params.payload === \"string\"\n ? new TextEncoder().encode(params.payload)\n : params.payload\n const signed = concat(new TextEncoder().encode(`${id}.${timestamp}.`), body)\n const candidates = signatures\n .split(\" \")\n .filter((entry) => entry.startsWith(\"v1,\"))\n .map((entry) => fromBase64(entry.slice(3)))\n\n const subtle = webCrypto()\n const secrets =\n typeof params.secret === \"string\" ? [params.secret] : params.secret\n for (const secret of secrets) {\n const raw = secret.startsWith(SECRET_PREFIX)\n ? fromBase64(secret.slice(SECRET_PREFIX.length))\n : undefined\n if (!raw) {\n throw new WebhookVerificationError(\n \"The secret should be whsec_ and base64: copy it from the endpoint's settings.\",\n )\n }\n const key = await subtle.importKey(\n \"raw\",\n raw,\n { name: \"HMAC\", hash: \"SHA-256\" },\n false,\n [\"verify\"],\n )\n for (const candidate of candidates) {\n // `verify` compares in constant time.\n if (candidate && (await subtle.verify(\"HMAC\", key, candidate, signed))) {\n return JSON.parse(new TextDecoder().decode(body)) as WebhookEvent\n }\n }\n }\n\n throw new WebhookVerificationError(\n \"No signature matches: the body changed, or this is the wrong secret.\",\n )\n}\n\nfunction header(headers: WebhookHeaders, name: string) {\n if (typeof headers.get === \"function\") {\n return (\n (headers as { get(name: string): string | null }).get(name) ?? undefined\n )\n }\n const value = (headers as Record<string, string | string[] | undefined>)[name]\n return Array.isArray(value) ? value[0] : value\n}\n\nfunction webCrypto(): Subtle {\n const subtle = (globalThis.crypto as { subtle?: Subtle } | undefined)?.subtle\n if (!subtle) {\n throw new MeterbaseError(\n \"No Web Crypto to verify a webhook with: run on Node 20+, Deno, Bun or a Worker.\",\n )\n }\n return subtle\n}\n\nfunction fromBase64(text: string) {\n try {\n return Uint8Array.from(atob(text), (char) => char.charCodeAt(0))\n } catch {\n return undefined\n }\n}\n\nfunction concat(head: Uint8Array, tail: Uint8Array) {\n const out = new Uint8Array(head.length + tail.length)\n out.set(head)\n out.set(tail, head.length)\n return out\n}\n","import { Client, type MeterbaseOptions, type RequestOptions } from \"./client.js\"\nimport { MeterbaseError, NotFoundError, TooLateError } from \"./errors.js\"\nimport type { CustomerAllowances as CustomerAllowancesResource } from \"./resources/customer-allowances.js\"\nimport type { CustomerPlan as CustomerPlanResource } from \"./resources/customer-plan.js\"\nimport { Customers as CustomersResource } from \"./resources/customers.js\"\nimport { Meters as MetersResource } from \"./resources/meters.js\"\nimport {\n Plans as PlansResource,\n type PlanAllowances as PlanAllowancesResource,\n} from \"./resources/plans.js\"\nimport type {\n CheckParams,\n CheckResult,\n ReleaseParams,\n ReleaseResult,\n ReserveParams,\n ReserveResponse,\n TrackParams,\n TrackResult,\n WhoAmI,\n} from \"./types.js\"\n\n/**\n * A granted hold, with the two calls that close it. `commit` is `track` under\n * the hold's own id; `release` gives the capacity back.\n */\nexport type Hold = ReserveResponse & {\n allowed: true\n reservation_id: string\n quantity: number\n expires_at: string\n /**\n * Records what the work actually cost and releases the rest. Omit the\n * quantity to record what was held.\n *\n * Warns when it runs after `expires_at`: the hold stopped holding anything\n * at that instant, so the work was no longer protected. That warning is the\n * only feedback there is on an `expires_in_seconds` guessed too short.\n */\n commit(quantity?: number, options?: RequestOptions): Promise<TrackResult>\n /**\n * Gives the hold back. Nothing is recorded.\n *\n * Resolves with `null` rather than throwing when there is nothing left to\n * release — already committed, already released. This is the one call meant\n * to run on the failure path, where throwing would mask the error the\n * caller is already handling, and \"nothing left to release\" is the outcome\n * a release wanted anyway. `meterbase.release` throws the 404, as every\n * other call does.\n */\n release(options?: RequestOptions): Promise<ReleaseResult | null>\n}\n\n/** A refused reserve holds nothing, so it carries no id and no expiry. */\nexport type ReserveRefused = ReserveResponse & {\n allowed: false\n reservation_id?: undefined\n expires_at?: undefined\n}\n\nexport type ReserveResult = Hold | ReserveRefused\n\nexport class Meterbase {\n readonly customers: Customers\n readonly meters: Meters\n readonly plans: Plans\n\n readonly #client: Client\n\n constructor(options: MeterbaseOptions) {\n this.#client = new Client(options)\n this.customers = new CustomersResource(this.#client)\n this.meters = new MetersResource(this.#client)\n this.plans = new PlansResource(this.#client)\n }\n\n /**\n * Asks whether a customer may consume `quantity` of a meter, named by the\n * tenant's own external id and the meter's key. Absence of entitlement is\n * not permission: a customer with no plan and no grant is denied.\n *\n * This is the gate, and the only call that ever refuses. Run it before the\n * work; record the work with `track` afterwards.\n *\n * Two gates answer it, and `allowed` needs both: the customer's capacity has\n * to cover the quantity, and every rate-limit window in force has to admit\n * it. `reason` names the one that said no. `rate_limits` reports each window\n * whether or not it refused, so a caller can ease off as its headroom closes\n * instead of discovering the ceiling by hitting it.\n */\n check(params: CheckParams, options?: RequestOptions): Promise<CheckResult> {\n return this.#client.request({\n ...options,\n method: \"POST\",\n path: \"/v1/check\",\n body: params,\n })\n }\n\n /**\n * Records usage that already happened — the tokens were spent, the image\n * was generated — so it never refuses on capacity. A quantity beyond the\n * customer's capacity is recorded, drives `available` to 0, and the next\n * `check` says no. The answer is a receipt, not a verdict.\n *\n * `idempotency_key` is a UUIDv7, generated when omitted, so retrying this\n * call — the SDK's own retries included — replays the original rather than\n * counting the same work twice. The engine keeps that claim for an hour,\n * which is how long a retry stays recognisable.\n */\n // `async` so that generating the key cannot throw synchronously out of a\n // method that otherwise only ever rejects: one call, one way to fail.\n async track(\n params: TrackParams,\n options?: RequestOptions,\n ): Promise<TrackResult> {\n return this.#keyed(IDEMPOTENCY_WINDOW_MS, params.idempotency_key, (key) =>\n this.#client.request<TrackResult>({\n ...options,\n method: \"POST\",\n path: \"/v1/usage/track\",\n // Fixed before the retry loop is entered: every attempt of this call\n // carries the same key, which is what makes replaying it safe.\n body: { ...params, idempotency_key: key },\n idempotent: true,\n }),\n )\n }\n\n /**\n * Holds capacity for work that cannot be done twice, or refuses. The same\n * decision `check` makes, and then a hold on the capacity until the work\n * is committed, released, or expires.\n *\n * The rule for choosing: can you afford to do the work twice? `check`. No?\n * `reserve`. A reserve costs a transaction where a check costs a cached\n * read, refusals included, so it is not a per-request gate on cheap work.\n *\n * Two concurrent reserves for the same customer and meter cannot both be\n * granted the same capacity; that is the whole point, and it is what\n * `check` → work → `track` could never promise.\n */\n async reserve(\n params: ReserveParams,\n options?: RequestOptions,\n ): Promise<ReserveResult> {\n const response = await this.#keyed(\n RESERVE_WINDOW_MS,\n params.reservation_id,\n (id) =>\n this.#client.request<ReserveResponse>({\n ...options,\n method: \"POST\",\n path: \"/v1/usage/reserve\",\n body: { ...params, reservation_id: id },\n // A retry under the same id finds the hold it already made rather\n // than making a second one.\n idempotent: true,\n }),\n )\n\n return this.#hold(params, response)\n }\n\n /**\n * Gives a hold back: the work did not happen, so nothing is recorded.\n *\n * Throws `NotFoundError` when the id names nothing — committed, released\n * already, or never made, which are one absence with one meaning. Prefer\n * `hold.release()`, which treats that as the success it is.\n */\n release(\n params: ReleaseParams,\n options?: RequestOptions,\n ): Promise<ReleaseResult> {\n return this.#client.request({\n ...options,\n method: \"POST\",\n path: \"/v1/usage/release\",\n body: params,\n })\n }\n\n /** Reports which workspace this key acts for. */\n whoami(options?: RequestOptions): Promise<WhoAmI> {\n return this.#client.request({\n ...options,\n method: \"GET\",\n path: \"/v1/whoami\",\n })\n }\n\n /**\n * Sends a call that carries a caller-minted UUIDv7, minting one when the\n * caller supplied none and re-minting once if this machine's clock put it\n * outside the engine's window.\n *\n * A key the caller supplied is never re-minted: this cannot know whether it\n * names work already recorded, and replacing it could count that work\n * twice.\n */\n async #keyed<T>(\n window: number,\n supplied: string | undefined,\n send: (key: string) => Promise<T>,\n ): Promise<T> {\n if (supplied !== undefined) return send(supplied)\n\n const key = idempotencyKey(this.#client.now())\n const startedAt = Date.now()\n\n try {\n return await send(key)\n } catch (error) {\n // The only failure this can fix by itself: a clock that disagrees with\n // the engine's.\n if (!(error instanceof TooLateError) || error.serverTime === undefined) {\n throw error\n }\n\n // Re-minting is safe only if no attempt under the old key can have\n // landed. `send` retries internally, so this 422 may have come from a\n // later attempt while an earlier one succeeded. If the key was already\n // outside the window when the call began, every attempt was refused.\n const elapsed = Date.now() - startedAt\n const serverAtStart = error.serverTime.getTime() - elapsed\n if (Math.abs(serverAtStart - mintedAtMs(key)) <= window) throw error\n\n this.#client.observeServerTime(error.serverTime)\n\n return await send(idempotencyKey(this.#client.now()))\n }\n }\n\n /** Puts `commit` and `release` on a granted hold; a refusal is left as it is. */\n #hold(params: ReserveParams, response: ReserveResponse): ReserveResult {\n if (!response.allowed) return response as ReserveRefused\n\n const id = response.reservation_id\n const expiresAt = response.expires_at\n\n // A grant without them is not a hold this can hand back: `allowed` would\n // narrow to the arm that carries `commit`, and the caller would find it\n // missing at the one moment they are relying on it. Louder here.\n if (id === undefined || expiresAt === undefined) {\n throw new MeterbaseError(\n \"The engine granted a reservation without an id or an expiry, so \" +\n \"there is no hold to commit or release. The capacity it set aside \" +\n \"comes back on its own.\",\n )\n }\n\n const expiresAtMs = Date.parse(expiresAt)\n\n return {\n ...response,\n allowed: true,\n reservation_id: id,\n quantity: response.quantity ?? params.quantity ?? 1,\n expires_at: expiresAt,\n\n commit: (quantity, commitOptions) => {\n if (\n Number.isFinite(expiresAtMs) &&\n this.#client.now() > expiresAtMs &&\n typeof globalThis.console?.warn === \"function\"\n ) {\n globalThis.console.warn(\n `Meterbase: committing reservation ${id} after it expired at ` +\n `${expiresAt}. The event is still recorded, but the capacity ` +\n `was no longer held — raise expires_in_seconds for this work.`,\n )\n }\n\n return this.track(\n {\n customer_id: params.customer_id,\n meter_id: params.meter_id,\n quantity,\n // The hold's own id, so the track commits it rather than\n // recording a second event beside it.\n idempotency_key: id,\n },\n commitOptions,\n )\n },\n\n release: async (releaseOptions) => {\n try {\n return await this.release({ reservation_id: id }, releaseOptions)\n } catch (error) {\n if (error instanceof NotFoundError) return null\n throw error\n }\n },\n }\n }\n}\n\n/**\n * The resource namespaces, type-only: none is constructible without the\n * unexported Client. Instance types rather than `export type { Customers }`,\n * which the declaration bundler re-emits as a value export — promising a\n * runtime binding the bundle never has.\n */\nexport type CustomerAllowances = InstanceType<typeof CustomerAllowancesResource>\nexport type CustomerPlan = InstanceType<typeof CustomerPlanResource>\nexport type Customers = InstanceType<typeof CustomersResource>\nexport type Meters = InstanceType<typeof MetersResource>\nexport type PlanAllowances = InstanceType<typeof PlanAllowancesResource>\nexport type Plans = InstanceType<typeof PlansResource>\nexport type { MeterbaseOptions, RequestOptions }\nexport * from \"./errors.js\"\nexport type * from \"./types.js\"\nexport { verifyWebhook } from \"./webhooks.js\"\nexport type { VerifyWebhookParams, WebhookHeaders } from \"./webhooks.js\"\n\n/**\n * A UUIDv7: 48 bits of Unix milliseconds, then the version and variant, then\n * 74 random bits. `crypto.randomUUID()` mints a v4, which carries no time, so\n * this builds one from random bytes.\n *\n * `atMs` is the engine's clock as the client knows it, not this machine's: a\n * device an hour out would otherwise mint keys the engine refuses.\n */\n/** How far the engine lets a key's timestamp sit from its own clock. */\nconst IDEMPOTENCY_WINDOW_MS = 60 * 60 * 1000\n\n/**\n * The same guard for a reservation id, and narrower on purpose: the id is\n * minted at the call, and the engine has to leave room to commit the hold it\n * names long after.\n */\nconst RESERVE_WINDOW_MS = 30 * 60 * 1000\n\n/** The millisecond a v7 carries in its first 48 bits. */\nfunction mintedAtMs(key: string): number {\n return Number.parseInt(key.replace(/-/g, \"\").slice(0, 12), 16)\n}\n\nfunction idempotencyKey(atMs: number): string {\n // Structurally, not as `Crypto`: that lib type is the DOM's, and this\n // compiles without it so the SDK stays as portable as `fetch` is.\n const webcrypto = globalThis.crypto as\n { getRandomValues?: (array: Uint8Array) => Uint8Array } | undefined\n\n if (typeof webcrypto?.getRandomValues !== \"function\") {\n throw new MeterbaseError(\n \"No crypto to generate an idempotency key with: pass `idempotency_key` \" +\n \"yourself (a UUIDv7), or run somewhere `crypto.getRandomValues` exists.\",\n )\n }\n\n const bytes = webcrypto.getRandomValues(new Uint8Array(16))\n\n // Big-endian ms in the first six bytes, split in two so the arithmetic\n // stays 32-bit safe without BigInt.\n const ms = Math.max(0, Math.trunc(atMs))\n const high = Math.floor(ms / 0x1_0000_0000) // the top 16 bits of 48\n const low = ms >>> 0 // the bottom 32\n bytes[0] = (high >>> 8) & 0xff\n bytes[1] = high & 0xff\n bytes[2] = (low >>> 24) & 0xff\n bytes[3] = (low >>> 16) & 0xff\n bytes[4] = (low >>> 8) & 0xff\n bytes[5] = low & 0xff\n\n bytes[6] = (bytes[6]! & 0x0f) | 0x70 // version 7\n bytes[8] = (bytes[8]! & 0x3f) | 0x80 // variant 10\n\n const hex = Array.from(bytes, (b) => b.toString(16).padStart(2, \"0\")).join(\"\")\n\n return [\n hex.slice(0, 8),\n hex.slice(8, 12),\n hex.slice(12, 16),\n hex.slice(16, 20),\n hex.slice(20),\n ].join(\"-\")\n}\n"]}
|