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 +157 -18
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +151 -4
- package/dist/index.d.ts +151 -4
- package/dist/index.js +157 -18
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
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
|
|
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:
|
|
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
|
-
|
|
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
|
};
|
package/dist/index.cjs.map
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
|
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:
|
|
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
|
-
|
|
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":";AAAA,OAAO,kBAAkB;AAkDlB,IAAM,eAAN,cAA2B,MAAM;AAAA,EACtC;AAAA,EACA;AAAA,EAEA,YAAY,SAAiB,MAA+C;AAC1E,UAAM,OAAO;AACb,SAAK,OAAO;AACZ,SAAK,SAAS,MAAM;AACpB,SAAK,UAAU,MAAM;AAAA,EACvB;AACF;AAEO,IAAM,UAAN,MAEP;AAAA,EACU;AAAA,EACA;AAAA,EACR;AAAA,EACA;AAAA,EACA;AAAA,EAEA,YAAY,QAAgB,OAA6B,CAAC,GAAG;AAC3D,UAAM,UAAU,KAAK,WAAW;AAChC,SAAK,SAAS,EAAE,aAAa,OAAO;AACpC,SAAK,SAAS,aAAoB;AAAA,MAChC;AAAA,MACA,OAAO,KAAK;AAAA,MACZ,SAAS;AAAA,QACP,aAAa;AAAA,QACb,GAAI,KAAK,YAAY,EAAE,cAAc,KAAK,UAAU,IAAI,CAAC;AAAA,MAC3D;AAAA,IACF,CAAC;AAED,SAAK,YAAY;AAAA,MACf,KAAK,OAAO,eAA+E;AACzF,cAAM,EAAE,MAAM,OAAO,SAAS,IAAI,MAAM,KAAK,OAAO,IAAI,gBAAgB;AAAA,UACtE,QAAQ,EAAE,OAAO,EAAE,WAAW,GAAG,QAAQ,KAAK,OAAO;AAAA,QACvD,CAAC;AACD,YAAI;AACF,gBAAM,IAAI,aAAa,MAAM,SAAS,kBAAkB,EAAE,QAAQ,UAAU,QAAQ,SAAS,MAAM,CAAC;AACtG,eAAQ,QAAQ;AAAA,MAClB;AAAA,MACA,UAAU,OACR,UACgE;AAChE,cAAM,EAAE,MAAM,OAAO,SAAS,IAAI,MAAM,KAAK,OAAO,KAAK,yBAAyB;AAAA,UAChF,QAAQ,EAAE,QAAQ,KAAK,OAAO;AAAA,UAC9B,MAAM;AAAA,QACR,CAAC;AACD,YAAI;AACF,gBAAM,IAAI,aAAa,MAAM,SAAS,kBAAkB,EAAE,QAAQ,UAAU,QAAQ,SAAS,MAAM,CAAC;AACtG,eAAQ,QAAQ;AAAA,MAClB;AAAA,MACA,QAAQ,OAAO,UAAqF;AAClG,cAAM,EAAE,MAAM,OAAO,SAAS,IAAI,MAAM,KAAK,OAAO,KAAK,gBAAgB;AAAA,UACvE,QAAQ,EAAE,QAAQ,KAAK,OAAO;AAAA,UAC9B,MAAM;AAAA,QACR,CAAC;AACD,YAAI;AACF,gBAAM,IAAI,aAAa,MAAM,SAAS,kBAAkB,EAAE,QAAQ,UAAU,QAAQ,SAAS,MAAM,CAAC;AACtG,eAAO;AAAA,MACT;AAAA,MACA,QAAQ,OAAO,UAAkF;AAC/F,cAAM,EAAE,MAAM,OAAO,SAAS,IAAI,MAAM,KAAK,OAAO,IAAI,gBAAgB;AAAA,UACtE,QAAQ,EAAE,QAAQ,KAAK,OAAO;AAAA,UAC9B,MAAM;AAAA,QACR,CAAC;AACD,YAAI;AACF,gBAAM,IAAI,aAAa,MAAM,SAAS,kBAAkB,EAAE,QAAQ,UAAU,QAAQ,SAAS,MAAM,CAAC;AACtG,eAAO;AAAA,MACT;AAAA,MACA,QAAQ,OAAO,eAAwD;AACrE,cAAM,EAAE,MAAM,OAAO,SAAS,IAAI,MAAM,KAAK,OAAO,OAAO,gBAAgB;AAAA,UACzE,QAAQ,EAAE,OAAO,EAAE,WAAW,GAAG,QAAQ,KAAK,OAAO;AAAA,QACvD,CAAC;AACD,YAAI;AACF,gBAAM,IAAI,aAAa,MAAM,SAAS,kBAAkB,EAAE,QAAQ,UAAU,QAAQ,SAAS,MAAM,CAAC;AACtG,eAAO;AAAA,MACT;AAAA,IACF;AAEA,SAAK,WAAW;AAAA,MACd,WAAW,OAAO,eAAmD;AACnE,cAAM,EAAE,MAAM,OAAO,SAAS,IAAI,MAAM,KAAK,OAAO,IAAI,sBAAsB;AAAA,UAC5E,QAAQ,EAAE,OAAO,EAAE,WAAW,GAAG,QAAQ,KAAK,OAAO;AAAA,QACvD,CAAC;AACD,YAAI;AACF,gBAAM,IAAI,aAAa,MAAM,SAAS,kBAAkB,EAAE,QAAQ,UAAU,QAAQ,SAAS,MAAM,CAAC;AACtG,eAAO;AAAA,MACT;AAAA,IACF;AAEA,SAAK,QAAQ;AAAA,MACX,OAAO,OACL,UACgC;AAChC,cAAM,EAAE,MAAM,OAAO,SAAS,IAAI,MAAM,KAAK,OAAO,KAAK,aAAa;AAAA,UACpE,QAAQ,EAAE,QAAQ,KAAK,OAAO;AAAA,UAC9B,MAAM;AAAA,QACR,CAAC;AACD,YAAI;AACF,gBAAM,IAAI,aAAa,MAAM,SAAS,kBAAkB,EAAE,QAAQ,UAAU,QAAQ,SAAS,MAAM,CAAC;AACtG,eAAO;AAAA,MACT;AAAA,IACF;AAAA,EACF;AACF;","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":";AAAA,OAAO,kBAAkB;AA2BzB,IAAM,oBAAoB;AAC1B,IAAM,cAAc;AACpB,IAAM,gBAAgB;AACtB,IAAM,qBAAqB;AAC3B,IAAM,YAAY;AAClB,IAAM,qBAAqB;AAC3B,IAAM,qBAAqB;AAE3B,IAAM,aAA8C;AAAA,EAClD,MAAM;AAAA,EACN,OAAO;AAAA,EACP,SAAS;AAAA,EACT,MAAM;AAAA,EACN,OAAO;AACT;AASA,IAAM,QAAQ,CAAC,OAA8B,IAAI,QAAQ,CAAC,YAAY,WAAW,SAAS,EAAE,CAAC;AAE7F,IAAM,kBAAkB,CAAC,eAA+B;AACtD,QAAM,UAAU,gBAAgB,KAAK,IAAI,oBAAoB,aAAa,CAAC;AAC3E,QAAM,SAAS,KAAK,OAAO,IAAI;AAC/B,SAAO,KAAK,IAAI,oBAAoB,UAAU,MAAM;AACtD;AAEA,IAAM,eAAe,CAAC,aAAsC;AAC1D,QAAM,YAAY,CAAC,UACjB,aAAa,UAAU,WAAW,KAAK,KAAK,WAAW,QAAQ;AAEjE,QAAM,QAAQ,CACZ,OACA,SACA,YACS;AACT,QAAI,CAAC,UAAU,KAAK,EAAG;AACvB,UAAM,SAAS,aAAa,MAAM,YAAY,CAAC,KAAK,OAAO;AAC3D,UAAM,UAAU,WAAW,OAAO,KAAK,OAAO,EAAE,SAAS,IAAI,UAAU;AAEvE,YAAQ,OAAO;AAAA,MACb,KAAK;AACH,kBAAU,QAAQ,MAAM,QAAQ,OAAO,IAAI,QAAQ,MAAM,MAAM;AAC/D;AAAA,MACF,KAAK;AACH,kBAAU,QAAQ,KAAK,QAAQ,OAAO,IAAI,QAAQ,KAAK,MAAM;AAC7D;AAAA,MACF,KAAK;AACH,kBAAU,QAAQ,KAAK,QAAQ,OAAO,IAAI,QAAQ,KAAK,MAAM;AAC7D;AAAA,MACF,KAAK;AACH,kBAAU,QAAQ,MAAM,QAAQ,OAAO,IAAI,QAAQ,MAAM,MAAM;AAC/D;AAAA,IACJ;AAAA,EACF;AAEA,SAAO;AAAA,IACL,OAAO,CAAC,SAAS,YAAY,MAAM,SAAS,SAAS,OAAO;AAAA,IAC5D,SAAS,CAAC,SAAS,YAAY,MAAM,WAAW,SAAS,OAAO;AAAA,IAChE,MAAM,CAAC,SAAS,YAAY,MAAM,QAAQ,SAAS,OAAO;AAAA,IAC1D,OAAO,CAAC,SAAS,YAAY,MAAM,SAAS,SAAS,OAAO;AAAA,EAC9D;AACF;AAEA,IAAM,oBAAoB,CAAC,OAA0B,SAAgD;AACnG,MAAI,MAAM,OAAQ,QAAO,KAAK;AAC9B,MAAI,OAAO,YAAY,eAAe,iBAAiB,QAAS,QAAO,MAAM;AAC7E,SAAO;AACT;AAEA,IAAM,oBAAoB,CACxB,OACA,SACoC;AACpC,QAAM,SACJ,MAAM,WACL,OAAO,YAAY,eAAe,iBAAiB,UAAU,MAAM,SAAS;AAC/E,QAAM,MACJ,OAAO,UAAU,WACb,QACA,iBAAiB,MACjB,MAAM,SAAS,IACf,MAAM;AACZ,SAAO,EAAE,QAAQ,IAAI;AACvB;AAEA,IAAM,kBAAkB,CAAC,UAA2B;AAClD,QAAM,aAAa;AACnB,MAAI,cAAc,OAAO,WAAW,UAAU,SAAU,QAAO,WAAW;AAC1E,SAAO;AACT;AAEA,IAAM,oBAAoB,CACxB,KACA,OACA,UACA,YACU;AACV,MAAI,MAAM,kBAAkB,EAAE,SAAS,QAAQ,UAAU,QAAQ,MAAM,CAAC;AACxE,QAAM,IAAI,aAAa,gBAAgB,KAAK,GAAG,EAAE,QAAQ,UAAU,QAAQ,SAAS,MAAM,CAAC;AAC7F;AAEA,IAAM,sBAAsB,CAAC,WAAyB,QAA8B;AAClF,SAAO,OAAO,OAA0B,SAA0C;AAChF,UAAM,EAAE,QAAQ,IAAI,IAAI,kBAAkB,OAAO,IAAI;AACrD,QAAI,UAAU;AACd,WAAO,MAAM;AACX,UAAI,MAAM,mBAAmB,EAAE,QAAQ,KAAK,SAAS,UAAU,GAAG,YAAY,YAAY,CAAC;AAC3F,YAAM,aAAa,IAAI,gBAAgB;AACvC,YAAM,YAAY,WAAW,MAAM,WAAW,MAAM,GAAG,kBAAkB;AACzE,YAAM,iBAAiB,kBAAkB,OAAO,IAAI;AACpD,UAAI,sBAA2C;AAE/C,UAAI,gBAAgB;AAClB,YAAI,eAAe,SAAS;AAC1B,qBAAW,MAAM;AAAA,QACnB,OAAO;AACL,gBAAM,UAAU,MAAM,WAAW,MAAM;AACvC,yBAAe,iBAAiB,SAAS,OAAO;AAChD,gCAAsB,MAAM,eAAe,oBAAoB,SAAS,OAAO;AAAA,QACjF;AAAA,MACF;AAEA,UAAI;AACF,cAAM,WAAW,MAAM,UAAU,OAAO,EAAE,GAAG,MAAM,QAAQ,WAAW,OAAO,CAAC;AAC9E,YAAI,SAAS,WAAW,kBAAmB,QAAO;AAElD,cAAM,aAAa,SAAS,QAAQ,IAAI,aAAa,KAAK;AAC1D,YAAI,QAAQ,wBAAwB;AAAA,UAClC;AAAA,UACA;AAAA,UACA,SAAS,UAAU;AAAA,UACnB,YAAY;AAAA,UACZ;AAAA,QACF,CAAC;AAED,YAAI,WAAW,aAAa;AAC1B,cAAI,MAAM,gCAAgC,EAAE,QAAQ,KAAK,UAAU,UAAU,EAAE,CAAC;AAChF,iBAAO;AAAA,QACT;AAEA,cAAM,UAAU,gBAAgB,UAAU,CAAC;AAC3C,YAAI,KAAK,qCAAqC;AAAA,UAC5C;AAAA,UACA;AAAA,UACA;AAAA,UACA,aAAa,UAAU;AAAA,UACvB,YAAY;AAAA,QACd,CAAC;AACD,cAAM,MAAM,OAAO;AACnB,mBAAW;AAAA,MACb,SAAS,OAAO;AACd,YAAI,WAAW,OAAO,SAAS;AAC7B,gBAAM,kBAAkB,gBAAgB,WAAW;AACnD,cAAI,iBAAiB;AACnB,gBAAI,QAAQ,6BAA6B,EAAE,QAAQ,KAAK,SAAS,UAAU,EAAE,CAAC;AAAA,UAChF,OAAO;AACL,gBAAI,MAAM,qBAAqB;AAAA,cAC7B;AAAA,cACA;AAAA,cACA,SAAS,UAAU;AAAA,cACnB,WAAW;AAAA,YACb,CAAC;AAAA,UACH;AAAA,QACF,OAAO;AACL,cAAI,MAAM,kBAAkB,EAAE,QAAQ,KAAK,SAAS,UAAU,GAAG,MAAM,CAAC;AAAA,QAC1E;AACA,cAAM;AAAA,MACR,UAAE;AACA,qBAAa,SAAS;AACtB,8BAAsB;AAAA,MACxB;AAAA,IACF;AAAA,EACF;AACF;AA8BO,IAAM,eAAN,cAA2B,MAAM;AAAA,EACtC;AAAA,EACA;AAAA,EAEA,YAAY,SAAiB,MAA+C;AAC1E,UAAM,OAAO;AACb,SAAK,OAAO;AACZ,SAAK,SAAS,MAAM;AACpB,SAAK,UAAU,MAAM;AAAA,EACvB;AACF;AAEO,IAAM,UAAN,MAEP;AAAA,EACU;AAAA,EACA;AAAA,EACA;AAAA,EACR;AAAA,EACA;AAAA,EACA;AAAA,EAEA,YAAY,QAAgB,OAA6B,CAAC,GAAG;AAC3D,UAAM,WAAW,KAAK,YAAY;AAClC,SAAK,MAAM,aAAa,QAAQ;AAChC,UAAM,UAAU;AAChB,SAAK,SAAS,EAAE,aAAa,OAAO;AACpC,UAAM,iBAAiB,oBAAoB,OAAO,KAAK,GAAG;AAC1D,SAAK,SAAS,aAAoB;AAAA,MAChC;AAAA,MACA,OAAO;AAAA,MACP,SAAS;AAAA,QACP,aAAa;AAAA,MACf;AAAA,IACF,CAAC;AAED,SAAK,YAAY;AAAA,MACf,KAAK,OAAO,eAA+E;AACzF,cAAM,EAAE,MAAM,OAAO,SAAS,IAAI,MAAM,KAAK,OAAO,IAAI,gBAAgB;AAAA,UACtE,QAAQ,EAAE,OAAO,EAAE,WAAW,GAAG,QAAQ,KAAK,OAAO;AAAA,QACvD,CAAC;AACD,YAAI,MAAO,mBAAkB,KAAK,KAAK,OAAO,UAAU,kBAAkB;AAC1E,eAAQ,QAAQ;AAAA,MAClB;AAAA,MACA,UAAU,OACR,UACgE;AAChE,cAAM,EAAE,MAAM,OAAO,SAAS,IAAI,MAAM,KAAK,OAAO,KAAK,yBAAyB;AAAA,UAChF,QAAQ,EAAE,QAAQ,KAAK,OAAO;AAAA,UAC9B,MAAM;AAAA,QACR,CAAC;AACD,YAAI,MAAO,mBAAkB,KAAK,KAAK,OAAO,UAAU,4BAA4B;AACpF,eAAQ,QAAQ;AAAA,MAClB;AAAA,MACA,QAAQ,OAAO,UAAqF;AAClG,cAAM,EAAE,MAAM,OAAO,SAAS,IAAI,MAAM,KAAK,OAAO,KAAK,gBAAgB;AAAA,UACvE,QAAQ,EAAE,QAAQ,KAAK,OAAO;AAAA,UAC9B,MAAM;AAAA,QACR,CAAC;AACD,YAAI,MAAO,mBAAkB,KAAK,KAAK,OAAO,UAAU,mBAAmB;AAC3E,eAAO;AAAA,MACT;AAAA,MACA,QAAQ,OAAO,UAAkF;AAC/F,cAAM,EAAE,MAAM,OAAO,SAAS,IAAI,MAAM,KAAK,OAAO,IAAI,gBAAgB;AAAA,UACtE,QAAQ,EAAE,QAAQ,KAAK,OAAO;AAAA,UAC9B,MAAM;AAAA,QACR,CAAC;AACD,YAAI,MAAO,mBAAkB,KAAK,KAAK,OAAO,UAAU,kBAAkB;AAC1E,eAAO;AAAA,MACT;AAAA,MACA,QAAQ,OAAO,eAAwD;AACrE,cAAM,EAAE,MAAM,OAAO,SAAS,IAAI,MAAM,KAAK,OAAO,OAAO,gBAAgB;AAAA,UACzE,QAAQ,EAAE,OAAO,EAAE,WAAW,GAAG,QAAQ,KAAK,OAAO;AAAA,QACvD,CAAC;AACD,YAAI,MAAO,mBAAkB,KAAK,KAAK,OAAO,UAAU,qBAAqB;AAC7E,eAAO;AAAA,MACT;AAAA,IACF;AAEA,SAAK,WAAW;AAAA,MACd,WAAW,OAAO,eAAmD;AACnE,cAAM,EAAE,MAAM,OAAO,SAAS,IAAI,MAAM,KAAK,OAAO,IAAI,sBAAsB;AAAA,UAC5E,QAAQ,EAAE,OAAO,EAAE,WAAW,GAAG,QAAQ,KAAK,OAAO;AAAA,QACvD,CAAC;AACD,YAAI,MAAO,mBAAkB,KAAK,KAAK,OAAO,UAAU,wBAAwB;AAChF,eAAO;AAAA,MACT;AAAA,IACF;AAEA,SAAK,QAAQ;AAAA,MACX,OAAO,OACL,UACgC;AAChC,cAAM,EAAE,MAAM,OAAO,SAAS,IAAI,MAAM,KAAK,OAAO,KAAK,aAAa;AAAA,UACpE,QAAQ,EAAE,QAAQ,KAAK,OAAO;AAAA,UAC9B,MAAM;AAAA,QACR,CAAC;AACD,YAAI,MAAO,mBAAkB,KAAK,KAAK,OAAO,UAAU,gBAAgB;AACxE,eAAO;AAAA,MACT;AAAA,MACA,YAAY,OACV,UACqC;AACrC,cAAM,EAAE,MAAM,OAAO,SAAS,IAAI,MAAM,KAAK,OAAO,KAAK,oBAAoB;AAAA,UAC3E,QAAQ,EAAE,QAAQ,KAAK,OAAO;AAAA,UAC9B,MAAM;AAAA,QACR,CAAC;AACD,YAAI,MAAO,mBAAkB,KAAK,KAAK,OAAO,UAAU,uBAAuB;AAC/E,eAAO;AAAA,MACT;AAAA,IACF;AAAA,EACF;AACF;","names":[]}
|