@porulle/adapter-shopify 0.67.0 → 0.68.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/graphql.js +2 -2
- package/dist/index.js +2 -2
- package/dist/oauth.d.ts +2 -0
- package/dist/oauth.js +7 -5
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +4 -4
- package/src/graphql.ts +2 -2
- package/src/index.ts +2 -2
- package/src/oauth.ts +7 -3
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@porulle/adapter-shopify",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.68.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
},
|
|
17
17
|
"dependencies": {
|
|
18
18
|
"zod": "^4.1.11",
|
|
19
|
-
"@porulle/core": "0.
|
|
19
|
+
"@porulle/core": "0.68.0"
|
|
20
20
|
},
|
|
21
21
|
"devDependencies": {
|
|
22
22
|
"@types/node": "^24.5.2",
|
|
@@ -24,8 +24,8 @@
|
|
|
24
24
|
"graphql": "^16.11.0",
|
|
25
25
|
"typescript": "5.9.2",
|
|
26
26
|
"vitest": "^3.2.4",
|
|
27
|
-
"@porulle/
|
|
28
|
-
"@porulle/
|
|
27
|
+
"@porulle/typescript-config": "0.1.0",
|
|
28
|
+
"@porulle/eslint-config": "0.1.0"
|
|
29
29
|
},
|
|
30
30
|
"publishConfig": {
|
|
31
31
|
"access": "public"
|
package/src/graphql.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Err, Ok } from "@porulle/core";
|
|
1
|
+
import { CHANNEL_CREDENTIALS_REJECTED, Err, Ok } from "@porulle/core";
|
|
2
2
|
import type { ChannelConnectorError, Result } from "@porulle/core";
|
|
3
3
|
import { z } from "zod";
|
|
4
4
|
|
|
@@ -90,7 +90,7 @@ export async function shopifyGraphql<T>(
|
|
|
90
90
|
return Err({ code: "SHOPIFY_API_FAILED", message: error instanceof Error ? error.message : "Shopify API request failed.", retriable: true });
|
|
91
91
|
}
|
|
92
92
|
if (response.status === 401 || response.status === 403) {
|
|
93
|
-
return Err({ code:
|
|
93
|
+
return Err({ code: CHANNEL_CREDENTIALS_REJECTED, message: `Shopify refused the access token (${response.status}).`, retriable: false });
|
|
94
94
|
}
|
|
95
95
|
if (response.status !== 429 && !response.ok) {
|
|
96
96
|
return Err({ code: "SHOPIFY_API_FAILED", message: `Shopify API request failed (${response.status}).`, retriable: response.status >= 500 });
|
package/src/index.ts
CHANGED
|
@@ -152,10 +152,10 @@ export function shopifyConnector(options: ShopifyConnectorOptions): ChannelConne
|
|
|
152
152
|
if (!credentials.ok) return credentials;
|
|
153
153
|
return Ok({ credentials: { ...credentials.value }, storeDomain: shop });
|
|
154
154
|
},
|
|
155
|
-
async liveCredentials(store) {
|
|
155
|
+
async liveCredentials(store, refresh) {
|
|
156
156
|
const credentials = parseShopifyCredentials(store.credentials);
|
|
157
157
|
if (!credentials) return Err(credentialsRequired);
|
|
158
|
-
const refreshed = await refreshIfExpiring({ fetchImpl, origin: origin(store.storeDomain), clientId: options.clientId, clientSecret: options.clientSecret, credentials, now: Date.now() });
|
|
158
|
+
const refreshed = await refreshIfExpiring({ fetchImpl, origin: origin(store.storeDomain), clientId: options.clientId, clientSecret: options.clientSecret, credentials, now: Date.now(), ...(refresh?.force === true ? { force: true } : {}) });
|
|
159
159
|
if (!refreshed.ok) return refreshed;
|
|
160
160
|
return Ok(refreshed.value === null ? null : { ...refreshed.value });
|
|
161
161
|
},
|
package/src/oauth.ts
CHANGED
|
@@ -181,11 +181,15 @@ export async function refreshIfExpiring(params: {
|
|
|
181
181
|
clientSecret: string;
|
|
182
182
|
credentials: ShopifyCredentials;
|
|
183
183
|
now: number;
|
|
184
|
+
/** Refresh even though the stated expiry is far off: Shopify just rejected the token. */
|
|
185
|
+
force?: boolean;
|
|
184
186
|
}): Promise<Result<ShopifyCredentials | null, ChannelConnectorError>> {
|
|
185
187
|
const { credentials } = params;
|
|
186
|
-
if (
|
|
187
|
-
|
|
188
|
-
|
|
188
|
+
if (params.force !== true) {
|
|
189
|
+
if (credentials.accessTokenExpiresAt === undefined) return Ok(null);
|
|
190
|
+
const expiresAt = Date.parse(credentials.accessTokenExpiresAt);
|
|
191
|
+
if (Number.isFinite(expiresAt) && expiresAt - params.now > ACCESS_TOKEN_REFRESH_MARGIN_MS) return Ok(null);
|
|
192
|
+
}
|
|
189
193
|
if (credentials.refreshToken === undefined) return oauthError("SHOPIFY_REAUTHORIZATION_REQUIRED", "The store's access token expired and no refresh token is held; the store must be reconnected.");
|
|
190
194
|
const token = await postTokenEndpoint(params.fetchImpl, params.origin, {
|
|
191
195
|
client_id: params.clientId,
|