@nitra/cap 7.1.0 → 7.1.2
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/app-update/README.md +23 -0
- package/app-update/index.js +49 -0
- package/auth/index.js +6 -0
- package/index.js +3 -0
- package/package.json +3 -7
- package/save-token/README.md +121 -0
- package/save-token/index.js +108 -0
- package/save-token/sw.js +13 -0
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Проверка и установка новой версии приложение в маркете
|
|
2
|
+
|
|
3
|
+
## API
|
|
4
|
+
|
|
5
|
+
- [`updateApp(...)`](#updateapp)
|
|
6
|
+
|
|
7
|
+
### updateApp(...)
|
|
8
|
+
|
|
9
|
+
```typescript
|
|
10
|
+
updateApp(isImmediate: boolean | undefined, isMandatory: boolean | undefined ) => Promise<void>
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Проверка и установка новой версии приложение в маркете
|
|
14
|
+
|
|
15
|
+
Для **Android**, через [In-app updates](https://developer.android.com/guide/playcore/in-app-updates)]
|
|
16
|
+
Для **IOS**, открываем App Store
|
|
17
|
+
|
|
18
|
+
| Параметр | Тип | Описание |
|
|
19
|
+
|-------------------|-----------|-------------------------------------------------------------------|
|
|
20
|
+
| **`isImmediate`** | `boolean` | только Android, обновление "в полный" экран, по-умолчанию - false |
|
|
21
|
+
| **`isMandatory`** | `boolean` | только Android, обязательно обновление, по-умолчанию - false |
|
|
22
|
+
|
|
23
|
+
---
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { Capacitor } from '@capacitor/core'
|
|
2
|
+
import {
|
|
3
|
+
AppUpdate,
|
|
4
|
+
AppUpdateAvailability,
|
|
5
|
+
FlexibleUpdateInstallStatus,
|
|
6
|
+
AppUpdateResultCode
|
|
7
|
+
} from '@capawesome/capacitor-app-update'
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Проверка наличия обновления, для Android установка обновления, IOS - открытие AppStore
|
|
11
|
+
* @async
|
|
12
|
+
* @function updateApp
|
|
13
|
+
* @param {boolean} isImmediate - только Android, обновление "в полный" экран, по-умолчанию - false
|
|
14
|
+
* @param {boolean} isMandatory - только Android, обязательно обновление, по-умолчанию - false
|
|
15
|
+
*/
|
|
16
|
+
export async function updateApp(isImmediate, isMandatory) {
|
|
17
|
+
if (!Capacitor.isNativePlatform() || !Capacitor.isPluginAvailable('AppUpdate')) {
|
|
18
|
+
return
|
|
19
|
+
}
|
|
20
|
+
const { updateAvailability } = await AppUpdate.getAppUpdateInfo()
|
|
21
|
+
if (updateAvailability !== AppUpdateAvailability.UPDATE_AVAILABLE) {
|
|
22
|
+
return
|
|
23
|
+
}
|
|
24
|
+
if (Capacitor.getPlatform() === 'ios') {
|
|
25
|
+
await AppUpdate.openAppStore()
|
|
26
|
+
return
|
|
27
|
+
}
|
|
28
|
+
if (Capacitor.getPlatform() === 'android') {
|
|
29
|
+
if (isImmediate) {
|
|
30
|
+
const appUpdateResult = await AppUpdate.performImmediateUpdate()
|
|
31
|
+
if (
|
|
32
|
+
isMandatory &&
|
|
33
|
+
(appUpdateResult.code === AppUpdateResultCode.CANCELED ||
|
|
34
|
+
appUpdateResult.code === AppUpdateResultCode.NOT_ALLOWED)
|
|
35
|
+
) {
|
|
36
|
+
await updateApp(isImmediate, isMandatory)
|
|
37
|
+
}
|
|
38
|
+
} else {
|
|
39
|
+
AppUpdate.addListener('onFlexibleUpdateStateChange', flexibleUpdateState => {
|
|
40
|
+
if (flexibleUpdateState.installStatus === FlexibleUpdateInstallStatus.DOWNLOADED) {
|
|
41
|
+
AppUpdate.removeAllListeners()
|
|
42
|
+
AppUpdate.completeFlexibleUpdate()
|
|
43
|
+
}
|
|
44
|
+
})
|
|
45
|
+
await AppUpdate.startFlexibleUpdate()
|
|
46
|
+
}
|
|
47
|
+
return
|
|
48
|
+
}
|
|
49
|
+
}
|
package/auth/index.js
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { default as NCapLoginApple } from './NCapLoginApple.vue'
|
|
2
|
+
export { default as NCapLoginGoogle } from './NCapLoginGoogle.vue'
|
|
3
|
+
export { default as NCapLoginMulti } from './NCapLoginMulti.vue'
|
|
4
|
+
export { default as NDialog } from './NDialog.vue'
|
|
5
|
+
export { default as NForgotPass } from './NForgotPass.vue'
|
|
6
|
+
export { default as NLoginGoogle } from './NLoginGoogle.vue'
|
package/index.js
ADDED
package/package.json
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nitra/cap",
|
|
3
|
-
"version": "7.1.
|
|
3
|
+
"version": "7.1.2",
|
|
4
4
|
"description": "Nitra capacitor components",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
7
|
-
".": "./index.js"
|
|
8
|
-
"./auth/*": "./auth/*"
|
|
7
|
+
".": "./index.js"
|
|
9
8
|
},
|
|
10
9
|
"scripts": {
|
|
11
10
|
"fix": "yarn dlx eslint --fix . && npx prettier --write . "
|
|
@@ -31,8 +30,5 @@
|
|
|
31
30
|
"@nitra/vite-boot": "^3.7.1",
|
|
32
31
|
"@simplewebauthn/browser": "^11.0.0",
|
|
33
32
|
"firebase": "^12.3.0"
|
|
34
|
-
}
|
|
35
|
-
"files": [
|
|
36
|
-
"auth"
|
|
37
|
-
]
|
|
33
|
+
}
|
|
38
34
|
}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
# Receiving and Saving User Push Tokens
|
|
2
|
+
|
|
3
|
+
## Description
|
|
4
|
+
|
|
5
|
+
This library is designed to handle obtaining and saving Firebase push tokens on the client side. It supports both mobile platforms (via Capacitor) and web platforms. The main function, `saveToken`, retrieves a push token from Firebase, stores it locally, and sends it to your server.
|
|
6
|
+
|
|
7
|
+
This library interacts with Firebase for token management and Capacitor to check the platform and permissions. It ensures that push tokens are properly handled, regardless of whether the platform is iOS, Android, or Web.
|
|
8
|
+
|
|
9
|
+
## API
|
|
10
|
+
|
|
11
|
+
### `saveToken()`
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
saveToken() => Promise<void>
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## usage the library
|
|
18
|
+
|
|
19
|
+
### To use this package, you should add this env to your project where you want to provide push notifications
|
|
20
|
+
|
|
21
|
+
`VITE_APP=test`
|
|
22
|
+
`VITE_PROJECT_ID=test`
|
|
23
|
+
`VITE_VAPID_KEY=test`
|
|
24
|
+
`VITE_API_KEY=test`
|
|
25
|
+
`VITE_AUTH_DOMAIN=test`
|
|
26
|
+
`VITE_STORAGE_BUCKET=test`
|
|
27
|
+
`VITE_MESSAGING_SENDER_ID=test`
|
|
28
|
+
`VITE_APP_ID=test`
|
|
29
|
+
|
|
30
|
+
## example in node
|
|
31
|
+
|
|
32
|
+
### Using function after login
|
|
33
|
+
|
|
34
|
+
```jsx
|
|
35
|
+
<template>
|
|
36
|
+
<n-code :on-token-checked="saveToken" />
|
|
37
|
+
</template>
|
|
38
|
+
|
|
39
|
+
<script setup>
|
|
40
|
+
import NCode from '@nitra/abie-components/auth/NCode.vue'
|
|
41
|
+
import { saveToken } from '@nitra/cap'
|
|
42
|
+
|
|
43
|
+
await saveToken()
|
|
44
|
+
</script>
|
|
45
|
+
|
|
46
|
+
<route lang="yaml">
|
|
47
|
+
meta:
|
|
48
|
+
layout: blank
|
|
49
|
+
</route>
|
|
50
|
+
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Environment Variable Validation with Vite
|
|
54
|
+
|
|
55
|
+
### To ensure that the required environment variables are set and the sw.js file is added to the project, add the following to your vite.config.js
|
|
56
|
+
|
|
57
|
+
```typescript
|
|
58
|
+
import { requireEnvVar } from '@nitra/vite-check-env'
|
|
59
|
+
import { defineConfig, loadEnv } from 'vite'
|
|
60
|
+
import { build } from 'esbuild'
|
|
61
|
+
|
|
62
|
+
export default {
|
|
63
|
+
plugins: [
|
|
64
|
+
{
|
|
65
|
+
name: 'nitra-service-worker-transform',
|
|
66
|
+
apply: 'build',
|
|
67
|
+
transformIndexHtml() {
|
|
68
|
+
build({
|
|
69
|
+
plugins: [env(loadEnv(mode, '.'))],
|
|
70
|
+
format: 'esm',
|
|
71
|
+
entryPoints: [path.join(process.cwd(), '../node_modules/@nitra/cap/save-token/sw.js')],
|
|
72
|
+
outfile: path.join(process.cwd(), 'dist', 'sw.js')
|
|
73
|
+
})
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
requireEnvVar([
|
|
77
|
+
'VITE_VAPID_KEY',
|
|
78
|
+
'VITE_APP',
|
|
79
|
+
'VITE_API_KEY',
|
|
80
|
+
'VITE_AUTH_DOMAIN',
|
|
81
|
+
'VITE_PROJECT_ID',
|
|
82
|
+
'VITE_STORAGE_BUCKET',
|
|
83
|
+
'VITE_MESSAGING_SENDER_ID',
|
|
84
|
+
'VITE_APP_ID'
|
|
85
|
+
])
|
|
86
|
+
]
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function env(props) {
|
|
90
|
+
return {
|
|
91
|
+
name: 'env',
|
|
92
|
+
setup: build => {
|
|
93
|
+
const options = build.initialOptions
|
|
94
|
+
const define = options.define ?? {}
|
|
95
|
+
for (const k in props) {
|
|
96
|
+
define[`import.meta.env.${k}`] = JSON.stringify(props[k])
|
|
97
|
+
}
|
|
98
|
+
options.define = {
|
|
99
|
+
...define
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
# For local test you can add this code
|
|
107
|
+
if (process.env.npm_lifecycle_event === 'start-remote-dev') {
|
|
108
|
+
proxy['^/n-push/.*'] = ''
|
|
109
|
+
} else {
|
|
110
|
+
proxy['^/n-push/.*'] = '<http://0.0.0.0:8090>'
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/n-push/ - url of the notify project
|
|
114
|
+
|
|
115
|
+
The `notify project` is a server-side component designed to handle API requests for saving user push tokens. It uses the Fastify framework and JWT-based security for authentication.
|
|
116
|
+
|
|
117
|
+
### Install the plugin in the project directory
|
|
118
|
+
|
|
119
|
+
```typescript
|
|
120
|
+
yarn add -D @nitra/vite-check-env
|
|
121
|
+
```
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { Capacitor } from '@capacitor/core'
|
|
2
|
+
import { FirebaseMessaging } from '@capacitor-firebase/messaging'
|
|
3
|
+
import { getToken } from '@nitra/vite-boot/token'
|
|
4
|
+
import { initializeApp, getApps } from 'firebase/app'
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Save the Firebase push token for a given app and platform.
|
|
8
|
+
* @returns {Promise<void>}
|
|
9
|
+
*/
|
|
10
|
+
export async function saveToken() {
|
|
11
|
+
try {
|
|
12
|
+
if (localStorage.getItem(`pushToken_${import.meta.env.VITE_APP}`)) {
|
|
13
|
+
console.log('Push Token is already exists.')
|
|
14
|
+
|
|
15
|
+
return
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// Check if Firebase is already initialized
|
|
19
|
+
if (getApps().length === 0) {
|
|
20
|
+
initializeApp({
|
|
21
|
+
apiKey: import.meta.env.VITE_API_KEY,
|
|
22
|
+
authDomain: import.meta.env.VITE_AUTH_DOMAIN,
|
|
23
|
+
projectId: import.meta.env.VITE_PROJECT_ID,
|
|
24
|
+
storageBucket: import.meta.env.VITE_STORAGE_BUCKET,
|
|
25
|
+
messagingSenderId: import.meta.env.VITE_MESSAGING_SENDER_ID,
|
|
26
|
+
appId: import.meta.env.VITE_APP_ID
|
|
27
|
+
})
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (Capacitor.isNativePlatform() && !Capacitor.isPluginAvailable('FirebaseMessaging')) {
|
|
31
|
+
console.error('FirebaseMessaging plugin is not available')
|
|
32
|
+
|
|
33
|
+
return
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
let permissions = await FirebaseMessaging.checkPermissions()
|
|
37
|
+
|
|
38
|
+
if (permissions.receive !== 'granted') {
|
|
39
|
+
console.warn('Permissions are not granted, try to request permissions...')
|
|
40
|
+
|
|
41
|
+
let permissionsRequest = await FirebaseMessaging.requestPermissions()
|
|
42
|
+
|
|
43
|
+
if (permissionsRequest.receive !== 'granted') {
|
|
44
|
+
console.error('Permissions are not granted, exiting...')
|
|
45
|
+
|
|
46
|
+
return
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const pushToken = Capacitor.isNativePlatform()
|
|
51
|
+
? await FirebaseMessaging.getToken() // For iOS/Android
|
|
52
|
+
: await getWebPushToken()
|
|
53
|
+
|
|
54
|
+
if (!pushToken?.token && typeof pushToken?.token !== 'string') {
|
|
55
|
+
console.error('Token is undefined exiting...')
|
|
56
|
+
|
|
57
|
+
return
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
await sendTokenToServer(pushToken.token)
|
|
61
|
+
} catch (error) {
|
|
62
|
+
console.error('Error while saving push token:', error)
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Get the Firebase push token for web platform.
|
|
68
|
+
* @returns {Promise<object>} Web Push token
|
|
69
|
+
*/
|
|
70
|
+
async function getWebPushToken() {
|
|
71
|
+
try {
|
|
72
|
+
const serviceWorkerRegistration = await navigator.serviceWorker.register('sw.js', {
|
|
73
|
+
type: 'module'
|
|
74
|
+
})
|
|
75
|
+
|
|
76
|
+
return await FirebaseMessaging.getToken({
|
|
77
|
+
vapidKey: import.meta.env.VITE_VAPID_KEY,
|
|
78
|
+
serviceWorkerRegistration
|
|
79
|
+
})
|
|
80
|
+
} catch (error) {
|
|
81
|
+
console.error('Error getting web push token:', error)
|
|
82
|
+
throw error
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Send the Firebase push token to the server.
|
|
88
|
+
* @param {string} pushToken - The push token returned by Firebase Messaging.
|
|
89
|
+
* @returns {Promise<void>}
|
|
90
|
+
*/
|
|
91
|
+
async function sendTokenToServer(pushToken) {
|
|
92
|
+
const response = await fetch('/n-push/save-user', {
|
|
93
|
+
method: 'POST',
|
|
94
|
+
headers: {
|
|
95
|
+
'Content-Type': 'application/json',
|
|
96
|
+
authorization: `Bearer ${getToken()}`
|
|
97
|
+
},
|
|
98
|
+
body: JSON.stringify({
|
|
99
|
+
platform: Capacitor.getPlatform(),
|
|
100
|
+
app: import.meta.env.VITE_APP,
|
|
101
|
+
token: pushToken
|
|
102
|
+
})
|
|
103
|
+
})
|
|
104
|
+
|
|
105
|
+
if (response.ok) {
|
|
106
|
+
localStorage.setItem(`pushToken_${import.meta.env.VITE_APP}`, pushToken)
|
|
107
|
+
}
|
|
108
|
+
}
|
package/save-token/sw.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { getMessaging } from 'https://www.gstatic.com/firebasejs/10.13.2/firebase-messaging-sw.js'
|
|
2
|
+
import { initializeApp } from 'https://www.gstatic.com/firebasejs/10.13.2/firebase-app.js'
|
|
3
|
+
|
|
4
|
+
const firebaseApp = initializeApp({
|
|
5
|
+
apiKey: import.meta.env.VITE_API_KEY,
|
|
6
|
+
authDomain: import.meta.env.VITE_AUTH_DOMAIN,
|
|
7
|
+
projectId: import.meta.env.VITE_PROJECT_ID,
|
|
8
|
+
storageBucket: import.meta.env.VITE_STORAGE_BUCKET,
|
|
9
|
+
messagingSenderId: import.meta.env.VITE_MESSAGING_SENDER_ID,
|
|
10
|
+
appId: import.meta.env.VITE_APP_ID
|
|
11
|
+
})
|
|
12
|
+
|
|
13
|
+
export const messaging = getMessaging(firebaseApp)
|