priceos 0.0.25 → 0.0.30

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/dist/index.cjs CHANGED
@@ -37,6 +37,141 @@ module.exports = __toCommonJS(index_exports);
37
37
 
38
38
  // src/client.ts
39
39
  var import_openapi_fetch = __toESM(require("openapi-fetch"), 1);
40
+ var RATE_LIMIT_STATUS = 429;
41
+ var MAX_RETRIES = 4;
42
+ var BASE_DELAY_MS = 250;
43
+ var BACKOFF_MULTIPLIER = 2;
44
+ var JITTER_MS = 250;
45
+ var RETRY_DELAY_CAP_MS = 5e3;
46
+ var REQUEST_TIMEOUT_MS = 2e4;
47
+ var LOG_LEVELS = {
48
+ none: 0,
49
+ error: 1,
50
+ warning: 2,
51
+ info: 3,
52
+ debug: 4
53
+ };
54
+ var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
55
+ var getRetryDelayMs = (retryCount) => {
56
+ const backoff = BASE_DELAY_MS * Math.pow(BACKOFF_MULTIPLIER, retryCount - 1);
57
+ const jitter = Math.random() * JITTER_MS;
58
+ return Math.min(RETRY_DELAY_CAP_MS, backoff + jitter);
59
+ };
60
+ var createLogger = (logLevel) => {
61
+ const shouldLog = (level) => logLevel !== "none" && LOG_LEVELS[level] <= LOG_LEVELS[logLevel];
62
+ const write = (level, message, details) => {
63
+ if (!shouldLog(level)) return;
64
+ const prefix = `[PriceOS] ${level.toUpperCase()}: ${message}`;
65
+ const payload = details && Object.keys(details).length > 0 ? details : void 0;
66
+ switch (level) {
67
+ case "error":
68
+ payload ? console.error(prefix, payload) : console.error(prefix);
69
+ return;
70
+ case "warning":
71
+ payload ? console.warn(prefix, payload) : console.warn(prefix);
72
+ return;
73
+ case "info":
74
+ payload ? console.info(prefix, payload) : console.info(prefix);
75
+ return;
76
+ case "debug":
77
+ payload ? console.debug(prefix, payload) : console.debug(prefix);
78
+ return;
79
+ }
80
+ };
81
+ return {
82
+ error: (message, details) => write("error", message, details),
83
+ warning: (message, details) => write("warning", message, details),
84
+ info: (message, details) => write("info", message, details),
85
+ debug: (message, details) => write("debug", message, details)
86
+ };
87
+ };
88
+ var getUpstreamSignal = (input, init) => {
89
+ if (init?.signal) return init.signal;
90
+ if (typeof Request !== "undefined" && input instanceof Request) return input.signal;
91
+ return void 0;
92
+ };
93
+ var getRequestDetails = (input, init) => {
94
+ const method = init?.method ?? (typeof Request !== "undefined" && input instanceof Request ? input.method : "GET");
95
+ const url = typeof input === "string" ? input : input instanceof URL ? input.toString() : input.url;
96
+ return { method, url };
97
+ };
98
+ var getErrorMessage = (error) => {
99
+ const maybeError = error;
100
+ if (maybeError && typeof maybeError.error === "string") return maybeError.error;
101
+ return "Request failed";
102
+ };
103
+ var throwRequestError = (log, error, response, context) => {
104
+ log.error("Request failed", { context, status: response?.status, error });
105
+ throw new PriceOSError(getErrorMessage(error), { status: response?.status, details: error });
106
+ };
107
+ var createRetryingFetch = (baseFetch, log) => {
108
+ return async (input, init) => {
109
+ const { method, url } = getRequestDetails(input, init);
110
+ let attempt = 0;
111
+ while (true) {
112
+ log.debug("Request attempt", { method, url, attempt: attempt + 1, maxRetries: MAX_RETRIES });
113
+ const controller = new AbortController();
114
+ const timeoutId = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);
115
+ const upstreamSignal = getUpstreamSignal(input, init);
116
+ let removeAbortListener = null;
117
+ if (upstreamSignal) {
118
+ if (upstreamSignal.aborted) {
119
+ controller.abort();
120
+ } else {
121
+ const onAbort = () => controller.abort();
122
+ upstreamSignal.addEventListener("abort", onAbort);
123
+ removeAbortListener = () => upstreamSignal.removeEventListener("abort", onAbort);
124
+ }
125
+ }
126
+ try {
127
+ const response = await baseFetch(input, { ...init, signal: controller.signal });
128
+ if (response.status !== RATE_LIMIT_STATUS) return response;
129
+ const retryAfter = response.headers.get("retry-after") ?? void 0;
130
+ log.warning("Rate limit hit (429)", {
131
+ method,
132
+ url,
133
+ attempt: attempt + 1,
134
+ maxRetries: MAX_RETRIES,
135
+ retryAfter
136
+ });
137
+ if (attempt >= MAX_RETRIES) {
138
+ log.error("Rate limit retries exhausted", { method, url, attempts: attempt + 1 });
139
+ return response;
140
+ }
141
+ const delayMs = getRetryDelayMs(attempt + 1);
142
+ log.info("Waiting to retry after rate limit", {
143
+ method,
144
+ url,
145
+ delayMs,
146
+ nextAttempt: attempt + 2,
147
+ maxRetries: MAX_RETRIES
148
+ });
149
+ await sleep(delayMs);
150
+ attempt += 1;
151
+ } catch (error) {
152
+ if (controller.signal.aborted) {
153
+ const abortedByCaller = upstreamSignal?.aborted ?? false;
154
+ if (abortedByCaller) {
155
+ log.warning("Request aborted by caller", { method, url, attempt: attempt + 1 });
156
+ } else {
157
+ log.error("Request timed out", {
158
+ method,
159
+ url,
160
+ attempt: attempt + 1,
161
+ timeoutMs: REQUEST_TIMEOUT_MS
162
+ });
163
+ }
164
+ } else {
165
+ log.error("Request failed", { method, url, attempt: attempt + 1, error });
166
+ }
167
+ throw error;
168
+ } finally {
169
+ clearTimeout(timeoutId);
170
+ removeAbortListener?.();
171
+ }
172
+ }
173
+ };
174
+ };
40
175
  var PriceOSError = class extends Error {
41
176
  status;
42
177
  details;
@@ -50,18 +185,21 @@ var PriceOSError = class extends Error {
50
185
  var PriceOS = class {
51
186
  client;
52
187
  header;
188
+ log;
53
189
  customers;
54
190
  features;
55
191
  usage;
56
192
  constructor(apiKey, opts = {}) {
57
- const baseUrl = opts.baseUrl ?? "https://api.priceos.com";
193
+ const logLevel = opts.logLevel ?? "none";
194
+ this.log = createLogger(logLevel);
195
+ const baseUrl = "https://api.priceos.com";
58
196
  this.header = { "x-api-key": apiKey };
197
+ const fetchWithRetry = createRetryingFetch(fetch, this.log);
59
198
  this.client = (0, import_openapi_fetch.default)({
60
199
  baseUrl,
61
- fetch: opts.fetch,
200
+ fetch: fetchWithRetry,
62
201
  headers: {
63
- "x-api-key": apiKey,
64
- ...opts.userAgent ? { "user-agent": opts.userAgent } : {}
202
+ "x-api-key": apiKey
65
203
  }
66
204
  });
67
205
  this.customers = {
@@ -69,8 +207,7 @@ var PriceOS = class {
69
207
  const { data, error, response } = await this.client.GET("/v1/customer", {
70
208
  params: { query: { customerId }, header: this.header }
71
209
  });
72
- if (error)
73
- throw new PriceOSError(error.error ?? "Request failed", { status: response?.status, details: error });
210
+ if (error) throwRequestError(this.log, error, response, "GET /v1/customer");
74
211
  return data ?? null;
75
212
  },
76
213
  identify: async (input) => {
@@ -78,8 +215,7 @@ var PriceOS = class {
78
215
  params: { header: this.header },
79
216
  body: input
80
217
  });
81
- if (error)
82
- throw new PriceOSError(error.error ?? "Request failed", { status: response?.status, details: error });
218
+ if (error) throwRequestError(this.log, error, response, "POST /v1/customer/identify");
83
219
  return data ?? null;
84
220
  },
85
221
  create: async (input) => {
@@ -87,8 +223,7 @@ var PriceOS = class {
87
223
  params: { header: this.header },
88
224
  body: input
89
225
  });
90
- if (error)
91
- throw new PriceOSError(error.error ?? "Request failed", { status: response?.status, details: error });
226
+ if (error) throwRequestError(this.log, error, response, "POST /v1/customer");
92
227
  return data;
93
228
  },
94
229
  update: async (input) => {
@@ -96,16 +231,14 @@ var PriceOS = class {
96
231
  params: { header: this.header },
97
232
  body: input
98
233
  });
99
- if (error)
100
- throw new PriceOSError(error.error ?? "Request failed", { status: response?.status, details: error });
234
+ if (error) throwRequestError(this.log, error, response, "PUT /v1/customer");
101
235
  return data;
102
236
  },
103
237
  delete: async (customerId) => {
104
238
  const { data, error, response } = await this.client.DELETE("/v1/customer", {
105
239
  params: { query: { customerId }, header: this.header }
106
240
  });
107
- if (error)
108
- throw new PriceOSError(error.error ?? "Request failed", { status: response?.status, details: error });
241
+ if (error) throwRequestError(this.log, error, response, "DELETE /v1/customer");
109
242
  return data;
110
243
  }
111
244
  };
@@ -114,8 +247,7 @@ var PriceOS = class {
114
247
  const { data, error, response } = await this.client.GET("/v1/feature-access", {
115
248
  params: { query: { customerId }, header: this.header }
116
249
  });
117
- if (error)
118
- throw new PriceOSError(error.error ?? "Request failed", { status: response?.status, details: error });
250
+ if (error) throwRequestError(this.log, error, response, "GET /v1/feature-access");
119
251
  return data;
120
252
  }
121
253
  };
