@shopify/shopify-app-remix 4.2.1 → 5.0.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/cjs/server/authenticate/admin/authenticate.js +1 -3
- package/dist/cjs/server/authenticate/admin/authenticate.js.map +1 -1
- package/dist/cjs/server/authenticate/admin/helpers/validate-redirect-url.js +1 -1
- package/dist/cjs/server/authenticate/admin/helpers/validate-redirect-url.js.map +1 -1
- package/dist/cjs/server/authenticate/public/appProxy/authenticate.js +9 -3
- package/dist/cjs/server/authenticate/public/appProxy/authenticate.js.map +1 -1
- package/dist/cjs/server/authenticate/webhooks/authenticate.js +0 -1
- package/dist/cjs/server/authenticate/webhooks/authenticate.js.map +1 -1
- package/dist/cjs/server/shopify-app.js +1 -1
- package/dist/cjs/server/shopify-app.js.map +1 -1
- package/dist/cjs/server/test-helpers/test-config.js.map +1 -1
- package/dist/cjs/server/version.js +1 -1
- package/dist/cjs/server/version.js.map +1 -1
- package/dist/esm/server/authenticate/admin/authenticate.mjs +1 -3
- package/dist/esm/server/authenticate/admin/authenticate.mjs.map +1 -1
- package/dist/esm/server/authenticate/admin/helpers/validate-redirect-url.mjs +1 -1
- package/dist/esm/server/authenticate/admin/helpers/validate-redirect-url.mjs.map +1 -1
- package/dist/esm/server/authenticate/public/appProxy/authenticate.mjs +9 -3
- package/dist/esm/server/authenticate/public/appProxy/authenticate.mjs.map +1 -1
- package/dist/esm/server/authenticate/webhooks/authenticate.mjs +0 -1
- package/dist/esm/server/authenticate/webhooks/authenticate.mjs.map +1 -1
- package/dist/esm/server/shopify-app.mjs +1 -1
- package/dist/esm/server/shopify-app.mjs.map +1 -1
- package/dist/esm/server/test-helpers/test-config.mjs.map +1 -1
- package/dist/esm/server/version.mjs +1 -1
- package/dist/esm/server/version.mjs.map +1 -1
- package/dist/ts/server/authenticate/admin/authenticate.d.ts.map +1 -1
- package/dist/ts/server/authenticate/webhooks/authenticate.d.ts.map +1 -1
- package/dist/ts/server/authenticate/webhooks/types.d.ts +0 -19
- package/dist/ts/server/authenticate/webhooks/types.d.ts.map +1 -1
- package/dist/ts/server/config-types.d.ts +1 -1
- package/dist/ts/server/shopify-app.d.ts.map +1 -1
- package/dist/ts/server/test-helpers/test-config.d.ts.map +1 -1
- package/dist/ts/server/version.d.ts +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +11 -12
- package/src/server/__test-helpers/const.ts +1 -1
- package/src/server/__test-helpers/expect-admin-api-client.ts +1 -1
- package/src/server/__test-helpers/expect-storefront-api-client.ts +1 -1
- package/src/server/__test-helpers/mock-graphql-request.ts +2 -2
- package/src/server/__test-helpers/request-mock.ts +1 -1
- package/src/server/__test-helpers/setup-valid-request.ts +1 -2
- package/src/server/__test-helpers/test-config.ts +1 -1
- package/src/server/authenticate/admin/authenticate.ts +3 -6
- package/src/server/authenticate/admin/helpers/validate-redirect-url.ts +1 -1
- package/src/server/authenticate/public/appProxy/authenticate.ts +9 -12
- package/src/server/authenticate/public/customer-account/authenticate.public.customerAccount.doc.example.ts +2 -1
- package/src/server/authenticate/webhooks/authenticate.ts +0 -1
- package/src/server/authenticate/webhooks/authenticate.webhooks.doc.example.ts +6 -6
- package/src/server/authenticate/webhooks/types.ts +1 -22
- package/src/server/config-types.ts +1 -1
- package/src/server/shopify-app.ts +2 -4
- package/src/server/test-helpers/test-config.ts +3 -3
- package/src/server/version.ts +1 -1
package/package.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shopify/shopify-app-remix",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "5.0.0",
|
|
4
4
|
"description": "Shopify Remix - to simplify the building of Shopify Apps with Remix",
|
|
5
5
|
"engines": {
|
|
6
|
-
"node": ">=
|
|
6
|
+
"node": ">=22.0.0"
|
|
7
7
|
},
|
|
8
8
|
"repository": {
|
|
9
9
|
"type": "git",
|
|
@@ -70,21 +70,21 @@
|
|
|
70
70
|
"@remix-run/node": "^2.17.5",
|
|
71
71
|
"@remix-run/react": "^2.17.5",
|
|
72
72
|
"@remix-run/testing": "^2.17.5",
|
|
73
|
-
"@shopify/generate-docs": "^1.2.
|
|
73
|
+
"@shopify/generate-docs": "^1.2.3",
|
|
74
74
|
"@shopify/polaris": "^12.18.0",
|
|
75
75
|
"@shopify/react-testing": "^6.0.0",
|
|
76
|
-
"@shopify/shopify-app-session-storage-memory": "^
|
|
77
|
-
"@types/react": "^19.2.
|
|
78
|
-
"jest-fetch-mock": "^3.0
|
|
76
|
+
"@shopify/shopify-app-session-storage-memory": "^7.0.0",
|
|
77
|
+
"@types/react": "^19.2.17",
|
|
78
|
+
"jest-fetch-mock": "^3.2.0"
|
|
79
79
|
},
|
|
80
80
|
"dependencies": {
|
|
81
81
|
"@remix-run/server-runtime": "^2.17.5",
|
|
82
|
-
"@shopify/admin-api-client": "^
|
|
83
|
-
"@shopify/shopify-api": "^
|
|
84
|
-
"@shopify/shopify-app-session-storage": "^
|
|
85
|
-
"@shopify/storefront-api-client": "^
|
|
82
|
+
"@shopify/admin-api-client": "^2.0.0",
|
|
83
|
+
"@shopify/shopify-api": "^14.0.0",
|
|
84
|
+
"@shopify/shopify-app-session-storage": "^6.0.0",
|
|
85
|
+
"@shopify/storefront-api-client": "^2.0.0",
|
|
86
86
|
"compare-versions": "^6.1.1",
|
|
87
|
-
"isbot": "^5.
|
|
87
|
+
"isbot": "^5.2.0"
|
|
88
88
|
},
|
|
89
89
|
"peerDependencies": {
|
|
90
90
|
"@remix-run/node": "*",
|
|
@@ -113,7 +113,6 @@
|
|
|
113
113
|
"scripts": {
|
|
114
114
|
"build-docs": "sh docs/build-docs.sh",
|
|
115
115
|
"validate-docs": "sh ./docs/build-docs.sh isTest && pnpm compare-docs",
|
|
116
|
-
"lint": "eslint .",
|
|
117
116
|
"build": "pnpm rollup && pnpm tsc -p ./tsconfig.build.json",
|
|
118
117
|
"tsc": "tsc",
|
|
119
118
|
"test": "jest",
|
|
@@ -11,4 +11,4 @@ export {
|
|
|
11
11
|
BASE64_HOST,
|
|
12
12
|
USER_ID,
|
|
13
13
|
} from '@shopify/shopify-api/test-helpers';
|
|
14
|
-
export const GRAPHQL_URL = `https://${TEST_SHOP}/admin/api/${ApiVersion.
|
|
14
|
+
export const GRAPHQL_URL = `https://${TEST_SHOP}/admin/api/${ApiVersion.July26}/graphql.json`;
|
|
@@ -18,7 +18,7 @@ export function expectAdminApiClient(
|
|
|
18
18
|
const {admin, actualSession} = await factory();
|
|
19
19
|
await mockExternalRequest({
|
|
20
20
|
request: new Request(
|
|
21
|
-
`https://${TEST_SHOP}/admin/api/${ApiVersion.
|
|
21
|
+
`https://${TEST_SHOP}/admin/api/${ApiVersion.July26}/graphql.json`,
|
|
22
22
|
{
|
|
23
23
|
method: 'POST',
|
|
24
24
|
headers: {'X-Shopify-Access-Token': actualSession.accessToken!},
|
|
@@ -18,7 +18,7 @@ export function expectStorefrontApiClient(
|
|
|
18
18
|
const apiResponse = {data: {blogs: {nodes: [{id: 1}]}}, headers: {}};
|
|
19
19
|
await mockExternalRequest({
|
|
20
20
|
request: new Request(
|
|
21
|
-
`https://${TEST_SHOP}/api/${ApiVersion.
|
|
21
|
+
`https://${TEST_SHOP}/api/${ApiVersion.July26}/graphql.json`,
|
|
22
22
|
{
|
|
23
23
|
method: 'POST',
|
|
24
24
|
headers: {
|
|
@@ -10,7 +10,7 @@ export interface MockGraphqlRequestArg {
|
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
export function mockGraphqlRequest(
|
|
13
|
-
apiVersion = ApiVersion.
|
|
13
|
+
apiVersion = ApiVersion.July26,
|
|
14
14
|
shopUrl = TEST_SHOP,
|
|
15
15
|
) {
|
|
16
16
|
return async function ({
|
|
@@ -32,7 +32,7 @@ export function mockGraphqlRequest(
|
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
export function mockGraphqlRequests(
|
|
35
|
-
apiVersion = ApiVersion.
|
|
35
|
+
apiVersion = ApiVersion.July26,
|
|
36
36
|
shopUrl = TEST_SHOP,
|
|
37
37
|
) {
|
|
38
38
|
return async function (...mocks: MockGraphqlRequestArg[]) {
|
|
@@ -99,7 +99,7 @@ export async function validateMocks() {
|
|
|
99
99
|
// TODO: we're currently not checking the headers properly. We should fix this.
|
|
100
100
|
Object.entries(request.headers).forEach(([key, value]) => {
|
|
101
101
|
expected.headers[key] = value;
|
|
102
|
-
actual.headers[key] = (init?.headers as any)[key];
|
|
102
|
+
actual.headers[key] = (init?.headers as any)?.[key];
|
|
103
103
|
});
|
|
104
104
|
}
|
|
105
105
|
|
|
@@ -20,8 +20,7 @@ interface ValidExtensionRequestOptions {
|
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
type ValidRequestOptions =
|
|
23
|
-
|
|
|
24
|
-
| ValidExtensionRequestOptions;
|
|
23
|
+
ValidBaseRequestOptions | ValidExtensionRequestOptions;
|
|
25
24
|
|
|
26
25
|
export async function setupValidRequest(
|
|
27
26
|
shopify: ShopifyApp<any>,
|
|
@@ -19,7 +19,7 @@ const TEST_FUTURE_FLAGS: Required<{[key in keyof FutureFlags]: true}> = {
|
|
|
19
19
|
|
|
20
20
|
// Override the helper's future flags and logger settings for our purposes
|
|
21
21
|
const TEST_CONFIG = {
|
|
22
|
-
apiVersion: ApiVersion.
|
|
22
|
+
apiVersion: ApiVersion.July26,
|
|
23
23
|
isEmbeddedApp: true,
|
|
24
24
|
future: TEST_FUTURE_FLAGS,
|
|
25
25
|
logger: {
|
|
@@ -80,8 +80,7 @@ export function authStrategyFactory<ConfigArg extends AppConfigArg>({
|
|
|
80
80
|
}
|
|
81
81
|
|
|
82
82
|
type AdminContextBase =
|
|
83
|
-
|
|
|
84
|
-
| NonEmbeddedAdminContext<ConfigArg>;
|
|
83
|
+
EmbeddedAdminContext<ConfigArg> | NonEmbeddedAdminContext<ConfigArg>;
|
|
85
84
|
|
|
86
85
|
function createContext(
|
|
87
86
|
request: Request,
|
|
@@ -157,13 +156,11 @@ export function authStrategyFactory<ConfigArg extends AppConfigArg>({
|
|
|
157
156
|
await ensureSessionTokenSearchParamIfRequired(params, request);
|
|
158
157
|
}
|
|
159
158
|
|
|
160
|
-
logger.info('Authenticating admin request', {
|
|
161
|
-
shop: getShopFromRequest(request),
|
|
162
|
-
});
|
|
163
|
-
|
|
164
159
|
const {payload, shop, sessionId, sessionToken} =
|
|
165
160
|
await getSessionTokenContext(params, request);
|
|
166
161
|
|
|
162
|
+
logger.info('Authenticating admin request', {shop});
|
|
163
|
+
|
|
167
164
|
logger.debug('Loading session from storage', {shop, sessionId});
|
|
168
165
|
const existingSession = sessionId
|
|
169
166
|
? await config.sessionStorage!.loadSession(sessionId)
|
|
@@ -95,10 +95,9 @@ async function validateAppProxyHmac(
|
|
|
95
95
|
searchParams.delete('index');
|
|
96
96
|
}
|
|
97
97
|
|
|
98
|
-
let isValid = await api.utils.validateHmac(
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
);
|
|
98
|
+
let isValid = await api.utils.validateHmac(searchParams, {
|
|
99
|
+
signator: 'appProxy',
|
|
100
|
+
});
|
|
102
101
|
|
|
103
102
|
if (!isValid) {
|
|
104
103
|
const cleanPath = url.pathname
|
|
@@ -111,20 +110,18 @@ async function validateAppProxyHmac(
|
|
|
111
110
|
`?_data=${data}&${searchParams.toString().replace(/^\?/, '')}`,
|
|
112
111
|
);
|
|
113
112
|
|
|
114
|
-
isValid = await api.utils.validateHmac(
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
);
|
|
113
|
+
isValid = await api.utils.validateHmac(searchParams, {
|
|
114
|
+
signator: 'appProxy',
|
|
115
|
+
});
|
|
118
116
|
|
|
119
117
|
if (!isValid) {
|
|
120
118
|
const searchParams = new URLSearchParams(
|
|
121
119
|
`?_data=${data}._index&${url.search.replace(/^\?/, '')}`,
|
|
122
120
|
);
|
|
123
121
|
|
|
124
|
-
isValid = await api.utils.validateHmac(
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
);
|
|
122
|
+
isValid = await api.utils.validateHmac(searchParams, {
|
|
123
|
+
signator: 'appProxy',
|
|
124
|
+
});
|
|
128
125
|
}
|
|
129
126
|
}
|
|
130
127
|
|
|
@@ -10,7 +10,8 @@ export const loader = async ({request}: LoaderFunctionArgs) => {
|
|
|
10
10
|
};
|
|
11
11
|
|
|
12
12
|
export const action = async ({request}: ActionFunctionArgs) => {
|
|
13
|
-
const {cors, sessionToken} =
|
|
13
|
+
const {cors, sessionToken} =
|
|
14
|
+
await authenticate.public.customerAccount(request);
|
|
14
15
|
|
|
15
16
|
// Get offers for the customer
|
|
16
17
|
const offers = getOffers(sessionToken.des, sessionToken.sub);
|
|
@@ -60,7 +60,6 @@ export function authenticateWebhookFactory<Topics extends string>(
|
|
|
60
60
|
topic: check.topic as Topics,
|
|
61
61
|
webhookId: check.webhookId,
|
|
62
62
|
payload: JSON.parse(rawBody),
|
|
63
|
-
subTopic: check.subTopic || undefined,
|
|
64
63
|
session: undefined,
|
|
65
64
|
admin: undefined,
|
|
66
65
|
webhookType: check.webhookType,
|
|
@@ -30,13 +30,13 @@ export const action = async ({request}: ActionFunctionArgs) => {
|
|
|
30
30
|
}
|
|
31
31
|
}
|
|
32
32
|
`,
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
33
|
+
{
|
|
34
|
+
variables: {
|
|
35
|
+
productId: payload.admin_graphql_api_id,
|
|
36
|
+
time: new Date().toISOString(),
|
|
37
|
+
},
|
|
37
38
|
},
|
|
38
|
-
|
|
39
|
-
);
|
|
39
|
+
);
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
return new Response();
|
|
@@ -118,26 +118,6 @@ interface Context<Topics = string | number | symbol> {
|
|
|
118
118
|
*/
|
|
119
119
|
webhookType: WebhookTypeValue;
|
|
120
120
|
|
|
121
|
-
/**
|
|
122
|
-
* The sub-topic of the webhook. Only available for traditional webhooks.
|
|
123
|
-
*
|
|
124
|
-
* @example
|
|
125
|
-
* <caption>Webhook sub-topic.</caption>
|
|
126
|
-
* <description>Get the webhook sub-topic.</description>
|
|
127
|
-
* ```ts
|
|
128
|
-
* // /app/routes/webhooks.tsx
|
|
129
|
-
* import { ActionFunctionArgs } from "@remix-run/node";
|
|
130
|
-
* import { authenticate } from "../shopify.server";
|
|
131
|
-
*
|
|
132
|
-
* export const action = async ({ request }: ActionFunctionArgs) => {
|
|
133
|
-
* const { subTopic } = await authenticate.webhook(request);
|
|
134
|
-
* return new Response();
|
|
135
|
-
* };
|
|
136
|
-
* ```
|
|
137
|
-
*
|
|
138
|
-
*/
|
|
139
|
-
subTopic?: string;
|
|
140
|
-
|
|
141
121
|
/**
|
|
142
122
|
* The name assigned to the webhook subscription. Only available for traditional webhooks.
|
|
143
123
|
*/
|
|
@@ -255,8 +235,7 @@ export interface WebhookContextWithSession<
|
|
|
255
235
|
}
|
|
256
236
|
|
|
257
237
|
export type WebhookContext<Topics = string | number | symbol> =
|
|
258
|
-
|
|
|
259
|
-
| WebhookContextWithSession<Topics>;
|
|
238
|
+
WebhookContextWithoutSession<Topics> | WebhookContextWithSession<Topics>;
|
|
260
239
|
|
|
261
240
|
/**
|
|
262
241
|
* Verifies requests coming from Shopify webhooks.
|
|
@@ -89,9 +89,7 @@ export function shopifyApp<
|
|
|
89
89
|
});
|
|
90
90
|
|
|
91
91
|
const shopify:
|
|
92
|
-
|
|
|
93
|
-
| AppStoreApp<Config>
|
|
94
|
-
| SingleMerchantApp<Config> = {
|
|
92
|
+
AdminApp<Config> | AppStoreApp<Config> | SingleMerchantApp<Config> = {
|
|
95
93
|
sessionStorage: config.sessionStorage,
|
|
96
94
|
addDocumentResponseHeaders: addDocumentResponseHeadersFactory(params),
|
|
97
95
|
registerWebhooks: registerWebhooksFactory(params),
|
|
@@ -140,7 +138,7 @@ export function deriveApi(appConfig: AppConfigArg): BasicParams['api'] {
|
|
|
140
138
|
let appUrl: URL;
|
|
141
139
|
try {
|
|
142
140
|
appUrl = new URL(appConfig.appUrl);
|
|
143
|
-
} catch (
|
|
141
|
+
} catch (_error) {
|
|
144
142
|
const message =
|
|
145
143
|
appConfig.appUrl === ''
|
|
146
144
|
? `Detected an empty appUrl configuration, please make sure to set the necessary environment variables.\n` +
|
|
@@ -51,9 +51,9 @@ export function testConfig<
|
|
|
51
51
|
* the output being a const object.
|
|
52
52
|
*/
|
|
53
53
|
type Modify<Type1, Type2> = {
|
|
54
|
-
[
|
|
55
|
-
? never
|
|
56
|
-
|
|
54
|
+
[
|
|
55
|
+
key in keyof Type2 as Type2[key] extends undefined ? never : key
|
|
56
|
+
]: Type2[key];
|
|
57
57
|
} & {
|
|
58
58
|
[key in keyof Type1 as key extends keyof Type2 ? never : key]: Type1[key];
|
|
59
59
|
};
|
package/src/server/version.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const SHOPIFY_REMIX_LIBRARY_VERSION = '
|
|
1
|
+
export const SHOPIFY_REMIX_LIBRARY_VERSION = '5.0.0';
|