@sinlungtech/push-client 0.1.0 → 0.1.1
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/index.d.mts +12 -1
- package/dist/index.d.ts +12 -1
- package/dist/index.js +122 -5
- package/dist/index.mjs +123 -6
- package/package.json +13 -3
package/dist/index.d.mts
CHANGED
|
@@ -68,6 +68,17 @@ interface PushProviderProps {
|
|
|
68
68
|
* Called whenever a live notification event is received.
|
|
69
69
|
*/
|
|
70
70
|
onLiveNotification?: (payload: PushPayload) => void;
|
|
71
|
+
/**
|
|
72
|
+
* Built-in in-page alert UI for live notifications.
|
|
73
|
+
* Useful as a zero-config default when hosts don't provide custom handlers.
|
|
74
|
+
* Default: true
|
|
75
|
+
*/
|
|
76
|
+
showInPageAlerts?: boolean;
|
|
77
|
+
/**
|
|
78
|
+
* Auto-dismiss timeout (ms) for built-in in-page alerts.
|
|
79
|
+
* Default: 5000
|
|
80
|
+
*/
|
|
81
|
+
inPageAlertDurationMs?: number;
|
|
71
82
|
/**
|
|
72
83
|
* If true, requests notification permission and subscribes immediately on mount.
|
|
73
84
|
* If false (default), call subscribe() manually via usePush().
|
|
@@ -117,7 +128,7 @@ interface PushContextValue {
|
|
|
117
128
|
* Then in any component:
|
|
118
129
|
* const { isSubscribed, permission, subscribe, unsubscribe } = usePush();
|
|
119
130
|
*/
|
|
120
|
-
declare function PushProvider({ vapidKey, serviceWorkerPath, onSubscribe, onUnsubscribe, chatServerUrl, getToken, subscriptionsEndpoint, live, onLiveNotification, autoSubscribe, children, }: PushProviderProps): react_jsx_runtime.JSX.Element;
|
|
131
|
+
declare function PushProvider({ vapidKey, serviceWorkerPath, onSubscribe, onUnsubscribe, chatServerUrl, getToken, subscriptionsEndpoint, live, onLiveNotification, showInPageAlerts, inPageAlertDurationMs, autoSubscribe, children, }: PushProviderProps): react_jsx_runtime.JSX.Element;
|
|
121
132
|
declare function usePush(): PushContextValue;
|
|
122
133
|
|
|
123
134
|
declare function urlBase64ToUint8Array(base64String: string): ArrayBuffer;
|
package/dist/index.d.ts
CHANGED
|
@@ -68,6 +68,17 @@ interface PushProviderProps {
|
|
|
68
68
|
* Called whenever a live notification event is received.
|
|
69
69
|
*/
|
|
70
70
|
onLiveNotification?: (payload: PushPayload) => void;
|
|
71
|
+
/**
|
|
72
|
+
* Built-in in-page alert UI for live notifications.
|
|
73
|
+
* Useful as a zero-config default when hosts don't provide custom handlers.
|
|
74
|
+
* Default: true
|
|
75
|
+
*/
|
|
76
|
+
showInPageAlerts?: boolean;
|
|
77
|
+
/**
|
|
78
|
+
* Auto-dismiss timeout (ms) for built-in in-page alerts.
|
|
79
|
+
* Default: 5000
|
|
80
|
+
*/
|
|
81
|
+
inPageAlertDurationMs?: number;
|
|
71
82
|
/**
|
|
72
83
|
* If true, requests notification permission and subscribes immediately on mount.
|
|
73
84
|
* If false (default), call subscribe() manually via usePush().
|
|
@@ -117,7 +128,7 @@ interface PushContextValue {
|
|
|
117
128
|
* Then in any component:
|
|
118
129
|
* const { isSubscribed, permission, subscribe, unsubscribe } = usePush();
|
|
119
130
|
*/
|
|
120
|
-
declare function PushProvider({ vapidKey, serviceWorkerPath, onSubscribe, onUnsubscribe, chatServerUrl, getToken, subscriptionsEndpoint, live, onLiveNotification, autoSubscribe, children, }: PushProviderProps): react_jsx_runtime.JSX.Element;
|
|
131
|
+
declare function PushProvider({ vapidKey, serviceWorkerPath, onSubscribe, onUnsubscribe, chatServerUrl, getToken, subscriptionsEndpoint, live, onLiveNotification, showInPageAlerts, inPageAlertDurationMs, autoSubscribe, children, }: PushProviderProps): react_jsx_runtime.JSX.Element;
|
|
121
132
|
declare function usePush(): PushContextValue;
|
|
122
133
|
|
|
123
134
|
declare function urlBase64ToUint8Array(base64String: string): ArrayBuffer;
|
package/dist/index.js
CHANGED
|
@@ -75,6 +75,8 @@ function PushProvider({
|
|
|
75
75
|
subscriptionsEndpoint = "/api/push/subscriptions",
|
|
76
76
|
live,
|
|
77
77
|
onLiveNotification,
|
|
78
|
+
showInPageAlerts = true,
|
|
79
|
+
inPageAlertDurationMs = 5e3,
|
|
78
80
|
autoSubscribe = false,
|
|
79
81
|
children
|
|
80
82
|
}) {
|
|
@@ -85,6 +87,27 @@ function PushProvider({
|
|
|
85
87
|
const [isSubscribed, setIsSubscribed] = (0, import_react.useState)(false);
|
|
86
88
|
const [error, setError] = (0, import_react.useState)(null);
|
|
87
89
|
const [swReg, setSwReg] = (0, import_react.useState)(null);
|
|
90
|
+
const [inPageAlerts, setInPageAlerts] = (0, import_react.useState)([]);
|
|
91
|
+
const pushInPageAlert = (0, import_react.useCallback)(
|
|
92
|
+
(title, body) => {
|
|
93
|
+
const id = `${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
94
|
+
setInPageAlerts((prev) => [...prev, { id, title, body }].slice(-3));
|
|
95
|
+
window.setTimeout(() => {
|
|
96
|
+
setInPageAlerts((prev) => prev.filter((n) => n.id !== id));
|
|
97
|
+
}, Math.max(1e3, inPageAlertDurationMs));
|
|
98
|
+
},
|
|
99
|
+
[inPageAlertDurationMs]
|
|
100
|
+
);
|
|
101
|
+
const sameServerKey = (0, import_react.useCallback)((a, b) => {
|
|
102
|
+
if (!a) return false;
|
|
103
|
+
const ua = new Uint8Array(a);
|
|
104
|
+
const ub = new Uint8Array(b);
|
|
105
|
+
if (ua.length !== ub.length) return false;
|
|
106
|
+
for (let i = 0; i < ua.length; i += 1) {
|
|
107
|
+
if (ua[i] !== ub[i]) return false;
|
|
108
|
+
}
|
|
109
|
+
return true;
|
|
110
|
+
}, []);
|
|
88
111
|
const resolveServerUrl = (0, import_react.useCallback)(
|
|
89
112
|
(path) => {
|
|
90
113
|
if (/^https?:\/\//i.test(path)) return path;
|
|
@@ -145,19 +168,72 @@ function PushProvider({
|
|
|
145
168
|
const perm = await Notification.requestPermission();
|
|
146
169
|
setPermission(perm);
|
|
147
170
|
if (perm !== "granted") return;
|
|
171
|
+
const desiredServerKey = urlBase64ToUint8Array(vapidKey);
|
|
172
|
+
const existing = await swReg.pushManager.getSubscription();
|
|
173
|
+
if (existing) {
|
|
174
|
+
const existingKey = existing.options?.applicationServerKey ?? null;
|
|
175
|
+
const keyMatches = sameServerKey(existingKey, desiredServerKey);
|
|
176
|
+
if (keyMatches) {
|
|
177
|
+
const existingJson = existing.toJSON();
|
|
178
|
+
await (onSubscribe ?? defaultSubscribe)({
|
|
179
|
+
endpoint: existingJson.endpoint,
|
|
180
|
+
keys: existingJson.keys
|
|
181
|
+
});
|
|
182
|
+
setIsSubscribed(true);
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
const oldEndpoint = existing.endpoint;
|
|
186
|
+
await existing.unsubscribe();
|
|
187
|
+
if (onUnsubscribe) await onUnsubscribe(oldEndpoint);
|
|
188
|
+
else await defaultUnsubscribe(oldEndpoint);
|
|
189
|
+
}
|
|
148
190
|
const sub = await swReg.pushManager.subscribe({
|
|
149
191
|
userVisibleOnly: true,
|
|
150
|
-
applicationServerKey:
|
|
192
|
+
applicationServerKey: desiredServerKey
|
|
151
193
|
});
|
|
152
194
|
const json = sub.toJSON();
|
|
153
195
|
await (onSubscribe ?? defaultSubscribe)({ endpoint: json.endpoint, keys: json.keys });
|
|
154
196
|
setIsSubscribed(true);
|
|
155
197
|
} catch (err) {
|
|
198
|
+
const message = String(err?.message ?? err ?? "");
|
|
199
|
+
const recoverable = message.includes("different applicationServerKey") || message.includes("gcm_sender_id");
|
|
200
|
+
if (recoverable) {
|
|
201
|
+
try {
|
|
202
|
+
const stale = await swReg.pushManager.getSubscription();
|
|
203
|
+
if (stale) {
|
|
204
|
+
const oldEndpoint = stale.endpoint;
|
|
205
|
+
await stale.unsubscribe();
|
|
206
|
+
if (onUnsubscribe) await onUnsubscribe(oldEndpoint);
|
|
207
|
+
else await defaultUnsubscribe(oldEndpoint);
|
|
208
|
+
}
|
|
209
|
+
const retried = await swReg.pushManager.subscribe({
|
|
210
|
+
userVisibleOnly: true,
|
|
211
|
+
applicationServerKey: urlBase64ToUint8Array(vapidKey)
|
|
212
|
+
});
|
|
213
|
+
const retriedJson = retried.toJSON();
|
|
214
|
+
await (onSubscribe ?? defaultSubscribe)({
|
|
215
|
+
endpoint: retriedJson.endpoint,
|
|
216
|
+
keys: retriedJson.keys
|
|
217
|
+
});
|
|
218
|
+
setIsSubscribed(true);
|
|
219
|
+
return;
|
|
220
|
+
} catch {
|
|
221
|
+
}
|
|
222
|
+
}
|
|
156
223
|
const e = err instanceof Error ? err : new Error(String(err));
|
|
157
224
|
setError(e);
|
|
158
225
|
console.warn("[PushClient] subscribe failed:", e);
|
|
159
226
|
}
|
|
160
|
-
}, [
|
|
227
|
+
}, [
|
|
228
|
+
supported,
|
|
229
|
+
swReg,
|
|
230
|
+
vapidKey,
|
|
231
|
+
onSubscribe,
|
|
232
|
+
onUnsubscribe,
|
|
233
|
+
defaultSubscribe,
|
|
234
|
+
defaultUnsubscribe,
|
|
235
|
+
sameServerKey
|
|
236
|
+
]);
|
|
161
237
|
const unsubscribe = (0, import_react.useCallback)(async () => {
|
|
162
238
|
if (!supported || !swReg) return;
|
|
163
239
|
setError(null);
|
|
@@ -175,7 +251,7 @@ function PushProvider({
|
|
|
175
251
|
}
|
|
176
252
|
}, [supported, swReg, onUnsubscribe, defaultUnsubscribe]);
|
|
177
253
|
(0, import_react.useEffect)(() => {
|
|
178
|
-
if (autoSubscribe && swReg && !isSubscribed && permission
|
|
254
|
+
if (autoSubscribe && swReg && !isSubscribed && permission === "granted") {
|
|
179
255
|
subscribe();
|
|
180
256
|
}
|
|
181
257
|
}, [autoSubscribe, swReg, isSubscribed, permission, subscribe]);
|
|
@@ -241,6 +317,9 @@ function PushProvider({
|
|
|
241
317
|
tag: payload.tag
|
|
242
318
|
};
|
|
243
319
|
onLiveNotification?.(normalized);
|
|
320
|
+
if (!onLiveNotification && showInPageAlerts && normalized.body) {
|
|
321
|
+
pushInPageAlert(normalized.title, normalized.body);
|
|
322
|
+
}
|
|
244
323
|
if (showSystem && typeof window !== "undefined" && Notification.permission === "granted") {
|
|
245
324
|
new Notification(normalized.title, {
|
|
246
325
|
body: normalized.body,
|
|
@@ -260,8 +339,46 @@ function PushProvider({
|
|
|
260
339
|
} catch {
|
|
261
340
|
}
|
|
262
341
|
};
|
|
263
|
-
}, [chatServerUrl, getToken, live, onLiveNotification]);
|
|
264
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.
|
|
342
|
+
}, [chatServerUrl, getToken, live, onLiveNotification, showInPageAlerts, pushInPageAlert]);
|
|
343
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(PushContext.Provider, { value: { isSupported: supported, permission, isSubscribed, subscribe, unsubscribe, error }, children: [
|
|
344
|
+
children,
|
|
345
|
+
showInPageAlerts && inPageAlerts.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
346
|
+
"div",
|
|
347
|
+
{
|
|
348
|
+
style: {
|
|
349
|
+
position: "fixed",
|
|
350
|
+
right: 16,
|
|
351
|
+
bottom: 16,
|
|
352
|
+
zIndex: 2147483640,
|
|
353
|
+
display: "flex",
|
|
354
|
+
flexDirection: "column",
|
|
355
|
+
gap: 8,
|
|
356
|
+
pointerEvents: "none"
|
|
357
|
+
},
|
|
358
|
+
children: inPageAlerts.map((n) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
359
|
+
"div",
|
|
360
|
+
{
|
|
361
|
+
style: {
|
|
362
|
+
pointerEvents: "auto",
|
|
363
|
+
width: 320,
|
|
364
|
+
maxWidth: "calc(100vw - 32px)",
|
|
365
|
+
borderRadius: 12,
|
|
366
|
+
border: "1px solid #e5e7eb",
|
|
367
|
+
background: "#fff",
|
|
368
|
+
boxShadow: "0 8px 24px rgba(0,0,0,0.15)",
|
|
369
|
+
padding: "10px 12px",
|
|
370
|
+
fontFamily: "system-ui, sans-serif"
|
|
371
|
+
},
|
|
372
|
+
children: [
|
|
373
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: { margin: 0, fontSize: 12, fontWeight: 700, color: "#111827" }, children: n.title }),
|
|
374
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: { margin: "4px 0 0", fontSize: 12, color: "#4b5563", lineHeight: 1.35 }, children: n.body })
|
|
375
|
+
]
|
|
376
|
+
},
|
|
377
|
+
n.id
|
|
378
|
+
))
|
|
379
|
+
}
|
|
380
|
+
)
|
|
381
|
+
] });
|
|
265
382
|
}
|
|
266
383
|
function usePush() {
|
|
267
384
|
return (0, import_react.useContext)(PushContext);
|
package/dist/index.mjs
CHANGED
|
@@ -16,7 +16,7 @@ function isSupported() {
|
|
|
16
16
|
|
|
17
17
|
// src/PushProvider.tsx
|
|
18
18
|
import * as Ably from "ably";
|
|
19
|
-
import { jsx } from "react/jsx-runtime";
|
|
19
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
20
20
|
var PushContext = createContext({
|
|
21
21
|
isSupported: false,
|
|
22
22
|
permission: "default",
|
|
@@ -37,6 +37,8 @@ function PushProvider({
|
|
|
37
37
|
subscriptionsEndpoint = "/api/push/subscriptions",
|
|
38
38
|
live,
|
|
39
39
|
onLiveNotification,
|
|
40
|
+
showInPageAlerts = true,
|
|
41
|
+
inPageAlertDurationMs = 5e3,
|
|
40
42
|
autoSubscribe = false,
|
|
41
43
|
children
|
|
42
44
|
}) {
|
|
@@ -47,6 +49,27 @@ function PushProvider({
|
|
|
47
49
|
const [isSubscribed, setIsSubscribed] = useState(false);
|
|
48
50
|
const [error, setError] = useState(null);
|
|
49
51
|
const [swReg, setSwReg] = useState(null);
|
|
52
|
+
const [inPageAlerts, setInPageAlerts] = useState([]);
|
|
53
|
+
const pushInPageAlert = useCallback(
|
|
54
|
+
(title, body) => {
|
|
55
|
+
const id = `${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
56
|
+
setInPageAlerts((prev) => [...prev, { id, title, body }].slice(-3));
|
|
57
|
+
window.setTimeout(() => {
|
|
58
|
+
setInPageAlerts((prev) => prev.filter((n) => n.id !== id));
|
|
59
|
+
}, Math.max(1e3, inPageAlertDurationMs));
|
|
60
|
+
},
|
|
61
|
+
[inPageAlertDurationMs]
|
|
62
|
+
);
|
|
63
|
+
const sameServerKey = useCallback((a, b) => {
|
|
64
|
+
if (!a) return false;
|
|
65
|
+
const ua = new Uint8Array(a);
|
|
66
|
+
const ub = new Uint8Array(b);
|
|
67
|
+
if (ua.length !== ub.length) return false;
|
|
68
|
+
for (let i = 0; i < ua.length; i += 1) {
|
|
69
|
+
if (ua[i] !== ub[i]) return false;
|
|
70
|
+
}
|
|
71
|
+
return true;
|
|
72
|
+
}, []);
|
|
50
73
|
const resolveServerUrl = useCallback(
|
|
51
74
|
(path) => {
|
|
52
75
|
if (/^https?:\/\//i.test(path)) return path;
|
|
@@ -107,19 +130,72 @@ function PushProvider({
|
|
|
107
130
|
const perm = await Notification.requestPermission();
|
|
108
131
|
setPermission(perm);
|
|
109
132
|
if (perm !== "granted") return;
|
|
133
|
+
const desiredServerKey = urlBase64ToUint8Array(vapidKey);
|
|
134
|
+
const existing = await swReg.pushManager.getSubscription();
|
|
135
|
+
if (existing) {
|
|
136
|
+
const existingKey = existing.options?.applicationServerKey ?? null;
|
|
137
|
+
const keyMatches = sameServerKey(existingKey, desiredServerKey);
|
|
138
|
+
if (keyMatches) {
|
|
139
|
+
const existingJson = existing.toJSON();
|
|
140
|
+
await (onSubscribe ?? defaultSubscribe)({
|
|
141
|
+
endpoint: existingJson.endpoint,
|
|
142
|
+
keys: existingJson.keys
|
|
143
|
+
});
|
|
144
|
+
setIsSubscribed(true);
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
const oldEndpoint = existing.endpoint;
|
|
148
|
+
await existing.unsubscribe();
|
|
149
|
+
if (onUnsubscribe) await onUnsubscribe(oldEndpoint);
|
|
150
|
+
else await defaultUnsubscribe(oldEndpoint);
|
|
151
|
+
}
|
|
110
152
|
const sub = await swReg.pushManager.subscribe({
|
|
111
153
|
userVisibleOnly: true,
|
|
112
|
-
applicationServerKey:
|
|
154
|
+
applicationServerKey: desiredServerKey
|
|
113
155
|
});
|
|
114
156
|
const json = sub.toJSON();
|
|
115
157
|
await (onSubscribe ?? defaultSubscribe)({ endpoint: json.endpoint, keys: json.keys });
|
|
116
158
|
setIsSubscribed(true);
|
|
117
159
|
} catch (err) {
|
|
160
|
+
const message = String(err?.message ?? err ?? "");
|
|
161
|
+
const recoverable = message.includes("different applicationServerKey") || message.includes("gcm_sender_id");
|
|
162
|
+
if (recoverable) {
|
|
163
|
+
try {
|
|
164
|
+
const stale = await swReg.pushManager.getSubscription();
|
|
165
|
+
if (stale) {
|
|
166
|
+
const oldEndpoint = stale.endpoint;
|
|
167
|
+
await stale.unsubscribe();
|
|
168
|
+
if (onUnsubscribe) await onUnsubscribe(oldEndpoint);
|
|
169
|
+
else await defaultUnsubscribe(oldEndpoint);
|
|
170
|
+
}
|
|
171
|
+
const retried = await swReg.pushManager.subscribe({
|
|
172
|
+
userVisibleOnly: true,
|
|
173
|
+
applicationServerKey: urlBase64ToUint8Array(vapidKey)
|
|
174
|
+
});
|
|
175
|
+
const retriedJson = retried.toJSON();
|
|
176
|
+
await (onSubscribe ?? defaultSubscribe)({
|
|
177
|
+
endpoint: retriedJson.endpoint,
|
|
178
|
+
keys: retriedJson.keys
|
|
179
|
+
});
|
|
180
|
+
setIsSubscribed(true);
|
|
181
|
+
return;
|
|
182
|
+
} catch {
|
|
183
|
+
}
|
|
184
|
+
}
|
|
118
185
|
const e = err instanceof Error ? err : new Error(String(err));
|
|
119
186
|
setError(e);
|
|
120
187
|
console.warn("[PushClient] subscribe failed:", e);
|
|
121
188
|
}
|
|
122
|
-
}, [
|
|
189
|
+
}, [
|
|
190
|
+
supported,
|
|
191
|
+
swReg,
|
|
192
|
+
vapidKey,
|
|
193
|
+
onSubscribe,
|
|
194
|
+
onUnsubscribe,
|
|
195
|
+
defaultSubscribe,
|
|
196
|
+
defaultUnsubscribe,
|
|
197
|
+
sameServerKey
|
|
198
|
+
]);
|
|
123
199
|
const unsubscribe = useCallback(async () => {
|
|
124
200
|
if (!supported || !swReg) return;
|
|
125
201
|
setError(null);
|
|
@@ -137,7 +213,7 @@ function PushProvider({
|
|
|
137
213
|
}
|
|
138
214
|
}, [supported, swReg, onUnsubscribe, defaultUnsubscribe]);
|
|
139
215
|
useEffect(() => {
|
|
140
|
-
if (autoSubscribe && swReg && !isSubscribed && permission
|
|
216
|
+
if (autoSubscribe && swReg && !isSubscribed && permission === "granted") {
|
|
141
217
|
subscribe();
|
|
142
218
|
}
|
|
143
219
|
}, [autoSubscribe, swReg, isSubscribed, permission, subscribe]);
|
|
@@ -203,6 +279,9 @@ function PushProvider({
|
|
|
203
279
|
tag: payload.tag
|
|
204
280
|
};
|
|
205
281
|
onLiveNotification?.(normalized);
|
|
282
|
+
if (!onLiveNotification && showInPageAlerts && normalized.body) {
|
|
283
|
+
pushInPageAlert(normalized.title, normalized.body);
|
|
284
|
+
}
|
|
206
285
|
if (showSystem && typeof window !== "undefined" && Notification.permission === "granted") {
|
|
207
286
|
new Notification(normalized.title, {
|
|
208
287
|
body: normalized.body,
|
|
@@ -222,8 +301,46 @@ function PushProvider({
|
|
|
222
301
|
} catch {
|
|
223
302
|
}
|
|
224
303
|
};
|
|
225
|
-
}, [chatServerUrl, getToken, live, onLiveNotification]);
|
|
226
|
-
return /* @__PURE__ */
|
|
304
|
+
}, [chatServerUrl, getToken, live, onLiveNotification, showInPageAlerts, pushInPageAlert]);
|
|
305
|
+
return /* @__PURE__ */ jsxs(PushContext.Provider, { value: { isSupported: supported, permission, isSubscribed, subscribe, unsubscribe, error }, children: [
|
|
306
|
+
children,
|
|
307
|
+
showInPageAlerts && inPageAlerts.length > 0 && /* @__PURE__ */ jsx(
|
|
308
|
+
"div",
|
|
309
|
+
{
|
|
310
|
+
style: {
|
|
311
|
+
position: "fixed",
|
|
312
|
+
right: 16,
|
|
313
|
+
bottom: 16,
|
|
314
|
+
zIndex: 2147483640,
|
|
315
|
+
display: "flex",
|
|
316
|
+
flexDirection: "column",
|
|
317
|
+
gap: 8,
|
|
318
|
+
pointerEvents: "none"
|
|
319
|
+
},
|
|
320
|
+
children: inPageAlerts.map((n) => /* @__PURE__ */ jsxs(
|
|
321
|
+
"div",
|
|
322
|
+
{
|
|
323
|
+
style: {
|
|
324
|
+
pointerEvents: "auto",
|
|
325
|
+
width: 320,
|
|
326
|
+
maxWidth: "calc(100vw - 32px)",
|
|
327
|
+
borderRadius: 12,
|
|
328
|
+
border: "1px solid #e5e7eb",
|
|
329
|
+
background: "#fff",
|
|
330
|
+
boxShadow: "0 8px 24px rgba(0,0,0,0.15)",
|
|
331
|
+
padding: "10px 12px",
|
|
332
|
+
fontFamily: "system-ui, sans-serif"
|
|
333
|
+
},
|
|
334
|
+
children: [
|
|
335
|
+
/* @__PURE__ */ jsx("p", { style: { margin: 0, fontSize: 12, fontWeight: 700, color: "#111827" }, children: n.title }),
|
|
336
|
+
/* @__PURE__ */ jsx("p", { style: { margin: "4px 0 0", fontSize: 12, color: "#4b5563", lineHeight: 1.35 }, children: n.body })
|
|
337
|
+
]
|
|
338
|
+
},
|
|
339
|
+
n.id
|
|
340
|
+
))
|
|
341
|
+
}
|
|
342
|
+
)
|
|
343
|
+
] });
|
|
227
344
|
}
|
|
228
345
|
function usePush() {
|
|
229
346
|
return useContext(PushContext);
|
package/package.json
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sinlungtech/push-client",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "Web Push notification client for Next.js — service worker registration, permission handling, and subscription management",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.mjs",
|
|
7
7
|
"types": "dist/index.d.ts",
|
|
8
|
-
"files": [
|
|
8
|
+
"files": [
|
|
9
|
+
"dist",
|
|
10
|
+
"sw-template.js"
|
|
11
|
+
],
|
|
9
12
|
"scripts": {
|
|
10
13
|
"build": "tsup src/index.ts --format cjs,esm --dts",
|
|
11
14
|
"dev": "tsup src/index.ts --format cjs,esm --dts --watch"
|
|
@@ -22,6 +25,13 @@
|
|
|
22
25
|
"tsup": "^8.0.0",
|
|
23
26
|
"typescript": "^5"
|
|
24
27
|
},
|
|
25
|
-
"keywords": [
|
|
28
|
+
"keywords": [
|
|
29
|
+
"web-push",
|
|
30
|
+
"pwa",
|
|
31
|
+
"service-worker",
|
|
32
|
+
"notifications",
|
|
33
|
+
"react",
|
|
34
|
+
"nextjs"
|
|
35
|
+
],
|
|
26
36
|
"license": "MIT"
|
|
27
37
|
}
|