@rpcbase/db 0.62.0 → 0.64.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/dist/acl/index.js +1 -1
- package/dist/{can-urGFf45M.js → can-D558uqd-.js} +7 -11
- package/dist/{can-urGFf45M.js.map → can-D558uqd-.js.map} +1 -1
- package/dist/{index-Drge1bnG.js → index-g1_0RZ-U.js} +4 -5
- package/dist/{index-Drge1bnG.js.map → index-g1_0RZ-U.js.map} +1 -1
- package/dist/index.browser.js +1 -1
- package/dist/index.js +879 -312
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { a as registerPoliciesFromModules } from "./can-
|
|
2
|
-
import { b, d, f, e, g, c, r } from "./can-
|
|
1
|
+
import { a as registerPoliciesFromModules } from "./can-D558uqd-.js";
|
|
2
|
+
import { b, d, f, e, g, c, r } from "./can-D558uqd-.js";
|
|
3
3
|
import mongoose, { Schema as Schema$1, Types } from "mongoose";
|
|
4
4
|
import { default as default2 } from "mongoose";
|
|
5
5
|
import { z } from "zod";
|
|
6
6
|
import { timingSafeEqual, createHmac } from "node:crypto";
|
|
7
|
-
import { w as withLocalizedStringFallback } from "./index-
|
|
8
|
-
import { a, E, L, c as c2, e as e2, m, r as r2, z as z2, b as b2, f as f2, d as d2 } from "./index-
|
|
7
|
+
import { w as withLocalizedStringFallback } from "./index-g1_0RZ-U.js";
|
|
8
|
+
import { a, E, L, c as c2, e as e2, m, r as r2, z as z2, b as b2, f as f2, d as d2 } from "./index-g1_0RZ-U.js";
|
|
9
9
|
import assert from "assert";
|
|
10
10
|
import { accessibleBy, accessibleRecordsPlugin } from "@casl/mongoose";
|
|
11
11
|
import "@casl/ability";
|
|
@@ -34,33 +34,97 @@ const ZRBUser = z.object({
|
|
|
34
34
|
emailVerificationExpiresAt: z.date().optional()
|
|
35
35
|
});
|
|
36
36
|
const RBUserSchema = new Schema$1({
|
|
37
|
-
email: {
|
|
38
|
-
|
|
39
|
-
|
|
37
|
+
email: {
|
|
38
|
+
type: String,
|
|
39
|
+
unique: true,
|
|
40
|
+
sparse: true
|
|
41
|
+
},
|
|
42
|
+
phone: {
|
|
43
|
+
type: String,
|
|
44
|
+
unique: true,
|
|
45
|
+
sparse: true
|
|
46
|
+
},
|
|
47
|
+
password: {
|
|
48
|
+
type: String,
|
|
49
|
+
required: true
|
|
50
|
+
},
|
|
40
51
|
name: String,
|
|
41
|
-
tenants: {
|
|
42
|
-
|
|
52
|
+
tenants: {
|
|
53
|
+
type: [String],
|
|
54
|
+
index: true,
|
|
55
|
+
required: true
|
|
56
|
+
},
|
|
57
|
+
tenantRoles: {
|
|
58
|
+
type: Map,
|
|
59
|
+
of: [String],
|
|
60
|
+
required: false,
|
|
61
|
+
default: {}
|
|
62
|
+
},
|
|
43
63
|
oauthProviders: {
|
|
44
64
|
type: Map,
|
|
45
65
|
of: new Schema$1({
|
|
46
|
-
subject: {
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
66
|
+
subject: {
|
|
67
|
+
type: String,
|
|
68
|
+
required: true
|
|
69
|
+
},
|
|
70
|
+
email: {
|
|
71
|
+
type: String,
|
|
72
|
+
required: false
|
|
73
|
+
},
|
|
74
|
+
name: {
|
|
75
|
+
type: String,
|
|
76
|
+
required: false
|
|
77
|
+
},
|
|
78
|
+
accessToken: {
|
|
79
|
+
type: String,
|
|
80
|
+
required: false
|
|
81
|
+
},
|
|
82
|
+
refreshToken: {
|
|
83
|
+
type: String,
|
|
84
|
+
required: false
|
|
85
|
+
},
|
|
86
|
+
idToken: {
|
|
87
|
+
type: String,
|
|
88
|
+
required: false
|
|
89
|
+
},
|
|
90
|
+
scope: {
|
|
91
|
+
type: String,
|
|
92
|
+
required: false
|
|
93
|
+
},
|
|
94
|
+
tokenType: {
|
|
95
|
+
type: String,
|
|
96
|
+
required: false
|
|
97
|
+
},
|
|
98
|
+
expiresAt: {
|
|
99
|
+
type: Date,
|
|
100
|
+
required: false
|
|
101
|
+
},
|
|
102
|
+
rawUserInfo: {
|
|
103
|
+
type: Schema$1.Types.Mixed,
|
|
104
|
+
required: false
|
|
105
|
+
},
|
|
106
|
+
createdAt: {
|
|
107
|
+
type: Date,
|
|
108
|
+
required: false
|
|
109
|
+
},
|
|
110
|
+
updatedAt: {
|
|
111
|
+
type: Date,
|
|
112
|
+
required: false
|
|
113
|
+
}
|
|
114
|
+
}, {
|
|
115
|
+
_id: false
|
|
116
|
+
}),
|
|
59
117
|
default: {},
|
|
60
118
|
required: false
|
|
61
119
|
},
|
|
62
|
-
emailVerificationCode: {
|
|
63
|
-
|
|
120
|
+
emailVerificationCode: {
|
|
121
|
+
type: String,
|
|
122
|
+
required: false
|
|
123
|
+
},
|
|
124
|
+
emailVerificationExpiresAt: {
|
|
125
|
+
type: Date,
|
|
126
|
+
required: false
|
|
127
|
+
}
|
|
64
128
|
});
|
|
65
129
|
const ZRBTenant = z.object({
|
|
66
130
|
tenantId: z.string(),
|
|
@@ -68,18 +132,20 @@ const ZRBTenant = z.object({
|
|
|
68
132
|
name: z.string().optional()
|
|
69
133
|
});
|
|
70
134
|
const RBTenantSchema = new Schema$1({
|
|
71
|
-
tenantId: {
|
|
72
|
-
|
|
73
|
-
|
|
135
|
+
tenantId: {
|
|
136
|
+
type: String,
|
|
137
|
+
required: true,
|
|
138
|
+
unique: true,
|
|
139
|
+
index: true
|
|
140
|
+
},
|
|
141
|
+
parentTenantId: {
|
|
142
|
+
type: String
|
|
143
|
+
},
|
|
144
|
+
name: {
|
|
145
|
+
type: String
|
|
146
|
+
}
|
|
74
147
|
});
|
|
75
|
-
const ZRBTenantSubscriptionStatus = z.enum([
|
|
76
|
-
"trialing",
|
|
77
|
-
"active",
|
|
78
|
-
"past_due",
|
|
79
|
-
"paused",
|
|
80
|
-
"canceled",
|
|
81
|
-
"expired"
|
|
82
|
-
]);
|
|
148
|
+
const ZRBTenantSubscriptionStatus = z.enum(["trialing", "active", "past_due", "paused", "canceled", "expired"]);
|
|
83
149
|
const ZRBTenantSubscriptionIntervalUnit = z.enum(["month", "year"]);
|
|
84
150
|
const ZRBTenantSubscriptionType = z.enum(["primary", "addon"]);
|
|
85
151
|
const ZRBTenantSubscriptionScope = z.enum(["tenant", "shop", "custom"]);
|
|
@@ -108,46 +174,107 @@ const ZRBTenantSubscription = z.object({
|
|
|
108
174
|
latestEventAt: z.date().optional(),
|
|
109
175
|
metadata: z.record(z.string(), z.unknown()).optional()
|
|
110
176
|
});
|
|
111
|
-
const RBTenantSubscriptionSchema = new Schema$1(
|
|
112
|
-
{
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
177
|
+
const RBTenantSubscriptionSchema = new Schema$1({
|
|
178
|
+
tenantId: {
|
|
179
|
+
type: String,
|
|
180
|
+
required: true,
|
|
181
|
+
index: true
|
|
182
|
+
},
|
|
183
|
+
subscriptionId: {
|
|
184
|
+
type: String,
|
|
185
|
+
required: true
|
|
186
|
+
},
|
|
187
|
+
type: {
|
|
188
|
+
type: String,
|
|
189
|
+
required: true,
|
|
190
|
+
enum: ZRBTenantSubscriptionType.options,
|
|
191
|
+
default: "primary"
|
|
192
|
+
},
|
|
193
|
+
parentSubscriptionId: {
|
|
194
|
+
type: String
|
|
195
|
+
},
|
|
196
|
+
scope: {
|
|
197
|
+
type: String,
|
|
198
|
+
enum: ZRBTenantSubscriptionScope.options,
|
|
199
|
+
default: "tenant"
|
|
200
|
+
},
|
|
201
|
+
scopeId: {
|
|
202
|
+
type: String
|
|
203
|
+
},
|
|
204
|
+
planKey: {
|
|
205
|
+
type: String,
|
|
206
|
+
required: true
|
|
207
|
+
},
|
|
208
|
+
status: {
|
|
209
|
+
type: String,
|
|
210
|
+
required: true,
|
|
211
|
+
enum: ZRBTenantSubscriptionStatus.options
|
|
212
|
+
},
|
|
213
|
+
intervalUnit: {
|
|
214
|
+
type: String,
|
|
215
|
+
required: true,
|
|
216
|
+
enum: ZRBTenantSubscriptionIntervalUnit.options
|
|
217
|
+
},
|
|
218
|
+
intervalCount: {
|
|
219
|
+
type: Number,
|
|
220
|
+
min: 1,
|
|
221
|
+
default: 1
|
|
222
|
+
},
|
|
223
|
+
modules: {
|
|
224
|
+
type: [String],
|
|
225
|
+
default: []
|
|
226
|
+
},
|
|
227
|
+
currentPeriodStart: {
|
|
228
|
+
type: Date
|
|
229
|
+
},
|
|
230
|
+
currentPeriodEnd: {
|
|
231
|
+
type: Date
|
|
232
|
+
},
|
|
233
|
+
trialEndsAt: {
|
|
234
|
+
type: Date
|
|
235
|
+
},
|
|
236
|
+
cancelAt: {
|
|
237
|
+
type: Date
|
|
238
|
+
},
|
|
239
|
+
cancelAtPeriodEnd: {
|
|
240
|
+
type: Boolean,
|
|
241
|
+
default: false
|
|
242
|
+
},
|
|
243
|
+
canceledAt: {
|
|
244
|
+
type: Date
|
|
245
|
+
},
|
|
246
|
+
provider: {
|
|
247
|
+
type: String
|
|
248
|
+
},
|
|
249
|
+
providerCustomerId: {
|
|
250
|
+
type: String
|
|
251
|
+
},
|
|
252
|
+
providerSubscriptionId: {
|
|
253
|
+
type: String
|
|
254
|
+
},
|
|
255
|
+
latestEventId: {
|
|
256
|
+
type: String
|
|
257
|
+
},
|
|
258
|
+
latestEventAt: {
|
|
259
|
+
type: Date
|
|
260
|
+
},
|
|
261
|
+
metadata: {
|
|
262
|
+
type: Schema$1.Types.Mixed
|
|
263
|
+
}
|
|
264
|
+
});
|
|
265
|
+
RBTenantSubscriptionSchema.index({
|
|
266
|
+
tenantId: 1,
|
|
267
|
+
subscriptionId: 1
|
|
268
|
+
}, {
|
|
269
|
+
unique: true
|
|
270
|
+
});
|
|
271
|
+
RBTenantSubscriptionSchema.index({
|
|
272
|
+
tenantId: 1,
|
|
273
|
+
scope: 1,
|
|
274
|
+
scopeId: 1
|
|
275
|
+
});
|
|
276
|
+
const ZRBTenantSubscriptionEventSource = z.enum(["admin", "system", "webhook", "user"]);
|
|
277
|
+
const ZRBTenantSubscriptionChangeDirection = z.enum(["upgrade", "downgrade", "lateral"]);
|
|
151
278
|
const ZRBTenantSubscriptionEvent = z.object({
|
|
152
279
|
tenantId: z.string(),
|
|
153
280
|
subscriptionId: z.string(),
|
|
@@ -173,48 +300,123 @@ const ZRBTenantSubscriptionEvent = z.object({
|
|
|
173
300
|
providerPayload: z.unknown().optional(),
|
|
174
301
|
metadata: z.record(z.string(), z.unknown()).optional()
|
|
175
302
|
});
|
|
176
|
-
const RBTenantSubscriptionEventSchema = new Schema$1(
|
|
177
|
-
{
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
303
|
+
const RBTenantSubscriptionEventSchema = new Schema$1({
|
|
304
|
+
tenantId: {
|
|
305
|
+
type: String,
|
|
306
|
+
required: true,
|
|
307
|
+
index: true
|
|
308
|
+
},
|
|
309
|
+
subscriptionId: {
|
|
310
|
+
type: String,
|
|
311
|
+
required: true,
|
|
312
|
+
index: true
|
|
313
|
+
},
|
|
314
|
+
type: {
|
|
315
|
+
type: String,
|
|
316
|
+
required: true
|
|
317
|
+
},
|
|
318
|
+
occurredAt: {
|
|
319
|
+
type: Date,
|
|
320
|
+
required: true,
|
|
321
|
+
default: Date.now
|
|
322
|
+
},
|
|
323
|
+
effectiveAt: {
|
|
324
|
+
type: Date
|
|
325
|
+
},
|
|
326
|
+
fromPlanKey: {
|
|
327
|
+
type: String
|
|
328
|
+
},
|
|
329
|
+
toPlanKey: {
|
|
330
|
+
type: String
|
|
331
|
+
},
|
|
332
|
+
fromStatus: {
|
|
333
|
+
type: String,
|
|
334
|
+
enum: ZRBTenantSubscriptionStatus.options
|
|
335
|
+
},
|
|
336
|
+
toStatus: {
|
|
337
|
+
type: String,
|
|
338
|
+
enum: ZRBTenantSubscriptionStatus.options
|
|
339
|
+
},
|
|
340
|
+
fromModules: {
|
|
341
|
+
type: [String],
|
|
342
|
+
default: void 0
|
|
343
|
+
},
|
|
344
|
+
toModules: {
|
|
345
|
+
type: [String],
|
|
346
|
+
default: void 0
|
|
347
|
+
},
|
|
348
|
+
fromIntervalUnit: {
|
|
349
|
+
type: String,
|
|
350
|
+
enum: ZRBTenantSubscriptionIntervalUnit.options
|
|
351
|
+
},
|
|
352
|
+
toIntervalUnit: {
|
|
353
|
+
type: String,
|
|
354
|
+
enum: ZRBTenantSubscriptionIntervalUnit.options
|
|
355
|
+
},
|
|
356
|
+
fromIntervalCount: {
|
|
357
|
+
type: Number,
|
|
358
|
+
min: 1
|
|
359
|
+
},
|
|
360
|
+
toIntervalCount: {
|
|
361
|
+
type: Number,
|
|
362
|
+
min: 1
|
|
363
|
+
},
|
|
364
|
+
direction: {
|
|
365
|
+
type: String,
|
|
366
|
+
enum: ZRBTenantSubscriptionChangeDirection.options
|
|
367
|
+
},
|
|
368
|
+
actorUserId: {
|
|
369
|
+
type: String
|
|
370
|
+
},
|
|
371
|
+
source: {
|
|
372
|
+
type: String,
|
|
373
|
+
enum: ZRBTenantSubscriptionEventSource.options
|
|
374
|
+
},
|
|
375
|
+
reason: {
|
|
376
|
+
type: String
|
|
377
|
+
},
|
|
378
|
+
provider: {
|
|
379
|
+
type: String
|
|
380
|
+
},
|
|
381
|
+
providerEventId: {
|
|
382
|
+
type: String
|
|
383
|
+
},
|
|
384
|
+
providerPayload: {
|
|
385
|
+
type: Schema$1.Types.Mixed
|
|
386
|
+
},
|
|
387
|
+
metadata: {
|
|
388
|
+
type: Schema$1.Types.Mixed
|
|
389
|
+
}
|
|
390
|
+
});
|
|
391
|
+
RBTenantSubscriptionEventSchema.index({
|
|
392
|
+
tenantId: 1,
|
|
393
|
+
subscriptionId: 1,
|
|
394
|
+
occurredAt: 1
|
|
395
|
+
});
|
|
396
|
+
RBTenantSubscriptionEventSchema.index({
|
|
397
|
+
provider: 1,
|
|
398
|
+
providerEventId: 1
|
|
399
|
+
}, {
|
|
400
|
+
unique: true,
|
|
401
|
+
sparse: true
|
|
402
|
+
});
|
|
205
403
|
const ZRBRtsCounter = z.object({
|
|
206
404
|
_id: z.string(),
|
|
207
405
|
seq: z.number().int().min(0)
|
|
208
406
|
});
|
|
209
|
-
const RBRtsCounterSchema = new Schema$1(
|
|
210
|
-
{
|
|
211
|
-
|
|
212
|
-
|
|
407
|
+
const RBRtsCounterSchema = new Schema$1({
|
|
408
|
+
_id: {
|
|
409
|
+
type: String,
|
|
410
|
+
required: true
|
|
213
411
|
},
|
|
214
|
-
{
|
|
215
|
-
|
|
412
|
+
seq: {
|
|
413
|
+
type: Number,
|
|
414
|
+
required: true,
|
|
415
|
+
default: 0
|
|
216
416
|
}
|
|
217
|
-
|
|
417
|
+
}, {
|
|
418
|
+
versionKey: false
|
|
419
|
+
});
|
|
218
420
|
const ttlSecondsRaw = process.env.RB_RTS_CHANGES_TTL_S ?? "";
|
|
219
421
|
const ttlSeconds = Number.isFinite(Number(ttlSecondsRaw)) ? Math.max(60, Math.floor(Number(ttlSecondsRaw))) : 60 * 60 * 24 * 30;
|
|
220
422
|
const ZRBRtsChangeOp = z.enum(["delete", "reset_model"]);
|
|
@@ -225,20 +427,43 @@ const ZRBRtsChange = z.object({
|
|
|
225
427
|
docId: z.string().optional(),
|
|
226
428
|
ts: z.date()
|
|
227
429
|
});
|
|
228
|
-
const RBRtsChangeSchema = new Schema$1(
|
|
229
|
-
{
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
430
|
+
const RBRtsChangeSchema = new Schema$1({
|
|
431
|
+
seq: {
|
|
432
|
+
type: Number,
|
|
433
|
+
required: true
|
|
434
|
+
},
|
|
435
|
+
modelName: {
|
|
436
|
+
type: String,
|
|
437
|
+
required: true,
|
|
438
|
+
index: true
|
|
439
|
+
},
|
|
440
|
+
op: {
|
|
441
|
+
type: String,
|
|
442
|
+
required: true,
|
|
443
|
+
enum: ZRBRtsChangeOp.options
|
|
444
|
+
},
|
|
445
|
+
docId: {
|
|
446
|
+
type: String,
|
|
447
|
+
required: false
|
|
448
|
+
},
|
|
449
|
+
ts: {
|
|
450
|
+
type: Date,
|
|
451
|
+
required: true,
|
|
452
|
+
default: Date.now
|
|
453
|
+
}
|
|
454
|
+
}, {
|
|
455
|
+
versionKey: false
|
|
456
|
+
});
|
|
457
|
+
RBRtsChangeSchema.index({
|
|
458
|
+
seq: 1
|
|
459
|
+
}, {
|
|
460
|
+
unique: true
|
|
461
|
+
});
|
|
462
|
+
RBRtsChangeSchema.index({
|
|
463
|
+
ts: 1
|
|
464
|
+
}, {
|
|
465
|
+
expireAfterSeconds: ttlSeconds
|
|
466
|
+
});
|
|
242
467
|
const ZRBUploadSessionStatus = z.enum(["uploading", "assembling", "done", "error"]);
|
|
243
468
|
const ZRBUploadSession = z.object({
|
|
244
469
|
_id: z.string(),
|
|
@@ -256,42 +481,100 @@ const ZRBUploadSession = z.object({
|
|
|
256
481
|
isPublic: z.boolean().optional(),
|
|
257
482
|
error: z.string().optional()
|
|
258
483
|
});
|
|
259
|
-
const RBUploadSessionSchema = new Schema$1(
|
|
260
|
-
{
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
484
|
+
const RBUploadSessionSchema = new Schema$1({
|
|
485
|
+
_id: {
|
|
486
|
+
type: String,
|
|
487
|
+
required: true
|
|
488
|
+
},
|
|
489
|
+
userId: {
|
|
490
|
+
type: String,
|
|
491
|
+
required: false,
|
|
492
|
+
index: true
|
|
493
|
+
},
|
|
494
|
+
ownerKeyHash: {
|
|
495
|
+
type: String,
|
|
496
|
+
required: false
|
|
497
|
+
},
|
|
498
|
+
filename: {
|
|
499
|
+
type: String,
|
|
500
|
+
required: true
|
|
501
|
+
},
|
|
502
|
+
mimeType: {
|
|
503
|
+
type: String,
|
|
504
|
+
required: true
|
|
505
|
+
},
|
|
506
|
+
totalSize: {
|
|
507
|
+
type: Number,
|
|
508
|
+
required: true
|
|
509
|
+
},
|
|
510
|
+
chunkSize: {
|
|
511
|
+
type: Number,
|
|
512
|
+
required: true
|
|
513
|
+
},
|
|
514
|
+
chunksTotal: {
|
|
515
|
+
type: Number,
|
|
516
|
+
required: true
|
|
517
|
+
},
|
|
518
|
+
status: {
|
|
519
|
+
type: String,
|
|
520
|
+
required: true,
|
|
521
|
+
enum: ZRBUploadSessionStatus.options
|
|
522
|
+
},
|
|
523
|
+
createdAt: {
|
|
524
|
+
type: Date,
|
|
525
|
+
required: true,
|
|
526
|
+
default: Date.now
|
|
527
|
+
},
|
|
528
|
+
expiresAt: {
|
|
529
|
+
type: Date,
|
|
530
|
+
required: true
|
|
531
|
+
},
|
|
532
|
+
fileId: {
|
|
533
|
+
type: String,
|
|
534
|
+
required: false
|
|
535
|
+
},
|
|
536
|
+
isPublic: {
|
|
537
|
+
type: Boolean,
|
|
538
|
+
required: false
|
|
539
|
+
},
|
|
540
|
+
error: {
|
|
541
|
+
type: String,
|
|
542
|
+
required: false
|
|
543
|
+
}
|
|
544
|
+
}, {
|
|
545
|
+
versionKey: false
|
|
546
|
+
});
|
|
547
|
+
RBUploadSessionSchema.index({
|
|
548
|
+
expiresAt: 1
|
|
549
|
+
}, {
|
|
550
|
+
expireAfterSeconds: 0
|
|
551
|
+
});
|
|
281
552
|
const RBUploadSessionPolicy = {
|
|
282
553
|
subject: "RBUploadSession",
|
|
283
554
|
define: (builder, ctx) => {
|
|
284
555
|
builder.can("create", "RBUploadSession");
|
|
285
556
|
if (ctx.userId) {
|
|
286
|
-
builder.can("read", "RBUploadSession", {
|
|
287
|
-
|
|
288
|
-
|
|
557
|
+
builder.can("read", "RBUploadSession", {
|
|
558
|
+
userId: ctx.userId
|
|
559
|
+
});
|
|
560
|
+
builder.can("update", "RBUploadSession", {
|
|
561
|
+
userId: ctx.userId
|
|
562
|
+
});
|
|
563
|
+
builder.can("delete", "RBUploadSession", {
|
|
564
|
+
userId: ctx.userId
|
|
565
|
+
});
|
|
289
566
|
}
|
|
290
567
|
const uploadKeyHash = typeof ctx.claims?.uploadKeyHash === "string" ? ctx.claims.uploadKeyHash.trim() : "";
|
|
291
568
|
if (uploadKeyHash) {
|
|
292
|
-
builder.can("read", "RBUploadSession", {
|
|
293
|
-
|
|
294
|
-
|
|
569
|
+
builder.can("read", "RBUploadSession", {
|
|
570
|
+
ownerKeyHash: uploadKeyHash
|
|
571
|
+
});
|
|
572
|
+
builder.can("update", "RBUploadSession", {
|
|
573
|
+
ownerKeyHash: uploadKeyHash
|
|
574
|
+
});
|
|
575
|
+
builder.can("delete", "RBUploadSession", {
|
|
576
|
+
ownerKeyHash: uploadKeyHash
|
|
577
|
+
});
|
|
295
578
|
}
|
|
296
579
|
}
|
|
297
580
|
};
|
|
@@ -304,22 +587,51 @@ const ZRBUploadChunk = z.object({
|
|
|
304
587
|
createdAt: z.date(),
|
|
305
588
|
expiresAt: z.date()
|
|
306
589
|
});
|
|
307
|
-
const RBUploadChunkSchema = new Schema$1(
|
|
308
|
-
{
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
},
|
|
317
|
-
{
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
590
|
+
const RBUploadChunkSchema = new Schema$1({
|
|
591
|
+
uploadId: {
|
|
592
|
+
type: String,
|
|
593
|
+
required: true,
|
|
594
|
+
index: true
|
|
595
|
+
},
|
|
596
|
+
index: {
|
|
597
|
+
type: Number,
|
|
598
|
+
required: true
|
|
599
|
+
},
|
|
600
|
+
data: {
|
|
601
|
+
type: Buffer,
|
|
602
|
+
required: true
|
|
603
|
+
},
|
|
604
|
+
size: {
|
|
605
|
+
type: Number,
|
|
606
|
+
required: true
|
|
607
|
+
},
|
|
608
|
+
sha256: {
|
|
609
|
+
type: String,
|
|
610
|
+
required: false
|
|
611
|
+
},
|
|
612
|
+
createdAt: {
|
|
613
|
+
type: Date,
|
|
614
|
+
required: true,
|
|
615
|
+
default: Date.now
|
|
616
|
+
},
|
|
617
|
+
expiresAt: {
|
|
618
|
+
type: Date,
|
|
619
|
+
required: true
|
|
620
|
+
}
|
|
621
|
+
}, {
|
|
622
|
+
versionKey: false
|
|
623
|
+
});
|
|
624
|
+
RBUploadChunkSchema.index({
|
|
625
|
+
uploadId: 1,
|
|
626
|
+
index: 1
|
|
627
|
+
}, {
|
|
628
|
+
unique: true
|
|
629
|
+
});
|
|
630
|
+
RBUploadChunkSchema.index({
|
|
631
|
+
expiresAt: 1
|
|
632
|
+
}, {
|
|
633
|
+
expireAfterSeconds: 0
|
|
634
|
+
});
|
|
323
635
|
const ZRBNotification = z.object({
|
|
324
636
|
userId: z.string(),
|
|
325
637
|
topic: z.string().optional(),
|
|
@@ -333,35 +645,92 @@ const ZRBNotification = z.object({
|
|
|
333
645
|
metadata: z.record(z.string(), z.unknown()).optional()
|
|
334
646
|
});
|
|
335
647
|
const TTL_90_DAYS_S = 60 * 60 * 24 * 90;
|
|
336
|
-
const RBNotificationSchema = new Schema$1(
|
|
337
|
-
{
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
648
|
+
const RBNotificationSchema = new Schema$1({
|
|
649
|
+
userId: {
|
|
650
|
+
type: String,
|
|
651
|
+
required: true,
|
|
652
|
+
index: true
|
|
653
|
+
},
|
|
654
|
+
topic: {
|
|
655
|
+
type: String,
|
|
656
|
+
required: false,
|
|
657
|
+
index: true
|
|
658
|
+
},
|
|
659
|
+
title: {
|
|
660
|
+
type: String,
|
|
661
|
+
required: true
|
|
662
|
+
},
|
|
663
|
+
body: {
|
|
664
|
+
type: String,
|
|
665
|
+
required: false
|
|
666
|
+
},
|
|
667
|
+
url: {
|
|
668
|
+
type: String,
|
|
669
|
+
required: false
|
|
670
|
+
},
|
|
671
|
+
createdAt: {
|
|
672
|
+
type: Date,
|
|
673
|
+
required: true,
|
|
674
|
+
default: Date.now,
|
|
675
|
+
index: true
|
|
676
|
+
},
|
|
677
|
+
seenAt: {
|
|
678
|
+
type: Date,
|
|
679
|
+
required: false,
|
|
680
|
+
index: true
|
|
681
|
+
},
|
|
682
|
+
readAt: {
|
|
683
|
+
type: Date,
|
|
684
|
+
required: false,
|
|
685
|
+
index: true
|
|
686
|
+
},
|
|
687
|
+
archivedAt: {
|
|
688
|
+
type: Date,
|
|
689
|
+
required: false
|
|
690
|
+
},
|
|
691
|
+
metadata: {
|
|
692
|
+
type: Schema$1.Types.Mixed,
|
|
693
|
+
required: false
|
|
694
|
+
}
|
|
695
|
+
}, {
|
|
696
|
+
versionKey: false
|
|
697
|
+
});
|
|
698
|
+
RBNotificationSchema.index({
|
|
699
|
+
userId: 1,
|
|
700
|
+
archivedAt: 1,
|
|
701
|
+
createdAt: -1
|
|
702
|
+
});
|
|
703
|
+
RBNotificationSchema.index({
|
|
704
|
+
userId: 1,
|
|
705
|
+
seenAt: 1,
|
|
706
|
+
archivedAt: 1,
|
|
707
|
+
createdAt: -1
|
|
708
|
+
});
|
|
709
|
+
RBNotificationSchema.index({
|
|
710
|
+
userId: 1,
|
|
711
|
+
readAt: 1,
|
|
712
|
+
archivedAt: 1,
|
|
713
|
+
createdAt: -1
|
|
714
|
+
});
|
|
715
|
+
RBNotificationSchema.index({
|
|
716
|
+
archivedAt: 1
|
|
717
|
+
}, {
|
|
718
|
+
expireAfterSeconds: TTL_90_DAYS_S
|
|
719
|
+
});
|
|
357
720
|
const RBNotificationPolicy = {
|
|
358
721
|
subject: "RBNotification",
|
|
359
722
|
define: (builder, ctx) => {
|
|
360
723
|
if (!ctx.userId) return;
|
|
361
724
|
builder.can("create", "RBNotification");
|
|
362
|
-
builder.can("read", "RBNotification", {
|
|
363
|
-
|
|
364
|
-
|
|
725
|
+
builder.can("read", "RBNotification", {
|
|
726
|
+
userId: ctx.userId
|
|
727
|
+
});
|
|
728
|
+
builder.can("update", "RBNotification", {
|
|
729
|
+
userId: ctx.userId
|
|
730
|
+
});
|
|
731
|
+
builder.can("delete", "RBNotification", {
|
|
732
|
+
userId: ctx.userId
|
|
733
|
+
});
|
|
365
734
|
}
|
|
366
735
|
};
|
|
367
736
|
const ZRBNotificationDigestFrequency = z.enum(["off", "daily", "weekly"]);
|
|
@@ -377,44 +746,72 @@ const ZRBNotificationSettings = z.object({
|
|
|
377
746
|
topicPreferences: z.array(ZRBNotificationTopicPreference).optional(),
|
|
378
747
|
lastDigestSentAt: z.date().optional()
|
|
379
748
|
});
|
|
380
|
-
const TopicPreferenceSchema = new Schema$1(
|
|
381
|
-
{
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
{
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
749
|
+
const TopicPreferenceSchema = new Schema$1({
|
|
750
|
+
topic: {
|
|
751
|
+
type: String,
|
|
752
|
+
required: true
|
|
753
|
+
},
|
|
754
|
+
inApp: {
|
|
755
|
+
type: Boolean,
|
|
756
|
+
required: true,
|
|
757
|
+
default: true
|
|
758
|
+
},
|
|
759
|
+
emailDigest: {
|
|
760
|
+
type: Boolean,
|
|
761
|
+
required: true,
|
|
762
|
+
default: true
|
|
763
|
+
},
|
|
764
|
+
push: {
|
|
765
|
+
type: Boolean,
|
|
766
|
+
required: true,
|
|
767
|
+
default: false
|
|
768
|
+
}
|
|
769
|
+
}, {
|
|
770
|
+
_id: false
|
|
771
|
+
});
|
|
772
|
+
const RBNotificationSettingsSchema = new Schema$1({
|
|
773
|
+
userId: {
|
|
774
|
+
type: String,
|
|
775
|
+
required: true
|
|
776
|
+
},
|
|
777
|
+
digestFrequency: {
|
|
778
|
+
type: String,
|
|
779
|
+
required: true,
|
|
780
|
+
enum: ZRBNotificationDigestFrequency.options,
|
|
781
|
+
default: "weekly"
|
|
782
|
+
},
|
|
783
|
+
topicPreferences: {
|
|
784
|
+
type: [TopicPreferenceSchema],
|
|
785
|
+
default: []
|
|
403
786
|
},
|
|
404
|
-
{
|
|
405
|
-
|
|
406
|
-
|
|
787
|
+
lastDigestSentAt: {
|
|
788
|
+
type: Date,
|
|
789
|
+
required: false
|
|
407
790
|
}
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
791
|
+
}, {
|
|
792
|
+
versionKey: false,
|
|
793
|
+
timestamps: true
|
|
794
|
+
});
|
|
795
|
+
RBNotificationSettingsSchema.index({
|
|
796
|
+
userId: 1
|
|
797
|
+
}, {
|
|
798
|
+
unique: true
|
|
799
|
+
});
|
|
800
|
+
RBNotificationSettingsSchema.index({
|
|
801
|
+
userId: 1,
|
|
802
|
+
"topicPreferences.topic": 1
|
|
803
|
+
});
|
|
411
804
|
const RBNotificationSettingsPolicy = {
|
|
412
805
|
subject: "RBNotificationSettings",
|
|
413
806
|
define: (builder, ctx) => {
|
|
414
807
|
if (!ctx.userId) return;
|
|
415
808
|
builder.can("create", "RBNotificationSettings");
|
|
416
|
-
builder.can("read", "RBNotificationSettings", {
|
|
417
|
-
|
|
809
|
+
builder.can("read", "RBNotificationSettings", {
|
|
810
|
+
userId: ctx.userId
|
|
811
|
+
});
|
|
812
|
+
builder.can("update", "RBNotificationSettings", {
|
|
813
|
+
userId: ctx.userId
|
|
814
|
+
});
|
|
418
815
|
}
|
|
419
816
|
};
|
|
420
817
|
const ZRBOAuthRequest = z.object({
|
|
@@ -425,18 +822,41 @@ const ZRBOAuthRequest = z.object({
|
|
|
425
822
|
createdAt: z.date(),
|
|
426
823
|
expiresAt: z.date()
|
|
427
824
|
});
|
|
428
|
-
const RBOAuthRequestSchema = new Schema$1(
|
|
429
|
-
{
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
825
|
+
const RBOAuthRequestSchema = new Schema$1({
|
|
826
|
+
_id: {
|
|
827
|
+
type: String,
|
|
828
|
+
required: true
|
|
829
|
+
},
|
|
830
|
+
providerId: {
|
|
831
|
+
type: String,
|
|
832
|
+
required: true,
|
|
833
|
+
index: true
|
|
834
|
+
},
|
|
835
|
+
codeVerifier: {
|
|
836
|
+
type: String,
|
|
837
|
+
required: true
|
|
838
|
+
},
|
|
839
|
+
returnTo: {
|
|
840
|
+
type: String,
|
|
841
|
+
required: false
|
|
842
|
+
},
|
|
843
|
+
createdAt: {
|
|
844
|
+
type: Date,
|
|
845
|
+
required: true,
|
|
846
|
+
default: Date.now
|
|
847
|
+
},
|
|
848
|
+
expiresAt: {
|
|
849
|
+
type: Date,
|
|
850
|
+
required: true
|
|
851
|
+
}
|
|
852
|
+
}, {
|
|
853
|
+
versionKey: false
|
|
854
|
+
});
|
|
855
|
+
RBOAuthRequestSchema.index({
|
|
856
|
+
expiresAt: 1
|
|
857
|
+
}, {
|
|
858
|
+
expireAfterSeconds: 0
|
|
859
|
+
});
|
|
440
860
|
const frameworkSchemas = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
441
861
|
__proto__: null,
|
|
442
862
|
RBNotificationPolicy,
|
|
@@ -493,7 +913,10 @@ function localizedStringField(options) {
|
|
|
493
913
|
get: (value) => withLocalizedStringFallback(userGet ? userGet(value) : value)
|
|
494
914
|
};
|
|
495
915
|
}
|
|
496
|
-
const {
|
|
916
|
+
const {
|
|
917
|
+
Schema,
|
|
918
|
+
model
|
|
919
|
+
} = mongoose;
|
|
497
920
|
class PaginationValidationError extends Error {
|
|
498
921
|
code = "invalid_pagination";
|
|
499
922
|
statusCode = 400;
|
|
@@ -515,18 +938,26 @@ const normalizePaginationSpec = (spec) => {
|
|
|
515
938
|
const direction = spec.direction ?? "next";
|
|
516
939
|
if (direction !== "next" && direction !== "prev") throw new PaginationValidationError("Invalid pagination direction");
|
|
517
940
|
if (!Array.isArray(spec.sort) || spec.sort.length === 0) throw new PaginationValidationError("Invalid pagination sort");
|
|
518
|
-
const sort = spec.sort.map(({
|
|
941
|
+
const sort = spec.sort.map(({
|
|
942
|
+
field,
|
|
943
|
+
order
|
|
944
|
+
}) => ({
|
|
519
945
|
field: assertSafeMongoFieldPath(field),
|
|
520
946
|
order: normalizeOrder(order)
|
|
521
947
|
}));
|
|
522
948
|
const seenFields = /* @__PURE__ */ new Set();
|
|
523
|
-
for (const {
|
|
949
|
+
for (const {
|
|
950
|
+
field
|
|
951
|
+
} of sort) {
|
|
524
952
|
if (seenFields.has(field)) throw new PaginationValidationError(`Duplicate pagination sort field: ${field}`);
|
|
525
953
|
seenFields.add(field);
|
|
526
954
|
}
|
|
527
955
|
const primaryOrder = sort[0]?.order;
|
|
528
956
|
if (!seenFields.has("_id")) {
|
|
529
|
-
sort.push({
|
|
957
|
+
sort.push({
|
|
958
|
+
field: "_id",
|
|
959
|
+
order: primaryOrder
|
|
960
|
+
});
|
|
530
961
|
}
|
|
531
962
|
return {
|
|
532
963
|
...spec,
|
|
@@ -562,14 +993,19 @@ const assertSafeMongoFieldPath = (field) => {
|
|
|
562
993
|
const encodePaginationCursor = (spec, node, options) => {
|
|
563
994
|
const normalized = normalizePaginationSpec(spec);
|
|
564
995
|
const values = /* @__PURE__ */ Object.create(null);
|
|
565
|
-
for (const {
|
|
996
|
+
for (const {
|
|
997
|
+
field
|
|
998
|
+
} of normalized.sort) {
|
|
566
999
|
const value = readFieldValue(node, field);
|
|
567
1000
|
if (typeof value === "undefined") {
|
|
568
1001
|
throw new Error(`Pagination cursor encode failed (missing field: ${field})`);
|
|
569
1002
|
}
|
|
570
1003
|
values[field] = encodeCursorValue(field, value);
|
|
571
1004
|
}
|
|
572
|
-
const payload = {
|
|
1005
|
+
const payload = {
|
|
1006
|
+
v: 1,
|
|
1007
|
+
values
|
|
1008
|
+
};
|
|
573
1009
|
const payloadB64 = Buffer.from(JSON.stringify(payload), "utf8").toString("base64url");
|
|
574
1010
|
const sigB64 = signCursorPayloadB64(payloadB64, options.signingSecret);
|
|
575
1011
|
return `${payloadB64}.${sigB64}`;
|
|
@@ -592,7 +1028,9 @@ const decodePaginationCursor = (spec, cursor, options) => {
|
|
|
592
1028
|
if (payload.v !== 1) throw new PaginationValidationError("Unsupported pagination cursor version");
|
|
593
1029
|
if (!payload.values || typeof payload.values !== "object") throw new PaginationValidationError("Invalid pagination cursor payload");
|
|
594
1030
|
const decoded = /* @__PURE__ */ Object.create(null);
|
|
595
|
-
for (const {
|
|
1031
|
+
for (const {
|
|
1032
|
+
field
|
|
1033
|
+
} of normalized.sort) {
|
|
596
1034
|
if (!Object.prototype.hasOwnProperty.call(payload.values, field)) {
|
|
597
1035
|
throw new PaginationValidationError(`Pagination cursor missing field: ${field}`);
|
|
598
1036
|
}
|
|
@@ -615,18 +1053,24 @@ const verifyCursorSignature = (payloadB64, sigB64, secret) => {
|
|
|
615
1053
|
const encodeCursorValue = (field, value) => {
|
|
616
1054
|
if (value === null) return null;
|
|
617
1055
|
if (field === "_id") {
|
|
618
|
-
if (value instanceof Types.ObjectId) return {
|
|
619
|
-
|
|
1056
|
+
if (value instanceof Types.ObjectId) return {
|
|
1057
|
+
$oid: value.toHexString()
|
|
1058
|
+
};
|
|
1059
|
+
if (typeof value === "string") return value;
|
|
1060
|
+
throw new Error("Pagination cursor encode failed (_id must be an ObjectId or string)");
|
|
620
1061
|
}
|
|
621
|
-
if (value instanceof Date) return {
|
|
1062
|
+
if (value instanceof Date) return {
|
|
1063
|
+
$date: value.toISOString()
|
|
1064
|
+
};
|
|
622
1065
|
if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") return value;
|
|
623
|
-
if (value instanceof Types.ObjectId) return {
|
|
1066
|
+
if (value instanceof Types.ObjectId) return {
|
|
1067
|
+
$oid: value.toHexString()
|
|
1068
|
+
};
|
|
624
1069
|
throw new Error(`Unsupported pagination cursor value type for field: ${field}`);
|
|
625
1070
|
};
|
|
626
1071
|
const decodeCursorValue = (field, value) => {
|
|
627
1072
|
if (value === null) return null;
|
|
628
1073
|
if (typeof value === "string") {
|
|
629
|
-
if (field === "_id") throw new PaginationValidationError(`Invalid pagination cursor ObjectId for field: ${field}`);
|
|
630
1074
|
return value;
|
|
631
1075
|
}
|
|
632
1076
|
if (typeof value === "number" || typeof value === "boolean") return value;
|
|
@@ -681,7 +1125,10 @@ const compileMongoPagination = (spec, options) => {
|
|
|
681
1125
|
};
|
|
682
1126
|
const toMongoSort = (spec) => {
|
|
683
1127
|
const mongoSort = /* @__PURE__ */ Object.create(null);
|
|
684
|
-
for (const {
|
|
1128
|
+
for (const {
|
|
1129
|
+
field,
|
|
1130
|
+
order
|
|
1131
|
+
} of spec.sort) {
|
|
685
1132
|
const forQueryOrder = spec.direction === "prev" ? invertOrder(order) : order;
|
|
686
1133
|
mongoSort[field] = forQueryOrder === "asc" ? 1 : -1;
|
|
687
1134
|
}
|
|
@@ -706,9 +1153,13 @@ const buildKeysetFilterDelta = (spec, cursorValues) => {
|
|
|
706
1153
|
const cmp = /* @__PURE__ */ Object.create(null);
|
|
707
1154
|
cmp[current.field] = cmpOp;
|
|
708
1155
|
and.push(cmp);
|
|
709
|
-
branches.push(and.length === 1 ? and[0] : {
|
|
1156
|
+
branches.push(and.length === 1 ? and[0] : {
|
|
1157
|
+
$and: and
|
|
1158
|
+
});
|
|
710
1159
|
}
|
|
711
|
-
return {
|
|
1160
|
+
return {
|
|
1161
|
+
$or: branches
|
|
1162
|
+
};
|
|
712
1163
|
};
|
|
713
1164
|
const getKeysetOp = (order, direction) => {
|
|
714
1165
|
if (direction === "next") return order === "asc" ? "$gt" : "$lt";
|
|
@@ -729,7 +1180,10 @@ const materializeMongoPagination = (compiled, fetchedNodes, options) => {
|
|
|
729
1180
|
hasPrevPage
|
|
730
1181
|
};
|
|
731
1182
|
if (nodes.length === 0) {
|
|
732
|
-
return {
|
|
1183
|
+
return {
|
|
1184
|
+
nodes,
|
|
1185
|
+
pageInfo
|
|
1186
|
+
};
|
|
733
1187
|
}
|
|
734
1188
|
if (hasPrevPage) {
|
|
735
1189
|
pageInfo.prevCursor = encodePaginationCursor(compiled.spec, nodes[0], options.cursor);
|
|
@@ -737,7 +1191,10 @@ const materializeMongoPagination = (compiled, fetchedNodes, options) => {
|
|
|
737
1191
|
if (hasNextPage) {
|
|
738
1192
|
pageInfo.nextCursor = encodePaginationCursor(compiled.spec, nodes[nodes.length - 1], options.cursor);
|
|
739
1193
|
}
|
|
740
|
-
return {
|
|
1194
|
+
return {
|
|
1195
|
+
nodes,
|
|
1196
|
+
pageInfo
|
|
1197
|
+
};
|
|
741
1198
|
};
|
|
742
1199
|
const MongoAdapter = {
|
|
743
1200
|
applyPagination: (query, compiled) => {
|
|
@@ -748,13 +1205,17 @@ const MongoAdapter = {
|
|
|
748
1205
|
}
|
|
749
1206
|
};
|
|
750
1207
|
const paginateMongoQuery = async (query, pagination, options) => {
|
|
751
|
-
const compiled = compileMongoPagination(pagination, {
|
|
1208
|
+
const compiled = compileMongoPagination(pagination, {
|
|
1209
|
+
cursor: options.cursor
|
|
1210
|
+
});
|
|
752
1211
|
MongoAdapter.applyPagination(query, compiled);
|
|
753
1212
|
const fetchedNodes = await query.exec();
|
|
754
1213
|
if (!Array.isArray(fetchedNodes)) {
|
|
755
1214
|
throw new Error("paginateMongoQuery expects query.exec() to return an array");
|
|
756
1215
|
}
|
|
757
|
-
return materializeMongoPagination(compiled, fetchedNodes, {
|
|
1216
|
+
return materializeMongoPagination(compiled, fetchedNodes, {
|
|
1217
|
+
cursor: options.cursor
|
|
1218
|
+
});
|
|
758
1219
|
};
|
|
759
1220
|
const getQueryOptions$1 = (query) => {
|
|
760
1221
|
if (!query || typeof query !== "object") return void 0;
|
|
@@ -775,7 +1236,9 @@ const mongoPaginationPlugin = (schema, pluginOptions) => {
|
|
|
775
1236
|
if (!spec) throw new Error("Missing pagination spec");
|
|
776
1237
|
const cursor = options?.cursor ?? getCursorFromOptions(this) ?? pluginOptions?.cursor;
|
|
777
1238
|
if (!cursor?.signingSecret) throw new Error("Missing pagination cursor signingSecret");
|
|
778
|
-
return await paginateMongoQuery(this, spec, {
|
|
1239
|
+
return await paginateMongoQuery(this, spec, {
|
|
1240
|
+
cursor
|
|
1241
|
+
});
|
|
779
1242
|
};
|
|
780
1243
|
};
|
|
781
1244
|
const buildSearchTextStage = (options) => {
|
|
@@ -793,14 +1256,20 @@ const buildSearchTextStage = (options) => {
|
|
|
793
1256
|
}
|
|
794
1257
|
};
|
|
795
1258
|
if (options.highlightPath) {
|
|
796
|
-
stage.$search.highlight = {
|
|
1259
|
+
stage.$search.highlight = {
|
|
1260
|
+
path: options.highlightPath
|
|
1261
|
+
};
|
|
797
1262
|
}
|
|
798
1263
|
return stage;
|
|
799
1264
|
};
|
|
800
1265
|
const searchMetaProjection = () => {
|
|
801
1266
|
return {
|
|
802
|
-
score: {
|
|
803
|
-
|
|
1267
|
+
score: {
|
|
1268
|
+
$meta: "searchScore"
|
|
1269
|
+
},
|
|
1270
|
+
highlights: {
|
|
1271
|
+
$meta: "searchHighlights"
|
|
1272
|
+
}
|
|
804
1273
|
};
|
|
805
1274
|
};
|
|
806
1275
|
const listResultHasIndex = (listResult, name) => {
|
|
@@ -826,27 +1295,38 @@ const ensureSearchIndex = async (params) => {
|
|
|
826
1295
|
if (!name) throw new Error("Missing search index name");
|
|
827
1296
|
let listResult;
|
|
828
1297
|
try {
|
|
829
|
-
listResult = await params.db.command({
|
|
1298
|
+
listResult = await params.db.command({
|
|
1299
|
+
listSearchIndexes: collection
|
|
1300
|
+
});
|
|
830
1301
|
} catch (error) {
|
|
831
1302
|
const message = error instanceof Error ? error.message : String(error);
|
|
832
1303
|
throw new Error(`listSearchIndexes failed for "${collection}": ${message}`);
|
|
833
1304
|
}
|
|
834
1305
|
if (listResultHasIndex(listResult, name)) {
|
|
835
|
-
return {
|
|
1306
|
+
return {
|
|
1307
|
+
created: false
|
|
1308
|
+
};
|
|
836
1309
|
}
|
|
837
1310
|
try {
|
|
838
1311
|
await params.db.command({
|
|
839
1312
|
createSearchIndexes: collection,
|
|
840
|
-
indexes: [{
|
|
1313
|
+
indexes: [{
|
|
1314
|
+
name,
|
|
1315
|
+
definition: params.definition
|
|
1316
|
+
}]
|
|
841
1317
|
});
|
|
842
1318
|
} catch (error) {
|
|
843
1319
|
if (isIndexAlreadyExistsError(error)) {
|
|
844
|
-
return {
|
|
1320
|
+
return {
|
|
1321
|
+
created: false
|
|
1322
|
+
};
|
|
845
1323
|
}
|
|
846
1324
|
const message = error instanceof Error ? error.message : String(error);
|
|
847
1325
|
throw new Error(`createSearchIndexes failed for "${collection}" (index "${name}"): ${message}`);
|
|
848
1326
|
}
|
|
849
|
-
return {
|
|
1327
|
+
return {
|
|
1328
|
+
created: true
|
|
1329
|
+
};
|
|
850
1330
|
};
|
|
851
1331
|
const getAppName$1 = (env = process.env) => {
|
|
852
1332
|
const appName = env.APP_NAME?.trim();
|
|
@@ -899,7 +1379,9 @@ const ensureMongooseConnection = async (dbName) => {
|
|
|
899
1379
|
});
|
|
900
1380
|
}
|
|
901
1381
|
await waitForOpen(rootConnection);
|
|
902
|
-
const connection = rootConnection.name === normalizedDbName ? rootConnection : rootConnection.useDb(normalizedDbName, {
|
|
1382
|
+
const connection = rootConnection.name === normalizedDbName ? rootConnection : rootConnection.useDb(normalizedDbName, {
|
|
1383
|
+
useCache: true
|
|
1384
|
+
});
|
|
903
1385
|
await waitForOpen(connection);
|
|
904
1386
|
connections.set(normalizedDbName, connection);
|
|
905
1387
|
return connection;
|
|
@@ -937,22 +1419,42 @@ const getQuerySession = (query) => {
|
|
|
937
1419
|
const getRtsModels = (db) => {
|
|
938
1420
|
const RtsCounter = db.models.RBRtsCounter ?? db.model("RBRtsCounter", RBRtsCounterSchema);
|
|
939
1421
|
const RtsChange = db.models.RBRtsChange ?? db.model("RBRtsChange", RBRtsChangeSchema);
|
|
940
|
-
return {
|
|
1422
|
+
return {
|
|
1423
|
+
RtsCounter,
|
|
1424
|
+
RtsChange
|
|
1425
|
+
};
|
|
941
1426
|
};
|
|
942
1427
|
const allocateSeqRange = async (db, count, session) => {
|
|
943
|
-
const {
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
1428
|
+
const {
|
|
1429
|
+
RtsCounter
|
|
1430
|
+
} = getRtsModels(db);
|
|
1431
|
+
const updated = await RtsCounter.findOneAndUpdate({
|
|
1432
|
+
_id: RTS_COUNTER_ID
|
|
1433
|
+
}, {
|
|
1434
|
+
$inc: {
|
|
1435
|
+
seq: count
|
|
1436
|
+
}
|
|
1437
|
+
}, {
|
|
1438
|
+
upsert: true,
|
|
1439
|
+
new: true,
|
|
1440
|
+
setDefaultsOnInsert: true,
|
|
1441
|
+
projection: {
|
|
1442
|
+
seq: 1
|
|
1443
|
+
},
|
|
1444
|
+
session
|
|
1445
|
+
}).lean();
|
|
949
1446
|
const end = Number(updated?.seq ?? 0);
|
|
950
1447
|
const start = end - count + 1;
|
|
951
|
-
return {
|
|
1448
|
+
return {
|
|
1449
|
+
start,
|
|
1450
|
+
end
|
|
1451
|
+
};
|
|
952
1452
|
};
|
|
953
1453
|
const insertChanges = async (db, changes, session) => {
|
|
954
1454
|
if (!changes.length) return;
|
|
955
|
-
const {
|
|
1455
|
+
const {
|
|
1456
|
+
RtsChange
|
|
1457
|
+
} = getRtsModels(db);
|
|
956
1458
|
const ts = /* @__PURE__ */ new Date();
|
|
957
1459
|
const docs = changes.map((c3) => ({
|
|
958
1460
|
seq: c3.seq,
|
|
@@ -962,7 +1464,9 @@ const insertChanges = async (db, changes, session) => {
|
|
|
962
1464
|
ts
|
|
963
1465
|
}));
|
|
964
1466
|
if (session) {
|
|
965
|
-
await RtsChange.insertMany(docs, {
|
|
1467
|
+
await RtsChange.insertMany(docs, {
|
|
1468
|
+
session
|
|
1469
|
+
});
|
|
966
1470
|
return;
|
|
967
1471
|
}
|
|
968
1472
|
await RtsChange.insertMany(docs);
|
|
@@ -970,7 +1474,9 @@ const insertChanges = async (db, changes, session) => {
|
|
|
970
1474
|
const recordDeleteChanges = async (db, modelName, ids, session) => {
|
|
971
1475
|
const uniqueIds = Array.from(new Set(ids)).filter(Boolean);
|
|
972
1476
|
if (!uniqueIds.length) return;
|
|
973
|
-
const {
|
|
1477
|
+
const {
|
|
1478
|
+
start
|
|
1479
|
+
} = await allocateSeqRange(db, uniqueIds.length, session);
|
|
974
1480
|
await insertChanges(db, uniqueIds.map((docId, idx) => ({
|
|
975
1481
|
seq: start + idx,
|
|
976
1482
|
modelName,
|
|
@@ -979,8 +1485,14 @@ const recordDeleteChanges = async (db, modelName, ids, session) => {
|
|
|
979
1485
|
})), session);
|
|
980
1486
|
};
|
|
981
1487
|
const recordResetModel = async (db, modelName, session) => {
|
|
982
|
-
const {
|
|
983
|
-
|
|
1488
|
+
const {
|
|
1489
|
+
start
|
|
1490
|
+
} = await allocateSeqRange(db, 1, session);
|
|
1491
|
+
await insertChanges(db, [{
|
|
1492
|
+
seq: start,
|
|
1493
|
+
modelName,
|
|
1494
|
+
op: "reset_model"
|
|
1495
|
+
}], session);
|
|
984
1496
|
};
|
|
985
1497
|
const captureDeleteMeta = async (query, mode) => {
|
|
986
1498
|
const modelName = String(query?.model?.modelName ?? "");
|
|
@@ -988,7 +1500,9 @@ const captureDeleteMeta = async (query, mode) => {
|
|
|
988
1500
|
if (isGlobalDb(query?.model?.db)) return;
|
|
989
1501
|
const filter = typeof query.getFilter === "function" ? query.getFilter() : query.getQuery?.() ?? {};
|
|
990
1502
|
const session = getQuerySession(query);
|
|
991
|
-
const findQuery = query.model.find(filter, {
|
|
1503
|
+
const findQuery = query.model.find(filter, {
|
|
1504
|
+
_id: 1
|
|
1505
|
+
});
|
|
992
1506
|
if (session && typeof findQuery.session === "function") {
|
|
993
1507
|
findQuery.session(session);
|
|
994
1508
|
}
|
|
@@ -1027,19 +1541,34 @@ const flushDeleteMeta = async (query) => {
|
|
|
1027
1541
|
}
|
|
1028
1542
|
};
|
|
1029
1543
|
const rtsChangeLogPlugin = (schema) => {
|
|
1030
|
-
schema.pre("deleteOne", {
|
|
1544
|
+
schema.pre("deleteOne", {
|
|
1545
|
+
query: true,
|
|
1546
|
+
document: false
|
|
1547
|
+
}, async function() {
|
|
1031
1548
|
await captureDeleteMeta(this, "one");
|
|
1032
1549
|
});
|
|
1033
|
-
schema.pre("deleteMany", {
|
|
1550
|
+
schema.pre("deleteMany", {
|
|
1551
|
+
query: true,
|
|
1552
|
+
document: false
|
|
1553
|
+
}, async function() {
|
|
1034
1554
|
await captureDeleteMeta(this, "many");
|
|
1035
1555
|
});
|
|
1036
|
-
schema.post("deleteOne", {
|
|
1556
|
+
schema.post("deleteOne", {
|
|
1557
|
+
query: true,
|
|
1558
|
+
document: false
|
|
1559
|
+
}, async function() {
|
|
1037
1560
|
await flushDeleteMeta(this);
|
|
1038
1561
|
});
|
|
1039
|
-
schema.post("deleteMany", {
|
|
1562
|
+
schema.post("deleteMany", {
|
|
1563
|
+
query: true,
|
|
1564
|
+
document: false
|
|
1565
|
+
}, async function() {
|
|
1040
1566
|
await flushDeleteMeta(this);
|
|
1041
1567
|
});
|
|
1042
|
-
schema.post("findOneAndDelete", {
|
|
1568
|
+
schema.post("findOneAndDelete", {
|
|
1569
|
+
query: true,
|
|
1570
|
+
document: false
|
|
1571
|
+
}, async function(doc) {
|
|
1043
1572
|
const modelName = String(this?.model?.modelName ?? "");
|
|
1044
1573
|
if (!modelName || modelName.startsWith("RB") || EXCLUDED_MODEL_NAMES.has(modelName)) return;
|
|
1045
1574
|
const db = this?.model?.db;
|
|
@@ -1060,7 +1589,9 @@ const mergeMongoQuery = (left, right) => {
|
|
|
1060
1589
|
const leftQuery = isRecord(left) ? left : {};
|
|
1061
1590
|
if (Object.keys(leftQuery).length === 0) return right;
|
|
1062
1591
|
if (Object.keys(right).length === 0) return leftQuery;
|
|
1063
|
-
return {
|
|
1592
|
+
return {
|
|
1593
|
+
$and: [leftQuery, right]
|
|
1594
|
+
};
|
|
1064
1595
|
};
|
|
1065
1596
|
const getQueryOptions = (query) => {
|
|
1066
1597
|
if (!query || typeof query !== "object") return void 0;
|
|
@@ -1094,12 +1625,16 @@ const addQueryAclFilter = (query, action) => {
|
|
|
1094
1625
|
};
|
|
1095
1626
|
const injectAggregateMatch = (pipeline, match) => {
|
|
1096
1627
|
if (pipeline.length === 0) {
|
|
1097
|
-
pipeline.unshift({
|
|
1628
|
+
pipeline.unshift({
|
|
1629
|
+
$match: match
|
|
1630
|
+
});
|
|
1098
1631
|
return;
|
|
1099
1632
|
}
|
|
1100
1633
|
const first = pipeline[0];
|
|
1101
1634
|
if (!isRecord(first)) {
|
|
1102
|
-
pipeline.unshift({
|
|
1635
|
+
pipeline.unshift({
|
|
1636
|
+
$match: match
|
|
1637
|
+
});
|
|
1103
1638
|
return;
|
|
1104
1639
|
}
|
|
1105
1640
|
if ("$geoNear" in first) {
|
|
@@ -1110,10 +1645,14 @@ const injectAggregateMatch = (pipeline, match) => {
|
|
|
1110
1645
|
}
|
|
1111
1646
|
}
|
|
1112
1647
|
if ("$search" in first || "$vectorSearch" in first || "$searchMeta" in first) {
|
|
1113
|
-
pipeline.splice(1, 0, {
|
|
1648
|
+
pipeline.splice(1, 0, {
|
|
1649
|
+
$match: match
|
|
1650
|
+
});
|
|
1114
1651
|
return;
|
|
1115
1652
|
}
|
|
1116
|
-
pipeline.unshift({
|
|
1653
|
+
pipeline.unshift({
|
|
1654
|
+
$match: match
|
|
1655
|
+
});
|
|
1117
1656
|
};
|
|
1118
1657
|
const addAggregateAclFilter = (aggregate, action) => {
|
|
1119
1658
|
const storedAcl = getStoredAclFromAggregate(aggregate);
|
|
@@ -1132,7 +1671,12 @@ const patchAggregateAcl = () => {
|
|
|
1132
1671
|
const AggregatePrototype = mongoose.Aggregate.prototype;
|
|
1133
1672
|
if (typeof AggregatePrototype.acl === "function") return;
|
|
1134
1673
|
AggregatePrototype.acl = function(ability, action = "read") {
|
|
1135
|
-
this.option({
|
|
1674
|
+
this.option({
|
|
1675
|
+
rbAcl: {
|
|
1676
|
+
ability,
|
|
1677
|
+
action
|
|
1678
|
+
}
|
|
1679
|
+
});
|
|
1136
1680
|
return this;
|
|
1137
1681
|
};
|
|
1138
1682
|
};
|
|
@@ -1154,7 +1698,12 @@ const createModelAclProxy = (model2, ability) => {
|
|
|
1154
1698
|
const mongooseAclPlugin = (schema) => {
|
|
1155
1699
|
patchAggregateAcl();
|
|
1156
1700
|
schema.query.acl = function(ability, action) {
|
|
1157
|
-
this.setOptions({
|
|
1701
|
+
this.setOptions({
|
|
1702
|
+
rbAcl: {
|
|
1703
|
+
ability,
|
|
1704
|
+
action
|
|
1705
|
+
}
|
|
1706
|
+
});
|
|
1158
1707
|
return this;
|
|
1159
1708
|
};
|
|
1160
1709
|
schema.statics.acl = function(ability) {
|
|
@@ -1201,20 +1750,10 @@ const mongooseAclPlugin = (schema) => {
|
|
|
1201
1750
|
});
|
|
1202
1751
|
};
|
|
1203
1752
|
let cachedModels = null;
|
|
1204
|
-
const DEFAULT_GLOBAL_RB_MODEL_NAMES_SET = /* @__PURE__ */ new Set([
|
|
1205
|
-
"RBUser",
|
|
1206
|
-
"RBTenant",
|
|
1207
|
-
"RBOAuthRequest"
|
|
1208
|
-
]);
|
|
1753
|
+
const DEFAULT_GLOBAL_RB_MODEL_NAMES_SET = /* @__PURE__ */ new Set(["RBUser", "RBTenant", "RBOAuthRequest"]);
|
|
1209
1754
|
const assertSchema = (exportName, value) => {
|
|
1210
1755
|
if (value instanceof mongoose.Schema) return value;
|
|
1211
|
-
throw new Error(
|
|
1212
|
-
[
|
|
1213
|
-
`Expected ${exportName} to be an instance of mongoose.Schema, but it was not.`,
|
|
1214
|
-
"rpcbase supports mongoose 9+ only.",
|
|
1215
|
-
"Fix: ensure the project is using mongoose 9.x and that all packages resolve the same mongoose instance (try `npm ls mongoose`)."
|
|
1216
|
-
].join(" ")
|
|
1217
|
-
);
|
|
1756
|
+
throw new Error([`Expected ${exportName} to be an instance of mongoose.Schema, but it was not.`, "rpcbase supports mongoose 9+ only.", "Fix: ensure the project is using mongoose 9.x and that all packages resolve the same mongoose instance (try `npm ls mongoose`)."].join(" "));
|
|
1218
1757
|
};
|
|
1219
1758
|
const getFrameworkSchemaForModelName = (modelName) => {
|
|
1220
1759
|
const exportName = `${modelName}Schema`;
|
|
@@ -1237,14 +1776,23 @@ const registerSchema = (target, other, modelName, schema, scope) => {
|
|
|
1237
1776
|
const buildSchemasFromModules = (modules) => Object.entries(modules).filter(([key]) => key.endsWith("Schema")).map(([key, schemaValue]) => {
|
|
1238
1777
|
const schema = assertSchema(key, schemaValue);
|
|
1239
1778
|
const modelName = key.replace(/Schema$/, "");
|
|
1240
|
-
return {
|
|
1779
|
+
return {
|
|
1780
|
+
modelName,
|
|
1781
|
+
schema
|
|
1782
|
+
};
|
|
1241
1783
|
});
|
|
1242
|
-
const registerModels = ({
|
|
1784
|
+
const registerModels = ({
|
|
1785
|
+
tenant,
|
|
1786
|
+
global
|
|
1787
|
+
}) => {
|
|
1243
1788
|
registerPoliciesFromModules(frameworkSchemas);
|
|
1244
1789
|
registerPoliciesFromModules(tenant);
|
|
1245
1790
|
const tenantSchemas = {};
|
|
1246
1791
|
const globalSchemas = {};
|
|
1247
|
-
for (const {
|
|
1792
|
+
for (const {
|
|
1793
|
+
modelName,
|
|
1794
|
+
schema
|
|
1795
|
+
} of buildSchemasFromModules(frameworkSchemas)) {
|
|
1248
1796
|
if (DEFAULT_GLOBAL_RB_MODEL_NAMES_SET.has(modelName)) {
|
|
1249
1797
|
const cloned = schema.clone();
|
|
1250
1798
|
registerSchema(globalSchemas, tenantSchemas, modelName, cloned);
|
|
@@ -1254,7 +1802,10 @@ const registerModels = ({ tenant, global }) => {
|
|
|
1254
1802
|
registerSchema(tenantSchemas, globalSchemas, modelName, cloned);
|
|
1255
1803
|
}
|
|
1256
1804
|
}
|
|
1257
|
-
for (const {
|
|
1805
|
+
for (const {
|
|
1806
|
+
modelName,
|
|
1807
|
+
schema
|
|
1808
|
+
} of buildSchemasFromModules(tenant)) {
|
|
1258
1809
|
if (modelName === "RBUser" || modelName === "RBTenant") {
|
|
1259
1810
|
throw new Error(`Invalid tenant model name "${modelName}". RBUser/RBTenant are global models.`);
|
|
1260
1811
|
}
|
|
@@ -1267,7 +1818,10 @@ const registerModels = ({ tenant, global }) => {
|
|
|
1267
1818
|
applyTenantPlugins(cloned);
|
|
1268
1819
|
registerSchema(tenantSchemas, globalSchemas, modelName, cloned);
|
|
1269
1820
|
}
|
|
1270
|
-
for (const {
|
|
1821
|
+
for (const {
|
|
1822
|
+
modelName,
|
|
1823
|
+
schema
|
|
1824
|
+
} of buildSchemasFromModules(global ?? {})) {
|
|
1271
1825
|
if (modelName.startsWith("RB")) {
|
|
1272
1826
|
const frameworkSchema = getFrameworkSchemaForModelName(modelName);
|
|
1273
1827
|
if (frameworkSchema && schema === frameworkSchema) continue;
|
|
@@ -1276,15 +1830,24 @@ const registerModels = ({ tenant, global }) => {
|
|
|
1276
1830
|
const cloned = schema.clone();
|
|
1277
1831
|
registerSchema(globalSchemas, tenantSchemas, modelName, cloned);
|
|
1278
1832
|
}
|
|
1279
|
-
const allSchemas = {
|
|
1833
|
+
const allSchemas = {
|
|
1834
|
+
...globalSchemas,
|
|
1835
|
+
...tenantSchemas
|
|
1836
|
+
};
|
|
1280
1837
|
for (const [modelName, schema] of Object.entries(allSchemas)) {
|
|
1281
1838
|
if (!mongoose.models[modelName]) {
|
|
1282
1839
|
mongoose.model(modelName, schema);
|
|
1283
1840
|
}
|
|
1284
1841
|
}
|
|
1285
1842
|
cachedModels = {
|
|
1286
|
-
tenant: {
|
|
1287
|
-
|
|
1843
|
+
tenant: {
|
|
1844
|
+
...cachedModels?.tenant ?? {},
|
|
1845
|
+
...tenantSchemas
|
|
1846
|
+
},
|
|
1847
|
+
global: {
|
|
1848
|
+
...cachedModels?.global ?? {},
|
|
1849
|
+
...globalSchemas
|
|
1850
|
+
}
|
|
1288
1851
|
};
|
|
1289
1852
|
};
|
|
1290
1853
|
const getRegisteredModels = (scope) => {
|
|
@@ -1392,7 +1955,11 @@ async function withTransaction(scope, fn, options) {
|
|
|
1392
1955
|
const filesystemDb = await ensureMongooseConnection(filesystemDbName);
|
|
1393
1956
|
const session = await tenantDb.startSession();
|
|
1394
1957
|
const tenantCtx = typeof scope === "object" && "ctx" in scope ? scope.ctx : buildTenantLoadModelCtx(normalizedTenantId);
|
|
1395
|
-
const globalCtx = {
|
|
1958
|
+
const globalCtx = {
|
|
1959
|
+
req: {
|
|
1960
|
+
session: null
|
|
1961
|
+
}
|
|
1962
|
+
};
|
|
1396
1963
|
try {
|
|
1397
1964
|
return await session.withTransaction(async () => fn({
|
|
1398
1965
|
tenantId: normalizedTenantId,
|