@crosspost/sdk 0.1.8 → 0.1.9
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 +93 -98
- package/dist/index.d.cts +0 -9
- package/dist/index.d.ts +0 -9
- package/dist/index.js +93 -98
- package/package.json +1 -1
- package/src/core/client.ts +0 -2
- package/src/core/config.ts +0 -6
- package/src/core/request.ts +110 -127
package/dist/index.cjs
CHANGED
@@ -4215,6 +4215,7 @@ var ApiErrorCode = /* @__PURE__ */ ((ApiErrorCode2) => {
|
|
4215
4215
|
ApiErrorCode2["POST_DELETION_FAILED"] = "POST_DELETION_FAILED";
|
4216
4216
|
ApiErrorCode2["POST_INTERACTION_FAILED"] = "POST_INTERACTION_FAILED";
|
4217
4217
|
ApiErrorCode2["NETWORK_ERROR"] = "NETWORK_ERROR";
|
4218
|
+
ApiErrorCode2["INVALID_RESPONSE"] = "INVALID_RESPONSE";
|
4218
4219
|
return ApiErrorCode2;
|
4219
4220
|
})(ApiErrorCode || {});
|
4220
4221
|
var ApiErrorCodeSchema = z.enum(Object.values(ApiErrorCode));
|
@@ -4294,7 +4295,11 @@ var errorCodeToStatusCode = {
|
|
4294
4295
|
[
|
4295
4296
|
"NETWORK_ERROR"
|
4296
4297
|
/* NETWORK_ERROR */
|
4297
|
-
]: 503
|
4298
|
+
]: 503,
|
4299
|
+
[
|
4300
|
+
"INVALID_RESPONSE"
|
4301
|
+
/* INVALID_RESPONSE */
|
4302
|
+
]: 500
|
4298
4303
|
};
|
4299
4304
|
var ErrorDetailSchema = z.object({
|
4300
4305
|
message: z.string().describe("Human-readable error message"),
|
@@ -4983,103 +4988,96 @@ async function makeRequest(method, path, options, data, query) {
|
|
4983
4988
|
const context = {
|
4984
4989
|
method,
|
4985
4990
|
path,
|
4986
|
-
url
|
4987
|
-
retries: options.retries
|
4991
|
+
url
|
4988
4992
|
};
|
4989
|
-
|
4990
|
-
|
4991
|
-
|
4992
|
-
|
4993
|
-
|
4993
|
+
const controller = new AbortController();
|
4994
|
+
const timeoutId = setTimeout(() => controller.abort(), options.timeout);
|
4995
|
+
try {
|
4996
|
+
const headers = {
|
4997
|
+
"Content-Type": "application/json",
|
4998
|
+
"Accept": "application/json"
|
4999
|
+
};
|
5000
|
+
if (method === "GET") {
|
5001
|
+
const nearAccount = options.nearAccount || options.nearAuthData?.account_id;
|
5002
|
+
if (!nearAccount) {
|
5003
|
+
throw new CrosspostError(
|
5004
|
+
"No NEAR account provided for GET request",
|
5005
|
+
ApiErrorCode.UNAUTHORIZED,
|
5006
|
+
401
|
5007
|
+
);
|
5008
|
+
}
|
5009
|
+
headers["X-Near-Account"] = nearAccount;
|
5010
|
+
} else {
|
5011
|
+
if (!options.nearAuthData) {
|
5012
|
+
throw new CrosspostError(
|
5013
|
+
"NEAR authentication data required for non-GET request",
|
5014
|
+
ApiErrorCode.UNAUTHORIZED,
|
5015
|
+
401
|
5016
|
+
);
|
5017
|
+
}
|
5018
|
+
headers["Authorization"] = `Bearer ${(0, import_near_sign_verify.createAuthToken)(options.nearAuthData)}`;
|
5019
|
+
}
|
5020
|
+
const requestOptions = {
|
5021
|
+
method,
|
5022
|
+
headers,
|
5023
|
+
body: method !== "GET" && data ? JSON.stringify(data) : void 0,
|
5024
|
+
signal: controller.signal
|
5025
|
+
};
|
5026
|
+
const response = await fetch(url, requestOptions);
|
5027
|
+
clearTimeout(timeoutId);
|
5028
|
+
let responseData;
|
5029
|
+
try {
|
5030
|
+
responseData = await response.json();
|
5031
|
+
} catch (jsonError) {
|
5032
|
+
let responseText;
|
4994
5033
|
try {
|
4995
|
-
|
4996
|
-
|
4997
|
-
"Accept": "application/json"
|
4998
|
-
};
|
4999
|
-
if (method === "GET") {
|
5000
|
-
const nearAccount = options.nearAccount || options.nearAuthData?.account_id;
|
5001
|
-
if (!nearAccount) {
|
5002
|
-
throw new CrosspostError(
|
5003
|
-
"No NEAR account provided for GET request",
|
5004
|
-
ApiErrorCode.UNAUTHORIZED,
|
5005
|
-
401
|
5006
|
-
);
|
5007
|
-
}
|
5008
|
-
headers["X-Near-Account"] = nearAccount;
|
5009
|
-
} else {
|
5010
|
-
if (!options.nearAuthData) {
|
5011
|
-
throw new CrosspostError(
|
5012
|
-
"NEAR authentication data required for non-GET request",
|
5013
|
-
ApiErrorCode.UNAUTHORIZED,
|
5014
|
-
401
|
5015
|
-
);
|
5016
|
-
}
|
5017
|
-
headers["Authorization"] = `Bearer ${(0, import_near_sign_verify.createAuthToken)(options.nearAuthData)}`;
|
5018
|
-
}
|
5019
|
-
const requestOptions = {
|
5020
|
-
method,
|
5021
|
-
headers,
|
5022
|
-
body: method !== "GET" && data ? JSON.stringify(data) : void 0,
|
5023
|
-
signal: controller.signal
|
5024
|
-
};
|
5025
|
-
const response = await fetch(url, requestOptions);
|
5026
|
-
clearTimeout(timeoutId);
|
5027
|
-
let responseData;
|
5028
|
-
try {
|
5029
|
-
responseData = await response.json();
|
5030
|
-
} catch (jsonError) {
|
5031
|
-
if (!response.ok) {
|
5032
|
-
throw new CrosspostError(
|
5033
|
-
`API request failed with status ${response.status} and non-JSON response`,
|
5034
|
-
ApiErrorCode.NETWORK_ERROR,
|
5035
|
-
response.status,
|
5036
|
-
{ originalStatusText: response.statusText }
|
5037
|
-
);
|
5038
|
-
}
|
5039
|
-
throw new CrosspostError(
|
5040
|
-
`Failed to parse JSON response: ${jsonError instanceof Error ? jsonError.message : String(jsonError)}`,
|
5041
|
-
ApiErrorCode.INTERNAL_ERROR,
|
5042
|
-
response.status
|
5043
|
-
);
|
5044
|
-
}
|
5045
|
-
if (!response.ok) {
|
5046
|
-
lastError = handleErrorResponse(responseData, response.status);
|
5047
|
-
const shouldRetry = lastError instanceof CrosspostError && lastError.code === ApiErrorCode.RATE_LIMITED;
|
5048
|
-
if (shouldRetry && attempt < options.retries) {
|
5049
|
-
await new Promise((resolve) => setTimeout(resolve, 1e3 * Math.pow(2, attempt)));
|
5050
|
-
continue;
|
5051
|
-
}
|
5052
|
-
throw lastError;
|
5053
|
-
}
|
5054
|
-
if (responseData && typeof responseData === "object" && "success" in responseData) {
|
5055
|
-
if (responseData.success) {
|
5056
|
-
return responseData.data;
|
5057
|
-
} else {
|
5058
|
-
lastError = handleErrorResponse(responseData, response.status);
|
5059
|
-
const shouldRetry = lastError instanceof CrosspostError && lastError.code === ApiErrorCode.RATE_LIMITED;
|
5060
|
-
if (shouldRetry && attempt < options.retries) {
|
5061
|
-
await new Promise((resolve) => setTimeout(resolve, 1e3 * Math.pow(2, attempt)));
|
5062
|
-
continue;
|
5063
|
-
}
|
5064
|
-
throw lastError;
|
5065
|
-
}
|
5066
|
-
}
|
5067
|
-
} catch (error) {
|
5068
|
-
clearTimeout(timeoutId);
|
5069
|
-
lastError = error instanceof Error ? error : new Error(String(error));
|
5070
|
-
const isNetworkError2 = error instanceof TypeError || error instanceof DOMException && error.name === "AbortError";
|
5071
|
-
if (isNetworkError2 && attempt < options.retries) {
|
5072
|
-
await new Promise((resolve) => setTimeout(resolve, 1e3 * Math.pow(2, attempt)));
|
5073
|
-
continue;
|
5074
|
-
}
|
5075
|
-
if (!(error instanceof CrosspostError)) {
|
5076
|
-
throw createNetworkError(error, url, options.timeout);
|
5077
|
-
}
|
5078
|
-
throw error;
|
5034
|
+
responseText = await response.text();
|
5035
|
+
} catch (_) {
|
5079
5036
|
}
|
5037
|
+
throw new CrosspostError(
|
5038
|
+
`API request failed with status ${response.status} and non-JSON response`,
|
5039
|
+
ApiErrorCode.INVALID_RESPONSE,
|
5040
|
+
response.status,
|
5041
|
+
{
|
5042
|
+
originalStatusText: response.statusText,
|
5043
|
+
originalError: jsonError instanceof Error ? jsonError.message : String(jsonError),
|
5044
|
+
responseText
|
5045
|
+
}
|
5046
|
+
);
|
5047
|
+
}
|
5048
|
+
if (!response.ok) {
|
5049
|
+
throw handleErrorResponse(responseData, response.status);
|
5080
5050
|
}
|
5081
|
-
|
5082
|
-
|
5051
|
+
if (!responseData || typeof responseData !== "object" || !("success" in responseData)) {
|
5052
|
+
throw new CrosspostError(
|
5053
|
+
"Invalid success response format from API",
|
5054
|
+
ApiErrorCode.INVALID_RESPONSE,
|
5055
|
+
response.status,
|
5056
|
+
{ responseData }
|
5057
|
+
);
|
5058
|
+
}
|
5059
|
+
if (responseData.success) {
|
5060
|
+
return responseData.data;
|
5061
|
+
}
|
5062
|
+
throw handleErrorResponse(responseData, response.status);
|
5063
|
+
} catch (error) {
|
5064
|
+
clearTimeout(timeoutId);
|
5065
|
+
if (error instanceof CrosspostError) {
|
5066
|
+
throw enrichErrorWithContext(error, context);
|
5067
|
+
}
|
5068
|
+
if (error instanceof TypeError || error instanceof DOMException && error.name === "AbortError") {
|
5069
|
+
throw enrichErrorWithContext(createNetworkError(error, url, options.timeout), context);
|
5070
|
+
}
|
5071
|
+
throw enrichErrorWithContext(
|
5072
|
+
new CrosspostError(
|
5073
|
+
error instanceof Error ? error.message : String(error),
|
5074
|
+
ApiErrorCode.INTERNAL_ERROR,
|
5075
|
+
500,
|
5076
|
+
{ originalError: String(error) }
|
5077
|
+
),
|
5078
|
+
context
|
5079
|
+
);
|
5080
|
+
}
|
5083
5081
|
}
|
5084
5082
|
|
5085
5083
|
// src/api/activity.ts
|
@@ -5415,8 +5413,7 @@ var SystemApi = class {
|
|
5415
5413
|
// src/core/config.ts
|
5416
5414
|
var DEFAULT_CONFIG = {
|
5417
5415
|
baseUrl: "https://open-crosspost-proxy.deno.dev/",
|
5418
|
-
timeout: 3e4
|
5419
|
-
retries: 2
|
5416
|
+
timeout: 3e4
|
5420
5417
|
};
|
5421
5418
|
|
5422
5419
|
// src/core/client.ts
|
@@ -5428,12 +5425,10 @@ var CrosspostClient = class {
|
|
5428
5425
|
constructor(config = {}) {
|
5429
5426
|
const baseUrl = config.baseUrl || DEFAULT_CONFIG.baseUrl;
|
5430
5427
|
const timeout = config.timeout || DEFAULT_CONFIG.timeout;
|
5431
|
-
const retries = config.retries ?? DEFAULT_CONFIG.retries;
|
5432
5428
|
const nearAuthData = config.nearAuthData;
|
5433
5429
|
this.options = {
|
5434
5430
|
baseUrl,
|
5435
5431
|
timeout,
|
5436
|
-
retries,
|
5437
5432
|
nearAuthData
|
5438
5433
|
};
|
5439
5434
|
this.auth = new AuthApi(this.options);
|
package/dist/index.d.cts
CHANGED
@@ -24,10 +24,6 @@ interface RequestOptions {
|
|
24
24
|
* Request timeout in milliseconds
|
25
25
|
*/
|
26
26
|
timeout: number;
|
27
|
-
/**
|
28
|
-
* Number of retries for failed requests
|
29
|
-
*/
|
30
|
-
retries: number;
|
31
27
|
}
|
32
28
|
|
33
29
|
/**
|
@@ -228,11 +224,6 @@ interface CrosspostClientConfig {
|
|
228
224
|
* @default 30000
|
229
225
|
*/
|
230
226
|
timeout?: number;
|
231
|
-
/**
|
232
|
-
* Number of retries for failed requests (specifically for network errors or 5xx status codes)
|
233
|
-
* @default 2
|
234
|
-
*/
|
235
|
-
retries?: number;
|
236
227
|
}
|
237
228
|
|
238
229
|
/**
|
package/dist/index.d.ts
CHANGED
@@ -24,10 +24,6 @@ interface RequestOptions {
|
|
24
24
|
* Request timeout in milliseconds
|
25
25
|
*/
|
26
26
|
timeout: number;
|
27
|
-
/**
|
28
|
-
* Number of retries for failed requests
|
29
|
-
*/
|
30
|
-
retries: number;
|
31
27
|
}
|
32
28
|
|
33
29
|
/**
|
@@ -228,11 +224,6 @@ interface CrosspostClientConfig {
|
|
228
224
|
* @default 30000
|
229
225
|
*/
|
230
226
|
timeout?: number;
|
231
|
-
/**
|
232
|
-
* Number of retries for failed requests (specifically for network errors or 5xx status codes)
|
233
|
-
* @default 2
|
234
|
-
*/
|
235
|
-
retries?: number;
|
236
227
|
}
|
237
228
|
|
238
229
|
/**
|
package/dist/index.js
CHANGED
@@ -4095,6 +4095,7 @@ var ApiErrorCode = /* @__PURE__ */ ((ApiErrorCode2) => {
|
|
4095
4095
|
ApiErrorCode2["POST_DELETION_FAILED"] = "POST_DELETION_FAILED";
|
4096
4096
|
ApiErrorCode2["POST_INTERACTION_FAILED"] = "POST_INTERACTION_FAILED";
|
4097
4097
|
ApiErrorCode2["NETWORK_ERROR"] = "NETWORK_ERROR";
|
4098
|
+
ApiErrorCode2["INVALID_RESPONSE"] = "INVALID_RESPONSE";
|
4098
4099
|
return ApiErrorCode2;
|
4099
4100
|
})(ApiErrorCode || {});
|
4100
4101
|
var ApiErrorCodeSchema = z.enum(Object.values(ApiErrorCode));
|
@@ -4174,7 +4175,11 @@ var errorCodeToStatusCode = {
|
|
4174
4175
|
[
|
4175
4176
|
"NETWORK_ERROR"
|
4176
4177
|
/* NETWORK_ERROR */
|
4177
|
-
]: 503
|
4178
|
+
]: 503,
|
4179
|
+
[
|
4180
|
+
"INVALID_RESPONSE"
|
4181
|
+
/* INVALID_RESPONSE */
|
4182
|
+
]: 500
|
4178
4183
|
};
|
4179
4184
|
var ErrorDetailSchema = z.object({
|
4180
4185
|
message: z.string().describe("Human-readable error message"),
|
@@ -4863,103 +4868,96 @@ async function makeRequest(method, path, options, data, query) {
|
|
4863
4868
|
const context = {
|
4864
4869
|
method,
|
4865
4870
|
path,
|
4866
|
-
url
|
4867
|
-
retries: options.retries
|
4871
|
+
url
|
4868
4872
|
};
|
4869
|
-
|
4870
|
-
|
4871
|
-
|
4872
|
-
|
4873
|
-
|
4873
|
+
const controller = new AbortController();
|
4874
|
+
const timeoutId = setTimeout(() => controller.abort(), options.timeout);
|
4875
|
+
try {
|
4876
|
+
const headers = {
|
4877
|
+
"Content-Type": "application/json",
|
4878
|
+
"Accept": "application/json"
|
4879
|
+
};
|
4880
|
+
if (method === "GET") {
|
4881
|
+
const nearAccount = options.nearAccount || options.nearAuthData?.account_id;
|
4882
|
+
if (!nearAccount) {
|
4883
|
+
throw new CrosspostError(
|
4884
|
+
"No NEAR account provided for GET request",
|
4885
|
+
ApiErrorCode.UNAUTHORIZED,
|
4886
|
+
401
|
4887
|
+
);
|
4888
|
+
}
|
4889
|
+
headers["X-Near-Account"] = nearAccount;
|
4890
|
+
} else {
|
4891
|
+
if (!options.nearAuthData) {
|
4892
|
+
throw new CrosspostError(
|
4893
|
+
"NEAR authentication data required for non-GET request",
|
4894
|
+
ApiErrorCode.UNAUTHORIZED,
|
4895
|
+
401
|
4896
|
+
);
|
4897
|
+
}
|
4898
|
+
headers["Authorization"] = `Bearer ${createAuthToken(options.nearAuthData)}`;
|
4899
|
+
}
|
4900
|
+
const requestOptions = {
|
4901
|
+
method,
|
4902
|
+
headers,
|
4903
|
+
body: method !== "GET" && data ? JSON.stringify(data) : void 0,
|
4904
|
+
signal: controller.signal
|
4905
|
+
};
|
4906
|
+
const response = await fetch(url, requestOptions);
|
4907
|
+
clearTimeout(timeoutId);
|
4908
|
+
let responseData;
|
4909
|
+
try {
|
4910
|
+
responseData = await response.json();
|
4911
|
+
} catch (jsonError) {
|
4912
|
+
let responseText;
|
4874
4913
|
try {
|
4875
|
-
|
4876
|
-
|
4877
|
-
"Accept": "application/json"
|
4878
|
-
};
|
4879
|
-
if (method === "GET") {
|
4880
|
-
const nearAccount = options.nearAccount || options.nearAuthData?.account_id;
|
4881
|
-
if (!nearAccount) {
|
4882
|
-
throw new CrosspostError(
|
4883
|
-
"No NEAR account provided for GET request",
|
4884
|
-
ApiErrorCode.UNAUTHORIZED,
|
4885
|
-
401
|
4886
|
-
);
|
4887
|
-
}
|
4888
|
-
headers["X-Near-Account"] = nearAccount;
|
4889
|
-
} else {
|
4890
|
-
if (!options.nearAuthData) {
|
4891
|
-
throw new CrosspostError(
|
4892
|
-
"NEAR authentication data required for non-GET request",
|
4893
|
-
ApiErrorCode.UNAUTHORIZED,
|
4894
|
-
401
|
4895
|
-
);
|
4896
|
-
}
|
4897
|
-
headers["Authorization"] = `Bearer ${createAuthToken(options.nearAuthData)}`;
|
4898
|
-
}
|
4899
|
-
const requestOptions = {
|
4900
|
-
method,
|
4901
|
-
headers,
|
4902
|
-
body: method !== "GET" && data ? JSON.stringify(data) : void 0,
|
4903
|
-
signal: controller.signal
|
4904
|
-
};
|
4905
|
-
const response = await fetch(url, requestOptions);
|
4906
|
-
clearTimeout(timeoutId);
|
4907
|
-
let responseData;
|
4908
|
-
try {
|
4909
|
-
responseData = await response.json();
|
4910
|
-
} catch (jsonError) {
|
4911
|
-
if (!response.ok) {
|
4912
|
-
throw new CrosspostError(
|
4913
|
-
`API request failed with status ${response.status} and non-JSON response`,
|
4914
|
-
ApiErrorCode.NETWORK_ERROR,
|
4915
|
-
response.status,
|
4916
|
-
{ originalStatusText: response.statusText }
|
4917
|
-
);
|
4918
|
-
}
|
4919
|
-
throw new CrosspostError(
|
4920
|
-
`Failed to parse JSON response: ${jsonError instanceof Error ? jsonError.message : String(jsonError)}`,
|
4921
|
-
ApiErrorCode.INTERNAL_ERROR,
|
4922
|
-
response.status
|
4923
|
-
);
|
4924
|
-
}
|
4925
|
-
if (!response.ok) {
|
4926
|
-
lastError = handleErrorResponse(responseData, response.status);
|
4927
|
-
const shouldRetry = lastError instanceof CrosspostError && lastError.code === ApiErrorCode.RATE_LIMITED;
|
4928
|
-
if (shouldRetry && attempt < options.retries) {
|
4929
|
-
await new Promise((resolve) => setTimeout(resolve, 1e3 * Math.pow(2, attempt)));
|
4930
|
-
continue;
|
4931
|
-
}
|
4932
|
-
throw lastError;
|
4933
|
-
}
|
4934
|
-
if (responseData && typeof responseData === "object" && "success" in responseData) {
|
4935
|
-
if (responseData.success) {
|
4936
|
-
return responseData.data;
|
4937
|
-
} else {
|
4938
|
-
lastError = handleErrorResponse(responseData, response.status);
|
4939
|
-
const shouldRetry = lastError instanceof CrosspostError && lastError.code === ApiErrorCode.RATE_LIMITED;
|
4940
|
-
if (shouldRetry && attempt < options.retries) {
|
4941
|
-
await new Promise((resolve) => setTimeout(resolve, 1e3 * Math.pow(2, attempt)));
|
4942
|
-
continue;
|
4943
|
-
}
|
4944
|
-
throw lastError;
|
4945
|
-
}
|
4946
|
-
}
|
4947
|
-
} catch (error) {
|
4948
|
-
clearTimeout(timeoutId);
|
4949
|
-
lastError = error instanceof Error ? error : new Error(String(error));
|
4950
|
-
const isNetworkError2 = error instanceof TypeError || error instanceof DOMException && error.name === "AbortError";
|
4951
|
-
if (isNetworkError2 && attempt < options.retries) {
|
4952
|
-
await new Promise((resolve) => setTimeout(resolve, 1e3 * Math.pow(2, attempt)));
|
4953
|
-
continue;
|
4954
|
-
}
|
4955
|
-
if (!(error instanceof CrosspostError)) {
|
4956
|
-
throw createNetworkError(error, url, options.timeout);
|
4957
|
-
}
|
4958
|
-
throw error;
|
4914
|
+
responseText = await response.text();
|
4915
|
+
} catch (_) {
|
4959
4916
|
}
|
4917
|
+
throw new CrosspostError(
|
4918
|
+
`API request failed with status ${response.status} and non-JSON response`,
|
4919
|
+
ApiErrorCode.INVALID_RESPONSE,
|
4920
|
+
response.status,
|
4921
|
+
{
|
4922
|
+
originalStatusText: response.statusText,
|
4923
|
+
originalError: jsonError instanceof Error ? jsonError.message : String(jsonError),
|
4924
|
+
responseText
|
4925
|
+
}
|
4926
|
+
);
|
4927
|
+
}
|
4928
|
+
if (!response.ok) {
|
4929
|
+
throw handleErrorResponse(responseData, response.status);
|
4960
4930
|
}
|
4961
|
-
|
4962
|
-
|
4931
|
+
if (!responseData || typeof responseData !== "object" || !("success" in responseData)) {
|
4932
|
+
throw new CrosspostError(
|
4933
|
+
"Invalid success response format from API",
|
4934
|
+
ApiErrorCode.INVALID_RESPONSE,
|
4935
|
+
response.status,
|
4936
|
+
{ responseData }
|
4937
|
+
);
|
4938
|
+
}
|
4939
|
+
if (responseData.success) {
|
4940
|
+
return responseData.data;
|
4941
|
+
}
|
4942
|
+
throw handleErrorResponse(responseData, response.status);
|
4943
|
+
} catch (error) {
|
4944
|
+
clearTimeout(timeoutId);
|
4945
|
+
if (error instanceof CrosspostError) {
|
4946
|
+
throw enrichErrorWithContext(error, context);
|
4947
|
+
}
|
4948
|
+
if (error instanceof TypeError || error instanceof DOMException && error.name === "AbortError") {
|
4949
|
+
throw enrichErrorWithContext(createNetworkError(error, url, options.timeout), context);
|
4950
|
+
}
|
4951
|
+
throw enrichErrorWithContext(
|
4952
|
+
new CrosspostError(
|
4953
|
+
error instanceof Error ? error.message : String(error),
|
4954
|
+
ApiErrorCode.INTERNAL_ERROR,
|
4955
|
+
500,
|
4956
|
+
{ originalError: String(error) }
|
4957
|
+
),
|
4958
|
+
context
|
4959
|
+
);
|
4960
|
+
}
|
4963
4961
|
}
|
4964
4962
|
|
4965
4963
|
// src/api/activity.ts
|
@@ -5295,8 +5293,7 @@ var SystemApi = class {
|
|
5295
5293
|
// src/core/config.ts
|
5296
5294
|
var DEFAULT_CONFIG = {
|
5297
5295
|
baseUrl: "https://open-crosspost-proxy.deno.dev/",
|
5298
|
-
timeout: 3e4
|
5299
|
-
retries: 2
|
5296
|
+
timeout: 3e4
|
5300
5297
|
};
|
5301
5298
|
|
5302
5299
|
// src/core/client.ts
|
@@ -5308,12 +5305,10 @@ var CrosspostClient = class {
|
|
5308
5305
|
constructor(config = {}) {
|
5309
5306
|
const baseUrl = config.baseUrl || DEFAULT_CONFIG.baseUrl;
|
5310
5307
|
const timeout = config.timeout || DEFAULT_CONFIG.timeout;
|
5311
|
-
const retries = config.retries ?? DEFAULT_CONFIG.retries;
|
5312
5308
|
const nearAuthData = config.nearAuthData;
|
5313
5309
|
this.options = {
|
5314
5310
|
baseUrl,
|
5315
5311
|
timeout,
|
5316
|
-
retries,
|
5317
5312
|
nearAuthData
|
5318
5313
|
};
|
5319
5314
|
this.auth = new AuthApi(this.options);
|
package/package.json
CHANGED
package/src/core/client.ts
CHANGED
@@ -24,14 +24,12 @@ export class CrosspostClient {
|
|
24
24
|
constructor(config: CrosspostClientConfig = {}) {
|
25
25
|
const baseUrl = config.baseUrl || DEFAULT_CONFIG.baseUrl; // you can deploy your own
|
26
26
|
const timeout = config.timeout || DEFAULT_CONFIG.timeout;
|
27
|
-
const retries = config.retries ?? DEFAULT_CONFIG.retries;
|
28
27
|
|
29
28
|
const nearAuthData = config.nearAuthData;
|
30
29
|
|
31
30
|
this.options = {
|
32
31
|
baseUrl,
|
33
32
|
timeout,
|
34
|
-
retries,
|
35
33
|
nearAuthData,
|
36
34
|
};
|
37
35
|
|
package/src/core/config.ts
CHANGED
@@ -18,11 +18,6 @@ export interface CrosspostClientConfig {
|
|
18
18
|
* @default 30000
|
19
19
|
*/
|
20
20
|
timeout?: number;
|
21
|
-
/**
|
22
|
-
* Number of retries for failed requests (specifically for network errors or 5xx status codes)
|
23
|
-
* @default 2
|
24
|
-
*/
|
25
|
-
retries?: number;
|
26
21
|
}
|
27
22
|
|
28
23
|
/**
|
@@ -31,5 +26,4 @@ export interface CrosspostClientConfig {
|
|
31
26
|
export const DEFAULT_CONFIG: Required<Omit<CrosspostClientConfig, 'nearAuthData'>> = {
|
32
27
|
baseUrl: 'https://open-crosspost-proxy.deno.dev/',
|
33
28
|
timeout: 30000,
|
34
|
-
retries: 2,
|
35
29
|
};
|
package/src/core/request.ts
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
import { ApiErrorCode, type StatusCode } from '@crosspost/types';
|
2
2
|
import { createAuthToken, type NearAuthData } from 'near-sign-verify';
|
3
3
|
import {
|
4
|
-
apiWrapper,
|
5
4
|
createNetworkError,
|
6
5
|
CrosspostError,
|
6
|
+
enrichErrorWithContext,
|
7
7
|
handleErrorResponse,
|
8
8
|
} from '../utils/error.ts';
|
9
9
|
|
@@ -29,14 +29,10 @@ export interface RequestOptions {
|
|
29
29
|
* Request timeout in milliseconds
|
30
30
|
*/
|
31
31
|
timeout: number;
|
32
|
-
/**
|
33
|
-
* Number of retries for failed requests
|
34
|
-
*/
|
35
|
-
retries: number;
|
36
32
|
}
|
37
33
|
|
38
34
|
/**
|
39
|
-
* Makes a request to the API with
|
35
|
+
* Makes a request to the API with error handling
|
40
36
|
*
|
41
37
|
* @param method The HTTP method
|
42
38
|
* @param path The API path
|
@@ -76,131 +72,118 @@ export async function makeRequest<
|
|
76
72
|
method,
|
77
73
|
path,
|
78
74
|
url,
|
79
|
-
retries: options.retries,
|
80
75
|
};
|
81
76
|
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
77
|
+
const controller = new AbortController();
|
78
|
+
const timeoutId = setTimeout(() => controller.abort(), options.timeout);
|
79
|
+
|
80
|
+
try {
|
81
|
+
const headers: Record<string, string> = {
|
82
|
+
'Content-Type': 'application/json',
|
83
|
+
'Accept': 'application/json',
|
84
|
+
};
|
85
|
+
|
86
|
+
// For GET requests, use X-Near-Account header if available
|
87
|
+
if (method === 'GET') {
|
88
|
+
const nearAccount = options.nearAccount || options.nearAuthData?.account_id;
|
89
|
+
if (!nearAccount) {
|
90
|
+
throw new CrosspostError(
|
91
|
+
'No NEAR account provided for GET request',
|
92
|
+
ApiErrorCode.UNAUTHORIZED,
|
93
|
+
401,
|
94
|
+
);
|
95
|
+
}
|
96
|
+
headers['X-Near-Account'] = nearAccount;
|
97
|
+
} else {
|
98
|
+
// For non-GET requests, require nearAuthData
|
99
|
+
if (!options.nearAuthData) {
|
100
|
+
throw new CrosspostError(
|
101
|
+
'NEAR authentication data required for non-GET request',
|
102
|
+
ApiErrorCode.UNAUTHORIZED,
|
103
|
+
401,
|
104
|
+
);
|
105
|
+
}
|
106
|
+
headers['Authorization'] = `Bearer ${createAuthToken(options.nearAuthData)}`;
|
107
|
+
}
|
88
108
|
|
109
|
+
const requestOptions: RequestInit = {
|
110
|
+
method,
|
111
|
+
headers,
|
112
|
+
body: method !== 'GET' && data ? JSON.stringify(data) : undefined,
|
113
|
+
signal: controller.signal,
|
114
|
+
};
|
115
|
+
|
116
|
+
const response = await fetch(url, requestOptions);
|
117
|
+
clearTimeout(timeoutId);
|
118
|
+
|
119
|
+
let responseData: any;
|
120
|
+
try {
|
121
|
+
responseData = await response.json();
|
122
|
+
} catch (jsonError) {
|
123
|
+
// JSON parsing failed - try to get response text for context
|
124
|
+
let responseText: string | undefined;
|
89
125
|
try {
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
);
|
104
|
-
}
|
105
|
-
headers['X-Near-Account'] = nearAccount;
|
106
|
-
} else {
|
107
|
-
// For non-GET requests, require nearAuthData
|
108
|
-
if (!options.nearAuthData) {
|
109
|
-
throw new CrosspostError(
|
110
|
-
'NEAR authentication data required for non-GET request',
|
111
|
-
ApiErrorCode.UNAUTHORIZED,
|
112
|
-
401,
|
113
|
-
);
|
114
|
-
}
|
115
|
-
headers['Authorization'] = `Bearer ${createAuthToken(options.nearAuthData)}`;
|
116
|
-
}
|
117
|
-
|
118
|
-
const requestOptions: RequestInit = {
|
119
|
-
method,
|
120
|
-
headers,
|
121
|
-
body: method !== 'GET' && data ? JSON.stringify(data) : undefined,
|
122
|
-
signal: controller.signal,
|
123
|
-
};
|
124
|
-
|
125
|
-
const response = await fetch(url, requestOptions);
|
126
|
-
clearTimeout(timeoutId); // Clear timeout if fetch completes
|
127
|
-
|
128
|
-
let responseData: any;
|
129
|
-
try {
|
130
|
-
responseData = await response.json();
|
131
|
-
} catch (jsonError) {
|
132
|
-
// If JSON parsing fails, did API throw an error?
|
133
|
-
if (!response.ok) {
|
134
|
-
throw new CrosspostError(
|
135
|
-
`API request failed with status ${response.status} and non-JSON response`,
|
136
|
-
ApiErrorCode.NETWORK_ERROR,
|
137
|
-
response.status as StatusCode,
|
138
|
-
{ originalStatusText: response.statusText },
|
139
|
-
);
|
140
|
-
}
|
141
|
-
// Otherwise, throw a custom error
|
142
|
-
throw new CrosspostError(
|
143
|
-
`Failed to parse JSON response: ${
|
144
|
-
jsonError instanceof Error ? jsonError.message : String(jsonError)
|
145
|
-
}`,
|
146
|
-
ApiErrorCode.INTERNAL_ERROR,
|
147
|
-
response.status as StatusCode,
|
148
|
-
);
|
149
|
-
}
|
150
|
-
|
151
|
-
if (!response.ok) {
|
152
|
-
lastError = handleErrorResponse(responseData, response.status);
|
153
|
-
// Only retry rate limit errors
|
154
|
-
const shouldRetry = lastError instanceof CrosspostError &&
|
155
|
-
lastError.code === ApiErrorCode.RATE_LIMITED;
|
156
|
-
if (shouldRetry && attempt < options.retries) {
|
157
|
-
await new Promise((resolve) => setTimeout(resolve, 1000 * Math.pow(2, attempt))); // Exponential backoff
|
158
|
-
continue; // Retry
|
159
|
-
}
|
160
|
-
throw lastError; // Throw error if not retrying or retries exhausted
|
161
|
-
}
|
162
|
-
|
163
|
-
// Handle response based on success flag
|
164
|
-
if (responseData && typeof responseData === 'object' && 'success' in responseData) {
|
165
|
-
if (responseData.success) {
|
166
|
-
// Success response - return the data
|
167
|
-
return responseData.data as TResponse;
|
168
|
-
} else {
|
169
|
-
// Error response - handle with our error utilities
|
170
|
-
lastError = handleErrorResponse(responseData, response.status);
|
171
|
-
// Only retry rate limit errors
|
172
|
-
const shouldRetry = lastError instanceof CrosspostError &&
|
173
|
-
lastError.code === ApiErrorCode.RATE_LIMITED;
|
174
|
-
if (shouldRetry && attempt < options.retries) {
|
175
|
-
await new Promise((resolve) => setTimeout(resolve, 1000 * Math.pow(2, attempt))); // Exponential backoff
|
176
|
-
continue; // Retry
|
177
|
-
}
|
178
|
-
throw lastError;
|
179
|
-
}
|
180
|
-
}
|
181
|
-
} catch (error) {
|
182
|
-
clearTimeout(timeoutId); // Clear timeout on error
|
183
|
-
lastError = error instanceof Error ? error : new Error(String(error)); // Store the error
|
184
|
-
|
185
|
-
// Handle fetch/network errors specifically for retries
|
186
|
-
const isNetworkError = error instanceof TypeError ||
|
187
|
-
(error instanceof DOMException && error.name === 'AbortError');
|
188
|
-
if (isNetworkError && attempt < options.retries) {
|
189
|
-
await new Promise((resolve) => setTimeout(resolve, 1000 * Math.pow(2, attempt))); // Exponential backoff
|
190
|
-
continue; // Retry network error
|
191
|
-
}
|
192
|
-
|
193
|
-
// If it's not a known ApiError/PlatformError, wrap it
|
194
|
-
if (!(error instanceof CrosspostError)) {
|
195
|
-
throw createNetworkError(error, url, options.timeout);
|
196
|
-
}
|
197
|
-
|
198
|
-
throw error; // Re-throw known ApiError or final network error
|
199
|
-
}
|
126
|
+
responseText = await response.text();
|
127
|
+
} catch (_) { /* ignore */ }
|
128
|
+
|
129
|
+
throw new CrosspostError(
|
130
|
+
`API request failed with status ${response.status} and non-JSON response`,
|
131
|
+
ApiErrorCode.INVALID_RESPONSE,
|
132
|
+
response.status as StatusCode,
|
133
|
+
{
|
134
|
+
originalStatusText: response.statusText,
|
135
|
+
originalError: jsonError instanceof Error ? jsonError.message : String(jsonError),
|
136
|
+
responseText,
|
137
|
+
},
|
138
|
+
);
|
200
139
|
}
|
201
140
|
|
202
|
-
//
|
203
|
-
|
204
|
-
|
205
|
-
|
141
|
+
// Handle non-ok responses (4xx/5xx)
|
142
|
+
if (!response.ok) {
|
143
|
+
throw handleErrorResponse(responseData, response.status);
|
144
|
+
}
|
145
|
+
|
146
|
+
// Validate success response structure
|
147
|
+
if (!responseData || typeof responseData !== 'object' || !('success' in responseData)) {
|
148
|
+
throw new CrosspostError(
|
149
|
+
'Invalid success response format from API',
|
150
|
+
ApiErrorCode.INVALID_RESPONSE,
|
151
|
+
response.status as StatusCode,
|
152
|
+
{ responseData },
|
153
|
+
);
|
154
|
+
}
|
155
|
+
|
156
|
+
if (responseData.success) {
|
157
|
+
return responseData.data as TResponse;
|
158
|
+
}
|
159
|
+
|
160
|
+
// If we get here, we have response.ok but success: false
|
161
|
+
// This is unexpected - treat as an error
|
162
|
+
throw handleErrorResponse(responseData, response.status);
|
163
|
+
} catch (error) {
|
164
|
+
clearTimeout(timeoutId);
|
165
|
+
|
166
|
+
if (error instanceof CrosspostError) {
|
167
|
+
// Enrich CrosspostError with request context
|
168
|
+
throw enrichErrorWithContext(error, context);
|
169
|
+
}
|
170
|
+
|
171
|
+
// Handle network errors (including timeouts)
|
172
|
+
if (
|
173
|
+
error instanceof TypeError || (error instanceof DOMException && error.name === 'AbortError')
|
174
|
+
) {
|
175
|
+
throw enrichErrorWithContext(createNetworkError(error, url, options.timeout), context);
|
176
|
+
}
|
177
|
+
|
178
|
+
// For any other errors, wrap them with context
|
179
|
+
throw enrichErrorWithContext(
|
180
|
+
new CrosspostError(
|
181
|
+
error instanceof Error ? error.message : String(error),
|
182
|
+
ApiErrorCode.INTERNAL_ERROR,
|
183
|
+
500,
|
184
|
+
{ originalError: String(error) },
|
185
|
+
),
|
186
|
+
context,
|
187
|
+
);
|
188
|
+
}
|
206
189
|
}
|