@@ -125,8 +257,15 @@ var PriceOS = class {
125
257
  params: { header: this.header },
126
258
  body: input
127
259
  });
128
- if (error)
129
- throw new PriceOSError(error.error ?? "Request failed", { status: response?.status, details: error });
260
+ if (error) throwRequestError(this.log, error, response, "POST /v1/usage");
261
+ return data;
262
+ },
263
+ listEvents: async (input) => {
264
+ const { data, error, response } = await this.client.POST("/v1/usage/events", {
265
+ params: { header: this.header },
266
+ body: input
267
+ });
268
+ if (error) throwRequestError(this.log, error, response, "POST /v1/usage/events");
130
269
  return data;
131
270
  }
132
271
  };
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/client.ts"],"sourcesContent":["export { PriceOS, PriceOSError } from \"./client\";\nexport type {\n PriceOSClientOptions,\n PriceOSCustomersClient,\n PriceOSFeaturesClient,\n PriceOSHttpClient,\n PriceOSUsageClient,\n} from \"./client\";\nexport type {\n CreateCustomerRequest,\n CreateCustomerResponse,\n DeleteCustomerRequest,\n DeleteCustomerResponse,\n GetCustomerResponse,\n GetFeatureAccessResponse,\n IdentifyCustomerBody,\n IdentifyCustomerResponse,\n LimitFeatureKeyFromAccessMap,\n TrackUsageBody,\n TrackUsageResponse,\n UpdateCustomerBody,\n UpdateCustomerResponse,\n} from \"./types\";\n","import createClient from \"openapi-fetch\";\nimport type { Client } from \"openapi-fetch\";\nimport type { paths } from \"./gen/openapi\";\nimport {\n CreateCustomerRequest,\n CreateCustomerResponse,\n DeleteCustomerResponse,\n GetCustomerResponse,\n GetFeatureAccessResponse,\n IdentifyCustomerBody,\n IdentifyCustomerResponse,\n LimitFeatureKeyFromAccessMap,\n TrackUsageBody,\n TrackUsageResponse,\n UpdateCustomerBody,\n UpdateCustomerResponse,\n} from \"./types\";\n\n// --- Public options ---\nexport type PriceOSClientOptions = {\n baseUrl?: string;\n fetch?: typeof fetch;\n userAgent?: string;\n};\n\nexport type PriceOSCustomersClient<TFeatureAccessMap = GetFeatureAccessResponse> = {\n get(customerId: string): Promise<GetCustomerResponse<TFeatureAccessMap> | null>;\n identify(input: IdentifyCustomerBody): Promise<IdentifyCustomerResponse<TFeatureAccessMap> | null>;\n create(input: CreateCustomerRequest): Promise<CreateCustomerResponse<TFeatureAccessMap>>;\n update(input: UpdateCustomerBody): Promise<UpdateCustomerResponse<TFeatureAccessMap>>;\n delete(customerId: string): Promise<DeleteCustomerResponse>;\n};\n\nexport type PriceOSFeaturesClient<TFeatureAccessMap = GetFeatureAccessResponse> = {\n getAccess(customerId: string): Promise<TFeatureAccessMap>;\n};\n\nexport type PriceOSUsageClient<TFeatureAccessMap = GetFeatureAccessResponse> = {\n track(\n input: TrackUsageBody<LimitFeatureKeyFromAccessMap<TFeatureAccessMap>>\n ): Promise<TrackUsageResponse>;\n};\n\n// --- Public SDK surface type ---\nexport type PriceOSHttpClient<TFeatureAccessMap = GetFeatureAccessResponse> = {\n customers: PriceOSCustomersClient<TFeatureAccessMap>;\n features: PriceOSFeaturesClient<TFeatureAccessMap>;\n usage: PriceOSUsageClient<TFeatureAccessMap>;\n};\n\nexport class PriceOSError extends Error {\n status?: number;\n details?: unknown;\n\n constructor(message: string, opts?: { status?: number; details?: unknown }) {\n super(message);\n this.name = \"PriceOSError\";\n this.status = opts?.status;\n this.details = opts?.details;\n }\n}\n\nexport class PriceOS<TFeatureAccessMap = GetFeatureAccessResponse>\n implements PriceOSHttpClient<TFeatureAccessMap>\n{\n private client: Client<paths>;\n private header: { \"x-api-key\": string };\n customers: PriceOSCustomersClient<TFeatureAccessMap>;\n features: PriceOSFeaturesClient<TFeatureAccessMap>;\n usage: PriceOSUsageClient<TFeatureAccessMap>;\n\n constructor(apiKey: string, opts: PriceOSClientOptions = {}) {\n const baseUrl = opts.baseUrl ?? \"https://api.priceos.com\";\n this.header = { \"x-api-key\": apiKey };\n this.client = createClient<paths>({\n baseUrl,\n fetch: opts.fetch,\n headers: {\n \"x-api-key\": apiKey,\n ...(opts.userAgent ? { \"user-agent\": opts.userAgent } : {}),\n },\n });\n\n this.customers = {\n get: async (customerId: string): Promise<GetCustomerResponse<TFeatureAccessMap> | null> => {\n const { data, error, response } = await this.client.GET(\"/v1/customer\", {\n params: { query: { customerId }, header: this.header },\n });\n if (error)\n throw new PriceOSError(error.error ?? \"Request failed\", { status: response?.status, details: error });\n return (data ?? null) as GetCustomerResponse<TFeatureAccessMap> | null;\n },\n identify: async (\n input: IdentifyCustomerBody\n ): Promise<IdentifyCustomerResponse<TFeatureAccessMap> | null> => {\n const { data, error, response } = await this.client.POST(\"/v1/customer/identify\", {\n params: { header: this.header },\n body: input,\n });\n if (error)\n throw new PriceOSError(error.error ?? \"Request failed\", { status: response?.status, details: error });\n return (data ?? null) as IdentifyCustomerResponse<TFeatureAccessMap> | null;\n },\n create: async (input: CreateCustomerRequest): Promise<CreateCustomerResponse<TFeatureAccessMap>> => {\n const { data, error, response } = await this.client.POST(\"/v1/customer\", {\n params: { header: this.header },\n body: input,\n });\n if (error)\n throw new PriceOSError(error.error ?? \"Request failed\", { status: response?.status, details: error });\n return data! as CreateCustomerResponse<TFeatureAccessMap>;\n },\n update: async (input: UpdateCustomerBody): Promise<UpdateCustomerResponse<TFeatureAccessMap>> => {\n const { data, error, response } = await this.client.PUT(\"/v1/customer\", {\n params: { header: this.header },\n body: input,\n });\n if (error)\n throw new PriceOSError(error.error ?? \"Request failed\", { status: response?.status, details: error });\n return data! as UpdateCustomerResponse<TFeatureAccessMap>;\n },\n delete: async (customerId: string): Promise<DeleteCustomerResponse> => {\n const { data, error, response } = await this.client.DELETE(\"/v1/customer\", {\n params: { query: { customerId }, header: this.header },\n });\n if (error)\n throw new PriceOSError(error.error ?? \"Request failed\", { status: response?.status, details: error });\n return data! as DeleteCustomerResponse;\n },\n };\n\n this.features = {\n getAccess: async (customerId: string): Promise<TFeatureAccessMap> => {\n const { data, error, response } = await this.client.GET(\"/v1/feature-access\", {\n params: { query: { customerId }, header: this.header },\n });\n if (error)\n throw new PriceOSError(error.error ?? \"Request failed\", { status: response?.status, details: error });\n return data! as TFeatureAccessMap;\n },\n };\n\n this.usage = {\n track: async (\n input: TrackUsageBody<LimitFeatureKeyFromAccessMap<TFeatureAccessMap>>\n ): Promise<TrackUsageResponse> => {\n const { data, error, response } = await this.client.POST(\"/v1/usage\", {\n params: { header: this.header },\n body: input,\n });\n if (error)\n throw new PriceOSError(error.error ?? \"Request failed\", { status: response?.status, details: error });\n return data!;\n },\n };\n }\n}\n"],"mappings":"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","names":["createClient"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/client.ts"],"sourcesContent":["export { PriceOS, PriceOSError } from \"./client\";\nexport type {\n PriceOSClientOptions,\n PriceOSLogLevel,\n PriceOSCustomersClient,\n PriceOSFeaturesClient,\n PriceOSHttpClient,\n PriceOSUsageClient,\n} from \"./client\";\nexport type {\n CreateCustomerRequest,\n CreateCustomerResponse,\n DeleteCustomerRequest,\n DeleteCustomerResponse,\n GetCustomerResponse,\n GetFeatureAccessResponse,\n IdentifyCustomerBody,\n IdentifyCustomerResponse,\n LimitFeatureKeyFromAccessMap,\n ListUsageEventsBody,\n ListUsageEventsResponse,\n UsageEvent,\n TrackUsageBody,\n TrackUsageResponse,\n UpdateCustomerBody,\n UpdateCustomerResponse,\n} from \"./types\";\n","import createClient from \"openapi-fetch\";\nimport type { Client } from \"openapi-fetch\";\nimport type { paths } from \"./gen/openapi\";\nimport {\n CreateCustomerRequest,\n CreateCustomerResponse,\n DeleteCustomerResponse,\n GetCustomerResponse,\n GetFeatureAccessResponse,\n IdentifyCustomerBody,\n IdentifyCustomerResponse,\n LimitFeatureKeyFromAccessMap,\n ListUsageEventsBody,\n ListUsageEventsResponse,\n TrackUsageBody,\n TrackUsageResponse,\n UpdateCustomerBody,\n UpdateCustomerResponse,\n} from \"./types\";\n\nexport type PriceOSLogLevel = \"none\" | \"error\" | \"warning\" | \"info\" | \"debug\";\n\n// --- Public options ---\nexport type PriceOSClientOptions = {\n logLevel?: PriceOSLogLevel;\n};\n\nconst RATE_LIMIT_STATUS = 429;\nconst MAX_RETRIES = 4;\nconst BASE_DELAY_MS = 250;\nconst BACKOFF_MULTIPLIER = 2;\nconst JITTER_MS = 250;\nconst RETRY_DELAY_CAP_MS = 5_000;\nconst REQUEST_TIMEOUT_MS = 20_000;\n\nconst LOG_LEVELS: Record<PriceOSLogLevel, number> = {\n none: 0,\n error: 1,\n warning: 2,\n info: 3,\n debug: 4,\n};\n\ntype Logger = {\n error: (message: string, details?: Record<string, unknown>) => void;\n warning: (message: string, details?: Record<string, unknown>) => void;\n info: (message: string, details?: Record<string, unknown>) => void;\n debug: (message: string, details?: Record<string, unknown>) => void;\n};\n\nconst sleep = (ms: number): Promise<void> => new Promise((resolve) => setTimeout(resolve, ms));\n\nconst getRetryDelayMs = (retryCount: number): number => {\n const backoff = BASE_DELAY_MS * Math.pow(BACKOFF_MULTIPLIER, retryCount - 1);\n const jitter = Math.random() * JITTER_MS;\n return Math.min(RETRY_DELAY_CAP_MS, backoff + jitter);\n};\n\nconst createLogger = (logLevel: PriceOSLogLevel): Logger => {\n const shouldLog = (level: PriceOSLogLevel): boolean =>\n logLevel !== \"none\" && LOG_LEVELS[level] <= LOG_LEVELS[logLevel];\n\n const write = (\n level: PriceOSLogLevel,\n message: string,\n details?: Record<string, unknown>\n ): void => {\n if (!shouldLog(level)) return;\n const prefix = `[PriceOS] ${level.toUpperCase()}: ${message}`;\n const payload = details && Object.keys(details).length > 0 ? details : undefined;\n\n switch (level) {\n case \"error\":\n payload ? console.error(prefix, payload) : console.error(prefix);\n return;\n case \"warning\":\n payload ? console.warn(prefix, payload) : console.warn(prefix);\n return;\n case \"info\":\n payload ? console.info(prefix, payload) : console.info(prefix);\n return;\n case \"debug\":\n payload ? console.debug(prefix, payload) : console.debug(prefix);\n return;\n }\n };\n\n return {\n error: (message, details) => write(\"error\", message, details),\n warning: (message, details) => write(\"warning\", message, details),\n info: (message, details) => write(\"info\", message, details),\n debug: (message, details) => write(\"debug\", message, details),\n };\n};\n\nconst getUpstreamSignal = (input: RequestInfo | URL, init?: RequestInit): AbortSignal | undefined => {\n if (init?.signal) return init.signal;\n if (typeof Request !== \"undefined\" && input instanceof Request) return input.signal;\n return undefined;\n};\n\nconst getRequestDetails = (\n input: RequestInfo | URL,\n init?: RequestInit\n): { method: string; url: string } => {\n const method =\n init?.method ??\n (typeof Request !== \"undefined\" && input instanceof Request ? input.method : \"GET\");\n const url =\n typeof input === \"string\"\n ? input\n : input instanceof URL\n ? input.toString()\n : input.url;\n return { method, url };\n};\n\nconst getErrorMessage = (error: unknown): string => {\n const maybeError = error as { error?: unknown } | null;\n if (maybeError && typeof maybeError.error === \"string\") return maybeError.error;\n return \"Request failed\";\n};\n\nconst throwRequestError = (\n log: Logger,\n error: unknown,\n response: Response | undefined,\n context: string\n): never => {\n log.error(\"Request failed\", { context, status: response?.status, error });\n throw new PriceOSError(getErrorMessage(error), { status: response?.status, details: error });\n};\n\nconst createRetryingFetch = (baseFetch: typeof fetch, log: Logger): typeof fetch => {\n return async (input: RequestInfo | URL, init?: RequestInit): Promise<Response> => {\n const { method, url } = getRequestDetails(input, init);\n let attempt = 0;\n while (true) {\n log.debug(\"Request attempt\", { method, url, attempt: attempt + 1, maxRetries: MAX_RETRIES });\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);\n const upstreamSignal = getUpstreamSignal(input, init);\n let removeAbortListener: (() => void) | null = null;\n\n if (upstreamSignal) {\n if (upstreamSignal.aborted) {\n controller.abort();\n } else {\n const onAbort = () => controller.abort();\n upstreamSignal.addEventListener(\"abort\", onAbort);\n removeAbortListener = () => upstreamSignal.removeEventListener(\"abort\", onAbort);\n }\n }\n\n try {\n const response = await baseFetch(input, { ...init, signal: controller.signal });\n if (response.status !== RATE_LIMIT_STATUS) return response;\n\n const retryAfter = response.headers.get(\"retry-after\") ?? undefined;\n log.warning(\"Rate limit hit (429)\", {\n method,\n url,\n attempt: attempt + 1,\n maxRetries: MAX_RETRIES,\n retryAfter,\n });\n\n if (attempt >= MAX_RETRIES) {\n log.error(\"Rate limit retries exhausted\", { method, url, attempts: attempt + 1 });\n return response;\n }\n\n const delayMs = getRetryDelayMs(attempt + 1);\n log.info(\"Waiting to retry after rate limit\", {\n method,\n url,\n delayMs,\n nextAttempt: attempt + 2,\n maxRetries: MAX_RETRIES,\n });\n await sleep(delayMs);\n attempt += 1;\n } catch (error) {\n if (controller.signal.aborted) {\n const abortedByCaller = upstreamSignal?.aborted ?? false;\n if (abortedByCaller) {\n log.warning(\"Request aborted by caller\", { method, url, attempt: attempt + 1 });\n } else {\n log.error(\"Request timed out\", {\n method,\n url,\n attempt: attempt + 1,\n timeoutMs: REQUEST_TIMEOUT_MS,\n });\n }\n } else {\n log.error(\"Request failed\", { method, url, attempt: attempt + 1, error });\n }\n throw error;\n } finally {\n clearTimeout(timeoutId);\n removeAbortListener?.();\n }\n }\n };\n};\n\nexport type PriceOSCustomersClient<TFeatureAccessMap = GetFeatureAccessResponse> = {\n get(customerId: string): Promise<GetCustomerResponse<TFeatureAccessMap> | null>;\n identify(input: IdentifyCustomerBody): Promise<IdentifyCustomerResponse<TFeatureAccessMap> | null>;\n create(input: CreateCustomerRequest): Promise<CreateCustomerResponse<TFeatureAccessMap>>;\n update(input: UpdateCustomerBody): Promise<UpdateCustomerResponse<TFeatureAccessMap>>;\n delete(customerId: string): Promise<DeleteCustomerResponse>;\n};\n\nexport type PriceOSFeaturesClient<TFeatureAccessMap = GetFeatureAccessResponse> = {\n getAccess(customerId: string): Promise<TFeatureAccessMap>;\n};\n\nexport type PriceOSUsageClient<TFeatureAccessMap = GetFeatureAccessResponse> = {\n track(\n input: TrackUsageBody<LimitFeatureKeyFromAccessMap<TFeatureAccessMap>>\n ): Promise<TrackUsageResponse>;\n listEvents(\n input: ListUsageEventsBody<LimitFeatureKeyFromAccessMap<TFeatureAccessMap>>\n ): Promise<ListUsageEventsResponse>;\n};\n\n// --- Public SDK surface type ---\nexport type PriceOSHttpClient<TFeatureAccessMap = GetFeatureAccessResponse> = {\n customers: PriceOSCustomersClient<TFeatureAccessMap>;\n features: PriceOSFeaturesClient<TFeatureAccessMap>;\n usage: PriceOSUsageClient<TFeatureAccessMap>;\n};\n\nexport class PriceOSError extends Error {\n status?: number;\n details?: unknown;\n\n constructor(message: string, opts?: { status?: number; details?: unknown }) {\n super(message);\n this.name = \"PriceOSError\";\n this.status = opts?.status;\n this.details = opts?.details;\n }\n}\n\nexport class PriceOS<TFeatureAccessMap = GetFeatureAccessResponse>\n implements PriceOSHttpClient<TFeatureAccessMap>\n{\n private client: Client<paths>;\n private header: { \"x-api-key\": string };\n private log: Logger;\n customers: PriceOSCustomersClient<TFeatureAccessMap>;\n features: PriceOSFeaturesClient<TFeatureAccessMap>;\n usage: PriceOSUsageClient<TFeatureAccessMap>;\n\n constructor(apiKey: string, opts: PriceOSClientOptions = {}) {\n const logLevel = opts.logLevel ?? \"none\";\n this.log = createLogger(logLevel);\n const baseUrl = \"https://api.priceos.com\";\n this.header = { \"x-api-key\": apiKey };\n const fetchWithRetry = createRetryingFetch(fetch, this.log);\n this.client = createClient<paths>({\n baseUrl,\n fetch: fetchWithRetry,\n headers: {\n \"x-api-key\": apiKey,\n },\n });\n\n this.customers = {\n get: async (customerId: string): Promise<GetCustomerResponse<TFeatureAccessMap> | null> => {\n const { data, error, response } = await this.client.GET(\"/v1/customer\", {\n params: { query: { customerId }, header: this.header },\n });\n if (error) throwRequestError(this.log, error, response, \"GET /v1/customer\");\n return (data ?? null) as GetCustomerResponse<TFeatureAccessMap> | null;\n },\n identify: async (\n input: IdentifyCustomerBody\n ): Promise<IdentifyCustomerResponse<TFeatureAccessMap> | null> => {\n const { data, error, response } = await this.client.POST(\"/v1/customer/identify\", {\n params: { header: this.header },\n body: input,\n });\n if (error) throwRequestError(this.log, error, response, \"POST /v1/customer/identify\");\n return (data ?? null) as IdentifyCustomerResponse<TFeatureAccessMap> | null;\n },\n create: async (input: CreateCustomerRequest): Promise<CreateCustomerResponse<TFeatureAccessMap>> => {\n const { data, error, response } = await this.client.POST(\"/v1/customer\", {\n params: { header: this.header },\n body: input,\n });\n if (error) throwRequestError(this.log, error, response, \"POST /v1/customer\");\n return data! as CreateCustomerResponse<TFeatureAccessMap>;\n },\n update: async (input: UpdateCustomerBody): Promise<UpdateCustomerResponse<TFeatureAccessMap>> => {\n const { data, error, response } = await this.client.PUT(\"/v1/customer\", {\n params: { header: this.header },\n body: input,\n });\n if (error) throwRequestError(this.log, error, response, \"PUT /v1/customer\");\n return data! as UpdateCustomerResponse<TFeatureAccessMap>;\n },\n delete: async (customerId: string): Promise<DeleteCustomerResponse> => {\n const { data, error, response } = await this.client.DELETE(\"/v1/customer\", {\n params: { query: { customerId }, header: this.header },\n });\n if (error) throwRequestError(this.log, error, response, \"DELETE /v1/customer\");\n return data! as DeleteCustomerResponse;\n },\n };\n\n this.features = {\n getAccess: async (customerId: string): Promise<TFeatureAccessMap> => {\n const { data, error, response } = await this.client.GET(\"/v1/feature-access\", {\n params: { query: { customerId }, header: this.header },\n });\n if (error) throwRequestError(this.log, error, response, \"GET /v1/feature-access\");\n return data! as TFeatureAccessMap;\n },\n };\n\n this.usage = {\n track: async (\n input: TrackUsageBody<LimitFeatureKeyFromAccessMap<TFeatureAccessMap>>\n ): Promise<TrackUsageResponse> => {\n const { data, error, response } = await this.client.POST(\"/v1/usage\", {\n params: { header: this.header },\n body: input,\n });\n if (error) throwRequestError(this.log, error, response, \"POST /v1/usage\");\n return data!;\n },\n listEvents: async (\n input: ListUsageEventsBody<LimitFeatureKeyFromAccessMap<TFeatureAccessMap>>\n ): Promise<ListUsageEventsResponse> => {\n const { data, error, response } = await this.client.POST(\"/v1/usage/events\", {\n params: { header: this.header },\n body: input,\n });\n if (error) throwRequestError(this.log, error, response, \"POST /v1/usage/events\");\n return data!;\n },\n };\n }\n}\n"],"mappings":"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","names":["createClient"]}
package/dist/index.d.cts CHANGED
@@ -1128,6 +1128,146 @@ interface paths {
1128
1128
  patch?: never;
1129
1129
  trace?: never;
1130
1130
  };
