@dereekb/firebase-server 12.6.21 → 13.0.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/LICENSE +1 -1
- package/index.cjs.js +2937 -0
- package/index.esm.js +2775 -0
- package/mailgun/index.cjs.js +48 -0
- package/mailgun/index.esm.js +46 -0
- package/mailgun/package.json +26 -6
- package/model/index.cjs.js +5298 -0
- package/model/index.d.ts +1 -0
- package/model/index.esm.js +5161 -0
- package/model/package.json +31 -3
- package/model/src/lib/notification/notification.module.d.ts +10 -10
- package/model/src/lib/storagefile/storagefile.task.service.handler.d.ts +3 -14
- package/package.json +48 -27
- package/src/lib/auth/auth.context.d.ts +1 -1
- package/src/lib/auth/auth.service.d.ts +1 -1
- package/src/lib/function/assert.d.ts +2 -2
- package/src/lib/function/context.d.ts +1 -1
- package/src/lib/index.d.ts +1 -0
- package/src/lib/nest/app.d.ts +1 -1
- package/src/lib/nest/development/development.app.function.d.ts +1 -2
- package/src/lib/nest/function/call.d.ts +1 -1
- package/src/lib/nest/function/context.d.ts +0 -4
- package/src/lib/nest/function/index.d.ts +0 -1
- package/src/lib/nest/function/nest.d.ts +1 -1
- package/src/lib/nest/function/v2/blocking.d.ts +3 -2
- package/src/lib/nest/model/crud.assert.function.d.ts +0 -4
- package/src/lib/storage/storage.d.ts +1 -1
- package/src/lib/type.d.ts +9 -0
- package/test/index.cjs.js +1324 -0
- package/test/index.d.ts +1 -0
- package/test/index.esm.js +1247 -0
- package/test/package.json +34 -3
- package/test/src/lib/firebase/firebase.admin.auth.d.ts +22 -13
- package/test/src/lib/firebase/firebase.admin.collection.d.ts +6 -6
- package/test/src/lib/firebase/firebase.admin.d.ts +10 -10
- package/test/src/lib/firebase/firebase.admin.function.d.ts +9 -9
- package/test/src/lib/firebase/firebase.admin.nest.d.ts +8 -8
- package/test/src/lib/firebase/firebase.admin.nest.function.d.ts +9 -9
- package/test/src/lib/firebase/firebase.test.d.ts +30 -0
- package/test/src/lib/firebase/index.d.ts +1 -1
- package/test/src/lib/firestore/firestore.admin.d.ts +3 -3
- package/test/src/lib/firestore/firestore.d.ts +2 -2
- package/test/src/lib/storage/storage.admin.d.ts +3 -3
- package/test/src/lib/storage/storage.d.ts +2 -2
- package/zoho/LICENSE +1 -1
- package/zoho/index.d.ts +1 -0
- package/zoho/index.esm.js +2 -2
- package/zoho/package.json +12 -8
- package/CHANGELOG.md +0 -2233
- package/mailgun/src/index.js +0 -5
- package/mailgun/src/index.js.map +0 -1
- package/mailgun/src/lib/auth.mailgun.js +0 -41
- package/mailgun/src/lib/auth.mailgun.js.map +0 -1
- package/mailgun/src/lib/index.js +0 -5
- package/mailgun/src/lib/index.js.map +0 -1
- package/model/src/index.js +0 -5
- package/model/src/index.js.map +0 -1
- package/model/src/lib/index.js +0 -7
- package/model/src/lib/index.js.map +0 -1
- package/model/src/lib/mailgun/index.js +0 -5
- package/model/src/lib/mailgun/index.js.map +0 -1
- package/model/src/lib/mailgun/notification.send.service.mailgun.js +0 -68
- package/model/src/lib/mailgun/notification.send.service.mailgun.js.map +0 -1
- package/model/src/lib/notification/index.js +0 -20
- package/model/src/lib/notification/index.js.map +0 -1
- package/model/src/lib/notification/notification.action.init.service.js +0 -230
- package/model/src/lib/notification/notification.action.init.service.js.map +0 -1
- package/model/src/lib/notification/notification.action.service.js +0 -1487
- package/model/src/lib/notification/notification.action.service.js.map +0 -1
- package/model/src/lib/notification/notification.config.js +0 -13
- package/model/src/lib/notification/notification.config.js.map +0 -1
- package/model/src/lib/notification/notification.config.service.js +0 -60
- package/model/src/lib/notification/notification.config.service.js.map +0 -1
- package/model/src/lib/notification/notification.create.run.js +0 -59
- package/model/src/lib/notification/notification.create.run.js.map +0 -1
- package/model/src/lib/notification/notification.error.js +0 -87
- package/model/src/lib/notification/notification.error.js.map +0 -1
- package/model/src/lib/notification/notification.expedite.service.js +0 -112
- package/model/src/lib/notification/notification.expedite.service.js.map +0 -1
- package/model/src/lib/notification/notification.module.js +0 -106
- package/model/src/lib/notification/notification.module.js.map +0 -1
- package/model/src/lib/notification/notification.send.js +0 -3
- package/model/src/lib/notification/notification.send.js.map +0 -1
- package/model/src/lib/notification/notification.send.service.js +0 -10
- package/model/src/lib/notification/notification.send.service.js.map +0 -1
- package/model/src/lib/notification/notification.send.service.notificationsummary.js +0 -104
- package/model/src/lib/notification/notification.send.service.notificationsummary.js.map +0 -1
- package/model/src/lib/notification/notification.send.service.text.js +0 -29
- package/model/src/lib/notification/notification.send.service.text.js.map +0 -1
- package/model/src/lib/notification/notification.task.service.handler.js +0 -65
- package/model/src/lib/notification/notification.task.service.handler.js.map +0 -1
- package/model/src/lib/notification/notification.task.service.js +0 -10
- package/model/src/lib/notification/notification.task.service.js.map +0 -1
- package/model/src/lib/notification/notification.task.service.util.js +0 -27
- package/model/src/lib/notification/notification.task.service.util.js.map +0 -1
- package/model/src/lib/notification/notification.task.subtask.handler.js +0 -256
- package/model/src/lib/notification/notification.task.subtask.handler.js.map +0 -1
- package/model/src/lib/notification/notification.util.js +0 -478
- package/model/src/lib/notification/notification.util.js.map +0 -1
- package/model/src/lib/storagefile/index.js +0 -12
- package/model/src/lib/storagefile/index.js.map +0 -1
- package/model/src/lib/storagefile/storagefile.action.init.service.js +0 -155
- package/model/src/lib/storagefile/storagefile.action.init.service.js.map +0 -1
- package/model/src/lib/storagefile/storagefile.action.server.js +0 -797
- package/model/src/lib/storagefile/storagefile.action.server.js.map +0 -1
- package/model/src/lib/storagefile/storagefile.error.js +0 -106
- package/model/src/lib/storagefile/storagefile.error.js.map +0 -1
- package/model/src/lib/storagefile/storagefile.module.js +0 -64
- package/model/src/lib/storagefile/storagefile.module.js.map +0 -1
- package/model/src/lib/storagefile/storagefile.task.service.handler.js +0 -287
- package/model/src/lib/storagefile/storagefile.task.service.handler.js.map +0 -1
- package/model/src/lib/storagefile/storagefile.upload.service.initializer.js +0 -180
- package/model/src/lib/storagefile/storagefile.upload.service.initializer.js.map +0 -1
- package/model/src/lib/storagefile/storagefile.upload.service.js +0 -10
- package/model/src/lib/storagefile/storagefile.upload.service.js.map +0 -1
- package/model/src/lib/storagefile/storagefile.util.js +0 -54
- package/model/src/lib/storagefile/storagefile.util.js.map +0 -1
- package/src/index.js +0 -5
- package/src/index.js.map +0 -1
- package/src/lib/auth/auth.context.js +0 -13
- package/src/lib/auth/auth.context.js.map +0 -1
- package/src/lib/auth/auth.service.error.js +0 -34
- package/src/lib/auth/auth.service.error.js.map +0 -1
- package/src/lib/auth/auth.service.js +0 -427
- package/src/lib/auth/auth.service.js.map +0 -1
- package/src/lib/auth/auth.util.js +0 -23
- package/src/lib/auth/auth.util.js.map +0 -1
- package/src/lib/auth/index.js +0 -8
- package/src/lib/auth/index.js.map +0 -1
- package/src/lib/env/env.service.js +0 -7
- package/src/lib/env/env.service.js.map +0 -1
- package/src/lib/env/index.js +0 -5
- package/src/lib/env/index.js.map +0 -1
- package/src/lib/firestore/array.js +0 -34
- package/src/lib/firestore/array.js.map +0 -1
- package/src/lib/firestore/driver.accessor.batch.js +0 -93
- package/src/lib/firestore/driver.accessor.batch.js.map +0 -1
- package/src/lib/firestore/driver.accessor.default.js +0 -62
- package/src/lib/firestore/driver.accessor.default.js.map +0 -1
- package/src/lib/firestore/driver.accessor.js +0 -50
- package/src/lib/firestore/driver.accessor.js.map +0 -1
- package/src/lib/firestore/driver.accessor.transaction.js +0 -96
- package/src/lib/firestore/driver.accessor.transaction.js.map +0 -1
- package/src/lib/firestore/driver.js +0 -14
- package/src/lib/firestore/driver.js.map +0 -1
- package/src/lib/firestore/driver.query.js +0 -55
- package/src/lib/firestore/driver.query.js.map +0 -1
- package/src/lib/firestore/firestore.js +0 -10
- package/src/lib/firestore/firestore.js.map +0 -1
- package/src/lib/firestore/increment.js +0 -17
- package/src/lib/firestore/increment.js.map +0 -1
- package/src/lib/firestore/index.js +0 -9
- package/src/lib/firestore/index.js.map +0 -1
- package/src/lib/function/assert.js +0 -68
- package/src/lib/function/assert.js.map +0 -1
- package/src/lib/function/context.js +0 -14
- package/src/lib/function/context.js.map +0 -1
- package/src/lib/function/error.auth.js +0 -25
- package/src/lib/function/error.auth.js.map +0 -1
- package/src/lib/function/error.js +0 -221
- package/src/lib/function/error.js.map +0 -1
- package/src/lib/function/index.js +0 -9
- package/src/lib/function/index.js.map +0 -1
- package/src/lib/function/type.js +0 -3
- package/src/lib/function/type.js.map +0 -1
- package/src/lib/index.js +0 -11
- package/src/lib/index.js.map +0 -1
- package/src/lib/nest/app.js +0 -114
- package/src/lib/nest/app.js.map +0 -1
- package/src/lib/nest/auth/auth.module.js +0 -60
- package/src/lib/nest/auth/auth.module.js.map +0 -1
- package/src/lib/nest/auth/auth.util.js +0 -72
- package/src/lib/nest/auth/auth.util.js.map +0 -1
- package/src/lib/nest/auth/index.js +0 -6
- package/src/lib/nest/auth/index.js.map +0 -1
- package/src/lib/nest/development/development.app.function.js +0 -38
- package/src/lib/nest/development/development.app.function.js.map +0 -1
- package/src/lib/nest/development/development.assert.function.js +0 -3
- package/src/lib/nest/development/development.assert.function.js.map +0 -1
- package/src/lib/nest/development/development.function.js +0 -41
- package/src/lib/nest/development/development.function.js.map +0 -1
- package/src/lib/nest/development/development.schedule.function.error.js +0 -35
- package/src/lib/nest/development/development.schedule.function.error.js.map +0 -1
- package/src/lib/nest/development/development.schedule.function.js +0 -54
- package/src/lib/nest/development/development.schedule.function.js.map +0 -1
- package/src/lib/nest/development/index.js +0 -9
- package/src/lib/nest/development/index.js.map +0 -1
- package/src/lib/nest/env/env.service.js +0 -19
- package/src/lib/nest/env/env.service.js.map +0 -1
- package/src/lib/nest/env/env.util.js +0 -12
- package/src/lib/nest/env/env.util.js.map +0 -1
- package/src/lib/nest/env/index.js +0 -6
- package/src/lib/nest/env/index.js.map +0 -1
- package/src/lib/nest/firebase/firebase.module.js +0 -17
- package/src/lib/nest/firebase/firebase.module.js.map +0 -1
- package/src/lib/nest/firebase/index.js +0 -5
- package/src/lib/nest/firebase/index.js.map +0 -1
- package/src/lib/nest/firestore/firestore.module.js +0 -86
- package/src/lib/nest/firestore/firestore.module.js.map +0 -1
- package/src/lib/nest/firestore/index.js +0 -5
- package/src/lib/nest/firestore/index.js.map +0 -1
- package/src/lib/nest/function/call.js +0 -46
- package/src/lib/nest/function/call.js.map +0 -1
- package/src/lib/nest/function/context.js +0 -79
- package/src/lib/nest/function/context.js.map +0 -1
- package/src/lib/nest/function/index.js +0 -10
- package/src/lib/nest/function/index.js.map +0 -1
- package/src/lib/nest/function/nest.js +0 -17
- package/src/lib/nest/function/nest.js.map +0 -1
- package/src/lib/nest/function/schedule.js +0 -8
- package/src/lib/nest/function/schedule.js.map +0 -1
- package/src/lib/nest/function/v1/call.d.ts +0 -59
- package/src/lib/nest/function/v1/call.js +0 -55
- package/src/lib/nest/function/v1/call.js.map +0 -1
- package/src/lib/nest/function/v1/event.d.ts +0 -80
- package/src/lib/nest/function/v1/event.js +0 -52
- package/src/lib/nest/function/v1/event.js.map +0 -1
- package/src/lib/nest/function/v1/index.d.ts +0 -3
- package/src/lib/nest/function/v1/index.js +0 -7
- package/src/lib/nest/function/v1/index.js.map +0 -1
- package/src/lib/nest/function/v1/schedule.d.ts +0 -47
- package/src/lib/nest/function/v1/schedule.js +0 -68
- package/src/lib/nest/function/v1/schedule.js.map +0 -1
- package/src/lib/nest/function/v2/blocking.js +0 -38
- package/src/lib/nest/function/v2/blocking.js.map +0 -1
- package/src/lib/nest/function/v2/call.js +0 -31
- package/src/lib/nest/function/v2/call.js.map +0 -1
- package/src/lib/nest/function/v2/event.js +0 -25
- package/src/lib/nest/function/v2/event.js.map +0 -1
- package/src/lib/nest/function/v2/index.js +0 -9
- package/src/lib/nest/function/v2/index.js.map +0 -1
- package/src/lib/nest/function/v2/schedule.js +0 -56
- package/src/lib/nest/function/v2/schedule.js.map +0 -1
- package/src/lib/nest/function/v2/taskqueue.js +0 -26
- package/src/lib/nest/function/v2/taskqueue.js.map +0 -1
- package/src/lib/nest/index.js +0 -15
- package/src/lib/nest/index.js.map +0 -1
- package/src/lib/nest/middleware/appcheck.decorator.js +0 -12
- package/src/lib/nest/middleware/appcheck.decorator.js.map +0 -1
- package/src/lib/nest/middleware/appcheck.js +0 -3
- package/src/lib/nest/middleware/appcheck.js.map +0 -1
- package/src/lib/nest/middleware/appcheck.middleware.js +0 -74
- package/src/lib/nest/middleware/appcheck.middleware.js.map +0 -1
- package/src/lib/nest/middleware/appcheck.module.js +0 -21
- package/src/lib/nest/middleware/appcheck.module.js.map +0 -1
- package/src/lib/nest/middleware/globalprefix.js +0 -11
- package/src/lib/nest/middleware/globalprefix.js.map +0 -1
- package/src/lib/nest/middleware/index.js +0 -10
- package/src/lib/nest/middleware/index.js.map +0 -1
- package/src/lib/nest/middleware/rawbody.middleware.js +0 -16
- package/src/lib/nest/middleware/rawbody.middleware.js.map +0 -1
- package/src/lib/nest/middleware/webhook.js +0 -24
- package/src/lib/nest/middleware/webhook.js.map +0 -1
- package/src/lib/nest/model/call.model.function.js +0 -73
- package/src/lib/nest/model/call.model.function.js.map +0 -1
- package/src/lib/nest/model/create.model.function.js +0 -27
- package/src/lib/nest/model/create.model.function.js.map +0 -1
- package/src/lib/nest/model/crud.assert.function.js +0 -3
- package/src/lib/nest/model/crud.assert.function.js.map +0 -1
- package/src/lib/nest/model/delete.model.function.js +0 -27
- package/src/lib/nest/model/delete.model.function.js.map +0 -1
- package/src/lib/nest/model/index.js +0 -11
- package/src/lib/nest/model/index.js.map +0 -1
- package/src/lib/nest/model/permission.error.js +0 -24
- package/src/lib/nest/model/permission.error.js.map +0 -1
- package/src/lib/nest/model/read.model.function.js +0 -27
- package/src/lib/nest/model/read.model.function.js.map +0 -1
- package/src/lib/nest/model/specifier.function.js +0 -35
- package/src/lib/nest/model/specifier.function.js.map +0 -1
- package/src/lib/nest/model/update.model.function.js +0 -27
- package/src/lib/nest/model/update.model.function.js.map +0 -1
- package/src/lib/nest/nest.provider.js +0 -89
- package/src/lib/nest/nest.provider.js.map +0 -1
- package/src/lib/nest/storage/index.js +0 -5
- package/src/lib/nest/storage/index.js.map +0 -1
- package/src/lib/nest/storage/storage.module.js +0 -112
- package/src/lib/nest/storage/storage.module.js.map +0 -1
- package/src/lib/storage/driver.accessor.js +0 -299
- package/src/lib/storage/driver.accessor.js.map +0 -1
- package/src/lib/storage/driver.js +0 -12
- package/src/lib/storage/driver.js.map +0 -1
- package/src/lib/storage/index.js +0 -8
- package/src/lib/storage/index.js.map +0 -1
- package/src/lib/storage/storage.js +0 -20
- package/src/lib/storage/storage.js.map +0 -1
- package/src/lib/storage/storage.service.js +0 -26
- package/src/lib/storage/storage.service.js.map +0 -1
- package/test/src/index.js +0 -5
- package/test/src/index.js.map +0 -1
- package/test/src/lib/firebase/firebase.admin.auth.js +0 -260
- package/test/src/lib/firebase/firebase.admin.auth.js.map +0 -1
- package/test/src/lib/firebase/firebase.admin.collection.js +0 -108
- package/test/src/lib/firebase/firebase.admin.collection.js.map +0 -1
- package/test/src/lib/firebase/firebase.admin.function.js +0 -132
- package/test/src/lib/firebase/firebase.admin.function.js.map +0 -1
- package/test/src/lib/firebase/firebase.admin.js +0 -174
- package/test/src/lib/firebase/firebase.admin.js.map +0 -1
- package/test/src/lib/firebase/firebase.admin.nest.function.callable.context.js +0 -42
- package/test/src/lib/firebase/firebase.admin.nest.function.callable.context.js.map +0 -1
- package/test/src/lib/firebase/firebase.admin.nest.function.cloud.context.js +0 -40
- package/test/src/lib/firebase/firebase.admin.nest.function.cloud.context.js.map +0 -1
- package/test/src/lib/firebase/firebase.admin.nest.function.js +0 -64
- package/test/src/lib/firebase/firebase.admin.nest.function.js.map +0 -1
- package/test/src/lib/firebase/firebase.admin.nest.js +0 -107
- package/test/src/lib/firebase/firebase.admin.nest.js.map +0 -1
- package/test/src/lib/firebase/firebase.admin.test.server.js +0 -37
- package/test/src/lib/firebase/firebase.admin.test.server.js.map +0 -1
- package/test/src/lib/firebase/firebase.function.js +0 -58
- package/test/src/lib/firebase/firebase.function.js.map +0 -1
- package/test/src/lib/firebase/firebase.jest.d.ts +0 -21
- package/test/src/lib/firebase/firebase.jest.js +0 -45
- package/test/src/lib/firebase/firebase.jest.js.map +0 -1
- package/test/src/lib/firebase/firebase.js +0 -74
- package/test/src/lib/firebase/firebase.js.map +0 -1
- package/test/src/lib/firebase/index.js +0 -15
- package/test/src/lib/firebase/index.js.map +0 -1
- package/test/src/lib/firestore/firestore.admin.js +0 -21
- package/test/src/lib/firestore/firestore.admin.js.map +0 -1
- package/test/src/lib/firestore/firestore.js +0 -57
- package/test/src/lib/firestore/firestore.js.map +0 -1
- package/test/src/lib/firestore/index.js +0 -6
- package/test/src/lib/firestore/index.js.map +0 -1
- package/test/src/lib/index.js +0 -7
- package/test/src/lib/index.js.map +0 -1
- package/test/src/lib/storage/index.js +0 -6
- package/test/src/lib/storage/index.js.map +0 -1
- package/test/src/lib/storage/storage.admin.js +0 -21
- package/test/src/lib/storage/storage.admin.js.map +0 -1
- package/test/src/lib/storage/storage.js +0 -59
- package/test/src/lib/storage/storage.js.map +0 -1
- /package/{zoho/index.cjs.d.ts → index.d.ts} +0 -0
- /package/{zoho/index.esm.d.ts → mailgun/index.d.ts} +0 -0
|
@@ -1,1487 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.SEND_QUEUE_NOTIFICATIONS_TASK_EXCESS_THRESHOLD = exports.NOTIFICATION_TASK_TYPE_FAILURE_DELAY_MS = exports.NOTIFICATION_TASK_TYPE_FAILURE_DELAY_HOURS = exports.NOTIFICATION_TASK_TYPE_MAX_SEND_ATTEMPTS = exports.NOTIFICATION_TASK_MINIMUM_SET_AT_THROTTLE_TIME_MINUTES = exports.NOTIFICATION_BOX_NOT_INITIALIZED_DELAY_MINUTES = exports.NOTIFICATION_MAX_SEND_ATTEMPTS = exports.KNOWN_BUT_UNCONFIGURED_NOTIFICATION_TEMPLATE_TYPE_DELETE_AFTER_RETRY_ATTEMPTS = exports.KNOWN_BUT_UNCONFIGURED_NOTIFICATION_TEMPLATE_TYPE_HOURS_DELAY = exports.UNKNOWN_NOTIFICATION_TASK_TYPE_DELETE_AFTER_RETRY_ATTEMPTS = exports.UNKNOWN_NOTIFICATION_TASK_TYPE_HOURS_DELAY = exports.UNKNOWN_NOTIFICATION_TEMPLATE_TYPE_DELETE_AFTER_RETRY_ATTEMPTS = exports.UNKNOWN_NOTIFICATION_TEMPLATE_TYPE_HOURS_DELAY = exports.NotificationServerActions = exports.NOTIFICATION_SERVER_ACTION_CONTEXT_TOKEN = exports.BASE_NOTIFICATION_SERVER_ACTION_CONTEXT_TOKEN = void 0;
|
|
4
|
-
exports.notificationServerActions = notificationServerActions;
|
|
5
|
-
exports.createNotificationUserFactory = createNotificationUserFactory;
|
|
6
|
-
exports.updateNotificationUserFactory = updateNotificationUserFactory;
|
|
7
|
-
exports.resyncNotificationUserFactory = resyncNotificationUserFactory;
|
|
8
|
-
exports.resyncAllNotificationUsersFactory = resyncAllNotificationUsersFactory;
|
|
9
|
-
exports.createNotificationSummaryFactory = createNotificationSummaryFactory;
|
|
10
|
-
exports.updateNotificationSummaryFactory = updateNotificationSummaryFactory;
|
|
11
|
-
exports.createNotificationBoxInTransactionFactory = createNotificationBoxInTransactionFactory;
|
|
12
|
-
exports.createNotificationBoxFactory = createNotificationBoxFactory;
|
|
13
|
-
exports.updateNotificationBoxFactory = updateNotificationBoxFactory;
|
|
14
|
-
exports.updateNotificationBoxRecipientExclusionInTransactionFactory = updateNotificationBoxRecipientExclusionInTransactionFactory;
|
|
15
|
-
exports.updateNotificationBoxRecipientInTransactionFactory = updateNotificationBoxRecipientInTransactionFactory;
|
|
16
|
-
exports.updateNotificationBoxRecipientFactory = updateNotificationBoxRecipientFactory;
|
|
17
|
-
exports.sendNotificationFactory = sendNotificationFactory;
|
|
18
|
-
exports.sendQueuedNotificationsFactory = sendQueuedNotificationsFactory;
|
|
19
|
-
exports.cleanupSentNotificationsFactory = cleanupSentNotificationsFactory;
|
|
20
|
-
const date_1 = require("@dereekb/date");
|
|
21
|
-
const firebase_1 = require("@dereekb/firebase");
|
|
22
|
-
const firebase_server_1 = require("@dereekb/firebase-server");
|
|
23
|
-
const util_1 = require("@dereekb/util");
|
|
24
|
-
const date_fns_1 = require("date-fns");
|
|
25
|
-
const notification_error_1 = require("./notification.error");
|
|
26
|
-
const notification_util_1 = require("./notification.util");
|
|
27
|
-
const notification_task_service_util_1 = require("./notification.task.service.util");
|
|
28
|
-
/**
|
|
29
|
-
* Injection token for the BaseNotificationServerActionsContext
|
|
30
|
-
*/
|
|
31
|
-
exports.BASE_NOTIFICATION_SERVER_ACTION_CONTEXT_TOKEN = 'BASE_NOTIFICATION_SERVER_ACTION_CONTEXT';
|
|
32
|
-
/**
|
|
33
|
-
* Injection token for the NotificationServerActionsContext
|
|
34
|
-
*/
|
|
35
|
-
exports.NOTIFICATION_SERVER_ACTION_CONTEXT_TOKEN = 'NOTIFICATION_SERVER_ACTION_CONTEXT';
|
|
36
|
-
class NotificationServerActions {
|
|
37
|
-
}
|
|
38
|
-
exports.NotificationServerActions = NotificationServerActions;
|
|
39
|
-
function notificationServerActions(context) {
|
|
40
|
-
return {
|
|
41
|
-
createNotificationUser: createNotificationUserFactory(context),
|
|
42
|
-
updateNotificationUser: updateNotificationUserFactory(context),
|
|
43
|
-
resyncNotificationUser: resyncNotificationUserFactory(context),
|
|
44
|
-
resyncAllNotificationUsers: resyncAllNotificationUsersFactory(context),
|
|
45
|
-
createNotificationSummary: createNotificationSummaryFactory(context),
|
|
46
|
-
updateNotificationSummary: updateNotificationSummaryFactory(context),
|
|
47
|
-
createNotificationBox: createNotificationBoxFactory(context),
|
|
48
|
-
updateNotificationBox: updateNotificationBoxFactory(context),
|
|
49
|
-
updateNotificationBoxRecipient: updateNotificationBoxRecipientFactory(context),
|
|
50
|
-
sendNotification: sendNotificationFactory(context),
|
|
51
|
-
sendQueuedNotifications: sendQueuedNotificationsFactory(context),
|
|
52
|
-
cleanupSentNotifications: cleanupSentNotificationsFactory(context)
|
|
53
|
-
};
|
|
54
|
-
}
|
|
55
|
-
// MARK: Actions
|
|
56
|
-
function createNotificationUserFactory(context) {
|
|
57
|
-
const { firebaseServerActionTransformFunctionFactory, notificationUserCollection, authService } = context;
|
|
58
|
-
return firebaseServerActionTransformFunctionFactory(firebase_1.CreateNotificationUserParams, async (params) => {
|
|
59
|
-
const { uid } = params;
|
|
60
|
-
return async () => {
|
|
61
|
-
// assert they exist in the auth system
|
|
62
|
-
const userContext = authService.userContext(uid);
|
|
63
|
-
const userExistsInAuth = await userContext.exists();
|
|
64
|
-
if (!userExistsInAuth) {
|
|
65
|
-
throw (0, notification_error_1.notificationUserInvalidUidForCreateError)(uid);
|
|
66
|
-
}
|
|
67
|
-
const notificationUserDocument = notificationUserCollection.documentAccessor().loadDocumentForId(uid);
|
|
68
|
-
const newUserTemplate = {
|
|
69
|
-
uid,
|
|
70
|
-
x: [],
|
|
71
|
-
bc: [],
|
|
72
|
-
b: [],
|
|
73
|
-
dc: {
|
|
74
|
-
c: {}
|
|
75
|
-
},
|
|
76
|
-
gc: {
|
|
77
|
-
c: {}
|
|
78
|
-
}
|
|
79
|
-
};
|
|
80
|
-
await notificationUserDocument.create(newUserTemplate);
|
|
81
|
-
return notificationUserDocument;
|
|
82
|
-
};
|
|
83
|
-
});
|
|
84
|
-
}
|
|
85
|
-
function updateNotificationUserFactory(context) {
|
|
86
|
-
const { firestoreContext, firebaseServerActionTransformFunctionFactory, notificationUserCollection, appNotificationTemplateTypeInfoRecordService } = context;
|
|
87
|
-
return firebaseServerActionTransformFunctionFactory(firebase_1.UpdateNotificationUserParams, async (params) => {
|
|
88
|
-
const { gc: inputGc, dc: inputDc, bc: inputBc } = params;
|
|
89
|
-
return async (notificationUserDocument) => {
|
|
90
|
-
await firestoreContext.runTransaction(async (transaction) => {
|
|
91
|
-
const notificationUserDocumentInTransaction = notificationUserCollection.documentAccessorForTransaction(transaction).loadDocumentFrom(notificationUserDocument);
|
|
92
|
-
const notificationUser = await (0, firebase_server_1.assertSnapshotData)(notificationUserDocumentInTransaction);
|
|
93
|
-
const updateTemplate = {};
|
|
94
|
-
const allKnownNotificationTypes = appNotificationTemplateTypeInfoRecordService.getAllKnownTemplateTypes();
|
|
95
|
-
if (inputDc != null) {
|
|
96
|
-
updateTemplate.dc = (0, firebase_1.updateNotificationUserDefaultNotificationBoxRecipientConfig)(notificationUser.dc, inputDc, allKnownNotificationTypes);
|
|
97
|
-
}
|
|
98
|
-
if (inputGc != null) {
|
|
99
|
-
const nextGc = (0, firebase_1.updateNotificationUserDefaultNotificationBoxRecipientConfig)(notificationUser.gc, inputGc, allKnownNotificationTypes);
|
|
100
|
-
if (!(0, util_1.areEqualPOJOValues)(notificationUser.gc, nextGc)) {
|
|
101
|
-
updateTemplate.gc = nextGc;
|
|
102
|
-
// iterate and update any box config that has the effective recipient change
|
|
103
|
-
updateTemplate.bc = notificationUser.bc.map((currentConfig) => {
|
|
104
|
-
// check item isn't already marked for sync or marked as removed
|
|
105
|
-
if (currentConfig.ns === true || currentConfig.rm === true) {
|
|
106
|
-
return currentConfig;
|
|
107
|
-
}
|
|
108
|
-
const currentEffectiveRecipient = (0, firebase_1.effectiveNotificationBoxRecipientConfig)({
|
|
109
|
-
uid: notificationUser.uid,
|
|
110
|
-
appNotificationTemplateTypeInfoRecordService,
|
|
111
|
-
gc: notificationUser.gc,
|
|
112
|
-
boxConfig: currentConfig
|
|
113
|
-
});
|
|
114
|
-
const nextEffectiveRecipient = (0, firebase_1.effectiveNotificationBoxRecipientConfig)({
|
|
115
|
-
uid: notificationUser.uid,
|
|
116
|
-
appNotificationTemplateTypeInfoRecordService,
|
|
117
|
-
gc: nextGc,
|
|
118
|
-
boxConfig: currentConfig
|
|
119
|
-
});
|
|
120
|
-
const effectiveConfigChanged = !(0, util_1.areEqualPOJOValues)(currentEffectiveRecipient, nextEffectiveRecipient);
|
|
121
|
-
return effectiveConfigChanged ? { ...currentConfig, ns: true } : currentConfig;
|
|
122
|
-
});
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
if (inputBc != null) {
|
|
126
|
-
const updateTemplateBc = (0, firebase_1.updateNotificationUserNotificationBoxRecipientConfigs)(updateTemplate.bc ?? notificationUser.bc, inputBc, appNotificationTemplateTypeInfoRecordService);
|
|
127
|
-
if (updateTemplateBc != null) {
|
|
128
|
-
// re-apply exclusions to the updated configs
|
|
129
|
-
const withExclusions = (0, firebase_1.applyExclusionsToNotificationUserNotificationBoxRecipientConfigs)({
|
|
130
|
-
notificationUser,
|
|
131
|
-
bc: updateTemplateBc,
|
|
132
|
-
recalculateNs: false
|
|
133
|
-
});
|
|
134
|
-
updateTemplate.bc = withExclusions.bc;
|
|
135
|
-
updateTemplate.b = updateTemplateBc.map((x) => x.nb);
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
// if bc is being updated, then also update ns
|
|
139
|
-
if (updateTemplate.bc != null) {
|
|
140
|
-
updateTemplate.ns = (0, firebase_1.calculateNsForNotificationUserNotificationBoxRecipientConfigs)(updateTemplate.bc);
|
|
141
|
-
}
|
|
142
|
-
await notificationUserDocumentInTransaction.update(updateTemplate);
|
|
143
|
-
});
|
|
144
|
-
return notificationUserDocument;
|
|
145
|
-
};
|
|
146
|
-
});
|
|
147
|
-
}
|
|
148
|
-
const MAX_NOTIFICATION_BOXES_TO_UPDATE_PER_BATCH = 50;
|
|
149
|
-
function resyncNotificationUserFactory(context) {
|
|
150
|
-
const { firestoreContext, firebaseServerActionTransformFunctionFactory, notificationBoxCollection, notificationUserCollection, appNotificationTemplateTypeInfoRecordService } = context;
|
|
151
|
-
return firebaseServerActionTransformFunctionFactory(firebase_1.ResyncNotificationUserParams, async () => {
|
|
152
|
-
return async (notificationUserDocument) => {
|
|
153
|
-
// run updates in batches
|
|
154
|
-
let notificationBoxesUpdated = 0;
|
|
155
|
-
let hasMoreNotificationBoxesToSync = true;
|
|
156
|
-
while (hasMoreNotificationBoxesToSync) {
|
|
157
|
-
const batchResult = await firestoreContext.runTransaction(async (transaction) => {
|
|
158
|
-
const notificationUserDocumentInTransaction = notificationUserCollection.documentAccessorForTransaction(transaction).loadDocumentFrom(notificationUserDocument);
|
|
159
|
-
const notificationUser = await (0, firebase_server_1.assertSnapshotData)(notificationUserDocumentInTransaction);
|
|
160
|
-
const { gc } = notificationUser;
|
|
161
|
-
const notificationBoxConfigsToSync = notificationUser.bc.filter((x) => x.ns);
|
|
162
|
-
const notificationBoxConfigsToSyncInThisBatch = (0, util_1.takeFront)(notificationBoxConfigsToSync, MAX_NOTIFICATION_BOXES_TO_UPDATE_PER_BATCH);
|
|
163
|
-
/**
|
|
164
|
-
* These are the actual number of NotificationBox values that had recipients updated.
|
|
165
|
-
*/
|
|
166
|
-
let notificationBoxesUpdatedInBatch = 0;
|
|
167
|
-
let hasUnsyncedNotificationBoxConfigs = false;
|
|
168
|
-
if (notificationBoxConfigsToSyncInThisBatch.length > 0) {
|
|
169
|
-
const notificationBoxConfigsToSyncInThisBatchMap = (0, util_1.makeModelMap)(notificationBoxConfigsToSyncInThisBatch, (x) => x.nb);
|
|
170
|
-
const notificationBoxIdsToSyncInThisBatch = Array.from(notificationBoxConfigsToSyncInThisBatchMap.keys());
|
|
171
|
-
const notificationBoxDocuments = (0, firebase_1.loadDocumentsForIds)(notificationBoxCollection.documentAccessorForTransaction(transaction), notificationBoxIdsToSyncInThisBatch);
|
|
172
|
-
const notificationBoxDocumentSnapshotDataPairs = await (0, firebase_1.getDocumentSnapshotDataPairs)(notificationBoxDocuments);
|
|
173
|
-
const notificationBoxConfigsToRemoveFromNotificationUser = new Set();
|
|
174
|
-
const notificationUserNotificationBoxConfigsToMarkAsRemoved = new Set();
|
|
175
|
-
const nextRecipientsMap = new Map();
|
|
176
|
-
// update each NotificationBoxDocument
|
|
177
|
-
await (0, util_1.performAsyncTasks)(notificationBoxDocumentSnapshotDataPairs, async (notificationBoxDocumentSnapshotDataPair) => {
|
|
178
|
-
const { data: notificationBox, document } = notificationBoxDocumentSnapshotDataPair;
|
|
179
|
-
const nb = document.id;
|
|
180
|
-
const notificationUserNotificationBoxConfig = notificationBoxConfigsToSyncInThisBatchMap.get(nb); // always exists
|
|
181
|
-
if (!notificationBox) {
|
|
182
|
-
// if the entire NotificationBox no longer exists, flag to remove it from the user as a cleanup measure
|
|
183
|
-
notificationBoxConfigsToRemoveFromNotificationUser.add(nb);
|
|
184
|
-
}
|
|
185
|
-
else {
|
|
186
|
-
// update in the NotificationBox
|
|
187
|
-
const recipientIndex = notificationBox.r.findIndex((x) => x.uid === notificationUser.uid);
|
|
188
|
-
let r;
|
|
189
|
-
if (recipientIndex === -1) {
|
|
190
|
-
// if they are not in the NotificationBox, then mark them as removed on the user
|
|
191
|
-
notificationUserNotificationBoxConfigsToMarkAsRemoved.add(nb);
|
|
192
|
-
}
|
|
193
|
-
else if (notificationUserNotificationBoxConfig.rm) {
|
|
194
|
-
// remove from the notification box if it is flagged
|
|
195
|
-
r = (0, util_1.removeValuesAtIndexesFromArrayCopy)(notificationBox.r, recipientIndex);
|
|
196
|
-
}
|
|
197
|
-
else {
|
|
198
|
-
const { m } = notificationBox;
|
|
199
|
-
const recipient = notificationBox.r[recipientIndex];
|
|
200
|
-
const nextRecipient = (0, firebase_1.effectiveNotificationBoxRecipientConfig)({
|
|
201
|
-
uid: notificationUser.uid,
|
|
202
|
-
m,
|
|
203
|
-
appNotificationTemplateTypeInfoRecordService,
|
|
204
|
-
gc,
|
|
205
|
-
boxConfig: notificationUserNotificationBoxConfig,
|
|
206
|
-
recipient
|
|
207
|
-
});
|
|
208
|
-
const recipientHasChange = !(0, util_1.areEqualPOJOValues)(nextRecipient, recipient);
|
|
209
|
-
// only update recipients if the next/new recipient is not equal to the existing one
|
|
210
|
-
if (recipientHasChange) {
|
|
211
|
-
r = [...notificationBox.r];
|
|
212
|
-
r[recipientIndex] = nextRecipient;
|
|
213
|
-
nextRecipientsMap.set(nb, nextRecipient);
|
|
214
|
-
}
|
|
215
|
-
else {
|
|
216
|
-
nextRecipientsMap.set(nb, recipient);
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
// update recipients if needed
|
|
220
|
-
if (r != null) {
|
|
221
|
-
await document.update({ r });
|
|
222
|
-
notificationBoxesUpdatedInBatch += 1;
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
});
|
|
226
|
-
// Update the NotificationUser
|
|
227
|
-
const notificationBoxIdsSynced = new Set(notificationBoxIdsToSyncInThisBatch);
|
|
228
|
-
// start nextConfigs off as a new array with none of the sync'd ids
|
|
229
|
-
const nextConfigs = notificationBoxConfigsToSyncInThisBatch.filter((x) => !notificationBoxIdsSynced.has(x.nb));
|
|
230
|
-
notificationBoxIdsToSyncInThisBatch.forEach((nb) => {
|
|
231
|
-
let nextConfig;
|
|
232
|
-
if (notificationBoxConfigsToRemoveFromNotificationUser.has(nb)) {
|
|
233
|
-
// do nothing, as it should be removed
|
|
234
|
-
}
|
|
235
|
-
else {
|
|
236
|
-
const existingConfig = notificationBoxConfigsToSyncInThisBatchMap.get(nb);
|
|
237
|
-
if (notificationUserNotificationBoxConfigsToMarkAsRemoved.has(nb) || existingConfig.rm) {
|
|
238
|
-
// if the recipient was being removed or is marked as removed, then update the config to confirm removal
|
|
239
|
-
nextConfig = {
|
|
240
|
-
...existingConfig,
|
|
241
|
-
nb,
|
|
242
|
-
rm: true,
|
|
243
|
-
i: util_1.UNSET_INDEX_NUMBER
|
|
244
|
-
};
|
|
245
|
-
}
|
|
246
|
-
else {
|
|
247
|
-
// else, use the updated recipient and keep/copy the
|
|
248
|
-
const updatedRecipient = nextRecipientsMap.get(nb);
|
|
249
|
-
nextConfig = {
|
|
250
|
-
...existingConfig,
|
|
251
|
-
nb,
|
|
252
|
-
rm: false, // mark as not removed
|
|
253
|
-
i: updatedRecipient.i ?? util_1.UNSET_INDEX_NUMBER
|
|
254
|
-
};
|
|
255
|
-
}
|
|
256
|
-
}
|
|
257
|
-
if (nextConfig != null) {
|
|
258
|
-
nextConfig.ns = false; // mark as synced
|
|
259
|
-
nextConfigs.push(nextConfig);
|
|
260
|
-
}
|
|
261
|
-
});
|
|
262
|
-
const ns = nextConfigs.some((x) => x.ns);
|
|
263
|
-
await notificationUserDocumentInTransaction.update({ bc: nextConfigs, ns });
|
|
264
|
-
hasUnsyncedNotificationBoxConfigs = ns;
|
|
265
|
-
}
|
|
266
|
-
const batchResult = {
|
|
267
|
-
hasMoreNotificationBoxesToSync: hasUnsyncedNotificationBoxConfigs,
|
|
268
|
-
notificationBoxesUpdatedInBatch
|
|
269
|
-
};
|
|
270
|
-
return batchResult;
|
|
271
|
-
});
|
|
272
|
-
hasMoreNotificationBoxesToSync = batchResult.hasMoreNotificationBoxesToSync;
|
|
273
|
-
notificationBoxesUpdated += batchResult.notificationBoxesUpdatedInBatch;
|
|
274
|
-
}
|
|
275
|
-
const result = {
|
|
276
|
-
notificationBoxesUpdated
|
|
277
|
-
};
|
|
278
|
-
return result;
|
|
279
|
-
};
|
|
280
|
-
});
|
|
281
|
-
}
|
|
282
|
-
function resyncAllNotificationUsersFactory(context) {
|
|
283
|
-
const { notificationUserCollection } = context;
|
|
284
|
-
const resyncNotificationUser = resyncNotificationUserFactory(context);
|
|
285
|
-
return async () => {
|
|
286
|
-
let notificationBoxesUpdated = 0;
|
|
287
|
-
const resyncNotificationUserParams = { key: (0, firebase_1.firestoreDummyKey)() };
|
|
288
|
-
const resyncNotificationUserInstance = await resyncNotificationUser(resyncNotificationUserParams);
|
|
289
|
-
const iterateResult = await (0, firebase_1.iterateFirestoreDocumentSnapshotPairs)({
|
|
290
|
-
documentAccessor: notificationUserCollection.documentAccessor(),
|
|
291
|
-
iterateSnapshotPair: async (snapshotPair) => {
|
|
292
|
-
const { document: notificationUserDocument } = snapshotPair;
|
|
293
|
-
const result = await resyncNotificationUserInstance(notificationUserDocument);
|
|
294
|
-
notificationBoxesUpdated += result.notificationBoxesUpdated;
|
|
295
|
-
},
|
|
296
|
-
constraintsFactory: () => (0, firebase_1.notificationUsersFlaggedForNeedsSyncQuery)(),
|
|
297
|
-
snapshotsPerformTasksConfig: {
|
|
298
|
-
// prevent NotificationUsers with the same NotificationBoxes from being updated/sync'd at the same time
|
|
299
|
-
nonConcurrentTaskKeyFactory: (x) => {
|
|
300
|
-
const notificationBoxIdsToSync = x
|
|
301
|
-
.data()
|
|
302
|
-
.bc.filter((x) => x.ns)
|
|
303
|
-
.map((x) => x.nb);
|
|
304
|
-
return notificationBoxIdsToSync;
|
|
305
|
-
}
|
|
306
|
-
},
|
|
307
|
-
queryFactory: notificationUserCollection,
|
|
308
|
-
batchSize: undefined,
|
|
309
|
-
performTasksConfig: {
|
|
310
|
-
maxParallelTasks: 10
|
|
311
|
-
}
|
|
312
|
-
});
|
|
313
|
-
const result = {
|
|
314
|
-
notificationUsersResynced: iterateResult.totalSnapshotsVisited,
|
|
315
|
-
notificationBoxesUpdated
|
|
316
|
-
};
|
|
317
|
-
return result;
|
|
318
|
-
};
|
|
319
|
-
}
|
|
320
|
-
function createNotificationSummaryFactory(context) {
|
|
321
|
-
const { firebaseServerActionTransformFunctionFactory, notificationSummaryCollection } = context;
|
|
322
|
-
return firebaseServerActionTransformFunctionFactory(firebase_1.CreateNotificationSummaryParams, async (params) => {
|
|
323
|
-
const { model } = params;
|
|
324
|
-
return async () => {
|
|
325
|
-
const notificationSummaryId = (0, firebase_1.notificationSummaryIdForModel)(model);
|
|
326
|
-
const notificationSummaryDocument = notificationSummaryCollection.documentAccessor().loadDocumentForId(notificationSummaryId);
|
|
327
|
-
const newSummaryTemplate = (0, notification_util_1.makeNewNotificationSummaryTemplate)(model);
|
|
328
|
-
await notificationSummaryDocument.create(newSummaryTemplate);
|
|
329
|
-
return notificationSummaryDocument;
|
|
330
|
-
};
|
|
331
|
-
});
|
|
332
|
-
}
|
|
333
|
-
function updateNotificationSummaryFactory(context) {
|
|
334
|
-
const { firebaseServerActionTransformFunctionFactory } = context;
|
|
335
|
-
return firebaseServerActionTransformFunctionFactory(firebase_1.UpdateNotificationSummaryParams, async (params) => {
|
|
336
|
-
const { setReadAtTime, flagAllRead } = params;
|
|
337
|
-
return async (notificationSummaryDocument) => {
|
|
338
|
-
let updateTemplate;
|
|
339
|
-
if (setReadAtTime != null) {
|
|
340
|
-
updateTemplate = { rat: setReadAtTime };
|
|
341
|
-
}
|
|
342
|
-
else if (flagAllRead === true) {
|
|
343
|
-
updateTemplate = { rat: new Date() };
|
|
344
|
-
}
|
|
345
|
-
if (updateTemplate != null) {
|
|
346
|
-
await notificationSummaryDocument.update(updateTemplate);
|
|
347
|
-
}
|
|
348
|
-
return notificationSummaryDocument;
|
|
349
|
-
};
|
|
350
|
-
});
|
|
351
|
-
}
|
|
352
|
-
function createNotificationBoxInTransactionFactory(context) {
|
|
353
|
-
const { notificationBoxCollection } = context;
|
|
354
|
-
return async (params, transaction) => {
|
|
355
|
-
const { now: inputNow, skipCreate } = params;
|
|
356
|
-
const now = inputNow ?? new Date();
|
|
357
|
-
const notificationBoxDocument = (0, firebase_1.loadNotificationBoxDocumentForReferencePair)(params, notificationBoxCollection.documentAccessorForTransaction(transaction));
|
|
358
|
-
const notificationBoxTemplate = {
|
|
359
|
-
m: notificationBoxDocument.notificationBoxRelatedModelKey,
|
|
360
|
-
o: (0, firebase_1.firestoreDummyKey)(), // set during initialization
|
|
361
|
-
r: [],
|
|
362
|
-
cat: now,
|
|
363
|
-
w: (0, date_1.yearWeekCode)(now),
|
|
364
|
-
s: true // requires initialization
|
|
365
|
-
};
|
|
366
|
-
if (!skipCreate) {
|
|
367
|
-
await notificationBoxDocument.create(notificationBoxTemplate);
|
|
368
|
-
}
|
|
369
|
-
return {
|
|
370
|
-
notificationBoxTemplate,
|
|
371
|
-
notificationBoxDocument
|
|
372
|
-
};
|
|
373
|
-
};
|
|
374
|
-
}
|
|
375
|
-
function createNotificationBoxFactory(context) {
|
|
376
|
-
const { firestoreContext, notificationBoxCollection, firebaseServerActionTransformFunctionFactory } = context;
|
|
377
|
-
const createNotificationBoxInTransaction = createNotificationBoxInTransactionFactory(context);
|
|
378
|
-
return firebaseServerActionTransformFunctionFactory(firebase_1.CreateNotificationBoxParams, async (params) => {
|
|
379
|
-
const { model } = params;
|
|
380
|
-
return async () => {
|
|
381
|
-
const result = await firestoreContext.runTransaction(async (transaction) => {
|
|
382
|
-
const { notificationBoxDocument } = await createNotificationBoxInTransaction({ notificationBoxRelatedModelKey: model }, transaction);
|
|
383
|
-
return notificationBoxDocument;
|
|
384
|
-
});
|
|
385
|
-
return notificationBoxCollection.documentAccessor().loadDocumentFrom(result);
|
|
386
|
-
};
|
|
387
|
-
});
|
|
388
|
-
}
|
|
389
|
-
function updateNotificationBoxFactory({ firebaseServerActionTransformFunctionFactory }) {
|
|
390
|
-
return firebaseServerActionTransformFunctionFactory(firebase_1.UpdateNotificationBoxParams, async () => {
|
|
391
|
-
return async (notificationBoxDocument) => {
|
|
392
|
-
// does nothing currently.
|
|
393
|
-
return notificationBoxDocument;
|
|
394
|
-
};
|
|
395
|
-
});
|
|
396
|
-
}
|
|
397
|
-
function updateNotificationBoxRecipientExclusionInTransactionFactory(context) {
|
|
398
|
-
const { notificationBoxCollection, notificationUserCollection } = context;
|
|
399
|
-
return async (input, transaction) => {
|
|
400
|
-
const { params } = input;
|
|
401
|
-
const { uid: inputUid, i, setExclusion } = params;
|
|
402
|
-
const notificationBoxDocument = (0, firebase_1.loadNotificationBoxDocumentForReferencePair)(input, notificationBoxCollection.documentAccessorForTransaction(transaction));
|
|
403
|
-
let targetUid = inputUid;
|
|
404
|
-
let result = undefined;
|
|
405
|
-
if (setExclusion == null) {
|
|
406
|
-
throw new Error('setExclusion was undefined. Maybe you wanted to call updateNotificationBoxRecipientInTransactionFactory() instead?');
|
|
407
|
-
}
|
|
408
|
-
else if (!inputUid && i != null) {
|
|
409
|
-
// only load the notification box if targeting a recipient by index
|
|
410
|
-
const notificationBox = await notificationBoxDocument.snapshotData();
|
|
411
|
-
if (!notificationBox) {
|
|
412
|
-
throw (0, notification_error_1.notificationBoxExclusionTargetInvalidError)();
|
|
413
|
-
}
|
|
414
|
-
const targetRecipient = notificationBox.r.find((x) => x.i === i);
|
|
415
|
-
if (!targetRecipient || !targetRecipient.uid) {
|
|
416
|
-
throw (0, notification_error_1.notificationBoxExclusionTargetInvalidError)();
|
|
417
|
-
}
|
|
418
|
-
else {
|
|
419
|
-
targetUid = targetRecipient.uid;
|
|
420
|
-
}
|
|
421
|
-
}
|
|
422
|
-
if (!targetUid) {
|
|
423
|
-
throw (0, notification_error_1.notificationBoxExclusionTargetInvalidError)();
|
|
424
|
-
}
|
|
425
|
-
const notificationUserDocument = await notificationUserCollection.documentAccessorForTransaction(transaction).loadDocumentForId(targetUid);
|
|
426
|
-
const notificationUser = await notificationUserDocument.snapshotData();
|
|
427
|
-
if (notificationUser) {
|
|
428
|
-
// only update if the user exists
|
|
429
|
-
const targetExclusions = [notificationBoxDocument.id];
|
|
430
|
-
const { update: notificationUserUpdate } = (0, firebase_1.updateNotificationUserNotificationSendExclusions)({
|
|
431
|
-
notificationUser,
|
|
432
|
-
addExclusions: setExclusion ? targetExclusions : undefined,
|
|
433
|
-
removeExclusions: setExclusion ? undefined : targetExclusions
|
|
434
|
-
});
|
|
435
|
-
await notificationUserDocument.update(notificationUserUpdate);
|
|
436
|
-
result = {
|
|
437
|
-
notificationUserUpdate
|
|
438
|
-
};
|
|
439
|
-
}
|
|
440
|
-
return result;
|
|
441
|
-
};
|
|
442
|
-
}
|
|
443
|
-
function updateNotificationBoxRecipientInTransactionFactory(context) {
|
|
444
|
-
const { authService, notificationBoxCollection, notificationUserCollection } = context;
|
|
445
|
-
const createNotificationBoxInTransaction = createNotificationBoxInTransactionFactory(context);
|
|
446
|
-
return async (input, transaction) => {
|
|
447
|
-
const { params, allowCreateNotificationBoxIfItDoesNotExist, throwErrorIfNotificationBoxDoesNotExist } = input;
|
|
448
|
-
const { uid, i, insert, remove, configs: inputC, setExclusion } = params;
|
|
449
|
-
const findRecipientFn = (x) => (uid != null && x.uid === uid) || (i != null && x.i === i);
|
|
450
|
-
if (setExclusion != null) {
|
|
451
|
-
throw new Error('exclusion update must be processed by updateNotificationBoxRecipientExclusionInTransactionFactory() function.');
|
|
452
|
-
}
|
|
453
|
-
const notificationBoxDocument = (0, firebase_1.loadNotificationBoxDocumentForReferencePair)(input, notificationBoxCollection.documentAccessorForTransaction(transaction));
|
|
454
|
-
let notificationBox = await notificationBoxDocument.snapshotData();
|
|
455
|
-
let createNotificationBox = false;
|
|
456
|
-
let result = undefined;
|
|
457
|
-
if (!notificationBox) {
|
|
458
|
-
if (allowCreateNotificationBoxIfItDoesNotExist) {
|
|
459
|
-
const { notificationBoxTemplate } = await createNotificationBoxInTransaction({
|
|
460
|
-
notificationBoxDocument,
|
|
461
|
-
skipCreate: true // don't create since we still need to read things for the transaction
|
|
462
|
-
}, transaction);
|
|
463
|
-
notificationBox = notificationBoxTemplate;
|
|
464
|
-
createNotificationBox = true;
|
|
465
|
-
}
|
|
466
|
-
else if (throwErrorIfNotificationBoxDoesNotExist) {
|
|
467
|
-
throw (0, notification_error_1.notificationBoxDoesNotExist)();
|
|
468
|
-
}
|
|
469
|
-
}
|
|
470
|
-
if (notificationBox) {
|
|
471
|
-
const { m } = notificationBox;
|
|
472
|
-
let r;
|
|
473
|
-
let targetRecipientIndex = notificationBox.r.findIndex(findRecipientFn);
|
|
474
|
-
const targetRecipient = notificationBox.r[targetRecipientIndex];
|
|
475
|
-
let nextRecipient;
|
|
476
|
-
if (remove) {
|
|
477
|
-
if (targetRecipientIndex != null) {
|
|
478
|
-
r = [...notificationBox.r]; // remove if they exist.
|
|
479
|
-
delete r[targetRecipientIndex];
|
|
480
|
-
}
|
|
481
|
-
}
|
|
482
|
-
else {
|
|
483
|
-
if (!targetRecipient && !insert) {
|
|
484
|
-
throw (0, notification_error_1.notificationBoxRecipientDoesNotExistsError)();
|
|
485
|
-
}
|
|
486
|
-
const c = (inputC != null ? (0, firebase_1.notificationBoxRecipientTemplateConfigArrayToRecord)(inputC) : targetRecipient?.c) ?? {};
|
|
487
|
-
nextRecipient = {
|
|
488
|
-
uid,
|
|
489
|
-
i: targetRecipient?.i ?? util_1.UNSET_INDEX_NUMBER,
|
|
490
|
-
c,
|
|
491
|
-
...(0, firebase_1.updateNotificationRecipient)(targetRecipient ?? {}, params)
|
|
492
|
-
};
|
|
493
|
-
r = [...notificationBox.r];
|
|
494
|
-
if (targetRecipient) {
|
|
495
|
-
nextRecipient.i = targetRecipient.i;
|
|
496
|
-
nextRecipient = (0, firebase_1.mergeNotificationBoxRecipients)(targetRecipient, nextRecipient);
|
|
497
|
-
r[targetRecipientIndex] = nextRecipient; // override in the array
|
|
498
|
-
}
|
|
499
|
-
else {
|
|
500
|
-
const nextI = (0, util_1.computeNextFreeIndexOnSortedValuesFunction)(util_1.readIndexNumber)(notificationBox.r); // r is sorted by index in ascending order, so the last value is the largest i
|
|
501
|
-
nextRecipient.i = nextI;
|
|
502
|
-
// should have the greatest i value, push to end
|
|
503
|
-
r.push(nextRecipient);
|
|
504
|
-
targetRecipientIndex = r.length - 1;
|
|
505
|
-
}
|
|
506
|
-
}
|
|
507
|
-
// save changes to r if it has changed
|
|
508
|
-
if (r != null) {
|
|
509
|
-
const notificationUserId = targetRecipient?.uid ?? nextRecipient?.uid;
|
|
510
|
-
// sync with the notification user's document, if it exists
|
|
511
|
-
if (notificationUserId != null) {
|
|
512
|
-
const notificationBoxId = notificationBoxDocument.id;
|
|
513
|
-
const notificationUserDocument = await notificationUserCollection.documentAccessorForTransaction(transaction).loadDocumentForId(notificationUserId);
|
|
514
|
-
let notificationUser = await notificationUserDocument.snapshotData();
|
|
515
|
-
const createNotificationUser = !notificationUser && !remove && insert;
|
|
516
|
-
if (createNotificationUser) {
|
|
517
|
-
// assert they exist in the auth system
|
|
518
|
-
const userContext = authService.userContext(notificationUserId);
|
|
519
|
-
const userExistsInAuth = await userContext.exists();
|
|
520
|
-
if (!userExistsInAuth) {
|
|
521
|
-
throw (0, notification_error_1.notificationUserInvalidUidForCreateError)(notificationUserId);
|
|
522
|
-
}
|
|
523
|
-
const notificationUserTemplate = {
|
|
524
|
-
uid: notificationUserId,
|
|
525
|
-
b: [],
|
|
526
|
-
x: [],
|
|
527
|
-
bc: [],
|
|
528
|
-
ns: false,
|
|
529
|
-
dc: {
|
|
530
|
-
c: {}
|
|
531
|
-
},
|
|
532
|
-
gc: {
|
|
533
|
-
c: {}
|
|
534
|
-
}
|
|
535
|
-
};
|
|
536
|
-
notificationUser = notificationUserTemplate;
|
|
537
|
-
}
|
|
538
|
-
// if the user is being inserted or exists, then make updates
|
|
539
|
-
if (notificationUser != null) {
|
|
540
|
-
const { updatedBc, updatedNotificationBoxRecipient } = (0, notification_util_1.updateNotificationUserNotificationBoxRecipientConfig)({
|
|
541
|
-
notificationBoxId,
|
|
542
|
-
notificationUserId,
|
|
543
|
-
notificationBoxAssociatedModelKey: m,
|
|
544
|
-
notificationUser,
|
|
545
|
-
insertingRecipientIntoNotificationBox: insert,
|
|
546
|
-
removeRecipientFromNotificationBox: remove,
|
|
547
|
-
notificationBoxRecipient: nextRecipient
|
|
548
|
-
});
|
|
549
|
-
const updatedB = updatedBc ? updatedBc.map((x) => x.nb) : undefined;
|
|
550
|
-
if (createNotificationUser) {
|
|
551
|
-
const newUserTemplate = {
|
|
552
|
-
...notificationUser,
|
|
553
|
-
bc: updatedBc ?? [],
|
|
554
|
-
b: updatedB ?? []
|
|
555
|
-
};
|
|
556
|
-
await notificationUserDocument.create(newUserTemplate);
|
|
557
|
-
}
|
|
558
|
-
else if (updatedBc != null) {
|
|
559
|
-
await notificationUserDocument.update({ bc: updatedBc, b: updatedB });
|
|
560
|
-
}
|
|
561
|
-
// Set if nextRecipient is updated/influence from existing configuration
|
|
562
|
-
if (targetRecipientIndex != null && updatedNotificationBoxRecipient && !remove) {
|
|
563
|
-
r[targetRecipientIndex] = updatedNotificationBoxRecipient; // set the updated value in r
|
|
564
|
-
}
|
|
565
|
-
}
|
|
566
|
-
// else, if removing and they don't exist, nothing to update
|
|
567
|
-
}
|
|
568
|
-
const updatedNotificationBox = { ...notificationBox, r };
|
|
569
|
-
let notificationBoxWasCreated = false;
|
|
570
|
-
if (createNotificationBox) {
|
|
571
|
-
await notificationBoxDocument.create(updatedNotificationBox);
|
|
572
|
-
notificationBoxWasCreated = true;
|
|
573
|
-
}
|
|
574
|
-
else {
|
|
575
|
-
await notificationBoxDocument.update({ r });
|
|
576
|
-
}
|
|
577
|
-
result = {
|
|
578
|
-
updatedNotificationBox,
|
|
579
|
-
notificationBoxWasCreated,
|
|
580
|
-
notificationBoxDocument
|
|
581
|
-
};
|
|
582
|
-
}
|
|
583
|
-
}
|
|
584
|
-
return result;
|
|
585
|
-
};
|
|
586
|
-
}
|
|
587
|
-
function updateNotificationBoxRecipientFactory(context) {
|
|
588
|
-
const { firestoreContext, firebaseServerActionTransformFunctionFactory } = context;
|
|
589
|
-
const updateNotificationBoxRecipientInTransaction = updateNotificationBoxRecipientInTransactionFactory(context);
|
|
590
|
-
const updateNotificationBoxRecipientExclusionInTransaction = updateNotificationBoxRecipientExclusionInTransactionFactory(context);
|
|
591
|
-
return firebaseServerActionTransformFunctionFactory(firebase_1.UpdateNotificationBoxRecipientParams, async (params) => {
|
|
592
|
-
return async (notificationBoxDocument) => {
|
|
593
|
-
await firestoreContext.runTransaction(async (transaction) => {
|
|
594
|
-
if (params.setExclusion != null) {
|
|
595
|
-
await updateNotificationBoxRecipientExclusionInTransaction({
|
|
596
|
-
params,
|
|
597
|
-
notificationBoxDocument
|
|
598
|
-
}, transaction);
|
|
599
|
-
}
|
|
600
|
-
else {
|
|
601
|
-
await updateNotificationBoxRecipientInTransaction({
|
|
602
|
-
params,
|
|
603
|
-
throwErrorIfNotificationBoxDoesNotExist: true,
|
|
604
|
-
notificationBoxDocument
|
|
605
|
-
}, transaction);
|
|
606
|
-
}
|
|
607
|
-
});
|
|
608
|
-
return notificationBoxDocument;
|
|
609
|
-
};
|
|
610
|
-
});
|
|
611
|
-
}
|
|
612
|
-
exports.UNKNOWN_NOTIFICATION_TEMPLATE_TYPE_HOURS_DELAY = 8;
|
|
613
|
-
exports.UNKNOWN_NOTIFICATION_TEMPLATE_TYPE_DELETE_AFTER_RETRY_ATTEMPTS = 1;
|
|
614
|
-
exports.UNKNOWN_NOTIFICATION_TASK_TYPE_HOURS_DELAY = 8;
|
|
615
|
-
exports.UNKNOWN_NOTIFICATION_TASK_TYPE_DELETE_AFTER_RETRY_ATTEMPTS = 1;
|
|
616
|
-
exports.KNOWN_BUT_UNCONFIGURED_NOTIFICATION_TEMPLATE_TYPE_HOURS_DELAY = exports.UNKNOWN_NOTIFICATION_TEMPLATE_TYPE_HOURS_DELAY;
|
|
617
|
-
exports.KNOWN_BUT_UNCONFIGURED_NOTIFICATION_TEMPLATE_TYPE_DELETE_AFTER_RETRY_ATTEMPTS = 5;
|
|
618
|
-
exports.NOTIFICATION_MAX_SEND_ATTEMPTS = 5;
|
|
619
|
-
exports.NOTIFICATION_BOX_NOT_INITIALIZED_DELAY_MINUTES = 8;
|
|
620
|
-
/**
|
|
621
|
-
* Minimum time in minutes that a notification task can be attempted again
|
|
622
|
-
*/
|
|
623
|
-
exports.NOTIFICATION_TASK_MINIMUM_SET_AT_THROTTLE_TIME_MINUTES = 1;
|
|
624
|
-
exports.NOTIFICATION_TASK_TYPE_MAX_SEND_ATTEMPTS = 5;
|
|
625
|
-
exports.NOTIFICATION_TASK_TYPE_FAILURE_DELAY_HOURS = 3;
|
|
626
|
-
exports.NOTIFICATION_TASK_TYPE_FAILURE_DELAY_MS = (0, date_fns_1.hoursToMilliseconds)(exports.NOTIFICATION_TASK_TYPE_FAILURE_DELAY_HOURS);
|
|
627
|
-
function sendNotificationFactory(context) {
|
|
628
|
-
const { appNotificationTemplateTypeInfoRecordService, notificationSendService, notificationTaskService, notificationTemplateService, authService, notificationBoxCollection, notificationCollectionGroup, notificationUserCollection, firestoreContext, firebaseServerActionTransformFunctionFactory } = context;
|
|
629
|
-
const createNotificationBoxInTransaction = createNotificationBoxInTransactionFactory(context);
|
|
630
|
-
const notificationUserAccessor = notificationUserCollection.documentAccessor();
|
|
631
|
-
return firebaseServerActionTransformFunctionFactory(firebase_1.SendNotificationParams, async (params) => {
|
|
632
|
-
const { ignoreSendAtThrottle } = params;
|
|
633
|
-
return async (inputNotificationDocument) => {
|
|
634
|
-
const now = new Date();
|
|
635
|
-
// Load the notification document outside of any potential context (transaction, etc.)
|
|
636
|
-
const notificationDocument = notificationCollectionGroup.documentAccessor().loadDocumentFrom(inputNotificationDocument);
|
|
637
|
-
const { nextSat, throttled, tryRun, isNotificationTask, notificationTaskHandler, notification, createdBox, notificationBoxNeedsInitialization, notificationBox, notificationBoxModelKey, deletedNotification, templateInstance, isConfiguredTemplateType, isKnownTemplateType, onlySendToExplicitlyEnabledRecipients, onlyTextExplicitlyEnabledRecipients } = await firestoreContext.runTransaction(async (transaction) => {
|
|
638
|
-
const notificationBoxDocument = notificationBoxCollection.documentAccessorForTransaction(transaction).loadDocument(notificationDocument.parent);
|
|
639
|
-
const notificationDocumentInTransaction = notificationCollectionGroup.documentAccessorForTransaction(transaction).loadDocumentFrom(notificationDocument);
|
|
640
|
-
let [notificationBox, notification] = await Promise.all([(0, firebase_1.getDocumentSnapshotData)(notificationBoxDocument), (0, firebase_1.getDocumentSnapshotData)(notificationDocumentInTransaction)]);
|
|
641
|
-
const model = (0, firebase_1.inferKeyFromTwoWayFlatFirestoreModelKey)(notificationBoxDocument.id);
|
|
642
|
-
const isNotificationTask = notification?.st === firebase_1.NotificationSendType.TASK_NOTIFICATION;
|
|
643
|
-
let tryRun = true;
|
|
644
|
-
let throttled = false;
|
|
645
|
-
let nextSat;
|
|
646
|
-
if (!notification) {
|
|
647
|
-
tryRun = false;
|
|
648
|
-
}
|
|
649
|
-
else if (!ignoreSendAtThrottle) {
|
|
650
|
-
tryRun = !(0, date_fns_1.isFuture)(notification.sat);
|
|
651
|
-
if (!tryRun) {
|
|
652
|
-
throttled = true;
|
|
653
|
-
}
|
|
654
|
-
}
|
|
655
|
-
// always set nextSat if tryRun is true
|
|
656
|
-
if (tryRun) {
|
|
657
|
-
if (isNotificationTask) {
|
|
658
|
-
// can try to run the task again in 1 minute
|
|
659
|
-
nextSat = (0, date_fns_1.addMinutes)(now, exports.NOTIFICATION_TASK_MINIMUM_SET_AT_THROTTLE_TIME_MINUTES);
|
|
660
|
-
}
|
|
661
|
-
else {
|
|
662
|
-
// update the next send type of non-tasks to try being sent again in 10 minutes, if they fail
|
|
663
|
-
nextSat = (0, date_fns_1.addMinutes)(now, 10);
|
|
664
|
-
}
|
|
665
|
-
}
|
|
666
|
-
let createdBox = false;
|
|
667
|
-
let deletedNotification = false;
|
|
668
|
-
let notificationBoxNeedsInitialization = false;
|
|
669
|
-
let isKnownTemplateType;
|
|
670
|
-
let isConfiguredTemplateType;
|
|
671
|
-
let onlySendToExplicitlyEnabledRecipients;
|
|
672
|
-
let onlyTextExplicitlyEnabledRecipients;
|
|
673
|
-
let templateInstance;
|
|
674
|
-
let notificationTaskHandler;
|
|
675
|
-
async function deleteNotification() {
|
|
676
|
-
tryRun = false;
|
|
677
|
-
await notificationDocumentInTransaction.accessor.delete();
|
|
678
|
-
deletedNotification = true;
|
|
679
|
-
}
|
|
680
|
-
// create/init the notification box if necessary/configured.
|
|
681
|
-
if (notification && tryRun) {
|
|
682
|
-
// if we're still trying to run, check the template is ok. If not, cancel the run.
|
|
683
|
-
const { t // notification task/template type
|
|
684
|
-
} = notification.n;
|
|
685
|
-
if (isNotificationTask) {
|
|
686
|
-
notificationTaskHandler = notificationTaskService.taskHandlerForNotificationTaskType(t);
|
|
687
|
-
if (notificationTaskHandler) {
|
|
688
|
-
if (notification.a >= exports.NOTIFICATION_TASK_TYPE_MAX_SEND_ATTEMPTS) {
|
|
689
|
-
tryRun = false;
|
|
690
|
-
console.warn(`Configured notification task of type "${t}" has reached the delete threshhold after being attempted ${notification.a} times. Deleting notification task.`);
|
|
691
|
-
await deleteNotification();
|
|
692
|
-
}
|
|
693
|
-
}
|
|
694
|
-
else {
|
|
695
|
-
tryRun = false;
|
|
696
|
-
const delay = exports.UNKNOWN_NOTIFICATION_TASK_TYPE_HOURS_DELAY;
|
|
697
|
-
if (notification.a < exports.UNKNOWN_NOTIFICATION_TASK_TYPE_DELETE_AFTER_RETRY_ATTEMPTS) {
|
|
698
|
-
console.warn(`Notification task type of "${t}" was found in a Notification but has no handler. Action is being delayed by ${delay} hours.`);
|
|
699
|
-
nextSat = (0, date_fns_1.addHours)(now, delay);
|
|
700
|
-
}
|
|
701
|
-
else {
|
|
702
|
-
console.warn(`Notification task type of "${t}" was found in a Notification but has no handler. Action is being deleted.`);
|
|
703
|
-
// delete the notification
|
|
704
|
-
await deleteNotification();
|
|
705
|
-
}
|
|
706
|
-
}
|
|
707
|
-
}
|
|
708
|
-
else {
|
|
709
|
-
templateInstance = notificationTemplateService.templateInstanceForType(t);
|
|
710
|
-
isConfiguredTemplateType = templateInstance.isConfiguredType;
|
|
711
|
-
const templateTypeInfo = appNotificationTemplateTypeInfoRecordService.appNotificationTemplateTypeInfoRecord[t];
|
|
712
|
-
isKnownTemplateType = templateTypeInfo != null;
|
|
713
|
-
onlySendToExplicitlyEnabledRecipients = notification.ois ?? templateTypeInfo?.onlySendToExplicitlyEnabledRecipients;
|
|
714
|
-
onlyTextExplicitlyEnabledRecipients = notification.ots ?? templateTypeInfo?.onlyTextExplicitlyEnabledRecipients;
|
|
715
|
-
if (!isConfiguredTemplateType) {
|
|
716
|
-
// log the issue that an notification with an unconfigured type was queued
|
|
717
|
-
const retryAttempts = isKnownTemplateType ? exports.KNOWN_BUT_UNCONFIGURED_NOTIFICATION_TEMPLATE_TYPE_DELETE_AFTER_RETRY_ATTEMPTS : exports.UNKNOWN_NOTIFICATION_TEMPLATE_TYPE_DELETE_AFTER_RETRY_ATTEMPTS;
|
|
718
|
-
const delay = isKnownTemplateType ? exports.KNOWN_BUT_UNCONFIGURED_NOTIFICATION_TEMPLATE_TYPE_HOURS_DELAY : exports.UNKNOWN_NOTIFICATION_TEMPLATE_TYPE_HOURS_DELAY;
|
|
719
|
-
if (notification.a < retryAttempts) {
|
|
720
|
-
if (isKnownTemplateType) {
|
|
721
|
-
console.warn(`Unconfigured but known template type of "${t}" (${templateTypeInfo.name}) was found in a Notification. Send is being delayed by ${delay} hours.`);
|
|
722
|
-
}
|
|
723
|
-
else {
|
|
724
|
-
console.warn(`Unknown template type of "${t}" was found in a Notification. Send is being delayed by ${delay} hours.`);
|
|
725
|
-
}
|
|
726
|
-
// delay send for 12 hours, for a max of 24 hours incase it is an issue.
|
|
727
|
-
nextSat = (0, date_fns_1.addHours)(now, delay);
|
|
728
|
-
tryRun = false;
|
|
729
|
-
}
|
|
730
|
-
else {
|
|
731
|
-
console.warn(`Unconfigured template type of "${t}" was found in a Notification. The Notification has reached the delete threshhold after failing to send due to misconfiguration multiple times and is being deleted.`);
|
|
732
|
-
// after attempting to send 3 times, delete it.
|
|
733
|
-
await deleteNotification();
|
|
734
|
-
}
|
|
735
|
-
}
|
|
736
|
-
// handle the notification box's absence
|
|
737
|
-
if (!notificationBox && tryRun) {
|
|
738
|
-
switch (notification.st) {
|
|
739
|
-
case firebase_1.NotificationSendType.INIT_BOX_AND_SEND:
|
|
740
|
-
const { notificationBoxTemplate } = await createNotificationBoxInTransaction({ notificationBoxDocument }, transaction);
|
|
741
|
-
notificationBox = (0, firebase_1.setIdAndKeyFromKeyIdRefOnDocumentData)(notificationBoxTemplate, notificationBoxDocument);
|
|
742
|
-
createdBox = true;
|
|
743
|
-
break;
|
|
744
|
-
case firebase_1.NotificationSendType.SEND_IF_BOX_EXISTS:
|
|
745
|
-
// delete the notification since it won't get sent.
|
|
746
|
-
await deleteNotification();
|
|
747
|
-
break;
|
|
748
|
-
case firebase_1.NotificationSendType.SEND_WITHOUT_CREATING_BOX:
|
|
749
|
-
// continue with current tryRun
|
|
750
|
-
break;
|
|
751
|
-
}
|
|
752
|
-
}
|
|
753
|
-
// if the notification box is not initialized/synchronized yet, do not run.
|
|
754
|
-
if (tryRun && notificationBox && notificationBox.s) {
|
|
755
|
-
notificationBoxNeedsInitialization = true;
|
|
756
|
-
tryRun = false;
|
|
757
|
-
nextSat = (0, date_fns_1.addMinutes)(now, exports.NOTIFICATION_BOX_NOT_INITIALIZED_DELAY_MINUTES);
|
|
758
|
-
}
|
|
759
|
-
}
|
|
760
|
-
}
|
|
761
|
-
// update the notification send at time and attempt count
|
|
762
|
-
if (notification != null && nextSat != null && !deletedNotification) {
|
|
763
|
-
const isAtMaxAttempts = notification.a >= exports.NOTIFICATION_MAX_SEND_ATTEMPTS;
|
|
764
|
-
if (isAtMaxAttempts && notificationBoxNeedsInitialization) {
|
|
765
|
-
await deleteNotification(); // just delete the notification if the box still hasn't been initialized successfully at this point.
|
|
766
|
-
}
|
|
767
|
-
// check if it was just deleted
|
|
768
|
-
if (!deletedNotification) {
|
|
769
|
-
const a = isNotificationTask && tryRun ? notification.a : notification.a + 1; // do not update a notification task's attempt count here, unless tryRun fails
|
|
770
|
-
// NOTE: It is important to update sat so the notification task queue running doesn't get stuck in a query loop by notifications/tasks that have a sat value that is in the past, but was just run.
|
|
771
|
-
await notificationDocumentInTransaction.update({ sat: nextSat, a });
|
|
772
|
-
}
|
|
773
|
-
}
|
|
774
|
-
return {
|
|
775
|
-
nextSat,
|
|
776
|
-
throttled,
|
|
777
|
-
isNotificationTask,
|
|
778
|
-
deletedNotification,
|
|
779
|
-
createdBox,
|
|
780
|
-
notificationBoxModelKey: model,
|
|
781
|
-
notificationBoxNeedsInitialization,
|
|
782
|
-
notificationBox,
|
|
783
|
-
notification,
|
|
784
|
-
templateInstance,
|
|
785
|
-
isKnownTemplateType,
|
|
786
|
-
notificationTaskHandler,
|
|
787
|
-
isConfiguredTemplateType,
|
|
788
|
-
tryRun,
|
|
789
|
-
onlySendToExplicitlyEnabledRecipients,
|
|
790
|
-
onlyTextExplicitlyEnabledRecipients
|
|
791
|
-
};
|
|
792
|
-
});
|
|
793
|
-
let success = false;
|
|
794
|
-
let isUniqueNotificationTask = false;
|
|
795
|
-
let uniqueNotificationTaskConflict = false;
|
|
796
|
-
let sendEmailsResult;
|
|
797
|
-
let sendTextsResult;
|
|
798
|
-
let sendNotificationSummaryResult;
|
|
799
|
-
let loadMessageFunctionFailure = false;
|
|
800
|
-
let buildMessageFailure = false;
|
|
801
|
-
let notificationMarkedDone = false;
|
|
802
|
-
let notificationTaskCompletionType;
|
|
803
|
-
let notificationTaskPartsRunCount = 0;
|
|
804
|
-
let notificationTaskLoopingProtectionTriggered;
|
|
805
|
-
let onSendAttemptedResult;
|
|
806
|
-
let onSendSuccessResult;
|
|
807
|
-
const notificationTemplateType = templateInstance?.type;
|
|
808
|
-
if (isNotificationTask) {
|
|
809
|
-
await handleNotificationTask();
|
|
810
|
-
}
|
|
811
|
-
else {
|
|
812
|
-
await handleNormalNotification();
|
|
813
|
-
}
|
|
814
|
-
async function _runNotificationTaskNextPart(input) {
|
|
815
|
-
const { notification, notificationTaskHandler, previouslyCompleteSubTasks } = input;
|
|
816
|
-
const { n: item, cat, ut } = notification;
|
|
817
|
-
let tryRunNextPart = false;
|
|
818
|
-
let partNotificationTaskCompletionType;
|
|
819
|
-
let partNotificationMarkedDone = false;
|
|
820
|
-
let partTprReversal = false;
|
|
821
|
-
let partSuccess = false;
|
|
822
|
-
let nextCompleteSubTasks;
|
|
823
|
-
const unique = ut ?? false;
|
|
824
|
-
const notificationTask = {
|
|
825
|
-
notificationDocument,
|
|
826
|
-
totalSendAttempts: notification.a,
|
|
827
|
-
currentCheckpointSendAttempts: notification.at ?? 0,
|
|
828
|
-
taskType: item.t,
|
|
829
|
-
item,
|
|
830
|
-
data: item.d,
|
|
831
|
-
checkpoints: notification.tpr,
|
|
832
|
-
createdAt: cat,
|
|
833
|
-
unique
|
|
834
|
-
};
|
|
835
|
-
// calculate results
|
|
836
|
-
const notificationTemplate = {};
|
|
837
|
-
// perform the task
|
|
838
|
-
try {
|
|
839
|
-
const handleTaskResult = await notificationTaskHandler.handleNotificationTask(notificationTask);
|
|
840
|
-
const { completion, updateMetadata, delayUntil, canRunNextCheckpoint, allCompletedSubTasks } = handleTaskResult;
|
|
841
|
-
partNotificationTaskCompletionType = completion;
|
|
842
|
-
partSuccess = true;
|
|
843
|
-
switch (completion) {
|
|
844
|
-
case true:
|
|
845
|
-
notificationTemplate.d = true; // mark as done
|
|
846
|
-
break;
|
|
847
|
-
case false:
|
|
848
|
-
// failed
|
|
849
|
-
notificationTemplate.a = notification.a + 1; // increase attempts count
|
|
850
|
-
notificationTemplate.at = (notification.at ?? 0) + 1; // increase checkpoint attempts count
|
|
851
|
-
// remove any completions, if applicable
|
|
852
|
-
notificationTemplate.tpr = (0, notification_task_service_util_1.removeFromCompletionsArrayWithTaskResult)(notification.tpr, handleTaskResult);
|
|
853
|
-
partSuccess = false;
|
|
854
|
-
break;
|
|
855
|
-
default:
|
|
856
|
-
// default case called if not true or false, which implies either a delay or partial completion
|
|
857
|
-
// update the checkpoint attempts count
|
|
858
|
-
if (Array.isArray(completion) && completion.length === 0) {
|
|
859
|
-
notificationTemplate.at = (notification.at ?? 0) + 1; // increase checkpoint attempt/delays count
|
|
860
|
-
tryRunNextPart = canRunNextCheckpoint === true && allCompletedSubTasks != null && delayUntil == null; // can only run the next part if subtasks were returned and there is no delay
|
|
861
|
-
}
|
|
862
|
-
else {
|
|
863
|
-
tryRunNextPart = canRunNextCheckpoint === true && delayUntil == null; // can try the next part if there is no delayUntil and canRunNextCheckpoint is true
|
|
864
|
-
notificationTemplate.at = 0; // reset checkpoint attempt/delay count
|
|
865
|
-
}
|
|
866
|
-
// add the checkpoint to the notification
|
|
867
|
-
notificationTemplate.tpr = [
|
|
868
|
-
...(0, notification_task_service_util_1.removeFromCompletionsArrayWithTaskResult)(notification.tpr, handleTaskResult), // remove any completions, if applicable
|
|
869
|
-
...(0, util_1.asArray)(completion)
|
|
870
|
-
];
|
|
871
|
-
// calculate the updated notification item
|
|
872
|
-
notificationTemplate.n = {
|
|
873
|
-
...notification.n,
|
|
874
|
-
d: {
|
|
875
|
-
...notification.n.d,
|
|
876
|
-
...(updateMetadata ? (0, util_1.filterOnlyUndefinedValues)(updateMetadata) : undefined) // ignore any undefined values
|
|
877
|
-
}
|
|
878
|
-
};
|
|
879
|
-
// can only run the next part if the tpr has changed, and the number of checkpoints completed has increased
|
|
880
|
-
// if the tpr has not changed, then it is also considered a reversal
|
|
881
|
-
if (tryRunNextPart) {
|
|
882
|
-
const tprChanged = !(0, util_1.iterablesAreSetEquivalent)(notification.tpr, notificationTemplate.tpr);
|
|
883
|
-
partTprReversal = !tprChanged || (tprChanged && notificationTemplate.tpr.length <= notification.tpr.length);
|
|
884
|
-
if (allCompletedSubTasks != null) {
|
|
885
|
-
switch (allCompletedSubTasks) {
|
|
886
|
-
case true:
|
|
887
|
-
case false:
|
|
888
|
-
// only run if there is no tpr reversal flagged
|
|
889
|
-
tryRunNextPart = !partTprReversal;
|
|
890
|
-
break;
|
|
891
|
-
default:
|
|
892
|
-
// check subtask tpr changes
|
|
893
|
-
nextCompleteSubTasks = (0, util_1.asArray)(allCompletedSubTasks);
|
|
894
|
-
const subtaskTprChanged = !(0, util_1.iterablesAreSetEquivalent)(previouslyCompleteSubTasks, nextCompleteSubTasks);
|
|
895
|
-
partTprReversal = !subtaskTprChanged || (subtaskTprChanged && nextCompleteSubTasks.length <= previouslyCompleteSubTasks.length);
|
|
896
|
-
break;
|
|
897
|
-
}
|
|
898
|
-
}
|
|
899
|
-
}
|
|
900
|
-
break;
|
|
901
|
-
}
|
|
902
|
-
// do not update sat if the task is complete
|
|
903
|
-
if (completion !== true && delayUntil != null) {
|
|
904
|
-
// must be at least 20 seconds into the future from now, and/or the nextSat time to avoid parallel runs
|
|
905
|
-
const minimumNextSatTime = (0, date_fns_1.addSeconds)(new Date(), 20);
|
|
906
|
-
notificationTemplate.sat = (0, date_1.findMaxDate)([(0, util_1.dateOrMillisecondsToDate)(delayUntil, now), nextSat, minimumNextSatTime]) ?? minimumNextSatTime;
|
|
907
|
-
}
|
|
908
|
-
partNotificationMarkedDone = notificationTemplate.d === true;
|
|
909
|
-
}
|
|
910
|
-
catch (e) {
|
|
911
|
-
console.error(`Failed handling task for notification "${notification.key}" with type "${notificationTask.taskType}": `, e);
|
|
912
|
-
notificationTemplate.a = notification.a + 1; // increase attempts count
|
|
913
|
-
notificationTemplate.sat = (0, util_1.dateOrMillisecondsToDate)(exports.NOTIFICATION_TASK_TYPE_FAILURE_DELAY_MS, now);
|
|
914
|
-
partSuccess = false;
|
|
915
|
-
}
|
|
916
|
-
// notification tasks are read
|
|
917
|
-
let saveTaskResult = true;
|
|
918
|
-
if (unique) {
|
|
919
|
-
isUniqueNotificationTask = true;
|
|
920
|
-
const latestNotification = await notificationDocument.snapshotData();
|
|
921
|
-
if (!latestNotification || !(0, date_1.isSameDate)(latestNotification.cat, notification.cat)) {
|
|
922
|
-
saveTaskResult = false;
|
|
923
|
-
uniqueNotificationTaskConflict = true;
|
|
924
|
-
}
|
|
925
|
-
}
|
|
926
|
-
if (saveTaskResult) {
|
|
927
|
-
await notificationDocument.update(notificationTemplate);
|
|
928
|
-
}
|
|
929
|
-
return {
|
|
930
|
-
tryRunNextPart,
|
|
931
|
-
partNotificationMarkedDone,
|
|
932
|
-
partNotificationTaskCompletionType,
|
|
933
|
-
partTprReversal,
|
|
934
|
-
nextCompleteSubTasks,
|
|
935
|
-
partSuccess
|
|
936
|
-
};
|
|
937
|
-
}
|
|
938
|
-
/**
|
|
939
|
-
* Notification task handling.
|
|
940
|
-
*
|
|
941
|
-
* Notification takss can have multiple async but sequential parts.
|
|
942
|
-
*
|
|
943
|
-
* Some of these parts may be able to be run immediately one after the other, instead of waiting for
|
|
944
|
-
* another sendNotification() to complete on it.
|
|
945
|
-
*/
|
|
946
|
-
async function handleNotificationTask() {
|
|
947
|
-
const MAX_NOTIFICATION_TASK_PARTS_RUN_ALLOWED = 5;
|
|
948
|
-
if (tryRun && notification != null && notificationTaskHandler) {
|
|
949
|
-
let currentNotification = notification;
|
|
950
|
-
let previouslyCompleteSubTasks = [];
|
|
951
|
-
notificationTaskLoopingProtectionTriggered = false;
|
|
952
|
-
notificationTaskPartsRunCount = 0;
|
|
953
|
-
while (notificationTaskPartsRunCount < MAX_NOTIFICATION_TASK_PARTS_RUN_ALLOWED) {
|
|
954
|
-
notificationTaskPartsRunCount += 1;
|
|
955
|
-
const result = await _runNotificationTaskNextPart({
|
|
956
|
-
notification: currentNotification,
|
|
957
|
-
notificationTaskHandler,
|
|
958
|
-
previouslyCompleteSubTasks
|
|
959
|
-
});
|
|
960
|
-
notificationTaskCompletionType = result.partNotificationTaskCompletionType;
|
|
961
|
-
previouslyCompleteSubTasks = result.nextCompleteSubTasks ?? [];
|
|
962
|
-
success = result.partSuccess;
|
|
963
|
-
const tryRunNextPart = result.partSuccess && result.tryRunNextPart && !notificationTaskLoopingProtectionTriggered;
|
|
964
|
-
notificationTaskLoopingProtectionTriggered = notificationTaskLoopingProtectionTriggered || result.partTprReversal; // update the flag if the TPR has been reversed
|
|
965
|
-
if (tryRunNextPart) {
|
|
966
|
-
const updatedNotificationData = await notificationDocument.snapshotData();
|
|
967
|
-
if (updatedNotificationData) {
|
|
968
|
-
currentNotification = (0, firebase_1.setIdAndKeyFromKeyIdRefOnDocumentData)(updatedNotificationData, notificationDocument);
|
|
969
|
-
}
|
|
970
|
-
else {
|
|
971
|
-
break; // notification is unavailable now
|
|
972
|
-
}
|
|
973
|
-
}
|
|
974
|
-
else {
|
|
975
|
-
break; // escape the loop
|
|
976
|
-
}
|
|
977
|
-
}
|
|
978
|
-
}
|
|
979
|
-
}
|
|
980
|
-
/**
|
|
981
|
-
* Handles a normal (non-task) notification.
|
|
982
|
-
*/
|
|
983
|
-
async function handleNormalNotification() {
|
|
984
|
-
// notification is only null/undefined if it didn't exist.
|
|
985
|
-
if (notification != null) {
|
|
986
|
-
if (tryRun && templateInstance != null) {
|
|
987
|
-
// first load the message function
|
|
988
|
-
const messageFunction = await templateInstance
|
|
989
|
-
.loadMessageFunction({
|
|
990
|
-
item: notification.n,
|
|
991
|
-
notification,
|
|
992
|
-
notificationBox: {
|
|
993
|
-
m: notificationBoxModelKey
|
|
994
|
-
}
|
|
995
|
-
})
|
|
996
|
-
.catch((e) => {
|
|
997
|
-
loadMessageFunctionFailure = true;
|
|
998
|
-
success = false;
|
|
999
|
-
console.error(`Failed loading message function for type ${notificationTemplateType}: `, e);
|
|
1000
|
-
return undefined;
|
|
1001
|
-
});
|
|
1002
|
-
if (messageFunction) {
|
|
1003
|
-
function filterOutNoContentNotificationMessages(messages) {
|
|
1004
|
-
return messages.filter((x) => !x.flag);
|
|
1005
|
-
}
|
|
1006
|
-
// expand recipients
|
|
1007
|
-
const { emails: emailRecipients, texts: textRecipients, notificationSummaries: notificationSummaryRecipients } = await (0, notification_util_1.expandNotificationRecipients)({
|
|
1008
|
-
notification,
|
|
1009
|
-
notificationBox,
|
|
1010
|
-
authService,
|
|
1011
|
-
notificationUserAccessor,
|
|
1012
|
-
globalRecipients: messageFunction.globalRecipients,
|
|
1013
|
-
onlySendToExplicitlyEnabledRecipients,
|
|
1014
|
-
onlyTextExplicitlyEnabledRecipients,
|
|
1015
|
-
notificationSummaryIdForUid: notificationSendService.notificationSummaryIdForUidFunction
|
|
1016
|
-
});
|
|
1017
|
-
let { es, ts, ps, ns, esr: currentEsr, tsr: currentTsr } = notification;
|
|
1018
|
-
// do emails
|
|
1019
|
-
let esr;
|
|
1020
|
-
if (es === firebase_1.NotificationSendState.QUEUED || es === firebase_1.NotificationSendState.SENT_PARTIAL) {
|
|
1021
|
-
const emailRecipientsAlreadySentTo = new Set(currentEsr.map((x) => x.toLowerCase()));
|
|
1022
|
-
const emailInputContexts = emailRecipients
|
|
1023
|
-
.filter((x) => !emailRecipientsAlreadySentTo.has(x.emailAddress.toLowerCase()))
|
|
1024
|
-
.map((x) => {
|
|
1025
|
-
const context = {
|
|
1026
|
-
recipient: {
|
|
1027
|
-
n: x.name,
|
|
1028
|
-
e: x.emailAddress,
|
|
1029
|
-
t: x.phoneNumber
|
|
1030
|
-
}
|
|
1031
|
-
};
|
|
1032
|
-
return context;
|
|
1033
|
-
});
|
|
1034
|
-
const emailMessages = await Promise.all(emailInputContexts.map(messageFunction))
|
|
1035
|
-
.then(filterOutNoContentNotificationMessages)
|
|
1036
|
-
.catch((e) => {
|
|
1037
|
-
console.error(`Failed building message function for type ${notificationTemplateType}: `, e);
|
|
1038
|
-
buildMessageFailure = true;
|
|
1039
|
-
return undefined;
|
|
1040
|
-
});
|
|
1041
|
-
if (emailMessages?.length) {
|
|
1042
|
-
if (notificationSendService.emailSendService != null) {
|
|
1043
|
-
let sendInstance;
|
|
1044
|
-
try {
|
|
1045
|
-
sendInstance = await notificationSendService.emailSendService.buildSendInstanceForEmailNotificationMessages(emailMessages);
|
|
1046
|
-
}
|
|
1047
|
-
catch (e) {
|
|
1048
|
-
console.error(`Failed building email send instance for notification "${notification.id}" with type "${notificationTemplateType}": `, e);
|
|
1049
|
-
es = firebase_1.NotificationSendState.CONFIG_ERROR;
|
|
1050
|
-
}
|
|
1051
|
-
if (sendInstance) {
|
|
1052
|
-
try {
|
|
1053
|
-
sendEmailsResult = await sendInstance();
|
|
1054
|
-
}
|
|
1055
|
-
catch (e) {
|
|
1056
|
-
console.error(`Failed sending email notification "${notification.id}" with type "${notificationTemplateType}": `, e);
|
|
1057
|
-
es = firebase_1.NotificationSendState.SEND_ERROR;
|
|
1058
|
-
}
|
|
1059
|
-
}
|
|
1060
|
-
}
|
|
1061
|
-
else {
|
|
1062
|
-
console.error(`Failed sending email notification "${notification.id}" with type "${notificationTemplateType}" due to no email service being configured.`);
|
|
1063
|
-
es = firebase_1.NotificationSendState.CONFIG_ERROR;
|
|
1064
|
-
}
|
|
1065
|
-
if (sendEmailsResult != null) {
|
|
1066
|
-
const { success, failed } = sendEmailsResult;
|
|
1067
|
-
esr = success.length ? currentEsr.concat(success.map((x) => x.toLowerCase())) : undefined;
|
|
1068
|
-
if (failed.length > 0) {
|
|
1069
|
-
es = firebase_1.NotificationSendState.SENT_PARTIAL;
|
|
1070
|
-
}
|
|
1071
|
-
else {
|
|
1072
|
-
es = firebase_1.NotificationSendState.SENT;
|
|
1073
|
-
}
|
|
1074
|
-
}
|
|
1075
|
-
}
|
|
1076
|
-
else {
|
|
1077
|
-
es = firebase_1.NotificationSendState.SENT;
|
|
1078
|
-
}
|
|
1079
|
-
}
|
|
1080
|
-
// do phone numbers
|
|
1081
|
-
let tsr;
|
|
1082
|
-
if (ts === firebase_1.NotificationSendState.QUEUED || ts === firebase_1.NotificationSendState.SENT_PARTIAL) {
|
|
1083
|
-
const textRecipientsAlreadySentTo = new Set(currentTsr);
|
|
1084
|
-
const textInputContexts = textRecipients
|
|
1085
|
-
.filter((x) => !textRecipientsAlreadySentTo.has(x.phoneNumber))
|
|
1086
|
-
.map((x) => {
|
|
1087
|
-
const context = {
|
|
1088
|
-
recipient: {
|
|
1089
|
-
n: x.name,
|
|
1090
|
-
e: x.emailAddress,
|
|
1091
|
-
t: x.phoneNumber
|
|
1092
|
-
}
|
|
1093
|
-
};
|
|
1094
|
-
return context;
|
|
1095
|
-
});
|
|
1096
|
-
const textMessages = await Promise.all(textInputContexts.map(messageFunction))
|
|
1097
|
-
.then(filterOutNoContentNotificationMessages)
|
|
1098
|
-
.catch((e) => {
|
|
1099
|
-
console.error(`Failed building message function for type ${notificationTemplateType}: `, e);
|
|
1100
|
-
buildMessageFailure = true;
|
|
1101
|
-
return undefined;
|
|
1102
|
-
});
|
|
1103
|
-
if (textMessages?.length) {
|
|
1104
|
-
if (notificationSendService.textSendService != null) {
|
|
1105
|
-
let sendInstance;
|
|
1106
|
-
try {
|
|
1107
|
-
sendInstance = await notificationSendService.textSendService.buildSendInstanceForTextNotificationMessages(textMessages);
|
|
1108
|
-
}
|
|
1109
|
-
catch (e) {
|
|
1110
|
-
console.error(`Failed building text send instance for notification "${notification.id}" with type "${notificationTemplateType}": `, e);
|
|
1111
|
-
ts = firebase_1.NotificationSendState.CONFIG_ERROR;
|
|
1112
|
-
}
|
|
1113
|
-
if (sendInstance) {
|
|
1114
|
-
try {
|
|
1115
|
-
sendTextsResult = await sendInstance();
|
|
1116
|
-
}
|
|
1117
|
-
catch (e) {
|
|
1118
|
-
console.error(`Failed sending text notification "${notification.id}" with type "${notificationTemplateType}": `, e);
|
|
1119
|
-
ts = firebase_1.NotificationSendState.SEND_ERROR;
|
|
1120
|
-
}
|
|
1121
|
-
}
|
|
1122
|
-
}
|
|
1123
|
-
else {
|
|
1124
|
-
console.error(`Failed sending text notification "${notification.id}" with type "${notificationTemplateType}" due to no text service being configured.`);
|
|
1125
|
-
ts = firebase_1.NotificationSendState.CONFIG_ERROR;
|
|
1126
|
-
}
|
|
1127
|
-
if (sendTextsResult != null) {
|
|
1128
|
-
const { success, failed } = sendTextsResult;
|
|
1129
|
-
tsr = success.length ? currentTsr.concat(success) : undefined;
|
|
1130
|
-
if (failed.length > 0) {
|
|
1131
|
-
ts = firebase_1.NotificationSendState.SENT_PARTIAL;
|
|
1132
|
-
}
|
|
1133
|
-
else {
|
|
1134
|
-
ts = firebase_1.NotificationSendState.SENT;
|
|
1135
|
-
}
|
|
1136
|
-
}
|
|
1137
|
-
}
|
|
1138
|
-
else {
|
|
1139
|
-
ts = firebase_1.NotificationSendState.SENT;
|
|
1140
|
-
}
|
|
1141
|
-
}
|
|
1142
|
-
ps = firebase_1.NotificationSendState.NO_TRY;
|
|
1143
|
-
// NOTE: FCM token management will probably done with a separate system within Notification that stores FCMs for specific users in the app. May also use UIDs to determine who got the push notificdation or not...
|
|
1144
|
-
// do notification summaries
|
|
1145
|
-
if (ns === firebase_1.NotificationSendState.QUEUED || ns === firebase_1.NotificationSendState.SENT_PARTIAL) {
|
|
1146
|
-
const notificationSummaryInputContexts = notificationSummaryRecipients.map((x) => {
|
|
1147
|
-
const context = {
|
|
1148
|
-
recipient: {
|
|
1149
|
-
n: x.name,
|
|
1150
|
-
s: x.notificationSummaryId
|
|
1151
|
-
}
|
|
1152
|
-
};
|
|
1153
|
-
return context;
|
|
1154
|
-
});
|
|
1155
|
-
const notificationSummaryMessages = await Promise.all(notificationSummaryInputContexts.map(messageFunction))
|
|
1156
|
-
.then(filterOutNoContentNotificationMessages)
|
|
1157
|
-
.catch((e) => {
|
|
1158
|
-
console.error(`Failed building message function for type ${notificationTemplateType}: `, e);
|
|
1159
|
-
buildMessageFailure = true;
|
|
1160
|
-
return undefined;
|
|
1161
|
-
});
|
|
1162
|
-
if (notificationSummaryMessages?.length) {
|
|
1163
|
-
if (notificationSendService.notificationSummarySendService != null) {
|
|
1164
|
-
let sendInstance;
|
|
1165
|
-
try {
|
|
1166
|
-
sendInstance = await notificationSendService.notificationSummarySendService.buildSendInstanceForNotificationSummaryMessages(notificationSummaryMessages);
|
|
1167
|
-
}
|
|
1168
|
-
catch (e) {
|
|
1169
|
-
console.error(`Failed building notification summary send instance for notification "${notification.id}" with type "${notificationTemplateType}": `, e);
|
|
1170
|
-
ns = firebase_1.NotificationSendState.CONFIG_ERROR;
|
|
1171
|
-
}
|
|
1172
|
-
if (sendInstance) {
|
|
1173
|
-
try {
|
|
1174
|
-
sendNotificationSummaryResult = await sendInstance();
|
|
1175
|
-
ns = firebase_1.NotificationSendState.SENT;
|
|
1176
|
-
}
|
|
1177
|
-
catch (e) {
|
|
1178
|
-
console.error(`Failed sending notification summary notification "${notification.id}" with type "${notificationTemplateType}": `, e);
|
|
1179
|
-
ns = firebase_1.NotificationSendState.SEND_ERROR;
|
|
1180
|
-
}
|
|
1181
|
-
}
|
|
1182
|
-
}
|
|
1183
|
-
else {
|
|
1184
|
-
console.error(`Failed sending notification summary notification "${notification.id}" with type "${notificationTemplateType}" due to no notification summary service being configured.`);
|
|
1185
|
-
ns = firebase_1.NotificationSendState.CONFIG_ERROR;
|
|
1186
|
-
}
|
|
1187
|
-
}
|
|
1188
|
-
else {
|
|
1189
|
-
ns = firebase_1.NotificationSendState.SENT;
|
|
1190
|
-
}
|
|
1191
|
-
}
|
|
1192
|
-
// calculate results
|
|
1193
|
-
const notificationTemplate = { es, ts, ps, ns, esr, tsr };
|
|
1194
|
-
success = (0, firebase_1.notificationSendFlagsImplyIsComplete)(notificationTemplate);
|
|
1195
|
-
if (success) {
|
|
1196
|
-
notificationTemplate.d = true;
|
|
1197
|
-
}
|
|
1198
|
-
else {
|
|
1199
|
-
notificationTemplate.a = notification.a + 1;
|
|
1200
|
-
if (notificationTemplate.a >= exports.NOTIFICATION_MAX_SEND_ATTEMPTS) {
|
|
1201
|
-
notificationTemplate.d = true;
|
|
1202
|
-
}
|
|
1203
|
-
}
|
|
1204
|
-
await notificationDocument.update(notificationTemplate);
|
|
1205
|
-
notificationMarkedDone = notificationTemplate.d === true;
|
|
1206
|
-
const callbackDetails = {
|
|
1207
|
-
success,
|
|
1208
|
-
updatedSendFlags: notificationTemplate,
|
|
1209
|
-
sendEmailsResult,
|
|
1210
|
-
sendTextsResult,
|
|
1211
|
-
sendNotificationSummaryResult
|
|
1212
|
-
};
|
|
1213
|
-
const { onSendAttempted, onSendSuccess } = messageFunction;
|
|
1214
|
-
// call onSendAttempted, if one is configured
|
|
1215
|
-
if (onSendAttempted) {
|
|
1216
|
-
onSendAttemptedResult = await (0, util_1.asPromise)(onSendAttempted(callbackDetails))
|
|
1217
|
-
.then((value) => {
|
|
1218
|
-
return { value };
|
|
1219
|
-
})
|
|
1220
|
-
.catch((e) => {
|
|
1221
|
-
console.warn(`Caught exception while calling onSendAttempted for notification "${notification.id}" with type "${notificationTemplateType}": `, e);
|
|
1222
|
-
return { error: e };
|
|
1223
|
-
});
|
|
1224
|
-
}
|
|
1225
|
-
// call onSendSuccess, if one is configured
|
|
1226
|
-
if (notificationMarkedDone && onSendSuccess) {
|
|
1227
|
-
onSendSuccessResult = await (0, util_1.asPromise)(onSendSuccess(callbackDetails))
|
|
1228
|
-
.then((value) => {
|
|
1229
|
-
return { value };
|
|
1230
|
-
})
|
|
1231
|
-
.catch((e) => {
|
|
1232
|
-
console.warn(`Caught exception while calling onSendSuccess for notification "${notification.id}" with type "${notificationTemplateType}": `, e);
|
|
1233
|
-
return { error: e };
|
|
1234
|
-
});
|
|
1235
|
-
}
|
|
1236
|
-
}
|
|
1237
|
-
}
|
|
1238
|
-
else {
|
|
1239
|
-
switch (notification.st) {
|
|
1240
|
-
case firebase_1.NotificationSendType.SEND_IF_BOX_EXISTS:
|
|
1241
|
-
// deleted successfully
|
|
1242
|
-
success = deletedNotification;
|
|
1243
|
-
break;
|
|
1244
|
-
}
|
|
1245
|
-
}
|
|
1246
|
-
}
|
|
1247
|
-
}
|
|
1248
|
-
const result = {
|
|
1249
|
-
notificationTemplateType,
|
|
1250
|
-
isKnownTemplateType,
|
|
1251
|
-
isNotificationTask,
|
|
1252
|
-
isUniqueNotificationTask,
|
|
1253
|
-
uniqueNotificationTaskConflict,
|
|
1254
|
-
isConfiguredTemplateType,
|
|
1255
|
-
throttled,
|
|
1256
|
-
exists: notification != null,
|
|
1257
|
-
boxExists: notificationBox != null,
|
|
1258
|
-
notificationTaskPartsRunCount,
|
|
1259
|
-
notificationTaskLoopingProtectionTriggered,
|
|
1260
|
-
notificationBoxNeedsInitialization,
|
|
1261
|
-
notificationTaskCompletionType,
|
|
1262
|
-
createdBox,
|
|
1263
|
-
deletedNotification,
|
|
1264
|
-
notificationMarkedDone,
|
|
1265
|
-
tryRun,
|
|
1266
|
-
success,
|
|
1267
|
-
sendEmailsResult,
|
|
1268
|
-
sendTextsResult,
|
|
1269
|
-
sendNotificationSummaryResult,
|
|
1270
|
-
loadMessageFunctionFailure,
|
|
1271
|
-
buildMessageFailure,
|
|
1272
|
-
onSendAttemptedResult,
|
|
1273
|
-
onSendSuccessResult
|
|
1274
|
-
};
|
|
1275
|
-
return result;
|
|
1276
|
-
};
|
|
1277
|
-
});
|
|
1278
|
-
}
|
|
1279
|
-
exports.SEND_QUEUE_NOTIFICATIONS_TASK_EXCESS_THRESHOLD = 5000;
|
|
1280
|
-
function sendQueuedNotificationsFactory(context) {
|
|
1281
|
-
const { firebaseServerActionTransformFunctionFactory, notificationCollectionGroup } = context;
|
|
1282
|
-
const sendNotification = sendNotificationFactory(context);
|
|
1283
|
-
return firebaseServerActionTransformFunctionFactory(firebase_1.SendQueuedNotificationsParams, async (params) => {
|
|
1284
|
-
const { maxSendNotificationLoops } = params;
|
|
1285
|
-
const maxLoops = maxSendNotificationLoops ?? Number.MAX_SAFE_INTEGER;
|
|
1286
|
-
const sendNotificationLoopsTaskExcessThreshold = params.sendNotificationLoopsTaskExcessThreshold ?? exports.SEND_QUEUE_NOTIFICATIONS_TASK_EXCESS_THRESHOLD;
|
|
1287
|
-
return async (input) => {
|
|
1288
|
-
const maxParallelTasks = input?.maxParellelSendTasks ?? params.maxParellelSendTasks ?? 5;
|
|
1289
|
-
const onSendNotificationResult = input?.onSendNotificationResult ?? (0, util_1.mapIdentityFunction)();
|
|
1290
|
-
let notificationLoopCount = 0;
|
|
1291
|
-
let notificationBoxesCreated = 0;
|
|
1292
|
-
let notificationsDeleted = 0;
|
|
1293
|
-
let notificationTasksVisited = 0;
|
|
1294
|
-
let notificationsVisited = 0;
|
|
1295
|
-
let notificationsSucceeded = 0;
|
|
1296
|
-
let notificationsDelayed = 0;
|
|
1297
|
-
let notificationsFailed = 0;
|
|
1298
|
-
let sendEmailsResult;
|
|
1299
|
-
let sendTextsResult;
|
|
1300
|
-
let sendNotificationSummaryResult;
|
|
1301
|
-
const sendNotificationParams = { key: (0, firebase_1.firestoreDummyKey)(), throwErrorIfSent: false };
|
|
1302
|
-
const sendNotificationInstance = await sendNotification(sendNotificationParams);
|
|
1303
|
-
let excessLoopsDetected = false;
|
|
1304
|
-
const sendQueuedNotifications = async () => {
|
|
1305
|
-
const query = notificationCollectionGroup.queryDocument((0, firebase_1.notificationsPastSendAtTimeQuery)());
|
|
1306
|
-
const notificationDocuments = await query.getDocs();
|
|
1307
|
-
const result = await (0, util_1.performAsyncTasks)(notificationDocuments, async (notificationDocument) => {
|
|
1308
|
-
const result = await sendNotificationInstance(notificationDocument);
|
|
1309
|
-
onSendNotificationResult(result, notificationDocument);
|
|
1310
|
-
return result;
|
|
1311
|
-
}, {
|
|
1312
|
-
maxParallelTasks
|
|
1313
|
-
});
|
|
1314
|
-
return result;
|
|
1315
|
-
};
|
|
1316
|
-
// iterate through all notification items that need to be synced
|
|
1317
|
-
// eslint-disable-next-line no-constant-condition
|
|
1318
|
-
while (notificationLoopCount < maxLoops) {
|
|
1319
|
-
const sendQueuedNotificationsResults = await sendQueuedNotifications();
|
|
1320
|
-
sendQueuedNotificationsResults.results.forEach((x) => {
|
|
1321
|
-
const result = x[1];
|
|
1322
|
-
if (result.success) {
|
|
1323
|
-
notificationsSucceeded += 1;
|
|
1324
|
-
}
|
|
1325
|
-
else if (result.createdBox || result.notificationBoxNeedsInitialization) {
|
|
1326
|
-
notificationsDelayed += 1;
|
|
1327
|
-
}
|
|
1328
|
-
else {
|
|
1329
|
-
notificationsFailed += 1;
|
|
1330
|
-
}
|
|
1331
|
-
if (result.isNotificationTask) {
|
|
1332
|
-
notificationTasksVisited += 1;
|
|
1333
|
-
}
|
|
1334
|
-
if (result.deletedNotification) {
|
|
1335
|
-
notificationsDeleted += 1;
|
|
1336
|
-
}
|
|
1337
|
-
if (result.createdBox) {
|
|
1338
|
-
notificationBoxesCreated += 1;
|
|
1339
|
-
}
|
|
1340
|
-
sendEmailsResult = (0, firebase_1.mergeNotificationSendMessagesResult)(sendEmailsResult, result.sendEmailsResult);
|
|
1341
|
-
sendTextsResult = (0, firebase_1.mergeNotificationSendMessagesResult)(sendTextsResult, result.sendTextsResult);
|
|
1342
|
-
sendNotificationSummaryResult = (0, firebase_1.mergeNotificationSendMessagesResult)(sendNotificationSummaryResult, result.sendNotificationSummaryResult);
|
|
1343
|
-
});
|
|
1344
|
-
const found = sendQueuedNotificationsResults.results.length;
|
|
1345
|
-
notificationsVisited += found;
|
|
1346
|
-
notificationLoopCount += 1;
|
|
1347
|
-
if (!found) {
|
|
1348
|
-
break;
|
|
1349
|
-
}
|
|
1350
|
-
else if (!excessLoopsDetected && notificationLoopCount > sendNotificationLoopsTaskExcessThreshold) {
|
|
1351
|
-
excessLoopsDetected = true;
|
|
1352
|
-
console.error(`sendQueuedNotifications(EXCESS_LOOPS_DETECTED): Exceeded send notification loops task excess threshold of ${sendNotificationLoopsTaskExcessThreshold}.`);
|
|
1353
|
-
// continue the loops
|
|
1354
|
-
}
|
|
1355
|
-
}
|
|
1356
|
-
const result = {
|
|
1357
|
-
excessLoopsDetected,
|
|
1358
|
-
notificationLoopCount,
|
|
1359
|
-
notificationBoxesCreated,
|
|
1360
|
-
notificationsDeleted,
|
|
1361
|
-
notificationTasksVisited,
|
|
1362
|
-
notificationsVisited,
|
|
1363
|
-
notificationsSucceeded,
|
|
1364
|
-
notificationsDelayed,
|
|
1365
|
-
notificationsFailed,
|
|
1366
|
-
sendEmailsResult,
|
|
1367
|
-
sendTextsResult,
|
|
1368
|
-
sendNotificationSummaryResult
|
|
1369
|
-
};
|
|
1370
|
-
return result;
|
|
1371
|
-
};
|
|
1372
|
-
});
|
|
1373
|
-
}
|
|
1374
|
-
function cleanupSentNotificationsFactory(context) {
|
|
1375
|
-
const { firestoreContext, firebaseServerActionTransformFunctionFactory, notificationCollectionGroup, notificationBoxCollection, notificationWeekCollectionFactory } = context;
|
|
1376
|
-
return firebaseServerActionTransformFunctionFactory(firebase_1.CleanupSentNotificationsParams, async () => {
|
|
1377
|
-
return async () => {
|
|
1378
|
-
let notificationBoxesUpdatesCount = 0;
|
|
1379
|
-
let notificationsDeleted = 0;
|
|
1380
|
-
const notificationTasksDeletedCount = 0;
|
|
1381
|
-
let notificationWeeksCreated = 0;
|
|
1382
|
-
let notificationWeeksUpdated = 0;
|
|
1383
|
-
// iterate through all Notification items that need to be cleaned up
|
|
1384
|
-
// eslint-disable-next-line no-constant-condition
|
|
1385
|
-
while (true) {
|
|
1386
|
-
const cleanupSentNotificationsResults = await cleanupSentNotifications();
|
|
1387
|
-
cleanupSentNotificationsResults.results.forEach((x) => {
|
|
1388
|
-
const { itemsDeleted, weeksCreated, weeksUpdated } = x[1];
|
|
1389
|
-
notificationsDeleted += itemsDeleted;
|
|
1390
|
-
notificationWeeksCreated += weeksCreated;
|
|
1391
|
-
notificationWeeksUpdated += weeksUpdated;
|
|
1392
|
-
});
|
|
1393
|
-
const notificationBoxesUpdated = cleanupSentNotificationsResults.results.length;
|
|
1394
|
-
notificationBoxesUpdatesCount += notificationBoxesUpdated;
|
|
1395
|
-
if (!notificationBoxesUpdated) {
|
|
1396
|
-
break;
|
|
1397
|
-
}
|
|
1398
|
-
}
|
|
1399
|
-
async function cleanupSentNotifications() {
|
|
1400
|
-
const query = notificationCollectionGroup.queryDocument((0, firebase_1.notificationsReadyForCleanupQuery)());
|
|
1401
|
-
const notificationDocuments = await query.getDocs();
|
|
1402
|
-
const notificationDocumentsGroupedByNotificationBox = Array.from((0, util_1.makeValuesGroupMap)(notificationDocuments, (x) => x.parent.id).values());
|
|
1403
|
-
const result = await (0, util_1.performAsyncTasks)(notificationDocumentsGroupedByNotificationBox, async (notificationDocumentsInSameBox) => {
|
|
1404
|
-
const allPairs = await (0, firebase_1.getDocumentSnapshotDataPairs)(notificationDocumentsInSameBox);
|
|
1405
|
-
const allPairsWithDataAndMarkedDeleted = allPairs.filter((x) => x.data?.d);
|
|
1406
|
-
const { included: taskPairsWithDataAndMarkedDeleted, excluded: normalPairsWithDataAndMarkedDeleted } = (0, util_1.separateValues)(allPairsWithDataAndMarkedDeleted, (x) => x.data?.st === firebase_1.NotificationSendType.TASK_NOTIFICATION);
|
|
1407
|
-
const pairsGroupedByWeek = Array.from((0, util_1.makeValuesGroupMap)(normalPairsWithDataAndMarkedDeleted, (x) => (0, date_1.yearWeekCode)(x.data.sat)).entries());
|
|
1408
|
-
// batch incase there are a lot of new notifications to move to week
|
|
1409
|
-
const pairsGroupedByWeekInBatches = pairsGroupedByWeek
|
|
1410
|
-
.map((x) => {
|
|
1411
|
-
const batches = (0, util_1.batch)(x[1], 40);
|
|
1412
|
-
return batches.map((batch) => [x[0], batch]);
|
|
1413
|
-
})
|
|
1414
|
-
.flat();
|
|
1415
|
-
const notificationBoxDocument = await notificationBoxCollection.documentAccessor().loadDocument(notificationDocumentsInSameBox[0].parent);
|
|
1416
|
-
// create/update the NotificationWeek
|
|
1417
|
-
const notificationWeekResults = await (0, util_1.performAsyncTasks)(pairsGroupedByWeekInBatches, async ([yearWeekCode, notificationDocumentsInSameWeek]) => {
|
|
1418
|
-
return firestoreContext.runTransaction(async (transaction) => {
|
|
1419
|
-
const notificationWeekDocument = notificationWeekCollectionFactory(notificationBoxDocument).documentAccessorForTransaction(transaction).loadDocumentForId(`${yearWeekCode}`);
|
|
1420
|
-
const notificationDocumentsInTransaction = (0, firebase_1.loadDocumentsForDocumentReferencesFromValues)(notificationCollectionGroup.documentAccessorForTransaction(transaction), notificationDocumentsInSameWeek, (x) => x.snapshot.ref);
|
|
1421
|
-
const notificationWeek = await notificationWeekDocument.snapshotData();
|
|
1422
|
-
const newItems = (0, util_1.filterMaybeArrayValues)(notificationDocumentsInSameWeek.map((x) => {
|
|
1423
|
-
const data = x.data;
|
|
1424
|
-
const shouldSaveToNotificationWeek = (0, firebase_1.shouldSaveNotificationToNotificationWeek)(data);
|
|
1425
|
-
return shouldSaveToNotificationWeek ? data.n : undefined;
|
|
1426
|
-
}));
|
|
1427
|
-
const n = [...(notificationWeek?.n ?? []), ...newItems];
|
|
1428
|
-
if (!notificationWeek) {
|
|
1429
|
-
// create
|
|
1430
|
-
await notificationWeekDocument.create({
|
|
1431
|
-
w: yearWeekCode,
|
|
1432
|
-
n
|
|
1433
|
-
});
|
|
1434
|
-
}
|
|
1435
|
-
else {
|
|
1436
|
-
// update
|
|
1437
|
-
await notificationWeekDocument.update({
|
|
1438
|
-
n
|
|
1439
|
-
});
|
|
1440
|
-
}
|
|
1441
|
-
// delete the notification items
|
|
1442
|
-
await Promise.all(notificationDocumentsInTransaction.map((x) => x.accessor.delete()));
|
|
1443
|
-
return {
|
|
1444
|
-
created: !notificationWeek
|
|
1445
|
-
};
|
|
1446
|
-
});
|
|
1447
|
-
});
|
|
1448
|
-
// delete all the task notifications
|
|
1449
|
-
const writeBatch = firestoreContext.batch();
|
|
1450
|
-
const writeBatchAccessor = notificationCollectionGroup.documentAccessorForTransaction(writeBatch);
|
|
1451
|
-
await Promise.all(taskPairsWithDataAndMarkedDeleted.map((x) => writeBatchAccessor.loadDocumentFrom(x.document).accessor.delete()));
|
|
1452
|
-
await writeBatch.commit();
|
|
1453
|
-
let weeksCreated = 0;
|
|
1454
|
-
let weeksUpdated = 0;
|
|
1455
|
-
const tasksDeleted = taskPairsWithDataAndMarkedDeleted.length;
|
|
1456
|
-
notificationWeekResults.results.forEach((x) => {
|
|
1457
|
-
if (x[1].created) {
|
|
1458
|
-
weeksCreated += 1;
|
|
1459
|
-
}
|
|
1460
|
-
else {
|
|
1461
|
-
weeksUpdated += 1;
|
|
1462
|
-
}
|
|
1463
|
-
});
|
|
1464
|
-
const result = {
|
|
1465
|
-
weeksCreated,
|
|
1466
|
-
weeksUpdated,
|
|
1467
|
-
itemsDeleted: allPairsWithDataAndMarkedDeleted.length,
|
|
1468
|
-
tasksDeleted
|
|
1469
|
-
};
|
|
1470
|
-
return result;
|
|
1471
|
-
}, {
|
|
1472
|
-
maxParallelTasks: 10
|
|
1473
|
-
});
|
|
1474
|
-
return result;
|
|
1475
|
-
}
|
|
1476
|
-
const result = {
|
|
1477
|
-
notificationBoxesUpdatesCount,
|
|
1478
|
-
notificationTasksDeletedCount,
|
|
1479
|
-
notificationsDeleted,
|
|
1480
|
-
notificationWeeksCreated,
|
|
1481
|
-
notificationWeeksUpdated
|
|
1482
|
-
};
|
|
1483
|
-
return result;
|
|
1484
|
-
};
|
|
1485
|
-
});
|
|
1486
|
-
}
|
|
1487
|
-
//# sourceMappingURL=notification.action.service.js.map
|