@protobase/cli 0.73.1 → 0.73.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.
|
@@ -8,9 +8,13 @@ import { pushRecord } from "@protobase/schema/internal";
|
|
|
8
8
|
* names the subscription's endpoint and the push names the record's user. A push without a title shows the app's
|
|
9
9
|
* name alone. A push with no record, or for another endpoint or user, shows nothing: the worker closes what it showed,
|
|
10
10
|
* clears the badge, drops the record and unsubscribes.
|
|
11
|
-
* -
|
|
12
|
-
* a
|
|
13
|
-
*
|
|
11
|
+
* - A push's tap opens its `notification.navigate`, or its `url` when it has none, and each of its `notification.actions`
|
|
12
|
+
* shows as a button that opens the action's own `navigate`, or the tap's url when it has none. Nothing else in the
|
|
13
|
+
* push, such as its `data`, is kept for a tap.
|
|
14
|
+
* - `notificationclick` opens the tapped action's url, or the notification's for a tap on no action it knows, only when
|
|
15
|
+
* it is an absolute `http` or `https` URL, parsed without a base: on the worker's own origin in a window of the app,
|
|
16
|
+
* focused and navigated there, or in a new window when none is open; on any other origin always in a new window.
|
|
17
|
+
* Anything else opens nothing, whoever showed the notification, and a failing action never falls back to another url.
|
|
14
18
|
* - `pushsubscriptionchange` marks an existing record for renewal, which the helper registers once its user is signed
|
|
15
19
|
* in; the worker has no token to do so itself.
|
|
16
20
|
*/
|
|
@@ -59,6 +63,22 @@ const pushData = (data) => {
|
|
|
59
63
|
}
|
|
60
64
|
|
|
61
65
|
const text = (value) => (typeof value === 'string' ? value : undefined)
|
|
66
|
+
const plainObject = (value) => value !== null && typeof value === 'object' && !Array.isArray(value)
|
|
67
|
+
|
|
68
|
+
// The checked urls a tap may open: the notification's, and per action [action, url], with null for a navigate that
|
|
69
|
+
// fails, so its button opens nothing. Pairs rather than an object keyed by the push's action names.
|
|
70
|
+
const tapTargets = (push) => {
|
|
71
|
+
const notification = plainObject(push.notification) ? push.notification : {}
|
|
72
|
+
const url = notification.navigate !== undefined ? tapUrl(notification.navigate) : tapUrl(push.url)
|
|
73
|
+
const actions = (Array.isArray(notification.actions) ? notification.actions : []).filter(
|
|
74
|
+
(action) => plainObject(action) && text(action.action) !== undefined && text(action.title) !== undefined,
|
|
75
|
+
)
|
|
76
|
+
return {
|
|
77
|
+
url,
|
|
78
|
+
buttons: actions.map((action) => ({ action: action.action, title: action.title })),
|
|
79
|
+
actions: actions.map((action) => [action.action, action.navigate === undefined ? url ?? null : tapUrl(action.navigate) ?? null]),
|
|
80
|
+
}
|
|
81
|
+
}
|
|
62
82
|
|
|
63
83
|
// This browser is no longer registered for anyone: nothing it showed stays, and it gets no more pushes.
|
|
64
84
|
const forgetPush = async () => {
|
|
@@ -75,11 +95,12 @@ const showPush = async (data) => {
|
|
|
75
95
|
const push = pushData(data)
|
|
76
96
|
if (!push || text(push.title) === undefined) return self.registration.showNotification(text(record.appName) || self.location.host, {})
|
|
77
97
|
if (push.user !== record.userId) return forgetPush()
|
|
78
|
-
const url =
|
|
98
|
+
const { url, buttons, actions } = tapTargets(push)
|
|
79
99
|
const options = {}
|
|
80
100
|
if (text(push.body) !== undefined) options.body = push.body
|
|
81
101
|
if (text(push.tag) !== undefined) options.tag = push.tag
|
|
82
|
-
if (
|
|
102
|
+
if (buttons.length > 0) options.actions = buttons
|
|
103
|
+
if (url !== undefined || actions.length > 0) options.data = { ...(url !== undefined && { url }), ...(actions.length > 0 && { actions }) }
|
|
83
104
|
if (typeof push.badge === 'number' && self.navigator.setAppBadge) await self.navigator.setAppBadge(push.badge)
|
|
84
105
|
return self.registration.showNotification(push.title, options)
|
|
85
106
|
}
|
|
@@ -98,15 +119,22 @@ const openInApp = async (url) => {
|
|
|
98
119
|
}
|
|
99
120
|
}
|
|
100
121
|
|
|
101
|
-
|
|
122
|
+
// The url a tap opens, checked again: page code may show a notification with any data.
|
|
123
|
+
const tappedUrl = (data, action) => {
|
|
124
|
+
if (!plainObject(data)) return undefined
|
|
125
|
+
const pair = action && Array.isArray(data.actions) ? data.actions.find((entry) => Array.isArray(entry) && entry[0] === action) : undefined
|
|
126
|
+
return tapUrl(pair ? pair[1] : data.url)
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const openTap = (notification, action) => {
|
|
102
130
|
notification.close()
|
|
103
|
-
const url =
|
|
131
|
+
const url = tappedUrl(notification.data, action)
|
|
104
132
|
if (url === undefined) return Promise.resolve()
|
|
105
133
|
return new URL(url).origin === self.location.origin ? openInApp(url) : self.clients.openWindow(url)
|
|
106
134
|
}
|
|
107
135
|
|
|
108
136
|
self.addEventListener('push', (event) => event.waitUntil(showPush(event.data)))
|
|
109
|
-
self.addEventListener('notificationclick', (event) => event.waitUntil(openTap(event.notification)))
|
|
137
|
+
self.addEventListener('notificationclick', (event) => event.waitUntil(openTap(event.notification, event.action)))
|
|
110
138
|
self.addEventListener('pushsubscriptionchange', (event) => {
|
|
111
139
|
event.waitUntil(readPushRecord().then((record) => record && writePushRecord({ ...record, renew: true })))
|
|
112
140
|
})
|
package/dist/cli/package.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@protobase/cli",
|
|
3
|
-
"version": "0.73.
|
|
3
|
+
"version": "0.73.2",
|
|
4
4
|
"description": "The protobase command: scaffold, doctor, dev, build and serve a Protobase project.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
|
@@ -43,13 +43,13 @@
|
|
|
43
43
|
"dependencies": {
|
|
44
44
|
"@better-auth/core": "^1.7.12",
|
|
45
45
|
"@hono/node-server": "^2.1.3",
|
|
46
|
-
"@protobase/config": "0.73.
|
|
47
|
-
"@protobase/layout": "0.73.
|
|
48
|
-
"@protobase/query": "0.73.
|
|
49
|
-
"@protobase/schema": "0.73.
|
|
50
|
-
"@protobase/server": "0.73.
|
|
51
|
-
"@protobase/ui": "0.73.
|
|
52
|
-
"@protobase/workflows": "0.73.
|
|
46
|
+
"@protobase/config": "0.73.2",
|
|
47
|
+
"@protobase/layout": "0.73.2",
|
|
48
|
+
"@protobase/query": "0.73.2",
|
|
49
|
+
"@protobase/schema": "0.73.2",
|
|
50
|
+
"@protobase/server": "0.73.2",
|
|
51
|
+
"@protobase/ui": "0.73.2",
|
|
52
|
+
"@protobase/workflows": "0.73.2",
|
|
53
53
|
"@react-email/render": "^2.1.0",
|
|
54
54
|
"@scalar/hono-api-reference": "^0.12.10",
|
|
55
55
|
"@sentry/vite-plugin": "^11.10.0",
|
|
@@ -207,7 +207,7 @@ export const PushButton = () => {
|
|
|
207
207
|
- Only someone signed in as themselves can turn push on: a visitor's click and staff signed in as the user do nothing.
|
|
208
208
|
- On iPhone and iPad, push works in the app added to the Home Screen; a browser tab answers `unsupported`.
|
|
209
209
|
- Signing out turns push off in this browser, and so does someone else signing in on it: what the browser showed is closed, the app's badge cleared, and the device removed. Signing in again as the same user keeps it on. Each push names the user its device is registered for, and the browser shows nothing of a push for another user than the one it holds push for.
|
|
210
|
-
- A tap on a notification
|
|
210
|
+
- A tap on a notification opens its `platform.web.payload` `notification.navigate`, or its `url` when it has none, and each of the payload's `notification.actions` shows as a button that opens its own `navigate`, or the notification's url when it has none. The browser checks each url again as the server does and opens nothing for one that fails; no other field, such as `data`, is ever opened. A url on your app's origin opens that page in the app, in an open window of it or a new one; any other url opens in a new tab.
|
|
211
211
|
|
|
212
212
|
`protobase serve` and `protobase dev` both serve the service worker that shows notifications, `protobase dev` only when the app has `notifications`.
|
|
213
213
|
|