1131
+ "/v1/usage/events": {
1132
+ parameters: {
1133
+ query?: never;
1134
+ header?: never;
1135
+ path?: never;
1136
+ cookie?: never;
1137
+ };
1138
+ get?: never;
1139
+ put?: never;
1140
+ /**
1141
+ * List usage events
1142
+ * @description List usage events for a customer and feature.
1143
+ */
1144
+ post: {
1145
+ parameters: {
1146
+ query?: never;
1147
+ header: {
1148
+ /** @description API key from your PriceOS dashboard. */
1149
+ "x-api-key": string;
1150
+ };
1151
+ path?: never;
1152
+ cookie?: never;
1153
+ };
1154
+ requestBody: {
1155
+ content: {
1156
+ "application/json": {
1157
+ /** @description Customer ID (internal or Stripe). */
1158
+ customerId: string;
1159
+ /** @description Feature key to filter usage events. */
1160
+ featureKey: string;
1161
+ /**
1162
+ * @description Offset for pagination.
1163
+ * @default 0
1164
+ */
1165
+ offset?: number;
1166
+ /**
1167
+ * @description Limit for pagination.
1168
+ * @default 100
1169
+ */
1170
+ limit?: number;
1171
+ /** @description Custom time range (optional). */
1172
+ customRange?: {
1173
+ /** @description Unix timestamp (ms) start for the custom range. */
1174
+ start: number;
1175
+ /** @description Unix timestamp (ms) end for the custom range. */
1176
+ end: number;
1177
+ };
1178
+ };
1179
+ };
1180
+ };
1181
+ responses: {
1182
+ /** @description Usage events list */
1183
+ 200: {
1184
+ headers: {
1185
+ [name: string]: unknown;
1186
+ };
1187
+ content: {
1188
+ "application/json": {
1189
+ /** @description Usage events. */
1190
+ usageEvents: {
1191
+ /** @description Usage event ID. */
1192
+ id: string;
1193
+ /** @description Usage amount recorded. */
1194
+ amount: number;
1195
+ /** @description Unix timestamp (ms) when the event occurred. */
1196
+ occurredAt: number;
1197
+ /** @description Idempotency key for the event. */
1198
+ idempotencyKey?: string | null;
1199
+ /** @description Event metadata (string key/value pairs). */
1200
+ metadata?: {
1201
+ [key: string]: string;
1202
+ };
1203
+ }[];
1204
+ /** @description Whether there are more results. */
1205
+ hasMore: boolean;
1206
+ /** @description Offset used for pagination. */
1207
+ offset: number;
1208
+ /** @description Limit used for pagination. */
1209
+ limit: number;
1210
+ /** @description Total usage events matching the query. */
1211
+ total: number;
1212
+ };
1213
+ };
1214
+ };
1215
+ /** @description Bad request */
1216
+ 400: {
1217
+ headers: {
1218
+ [name: string]: unknown;
1219
+ };
1220
+ content: {
1221
+ "application/json": {
1222
+ /** @description Error message. */
1223
+ error: string;
1224
+ };
1225
+ };
1226
+ };
1227
+ /** @description Unauthorized */
1228
+ 401: {
1229
+ headers: {
1230
+ [name: string]: unknown;
1231
+ };
1232
+ content: {
1233
+ "application/json": {
1234
+ /** @description Error message. */
1235
+ error: string;
1236
+ };
1237
+ };
1238
+ };
1239
+ /** @description Not found */
1240
+ 404: {
1241
+ headers: {
1242
+ [name: string]: unknown;
1243
+ };
1244
+ content: {
1245
+ "application/json": {
1246
+ /** @description Error message. */
1247
+ error: string;
1248
+ };
1249
+ };
1250
+ };
1251
+ /** @description Server error */
1252
+ 500: {
1253
+ headers: {
1254
+ [name: string]: unknown;
1255
+ };
1256
+ content: {
1257
+ "application/json": {
1258
+ /** @description Error message. */
1259
+ error: string;
1260
+ };
1261
+ };
1262
+ };
1263
+ };
1264
+ };
1265
+ delete?: never;
1266
+ options?: never;
1267
+ head?: never;
1268
+ patch?: never;
1269
+ trace?: never;
1270
+ };
1131
1271
  }
