@drawbridge/drawbridge-utils 0.0.18 → 0.0.20
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/shopify.cjs +84 -58
- package/dist/shopify.d.cts +106 -65
- package/dist/shopify.d.ts +106 -65
- package/dist/shopify.js +82 -57
- package/package.json +1 -1
package/dist/shopify.cjs
CHANGED
|
@@ -30,7 +30,8 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
30
30
|
var shopify_exports = {};
|
|
31
31
|
__export(shopify_exports, {
|
|
32
32
|
getAdminToken: () => getAdminToken,
|
|
33
|
-
refreshAdminToken: () => refreshAdminToken
|
|
33
|
+
refreshAdminToken: () => refreshAdminToken,
|
|
34
|
+
resolveConnectionSettings: () => resolveConnectionSettings
|
|
34
35
|
});
|
|
35
36
|
module.exports = __toCommonJS(shopify_exports);
|
|
36
37
|
|
|
@@ -65,6 +66,9 @@ var decrypt = (value) => {
|
|
|
65
66
|
};
|
|
66
67
|
|
|
67
68
|
// shopify.js
|
|
69
|
+
var SHOPIFY_ADMIN_API_VERSION = "2025-01";
|
|
70
|
+
var REFRESH_TOKEN_LIFETIME_MS = 90 * 24 * 60 * 60 * 1e3;
|
|
71
|
+
var ACCESS_TOKEN_REFRESH_BUFFER_MS = 5 * 60 * 1e3;
|
|
68
72
|
var shopifyOAuthFetch = async (url, body) => {
|
|
69
73
|
const response = await fetch(url, {
|
|
70
74
|
method: "POST",
|
|
@@ -75,13 +79,59 @@ var shopifyOAuthFetch = async (url, body) => {
|
|
|
75
79
|
});
|
|
76
80
|
if (!response.ok) {
|
|
77
81
|
const text = await response.text().catch(() => "");
|
|
78
|
-
|
|
82
|
+
const error = new Error(response.status + ": " + text);
|
|
83
|
+
error.status = response.status;
|
|
84
|
+
throw error;
|
|
79
85
|
}
|
|
80
86
|
return response.json();
|
|
81
87
|
};
|
|
88
|
+
var pingShop = async ({ adminAccessToken, domain }) => {
|
|
89
|
+
const response = await fetch(
|
|
90
|
+
`https://${domain}/admin/api/${SHOPIFY_ADMIN_API_VERSION}/shop.json`,
|
|
91
|
+
{
|
|
92
|
+
headers: {
|
|
93
|
+
"X-Shopify-Access-Token": adminAccessToken
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
);
|
|
97
|
+
if (!response.ok) {
|
|
98
|
+
const text = await response.text().catch(() => "");
|
|
99
|
+
const error = new Error(response.status + ": " + text);
|
|
100
|
+
error.status = response.status;
|
|
101
|
+
throw error;
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
var resolveConnectionSettings = async ({ connection, controller }) => {
|
|
105
|
+
const connectionSettings = (connection == null ? void 0 : connection.settings) ? decrypt(connection.settings) : {};
|
|
106
|
+
if (!(connection == null ? void 0 : connection.credential)) {
|
|
107
|
+
return connectionSettings;
|
|
108
|
+
}
|
|
109
|
+
const credential = await controller.get({
|
|
110
|
+
collection: "credential",
|
|
111
|
+
query: {
|
|
112
|
+
id: connection.credential
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
const credentialSettings = (credential == null ? void 0 : credential.settings) ? decrypt(credential.settings) : {};
|
|
116
|
+
return {
|
|
117
|
+
...credentialSettings,
|
|
118
|
+
...connectionSettings
|
|
119
|
+
};
|
|
120
|
+
};
|
|
82
121
|
var refreshAdminToken = async ({ connection, controller }) => {
|
|
83
|
-
const
|
|
84
|
-
|
|
122
|
+
const credential = await controller.get({
|
|
123
|
+
collection: "credential",
|
|
124
|
+
query: {
|
|
125
|
+
id: connection.credential
|
|
126
|
+
}
|
|
127
|
+
});
|
|
128
|
+
if (!credential) {
|
|
129
|
+
throw new Error("refreshAdminToken: credential not found for connection " + connection.id);
|
|
130
|
+
}
|
|
131
|
+
;
|
|
132
|
+
const settings = decrypt(credential.settings);
|
|
133
|
+
const { identifier: domain } = credential;
|
|
134
|
+
const { refreshToken } = settings;
|
|
85
135
|
const data = await shopifyOAuthFetch(
|
|
86
136
|
`https://${domain}/admin/oauth/access_token`,
|
|
87
137
|
{
|
|
@@ -95,72 +145,48 @@ var refreshAdminToken = async ({ connection, controller }) => {
|
|
|
95
145
|
const newRefreshToken = data.refresh_token;
|
|
96
146
|
const expiresIn = data.expires_in;
|
|
97
147
|
const tokenExpiresAt = expiresIn ? new Date(Date.now() + expiresIn * 1e3) : null;
|
|
98
|
-
const
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
data: {
|
|
112
|
-
$set: {
|
|
113
|
-
settings: encrypt({
|
|
114
|
-
...settings,
|
|
115
|
-
adminAccessToken,
|
|
116
|
-
refreshToken: newRefreshToken,
|
|
117
|
-
tokenExpiresAt
|
|
118
|
-
})
|
|
119
|
-
}
|
|
120
|
-
},
|
|
121
|
-
options,
|
|
122
|
-
query: {
|
|
123
|
-
id: connection.id
|
|
148
|
+
const refreshTokenExpiresAt = new Date(Date.now() + REFRESH_TOKEN_LIFETIME_MS);
|
|
149
|
+
await pingShop({ adminAccessToken, domain });
|
|
150
|
+
await controller.update({
|
|
151
|
+
collection: "credential",
|
|
152
|
+
data: {
|
|
153
|
+
$set: {
|
|
154
|
+
settings: encrypt({
|
|
155
|
+
...settings,
|
|
156
|
+
adminAccessToken,
|
|
157
|
+
refreshToken: newRefreshToken,
|
|
158
|
+
refreshTokenExpiresAt,
|
|
159
|
+
tokenExpiresAt
|
|
160
|
+
})
|
|
124
161
|
}
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
collection: "action",
|
|
129
|
-
data: {
|
|
130
|
-
completedAt: /* @__PURE__ */ new Date(),
|
|
131
|
-
error: null,
|
|
132
|
-
errorStatus: null,
|
|
133
|
-
organization: connection.organization,
|
|
134
|
-
request: null,
|
|
135
|
-
response: null,
|
|
136
|
-
slug: "action.shopify.token.refresh",
|
|
137
|
-
status: "succeeded",
|
|
138
|
-
trigger: {
|
|
139
|
-
data: {
|
|
140
|
-
connection: connection.id
|
|
141
|
-
},
|
|
142
|
-
event: "shopify.token"
|
|
143
|
-
},
|
|
144
|
-
usage: null,
|
|
145
|
-
workflow: tokenWorkflow.id
|
|
146
|
-
},
|
|
147
|
-
options
|
|
148
|
-
});
|
|
162
|
+
},
|
|
163
|
+
query: {
|
|
164
|
+
id: credential.id
|
|
149
165
|
}
|
|
150
|
-
;
|
|
151
166
|
});
|
|
152
167
|
return adminAccessToken;
|
|
153
168
|
};
|
|
154
169
|
var getAdminToken = async ({ connection, controller }) => {
|
|
155
|
-
|
|
156
|
-
|
|
170
|
+
if (!(connection == null ? void 0 : connection.credential)) {
|
|
171
|
+
return null;
|
|
172
|
+
}
|
|
173
|
+
;
|
|
174
|
+
const settings = await resolveConnectionSettings({ connection, controller });
|
|
175
|
+
const { adminAccessToken, refreshToken, tokenExpiresAt } = settings;
|
|
176
|
+
if (!refreshToken) {
|
|
177
|
+
return adminAccessToken;
|
|
178
|
+
}
|
|
179
|
+
;
|
|
180
|
+
const needsRefresh = !tokenExpiresAt || new Date(tokenExpiresAt) < new Date(Date.now() + ACCESS_TOKEN_REFRESH_BUFFER_MS);
|
|
157
181
|
if (needsRefresh) {
|
|
158
182
|
return refreshAdminToken({ connection, controller });
|
|
159
183
|
}
|
|
184
|
+
;
|
|
160
185
|
return adminAccessToken;
|
|
161
186
|
};
|
|
162
187
|
// Annotate the CommonJS export names for ESM import in node:
|
|
163
188
|
0 && (module.exports = {
|
|
164
189
|
getAdminToken,
|
|
165
|
-
refreshAdminToken
|
|
190
|
+
refreshAdminToken,
|
|
191
|
+
resolveConnectionSettings
|
|
166
192
|
});
|
package/dist/shopify.d.cts
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import { decrypt, encrypt } from './encrypt.cjs';
|
|
2
2
|
import 'crypto';
|
|
3
3
|
|
|
4
|
+
const SHOPIFY_ADMIN_API_VERSION = '2025-01';
|
|
5
|
+
const REFRESH_TOKEN_LIFETIME_MS = 90 * 24 * 60 * 60 * 1000;
|
|
6
|
+
const ACCESS_TOKEN_REFRESH_BUFFER_MS = 5 * 60 * 1000;
|
|
7
|
+
|
|
4
8
|
const shopifyOAuthFetch = async ( url, body ) => {
|
|
5
9
|
|
|
6
10
|
const response = await fetch( url, {
|
|
@@ -14,8 +18,11 @@ const shopifyOAuthFetch = async ( url, body ) => {
|
|
|
14
18
|
if( ! response.ok ){
|
|
15
19
|
|
|
16
20
|
const text = await response.text().catch( () => '' );
|
|
21
|
+
const error = new Error( response.status + ': ' + text );
|
|
22
|
+
|
|
23
|
+
error.status = response.status;
|
|
17
24
|
|
|
18
|
-
throw
|
|
25
|
+
throw error;
|
|
19
26
|
|
|
20
27
|
}
|
|
21
28
|
|
|
@@ -23,10 +30,73 @@ const shopifyOAuthFetch = async ( url, body ) => {
|
|
|
23
30
|
|
|
24
31
|
};
|
|
25
32
|
|
|
33
|
+
const pingShop = async ({ adminAccessToken, domain }) => {
|
|
34
|
+
|
|
35
|
+
const response = await fetch(
|
|
36
|
+
`https://${ domain }/admin/api/${ SHOPIFY_ADMIN_API_VERSION }/shop.json`,
|
|
37
|
+
{
|
|
38
|
+
headers : {
|
|
39
|
+
'X-Shopify-Access-Token' : adminAccessToken
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
if( ! response.ok ){
|
|
45
|
+
|
|
46
|
+
const text = await response.text().catch( () => '' );
|
|
47
|
+
const error = new Error( response.status + ': ' + text );
|
|
48
|
+
|
|
49
|
+
error.status = response.status;
|
|
50
|
+
|
|
51
|
+
throw error;
|
|
52
|
+
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
const resolveConnectionSettings = async ({ connection, controller }) => {
|
|
58
|
+
|
|
59
|
+
const connectionSettings = connection?.settings ? decrypt( connection.settings ) : {};
|
|
60
|
+
|
|
61
|
+
if( ! connection?.credential ){
|
|
62
|
+
|
|
63
|
+
return connectionSettings;
|
|
64
|
+
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const credential = await controller.get({
|
|
68
|
+
collection : 'credential',
|
|
69
|
+
query : {
|
|
70
|
+
id : connection.credential
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
const credentialSettings = credential?.settings ? decrypt( credential.settings ) : {};
|
|
75
|
+
|
|
76
|
+
return {
|
|
77
|
+
...credentialSettings,
|
|
78
|
+
...connectionSettings
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
};
|
|
82
|
+
|
|
26
83
|
const refreshAdminToken = async ({ connection, controller }) => {
|
|
27
84
|
|
|
28
|
-
const
|
|
29
|
-
|
|
85
|
+
const credential = await controller.get({
|
|
86
|
+
collection : 'credential',
|
|
87
|
+
query : {
|
|
88
|
+
id : connection.credential
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
if( ! credential ){
|
|
93
|
+
|
|
94
|
+
throw new Error( 'refreshAdminToken: credential not found for connection ' + connection.id );
|
|
95
|
+
|
|
96
|
+
}
|
|
97
|
+
const settings = decrypt( credential.settings );
|
|
98
|
+
const { identifier : domain } = credential;
|
|
99
|
+
const { refreshToken } = settings;
|
|
30
100
|
|
|
31
101
|
const data = await shopifyOAuthFetch(
|
|
32
102
|
`https://${ domain }/admin/oauth/access_token`,
|
|
@@ -42,86 +112,57 @@ const refreshAdminToken = async ({ connection, controller }) => {
|
|
|
42
112
|
const newRefreshToken = data.refresh_token;
|
|
43
113
|
const expiresIn = data.expires_in;
|
|
44
114
|
const tokenExpiresAt = expiresIn ? new Date( Date.now() + ( expiresIn * 1000 ) ) : null;
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
115
|
+
const refreshTokenExpiresAt = new Date( Date.now() + REFRESH_TOKEN_LIFETIME_MS );
|
|
116
|
+
|
|
117
|
+
await pingShop({ adminAccessToken, domain });
|
|
118
|
+
|
|
119
|
+
await controller.update({
|
|
120
|
+
collection : 'credential',
|
|
121
|
+
data : {
|
|
122
|
+
$set : {
|
|
123
|
+
settings : encrypt({
|
|
124
|
+
...settings,
|
|
125
|
+
adminAccessToken,
|
|
126
|
+
refreshToken : newRefreshToken,
|
|
127
|
+
refreshTokenExpiresAt,
|
|
128
|
+
tokenExpiresAt
|
|
129
|
+
})
|
|
130
|
+
}
|
|
131
|
+
},
|
|
48
132
|
query : {
|
|
49
|
-
|
|
50
|
-
organization : connection.organization,
|
|
51
|
-
system : true,
|
|
52
|
-
title : 'Shopify Token Activity'
|
|
133
|
+
id : credential.id
|
|
53
134
|
}
|
|
54
135
|
});
|
|
55
136
|
|
|
56
|
-
await controller.transaction( async ( session ) => {
|
|
57
|
-
|
|
58
|
-
const options = { session };
|
|
59
|
-
|
|
60
|
-
await controller.update({
|
|
61
|
-
collection : 'connection',
|
|
62
|
-
data : {
|
|
63
|
-
$set : {
|
|
64
|
-
settings : encrypt({
|
|
65
|
-
...settings,
|
|
66
|
-
adminAccessToken,
|
|
67
|
-
refreshToken : newRefreshToken,
|
|
68
|
-
tokenExpiresAt
|
|
69
|
-
})
|
|
70
|
-
}
|
|
71
|
-
},
|
|
72
|
-
options,
|
|
73
|
-
query : {
|
|
74
|
-
id : connection.id
|
|
75
|
-
}
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
if( tokenWorkflow ){
|
|
79
|
-
|
|
80
|
-
await controller.create({
|
|
81
|
-
collection : 'action',
|
|
82
|
-
data : {
|
|
83
|
-
completedAt : new Date(),
|
|
84
|
-
error : null,
|
|
85
|
-
errorStatus : null,
|
|
86
|
-
organization : connection.organization,
|
|
87
|
-
request : null,
|
|
88
|
-
response : null,
|
|
89
|
-
slug : 'action.shopify.token.refresh',
|
|
90
|
-
status : 'succeeded',
|
|
91
|
-
trigger : {
|
|
92
|
-
data : {
|
|
93
|
-
connection : connection.id
|
|
94
|
-
},
|
|
95
|
-
event : 'shopify.token'
|
|
96
|
-
},
|
|
97
|
-
usage : null,
|
|
98
|
-
workflow : tokenWorkflow.id
|
|
99
|
-
},
|
|
100
|
-
options
|
|
101
|
-
});
|
|
102
|
-
|
|
103
|
-
}
|
|
104
|
-
} );
|
|
105
|
-
|
|
106
137
|
return adminAccessToken;
|
|
107
138
|
|
|
108
139
|
};
|
|
109
140
|
|
|
110
141
|
const getAdminToken = async ({ connection, controller }) => {
|
|
111
142
|
|
|
112
|
-
|
|
143
|
+
if( ! connection?.credential ){
|
|
113
144
|
|
|
114
|
-
|
|
115
|
-
|
|
145
|
+
return null;
|
|
146
|
+
|
|
147
|
+
}
|
|
148
|
+
const settings = await resolveConnectionSettings({ connection, controller });
|
|
149
|
+
const { adminAccessToken, refreshToken, tokenExpiresAt } = settings;
|
|
150
|
+
|
|
151
|
+
if( ! refreshToken ){
|
|
152
|
+
|
|
153
|
+
return adminAccessToken;
|
|
154
|
+
|
|
155
|
+
}
|
|
156
|
+
const needsRefresh = ! tokenExpiresAt ||
|
|
157
|
+
new Date( tokenExpiresAt ) < new Date( Date.now() + ACCESS_TOKEN_REFRESH_BUFFER_MS );
|
|
116
158
|
|
|
117
159
|
if( needsRefresh ){
|
|
118
160
|
|
|
119
161
|
return refreshAdminToken({ connection, controller });
|
|
120
162
|
|
|
121
163
|
}
|
|
122
|
-
|
|
123
164
|
return adminAccessToken;
|
|
124
165
|
|
|
125
166
|
};
|
|
126
167
|
|
|
127
|
-
export { getAdminToken, refreshAdminToken };
|
|
168
|
+
export { getAdminToken, refreshAdminToken, resolveConnectionSettings };
|
package/dist/shopify.d.ts
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import { decrypt, encrypt } from './encrypt.js';
|
|
2
2
|
import 'crypto';
|
|
3
3
|
|
|
4
|
+
const SHOPIFY_ADMIN_API_VERSION = '2025-01';
|
|
5
|
+
const REFRESH_TOKEN_LIFETIME_MS = 90 * 24 * 60 * 60 * 1000;
|
|
6
|
+
const ACCESS_TOKEN_REFRESH_BUFFER_MS = 5 * 60 * 1000;
|
|
7
|
+
|
|
4
8
|
const shopifyOAuthFetch = async ( url, body ) => {
|
|
5
9
|
|
|
6
10
|
const response = await fetch( url, {
|
|
@@ -14,8 +18,11 @@ const shopifyOAuthFetch = async ( url, body ) => {
|
|
|
14
18
|
if( ! response.ok ){
|
|
15
19
|
|
|
16
20
|
const text = await response.text().catch( () => '' );
|
|
21
|
+
const error = new Error( response.status + ': ' + text );
|
|
22
|
+
|
|
23
|
+
error.status = response.status;
|
|
17
24
|
|
|
18
|
-
throw
|
|
25
|
+
throw error;
|
|
19
26
|
|
|
20
27
|
}
|
|
21
28
|
|
|
@@ -23,10 +30,73 @@ const shopifyOAuthFetch = async ( url, body ) => {
|
|
|
23
30
|
|
|
24
31
|
};
|
|
25
32
|
|
|
33
|
+
const pingShop = async ({ adminAccessToken, domain }) => {
|
|
34
|
+
|
|
35
|
+
const response = await fetch(
|
|
36
|
+
`https://${ domain }/admin/api/${ SHOPIFY_ADMIN_API_VERSION }/shop.json`,
|
|
37
|
+
{
|
|
38
|
+
headers : {
|
|
39
|
+
'X-Shopify-Access-Token' : adminAccessToken
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
if( ! response.ok ){
|
|
45
|
+
|
|
46
|
+
const text = await response.text().catch( () => '' );
|
|
47
|
+
const error = new Error( response.status + ': ' + text );
|
|
48
|
+
|
|
49
|
+
error.status = response.status;
|
|
50
|
+
|
|
51
|
+
throw error;
|
|
52
|
+
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
const resolveConnectionSettings = async ({ connection, controller }) => {
|
|
58
|
+
|
|
59
|
+
const connectionSettings = connection?.settings ? decrypt( connection.settings ) : {};
|
|
60
|
+
|
|
61
|
+
if( ! connection?.credential ){
|
|
62
|
+
|
|
63
|
+
return connectionSettings;
|
|
64
|
+
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const credential = await controller.get({
|
|
68
|
+
collection : 'credential',
|
|
69
|
+
query : {
|
|
70
|
+
id : connection.credential
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
const credentialSettings = credential?.settings ? decrypt( credential.settings ) : {};
|
|
75
|
+
|
|
76
|
+
return {
|
|
77
|
+
...credentialSettings,
|
|
78
|
+
...connectionSettings
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
};
|
|
82
|
+
|
|
26
83
|
const refreshAdminToken = async ({ connection, controller }) => {
|
|
27
84
|
|
|
28
|
-
const
|
|
29
|
-
|
|
85
|
+
const credential = await controller.get({
|
|
86
|
+
collection : 'credential',
|
|
87
|
+
query : {
|
|
88
|
+
id : connection.credential
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
if( ! credential ){
|
|
93
|
+
|
|
94
|
+
throw new Error( 'refreshAdminToken: credential not found for connection ' + connection.id );
|
|
95
|
+
|
|
96
|
+
}
|
|
97
|
+
const settings = decrypt( credential.settings );
|
|
98
|
+
const { identifier : domain } = credential;
|
|
99
|
+
const { refreshToken } = settings;
|
|
30
100
|
|
|
31
101
|
const data = await shopifyOAuthFetch(
|
|
32
102
|
`https://${ domain }/admin/oauth/access_token`,
|
|
@@ -42,86 +112,57 @@ const refreshAdminToken = async ({ connection, controller }) => {
|
|
|
42
112
|
const newRefreshToken = data.refresh_token;
|
|
43
113
|
const expiresIn = data.expires_in;
|
|
44
114
|
const tokenExpiresAt = expiresIn ? new Date( Date.now() + ( expiresIn * 1000 ) ) : null;
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
115
|
+
const refreshTokenExpiresAt = new Date( Date.now() + REFRESH_TOKEN_LIFETIME_MS );
|
|
116
|
+
|
|
117
|
+
await pingShop({ adminAccessToken, domain });
|
|
118
|
+
|
|
119
|
+
await controller.update({
|
|
120
|
+
collection : 'credential',
|
|
121
|
+
data : {
|
|
122
|
+
$set : {
|
|
123
|
+
settings : encrypt({
|
|
124
|
+
...settings,
|
|
125
|
+
adminAccessToken,
|
|
126
|
+
refreshToken : newRefreshToken,
|
|
127
|
+
refreshTokenExpiresAt,
|
|
128
|
+
tokenExpiresAt
|
|
129
|
+
})
|
|
130
|
+
}
|
|
131
|
+
},
|
|
48
132
|
query : {
|
|
49
|
-
|
|
50
|
-
organization : connection.organization,
|
|
51
|
-
system : true,
|
|
52
|
-
title : 'Shopify Token Activity'
|
|
133
|
+
id : credential.id
|
|
53
134
|
}
|
|
54
135
|
});
|
|
55
136
|
|
|
56
|
-
await controller.transaction( async ( session ) => {
|
|
57
|
-
|
|
58
|
-
const options = { session };
|
|
59
|
-
|
|
60
|
-
await controller.update({
|
|
61
|
-
collection : 'connection',
|
|
62
|
-
data : {
|
|
63
|
-
$set : {
|
|
64
|
-
settings : encrypt({
|
|
65
|
-
...settings,
|
|
66
|
-
adminAccessToken,
|
|
67
|
-
refreshToken : newRefreshToken,
|
|
68
|
-
tokenExpiresAt
|
|
69
|
-
})
|
|
70
|
-
}
|
|
71
|
-
},
|
|
72
|
-
options,
|
|
73
|
-
query : {
|
|
74
|
-
id : connection.id
|
|
75
|
-
}
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
if( tokenWorkflow ){
|
|
79
|
-
|
|
80
|
-
await controller.create({
|
|
81
|
-
collection : 'action',
|
|
82
|
-
data : {
|
|
83
|
-
completedAt : new Date(),
|
|
84
|
-
error : null,
|
|
85
|
-
errorStatus : null,
|
|
86
|
-
organization : connection.organization,
|
|
87
|
-
request : null,
|
|
88
|
-
response : null,
|
|
89
|
-
slug : 'action.shopify.token.refresh',
|
|
90
|
-
status : 'succeeded',
|
|
91
|
-
trigger : {
|
|
92
|
-
data : {
|
|
93
|
-
connection : connection.id
|
|
94
|
-
},
|
|
95
|
-
event : 'shopify.token'
|
|
96
|
-
},
|
|
97
|
-
usage : null,
|
|
98
|
-
workflow : tokenWorkflow.id
|
|
99
|
-
},
|
|
100
|
-
options
|
|
101
|
-
});
|
|
102
|
-
|
|
103
|
-
}
|
|
104
|
-
} );
|
|
105
|
-
|
|
106
137
|
return adminAccessToken;
|
|
107
138
|
|
|
108
139
|
};
|
|
109
140
|
|
|
110
141
|
const getAdminToken = async ({ connection, controller }) => {
|
|
111
142
|
|
|
112
|
-
|
|
143
|
+
if( ! connection?.credential ){
|
|
113
144
|
|
|
114
|
-
|
|
115
|
-
|
|
145
|
+
return null;
|
|
146
|
+
|
|
147
|
+
}
|
|
148
|
+
const settings = await resolveConnectionSettings({ connection, controller });
|
|
149
|
+
const { adminAccessToken, refreshToken, tokenExpiresAt } = settings;
|
|
150
|
+
|
|
151
|
+
if( ! refreshToken ){
|
|
152
|
+
|
|
153
|
+
return adminAccessToken;
|
|
154
|
+
|
|
155
|
+
}
|
|
156
|
+
const needsRefresh = ! tokenExpiresAt ||
|
|
157
|
+
new Date( tokenExpiresAt ) < new Date( Date.now() + ACCESS_TOKEN_REFRESH_BUFFER_MS );
|
|
116
158
|
|
|
117
159
|
if( needsRefresh ){
|
|
118
160
|
|
|
119
161
|
return refreshAdminToken({ connection, controller });
|
|
120
162
|
|
|
121
163
|
}
|
|
122
|
-
|
|
123
164
|
return adminAccessToken;
|
|
124
165
|
|
|
125
166
|
};
|
|
126
167
|
|
|
127
|
-
export { getAdminToken, refreshAdminToken };
|
|
168
|
+
export { getAdminToken, refreshAdminToken, resolveConnectionSettings };
|
package/dist/shopify.js
CHANGED
|
@@ -4,6 +4,9 @@ import {
|
|
|
4
4
|
} from "./chunk-CUUQCM5T.js";
|
|
5
5
|
|
|
6
6
|
// shopify.js
|
|
7
|
+
var SHOPIFY_ADMIN_API_VERSION = "2025-01";
|
|
8
|
+
var REFRESH_TOKEN_LIFETIME_MS = 90 * 24 * 60 * 60 * 1e3;
|
|
9
|
+
var ACCESS_TOKEN_REFRESH_BUFFER_MS = 5 * 60 * 1e3;
|
|
7
10
|
var shopifyOAuthFetch = async (url, body) => {
|
|
8
11
|
const response = await fetch(url, {
|
|
9
12
|
method: "POST",
|
|
@@ -14,13 +17,59 @@ var shopifyOAuthFetch = async (url, body) => {
|
|
|
14
17
|
});
|
|
15
18
|
if (!response.ok) {
|
|
16
19
|
const text = await response.text().catch(() => "");
|
|
17
|
-
|
|
20
|
+
const error = new Error(response.status + ": " + text);
|
|
21
|
+
error.status = response.status;
|
|
22
|
+
throw error;
|
|
18
23
|
}
|
|
19
24
|
return response.json();
|
|
20
25
|
};
|
|
26
|
+
var pingShop = async ({ adminAccessToken, domain }) => {
|
|
27
|
+
const response = await fetch(
|
|
28
|
+
`https://${domain}/admin/api/${SHOPIFY_ADMIN_API_VERSION}/shop.json`,
|
|
29
|
+
{
|
|
30
|
+
headers: {
|
|
31
|
+
"X-Shopify-Access-Token": adminAccessToken
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
);
|
|
35
|
+
if (!response.ok) {
|
|
36
|
+
const text = await response.text().catch(() => "");
|
|
37
|
+
const error = new Error(response.status + ": " + text);
|
|
38
|
+
error.status = response.status;
|
|
39
|
+
throw error;
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
var resolveConnectionSettings = async ({ connection, controller }) => {
|
|
43
|
+
const connectionSettings = (connection == null ? void 0 : connection.settings) ? decrypt(connection.settings) : {};
|
|
44
|
+
if (!(connection == null ? void 0 : connection.credential)) {
|
|
45
|
+
return connectionSettings;
|
|
46
|
+
}
|
|
47
|
+
const credential = await controller.get({
|
|
48
|
+
collection: "credential",
|
|
49
|
+
query: {
|
|
50
|
+
id: connection.credential
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
const credentialSettings = (credential == null ? void 0 : credential.settings) ? decrypt(credential.settings) : {};
|
|
54
|
+
return {
|
|
55
|
+
...credentialSettings,
|
|
56
|
+
...connectionSettings
|
|
57
|
+
};
|
|
58
|
+
};
|
|
21
59
|
var refreshAdminToken = async ({ connection, controller }) => {
|
|
22
|
-
const
|
|
23
|
-
|
|
60
|
+
const credential = await controller.get({
|
|
61
|
+
collection: "credential",
|
|
62
|
+
query: {
|
|
63
|
+
id: connection.credential
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
if (!credential) {
|
|
67
|
+
throw new Error("refreshAdminToken: credential not found for connection " + connection.id);
|
|
68
|
+
}
|
|
69
|
+
;
|
|
70
|
+
const settings = decrypt(credential.settings);
|
|
71
|
+
const { identifier: domain } = credential;
|
|
72
|
+
const { refreshToken } = settings;
|
|
24
73
|
const data = await shopifyOAuthFetch(
|
|
25
74
|
`https://${domain}/admin/oauth/access_token`,
|
|
26
75
|
{
|
|
@@ -34,71 +83,47 @@ var refreshAdminToken = async ({ connection, controller }) => {
|
|
|
34
83
|
const newRefreshToken = data.refresh_token;
|
|
35
84
|
const expiresIn = data.expires_in;
|
|
36
85
|
const tokenExpiresAt = expiresIn ? new Date(Date.now() + expiresIn * 1e3) : null;
|
|
37
|
-
const
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
data: {
|
|
51
|
-
$set: {
|
|
52
|
-
settings: encrypt({
|
|
53
|
-
...settings,
|
|
54
|
-
adminAccessToken,
|
|
55
|
-
refreshToken: newRefreshToken,
|
|
56
|
-
tokenExpiresAt
|
|
57
|
-
})
|
|
58
|
-
}
|
|
59
|
-
},
|
|
60
|
-
options,
|
|
61
|
-
query: {
|
|
62
|
-
id: connection.id
|
|
86
|
+
const refreshTokenExpiresAt = new Date(Date.now() + REFRESH_TOKEN_LIFETIME_MS);
|
|
87
|
+
await pingShop({ adminAccessToken, domain });
|
|
88
|
+
await controller.update({
|
|
89
|
+
collection: "credential",
|
|
90
|
+
data: {
|
|
91
|
+
$set: {
|
|
92
|
+
settings: encrypt({
|
|
93
|
+
...settings,
|
|
94
|
+
adminAccessToken,
|
|
95
|
+
refreshToken: newRefreshToken,
|
|
96
|
+
refreshTokenExpiresAt,
|
|
97
|
+
tokenExpiresAt
|
|
98
|
+
})
|
|
63
99
|
}
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
collection: "action",
|
|
68
|
-
data: {
|
|
69
|
-
completedAt: /* @__PURE__ */ new Date(),
|
|
70
|
-
error: null,
|
|
71
|
-
errorStatus: null,
|
|
72
|
-
organization: connection.organization,
|
|
73
|
-
request: null,
|
|
74
|
-
response: null,
|
|
75
|
-
slug: "action.shopify.token.refresh",
|
|
76
|
-
status: "succeeded",
|
|
77
|
-
trigger: {
|
|
78
|
-
data: {
|
|
79
|
-
connection: connection.id
|
|
80
|
-
},
|
|
81
|
-
event: "shopify.token"
|
|
82
|
-
},
|
|
83
|
-
usage: null,
|
|
84
|
-
workflow: tokenWorkflow.id
|
|
85
|
-
},
|
|
86
|
-
options
|
|
87
|
-
});
|
|
100
|
+
},
|
|
101
|
+
query: {
|
|
102
|
+
id: credential.id
|
|
88
103
|
}
|
|
89
|
-
;
|
|
90
104
|
});
|
|
91
105
|
return adminAccessToken;
|
|
92
106
|
};
|
|
93
107
|
var getAdminToken = async ({ connection, controller }) => {
|
|
94
|
-
|
|
95
|
-
|
|
108
|
+
if (!(connection == null ? void 0 : connection.credential)) {
|
|
109
|
+
return null;
|
|
110
|
+
}
|
|
111
|
+
;
|
|
112
|
+
const settings = await resolveConnectionSettings({ connection, controller });
|
|
113
|
+
const { adminAccessToken, refreshToken, tokenExpiresAt } = settings;
|
|
114
|
+
if (!refreshToken) {
|
|
115
|
+
return adminAccessToken;
|
|
116
|
+
}
|
|
117
|
+
;
|
|
118
|
+
const needsRefresh = !tokenExpiresAt || new Date(tokenExpiresAt) < new Date(Date.now() + ACCESS_TOKEN_REFRESH_BUFFER_MS);
|
|
96
119
|
if (needsRefresh) {
|
|
97
120
|
return refreshAdminToken({ connection, controller });
|
|
98
121
|
}
|
|
122
|
+
;
|
|
99
123
|
return adminAccessToken;
|
|
100
124
|
};
|
|
101
125
|
export {
|
|
102
126
|
getAdminToken,
|
|
103
|
-
refreshAdminToken
|
|
127
|
+
refreshAdminToken,
|
|
128
|
+
resolveConnectionSettings
|
|
104
129
|
};
|
package/package.json
CHANGED