@shopify/shop-minis-react 0.18.0 → 0.20.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/eslint/config.cjs +20 -0
- package/generated-hook-maps/hook-actions-map.json +6 -0
- package/package.json +3 -2
- package/src/hooks/index.ts +2 -0
- package/src/hooks/util/useCheckScopesConsent.ts +61 -0
- package/src/hooks/util/useRequestPermissions.ts +1 -0
- package/src/hooks/util/useRequestScopesConsent.ts +38 -0
- package/src/mocks.ts +8 -0
package/eslint/config.cjs
CHANGED
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
// Import the plugin directly so consumers don't need to install it separately
|
|
10
10
|
const compatPlugin = require('eslint-plugin-compat')
|
|
11
|
+
const importXPlugin = require('eslint-plugin-import-x')
|
|
11
12
|
const reactPlugin = require('eslint-plugin-react')
|
|
12
13
|
|
|
13
14
|
const shopMinisPlugin = require('./index.cjs')
|
|
@@ -29,6 +30,7 @@ module.exports = {
|
|
|
29
30
|
'shop-minis': shopMinisPlugin,
|
|
30
31
|
react: reactPlugin,
|
|
31
32
|
compat: compatPlugin,
|
|
33
|
+
'import-x': importXPlugin,
|
|
32
34
|
},
|
|
33
35
|
rules: {
|
|
34
36
|
// Console usage
|
|
@@ -37,6 +39,24 @@ module.exports = {
|
|
|
37
39
|
// React security
|
|
38
40
|
'react/no-danger': 'error',
|
|
39
41
|
|
|
42
|
+
// Block phantom-dep imports: every imported package must be declared in
|
|
43
|
+
// package.json. Hoisting can make undeclared imports resolve locally but
|
|
44
|
+
// they break under strict installs (pnpm) in the submission pipeline.
|
|
45
|
+
'import-x/no-extraneous-dependencies': [
|
|
46
|
+
'error',
|
|
47
|
+
{
|
|
48
|
+
devDependencies: [
|
|
49
|
+
'**/*.test.{js,jsx,ts,tsx}',
|
|
50
|
+
'**/*.spec.{js,jsx,ts,tsx}',
|
|
51
|
+
'**/test-setup.{js,ts}',
|
|
52
|
+
'**/test-utils.{js,jsx,ts,tsx}',
|
|
53
|
+
'**/setup-tests.{js,ts}',
|
|
54
|
+
'**/*.config.{js,cjs,mjs,ts}',
|
|
55
|
+
],
|
|
56
|
+
includeTypes: true,
|
|
57
|
+
},
|
|
58
|
+
],
|
|
59
|
+
|
|
40
60
|
// Shop Minis custom rules
|
|
41
61
|
'shop-minis/no-dynamic-asset-paths': 'warn',
|
|
42
62
|
'shop-minis/no-env-without-fallback': 'error',
|
|
@@ -15,6 +15,9 @@
|
|
|
15
15
|
"useCheckPermissions": [
|
|
16
16
|
"CHECK_PERMISSION"
|
|
17
17
|
],
|
|
18
|
+
"useCheckScopesConsent": [
|
|
19
|
+
"CHECK_SCOPES_CONSENT"
|
|
20
|
+
],
|
|
18
21
|
"useCloseMini": [
|
|
19
22
|
"CLOSE_MINI"
|
|
20
23
|
],
|
|
@@ -104,6 +107,9 @@
|
|
|
104
107
|
"useRequestPermissions": [
|
|
105
108
|
"REQUEST_PERMISSION"
|
|
106
109
|
],
|
|
110
|
+
"useRequestScopesConsent": [
|
|
111
|
+
"REQUEST_SCOPES_CONSENT"
|
|
112
|
+
],
|
|
107
113
|
"useSavedProducts": [
|
|
108
114
|
"GET_SAVED_PRODUCTS"
|
|
109
115
|
],
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shopify/shop-minis-react",
|
|
3
3
|
"license": "SEE LICENSE IN LICENSE.txt",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.20.0",
|
|
5
5
|
"sideEffects": false,
|
|
6
6
|
"type": "module",
|
|
7
7
|
"engines": {
|
|
@@ -63,7 +63,7 @@
|
|
|
63
63
|
"typescript": ">=5.0.0"
|
|
64
64
|
},
|
|
65
65
|
"dependencies": {
|
|
66
|
-
"@shopify/shop-minis-platform": "0.
|
|
66
|
+
"@shopify/shop-minis-platform": "0.17.0",
|
|
67
67
|
"@tailwindcss/vite": "4.1.8",
|
|
68
68
|
"@tanstack/react-query": "5.86.0",
|
|
69
69
|
"@types/lodash": "4.17.20",
|
|
@@ -77,6 +77,7 @@
|
|
|
77
77
|
"embla-carousel-react": "8.6.0",
|
|
78
78
|
"eslint": "8.57.0",
|
|
79
79
|
"eslint-plugin-compat": "6.0.2",
|
|
80
|
+
"eslint-plugin-import-x": "4.16.2",
|
|
80
81
|
"eslint-plugin-no-secrets": "2.2.1",
|
|
81
82
|
"eslint-plugin-react": "7.37.5",
|
|
82
83
|
"js-base64": "3.7.7",
|
package/src/hooks/index.ts
CHANGED
|
@@ -51,6 +51,8 @@ export * from './util/useImagePicker'
|
|
|
51
51
|
export * from './util/useKeyboardAvoidingView'
|
|
52
52
|
export * from './util/useRequestPermissions'
|
|
53
53
|
export * from './util/useCheckPermissions'
|
|
54
|
+
export * from './util/useCheckScopesConsent'
|
|
55
|
+
export * from './util/useRequestScopesConsent'
|
|
54
56
|
|
|
55
57
|
// - Intent Hooks
|
|
56
58
|
export * from './intents/useIntent'
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import {CheckScopesConsentResponse} from '@shopify/shop-minis-platform/actions'
|
|
2
|
+
|
|
3
|
+
import {useShopActionQuery} from '../../internal/reactQuery'
|
|
4
|
+
import {useShopActions} from '../../internal/useShopActions'
|
|
5
|
+
|
|
6
|
+
export interface UseCheckScopesConsentReturns {
|
|
7
|
+
/**
|
|
8
|
+
* Required scopes declared by the mini, fetched fresh from the API.
|
|
9
|
+
*/
|
|
10
|
+
requiredScopes: string[] | undefined
|
|
11
|
+
/**
|
|
12
|
+
* Scopes already granted by the user.
|
|
13
|
+
*/
|
|
14
|
+
grantedScopes: string[] | undefined
|
|
15
|
+
/**
|
|
16
|
+
* Consent status derived from comparing required vs granted scopes.
|
|
17
|
+
*
|
|
18
|
+
* - `'granted'` — all required scopes are granted, or none declared
|
|
19
|
+
* - `'partially_granted'` — at least one required scope is granted but not all
|
|
20
|
+
* - `'not_granted'` — no required scopes are granted
|
|
21
|
+
*/
|
|
22
|
+
status: CheckScopesConsentResponse['status'] | undefined
|
|
23
|
+
loading: boolean
|
|
24
|
+
error: Error | null
|
|
25
|
+
/**
|
|
26
|
+
* Re-fetch scope consent status. Call this after `requestScopesConsent()` resolves
|
|
27
|
+
* to get the updated status.
|
|
28
|
+
*/
|
|
29
|
+
refetch: () => Promise<void>
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export const useCheckScopesConsent = (): UseCheckScopesConsentReturns => {
|
|
33
|
+
const {checkScopesConsent} = useShopActions()
|
|
34
|
+
const {data, loading, error, refetch} = useShopActionQuery(
|
|
35
|
+
['scopesConsent'],
|
|
36
|
+
checkScopesConsent,
|
|
37
|
+
{}
|
|
38
|
+
)
|
|
39
|
+
return {
|
|
40
|
+
requiredScopes: data?.requiredScopes,
|
|
41
|
+
grantedScopes: data?.grantedScopes,
|
|
42
|
+
status: data?.status,
|
|
43
|
+
loading,
|
|
44
|
+
error,
|
|
45
|
+
refetch,
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Returns the current scope consent status for this mini, fetched fresh from the API on mount.
|
|
51
|
+
*
|
|
52
|
+
* Use `status` to branch UI on whether the user has granted all required scopes:
|
|
53
|
+
* - `'granted'` — all required scopes are granted (or none declared)
|
|
54
|
+
* - `'partially_granted'` — at least one required scope is granted but not all
|
|
55
|
+
* - `'not_granted'` — no required scopes are granted
|
|
56
|
+
*
|
|
57
|
+
* Call `refetch()` after `requestScopesConsent()` resolves to get the updated status.
|
|
58
|
+
* @publicDocs
|
|
59
|
+
*/
|
|
60
|
+
export type UseCheckScopesConsentGeneratedType =
|
|
61
|
+
() => UseCheckScopesConsentReturns
|
|
@@ -26,6 +26,7 @@ export const useRequestPermissions = (): UseRequestPermissionsReturns => {
|
|
|
26
26
|
/**
|
|
27
27
|
* The `useRequestPermissions` hook provides a function to request native device permissions from the user. It handles both app-level and system-level permission requests, showing appropriate dialogs and managing permission state. Supported permissions include camera, microphone, and device motion access.
|
|
28
28
|
*
|
|
29
|
+
* `errorMessage` is normally a string describing the failure. The value `'request_blocked'` is a reserved sentinel — it means the request couldn't be served because another consent or permission sheet is already showing, or the Mini's scope state hasn't finished loading yet. Don't surface this string to users.
|
|
29
30
|
*
|
|
30
31
|
* > Note: Before using this hook, add the required permissions to your Mini's manifest file: `"permissions": ["CAMERA"]`.
|
|
31
32
|
* @publicDocs
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import {RequestScopesConsentResponse} from '@shopify/shop-minis-platform/actions'
|
|
2
|
+
|
|
3
|
+
import {useHandleAction} from '../../internal/useHandleAction'
|
|
4
|
+
import {useShopActions} from '../../internal/useShopActions'
|
|
5
|
+
|
|
6
|
+
export interface UseRequestScopesConsentReturns {
|
|
7
|
+
/**
|
|
8
|
+
* Programmatically show the consent sheet for the Mini's required scopes.
|
|
9
|
+
*
|
|
10
|
+
* The sheet will show even if the user previously rejected it in the same
|
|
11
|
+
* session. Use this to build retry UX (e.g., a "Connect account" button).
|
|
12
|
+
*
|
|
13
|
+
* Resolves with `{granted: boolean}`. Rejects with `'request_blocked'`
|
|
14
|
+
* if the request can't be served right now — either another consent or
|
|
15
|
+
* permission sheet is already showing, or the Mini's scope state hasn't
|
|
16
|
+
* finished loading yet.
|
|
17
|
+
*
|
|
18
|
+
* Call `refetch()` on `useCheckScopesConsent` after resolution to get the
|
|
19
|
+
* updated scope status.
|
|
20
|
+
*/
|
|
21
|
+
requestScopesConsent: () => Promise<RequestScopesConsentResponse>
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export const useRequestScopesConsent = (): UseRequestScopesConsentReturns => {
|
|
25
|
+
const {requestScopesConsent} = useShopActions()
|
|
26
|
+
return {
|
|
27
|
+
requestScopesConsent: useHandleAction(requestScopesConsent),
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Returns a function to programmatically show the consent sheet. Use this to
|
|
33
|
+
* build re-consent UX after the user has previously rejected, or when partial
|
|
34
|
+
* scope grants are detected via `useCheckScopesConsent`.
|
|
35
|
+
* @publicDocs
|
|
36
|
+
*/
|
|
37
|
+
export type UseRequestScopesConsentGeneratedType =
|
|
38
|
+
() => UseRequestScopesConsentReturns
|
package/src/mocks.ts
CHANGED
|
@@ -578,6 +578,14 @@ export function makeMockActions(): ShopActions {
|
|
|
578
578
|
checkPermission: {
|
|
579
579
|
status: 'granted',
|
|
580
580
|
},
|
|
581
|
+
checkScopesConsent: {
|
|
582
|
+
data: {
|
|
583
|
+
requiredScopes: ['profile'],
|
|
584
|
+
grantedScopes: ['profile'],
|
|
585
|
+
status: 'granted',
|
|
586
|
+
},
|
|
587
|
+
},
|
|
588
|
+
requestScopesConsent: {granted: true},
|
|
581
589
|
reportError: undefined,
|
|
582
590
|
reportFetch: undefined,
|
|
583
591
|
invokeIntent: {code: 'closed' as const},
|