@usagetap/sdk 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -385,7 +385,8 @@ const { begin, end, vendor, endUsage } = envelope.data;
385
385
 
386
386
  Key exports from `@usagetap/sdk`:
387
387
 
388
- - `UsageTapClient` – minimal HTTP client for `call_begin` and `call_end`.
388
+ - `UsageTapClient` – minimal HTTP client for `call_begin`, `call_end`, and `checkUsage`.
389
+ - `checkUsage` – lightweight method to query current usage status without creating a call session.
389
390
  - `wrapOpenAI` – wraps an OpenAI client instance with automatic begin/end handling.
390
391
  - `wrapFetch` – wraps a fetch function to automatically instrument OpenAI API calls (minimal integration).
391
392
  - `withUsage` / `withUsageMiddleware` – Express middleware for server-side usage tracking (requires `express` peer dependency).
@@ -396,6 +397,21 @@ Key exports from `@usagetap/sdk`:
396
397
 
397
398
  All helpers are designed for server runtimes. Use `UsageTapClient` with `allowBrowser: true` only for sandbox/test scenarios.
398
399
 
400
+ ### Check usage without creating a call
401
+
402
+ When you need to display current quota status, plan details, or remaining balances without tracking a vendor call, use `checkUsage()`:
403
+
404
+ ```ts
405
+ const usageStatus = await usageTap.checkUsage({ customerId: "cust_123" });
406
+
407
+ console.log("Meters:", usageStatus.data.meters);
408
+ console.log("Allowed:", usageStatus.data.allowed);
409
+ console.log("Plan:", usageStatus.data.plan);
410
+ console.log("Balances:", usageStatus.data.balances);
411
+ ```
412
+
413
+ This returns the same rich usage snapshot as `call_begin` (meters, entitlements, subscription details, plan info, balances) but without creating a call record. Use this for dashboard widgets, pre-flight checks, or displaying quota status to users.
414
+
399
415
  ## Response envelope (canonical only)
400
416
 
401
417
  UsageTap responds exclusively with the canonical `{ result, data, correlationId }` envelope for every endpoint. The SDK automatically sends `Accept: application/vnd.usagetap.v1+json`, parses the envelope, and returns strongly typed data structures. Transitional `raw` payloads and the `normalize*` helpers have been removed—`response.data` already contains the canonical shape you should persist or render.
@@ -1,2 +1,2 @@
1
1
  import 'openai';
2
- export { N as NodeResponseLike, O as OpenAIAdapter, b as OpenAIAdapterInit, d as OpenAIInvokeParams, e as OpenAIInvokeResult, Y as OpenAIRequestContext, Z as OpenAIStreamCallResult, f as OpenAIStreamParams, g as OpenAIStreamResult, S as StreamMode, l as StreamOpenAIRouteOptions, h as StreamToResponseOptions, _ as UsageTapStream, i as WrapOpenAICallOptions, W as WrapOpenAIContext, a as WrapOpenAIOptions, j as WrapOpenAIResponseCallOptions, k as WrappedOpenAI, c as createOpenAIAdapter, p as pipeToResponse, s as streamOpenAIRoute, t as toNextResponse, w as wrapOpenAI } from '../openai-CKyw08rB.cjs';
2
+ export { N as NodeResponseLike, O as OpenAIAdapter, b as OpenAIAdapterInit, d as OpenAIInvokeParams, e as OpenAIInvokeResult, $ as OpenAIRequestContext, a0 as OpenAIStreamCallResult, f as OpenAIStreamParams, g as OpenAIStreamResult, S as StreamMode, l as StreamOpenAIRouteOptions, h as StreamToResponseOptions, a1 as UsageTapStream, i as WrapOpenAICallOptions, W as WrapOpenAIContext, a as WrapOpenAIOptions, j as WrapOpenAIResponseCallOptions, k as WrappedOpenAI, c as createOpenAIAdapter, p as pipeToResponse, s as streamOpenAIRoute, t as toNextResponse, w as wrapOpenAI } from '../openai-CeptbEGH.cjs';
@@ -1,2 +1,2 @@
1
1
  import 'openai';
2
- export { N as NodeResponseLike, O as OpenAIAdapter, b as OpenAIAdapterInit, d as OpenAIInvokeParams, e as OpenAIInvokeResult, Y as OpenAIRequestContext, Z as OpenAIStreamCallResult, f as OpenAIStreamParams, g as OpenAIStreamResult, S as StreamMode, l as StreamOpenAIRouteOptions, h as StreamToResponseOptions, _ as UsageTapStream, i as WrapOpenAICallOptions, W as WrapOpenAIContext, a as WrapOpenAIOptions, j as WrapOpenAIResponseCallOptions, k as WrappedOpenAI, c as createOpenAIAdapter, p as pipeToResponse, s as streamOpenAIRoute, t as toNextResponse, w as wrapOpenAI } from '../openai-CKyw08rB.js';
2
+ export { N as NodeResponseLike, O as OpenAIAdapter, b as OpenAIAdapterInit, d as OpenAIInvokeParams, e as OpenAIInvokeResult, $ as OpenAIRequestContext, a0 as OpenAIStreamCallResult, f as OpenAIStreamParams, g as OpenAIStreamResult, S as StreamMode, l as StreamOpenAIRouteOptions, h as StreamToResponseOptions, a1 as UsageTapStream, i as WrapOpenAICallOptions, W as WrapOpenAIContext, a as WrapOpenAIOptions, j as WrapOpenAIResponseCallOptions, k as WrappedOpenAI, c as createOpenAIAdapter, p as pipeToResponse, s as streamOpenAIRoute, t as toNextResponse, w as wrapOpenAI } from '../openai-CeptbEGH.js';
@@ -1,5 +1,5 @@
1
1
  import OpenAI from 'openai';
