@imksh/create 1.0.28 → 1.0.30
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/package.json +1 -1
- package/templates/layers/node/javascript/package.json +2 -1
- package/templates/layers/node/javascript/src/controllers/push.controller.js +35 -14
- package/templates/layers/node/javascript/src/models/pushSubscription.model.js +5 -0
- package/templates/layers/node/javascript/src/utils/pushHelper.js +59 -12
- package/templates/layers/node/typescript/package-lock.json +3795 -0
- package/templates/layers/node/typescript/package.json +2 -1
- package/templates/layers/node/typescript/src/controllers/push.controller.ts +35 -14
- package/templates/layers/node/typescript/src/models/pushSubscription.model.ts +6 -0
- package/templates/layers/node/typescript/src/services/auth.service.ts +3 -3
- package/templates/layers/node/typescript/src/utils/pushHelper.ts +66 -12
- package/templates/layers/node-prisma/javascript/package.json +6 -3
- package/templates/layers/node-prisma/javascript/prisma/schema.prisma +20 -9
- package/templates/layers/node-prisma/javascript/prisma.config.js +12 -0
- package/templates/layers/node-prisma/javascript/src/config/{db.js → prisma.js} +9 -1
- package/templates/layers/node-prisma/javascript/src/controllers/push.controller.js +58 -19
- package/templates/layers/node-prisma/javascript/src/utils/pushHelper.js +62 -14
- package/templates/layers/node-prisma/typescript/package-lock.json +4808 -0
- package/templates/layers/node-prisma/typescript/package.json +8 -4
- package/templates/layers/node-prisma/typescript/prisma/schema.prisma +20 -9
- package/templates/layers/node-prisma/typescript/prisma.config.ts +12 -0
- package/templates/layers/node-prisma/typescript/src/config/{db.ts → prisma.ts} +9 -1
- package/templates/layers/node-prisma/typescript/src/controllers/push.controller.ts +67 -22
- package/templates/layers/node-prisma/typescript/src/index.ts +1 -1
- package/templates/layers/node-prisma/typescript/src/middleware/auth.middleware.ts +15 -5
- package/templates/layers/node-prisma/typescript/src/services/auth.service.ts +134 -128
- package/templates/layers/node-prisma/typescript/src/utils/pushHelper.ts +69 -14
- package/templates/layers/react-native/base/src/components/ui/BiometricLock.tsx +2 -1
- package/templates/layers/react-native/base/src/config/appConfig.ts +44 -0
package/package.json
CHANGED
|
@@ -6,26 +6,47 @@ export const subscribe = async (req, res, next) => {
|
|
|
6
6
|
const subscription = req.body;
|
|
7
7
|
const userId = req.user?._id || req.user?.id; // supports both mongoose and prisma IDs
|
|
8
8
|
|
|
9
|
-
if (!subscription
|
|
9
|
+
if (!subscription) {
|
|
10
10
|
return next({ status: 400, message: "Invalid subscription payload" });
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
-
const
|
|
13
|
+
const isExpo = !!subscription.token;
|
|
14
|
+
const isWeb = !!(subscription.endpoint && subscription.keys);
|
|
14
15
|
|
|
15
|
-
if (
|
|
16
|
-
|
|
17
|
-
existingSub.user = userId; await existingSub.save();
|
|
18
|
-
}
|
|
19
|
-
return res.status(200).json({ success: true, message: "Already subscribed." });
|
|
16
|
+
if (!isExpo && !isWeb) {
|
|
17
|
+
return next({ status: 400, message: "Missing token (EXPO) or endpoint/keys (WEB)" });
|
|
20
18
|
}
|
|
21
19
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
20
|
+
if (isExpo) {
|
|
21
|
+
const existingSub = await PushSubscription.findOne({ expoPushToken: subscription.token });
|
|
22
|
+
if (existingSub) {
|
|
23
|
+
if (userId && String(existingSub.user) !== String(userId)) {
|
|
24
|
+
existingSub.user = userId; await existingSub.save();
|
|
25
|
+
}
|
|
26
|
+
return res.status(200).json({ success: true, message: "Already subscribed." });
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
await PushSubscription.create({
|
|
30
|
+
type: "EXPO",
|
|
31
|
+
expoPushToken: subscription.token,
|
|
32
|
+
user: userId || undefined
|
|
33
|
+
});
|
|
34
|
+
} else {
|
|
35
|
+
const existingSub = await PushSubscription.findOne({ endpoint: subscription.endpoint });
|
|
36
|
+
if (existingSub) {
|
|
37
|
+
if (userId && String(existingSub.user) !== String(userId)) {
|
|
38
|
+
existingSub.user = userId; await existingSub.save();
|
|
39
|
+
}
|
|
40
|
+
return res.status(200).json({ success: true, message: "Already subscribed." });
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
await PushSubscription.create({
|
|
44
|
+
type: "WEB",
|
|
45
|
+
endpoint: subscription.endpoint,
|
|
46
|
+
keys: subscription.keys,
|
|
47
|
+
user: userId || undefined
|
|
48
|
+
});
|
|
49
|
+
}
|
|
29
50
|
|
|
30
51
|
res.status(201).json({ success: true, message: "Subscription created." });
|
|
31
52
|
} catch (error) {
|
|
@@ -3,6 +3,11 @@ import mongoose from "mongoose";
|
|
|
3
3
|
// Handles both Web Push (endpoint + keys) and Expo Push (expoPushToken)
|
|
4
4
|
const pushSubscriptionSchema = new mongoose.Schema(
|
|
5
5
|
{
|
|
6
|
+
type: {
|
|
7
|
+
type: String,
|
|
8
|
+
enum: ["WEB", "EXPO"],
|
|
9
|
+
default: "WEB",
|
|
10
|
+
},
|
|
6
11
|
// Web Push fields
|
|
7
12
|
endpoint: {
|
|
8
13
|
type: String,
|
|
@@ -1,20 +1,67 @@
|
|
|
1
1
|
import webpush from "../config/webPush.js";
|
|
2
|
+
import { Expo } from "expo-server-sdk";
|
|
2
3
|
import logger from "./logger.js";
|
|
3
4
|
import PushSubscription from "../models/pushSubscription.model.js";
|
|
4
5
|
|
|
5
|
-
|
|
6
|
+
const expo = new Expo();
|
|
7
|
+
|
|
8
|
+
export const sendPushToUser = async (
|
|
9
|
+
userId,
|
|
10
|
+
title,
|
|
11
|
+
body,
|
|
12
|
+
url = "/",
|
|
13
|
+
) => {
|
|
6
14
|
try {
|
|
7
|
-
const
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
15
|
+
const subscriptions = await PushSubscription.find({ user: userId });
|
|
16
|
+
|
|
17
|
+
if (subscriptions.length === 0) return;
|
|
18
|
+
|
|
19
|
+
const webSubs = subscriptions.filter(s => s.type === "WEB");
|
|
20
|
+
const expoSubs = subscriptions.filter(s => s.type === "EXPO");
|
|
21
|
+
|
|
22
|
+
// Web Push
|
|
23
|
+
if (webSubs.length > 0) {
|
|
24
|
+
const payload = JSON.stringify({ title, body, url });
|
|
25
|
+
await Promise.allSettled(
|
|
26
|
+
webSubs.map(async (sub) => {
|
|
27
|
+
if (!sub.endpoint || !sub.keys) return;
|
|
28
|
+
const pushSub = { endpoint: sub.endpoint, keys: sub.keys };
|
|
29
|
+
try {
|
|
30
|
+
await webpush.sendNotification(pushSub, payload);
|
|
31
|
+
} catch (err) {
|
|
32
|
+
if (err.statusCode === 404 || err.statusCode === 410) {
|
|
33
|
+
await sub.deleteOne();
|
|
34
|
+
} else {
|
|
35
|
+
logger.error("Web Push Error", err);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
})
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Expo Push
|
|
43
|
+
if (expoSubs.length > 0) {
|
|
44
|
+
const messages = [];
|
|
45
|
+
for (const sub of expoSubs) {
|
|
46
|
+
if (!sub.expoPushToken || !Expo.isExpoPushToken(sub.expoPushToken)) continue;
|
|
47
|
+
messages.push({
|
|
48
|
+
to: sub.expoPushToken,
|
|
49
|
+
sound: "default",
|
|
50
|
+
title,
|
|
51
|
+
body,
|
|
52
|
+
data: { url },
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const chunks = expo.chunkPushNotifications(messages);
|
|
57
|
+
for (const chunk of chunks) {
|
|
58
|
+
try {
|
|
59
|
+
await expo.sendPushNotificationsAsync(chunk);
|
|
60
|
+
} catch (error) {
|
|
61
|
+
logger.error("Error sending push notification chunk", error);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
18
65
|
} catch (error) {
|
|
19
66
|
logger.error("Error sending push notification to user", error);
|
|
20
67
|
}
|