1132
1272
 
1133
1273
  type WithFeatureAccess<T, TFeatureAccessMap> = T extends {
@@ -1161,11 +1301,16 @@ type TrackUsageBody<TFeatureKey extends string = TrackUsageBodyBase["featureKey"
1161
1301
  featureKey: TFeatureKey;
1162
1302
  };
1163
1303
  type TrackUsageResponse = paths["/v1/usage"]["post"]["responses"][200]["content"]["application/json"];
1304
+ type ListUsageEventsBodyBase = paths["/v1/usage/events"]["post"]["requestBody"]["content"]["application/json"];
1305
+ type ListUsageEventsBody<TFeatureKey extends string = ListUsageEventsBodyBase["featureKey"]> = Omit<ListUsageEventsBodyBase, "featureKey"> & {
1306
+ featureKey: TFeatureKey;
1307
+ };
1308
+ type ListUsageEventsResponse = paths["/v1/usage/events"]["post"]["responses"][200]["content"]["application/json"];
1309
+ type UsageEvent = ListUsageEventsResponse["usageEvents"][number];
1164
1310
 
1311
+ type PriceOSLogLevel = "none" | "error" | "warning" | "info" | "debug";
1165
1312
  type PriceOSClientOptions = {
1166
- baseUrl?: string;
1167
- fetch?: typeof fetch;
1168
- userAgent?: string;
1313
+ logLevel?: PriceOSLogLevel;
1169
1314
  };
1170
1315
  type PriceOSCustomersClient<TFeatureAccessMap = GetFeatureAccessResponse> = {
1171
1316
  get(customerId: string): Promise<GetCustomerResponse<TFeatureAccessMap> | null>;
@@ -1179,6 +1324,7 @@ type PriceOSFeaturesClient<TFeatureAccessMap = GetFeatureAccessResponse> = {
1179
1324
  };
1180
1325
  type PriceOSUsageClient<TFeatureAccessMap = GetFeatureAccessResponse> = {
1181
1326
  track(input: TrackUsageBody<LimitFeatureKeyFromAccessMap<TFeatureAccessMap>>): Promise<TrackUsageResponse>;
1327
+ listEvents(input: ListUsageEventsBody<LimitFeatureKeyFromAccessMap<TFeatureAccessMap>>): Promise<ListUsageEventsResponse>;
1182
1328
  };
1183
1329
  type PriceOSHttpClient<TFeatureAccessMap = GetFeatureAccessResponse> = {
1184
1330
  customers: PriceOSCustomersClient<TFeatureAccessMap>;
@@ -1196,10 +1342,11 @@ declare class PriceOSError extends Error {
1196
1342
  declare class PriceOS<TFeatureAccessMap = GetFeatureAccessResponse> implements PriceOSHttpClient<TFeatureAccessMap> {
1197
1343
  private client;
1198
1344
  private header;
1345
+ private log;
1199
1346
  customers: PriceOSCustomersClient<TFeatureAccessMap>;
1200
1347
  features: PriceOSFeaturesClient<TFeatureAccessMap>;
1201
1348
  usage: PriceOSUsageClient<TFeatureAccessMap>;
1202
1349
  constructor(apiKey: string, opts?: PriceOSClientOptions);
1203
1350
  }
1204
1351
 
1205
- export { type CreateCustomerRequest, type CreateCustomerResponse, type DeleteCustomerRequest, type DeleteCustomerResponse, type GetCustomerResponse, type GetFeatureAccessResponse, type IdentifyCustomerBody, type IdentifyCustomerResponse, type LimitFeatureKeyFromAccessMap, PriceOS, type PriceOSClientOptions, type PriceOSCustomersClient, PriceOSError, type PriceOSFeaturesClient, type PriceOSHttpClient, type PriceOSUsageClient, type TrackUsageBody, type TrackUsageResponse, type UpdateCustomerBody, type UpdateCustomerResponse };
1352
+ export { type CreateCustomerRequest, type CreateCustomerResponse, type DeleteCustomerRequest, type DeleteCustomerResponse, type GetCustomerResponse, type GetFeatureAccessResponse, type IdentifyCustomerBody, type IdentifyCustomerResponse, type LimitFeatureKeyFromAccessMap, type ListUsageEventsBody, type ListUsageEventsResponse, PriceOS, type PriceOSClientOptions, type PriceOSCustomersClient, PriceOSError, type PriceOSFeaturesClient, type PriceOSHttpClient, type PriceOSLogLevel, type PriceOSUsageClient, type TrackUsageBody, type TrackUsageResponse, type UpdateCustomerBody, type UpdateCustomerResponse, type UsageEvent };
package/dist/index.d.ts CHANGED
@@ -1128,6 +1128,146 @@ interface paths {
1128
1128
  patch?: never;
1129
1129
  trace?: never;
1130
1130
  };
1131
+ "/v1/usage/events": {
1132
+ parameters: {
1133
+ query?: never;
1134
+ header?: never;
1135
+ path?: never;
1136
+ cookie?: never;
1137
+ };
1138
+ get?: never;
1139
+ put?: never;
1140
+ /**
1141
+ * List usage events
1142
+ * @description List usage events for a customer and feature.
1143
+ */
1144
+ post: {
1145
+ parameters: {
1146
+ query?: never;
1147
+ header: {
1148
+ /** @description API key from your PriceOS dashboard. */
1149
+ "x-api-key": string;
1150
+ };
1151
+ path?: never;
1152
+ cookie?: never;
1153
+ };
1154
+ requestBody: {
1155
+ content: {
1156
+ "application/json": {
1157
+ /** @description Customer ID (internal or Stripe). */
1158
+ customerId: string;
1159
+ /** @description Feature key to filter usage events. */
1160
+ featureKey: string;
1161
+ /**
1162
+ * @description Offset for pagination.
1163
+ * @default 0
1164
+ */
1165
+ offset?: number;
1166
+ /**
1167
+ * @description Limit for pagination.
1168
+ * @default 100
1169
+ */
1170
+ limit?: number;
1171
+ /** @description Custom time range (optional). */
1172
+ customRange?: {
1173
+ /** @description Unix timestamp (ms) start for the custom range. */
1174
+ start: number;
1175
+ /** @description Unix timestamp (ms) end for the custom range. */
1176
+ end: number;
1177
+ };
1178
+ };
1179
+ };
1180
+ };
1181
+ responses: {
1182
+ /** @description Usage events list */
1183
+ 200: {
1184
+ headers: {
1185
+ [name: string]: unknown;
1186
+ };
1187
+ content: {
1188
+ "application/json": {
1189
+ /** @description Usage events. */
1190
+ usageEvents: {
1191
+ /** @description Usage event ID. */
1192
+ id: string;
1193
+ /** @description Usage amount recorded. */
1194
+ amount: number;
1195
+ /** @description Unix timestamp (ms) when the event occurred. */
1196
+ occurredAt: number;
1197
+ /** @description Idempotency key for the event. */
1198
+ idempotencyKey?: string | null;
1199
+ /** @description Event metadata (string key/value pairs). */
1200
+ metadata?: {
1201
+ [key: string]: string;
1202
+ };
1203
+ }[];
1204
+ /** @description Whether there are more results. */
1205
+ hasMore: boolean;
1206
+ /** @description Offset used for pagination. */
1207
+ offset: number;
1208
+ /** @description Limit used for pagination. */
1209
+ limit: number;
1210
+ /** @description Total usage events matching the query. */
1211
+ total: number;
1212
+ };
1213
+ };
1214
+ };
1215
+ /** @description Bad request */
1216
+ 400: {
1217
+ headers: {
1218
+ [name: string]: unknown;
1219
+ };
1220
+ content: {
1221
+ "application/json": {
1222
+ /** @description Error message. */
1223
+ error: string;
1224
+ };
1225
+ };
1226
+ };
1227
+ /** @description Unauthorized */
1228
+ 401: {
1229
+ headers: {
1230
+ [name: string]: unknown;
1231
+ };
1232
+ content: {
1233
+ "application/json": {
1234
+ /** @description Error message. */
1235
+ error: string;
1236
+ };
1237
+ };
1238
+ };
1239
+ /** @description Not found */
1240
+ 404: {
1241
+ headers: {
1242
+ [name: string]: unknown;
1243
+ };
1244
+ content: {
1245
+ "application/json": {
1246
+ /** @description Error message. */
1247
+ error: string;
1248
+ };
1249
+ };
1250
+ };
1251
+ /** @description Server error */
1252
+ 500: {
1253
+ headers: {
1254
+ [name: string]: unknown;
1255
+ };
1256
+ content: {
1257
+ "application/json": {
1258
+ /** @description Error message. */
1259
+ error: string;
1260
+ };
1261
+ };
1262
+ };
1263
+ };
1264
+ };
1265
+ delete?: never;
1266
+ options?: never;
1267
+ head?: never;
1268
+ patch?: never;
1269
+ trace?: never;
1270
+ };
1131
1271
  }
1132
1272
 
1133
1273
  type WithFeatureAccess<T, TFeatureAccessMap> = T extends {
@@ -1161,11 +1301,16 @@ type TrackUsageBody<TFeatureKey extends string = TrackUsageBodyBase["featureKey"
1161
1301
  featureKey: TFeatureKey;
1162
1302
  };
1163
1303
  type TrackUsageResponse = paths["/v1/usage"]["post"]["responses"][200]["content"]["application/json"];
1304
+ type ListUsageEventsBodyBase = paths["/v1/usage/events"]["post"]["requestBody"]["content"]["application/json"];
1305
+ type ListUsageEventsBody<TFeatureKey extends string = ListUsageEventsBodyBase["featureKey"]> = Omit<ListUsageEventsBodyBase, "featureKey"> & {
1306
+ featureKey: TFeatureKey;
1307
+ };
1308
+ type ListUsageEventsResponse = paths["/v1/usage/events"]["post"]["responses"][200]["content"]["application/json"];
1309
+ type UsageEvent = ListUsageEventsResponse["usageEvents"][number];
1164
1310
 
1311
+ type PriceOSLogLevel = "none" | "error" | "warning" | "info" | "debug";
1165
1312
  type PriceOSClientOptions = {
1166
- baseUrl?: string;
1167
- fetch?: typeof fetch;
1168
- userAgent?: string;
1313
+ logLevel?: PriceOSLogLevel;
1169
1314
  };
1170
1315
  type PriceOSCustomersClient<TFeatureAccessMap = GetFeatureAccessResponse> = {
1171
1316
  get(customerId: string): Promise<GetCustomerResponse<TFeatureAccessMap> | null>;
@@ -1179,6 +1324,7 @@ type PriceOSFeaturesClient<TFeatureAccessMap = GetFeatureAccessResponse> = {
1179
1324
  };
1180
1325
  type PriceOSUsageClient<TFeatureAccessMap = GetFeatureAccessResponse> = {
1181
1326
  track(input: TrackUsageBody<LimitFeatureKeyFromAccessMap<TFeatureAccessMap>>): Promise<TrackUsageResponse>;
1327
+ listEvents(input: ListUsageEventsBody<LimitFeatureKeyFromAccessMap<TFeatureAccessMap>>): Promise<ListUsageEventsResponse>;
1182
1328
  };
1183
1329
  type PriceOSHttpClient<TFeatureAccessMap = GetFeatureAccessResponse> = {
1184
1330
  customers: PriceOSCustomersClient<TFeatureAccessMap>;
@@ -1196,10 +1342,11 @@ declare class PriceOSError extends Error {
1196
1342
  declare class PriceOS<TFeatureAccessMap = GetFeatureAccessResponse> implements PriceOSHttpClient<TFeatureAccessMap> {
1197
1343
  private client;
1198
1344
  private header;
1345
+ private log;
1199
1346
  customers: PriceOSCustomersClient<TFeatureAccessMap>;
1200
1347
  features: PriceOSFeaturesClient<TFeatureAccessMap>;
1201
1348
  usage: PriceOSUsageClient<TFeatureAccessMap>;
1202
1349
  constructor(apiKey: string, opts?: PriceOSClientOptions);
1203
1350
  }
1204
1351
 
1205
- export { type CreateCustomerRequest, type CreateCustomerResponse, type DeleteCustomerRequest, type DeleteCustomerResponse, type GetCustomerResponse, type GetFeatureAccessResponse, type IdentifyCustomerBody, type IdentifyCustomerResponse, type LimitFeatureKeyFromAccessMap, PriceOS, type PriceOSClientOptions, type PriceOSCustomersClient, PriceOSError, type PriceOSFeaturesClient, type PriceOSHttpClient, type PriceOSUsageClient, type TrackUsageBody, type TrackUsageResponse, type UpdateCustomerBody, type UpdateCustomerResponse };
1352
+ export { type CreateCustomerRequest, type CreateCustomerResponse, type DeleteCustomerRequest, type DeleteCustomerResponse, type GetCustomerResponse, type GetFeatureAccessResponse, type IdentifyCustomerBody, type IdentifyCustomerResponse, type LimitFeatureKeyFromAccessMap, type ListUsageEventsBody, type ListUsageEventsResponse, PriceOS, type PriceOSClientOptions, type PriceOSCustomersClient, PriceOSError, type PriceOSFeaturesClient, type PriceOSHttpClient, type PriceOSLogLevel, type PriceOSUsageClient, type TrackUsageBody, type TrackUsageResponse, type UpdateCustomerBody, type UpdateCustomerResponse, type UsageEvent };
package/dist/index.js CHANGED
@@ -1,5 +1,140 @@
1
1
  // src/client.ts
2
2
  import createClient from "openapi-fetch";
3
+ var RATE_LIMIT_STATUS = 429;
4
+ var MAX_RETRIES = 4;
5
+ var BASE_DELAY_MS = 250;
6
+ var BACKOFF_MULTIPLIER = 2;
7
+ var JITTER_MS = 250;
8
+ var RETRY_DELAY_CAP_MS = 5e3;
9
+ var REQUEST_TIMEOUT_MS = 2e4;
10
+ var LOG_LEVELS = {
11
+ none: 0,
12
+ error: 1,
13
+ warning: 2,
14
+ info: 3,
15
+ debug: 4
16
+ };
17
+ var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
18
+ var getRetryDelayMs = (retryCount) => {
19
+ const backoff = BASE_DELAY_MS * Math.pow(BACKOFF_MULTIPLIER, retryCount - 1);
20
+ const jitter = Math.random() * JITTER_MS;
21
+ return Math.min(RETRY_DELAY_CAP_MS, backoff + jitter);
22
+ };
23
+ var createLogger = (logLevel) => {
24
+ const shouldLog = (level) => logLevel !== "none" && LOG_LEVELS[level] <= LOG_LEVELS[logLevel];
25
+ const write = (level, message, details) => {
26
+ if (!shouldLog(level)) return;
27
+ const prefix = `[PriceOS] ${level.toUpperCase()}: ${message}`;
28
+ const payload = details && Object.keys(details).length > 0 ? details : void 0;
29
+ switch (level) {
30
+ case "error":
31
+ payload ? console.error(prefix, payload) : console.error(prefix);
32
+ return;
33
+ case "warning":
34
+ payload ? console.warn(prefix, payload) : console.warn(prefix);
35
+ return;
36
+ case "info":
37
+ payload ? console.info(prefix, payload) : console.info(prefix);
38
+ return;
39
+ case "debug":
40
+ payload ? console.debug(prefix, payload) : console.debug(prefix);
41
+ return;
42
+ }
43
+ };
44
+ return {
45
+ error: (message, details) => write("error", message, details),
46
+ warning: (message, details) => write("warning", message, details),
47
+ info: (message, details) => write("info", message, details),
48
+ debug: (message, details) => write("debug", message, details)
49
+ };
50
+ };
51
+ var getUpstreamSignal = (input, init) => {
52
+ if (init?.signal) return init.signal;
53
+ if (typeof Request !== "undefined" && input instanceof Request) return input.signal;
54
+ return void 0;
55
+ };
56
+ var getRequestDetails = (input, init) => {
57
+ const method = init?.method ?? (typeof Request !== "undefined" && input instanceof Request ? input.method : "GET");
58
+ const url = typeof input === "string" ? input : input instanceof URL ? input.toString() : input.url;
59
+ return { method, url };
60
+ };
61
+ var getErrorMessage = (error) => {
62
+ const maybeError = error;
63
+ if (maybeError && typeof maybeError.error === "string") return maybeError.error;
64
+ return "Request failed";
65
+ };
66
+ var throwRequestError = (log, error, response, context) => {
67
+ log.error("Request failed", { context, status: response?.status, error });
68
+ throw new PriceOSError(getErrorMessage(error), { status: response?.status, details: error });
69
+ };
70
+ var createRetryingFetch = (baseFetch, log) => {
71
+ return async (input, init) => {
72
+ const { method, url } = getRequestDetails(input, init);
73
+ let attempt = 0;
74
+ while (true) {
75
+ log.debug("Request attempt", { method, url, attempt: attempt + 1, maxRetries: MAX_RETRIES });
76
+ const controller = new AbortController();
77
+ const timeoutId = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);
78
+ const upstreamSignal = getUpstreamSignal(input, init);
79
+ let removeAbortListener = null;
80
+ if (upstreamSignal) {
81
+ if (upstreamSignal.aborted) {
82
+ controller.abort();
83
+ } else {
84
+ const onAbort = () => controller.abort();
85
+ upstreamSignal.addEventListener("abort", onAbort);
86
+ removeAbortListener = () => upstreamSignal.removeEventListener("abort", onAbort);
87
+ }
88
+ }
89
+ try {
90
+ const response = await baseFetch(input, { ...init, signal: controller.signal });
91
+ if (response.status !== RATE_LIMIT_STATUS) return response;
92
+ const retryAfter = response.headers.get("retry-after") ?? void 0;
93
+ log.warning("Rate limit hit (429)", {
94
+ method,
95
+ url,
96
+ attempt: attempt + 1,
97
+ maxRetries: MAX_RETRIES,
98
+ retryAfter
99
+ });
100
+ if (attempt >= MAX_RETRIES) {
101
+ log.error("Rate limit retries exhausted", { method, url, attempts: attempt + 1 });
102
+ return response;
103
+ }
104
+ const delayMs = getRetryDelayMs(attempt + 1);
105
+ log.info("Waiting to retry after rate limit", {
106
+ method,
107
+ url,
108
+ delayMs,
109
+ nextAttempt: attempt + 2,
110
+ maxRetries: MAX_RETRIES
111
+ });
112
+ await sleep(delayMs);
113
+ attempt += 1;
114
+ } catch (error) {
115
+ if (controller.signal.aborted) {
116
+ const abortedByCaller = upstreamSignal?.aborted ?? false;
117
+ if (abortedByCaller) {
118
+ log.warning("Request aborted by caller", { method, url, attempt: attempt + 1 });
119
+ } else {
120
+ log.error("Request timed out", {
121
+ method,
122
+ url,
123
+ attempt: attempt + 1,
124
+ timeoutMs: REQUEST_TIMEOUT_MS
125
+ });
126
+ }
127
+ } else {
128
+ log.error("Request failed", { method, url, attempt: attempt + 1, error });
129
+ }
130
+ throw error;
131
+ } finally {
132
+ clearTimeout(timeoutId);
133
+ removeAbortListener?.();
134
+ }
135
+ }
136
+ };
137
+ };
3
138
  var PriceOSError = class extends Error {
4
139
  status;
5
140
  details;
@@ -13,18 +148,21 @@ var PriceOSError = class extends Error {
13
148
  var PriceOS = class {
14
149
  client;
15
150
  header;
151
+ log;
16
152
  customers;
17
153
  features;
18
154
  usage;
19
155
  constructor(apiKey, opts = {}) {
20
- const baseUrl = opts.baseUrl ?? "https://api.priceos.com";
156
+ const logLevel = opts.logLevel ?? "none";
157
+ this.log = createLogger(logLevel);
158
+ const baseUrl = "https://api.priceos.com";
21
159
  this.header = { "x-api-key": apiKey };
160
+ const fetchWithRetry = createRetryingFetch(fetch, this.log);
22
161
  this.client = createClient({
23
162
  baseUrl,
24
- fetch: opts.fetch,
163
+ fetch: fetchWithRetry,
25
164
  headers: {
26
- "x-api-key": apiKey,
27
- ...opts.userAgent ? { "user-agent": opts.userAgent } : {}
165
+ "x-api-key": apiKey
28
166
  }
29
167
  });
30
168
  this.customers = {
@@ -32,8 +170,7 @@ var PriceOS = class {
32
170
  const { data, error, response } = await this.client.GET("/v1/customer", {
33
171
  params: { query: { customerId }, header: this.header }
34
172
  });
35
- if (error)
36
- throw new PriceOSError(error.error ?? "Request failed", { status: response?.status, details: error });
173
+ if (error) throwRequestError(this.log, error, response, "GET /v1/customer");
37
174
  return data ?? null;
38
175
  },
39
176
  identify: async (input) => {
@@ -41,8 +178,7 @@ var PriceOS = class {
41
178
  params: { header: this.header },
42
179
  body: input
43
180
  });
44
- if (error)
45
- throw new PriceOSError(error.error ?? "Request failed", { status: response?.status, details: error });
181
+ if (error) throwRequestError(this.log, error, response, "POST /v1/customer/identify");
46
182
  return data ?? null;
47
183
  },
48
184
  create: async (input) => {
@@ -50,8 +186,7 @@ var PriceOS = class {
50
186
  params: { header: this.header },
51
187
  body: input
52
188
  });
53
- if (error)
54
- throw new PriceOSError(error.error ?? "Request failed", { status: response?.status, details: error });
189
+ if (error) throwRequestError(this.log, error, response, "POST /v1/customer");
55
190
  return data;
56
191
  },
57
192
  update: async (input) => {
@@ -59,16 +194,14 @@ var PriceOS = class {
59
194
  params: { header: this.header },
60
195
  body: input
61
196
  });
62
- if (error)
63
- throw new PriceOSError(error.error ?? "Request failed", { status: response?.status, details: error });
197
+ if (error) throwRequestError(this.log, error, response, "PUT /v1/customer");
64
198
  return data;
65
199
  },
66
200
  delete: async (customerId) => {
67
201
  const { data, error, response } = await this.client.DELETE("/v1/customer", {
68
202
  params: { query: { customerId }, header: this.header }
69
203
  });
70
- if (error)
71
- throw new PriceOSError(error.error ?? "Request failed", { status: response?.status, details: error });
204
+ if (error) throwRequestError(this.log, error, response, "DELETE /v1/customer");
72
205
  return data;
73
206
  }
74
207
  };
@@ -77,8 +210,7 @@ var PriceOS = class {
77
210
  const { data, error, response } = await this.client.GET("/v1/feature-access", {
78
211
  params: { query: { customerId }, header: this.header }
79
212
  });
80
- if (error)
81
- throw new PriceOSError(error.error ?? "Request failed", { status: response?.status, details: error });
213
+ if (error) throwRequestError(this.log, error, response, "GET /v1/feature-access");
82
214
  return data;
83
215
  }
84
216
  };
@@ -88,8 +220,15 @@ var PriceOS = class {
88
220
  params: { header: this.header },
89
221
  body: input
90
222
  });
91
- if (error)
92
- throw new PriceOSError(error.error ?? "Request failed", { status: response?.status, details: error });
223
+ if (error) throwRequestError(this.log, error, response, "POST /v1/usage");
224
+ return data;
225
+ },
226
+ listEvents: async (input) => {
227
+ const { data, error, response } = await this.client.POST("/v1/usage/events", {
228
+ params: { header: this.header },
229
+ body: input
230
+ });
231
+ if (error) throwRequestError(this.log, error, response, "POST /v1/usage/events");
93
232
  return data;
94
233
  }
95
234
  };
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/client.ts"],"sourcesContent":["import createClient from \"openapi-fetch\";\nimport type { Client } from \"openapi-fetch\";\nimport type { paths } from \"./gen/openapi\";\nimport {\n CreateCustomerRequest,\n CreateCustomerResponse,\n DeleteCustomerResponse,\n GetCustomerResponse,\n GetFeatureAccessResponse,\n IdentifyCustomerBody,\n IdentifyCustomerResponse,\n LimitFeatureKeyFromAccessMap,\n TrackUsageBody,\n TrackUsageResponse,\n UpdateCustomerBody,\n UpdateCustomerResponse,\n} from \"./types\";\n\n// --- Public options ---\nexport type PriceOSClientOptions = {\n baseUrl?: string;\n fetch?: typeof fetch;\n userAgent?: string;\n};\n\nexport type PriceOSCustomersClient<TFeatureAccessMap = GetFeatureAccessResponse> = {\n get(customerId: string): Promise<GetCustomerResponse<TFeatureAccessMap> | null>;\n identify(input: IdentifyCustomerBody): Promise<IdentifyCustomerResponse<TFeatureAccessMap> | null>;\n create(input: CreateCustomerRequest): Promise<CreateCustomerResponse<TFeatureAccessMap>>;\n update(input: UpdateCustomerBody): Promise<UpdateCustomerResponse<TFeatureAccessMap>>;\n delete(customerId: string): Promise<DeleteCustomerResponse>;\n};\n\nexport type PriceOSFeaturesClient<TFeatureAccessMap = GetFeatureAccessResponse> = {\n getAccess(customerId: string): Promise<TFeatureAccessMap>;\n};\n\nexport type PriceOSUsageClient<TFeatureAccessMap = GetFeatureAccessResponse> = {\n track(\n input: TrackUsageBody<LimitFeatureKeyFromAccessMap<TFeatureAccessMap>>\n ): Promise<TrackUsageResponse>;\n};\n\n// --- Public SDK surface type ---\nexport type PriceOSHttpClient<TFeatureAccessMap = GetFeatureAccessResponse> = {\n customers: PriceOSCustomersClient<TFeatureAccessMap>;\n features: PriceOSFeaturesClient<TFeatureAccessMap>;\n usage: PriceOSUsageClient<TFeatureAccessMap>;\n};\n\nexport class PriceOSError extends Error {\n status?: number;\n details?: unknown;\n\n constructor(message: string, opts?: { status?: number; details?: unknown }) {\n super(message);\n this.name = \"PriceOSError\";\n this.status = opts?.status;\n this.details = opts?.details;\n }\n}\n\nexport class PriceOS<TFeatureAccessMap = GetFeatureAccessResponse>\n implements PriceOSHttpClient<TFeatureAccessMap>\n{\n private client: Client<paths>;\n private header: { \"x-api-key\": string };\n customers: PriceOSCustomersClient<TFeatureAccessMap>;\n features: PriceOSFeaturesClient<TFeatureAccessMap>;\n usage: PriceOSUsageClient<TFeatureAccessMap>;\n\n constructor(apiKey: string, opts: PriceOSClientOptions = {}) {\n const baseUrl = opts.baseUrl ?? \"https://api.priceos.com\";\n this.header = { \"x-api-key\": apiKey };\n this.client = createClient<paths>({\n baseUrl,\n fetch: opts.fetch,\n headers: {\n \"x-api-key\": apiKey,\n ...(opts.userAgent ? { \"user-agent\": opts.userAgent } : {}),\n },\n });\n\n this.customers = {\n get: async (customerId: string): Promise<GetCustomerResponse<TFeatureAccessMap> | null> => {\n const { data, error, response } = await this.client.GET(\"/v1/customer\", {\n params: { query: { customerId }, header: this.header },\n });\n if (error)\n throw new PriceOSError(error.error ?? \"Request failed\", { status: response?.status, details: error });\n return (data ?? null) as GetCustomerResponse<TFeatureAccessMap> | null;\n },\n identify: async (\n input: IdentifyCustomerBody\n ): Promise<IdentifyCustomerResponse<TFeatureAccessMap> | null> => {\n const { data, error, response } = await this.client.POST(\"/v1/customer/identify\", {\n params: { header: this.header },\n body: input,\n });\n if (error)\n throw new PriceOSError(error.error ?? \"Request failed\", { status: response?.status, details: error });\n return (data ?? null) as IdentifyCustomerResponse<TFeatureAccessMap> | null;\n },\n create: async (input: CreateCustomerRequest): Promise<CreateCustomerResponse<TFeatureAccessMap>> => {\n const { data, error, response } = await this.client.POST(\"/v1/customer\", {\n params: { header: this.header },\n body: input,\n });\n if (error)\n throw new PriceOSError(error.error ?? \"Request failed\", { status: response?.status, details: error });\n return data! as CreateCustomerResponse<TFeatureAccessMap>;\n },\n update: async (input: UpdateCustomerBody): Promise<UpdateCustomerResponse<TFeatureAccessMap>> => {\n const { data, error, response } = await this.client.PUT(\"/v1/customer\", {\n params: { header: this.header },\n body: input,\n });\n if (error)\n throw new PriceOSError(error.error ?? \"Request failed\", { status: response?.status, details: error });\n return data! as UpdateCustomerResponse<TFeatureAccessMap>;\n },\n delete: async (customerId: string): Promise<DeleteCustomerResponse> => {\n const { data, error, response } = await this.client.DELETE(\"/v1/customer\", {\n params: { query: { customerId }, header: this.header },\n });\n if (error)\n throw new PriceOSError(error.error ?? \"Request failed\", { status: response?.status, details: error });\n return data! as DeleteCustomerResponse;\n },\n };\n\n this.features = {\n getAccess: async (customerId: string): Promise<TFeatureAccessMap> => {\n const { data, error, response } = await this.client.GET(\"/v1/feature-access\", {\n params: { query: { customerId }, header: this.header },\n });\n if (error)\n throw new PriceOSError(error.error ?? \"Request failed\", { status: response?.status, details: error });\n return data! as TFeatureAccessMap;\n },\n };\n\n this.usage = {\n track: async (\n input: TrackUsageBody<LimitFeatureKeyFromAccessMap<TFeatureAccessMap>>\n ): Promise<TrackUsageResponse> => {\n const { data, error, response } = await this.client.POST(\"/v1/usage\", {\n params: { header: this.header },\n body: input,\n });\n if (error)\n throw new PriceOSError(error.error ?? \"Request failed\", { status: response?.status, details: error });\n return data!;\n },\n };\n }\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/client.ts"],"sourcesContent":["import createClient from \"openapi-fetch\";\nimport type { Client } from \"openapi-fetch\";\nimport type { paths } from \"./gen/openapi\";\nimport {\n CreateCustomerRequest,\n CreateCustomerResponse,\n DeleteCustomerResponse,\n GetCustomerResponse,\n GetFeatureAccessResponse,\n IdentifyCustomerBody,\n IdentifyCustomerResponse,\n LimitFeatureKeyFromAccessMap,\n ListUsageEventsBody,\n ListUsageEventsResponse,\n TrackUsageBody,\n TrackUsageResponse,\n UpdateCustomerBody,\n UpdateCustomerResponse,\n} from \"./types\";\n\nexport type PriceOSLogLevel = \"none\" | \"error\" | \"warning\" | \"info\" | \"debug\";\n\n// --- Public options ---\nexport type PriceOSClientOptions = {\n logLevel?: PriceOSLogLevel;\n};\n\nconst RATE_LIMIT_STATUS = 429;\nconst MAX_RETRIES = 4;\nconst BASE_DELAY_MS = 250;\nconst BACKOFF_MULTIPLIER = 2;\nconst JITTER_MS = 250;\nconst RETRY_DELAY_CAP_MS = 5_000;\nconst REQUEST_TIMEOUT_MS = 20_000;\n\nconst LOG_LEVELS: Record<PriceOSLogLevel, number> = {\n none: 0,\n error: 1,\n warning: 2,\n info: 3,\n debug: 4,\n};\n\ntype Logger = {\n error: (message: string, details?: Record<string, unknown>) => void;\n warning: (message: string, details?: Record<string, unknown>) => void;\n info: (message: string, details?: Record<string, unknown>) => void;\n debug: (message: string, details?: Record<string, unknown>) => void;\n};\n\nconst sleep = (ms: number): Promise<void> => new Promise((resolve) => setTimeout(resolve, ms));\n\nconst getRetryDelayMs = (retryCount: number): number => {\n const backoff = BASE_DELAY_MS * Math.pow(BACKOFF_MULTIPLIER, retryCount - 1);\n const jitter = Math.random() * JITTER_MS;\n return Math.min(RETRY_DELAY_CAP_MS, backoff + jitter);\n};\n\nconst createLogger = (logLevel: PriceOSLogLevel): Logger => {\n const shouldLog = (level: PriceOSLogLevel): boolean =>\n logLevel !== \"none\" && LOG_LEVELS[level] <= LOG_LEVELS[logLevel];\n\n const write = (\n level: PriceOSLogLevel,\n message: string,\n details?: Record<string, unknown>\n ): void => {\n if (!shouldLog(level)) return;\n const prefix = `[PriceOS] ${level.toUpperCase()}: ${message}`;\n const payload = details && Object.keys(details).length > 0 ? details : undefined;\n\n switch (level) {\n case \"error\":\n payload ? console.error(prefix, payload) : console.error(prefix);\n return;\n case \"warning\":\n payload ? console.warn(prefix, payload) : console.warn(prefix);\n return;\n case \"info\":\n payload ? console.info(prefix, payload) : console.info(prefix);\n return;\n case \"debug\":\n payload ? console.debug(prefix, payload) : console.debug(prefix);\n return;\n }\n };\n\n return {\n error: (message, details) => write(\"error\", message, details),\n warning: (message, details) => write(\"warning\", message, details),\n info: (message, details) => write(\"info\", message, details),\n debug: (message, details) => write(\"debug\", message, details),\n };\n};\n\nconst getUpstreamSignal = (input: RequestInfo | URL, init?: RequestInit): AbortSignal | undefined => {\n if (init?.signal) return init.signal;\n if (typeof Request !== \"undefined\" && input instanceof Request) return input.signal;\n return undefined;\n};\n\nconst getRequestDetails = (\n input: RequestInfo | URL,\n init?: RequestInit\n): { method: string; url: string } => {\n const method =\n init?.method ??\n (typeof Request !== \"undefined\" && input instanceof Request ? input.method : \"GET\");\n const url =\n typeof input === \"string\"\n ? input\n : input instanceof URL\n ? input.toString()\n : input.url;\n return { method, url };\n};\n\nconst getErrorMessage = (error: unknown): string => {\n const maybeError = error as { error?: unknown } | null;\n if (maybeError && typeof maybeError.error === \"string\") return maybeError.error;\n return \"Request failed\";\n};\n\nconst throwRequestError = (\n log: Logger,\n error: unknown,\n response: Response | undefined,\n context: string\n): never => {\n log.error(\"Request failed\", { context, status: response?.status, error });\n throw new PriceOSError(getErrorMessage(error), { status: response?.status, details: error });\n};\n\nconst createRetryingFetch = (baseFetch: typeof fetch, log: Logger): typeof fetch => {\n return async (input: RequestInfo | URL, init?: RequestInit): Promise<Response> => {\n const { method, url } = getRequestDetails(input, init);\n let attempt = 0;\n while (true) {\n log.debug(\"Request attempt\", { method, url, attempt: attempt + 1, maxRetries: MAX_RETRIES });\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);\n const upstreamSignal = getUpstreamSignal(input, init);\n let removeAbortListener: (() => void) | null = null;\n\n if (upstreamSignal) {\n if (upstreamSignal.aborted) {\n controller.abort();\n } else {\n const onAbort = () => controller.abort();\n upstreamSignal.addEventListener(\"abort\", onAbort);\n removeAbortListener = () => upstreamSignal.removeEventListener(\"abort\", onAbort);\n }\n }\n\n try {\n const response = await baseFetch(input, { ...init, signal: controller.signal });\n if (response.status !== RATE_LIMIT_STATUS) return response;\n\n const retryAfter = response.headers.get(\"retry-after\") ?? undefined;\n log.warning(\"Rate limit hit (429)\", {\n method,\n url,\n attempt: attempt + 1,\n maxRetries: MAX_RETRIES,\n retryAfter,\n });\n\n if (attempt >= MAX_RETRIES) {\n log.error(\"Rate limit retries exhausted\", { method, url, attempts: attempt + 1 });\n return response;\n }\n\n const delayMs = getRetryDelayMs(attempt + 1);\n log.info(\"Waiting to retry after rate limit\", {\n method,\n url,\n delayMs,\n nextAttempt: attempt + 2,\n maxRetries: MAX_RETRIES,\n });\n await sleep(delayMs);\n attempt += 1;\n } catch (error) {\n if (controller.signal.aborted) {\n const abortedByCaller = upstreamSignal?.aborted ?? false;\n if (abortedByCaller) {\n log.warning(\"Request aborted by caller\", { method, url, attempt: attempt + 1 });\n } else {\n log.error(\"Request timed out\", {\n method,\n url,\n attempt: attempt + 1,\n timeoutMs: REQUEST_TIMEOUT_MS,\n });\n }\n } else {\n log.error(\"Request failed\", { method, url, attempt: attempt + 1, error });\n }\n throw error;\n } finally {\n clearTimeout(timeoutId);\n removeAbortListener?.();\n }\n }\n };\n};\n\nexport type PriceOSCustomersClient<TFeatureAccessMap = GetFeatureAccessResponse> = {\n get(customerId: string): Promise<GetCustomerResponse<TFeatureAccessMap> | null>;\n identify(input: IdentifyCustomerBody): Promise<IdentifyCustomerResponse<TFeatureAccessMap> | null>;\n create(input: CreateCustomerRequest): Promise<CreateCustomerResponse<TFeatureAccessMap>>;\n update(input: UpdateCustomerBody): Promise<UpdateCustomerResponse<TFeatureAccessMap>>;\n delete(customerId: string): Promise<DeleteCustomerResponse>;\n};\n\nexport type PriceOSFeaturesClient<TFeatureAccessMap = GetFeatureAccessResponse> = {\n getAccess(customerId: string): Promise<TFeatureAccessMap>;\n};\n\nexport type PriceOSUsageClient<TFeatureAccessMap = GetFeatureAccessResponse> = {\n track(\n input: TrackUsageBody<LimitFeatureKeyFromAccessMap<TFeatureAccessMap>>\n ): Promise<TrackUsageResponse>;\n listEvents(\n input: ListUsageEventsBody<LimitFeatureKeyFromAccessMap<TFeatureAccessMap>>\n ): Promise<ListUsageEventsResponse>;\n};\n\n// --- Public SDK surface type ---\nexport type PriceOSHttpClient<TFeatureAccessMap = GetFeatureAccessResponse> = {\n customers: PriceOSCustomersClient<TFeatureAccessMap>;\n features: PriceOSFeaturesClient<TFeatureAccessMap>;\n usage: PriceOSUsageClient<TFeatureAccessMap>;\n};\n\nexport class PriceOSError extends Error {\n status?: number;\n details?: unknown;\n\n constructor(message: string, opts?: { status?: number; details?: unknown }) {\n super(message);\n this.name = \"PriceOSError\";\n this.status = opts?.status;\n this.details = opts?.details;\n }\n}\n\nexport class PriceOS<TFeatureAccessMap = GetFeatureAccessResponse>\n implements PriceOSHttpClient<TFeatureAccessMap>\n{\n private client: Client<paths>;\n private header: { \"x-api-key\": string };\n private log: Logger;\n customers: PriceOSCustomersClient<TFeatureAccessMap>;\n features: PriceOSFeaturesClient<TFeatureAccessMap>;\n usage: PriceOSUsageClient<TFeatureAccessMap>;\n\n constructor(apiKey: string, opts: PriceOSClientOptions = {}) {\n const logLevel = opts.logLevel ?? \"none\";\n this.log = createLogger(logLevel);\n const baseUrl = \"https://api.priceos.com\";\n this.header = { \"x-api-key\": apiKey };\n const fetchWithRetry = createRetryingFetch(fetch, this.log);\n this.client = createClient<paths>({\n baseUrl,\n fetch: fetchWithRetry,\n headers: {\n \"x-api-key\": apiKey,\n },\n });\n\n this.customers = {\n get: async (customerId: string): Promise<GetCustomerResponse<TFeatureAccessMap> | null> => {\n const { data, error, response } = await this.client.GET(\"/v1/customer\", {\n params: { query: { customerId }, header: this.header },\n });\n if (error) throwRequestError(this.log, error, response, \"GET /v1/customer\");\n return (data ?? null) as GetCustomerResponse<TFeatureAccessMap> | null;\n },\n identify: async (\n input: IdentifyCustomerBody\n ): Promise<IdentifyCustomerResponse<TFeatureAccessMap> | null> => {\n const { data, error, response } = await this.client.POST(\"/v1/customer/identify\", {\n params: { header: this.header },\n body: input,\n });\n if (error) throwRequestError(this.log, error, response, \"POST /v1/customer/identify\");\n return (data ?? null) as IdentifyCustomerResponse<TFeatureAccessMap> | null;\n },\n create: async (input: CreateCustomerRequest): Promise<CreateCustomerResponse<TFeatureAccessMap>> => {\n const { data, error, response } = await this.client.POST(\"/v1/customer\", {\n params: { header: this.header },\n body: input,\n });\n if (error) throwRequestError(this.log, error, response, \"POST /v1/customer\");\n return data! as CreateCustomerResponse<TFeatureAccessMap>;\n },\n update: async (input: UpdateCustomerBody): Promise<UpdateCustomerResponse<TFeatureAccessMap>> => {\n const { data, error, response } = await this.client.PUT(\"/v1/customer\", {\n params: { header: this.header },\n body: input,\n });\n if (error) throwRequestError(this.log, error, response, \"PUT /v1/customer\");\n return data! as UpdateCustomerResponse<TFeatureAccessMap>;\n },\n delete: async (customerId: string): Promise<DeleteCustomerResponse> => {\n const { data, error, response } = await this.client.DELETE(\"/v1/customer\", {\n params: { query: { customerId }, header: this.header },\n });\n if (error) throwRequestError(this.log, error, response, \"DELETE /v1/customer\");\n return data! as DeleteCustomerResponse;\n },\n };\n\n this.features = {\n getAccess: async (customerId: string): Promise<TFeatureAccessMap> => {\n const { data, error, response } = await this.client.GET(\"/v1/feature-access\", {\n params: { query: { customerId }, header: this.header },\n });\n if (error) throwRequestError(this.log, error, response, \"GET /v1/feature-access\");\n return data! as TFeatureAccessMap;\n },\n };\n\n this.usage = {\n track: async (\n input: TrackUsageBody<LimitFeatureKeyFromAccessMap<TFeatureAccessMap>>\n ): Promise<TrackUsageResponse> => {\n const { data, error, response } = await this.client.POST(\"/v1/usage\", {\n params: { header: this.header },\n body: input,\n });\n if (error) throwRequestError(this.log, error, response, \"POST /v1/usage\");\n return data!;\n },\n listEvents: async (\n input: ListUsageEventsBody<LimitFeatureKeyFromAccessMap<TFeatureAccessMap>>\n ): Promise<ListUsageEventsResponse> => {\n const { data, error, response } = await this.client.POST(\"/v1/usage/events\", {\n params: { header: this.header },\n body: input,\n });\n if (error) throwRequestError(this.log, error, response, \"POST /v1/usage/events\");\n return data!;\n },\n };\n }\n}\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "priceos",
3
- "version": "0.0.25",
3
+ "version": "0.0.30",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",