optropic 2.2.0 → 2.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +56 -8
- package/dist/index.d.cts +16 -2
- package/dist/index.d.ts +16 -2
- package/dist/index.js +56 -8
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -973,18 +973,20 @@ var SchemasResource = class {
|
|
|
973
973
|
// src/client.ts
|
|
974
974
|
var DEFAULT_BASE_URL = "https://api.optropic.com";
|
|
975
975
|
var DEFAULT_TIMEOUT = 3e4;
|
|
976
|
-
var SDK_VERSION = "2.
|
|
976
|
+
var SDK_VERSION = "2.3.0";
|
|
977
977
|
var SANDBOX_PREFIXES = ["optr_test_"];
|
|
978
978
|
var DEFAULT_RETRY_CONFIG = {
|
|
979
979
|
maxRetries: 3,
|
|
980
980
|
baseDelay: 1e3,
|
|
981
981
|
maxDelay: 1e4
|
|
982
982
|
};
|
|
983
|
+
var KEY_REDACT_RE = /(optr_(?:live|test)_)[a-zA-Z0-9_-]+/g;
|
|
983
984
|
var OptropicClient = class {
|
|
984
985
|
config;
|
|
985
986
|
baseUrl;
|
|
986
987
|
retryConfig;
|
|
987
988
|
_sandbox;
|
|
989
|
+
_debug;
|
|
988
990
|
assets;
|
|
989
991
|
audit;
|
|
990
992
|
compliance;
|
|
@@ -1003,6 +1005,7 @@ var OptropicClient = class {
|
|
|
1003
1005
|
...config,
|
|
1004
1006
|
timeout: config.timeout ?? DEFAULT_TIMEOUT
|
|
1005
1007
|
};
|
|
1008
|
+
this._debug = config.debug ?? false;
|
|
1006
1009
|
if (config.sandbox !== void 0) {
|
|
1007
1010
|
this._sandbox = config.sandbox;
|
|
1008
1011
|
} else {
|
|
@@ -1043,6 +1046,31 @@ var OptropicClient = class {
|
|
|
1043
1046
|
return this._sandbox ? "sandbox" : "live";
|
|
1044
1047
|
}
|
|
1045
1048
|
// ─────────────────────────────────────────────────────────────────────────
|
|
1049
|
+
// DEBUG LOGGING
|
|
1050
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
1051
|
+
redact(text) {
|
|
1052
|
+
return text.replace(KEY_REDACT_RE, "$1****");
|
|
1053
|
+
}
|
|
1054
|
+
logRequest(method, url, requestId, idempotencyKey) {
|
|
1055
|
+
if (!this._debug) return;
|
|
1056
|
+
const parts = [`${method} ${this.redact(url)}`, `req=${requestId}`];
|
|
1057
|
+
if (idempotencyKey) parts.push(`idempotency=${idempotencyKey}`);
|
|
1058
|
+
console.log(`[optropic] ${parts.join(" ")}`);
|
|
1059
|
+
}
|
|
1060
|
+
logResponse(method, path, status, durationMs, requestId, serverRequestId, attempt) {
|
|
1061
|
+
if (!this._debug) return;
|
|
1062
|
+
const parts = [`${method} ${path} \u2192 ${status} (${Math.round(durationMs)}ms)`, `req=${requestId}`];
|
|
1063
|
+
if (serverRequestId) parts.push(`server_req=${serverRequestId}`);
|
|
1064
|
+
if (attempt > 0) parts.push(`attempt=${attempt + 1}`);
|
|
1065
|
+
console.log(`[optropic] ${parts.join(" ")}`);
|
|
1066
|
+
}
|
|
1067
|
+
logRetry(method, path, attempt, delay, reason) {
|
|
1068
|
+
if (!this._debug) return;
|
|
1069
|
+
console.log(
|
|
1070
|
+
`[optropic] ${method} ${path} retry #${attempt + 1} in ${(delay / 1e3).toFixed(1)}s (${reason})`
|
|
1071
|
+
);
|
|
1072
|
+
}
|
|
1073
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
1046
1074
|
// PRIVATE METHODS
|
|
1047
1075
|
// ─────────────────────────────────────────────────────────────────────────
|
|
1048
1076
|
isValidApiKey(apiKey) {
|
|
@@ -1051,20 +1079,26 @@ var OptropicClient = class {
|
|
|
1051
1079
|
async request(options) {
|
|
1052
1080
|
const { method, path, body, headers = {}, timeout = this.config.timeout, idempotencyKey } = options;
|
|
1053
1081
|
const url = `${this.baseUrl}${path}`;
|
|
1082
|
+
const requestId = crypto.randomUUID();
|
|
1054
1083
|
const requestHeaders = {
|
|
1055
1084
|
"Content-Type": "application/json",
|
|
1056
1085
|
"Accept": "application/json",
|
|
1057
1086
|
"x-api-key": this.config.apiKey,
|
|
1058
1087
|
"X-SDK-Version": SDK_VERSION,
|
|
1059
1088
|
"X-SDK-Language": "typescript",
|
|
1089
|
+
"X-Request-ID": requestId,
|
|
1060
1090
|
...this.config.headers,
|
|
1061
1091
|
...headers
|
|
1062
1092
|
};
|
|
1093
|
+
let effectiveIdempotencyKey;
|
|
1063
1094
|
if (idempotencyKey) {
|
|
1064
1095
|
requestHeaders["Idempotency-Key"] = idempotencyKey;
|
|
1096
|
+
effectiveIdempotencyKey = idempotencyKey;
|
|
1065
1097
|
} else if (["POST", "PUT", "PATCH"].includes(method)) {
|
|
1066
|
-
|
|
1098
|
+
effectiveIdempotencyKey = crypto.randomUUID();
|
|
1099
|
+
requestHeaders["Idempotency-Key"] = effectiveIdempotencyKey;
|
|
1067
1100
|
}
|
|
1101
|
+
this.logRequest(method, url, requestId, effectiveIdempotencyKey);
|
|
1068
1102
|
let lastError = null;
|
|
1069
1103
|
let attempt = 0;
|
|
1070
1104
|
while (attempt <= this.retryConfig.maxRetries) {
|
|
@@ -1074,7 +1108,10 @@ var OptropicClient = class {
|
|
|
1074
1108
|
method,
|
|
1075
1109
|
requestHeaders,
|
|
1076
1110
|
body,
|
|
1077
|
-
timeout
|
|
1111
|
+
timeout,
|
|
1112
|
+
requestId,
|
|
1113
|
+
path,
|
|
1114
|
+
attempt
|
|
1078
1115
|
);
|
|
1079
1116
|
return response;
|
|
1080
1117
|
} catch (error) {
|
|
@@ -1092,8 +1129,12 @@ var OptropicClient = class {
|
|
|
1092
1129
|
const jitter = baseDelay * 0.5 * Math.random();
|
|
1093
1130
|
const delay = baseDelay + jitter;
|
|
1094
1131
|
if (error instanceof RateLimitedError) {
|
|
1095
|
-
|
|
1132
|
+
const retryDelay = error.retryAfter * 1e3;
|
|
1133
|
+
this.logRetry(method, path, attempt, retryDelay, "rate_limited");
|
|
1134
|
+
await this.sleep(retryDelay);
|
|
1096
1135
|
} else {
|
|
1136
|
+
const statusCode = error instanceof OptropicError ? error.statusCode : 0;
|
|
1137
|
+
this.logRetry(method, path, attempt, delay, `status=${statusCode}`);
|
|
1097
1138
|
await this.sleep(delay);
|
|
1098
1139
|
}
|
|
1099
1140
|
attempt++;
|
|
@@ -1101,9 +1142,10 @@ var OptropicClient = class {
|
|
|
1101
1142
|
}
|
|
1102
1143
|
throw lastError ?? new OptropicError("UNKNOWN_ERROR", "Request failed");
|
|
1103
1144
|
}
|
|
1104
|
-
async executeRequest(url, method, headers, body, timeout) {
|
|
1145
|
+
async executeRequest(url, method, headers, body, timeout, requestId, path, attempt) {
|
|
1105
1146
|
const controller = new AbortController();
|
|
1106
1147
|
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
|
1148
|
+
const t0 = performance.now();
|
|
1107
1149
|
try {
|
|
1108
1150
|
const response = await fetch(url, {
|
|
1109
1151
|
method,
|
|
@@ -1112,7 +1154,9 @@ var OptropicClient = class {
|
|
|
1112
1154
|
signal: controller.signal
|
|
1113
1155
|
});
|
|
1114
1156
|
clearTimeout(timeoutId);
|
|
1115
|
-
const
|
|
1157
|
+
const durationMs = performance.now() - t0;
|
|
1158
|
+
const serverRequestId = response.headers.get("x-request-id") ?? "";
|
|
1159
|
+
this.logResponse(method, path, response.status, durationMs, requestId, serverRequestId, attempt);
|
|
1116
1160
|
if (!response.ok) {
|
|
1117
1161
|
let errorBody;
|
|
1118
1162
|
try {
|
|
@@ -1135,7 +1179,7 @@ var OptropicClient = class {
|
|
|
1135
1179
|
code: errorBody.code,
|
|
1136
1180
|
message: errorBody.message,
|
|
1137
1181
|
details: errorBody.details,
|
|
1138
|
-
requestId
|
|
1182
|
+
requestId: serverRequestId || requestId
|
|
1139
1183
|
});
|
|
1140
1184
|
}
|
|
1141
1185
|
if (response.status === 204) {
|
|
@@ -1161,8 +1205,12 @@ var OptropicClient = class {
|
|
|
1161
1205
|
}
|
|
1162
1206
|
if (error instanceof Error) {
|
|
1163
1207
|
if (error.name === "AbortError") {
|
|
1208
|
+
const durationMs2 = performance.now() - t0;
|
|
1209
|
+
this.logResponse(method, path, 408, durationMs2, requestId, "", attempt);
|
|
1164
1210
|
throw new TimeoutError(timeout);
|
|
1165
1211
|
}
|
|
1212
|
+
const durationMs = performance.now() - t0;
|
|
1213
|
+
this.logResponse(method, path, 0, durationMs, requestId, "", attempt);
|
|
1166
1214
|
throw new NetworkError(error.message, { cause: error });
|
|
1167
1215
|
}
|
|
1168
1216
|
throw new OptropicError("UNKNOWN_ERROR", "An unexpected error occurred", {
|
|
@@ -1421,7 +1469,7 @@ async function verifyWebhookSignature(options) {
|
|
|
1421
1469
|
}
|
|
1422
1470
|
|
|
1423
1471
|
// src/index.ts
|
|
1424
|
-
var SDK_VERSION2 = "2.
|
|
1472
|
+
var SDK_VERSION2 = "2.3.0";
|
|
1425
1473
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1426
1474
|
0 && (module.exports = {
|
|
1427
1475
|
AssetsResource,
|
package/dist/index.d.cts
CHANGED
|
@@ -44,6 +44,12 @@ interface OptropicConfig {
|
|
|
44
44
|
* Retry configuration for failed requests.
|
|
45
45
|
*/
|
|
46
46
|
readonly retry?: RetryConfig;
|
|
47
|
+
/**
|
|
48
|
+
* Enable debug logging. When ``true``, every request and response
|
|
49
|
+
* is logged to the console with secrets redacted.
|
|
50
|
+
* @default false
|
|
51
|
+
*/
|
|
52
|
+
readonly debug?: boolean;
|
|
47
53
|
}
|
|
48
54
|
/**
|
|
49
55
|
* Retry configuration for network requests.
|
|
@@ -718,6 +724,7 @@ interface RequestOptions {
|
|
|
718
724
|
path: string;
|
|
719
725
|
body?: unknown;
|
|
720
726
|
headers?: Record<string, string>;
|
|
727
|
+
/** Per-operation timeout in ms. Overrides the client-level default. */
|
|
721
728
|
timeout?: number;
|
|
722
729
|
/** Idempotency key for safe mutation retries. Auto-generated for POST/PUT/PATCH if omitted. */
|
|
723
730
|
idempotencyKey?: string;
|
|
@@ -732,6 +739,7 @@ type RequestFn = <T>(options: RequestOptions) => Promise<T>;
|
|
|
732
739
|
*
|
|
733
740
|
* const client = new OptropicClient({
|
|
734
741
|
* apiKey: 'optr_live_xxxxxxxxxxxx',
|
|
742
|
+
* debug: true, // logs every request/response
|
|
735
743
|
* });
|
|
736
744
|
*
|
|
737
745
|
* // Create an asset
|
|
@@ -740,7 +748,7 @@ type RequestFn = <T>(options: RequestOptions) => Promise<T>;
|
|
|
740
748
|
* serial: 'SN001',
|
|
741
749
|
* });
|
|
742
750
|
*
|
|
743
|
-
* // Verify an asset
|
|
751
|
+
* // Verify an asset (with per-operation timeout)
|
|
744
752
|
* const result = await client.assets.verify(asset.id);
|
|
745
753
|
* ```
|
|
746
754
|
*/
|
|
@@ -749,6 +757,7 @@ declare class OptropicClient {
|
|
|
749
757
|
private readonly baseUrl;
|
|
750
758
|
private readonly retryConfig;
|
|
751
759
|
private readonly _sandbox;
|
|
760
|
+
private readonly _debug;
|
|
752
761
|
readonly assets: AssetsResource;
|
|
753
762
|
readonly audit: AuditResource;
|
|
754
763
|
readonly compliance: ComplianceResource;
|
|
@@ -764,6 +773,10 @@ declare class OptropicClient {
|
|
|
764
773
|
get isLive(): boolean;
|
|
765
774
|
/** Returns 'sandbox' or 'live'. */
|
|
766
775
|
get environment(): 'sandbox' | 'live';
|
|
776
|
+
private redact;
|
|
777
|
+
private logRequest;
|
|
778
|
+
private logResponse;
|
|
779
|
+
private logRetry;
|
|
767
780
|
private isValidApiKey;
|
|
768
781
|
private request;
|
|
769
782
|
private executeRequest;
|
|
@@ -781,6 +794,7 @@ declare class OptropicClient {
|
|
|
781
794
|
*
|
|
782
795
|
* const client = createClient({
|
|
783
796
|
* apiKey: process.env.OPTROPIC_API_KEY!,
|
|
797
|
+
* debug: true,
|
|
784
798
|
* });
|
|
785
799
|
* ```
|
|
786
800
|
*/
|
|
@@ -1310,6 +1324,6 @@ declare function createErrorFromResponse(statusCode: number, body: {
|
|
|
1310
1324
|
requestId?: string;
|
|
1311
1325
|
}): OptropicError;
|
|
1312
1326
|
|
|
1313
|
-
declare const SDK_VERSION = "2.
|
|
1327
|
+
declare const SDK_VERSION = "2.3.0";
|
|
1314
1328
|
|
|
1315
1329
|
export { type ApiKey, type Asset, AssetsResource, type AuditEvent, AuditResource, AuthenticationError, type BatchCreateParams, type BatchCreateResult, BatchNotFoundError, type BatteryPassportData, type ChainVerifyResult, CodeNotFoundError, type ComplianceConfig, ComplianceResource, type ConformityDeclaration, type CreateAssetParams, type CreateAuditEventParams, type CreateKeyParams, type CreateKeyResult, type CreateKeysetParams, type CreateSchemaParams, type DPPCategory, type DPPMetadata, type Document, type DocumentVerifyResult, DocumentsResource, type EnrollDocumentParams, type ErrorCode, type ExportParams, type ExportResult, type FiberEntry, type FilterHeader, type FilterSyncResult, InvalidCodeError, InvalidGTINError, InvalidSerialError, KeysResource, type Keyset, KeysetsResource, type ListAssetsParams, type ListAssetsResponse, type ListAuditParams, type ListAuditResponse, type ListDocumentsParams, type ListDocumentsResponse, type ListKeysetsParams, type ListKeysetsResponse, type ListProvenanceParams, type ListProvenanceResponse, type ListSchemasParams, type ListSchemasResponse, type MerkleProof, type MerkleRoot, NetworkError, type OfflineVerifyOptions, type OfflineVerifyResult, OptropicClient, type OptropicConfig, OptropicError, type ProvenanceChain, type ProvenanceEvent, type ProvenanceEventType, type ProvenanceLocation, ProvenanceResource, QuotaExceededError, RateLimitedError, type RecordProvenanceParams, type RequestFn, type RetryConfig, RevokedCodeError, SDK_VERSION, type SchemaValidationResult, SchemasResource, ServiceUnavailableError, StaleFilterError, type SubstanceEntry, type TextilePassportData, TimeoutError, type UpdateSchemaParams, type VerifyDocumentParams, type VerifyProvenanceResult, type VerifyResult, type VerticalSchema, type WebhookVerifyOptions, type WebhookVerifyResult, buildDPPConfig, createClient, createErrorFromResponse, parseFilterHeader, parseSaltsHeader, validateDPPMetadata, verifyOffline, verifyWebhookSignature };
|
package/dist/index.d.ts
CHANGED
|
@@ -44,6 +44,12 @@ interface OptropicConfig {
|
|
|
44
44
|
* Retry configuration for failed requests.
|
|
45
45
|
*/
|
|
46
46
|
readonly retry?: RetryConfig;
|
|
47
|
+
/**
|
|
48
|
+
* Enable debug logging. When ``true``, every request and response
|
|
49
|
+
* is logged to the console with secrets redacted.
|
|
50
|
+
* @default false
|
|
51
|
+
*/
|
|
52
|
+
readonly debug?: boolean;
|
|
47
53
|
}
|
|
48
54
|
/**
|
|
49
55
|
* Retry configuration for network requests.
|
|
@@ -718,6 +724,7 @@ interface RequestOptions {
|
|
|
718
724
|
path: string;
|
|
719
725
|
body?: unknown;
|
|
720
726
|
headers?: Record<string, string>;
|
|
727
|
+
/** Per-operation timeout in ms. Overrides the client-level default. */
|
|
721
728
|
timeout?: number;
|
|
722
729
|
/** Idempotency key for safe mutation retries. Auto-generated for POST/PUT/PATCH if omitted. */
|
|
723
730
|
idempotencyKey?: string;
|
|
@@ -732,6 +739,7 @@ type RequestFn = <T>(options: RequestOptions) => Promise<T>;
|
|
|
732
739
|
*
|
|
733
740
|
* const client = new OptropicClient({
|
|
734
741
|
* apiKey: 'optr_live_xxxxxxxxxxxx',
|
|
742
|
+
* debug: true, // logs every request/response
|
|
735
743
|
* });
|
|
736
744
|
*
|
|
737
745
|
* // Create an asset
|
|
@@ -740,7 +748,7 @@ type RequestFn = <T>(options: RequestOptions) => Promise<T>;
|
|
|
740
748
|
* serial: 'SN001',
|
|
741
749
|
* });
|
|
742
750
|
*
|
|
743
|
-
* // Verify an asset
|
|
751
|
+
* // Verify an asset (with per-operation timeout)
|
|
744
752
|
* const result = await client.assets.verify(asset.id);
|
|
745
753
|
* ```
|
|
746
754
|
*/
|
|
@@ -749,6 +757,7 @@ declare class OptropicClient {
|
|
|
749
757
|
private readonly baseUrl;
|
|
750
758
|
private readonly retryConfig;
|
|
751
759
|
private readonly _sandbox;
|
|
760
|
+
private readonly _debug;
|
|
752
761
|
readonly assets: AssetsResource;
|
|
753
762
|
readonly audit: AuditResource;
|
|
754
763
|
readonly compliance: ComplianceResource;
|
|
@@ -764,6 +773,10 @@ declare class OptropicClient {
|
|
|
764
773
|
get isLive(): boolean;
|
|
765
774
|
/** Returns 'sandbox' or 'live'. */
|
|
766
775
|
get environment(): 'sandbox' | 'live';
|
|
776
|
+
private redact;
|
|
777
|
+
private logRequest;
|
|
778
|
+
private logResponse;
|
|
779
|
+
private logRetry;
|
|
767
780
|
private isValidApiKey;
|
|
768
781
|
private request;
|
|
769
782
|
private executeRequest;
|
|
@@ -781,6 +794,7 @@ declare class OptropicClient {
|
|
|
781
794
|
*
|
|
782
795
|
* const client = createClient({
|
|
783
796
|
* apiKey: process.env.OPTROPIC_API_KEY!,
|
|
797
|
+
* debug: true,
|
|
784
798
|
* });
|
|
785
799
|
* ```
|
|
786
800
|
*/
|
|
@@ -1310,6 +1324,6 @@ declare function createErrorFromResponse(statusCode: number, body: {
|
|
|
1310
1324
|
requestId?: string;
|
|
1311
1325
|
}): OptropicError;
|
|
1312
1326
|
|
|
1313
|
-
declare const SDK_VERSION = "2.
|
|
1327
|
+
declare const SDK_VERSION = "2.3.0";
|
|
1314
1328
|
|
|
1315
1329
|
export { type ApiKey, type Asset, AssetsResource, type AuditEvent, AuditResource, AuthenticationError, type BatchCreateParams, type BatchCreateResult, BatchNotFoundError, type BatteryPassportData, type ChainVerifyResult, CodeNotFoundError, type ComplianceConfig, ComplianceResource, type ConformityDeclaration, type CreateAssetParams, type CreateAuditEventParams, type CreateKeyParams, type CreateKeyResult, type CreateKeysetParams, type CreateSchemaParams, type DPPCategory, type DPPMetadata, type Document, type DocumentVerifyResult, DocumentsResource, type EnrollDocumentParams, type ErrorCode, type ExportParams, type ExportResult, type FiberEntry, type FilterHeader, type FilterSyncResult, InvalidCodeError, InvalidGTINError, InvalidSerialError, KeysResource, type Keyset, KeysetsResource, type ListAssetsParams, type ListAssetsResponse, type ListAuditParams, type ListAuditResponse, type ListDocumentsParams, type ListDocumentsResponse, type ListKeysetsParams, type ListKeysetsResponse, type ListProvenanceParams, type ListProvenanceResponse, type ListSchemasParams, type ListSchemasResponse, type MerkleProof, type MerkleRoot, NetworkError, type OfflineVerifyOptions, type OfflineVerifyResult, OptropicClient, type OptropicConfig, OptropicError, type ProvenanceChain, type ProvenanceEvent, type ProvenanceEventType, type ProvenanceLocation, ProvenanceResource, QuotaExceededError, RateLimitedError, type RecordProvenanceParams, type RequestFn, type RetryConfig, RevokedCodeError, SDK_VERSION, type SchemaValidationResult, SchemasResource, ServiceUnavailableError, StaleFilterError, type SubstanceEntry, type TextilePassportData, TimeoutError, type UpdateSchemaParams, type VerifyDocumentParams, type VerifyProvenanceResult, type VerifyResult, type VerticalSchema, type WebhookVerifyOptions, type WebhookVerifyResult, buildDPPConfig, createClient, createErrorFromResponse, parseFilterHeader, parseSaltsHeader, validateDPPMetadata, verifyOffline, verifyWebhookSignature };
|
package/dist/index.js
CHANGED
|
@@ -906,18 +906,20 @@ var SchemasResource = class {
|
|
|
906
906
|
// src/client.ts
|
|
907
907
|
var DEFAULT_BASE_URL = "https://api.optropic.com";
|
|
908
908
|
var DEFAULT_TIMEOUT = 3e4;
|
|
909
|
-
var SDK_VERSION = "2.
|
|
909
|
+
var SDK_VERSION = "2.3.0";
|
|
910
910
|
var SANDBOX_PREFIXES = ["optr_test_"];
|
|
911
911
|
var DEFAULT_RETRY_CONFIG = {
|
|
912
912
|
maxRetries: 3,
|
|
913
913
|
baseDelay: 1e3,
|
|
914
914
|
maxDelay: 1e4
|
|
915
915
|
};
|
|
916
|
+
var KEY_REDACT_RE = /(optr_(?:live|test)_)[a-zA-Z0-9_-]+/g;
|
|
916
917
|
var OptropicClient = class {
|
|
917
918
|
config;
|
|
918
919
|
baseUrl;
|
|
919
920
|
retryConfig;
|
|
920
921
|
_sandbox;
|
|
922
|
+
_debug;
|
|
921
923
|
assets;
|
|
922
924
|
audit;
|
|
923
925
|
compliance;
|
|
@@ -936,6 +938,7 @@ var OptropicClient = class {
|
|
|
936
938
|
...config,
|
|
937
939
|
timeout: config.timeout ?? DEFAULT_TIMEOUT
|
|
938
940
|
};
|
|
941
|
+
this._debug = config.debug ?? false;
|
|
939
942
|
if (config.sandbox !== void 0) {
|
|
940
943
|
this._sandbox = config.sandbox;
|
|
941
944
|
} else {
|
|
@@ -976,6 +979,31 @@ var OptropicClient = class {
|
|
|
976
979
|
return this._sandbox ? "sandbox" : "live";
|
|
977
980
|
}
|
|
978
981
|
// ─────────────────────────────────────────────────────────────────────────
|
|
982
|
+
// DEBUG LOGGING
|
|
983
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
984
|
+
redact(text) {
|
|
985
|
+
return text.replace(KEY_REDACT_RE, "$1****");
|
|
986
|
+
}
|
|
987
|
+
logRequest(method, url, requestId, idempotencyKey) {
|
|
988
|
+
if (!this._debug) return;
|
|
989
|
+
const parts = [`${method} ${this.redact(url)}`, `req=${requestId}`];
|
|
990
|
+
if (idempotencyKey) parts.push(`idempotency=${idempotencyKey}`);
|
|
991
|
+
console.log(`[optropic] ${parts.join(" ")}`);
|
|
992
|
+
}
|
|
993
|
+
logResponse(method, path, status, durationMs, requestId, serverRequestId, attempt) {
|
|
994
|
+
if (!this._debug) return;
|
|
995
|
+
const parts = [`${method} ${path} \u2192 ${status} (${Math.round(durationMs)}ms)`, `req=${requestId}`];
|
|
996
|
+
if (serverRequestId) parts.push(`server_req=${serverRequestId}`);
|
|
997
|
+
if (attempt > 0) parts.push(`attempt=${attempt + 1}`);
|
|
998
|
+
console.log(`[optropic] ${parts.join(" ")}`);
|
|
999
|
+
}
|
|
1000
|
+
logRetry(method, path, attempt, delay, reason) {
|
|
1001
|
+
if (!this._debug) return;
|
|
1002
|
+
console.log(
|
|
1003
|
+
`[optropic] ${method} ${path} retry #${attempt + 1} in ${(delay / 1e3).toFixed(1)}s (${reason})`
|
|
1004
|
+
);
|
|
1005
|
+
}
|
|
1006
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
979
1007
|
// PRIVATE METHODS
|
|
980
1008
|
// ─────────────────────────────────────────────────────────────────────────
|
|
981
1009
|
isValidApiKey(apiKey) {
|
|
@@ -984,20 +1012,26 @@ var OptropicClient = class {
|
|
|
984
1012
|
async request(options) {
|
|
985
1013
|
const { method, path, body, headers = {}, timeout = this.config.timeout, idempotencyKey } = options;
|
|
986
1014
|
const url = `${this.baseUrl}${path}`;
|
|
1015
|
+
const requestId = crypto.randomUUID();
|
|
987
1016
|
const requestHeaders = {
|
|
988
1017
|
"Content-Type": "application/json",
|
|
989
1018
|
"Accept": "application/json",
|
|
990
1019
|
"x-api-key": this.config.apiKey,
|
|
991
1020
|
"X-SDK-Version": SDK_VERSION,
|
|
992
1021
|
"X-SDK-Language": "typescript",
|
|
1022
|
+
"X-Request-ID": requestId,
|
|
993
1023
|
...this.config.headers,
|
|
994
1024
|
...headers
|
|
995
1025
|
};
|
|
1026
|
+
let effectiveIdempotencyKey;
|
|
996
1027
|
if (idempotencyKey) {
|
|
997
1028
|
requestHeaders["Idempotency-Key"] = idempotencyKey;
|
|
1029
|
+
effectiveIdempotencyKey = idempotencyKey;
|
|
998
1030
|
} else if (["POST", "PUT", "PATCH"].includes(method)) {
|
|
999
|
-
|
|
1031
|
+
effectiveIdempotencyKey = crypto.randomUUID();
|
|
1032
|
+
requestHeaders["Idempotency-Key"] = effectiveIdempotencyKey;
|
|
1000
1033
|
}
|
|
1034
|
+
this.logRequest(method, url, requestId, effectiveIdempotencyKey);
|
|
1001
1035
|
let lastError = null;
|
|
1002
1036
|
let attempt = 0;
|
|
1003
1037
|
while (attempt <= this.retryConfig.maxRetries) {
|
|
@@ -1007,7 +1041,10 @@ var OptropicClient = class {
|
|
|
1007
1041
|
method,
|
|
1008
1042
|
requestHeaders,
|
|
1009
1043
|
body,
|
|
1010
|
-
timeout
|
|
1044
|
+
timeout,
|
|
1045
|
+
requestId,
|
|
1046
|
+
path,
|
|
1047
|
+
attempt
|
|
1011
1048
|
);
|
|
1012
1049
|
return response;
|
|
1013
1050
|
} catch (error) {
|
|
@@ -1025,8 +1062,12 @@ var OptropicClient = class {
|
|
|
1025
1062
|
const jitter = baseDelay * 0.5 * Math.random();
|
|
1026
1063
|
const delay = baseDelay + jitter;
|
|
1027
1064
|
if (error instanceof RateLimitedError) {
|
|
1028
|
-
|
|
1065
|
+
const retryDelay = error.retryAfter * 1e3;
|
|
1066
|
+
this.logRetry(method, path, attempt, retryDelay, "rate_limited");
|
|
1067
|
+
await this.sleep(retryDelay);
|
|
1029
1068
|
} else {
|
|
1069
|
+
const statusCode = error instanceof OptropicError ? error.statusCode : 0;
|
|
1070
|
+
this.logRetry(method, path, attempt, delay, `status=${statusCode}`);
|
|
1030
1071
|
await this.sleep(delay);
|
|
1031
1072
|
}
|
|
1032
1073
|
attempt++;
|
|
@@ -1034,9 +1075,10 @@ var OptropicClient = class {
|
|
|
1034
1075
|
}
|
|
1035
1076
|
throw lastError ?? new OptropicError("UNKNOWN_ERROR", "Request failed");
|
|
1036
1077
|
}
|
|
1037
|
-
async executeRequest(url, method, headers, body, timeout) {
|
|
1078
|
+
async executeRequest(url, method, headers, body, timeout, requestId, path, attempt) {
|
|
1038
1079
|
const controller = new AbortController();
|
|
1039
1080
|
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
|
1081
|
+
const t0 = performance.now();
|
|
1040
1082
|
try {
|
|
1041
1083
|
const response = await fetch(url, {
|
|
1042
1084
|
method,
|
|
@@ -1045,7 +1087,9 @@ var OptropicClient = class {
|
|
|
1045
1087
|
signal: controller.signal
|
|
1046
1088
|
});
|
|
1047
1089
|
clearTimeout(timeoutId);
|
|
1048
|
-
const
|
|
1090
|
+
const durationMs = performance.now() - t0;
|
|
1091
|
+
const serverRequestId = response.headers.get("x-request-id") ?? "";
|
|
1092
|
+
this.logResponse(method, path, response.status, durationMs, requestId, serverRequestId, attempt);
|
|
1049
1093
|
if (!response.ok) {
|
|
1050
1094
|
let errorBody;
|
|
1051
1095
|
try {
|
|
@@ -1068,7 +1112,7 @@ var OptropicClient = class {
|
|
|
1068
1112
|
code: errorBody.code,
|
|
1069
1113
|
message: errorBody.message,
|
|
1070
1114
|
details: errorBody.details,
|
|
1071
|
-
requestId
|
|
1115
|
+
requestId: serverRequestId || requestId
|
|
1072
1116
|
});
|
|
1073
1117
|
}
|
|
1074
1118
|
if (response.status === 204) {
|
|
@@ -1094,8 +1138,12 @@ var OptropicClient = class {
|
|
|
1094
1138
|
}
|
|
1095
1139
|
if (error instanceof Error) {
|
|
1096
1140
|
if (error.name === "AbortError") {
|
|
1141
|
+
const durationMs2 = performance.now() - t0;
|
|
1142
|
+
this.logResponse(method, path, 408, durationMs2, requestId, "", attempt);
|
|
1097
1143
|
throw new TimeoutError(timeout);
|
|
1098
1144
|
}
|
|
1145
|
+
const durationMs = performance.now() - t0;
|
|
1146
|
+
this.logResponse(method, path, 0, durationMs, requestId, "", attempt);
|
|
1099
1147
|
throw new NetworkError(error.message, { cause: error });
|
|
1100
1148
|
}
|
|
1101
1149
|
throw new OptropicError("UNKNOWN_ERROR", "An unexpected error occurred", {
|
|
@@ -1354,7 +1402,7 @@ async function verifyWebhookSignature(options) {
|
|
|
1354
1402
|
}
|
|
1355
1403
|
|
|
1356
1404
|
// src/index.ts
|
|
1357
|
-
var SDK_VERSION2 = "2.
|
|
1405
|
+
var SDK_VERSION2 = "2.3.0";
|
|
1358
1406
|
export {
|
|
1359
1407
|
AssetsResource,
|
|
1360
1408
|
AuditResource,
|