2
- import { U as UsageTapClient, O as OpenAIAdapter } from '../openai-CKyw08rB.cjs';
2
+ import { U as UsageTapClient, O as OpenAIAdapter } from '../openai-CeptbEGH.cjs';
3
3
 
4
4
  interface OpenRouterAdapterInit {
5
5
  client: OpenAI;
@@ -1,5 +1,5 @@
1
1
  import OpenAI from 'openai';
2
- import { U as UsageTapClient, O as OpenAIAdapter } from '../openai-CKyw08rB.js';
2
+ import { U as UsageTapClient, O as OpenAIAdapter } from '../openai-CeptbEGH.js';
3
3
 
4
4
  interface OpenRouterAdapterInit {
5
5
  client: OpenAI;
package/dist/index.cjs CHANGED
@@ -118,6 +118,7 @@ async function runWithRetry(operation, options, shouldRetry, onSchedule, signal)
118
118
  // src/client.ts
119
119
  var CALL_BEGIN_PATH = "call_begin";
120
120
  var CALL_END_PATH = "call_end";
121
+ var CHECK_USAGE_PATH = "customers/{customerId}/usage";
121
122
  var AUTH_HEADER = "authorization";
122
123
  var API_KEY_HEADER = "x-api-key";
123
124
  var CORRELATION_HEADER = "x-usage-correlation-id";
@@ -125,7 +126,7 @@ var IDEMPOTENCY_HEADER = "idempotency-key";
125
126
  var SDK_HEADER = "x-usage-sdk";
126
127
  var USER_AGENT = "UsageTapClient";
127
128
  var CANONICAL_MEDIA_TYPE = "application/vnd.usagetap.v1+json";
128
- var SDK_VERSION = "0.1.0" ;
129
+ var SDK_VERSION = "0.2.0" ;
129
130
  var HAS_WINDOW = typeof globalThis !== "undefined" && typeof globalThis.window !== "undefined";
130
131
  var UsageTapClient = class {
131
132
  apiKey;
@@ -219,6 +220,23 @@ var UsageTapClient = class {
219
220
  );
220
221
  return response;
221
222
  }
223
+ async checkUsage(request, options = {}) {
224
+ if (!request?.customerId) {
225
+ throw new UsageTapError(
226
+ "USAGETAP_BAD_REQUEST",
227
+ "checkUsage requires customerId"
228
+ );
229
+ }
230
+ const path = CHECK_USAGE_PATH.replace(
231
+ "{customerId}",
232
+ encodeURIComponent(request.customerId)
233
+ );
234
+ const response = await this.requestGet(
235
+ path,
236
+ options
237
+ );
238
+ return response;
239
+ }
222
240
  async withUsage(beginRequest, handler, options = {}) {
223
241
  const idempotencyKey = beginRequest.idempotency ?? (this.autoIdempotency ? this.idempotencyGenerator() : void 0);
224
242
  const beginPayload = idempotencyKey ? { ...beginRequest, idempotency: idempotencyKey } : { ...beginRequest };
@@ -338,6 +356,62 @@ var UsageTapClient = class {
338
356
  throw error;
339
357
  });
340
358
  }
359
+ async requestGet(path, options) {
360
+ const url = new URL(path, this.baseUrl).toString();
361
+ const headers = this.composeHeaders(void 0, options);
362
+ const resolvedRetry = resolveRetryOptions(
363
+ this.retryDefaults,
364
+ options.retries
365
+ );
366
+ const startTime = () => typeof performance !== "undefined" ? performance.now() : Date.now();
367
+ return runWithRetry(
368
+ async (attempt) => {
369
+ const startedAt = startTime();
370
+ this.log({
371
+ event: "request:start",
372
+ path,
373
+ attempt,
374
+ correlationId: options.correlationId
375
+ });
376
+ const response = await this.performFetch({
377
+ url,
378
+ method: "GET",
379
+ headers,
380
+ signal: options.signal
381
+ });
382
+ this.log({
383
+ event: "request:success",
384
+ path,
385
+ attempt,
386
+ correlationId: response.correlationId,
387
+ elapsedMs: startTime() - startedAt
388
+ });
389
+ return response;
390
+ },
391
+ resolvedRetry,
392
+ (error) => this.shouldRetry(error),
393
+ (attempt, delayMs, error) => {
394
+ this.log({
395
+ event: "retry:scheduled",
396
+ path,
397
+ attempt,
398
+ correlationId: options.correlationId,
399
+ error,
400
+ elapsedMs: delayMs
401
+ });
402
+ },
403
+ options.signal
404
+ ).catch((error) => {
405
+ this.log({
406
+ event: "retry:exhausted",
407
+ path,
408
+ attempt: resolvedRetry.maxAttempts,
409
+ correlationId: options.correlationId,
410
+ error
411
+ });
412
+ throw error;
413
+ });
414
+ }
341
415
  async performFetch(init) {
342
416
  let response;
343
417
  try {