@rpcbase/server 0.512.0 → 0.514.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.
@@ -14,7 +14,10 @@ const getSessionUser = (ctx) => {
14
14
  ctx.res.status(400);
15
15
  return null;
16
16
  }
17
- return { userId, tenantId };
17
+ return {
18
+ userId,
19
+ tenantId
20
+ };
18
21
  };
19
22
  const ListRoute = "/api/rb/notifications";
20
23
  const CreateRoute = "/api/rb/notifications/create";
@@ -122,59 +125,113 @@ const buildDisabledTopics = (settings, key) => {
122
125
  const listNotifications = async (payload, ctx) => {
123
126
  const session = getSessionUser(ctx);
124
127
  if (!session) {
125
- return { ok: false, error: "unauthorized" };
128
+ return {
129
+ ok: false,
130
+ error: "unauthorized"
131
+ };
126
132
  }
127
- const ability = buildAbilityFromSession({ tenantId: session.tenantId, session: ctx.req.session });
133
+ const ability = buildAbilityFromSession({
134
+ tenantId: session.tenantId,
135
+ session: ctx.req.session
136
+ });
128
137
  if (!ability.can("read", "RBNotification")) {
129
138
  ctx.res.status(403);
130
- return { ok: false, error: "forbidden" };
139
+ return {
140
+ ok: false,
141
+ error: "forbidden"
142
+ };
131
143
  }
132
144
  const parsed = listRequestSchema.safeParse(payload);
133
145
  if (!parsed.success) {
134
146
  ctx.res.status(400);
135
- return { ok: false, error: "invalid_payload" };
147
+ return {
148
+ ok: false,
149
+ error: "invalid_payload"
150
+ };
136
151
  }
137
- const { userId } = session;
152
+ const {
153
+ userId
154
+ } = session;
138
155
  const includeArchived = parsed.data.includeArchived === true;
139
156
  const unreadOnly = parsed.data.unreadOnly === true;
140
157
  const limit = parsed.data.limit ?? 50;
141
158
  const markSeen = parsed.data.markSeen === true;
142
159
  const SettingsModel = await models.get("RBNotificationSettings", ctx);
143
- const settings = await SettingsModel.findOne({ userId }).lean();
160
+ const settings = await SettingsModel.findOne({
161
+ userId
162
+ }).lean();
144
163
  const disabledTopics = buildDisabledTopics(settings, "inApp");
145
164
  const NotificationModel = await models.get("RBNotification", ctx);
146
- const queryFilters = [
147
- { userId },
148
- getAccessibleByQuery(ability, "read", "RBNotification")
149
- ];
150
- if (!includeArchived) queryFilters.push({ archivedAt: { $exists: false } });
151
- if (unreadOnly) queryFilters.push({ readAt: { $exists: false } });
152
- if (disabledTopics.length > 0) queryFilters.push({ topic: { $nin: disabledTopics } });
153
- const query = { $and: queryFilters };
154
- const notifications = await NotificationModel.find(query).sort({ createdAt: -1 }).limit(limit).lean();
155
- const unseenQueryFilters = [
156
- { userId },
157
- { archivedAt: { $exists: false } },
158
- { seenAt: { $exists: false } },
159
- getAccessibleByQuery(ability, "read", "RBNotification")
160
- ];
161
- if (disabledTopics.length > 0) unseenQueryFilters.push({ topic: { $nin: disabledTopics } });
162
- const unseenQuery = { $and: unseenQueryFilters };
163
- const unreadQueryFilters = [
164
- { userId },
165
- { archivedAt: { $exists: false } },
166
- { readAt: { $exists: false } },
167
- getAccessibleByQuery(ability, "read", "RBNotification")
168
- ];
169
- if (disabledTopics.length > 0) unreadQueryFilters.push({ topic: { $nin: disabledTopics } });
170
- const unreadQuery = { $and: unreadQueryFilters };
171
- const [unreadCount, unseenCount] = await Promise.all([
172
- NotificationModel.countDocuments(unreadQuery),
173
- NotificationModel.countDocuments(unseenQuery)
174
- ]);
165
+ const queryFilters = [{
166
+ userId
167
+ }, getAccessibleByQuery(ability, "read", "RBNotification")];
168
+ if (!includeArchived) queryFilters.push({
169
+ archivedAt: {
170
+ $exists: false
171
+ }
172
+ });
173
+ if (unreadOnly) queryFilters.push({
174
+ readAt: {
175
+ $exists: false
176
+ }
177
+ });
178
+ if (disabledTopics.length > 0) queryFilters.push({
179
+ topic: {
180
+ $nin: disabledTopics
181
+ }
182
+ });
183
+ const query = {
184
+ $and: queryFilters
185
+ };
186
+ const notifications = await NotificationModel.find(query).sort({
187
+ createdAt: -1
188
+ }).limit(limit).lean();
189
+ const unseenQueryFilters = [{
190
+ userId
191
+ }, {
192
+ archivedAt: {
193
+ $exists: false
194
+ }
195
+ }, {
196
+ seenAt: {
197
+ $exists: false
198
+ }
199
+ }, getAccessibleByQuery(ability, "read", "RBNotification")];
200
+ if (disabledTopics.length > 0) unseenQueryFilters.push({
201
+ topic: {
202
+ $nin: disabledTopics
203
+ }
204
+ });
205
+ const unseenQuery = {
206
+ $and: unseenQueryFilters
207
+ };
208
+ const unreadQueryFilters = [{
209
+ userId
210
+ }, {
211
+ archivedAt: {
212
+ $exists: false
213
+ }
214
+ }, {
215
+ readAt: {
216
+ $exists: false
217
+ }
218
+ }, getAccessibleByQuery(ability, "read", "RBNotification")];
219
+ if (disabledTopics.length > 0) unreadQueryFilters.push({
220
+ topic: {
221
+ $nin: disabledTopics
222
+ }
223
+ });
224
+ const unreadQuery = {
225
+ $and: unreadQueryFilters
226
+ };
227
+ const [unreadCount, unseenCount] = await Promise.all([NotificationModel.countDocuments(unreadQuery), NotificationModel.countDocuments(unseenQuery)]);
175
228
  const now = markSeen ? /* @__PURE__ */ new Date() : null;
176
229
  if (now && unseenCount > 0) {
177
- await NotificationModel.updateMany(unseenQuery, { $set: { seenAt: now } });
230
+ await NotificationModel.updateMany(unseenQuery, {
231
+ $set: {
232
+ seenAt: now
233
+ }
234
+ });
178
235
  }
179
236
  return listResponseSchema.parse({
180
237
  ok: true,
@@ -197,17 +254,29 @@ const listNotifications = async (payload, ctx) => {
197
254
  const createNotificationForCurrentUser = async (payload, ctx) => {
198
255
  const session = getSessionUser(ctx);
199
256
  if (!session) {
200
- return { ok: false, error: "unauthorized" };
257
+ return {
258
+ ok: false,
259
+ error: "unauthorized"
260
+ };
201
261
  }
202
- const ability = buildAbilityFromSession({ tenantId: session.tenantId, session: ctx.req.session });
262
+ const ability = buildAbilityFromSession({
263
+ tenantId: session.tenantId,
264
+ session: ctx.req.session
265
+ });
203
266
  if (!ability.can("create", "RBNotification")) {
204
267
  ctx.res.status(403);
205
- return { ok: false, error: "forbidden" };
268
+ return {
269
+ ok: false,
270
+ error: "forbidden"
271
+ };
206
272
  }
207
273
  const parsed = createRequestSchema.safeParse(payload);
208
274
  if (!parsed.success) {
209
275
  ctx.res.status(400);
210
- return { ok: false, error: "invalid_payload" };
276
+ return {
277
+ ok: false,
278
+ error: "invalid_payload"
279
+ };
211
280
  }
212
281
  const created = await createNotification(ctx, {
213
282
  userId: session.userId,
@@ -217,103 +286,199 @@ const createNotificationForCurrentUser = async (payload, ctx) => {
217
286
  url: parsed.data.url,
218
287
  metadata: parsed.data.metadata
219
288
  });
220
- return createResponseSchema.parse({ ok: true, id: created.id });
289
+ return createResponseSchema.parse({
290
+ ok: true,
291
+ id: created.id
292
+ });
221
293
  };
222
294
  const markRead = async (_payload, ctx) => {
223
295
  const session = getSessionUser(ctx);
224
296
  if (!session) {
225
- return { ok: false, error: "unauthorized" };
297
+ return {
298
+ ok: false,
299
+ error: "unauthorized"
300
+ };
226
301
  }
227
- const ability = buildAbilityFromSession({ tenantId: session.tenantId, session: ctx.req.session });
302
+ const ability = buildAbilityFromSession({
303
+ tenantId: session.tenantId,
304
+ session: ctx.req.session
305
+ });
228
306
  if (!ability.can("update", "RBNotification")) {
229
307
  ctx.res.status(403);
230
- return { ok: false, error: "forbidden" };
308
+ return {
309
+ ok: false,
310
+ error: "forbidden"
311
+ };
231
312
  }
232
313
  const notificationId = typeof ctx.req.params.notificationId === "string" ? ctx.req.params.notificationId.trim() : "";
233
314
  if (!notificationId) {
234
315
  ctx.res.status(400);
235
- return { ok: false, error: "missing_notification_id" };
316
+ return {
317
+ ok: false,
318
+ error: "missing_notification_id"
319
+ };
236
320
  }
237
321
  const NotificationModel = await models.get("RBNotification", ctx);
238
322
  const now = /* @__PURE__ */ new Date();
239
323
  try {
240
- await NotificationModel.updateOne(
241
- { $and: [{ _id: notificationId }, { archivedAt: { $exists: false } }, getAccessibleByQuery(ability, "update", "RBNotification")] },
242
- { $set: { readAt: now, seenAt: now } }
243
- );
324
+ await NotificationModel.updateOne({
325
+ $and: [{
326
+ _id: notificationId
327
+ }, {
328
+ archivedAt: {
329
+ $exists: false
330
+ }
331
+ }, getAccessibleByQuery(ability, "update", "RBNotification")]
332
+ }, {
333
+ $set: {
334
+ readAt: now,
335
+ seenAt: now
336
+ }
337
+ });
244
338
  } catch {
245
339
  ctx.res.status(400);
246
- return { ok: false, error: "invalid_notification_id" };
340
+ return {
341
+ ok: false,
342
+ error: "invalid_notification_id"
343
+ };
247
344
  }
248
- return { ok: true };
345
+ return {
346
+ ok: true
347
+ };
249
348
  };
250
349
  const markAllRead = async (_payload, ctx) => {
251
350
  const session = getSessionUser(ctx);
252
351
  if (!session) {
253
- return { ok: false, error: "unauthorized" };
352
+ return {
353
+ ok: false,
354
+ error: "unauthorized"
355
+ };
254
356
  }
255
- const ability = buildAbilityFromSession({ tenantId: session.tenantId, session: ctx.req.session });
357
+ const ability = buildAbilityFromSession({
358
+ tenantId: session.tenantId,
359
+ session: ctx.req.session
360
+ });
256
361
  if (!ability.can("update", "RBNotification")) {
257
362
  ctx.res.status(403);
258
- return { ok: false, error: "forbidden" };
363
+ return {
364
+ ok: false,
365
+ error: "forbidden"
366
+ };
259
367
  }
260
368
  const SettingsModel = await models.get("RBNotificationSettings", ctx);
261
- const settings = await SettingsModel.findOne({ userId: session.userId }).lean();
369
+ const settings = await SettingsModel.findOne({
370
+ userId: session.userId
371
+ }).lean();
262
372
  const disabledTopics = buildDisabledTopics(settings, "inApp");
263
373
  const NotificationModel = await models.get("RBNotification", ctx);
264
- const queryFilters = [
265
- { userId: session.userId },
266
- { archivedAt: { $exists: false } },
267
- { readAt: { $exists: false } },
268
- getAccessibleByQuery(ability, "update", "RBNotification")
269
- ];
270
- if (disabledTopics.length > 0) queryFilters.push({ topic: { $nin: disabledTopics } });
271
- const query = { $and: queryFilters };
374
+ const queryFilters = [{
375
+ userId: session.userId
376
+ }, {
377
+ archivedAt: {
378
+ $exists: false
379
+ }
380
+ }, {
381
+ readAt: {
382
+ $exists: false
383
+ }
384
+ }, getAccessibleByQuery(ability, "update", "RBNotification")];
385
+ if (disabledTopics.length > 0) queryFilters.push({
386
+ topic: {
387
+ $nin: disabledTopics
388
+ }
389
+ });
390
+ const query = {
391
+ $and: queryFilters
392
+ };
272
393
  const now = /* @__PURE__ */ new Date();
273
- await NotificationModel.updateMany(query, { $set: { readAt: now, seenAt: now } });
274
- return { ok: true };
394
+ await NotificationModel.updateMany(query, {
395
+ $set: {
396
+ readAt: now,
397
+ seenAt: now
398
+ }
399
+ });
400
+ return {
401
+ ok: true
402
+ };
275
403
  };
276
404
  const archiveNotification = async (_payload, ctx) => {
277
405
  const session = getSessionUser(ctx);
278
406
  if (!session) {
279
- return { ok: false, error: "unauthorized" };
407
+ return {
408
+ ok: false,
409
+ error: "unauthorized"
410
+ };
280
411
  }
281
- const ability = buildAbilityFromSession({ tenantId: session.tenantId, session: ctx.req.session });
412
+ const ability = buildAbilityFromSession({
413
+ tenantId: session.tenantId,
414
+ session: ctx.req.session
415
+ });
282
416
  if (!ability.can("update", "RBNotification")) {
283
417
  ctx.res.status(403);
284
- return { ok: false, error: "forbidden" };
418
+ return {
419
+ ok: false,
420
+ error: "forbidden"
421
+ };
285
422
  }
286
423
  const notificationId = typeof ctx.req.params.notificationId === "string" ? ctx.req.params.notificationId.trim() : "";
287
424
  if (!notificationId) {
288
425
  ctx.res.status(400);
289
- return { ok: false, error: "missing_notification_id" };
426
+ return {
427
+ ok: false,
428
+ error: "missing_notification_id"
429
+ };
290
430
  }
291
431
  const NotificationModel = await models.get("RBNotification", ctx);
292
432
  try {
293
- await NotificationModel.updateOne(
294
- { $and: [{ _id: notificationId }, { archivedAt: { $exists: false } }, getAccessibleByQuery(ability, "update", "RBNotification")] },
295
- { $set: { archivedAt: /* @__PURE__ */ new Date() } }
296
- );
433
+ await NotificationModel.updateOne({
434
+ $and: [{
435
+ _id: notificationId
436
+ }, {
437
+ archivedAt: {
438
+ $exists: false
439
+ }
440
+ }, getAccessibleByQuery(ability, "update", "RBNotification")]
441
+ }, {
442
+ $set: {
443
+ archivedAt: /* @__PURE__ */ new Date()
444
+ }
445
+ });
297
446
  } catch {
298
447
  ctx.res.status(400);
299
- return { ok: false, error: "invalid_notification_id" };
448
+ return {
449
+ ok: false,
450
+ error: "invalid_notification_id"
451
+ };
300
452
  }
301
- return { ok: true };
453
+ return {
454
+ ok: true
455
+ };
302
456
  };
303
457
  const getSettings = async (_payload, ctx) => {
304
458
  const session = getSessionUser(ctx);
305
459
  if (!session) {
306
- return { ok: false, error: "unauthorized" };
460
+ return {
461
+ ok: false,
462
+ error: "unauthorized"
463
+ };
307
464
  }
308
- const ability = buildAbilityFromSession({ tenantId: session.tenantId, session: ctx.req.session });
465
+ const ability = buildAbilityFromSession({
466
+ tenantId: session.tenantId,
467
+ session: ctx.req.session
468
+ });
309
469
  if (!ability.can("read", "RBNotificationSettings")) {
310
470
  ctx.res.status(403);
311
- return { ok: false, error: "forbidden" };
471
+ return {
472
+ ok: false,
473
+ error: "forbidden"
474
+ };
312
475
  }
313
476
  const SettingsModel = await models.get("RBNotificationSettings", ctx);
314
- const settings = await SettingsModel.findOne(
315
- { $and: [{ userId: session.userId }, getAccessibleByQuery(ability, "read", "RBNotificationSettings")] }
316
- ).lean();
477
+ const settings = await SettingsModel.findOne({
478
+ $and: [{
479
+ userId: session.userId
480
+ }, getAccessibleByQuery(ability, "read", "RBNotificationSettings")]
481
+ }).lean();
317
482
  const digestFrequencyRaw = typeof settings?.digestFrequency === "string" ? settings.digestFrequency : "weekly";
318
483
  const digestFrequency = digestFrequencyRaw === "off" || digestFrequencyRaw === "daily" || digestFrequencyRaw === "weekly" ? digestFrequencyRaw : "weekly";
319
484
  const topicPreferences = Array.isArray(settings?.topicPreferences) ? settings.topicPreferences.map((pref) => ({
@@ -334,17 +499,29 @@ const getSettings = async (_payload, ctx) => {
334
499
  const updateSettings = async (payload, ctx) => {
335
500
  const session = getSessionUser(ctx);
336
501
  if (!session) {
337
- return { ok: false, error: "unauthorized" };
502
+ return {
503
+ ok: false,
504
+ error: "unauthorized"
505
+ };
338
506
  }
339
- const ability = buildAbilityFromSession({ tenantId: session.tenantId, session: ctx.req.session });
507
+ const ability = buildAbilityFromSession({
508
+ tenantId: session.tenantId,
509
+ session: ctx.req.session
510
+ });
340
511
  if (!ability.can("update", "RBNotificationSettings")) {
341
512
  ctx.res.status(403);
342
- return { ok: false, error: "forbidden" };
513
+ return {
514
+ ok: false,
515
+ error: "forbidden"
516
+ };
343
517
  }
344
518
  const parsed = updateSettingsRequestSchema.safeParse(payload);
345
519
  if (!parsed.success) {
346
520
  ctx.res.status(400);
347
- return { ok: false, error: "invalid_payload" };
521
+ return {
522
+ ok: false,
523
+ error: "invalid_payload"
524
+ };
348
525
  }
349
526
  const SettingsModel = await models.get("RBNotificationSettings", ctx);
350
527
  const nextValues = {};
@@ -366,16 +543,22 @@ const updateSettings = async (payload, ctx) => {
366
543
  nextValues.topicPreferences = next;
367
544
  }
368
545
  const ops = {
369
- $setOnInsert: { userId: session.userId }
546
+ $setOnInsert: {
547
+ userId: session.userId
548
+ }
370
549
  };
371
550
  if (Object.keys(nextValues).length > 0) {
372
551
  ops.$set = nextValues;
373
552
  }
374
- const settings = await SettingsModel.findOneAndUpdate(
375
- { $and: [{ userId: session.userId }, getAccessibleByQuery(ability, "update", "RBNotificationSettings")] },
376
- ops,
377
- { upsert: true, new: true, setDefaultsOnInsert: true }
378
- ).lean();
553
+ const settings = await SettingsModel.findOneAndUpdate({
554
+ $and: [{
555
+ userId: session.userId
556
+ }, getAccessibleByQuery(ability, "update", "RBNotificationSettings")]
557
+ }, ops, {
558
+ upsert: true,
559
+ new: true,
560
+ setDefaultsOnInsert: true
561
+ }).lean();
379
562
  const digestFrequencyRaw = typeof settings?.digestFrequency === "string" ? settings.digestFrequency : "weekly";
380
563
  const digestFrequency = digestFrequencyRaw === "off" || digestFrequencyRaw === "daily" || digestFrequencyRaw === "weekly" ? digestFrequencyRaw : "weekly";
381
564
  const topicPreferences = Array.isArray(settings?.topicPreferences) ? settings.topicPreferences.map((pref) => ({
@@ -396,17 +579,29 @@ const updateSettings = async (payload, ctx) => {
396
579
  const runDigest = async (payload, ctx) => {
397
580
  const session = getSessionUser(ctx);
398
581
  if (!session) {
399
- return { ok: false, error: "unauthorized" };
582
+ return {
583
+ ok: false,
584
+ error: "unauthorized"
585
+ };
400
586
  }
401
- const ability = buildAbilityFromSession({ tenantId: session.tenantId, session: ctx.req.session });
587
+ const ability = buildAbilityFromSession({
588
+ tenantId: session.tenantId,
589
+ session: ctx.req.session
590
+ });
402
591
  if (!ability.can("read", "RBNotification")) {
403
592
  ctx.res.status(403);
404
- return { ok: false, error: "forbidden" };
593
+ return {
594
+ ok: false,
595
+ error: "forbidden"
596
+ };
405
597
  }
406
598
  const parsed = digestRunRequestSchema.safeParse(payload);
407
599
  if (!parsed.success) {
408
600
  ctx.res.status(400);
409
- return { ok: false, error: "invalid_payload" };
601
+ return {
602
+ ok: false,
603
+ error: "invalid_payload"
604
+ };
410
605
  }
411
606
  const result = await sendNotificationsDigestForUser(ctx, {
412
607
  userId: session.userId,
@@ -414,12 +609,17 @@ const runDigest = async (payload, ctx) => {
414
609
  });
415
610
  if (!result.ok) {
416
611
  ctx.res.status(500);
417
- return { ok: false, error: result.error };
612
+ return {
613
+ ok: false,
614
+ error: result.error
615
+ };
418
616
  }
419
617
  return {
420
618
  ok: true,
421
619
  sent: result.sent,
422
- ...result.skippedReason ? { skippedReason: result.skippedReason } : {}
620
+ ...result.skippedReason ? {
621
+ skippedReason: result.skippedReason
622
+ } : {}
423
623
  };
424
624
  };
425
625
  const handler = (api) => {
@@ -435,4 +635,4 @@ const handler = (api) => {
435
635
  export {
436
636
  handler as default
437
637
  };
438
- //# sourceMappingURL=handler-r-HYO3Oy.js.map
638
+ //# sourceMappingURL=handler-3gksYOQv.js.map