@rpcbase/db 0.122.0 → 0.124.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 +109 -13
- package/dist/acl/index.js.map +1 -1
- package/dist/billingStorage.d.ts.map +1 -1
- package/dist/index.browser.js +2 -16
- package/dist/index.js +2128 -2395
- package/dist/index.js.map +1 -1
- package/dist/model.js +0 -2
- package/dist/models/RBTenantSubscriptionEvent.d.ts +343 -14
- package/dist/models/RBTenantSubscriptionEvent.d.ts.map +1 -1
- package/dist/mongo.js +34 -22
- package/dist/mongo.js.map +1 -1
- package/dist/zod-DSnhyNso.js +132 -0
- package/dist/zod-DSnhyNso.js.map +1 -0
- package/package.json +1 -1
- package/dist/can-B4pD_pnR.js +0 -132
- package/dist/can-B4pD_pnR.js.map +0 -1
- package/dist/index-DrIoUXc2.js +0 -142
- package/dist/index-DrIoUXc2.js.map +0 -1
- package/dist/index.browser.js.map +0 -1
- package/dist/model.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,2452 +1,2185 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import
|
|
4
|
-
import {
|
|
5
|
-
import { z } from "zod";
|
|
6
|
-
import { SUBSCRIPTION_STATUSES, SUBSCRIPTION_INTERVAL_UNITS, SUBSCRIPTION_TYPES, SUBSCRIPTION_SCOPES, SUBSCRIPTION_EVENT_TYPES } from "@rpcbase/billing";
|
|
7
|
-
import { timingSafeEqual, createHmac } from "node:crypto";
|
|
8
|
-
import { w as withLocalizedStringFallback } from "./index-DrIoUXc2.js";
|
|
9
|
-
import { E, a as a2, L, b as b2, e as e2, m, r, z as z2, c as c2, d as d2, f as f2 } from "./index-DrIoUXc2.js";
|
|
10
|
-
import assert from "assert";
|
|
11
|
-
import { getMongoUrl, getMongoDirectConnection } from "./mongo.js";
|
|
1
|
+
import { buildAbility, buildAbilityFromSession, can, getAccessibleByQuery, getRegisteredPolicies, getTenantRolesFromSessionUser, hasRegisteredPolicy, registerPoliciesFromModules, registerPolicy } from "./acl/index.js";
|
|
2
|
+
import { a as makeZE164Phone, c as buildLocaleFallbackChain, d as zI18nString, f as zLocalizedString, i as E164_PHONE_REGEX, l as resolveLocalizedString, n as extendZod, o as zE164Phone, r as E164_PHONE_OR_EMPTY_REGEX, s as LANGUAGE_CODE_REGEX, t as z, u as withLocalizedStringFallback } from "./zod-DSnhyNso.js";
|
|
3
|
+
import "./model.js";
|
|
4
|
+
import { getMongoDirectConnection, getMongoUrl } from "./mongo.js";
|
|
12
5
|
import { accessibleBy, accessibleRecordsPlugin } from "@casl/mongoose";
|
|
13
|
-
import "
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
6
|
+
import mongoose, { Schema as Schema$1, Types, default as mongoose$1 } from "mongoose";
|
|
7
|
+
import { z as z$1 } from "zod";
|
|
8
|
+
import { SUBSCRIPTION_CHANGE_DIRECTIONS, SUBSCRIPTION_EVENT_TYPES, SUBSCRIPTION_INTERVAL_UNITS, SUBSCRIPTION_SCOPES, SUBSCRIPTION_STATUSES, SUBSCRIPTION_TYPES } from "@rpcbase/billing";
|
|
9
|
+
import { createHmac, timingSafeEqual } from "node:crypto";
|
|
10
|
+
import assert from "assert";
|
|
11
|
+
//#region \0rolldown/runtime.js
|
|
12
|
+
var __defProp = Object.defineProperty;
|
|
13
|
+
var __exportAll = (all, no_symbols) => {
|
|
14
|
+
let target = {};
|
|
15
|
+
for (var name in all) __defProp(target, name, {
|
|
16
|
+
get: all[name],
|
|
17
|
+
enumerable: true
|
|
18
|
+
});
|
|
19
|
+
if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
|
|
20
|
+
return target;
|
|
21
|
+
};
|
|
22
|
+
//#endregion
|
|
23
|
+
//#region src/models/RBUser.ts
|
|
24
|
+
var ZRBUser = z$1.object({
|
|
25
|
+
email: z$1.string().email().optional(),
|
|
26
|
+
password: z$1.string(),
|
|
27
|
+
name: z$1.string().optional(),
|
|
28
|
+
phone: z$1.string().optional(),
|
|
29
|
+
tenants: z$1.array(z$1.string()),
|
|
30
|
+
tenantRoles: z$1.record(z$1.string(), z$1.array(z$1.string())).optional(),
|
|
31
|
+
oauthProviders: z$1.record(z$1.string(), z$1.object({
|
|
32
|
+
subject: z$1.string(),
|
|
33
|
+
email: z$1.string().email().optional(),
|
|
34
|
+
name: z$1.string().optional(),
|
|
35
|
+
accessToken: z$1.string().optional(),
|
|
36
|
+
refreshToken: z$1.string().optional(),
|
|
37
|
+
idToken: z$1.string().optional(),
|
|
38
|
+
scope: z$1.string().optional(),
|
|
39
|
+
tokenType: z$1.string().optional(),
|
|
40
|
+
expiresAt: z$1.date().optional(),
|
|
41
|
+
rawUserInfo: z$1.unknown().optional(),
|
|
42
|
+
createdAt: z$1.date().optional(),
|
|
43
|
+
updatedAt: z$1.date().optional()
|
|
44
|
+
})).optional(),
|
|
45
|
+
emailVerificationCode: z$1.string().length(6).optional(),
|
|
46
|
+
emailVerificationExpiresAt: z$1.date().optional(),
|
|
47
|
+
passwordResetCode: z$1.string().length(6).optional(),
|
|
48
|
+
passwordResetCodeExpiresAt: z$1.date().optional(),
|
|
49
|
+
passwordResetToken: z$1.string().optional(),
|
|
50
|
+
passwordResetTokenExpiresAt: z$1.date().optional()
|
|
41
51
|
});
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
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
|
-
required: false
|
|
149
|
-
}
|
|
52
|
+
var RBUserSchema = new Schema$1({
|
|
53
|
+
email: {
|
|
54
|
+
type: String,
|
|
55
|
+
unique: true,
|
|
56
|
+
sparse: true
|
|
57
|
+
},
|
|
58
|
+
phone: {
|
|
59
|
+
type: String,
|
|
60
|
+
unique: true,
|
|
61
|
+
sparse: true
|
|
62
|
+
},
|
|
63
|
+
password: {
|
|
64
|
+
type: String,
|
|
65
|
+
required: true
|
|
66
|
+
},
|
|
67
|
+
name: String,
|
|
68
|
+
tenants: {
|
|
69
|
+
type: [String],
|
|
70
|
+
index: true,
|
|
71
|
+
required: true
|
|
72
|
+
},
|
|
73
|
+
tenantRoles: {
|
|
74
|
+
type: Map,
|
|
75
|
+
of: [String],
|
|
76
|
+
required: false,
|
|
77
|
+
default: {}
|
|
78
|
+
},
|
|
79
|
+
oauthProviders: {
|
|
80
|
+
type: Map,
|
|
81
|
+
of: new Schema$1({
|
|
82
|
+
subject: {
|
|
83
|
+
type: String,
|
|
84
|
+
required: true
|
|
85
|
+
},
|
|
86
|
+
email: {
|
|
87
|
+
type: String,
|
|
88
|
+
required: false
|
|
89
|
+
},
|
|
90
|
+
name: {
|
|
91
|
+
type: String,
|
|
92
|
+
required: false
|
|
93
|
+
},
|
|
94
|
+
accessToken: {
|
|
95
|
+
type: String,
|
|
96
|
+
required: false
|
|
97
|
+
},
|
|
98
|
+
refreshToken: {
|
|
99
|
+
type: String,
|
|
100
|
+
required: false
|
|
101
|
+
},
|
|
102
|
+
idToken: {
|
|
103
|
+
type: String,
|
|
104
|
+
required: false
|
|
105
|
+
},
|
|
106
|
+
scope: {
|
|
107
|
+
type: String,
|
|
108
|
+
required: false
|
|
109
|
+
},
|
|
110
|
+
tokenType: {
|
|
111
|
+
type: String,
|
|
112
|
+
required: false
|
|
113
|
+
},
|
|
114
|
+
expiresAt: {
|
|
115
|
+
type: Date,
|
|
116
|
+
required: false
|
|
117
|
+
},
|
|
118
|
+
rawUserInfo: {
|
|
119
|
+
type: Schema$1.Types.Mixed,
|
|
120
|
+
required: false
|
|
121
|
+
},
|
|
122
|
+
createdAt: {
|
|
123
|
+
type: Date,
|
|
124
|
+
required: false
|
|
125
|
+
},
|
|
126
|
+
updatedAt: {
|
|
127
|
+
type: Date,
|
|
128
|
+
required: false
|
|
129
|
+
}
|
|
130
|
+
}, { _id: false }),
|
|
131
|
+
default: {},
|
|
132
|
+
required: false
|
|
133
|
+
},
|
|
134
|
+
emailVerificationCode: {
|
|
135
|
+
type: String,
|
|
136
|
+
required: false
|
|
137
|
+
},
|
|
138
|
+
emailVerificationExpiresAt: {
|
|
139
|
+
type: Date,
|
|
140
|
+
required: false
|
|
141
|
+
},
|
|
142
|
+
passwordResetCode: {
|
|
143
|
+
type: String,
|
|
144
|
+
required: false
|
|
145
|
+
},
|
|
146
|
+
passwordResetCodeExpiresAt: {
|
|
147
|
+
type: Date,
|
|
148
|
+
required: false
|
|
149
|
+
},
|
|
150
|
+
passwordResetToken: {
|
|
151
|
+
type: String,
|
|
152
|
+
required: false
|
|
153
|
+
},
|
|
154
|
+
passwordResetTokenExpiresAt: {
|
|
155
|
+
type: Date,
|
|
156
|
+
required: false
|
|
157
|
+
}
|
|
150
158
|
});
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
159
|
+
//#endregion
|
|
160
|
+
//#region src/models/RBTenant.ts
|
|
161
|
+
var ZRBTenant = z$1.object({
|
|
162
|
+
tenantId: z$1.string(),
|
|
163
|
+
parentTenantId: z$1.string().optional(),
|
|
164
|
+
name: z$1.string().optional()
|
|
155
165
|
});
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
},
|
|
166
|
-
name: {
|
|
167
|
-
type: String
|
|
168
|
-
}
|
|
166
|
+
var RBTenantSchema = new Schema$1({
|
|
167
|
+
tenantId: {
|
|
168
|
+
type: String,
|
|
169
|
+
required: true,
|
|
170
|
+
unique: true,
|
|
171
|
+
index: true
|
|
172
|
+
},
|
|
173
|
+
parentTenantId: { type: String },
|
|
174
|
+
name: { type: String }
|
|
169
175
|
});
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
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
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
176
|
+
//#endregion
|
|
177
|
+
//#region src/models/RBTenantSubscriptionEvent.ts
|
|
178
|
+
var ZRBTenantSubscriptionStatus = z$1.enum(SUBSCRIPTION_STATUSES);
|
|
179
|
+
var ZRBTenantSubscriptionIntervalUnit = z$1.enum(SUBSCRIPTION_INTERVAL_UNITS);
|
|
180
|
+
var ZRBTenantSubscriptionType = z$1.enum(SUBSCRIPTION_TYPES);
|
|
181
|
+
var ZRBTenantSubscriptionScope = z$1.enum(SUBSCRIPTION_SCOPES);
|
|
182
|
+
var ZRBTenantSubscriptionEventType = z$1.enum(SUBSCRIPTION_EVENT_TYPES);
|
|
183
|
+
var ZRBTenantSubscriptionEventSource = z$1.enum([
|
|
184
|
+
"admin",
|
|
185
|
+
"system",
|
|
186
|
+
"webhook",
|
|
187
|
+
"user"
|
|
188
|
+
]);
|
|
189
|
+
var ZRBTenantSubscriptionChangeDirection = z$1.enum(SUBSCRIPTION_CHANGE_DIRECTIONS);
|
|
190
|
+
var subscriptionEventBaseSchema = z$1.object({
|
|
191
|
+
tenantId: z$1.string().trim().min(1),
|
|
192
|
+
subscriptionId: z$1.string().trim().min(1),
|
|
193
|
+
occurredAt: z$1.date(),
|
|
194
|
+
effectiveAt: z$1.date(),
|
|
195
|
+
subscriptionType: ZRBTenantSubscriptionType,
|
|
196
|
+
parentSubscriptionId: z$1.string().optional(),
|
|
197
|
+
scope: ZRBTenantSubscriptionScope,
|
|
198
|
+
scopeId: z$1.string().optional(),
|
|
199
|
+
fromPlanKey: z$1.string().optional(),
|
|
200
|
+
toPlanKey: z$1.string().optional(),
|
|
201
|
+
fromStatus: ZRBTenantSubscriptionStatus.optional(),
|
|
202
|
+
toStatus: ZRBTenantSubscriptionStatus.optional(),
|
|
203
|
+
fromModules: z$1.array(z$1.string()).optional(),
|
|
204
|
+
toModules: z$1.array(z$1.string()).optional(),
|
|
205
|
+
fromIntervalUnit: ZRBTenantSubscriptionIntervalUnit.optional(),
|
|
206
|
+
toIntervalUnit: ZRBTenantSubscriptionIntervalUnit.optional(),
|
|
207
|
+
fromIntervalCount: z$1.number().int().min(1).optional(),
|
|
208
|
+
toIntervalCount: z$1.number().int().min(1).optional(),
|
|
209
|
+
fromPriceId: z$1.string().optional(),
|
|
210
|
+
toPriceId: z$1.string().optional(),
|
|
211
|
+
billingAnchor: z$1.date().optional(),
|
|
212
|
+
supersedesEventId: z$1.string().optional(),
|
|
213
|
+
idempotencyKey: z$1.string().trim().min(1),
|
|
214
|
+
direction: ZRBTenantSubscriptionChangeDirection.optional(),
|
|
215
|
+
actorUserId: z$1.string().optional(),
|
|
216
|
+
source: ZRBTenantSubscriptionEventSource.optional(),
|
|
217
|
+
reason: z$1.string().optional(),
|
|
218
|
+
provider: z$1.string().optional(),
|
|
219
|
+
providerEventId: z$1.string().optional(),
|
|
220
|
+
providerPayload: z$1.unknown().optional(),
|
|
221
|
+
metadata: z$1.record(z$1.string(), z$1.unknown()).optional()
|
|
210
222
|
});
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
required: true,
|
|
220
|
-
index: true
|
|
221
|
-
},
|
|
222
|
-
type: {
|
|
223
|
-
type: String,
|
|
224
|
-
required: true,
|
|
225
|
-
enum: ZRBTenantSubscriptionEventType.options
|
|
226
|
-
},
|
|
227
|
-
occurredAt: {
|
|
228
|
-
type: Date,
|
|
229
|
-
required: true,
|
|
230
|
-
default: Date.now
|
|
231
|
-
},
|
|
232
|
-
effectiveAt: {
|
|
233
|
-
type: Date,
|
|
234
|
-
required: true
|
|
235
|
-
},
|
|
236
|
-
subscriptionType: {
|
|
237
|
-
type: String,
|
|
238
|
-
enum: ZRBTenantSubscriptionType.options
|
|
239
|
-
},
|
|
240
|
-
parentSubscriptionId: {
|
|
241
|
-
type: String
|
|
242
|
-
},
|
|
243
|
-
scope: {
|
|
244
|
-
type: String,
|
|
245
|
-
enum: ZRBTenantSubscriptionScope.options
|
|
246
|
-
},
|
|
247
|
-
scopeId: {
|
|
248
|
-
type: String
|
|
249
|
-
},
|
|
250
|
-
fromPlanKey: {
|
|
251
|
-
type: String
|
|
252
|
-
},
|
|
253
|
-
toPlanKey: {
|
|
254
|
-
type: String
|
|
255
|
-
},
|
|
256
|
-
fromStatus: {
|
|
257
|
-
type: String,
|
|
258
|
-
enum: ZRBTenantSubscriptionStatus.options
|
|
259
|
-
},
|
|
260
|
-
toStatus: {
|
|
261
|
-
type: String,
|
|
262
|
-
enum: ZRBTenantSubscriptionStatus.options
|
|
263
|
-
},
|
|
264
|
-
fromModules: {
|
|
265
|
-
type: [String],
|
|
266
|
-
default: void 0
|
|
267
|
-
},
|
|
268
|
-
toModules: {
|
|
269
|
-
type: [String],
|
|
270
|
-
default: void 0
|
|
271
|
-
},
|
|
272
|
-
fromIntervalUnit: {
|
|
273
|
-
type: String,
|
|
274
|
-
enum: ZRBTenantSubscriptionIntervalUnit.options
|
|
275
|
-
},
|
|
276
|
-
toIntervalUnit: {
|
|
277
|
-
type: String,
|
|
278
|
-
enum: ZRBTenantSubscriptionIntervalUnit.options
|
|
279
|
-
},
|
|
280
|
-
fromIntervalCount: {
|
|
281
|
-
type: Number,
|
|
282
|
-
min: 1
|
|
283
|
-
},
|
|
284
|
-
toIntervalCount: {
|
|
285
|
-
type: Number,
|
|
286
|
-
min: 1
|
|
287
|
-
},
|
|
288
|
-
fromPriceId: {
|
|
289
|
-
type: String
|
|
290
|
-
},
|
|
291
|
-
toPriceId: {
|
|
292
|
-
type: String
|
|
293
|
-
},
|
|
294
|
-
billingAnchor: {
|
|
295
|
-
type: Date
|
|
296
|
-
},
|
|
297
|
-
supersedesEventId: {
|
|
298
|
-
type: String
|
|
299
|
-
},
|
|
300
|
-
idempotencyKey: {
|
|
301
|
-
type: String
|
|
302
|
-
},
|
|
303
|
-
direction: {
|
|
304
|
-
type: String,
|
|
305
|
-
enum: ZRBTenantSubscriptionChangeDirection.options
|
|
306
|
-
},
|
|
307
|
-
actorUserId: {
|
|
308
|
-
type: String
|
|
309
|
-
},
|
|
310
|
-
source: {
|
|
311
|
-
type: String,
|
|
312
|
-
enum: ZRBTenantSubscriptionEventSource.options
|
|
313
|
-
},
|
|
314
|
-
reason: {
|
|
315
|
-
type: String
|
|
316
|
-
},
|
|
317
|
-
provider: {
|
|
318
|
-
type: String
|
|
319
|
-
},
|
|
320
|
-
providerEventId: {
|
|
321
|
-
type: String
|
|
322
|
-
},
|
|
323
|
-
providerPayload: {
|
|
324
|
-
type: Schema$1.Types.Mixed
|
|
325
|
-
},
|
|
326
|
-
metadata: {
|
|
327
|
-
type: Schema$1.Types.Mixed
|
|
328
|
-
}
|
|
223
|
+
var subscriptionCreatedEventSchema = subscriptionEventBaseSchema.extend({
|
|
224
|
+
type: z$1.literal("created"),
|
|
225
|
+
toPlanKey: z$1.string().trim().min(1),
|
|
226
|
+
toStatus: ZRBTenantSubscriptionStatus,
|
|
227
|
+
toModules: z$1.array(z$1.string()),
|
|
228
|
+
toIntervalUnit: ZRBTenantSubscriptionIntervalUnit,
|
|
229
|
+
toIntervalCount: z$1.number().int().min(1),
|
|
230
|
+
billingAnchor: z$1.date()
|
|
329
231
|
});
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
232
|
+
var subscriptionPlanChangedEventSchema = subscriptionEventBaseSchema.extend({
|
|
233
|
+
type: z$1.literal("plan_changed"),
|
|
234
|
+
fromPlanKey: z$1.string().trim().min(1),
|
|
235
|
+
toPlanKey: z$1.string().trim().min(1),
|
|
236
|
+
fromModules: z$1.array(z$1.string()),
|
|
237
|
+
toModules: z$1.array(z$1.string()),
|
|
238
|
+
fromIntervalUnit: ZRBTenantSubscriptionIntervalUnit,
|
|
239
|
+
toIntervalUnit: ZRBTenantSubscriptionIntervalUnit,
|
|
240
|
+
fromIntervalCount: z$1.number().int().min(1),
|
|
241
|
+
toIntervalCount: z$1.number().int().min(1)
|
|
335
242
|
});
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
unique: true,
|
|
341
|
-
sparse: true
|
|
243
|
+
var subscriptionStatusChangedEventSchema = subscriptionEventBaseSchema.extend({
|
|
244
|
+
type: z$1.literal("status_changed"),
|
|
245
|
+
fromStatus: ZRBTenantSubscriptionStatus,
|
|
246
|
+
toStatus: ZRBTenantSubscriptionStatus
|
|
342
247
|
});
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
unique: true,
|
|
348
|
-
sparse: true
|
|
248
|
+
var subscriptionResumedEventSchema = subscriptionEventBaseSchema.extend({
|
|
249
|
+
type: z$1.literal("resumed"),
|
|
250
|
+
fromStatus: ZRBTenantSubscriptionStatus,
|
|
251
|
+
toStatus: z$1.literal("active")
|
|
349
252
|
});
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
parentSubscriptionId: z.string().optional(),
|
|
355
|
-
scope: ZRBTenantSubscriptionScope,
|
|
356
|
-
scopeId: z.string().optional(),
|
|
357
|
-
planKey: z.string(),
|
|
358
|
-
priceId: z.string().optional(),
|
|
359
|
-
status: ZRBTenantSubscriptionStatus,
|
|
360
|
-
intervalUnit: ZRBTenantSubscriptionIntervalUnit,
|
|
361
|
-
intervalCount: z.number().int().min(1),
|
|
362
|
-
modules: z.array(z.string()),
|
|
363
|
-
billingAnchor: z.date(),
|
|
364
|
-
currentPeriodStart: z.date(),
|
|
365
|
-
currentPeriodEnd: z.date(),
|
|
366
|
-
cancelAtPeriodEnd: z.boolean(),
|
|
367
|
-
cancelAt: z.date().optional(),
|
|
368
|
-
canceledAt: z.date().optional(),
|
|
369
|
-
scheduledPlanKey: z.string().optional(),
|
|
370
|
-
scheduledPlanEffectiveAt: z.date().optional(),
|
|
371
|
-
provider: z.string().optional(),
|
|
372
|
-
latestEventId: z.string(),
|
|
373
|
-
latestEventAt: z.date(),
|
|
374
|
-
projectedAt: z.date()
|
|
253
|
+
var subscriptionCanceledEventSchema = subscriptionEventBaseSchema.extend({
|
|
254
|
+
type: z$1.literal("canceled"),
|
|
255
|
+
fromStatus: ZRBTenantSubscriptionStatus,
|
|
256
|
+
toStatus: z$1.literal("canceled")
|
|
375
257
|
});
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
index: true
|
|
381
|
-
},
|
|
382
|
-
subscriptionId: {
|
|
383
|
-
type: String,
|
|
384
|
-
required: true
|
|
385
|
-
},
|
|
386
|
-
type: {
|
|
387
|
-
type: String,
|
|
388
|
-
required: true,
|
|
389
|
-
enum: ZRBTenantSubscriptionType.options
|
|
390
|
-
},
|
|
391
|
-
parentSubscriptionId: {
|
|
392
|
-
type: String
|
|
393
|
-
},
|
|
394
|
-
scope: {
|
|
395
|
-
type: String,
|
|
396
|
-
required: true,
|
|
397
|
-
enum: ZRBTenantSubscriptionScope.options
|
|
398
|
-
},
|
|
399
|
-
scopeId: {
|
|
400
|
-
type: String
|
|
401
|
-
},
|
|
402
|
-
planKey: {
|
|
403
|
-
type: String,
|
|
404
|
-
required: true
|
|
405
|
-
},
|
|
406
|
-
priceId: {
|
|
407
|
-
type: String
|
|
408
|
-
},
|
|
409
|
-
status: {
|
|
410
|
-
type: String,
|
|
411
|
-
required: true,
|
|
412
|
-
enum: ZRBTenantSubscriptionStatus.options
|
|
413
|
-
},
|
|
414
|
-
intervalUnit: {
|
|
415
|
-
type: String,
|
|
416
|
-
required: true,
|
|
417
|
-
enum: ZRBTenantSubscriptionIntervalUnit.options
|
|
418
|
-
},
|
|
419
|
-
intervalCount: {
|
|
420
|
-
type: Number,
|
|
421
|
-
required: true,
|
|
422
|
-
min: 1
|
|
423
|
-
},
|
|
424
|
-
modules: {
|
|
425
|
-
type: [String],
|
|
426
|
-
required: true,
|
|
427
|
-
default: []
|
|
428
|
-
},
|
|
429
|
-
billingAnchor: {
|
|
430
|
-
type: Date,
|
|
431
|
-
required: true
|
|
432
|
-
},
|
|
433
|
-
currentPeriodStart: {
|
|
434
|
-
type: Date,
|
|
435
|
-
required: true
|
|
436
|
-
},
|
|
437
|
-
currentPeriodEnd: {
|
|
438
|
-
type: Date,
|
|
439
|
-
required: true
|
|
440
|
-
},
|
|
441
|
-
cancelAtPeriodEnd: {
|
|
442
|
-
type: Boolean,
|
|
443
|
-
required: true,
|
|
444
|
-
default: false
|
|
445
|
-
},
|
|
446
|
-
cancelAt: {
|
|
447
|
-
type: Date
|
|
448
|
-
},
|
|
449
|
-
canceledAt: {
|
|
450
|
-
type: Date
|
|
451
|
-
},
|
|
452
|
-
scheduledPlanKey: {
|
|
453
|
-
type: String
|
|
454
|
-
},
|
|
455
|
-
scheduledPlanEffectiveAt: {
|
|
456
|
-
type: Date
|
|
457
|
-
},
|
|
458
|
-
provider: {
|
|
459
|
-
type: String
|
|
460
|
-
},
|
|
461
|
-
latestEventId: {
|
|
462
|
-
type: String,
|
|
463
|
-
required: true
|
|
464
|
-
},
|
|
465
|
-
latestEventAt: {
|
|
466
|
-
type: Date,
|
|
467
|
-
required: true
|
|
468
|
-
},
|
|
469
|
-
projectedAt: {
|
|
470
|
-
type: Date,
|
|
471
|
-
required: true
|
|
472
|
-
}
|
|
258
|
+
var subscriptionRenewedEventSchema = subscriptionEventBaseSchema.extend({
|
|
259
|
+
type: z$1.literal("renewed"),
|
|
260
|
+
fromStatus: ZRBTenantSubscriptionStatus,
|
|
261
|
+
toStatus: ZRBTenantSubscriptionStatus
|
|
473
262
|
});
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
263
|
+
var ZRBTenantSubscriptionEvent = z$1.discriminatedUnion("type", [
|
|
264
|
+
subscriptionCreatedEventSchema,
|
|
265
|
+
subscriptionPlanChangedEventSchema,
|
|
266
|
+
subscriptionStatusChangedEventSchema,
|
|
267
|
+
subscriptionResumedEventSchema,
|
|
268
|
+
subscriptionCanceledEventSchema,
|
|
269
|
+
subscriptionRenewedEventSchema
|
|
270
|
+
]).superRefine((event, ctx) => {
|
|
271
|
+
if (event.subscriptionType === "addon" && !event.parentSubscriptionId?.trim()) ctx.addIssue({
|
|
272
|
+
code: "custom",
|
|
273
|
+
message: "parentSubscriptionId is required for add-on subscriptions",
|
|
274
|
+
path: ["parentSubscriptionId"]
|
|
275
|
+
});
|
|
276
|
+
if (event.scope !== "tenant" && !event.scopeId?.trim()) ctx.addIssue({
|
|
277
|
+
code: "custom",
|
|
278
|
+
message: "scopeId is required for non-tenant subscriptions",
|
|
279
|
+
path: ["scopeId"]
|
|
280
|
+
});
|
|
488
281
|
});
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
282
|
+
var requiredForEventTypes = (...types) => function requiredForEventType() {
|
|
283
|
+
return Boolean(this.type && types.includes(this.type));
|
|
284
|
+
};
|
|
285
|
+
var RBTenantSubscriptionEventSchema = new Schema$1({
|
|
286
|
+
tenantId: {
|
|
287
|
+
type: String,
|
|
288
|
+
required: true,
|
|
289
|
+
index: true
|
|
290
|
+
},
|
|
291
|
+
subscriptionId: {
|
|
292
|
+
type: String,
|
|
293
|
+
required: true,
|
|
294
|
+
index: true
|
|
295
|
+
},
|
|
296
|
+
type: {
|
|
297
|
+
type: String,
|
|
298
|
+
required: true,
|
|
299
|
+
enum: ZRBTenantSubscriptionEventType.options
|
|
300
|
+
},
|
|
301
|
+
occurredAt: {
|
|
302
|
+
type: Date,
|
|
303
|
+
required: true,
|
|
304
|
+
default: Date.now
|
|
305
|
+
},
|
|
306
|
+
effectiveAt: {
|
|
307
|
+
type: Date,
|
|
308
|
+
required: true
|
|
309
|
+
},
|
|
310
|
+
subscriptionType: {
|
|
311
|
+
type: String,
|
|
312
|
+
required: true,
|
|
313
|
+
enum: ZRBTenantSubscriptionType.options
|
|
314
|
+
},
|
|
315
|
+
parentSubscriptionId: {
|
|
316
|
+
type: String,
|
|
317
|
+
required() {
|
|
318
|
+
return this.subscriptionType === "addon";
|
|
319
|
+
}
|
|
320
|
+
},
|
|
321
|
+
scope: {
|
|
322
|
+
type: String,
|
|
323
|
+
required: true,
|
|
324
|
+
enum: ZRBTenantSubscriptionScope.options
|
|
325
|
+
},
|
|
326
|
+
scopeId: {
|
|
327
|
+
type: String,
|
|
328
|
+
required() {
|
|
329
|
+
return Boolean(this.scope && this.scope !== "tenant");
|
|
330
|
+
}
|
|
331
|
+
},
|
|
332
|
+
fromPlanKey: {
|
|
333
|
+
type: String,
|
|
334
|
+
required: requiredForEventTypes("plan_changed")
|
|
335
|
+
},
|
|
336
|
+
toPlanKey: {
|
|
337
|
+
type: String,
|
|
338
|
+
required: requiredForEventTypes("created", "plan_changed")
|
|
339
|
+
},
|
|
340
|
+
fromStatus: {
|
|
341
|
+
type: String,
|
|
342
|
+
required: requiredForEventTypes("status_changed", "resumed", "canceled", "renewed"),
|
|
343
|
+
enum: ZRBTenantSubscriptionStatus.options
|
|
344
|
+
},
|
|
345
|
+
toStatus: {
|
|
346
|
+
type: String,
|
|
347
|
+
required: requiredForEventTypes("created", "status_changed", "resumed", "canceled", "renewed"),
|
|
348
|
+
enum: ZRBTenantSubscriptionStatus.options
|
|
349
|
+
},
|
|
350
|
+
fromModules: {
|
|
351
|
+
type: [String],
|
|
352
|
+
required: requiredForEventTypes("plan_changed"),
|
|
353
|
+
default: void 0
|
|
354
|
+
},
|
|
355
|
+
toModules: {
|
|
356
|
+
type: [String],
|
|
357
|
+
required: requiredForEventTypes("created", "plan_changed"),
|
|
358
|
+
default: void 0
|
|
359
|
+
},
|
|
360
|
+
fromIntervalUnit: {
|
|
361
|
+
type: String,
|
|
362
|
+
required: requiredForEventTypes("plan_changed"),
|
|
363
|
+
enum: ZRBTenantSubscriptionIntervalUnit.options
|
|
364
|
+
},
|
|
365
|
+
toIntervalUnit: {
|
|
366
|
+
type: String,
|
|
367
|
+
required: requiredForEventTypes("created", "plan_changed"),
|
|
368
|
+
enum: ZRBTenantSubscriptionIntervalUnit.options
|
|
369
|
+
},
|
|
370
|
+
fromIntervalCount: {
|
|
371
|
+
type: Number,
|
|
372
|
+
required: requiredForEventTypes("plan_changed"),
|
|
373
|
+
min: 1
|
|
374
|
+
},
|
|
375
|
+
toIntervalCount: {
|
|
376
|
+
type: Number,
|
|
377
|
+
required: requiredForEventTypes("created", "plan_changed"),
|
|
378
|
+
min: 1
|
|
379
|
+
},
|
|
380
|
+
fromPriceId: { type: String },
|
|
381
|
+
toPriceId: { type: String },
|
|
382
|
+
billingAnchor: {
|
|
383
|
+
type: Date,
|
|
384
|
+
required: requiredForEventTypes("created")
|
|
385
|
+
},
|
|
386
|
+
supersedesEventId: { type: String },
|
|
387
|
+
idempotencyKey: {
|
|
388
|
+
type: String,
|
|
389
|
+
required: true
|
|
390
|
+
},
|
|
391
|
+
direction: {
|
|
392
|
+
type: String,
|
|
393
|
+
enum: ZRBTenantSubscriptionChangeDirection.options
|
|
394
|
+
},
|
|
395
|
+
actorUserId: { type: String },
|
|
396
|
+
source: {
|
|
397
|
+
type: String,
|
|
398
|
+
enum: ZRBTenantSubscriptionEventSource.options
|
|
399
|
+
},
|
|
400
|
+
reason: { type: String },
|
|
401
|
+
provider: { type: String },
|
|
402
|
+
providerEventId: { type: String },
|
|
403
|
+
providerPayload: { type: Schema$1.Types.Mixed },
|
|
404
|
+
metadata: { type: Schema$1.Types.Mixed }
|
|
501
405
|
});
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
modelName: z.string(),
|
|
508
|
-
op: ZRBRtsChangeOp,
|
|
509
|
-
docId: z.string().optional(),
|
|
510
|
-
ts: z.date()
|
|
406
|
+
RBTenantSubscriptionEventSchema.index({
|
|
407
|
+
tenantId: 1,
|
|
408
|
+
subscriptionId: 1,
|
|
409
|
+
effectiveAt: 1,
|
|
410
|
+
occurredAt: 1
|
|
511
411
|
});
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
required: true
|
|
516
|
-
},
|
|
517
|
-
modelName: {
|
|
518
|
-
type: String,
|
|
519
|
-
required: true,
|
|
520
|
-
index: true
|
|
521
|
-
},
|
|
522
|
-
op: {
|
|
523
|
-
type: String,
|
|
524
|
-
required: true,
|
|
525
|
-
enum: ZRBRtsChangeOp.options
|
|
526
|
-
},
|
|
527
|
-
docId: {
|
|
528
|
-
type: String,
|
|
529
|
-
required: false
|
|
530
|
-
},
|
|
531
|
-
ts: {
|
|
532
|
-
type: Date,
|
|
533
|
-
required: true,
|
|
534
|
-
default: Date.now
|
|
535
|
-
}
|
|
412
|
+
RBTenantSubscriptionEventSchema.index({
|
|
413
|
+
provider: 1,
|
|
414
|
+
providerEventId: 1
|
|
536
415
|
}, {
|
|
537
|
-
|
|
416
|
+
unique: true,
|
|
417
|
+
partialFilterExpression: {
|
|
418
|
+
provider: { $type: "string" },
|
|
419
|
+
providerEventId: { $type: "string" }
|
|
420
|
+
}
|
|
538
421
|
});
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
422
|
+
RBTenantSubscriptionEventSchema.index({
|
|
423
|
+
tenantId: 1,
|
|
424
|
+
idempotencyKey: 1
|
|
425
|
+
}, { unique: true });
|
|
426
|
+
//#endregion
|
|
427
|
+
//#region src/models/RBTenantSubscriptionProjection.ts
|
|
428
|
+
var ZRBTenantSubscriptionProjection = z$1.object({
|
|
429
|
+
tenantId: z$1.string(),
|
|
430
|
+
subscriptionId: z$1.string(),
|
|
431
|
+
type: ZRBTenantSubscriptionType,
|
|
432
|
+
parentSubscriptionId: z$1.string().optional(),
|
|
433
|
+
scope: ZRBTenantSubscriptionScope,
|
|
434
|
+
scopeId: z$1.string().optional(),
|
|
435
|
+
planKey: z$1.string(),
|
|
436
|
+
priceId: z$1.string().optional(),
|
|
437
|
+
status: ZRBTenantSubscriptionStatus,
|
|
438
|
+
intervalUnit: ZRBTenantSubscriptionIntervalUnit,
|
|
439
|
+
intervalCount: z$1.number().int().min(1),
|
|
440
|
+
modules: z$1.array(z$1.string()),
|
|
441
|
+
billingAnchor: z$1.date(),
|
|
442
|
+
currentPeriodStart: z$1.date(),
|
|
443
|
+
currentPeriodEnd: z$1.date(),
|
|
444
|
+
cancelAtPeriodEnd: z$1.boolean(),
|
|
445
|
+
cancelAt: z$1.date().optional(),
|
|
446
|
+
canceledAt: z$1.date().optional(),
|
|
447
|
+
scheduledPlanKey: z$1.string().optional(),
|
|
448
|
+
scheduledPlanEffectiveAt: z$1.date().optional(),
|
|
449
|
+
provider: z$1.string().optional(),
|
|
450
|
+
latestEventId: z$1.string(),
|
|
451
|
+
latestEventAt: z$1.date(),
|
|
452
|
+
projectedAt: z$1.date()
|
|
543
453
|
});
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
454
|
+
var RBTenantSubscriptionProjectionSchema = new Schema$1({
|
|
455
|
+
tenantId: {
|
|
456
|
+
type: String,
|
|
457
|
+
required: true,
|
|
458
|
+
index: true
|
|
459
|
+
},
|
|
460
|
+
subscriptionId: {
|
|
461
|
+
type: String,
|
|
462
|
+
required: true
|
|
463
|
+
},
|
|
464
|
+
type: {
|
|
465
|
+
type: String,
|
|
466
|
+
required: true,
|
|
467
|
+
enum: ZRBTenantSubscriptionType.options
|
|
468
|
+
},
|
|
469
|
+
parentSubscriptionId: { type: String },
|
|
470
|
+
scope: {
|
|
471
|
+
type: String,
|
|
472
|
+
required: true,
|
|
473
|
+
enum: ZRBTenantSubscriptionScope.options
|
|
474
|
+
},
|
|
475
|
+
scopeId: { type: String },
|
|
476
|
+
planKey: {
|
|
477
|
+
type: String,
|
|
478
|
+
required: true
|
|
479
|
+
},
|
|
480
|
+
priceId: { type: String },
|
|
481
|
+
status: {
|
|
482
|
+
type: String,
|
|
483
|
+
required: true,
|
|
484
|
+
enum: ZRBTenantSubscriptionStatus.options
|
|
485
|
+
},
|
|
486
|
+
intervalUnit: {
|
|
487
|
+
type: String,
|
|
488
|
+
required: true,
|
|
489
|
+
enum: ZRBTenantSubscriptionIntervalUnit.options
|
|
490
|
+
},
|
|
491
|
+
intervalCount: {
|
|
492
|
+
type: Number,
|
|
493
|
+
required: true,
|
|
494
|
+
min: 1
|
|
495
|
+
},
|
|
496
|
+
modules: {
|
|
497
|
+
type: [String],
|
|
498
|
+
required: true,
|
|
499
|
+
default: []
|
|
500
|
+
},
|
|
501
|
+
billingAnchor: {
|
|
502
|
+
type: Date,
|
|
503
|
+
required: true
|
|
504
|
+
},
|
|
505
|
+
currentPeriodStart: {
|
|
506
|
+
type: Date,
|
|
507
|
+
required: true
|
|
508
|
+
},
|
|
509
|
+
currentPeriodEnd: {
|
|
510
|
+
type: Date,
|
|
511
|
+
required: true
|
|
512
|
+
},
|
|
513
|
+
cancelAtPeriodEnd: {
|
|
514
|
+
type: Boolean,
|
|
515
|
+
required: true,
|
|
516
|
+
default: false
|
|
517
|
+
},
|
|
518
|
+
cancelAt: { type: Date },
|
|
519
|
+
canceledAt: { type: Date },
|
|
520
|
+
scheduledPlanKey: { type: String },
|
|
521
|
+
scheduledPlanEffectiveAt: { type: Date },
|
|
522
|
+
provider: { type: String },
|
|
523
|
+
latestEventId: {
|
|
524
|
+
type: String,
|
|
525
|
+
required: true
|
|
526
|
+
},
|
|
527
|
+
latestEventAt: {
|
|
528
|
+
type: Date,
|
|
529
|
+
required: true
|
|
530
|
+
},
|
|
531
|
+
projectedAt: {
|
|
532
|
+
type: Date,
|
|
533
|
+
required: true
|
|
534
|
+
}
|
|
548
535
|
});
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
chunkSize: z.number().int().min(1),
|
|
558
|
-
chunksTotal: z.number().int().min(1),
|
|
559
|
-
status: ZRBUploadSessionStatus,
|
|
560
|
-
createdAt: z.date(),
|
|
561
|
-
expiresAt: z.date(),
|
|
562
|
-
fileId: z.string().optional(),
|
|
563
|
-
isPublic: z.boolean().optional(),
|
|
564
|
-
error: z.string().optional()
|
|
536
|
+
RBTenantSubscriptionProjectionSchema.index({
|
|
537
|
+
tenantId: 1,
|
|
538
|
+
subscriptionId: 1
|
|
539
|
+
}, { unique: true });
|
|
540
|
+
RBTenantSubscriptionProjectionSchema.index({
|
|
541
|
+
tenantId: 1,
|
|
542
|
+
scope: 1,
|
|
543
|
+
scopeId: 1
|
|
565
544
|
});
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
userId: {
|
|
572
|
-
type: String,
|
|
573
|
-
required: false,
|
|
574
|
-
index: true
|
|
575
|
-
},
|
|
576
|
-
ownerKeyHash: {
|
|
577
|
-
type: String,
|
|
578
|
-
required: false
|
|
579
|
-
},
|
|
580
|
-
filename: {
|
|
581
|
-
type: String,
|
|
582
|
-
required: true
|
|
583
|
-
},
|
|
584
|
-
mimeType: {
|
|
585
|
-
type: String,
|
|
586
|
-
required: true
|
|
587
|
-
},
|
|
588
|
-
totalSize: {
|
|
589
|
-
type: Number,
|
|
590
|
-
required: true
|
|
591
|
-
},
|
|
592
|
-
chunkSize: {
|
|
593
|
-
type: Number,
|
|
594
|
-
required: true
|
|
595
|
-
},
|
|
596
|
-
chunksTotal: {
|
|
597
|
-
type: Number,
|
|
598
|
-
required: true
|
|
599
|
-
},
|
|
600
|
-
status: {
|
|
601
|
-
type: String,
|
|
602
|
-
required: true,
|
|
603
|
-
enum: ZRBUploadSessionStatus.options
|
|
604
|
-
},
|
|
605
|
-
createdAt: {
|
|
606
|
-
type: Date,
|
|
607
|
-
required: true,
|
|
608
|
-
default: Date.now
|
|
609
|
-
},
|
|
610
|
-
expiresAt: {
|
|
611
|
-
type: Date,
|
|
612
|
-
required: true
|
|
613
|
-
},
|
|
614
|
-
fileId: {
|
|
615
|
-
type: String,
|
|
616
|
-
required: false
|
|
617
|
-
},
|
|
618
|
-
isPublic: {
|
|
619
|
-
type: Boolean,
|
|
620
|
-
required: false
|
|
621
|
-
},
|
|
622
|
-
error: {
|
|
623
|
-
type: String,
|
|
624
|
-
required: false
|
|
625
|
-
}
|
|
626
|
-
}, {
|
|
627
|
-
versionKey: false
|
|
545
|
+
//#endregion
|
|
546
|
+
//#region src/models/RBRtsCounter.ts
|
|
547
|
+
var ZRBRtsCounter = z$1.object({
|
|
548
|
+
_id: z$1.string(),
|
|
549
|
+
seq: z$1.number().int().min(0)
|
|
628
550
|
});
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
551
|
+
var RBRtsCounterSchema = new Schema$1({
|
|
552
|
+
_id: {
|
|
553
|
+
type: String,
|
|
554
|
+
required: true
|
|
555
|
+
},
|
|
556
|
+
seq: {
|
|
557
|
+
type: Number,
|
|
558
|
+
required: true,
|
|
559
|
+
default: 0
|
|
560
|
+
}
|
|
561
|
+
}, { versionKey: false });
|
|
562
|
+
//#endregion
|
|
563
|
+
//#region src/models/RBRtsChange.ts
|
|
564
|
+
var ttlSecondsRaw = process.env.RB_RTS_CHANGES_TTL_S ?? "";
|
|
565
|
+
var ttlSeconds = Number.isFinite(Number(ttlSecondsRaw)) ? Math.max(60, Math.floor(Number(ttlSecondsRaw))) : 3600 * 24 * 30;
|
|
566
|
+
var ZRBRtsChangeOp = z$1.enum(["delete", "reset_model"]);
|
|
567
|
+
var ZRBRtsChange = z$1.object({
|
|
568
|
+
seq: z$1.number().int().min(0),
|
|
569
|
+
modelName: z$1.string(),
|
|
570
|
+
op: ZRBRtsChangeOp,
|
|
571
|
+
docId: z$1.string().optional(),
|
|
572
|
+
ts: z$1.date()
|
|
633
573
|
});
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
574
|
+
var RBRtsChangeSchema = new Schema$1({
|
|
575
|
+
seq: {
|
|
576
|
+
type: Number,
|
|
577
|
+
required: true
|
|
578
|
+
},
|
|
579
|
+
modelName: {
|
|
580
|
+
type: String,
|
|
581
|
+
required: true,
|
|
582
|
+
index: true
|
|
583
|
+
},
|
|
584
|
+
op: {
|
|
585
|
+
type: String,
|
|
586
|
+
required: true,
|
|
587
|
+
enum: ZRBRtsChangeOp.options
|
|
588
|
+
},
|
|
589
|
+
docId: {
|
|
590
|
+
type: String,
|
|
591
|
+
required: false
|
|
592
|
+
},
|
|
593
|
+
ts: {
|
|
594
|
+
type: Date,
|
|
595
|
+
required: true,
|
|
596
|
+
default: Date.now
|
|
597
|
+
}
|
|
598
|
+
}, { versionKey: false });
|
|
599
|
+
RBRtsChangeSchema.index({ seq: 1 }, { unique: true });
|
|
600
|
+
RBRtsChangeSchema.index({ ts: 1 }, { expireAfterSeconds: ttlSeconds });
|
|
601
|
+
//#endregion
|
|
602
|
+
//#region src/models/RBUploadSession.ts
|
|
603
|
+
var ZRBUploadSessionStatus = z$1.enum([
|
|
604
|
+
"uploading",
|
|
605
|
+
"assembling",
|
|
606
|
+
"done",
|
|
607
|
+
"error"
|
|
608
|
+
]);
|
|
609
|
+
var ZRBUploadSession = z$1.object({
|
|
610
|
+
_id: z$1.string(),
|
|
611
|
+
userId: z$1.string().optional(),
|
|
612
|
+
ownerKeyHash: z$1.string().optional(),
|
|
613
|
+
filename: z$1.string(),
|
|
614
|
+
mimeType: z$1.string(),
|
|
615
|
+
totalSize: z$1.number().int().min(0),
|
|
616
|
+
chunkSize: z$1.number().int().min(1),
|
|
617
|
+
chunksTotal: z$1.number().int().min(1),
|
|
618
|
+
status: ZRBUploadSessionStatus,
|
|
619
|
+
createdAt: z$1.date(),
|
|
620
|
+
expiresAt: z$1.date(),
|
|
621
|
+
fileId: z$1.string().optional(),
|
|
622
|
+
isPublic: z$1.boolean().optional(),
|
|
623
|
+
error: z$1.string().optional()
|
|
671
624
|
});
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
625
|
+
var RBUploadSessionSchema = new Schema$1({
|
|
626
|
+
_id: {
|
|
627
|
+
type: String,
|
|
628
|
+
required: true
|
|
629
|
+
},
|
|
630
|
+
userId: {
|
|
631
|
+
type: String,
|
|
632
|
+
required: false,
|
|
633
|
+
index: true
|
|
634
|
+
},
|
|
635
|
+
ownerKeyHash: {
|
|
636
|
+
type: String,
|
|
637
|
+
required: false
|
|
638
|
+
},
|
|
639
|
+
filename: {
|
|
640
|
+
type: String,
|
|
641
|
+
required: true
|
|
642
|
+
},
|
|
643
|
+
mimeType: {
|
|
644
|
+
type: String,
|
|
645
|
+
required: true
|
|
646
|
+
},
|
|
647
|
+
totalSize: {
|
|
648
|
+
type: Number,
|
|
649
|
+
required: true
|
|
650
|
+
},
|
|
651
|
+
chunkSize: {
|
|
652
|
+
type: Number,
|
|
653
|
+
required: true
|
|
654
|
+
},
|
|
655
|
+
chunksTotal: {
|
|
656
|
+
type: Number,
|
|
657
|
+
required: true
|
|
658
|
+
},
|
|
659
|
+
status: {
|
|
660
|
+
type: String,
|
|
661
|
+
required: true,
|
|
662
|
+
enum: ZRBUploadSessionStatus.options
|
|
663
|
+
},
|
|
664
|
+
createdAt: {
|
|
665
|
+
type: Date,
|
|
666
|
+
required: true,
|
|
667
|
+
default: Date.now
|
|
668
|
+
},
|
|
669
|
+
expiresAt: {
|
|
670
|
+
type: Date,
|
|
671
|
+
required: true
|
|
672
|
+
},
|
|
673
|
+
fileId: {
|
|
674
|
+
type: String,
|
|
675
|
+
required: false
|
|
676
|
+
},
|
|
677
|
+
isPublic: {
|
|
678
|
+
type: Boolean,
|
|
679
|
+
required: false
|
|
680
|
+
},
|
|
681
|
+
error: {
|
|
682
|
+
type: String,
|
|
683
|
+
required: false
|
|
684
|
+
}
|
|
685
|
+
}, { versionKey: false });
|
|
686
|
+
RBUploadSessionSchema.index({ expiresAt: 1 }, { expireAfterSeconds: 0 });
|
|
687
|
+
var RBUploadSessionPolicy = {
|
|
688
|
+
subject: "RBUploadSession",
|
|
689
|
+
define: (builder, ctx) => {
|
|
690
|
+
builder.can("create", "RBUploadSession");
|
|
691
|
+
if (ctx.userId) {
|
|
692
|
+
builder.can("read", "RBUploadSession", { userId: ctx.userId });
|
|
693
|
+
builder.can("update", "RBUploadSession", { userId: ctx.userId });
|
|
694
|
+
builder.can("delete", "RBUploadSession", { userId: ctx.userId });
|
|
695
|
+
}
|
|
696
|
+
const uploadKeyHash = typeof ctx.claims?.uploadKeyHash === "string" ? ctx.claims.uploadKeyHash.trim() : "";
|
|
697
|
+
if (uploadKeyHash) {
|
|
698
|
+
builder.can("read", "RBUploadSession", { ownerKeyHash: uploadKeyHash });
|
|
699
|
+
builder.can("update", "RBUploadSession", { ownerKeyHash: uploadKeyHash });
|
|
700
|
+
builder.can("delete", "RBUploadSession", { ownerKeyHash: uploadKeyHash });
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
};
|
|
704
|
+
//#endregion
|
|
705
|
+
//#region src/models/RBUploadChunk.ts
|
|
706
|
+
var ZRBUploadChunk = z$1.object({
|
|
707
|
+
uploadId: z$1.string(),
|
|
708
|
+
index: z$1.number().int().min(0),
|
|
709
|
+
data: z$1.unknown(),
|
|
710
|
+
size: z$1.number().int().min(0),
|
|
711
|
+
sha256: z$1.string().optional(),
|
|
712
|
+
createdAt: z$1.date(),
|
|
713
|
+
expiresAt: z$1.date()
|
|
705
714
|
});
|
|
715
|
+
var RBUploadChunkSchema = new Schema$1({
|
|
716
|
+
uploadId: {
|
|
717
|
+
type: String,
|
|
718
|
+
required: true,
|
|
719
|
+
index: true
|
|
720
|
+
},
|
|
721
|
+
index: {
|
|
722
|
+
type: Number,
|
|
723
|
+
required: true
|
|
724
|
+
},
|
|
725
|
+
data: {
|
|
726
|
+
type: Buffer,
|
|
727
|
+
required: true
|
|
728
|
+
},
|
|
729
|
+
size: {
|
|
730
|
+
type: Number,
|
|
731
|
+
required: true
|
|
732
|
+
},
|
|
733
|
+
sha256: {
|
|
734
|
+
type: String,
|
|
735
|
+
required: false
|
|
736
|
+
},
|
|
737
|
+
createdAt: {
|
|
738
|
+
type: Date,
|
|
739
|
+
required: true,
|
|
740
|
+
default: Date.now
|
|
741
|
+
},
|
|
742
|
+
expiresAt: {
|
|
743
|
+
type: Date,
|
|
744
|
+
required: true
|
|
745
|
+
}
|
|
746
|
+
}, { versionKey: false });
|
|
706
747
|
RBUploadChunkSchema.index({
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
}, {
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
webpush: z.record(z.string(), z.unknown()).optional(),
|
|
720
|
-
fcmOptions: z.record(z.string(), z.unknown()).optional(),
|
|
721
|
-
android: z.record(z.string(), z.unknown()).optional(),
|
|
722
|
-
apns: z.record(z.string(), z.unknown()).optional()
|
|
748
|
+
uploadId: 1,
|
|
749
|
+
index: 1
|
|
750
|
+
}, { unique: true });
|
|
751
|
+
RBUploadChunkSchema.index({ expiresAt: 1 }, { expireAfterSeconds: 0 });
|
|
752
|
+
//#endregion
|
|
753
|
+
//#region src/models/RBNotification.ts
|
|
754
|
+
var ZStringMap$1 = z$1.record(z$1.string(), z$1.string());
|
|
755
|
+
var ZRBNotificationPlatformPayload = z$1.object({
|
|
756
|
+
webpush: z$1.record(z$1.string(), z$1.unknown()).optional(),
|
|
757
|
+
fcmOptions: z$1.record(z$1.string(), z$1.unknown()).optional(),
|
|
758
|
+
android: z$1.record(z$1.string(), z$1.unknown()).optional(),
|
|
759
|
+
apns: z$1.record(z$1.string(), z$1.unknown()).optional()
|
|
723
760
|
}).passthrough();
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
});
|
|
740
|
-
const TTL_90_DAYS_S$1 = 60 * 60 * 24 * 90;
|
|
741
|
-
const RBNotificationSchema = new Schema$1({
|
|
742
|
-
userId: {
|
|
743
|
-
type: String,
|
|
744
|
-
required: true,
|
|
745
|
-
index: true
|
|
746
|
-
},
|
|
747
|
-
topic: {
|
|
748
|
-
type: String,
|
|
749
|
-
required: false,
|
|
750
|
-
index: true
|
|
751
|
-
},
|
|
752
|
-
tag: {
|
|
753
|
-
type: String,
|
|
754
|
-
required: false
|
|
755
|
-
},
|
|
756
|
-
deliveryId: {
|
|
757
|
-
type: String,
|
|
758
|
-
required: false
|
|
759
|
-
},
|
|
760
|
-
title: {
|
|
761
|
-
type: String,
|
|
762
|
-
required: true
|
|
763
|
-
},
|
|
764
|
-
body: {
|
|
765
|
-
type: String,
|
|
766
|
-
required: false
|
|
767
|
-
},
|
|
768
|
-
image: {
|
|
769
|
-
type: String,
|
|
770
|
-
required: false
|
|
771
|
-
},
|
|
772
|
-
data: {
|
|
773
|
-
type: Schema$1.Types.Mixed,
|
|
774
|
-
required: false
|
|
775
|
-
},
|
|
776
|
-
platform: {
|
|
777
|
-
type: Schema$1.Types.Mixed,
|
|
778
|
-
required: false
|
|
779
|
-
},
|
|
780
|
-
drawerActive: {
|
|
781
|
-
type: Boolean,
|
|
782
|
-
required: false
|
|
783
|
-
},
|
|
784
|
-
createdAt: {
|
|
785
|
-
type: Date,
|
|
786
|
-
required: true,
|
|
787
|
-
default: Date.now,
|
|
788
|
-
index: true
|
|
789
|
-
},
|
|
790
|
-
seenAt: {
|
|
791
|
-
type: Date,
|
|
792
|
-
required: false,
|
|
793
|
-
index: true
|
|
794
|
-
},
|
|
795
|
-
readAt: {
|
|
796
|
-
type: Date,
|
|
797
|
-
required: false,
|
|
798
|
-
index: true
|
|
799
|
-
},
|
|
800
|
-
archivedAt: {
|
|
801
|
-
type: Date,
|
|
802
|
-
required: false
|
|
803
|
-
}
|
|
804
|
-
}, {
|
|
805
|
-
versionKey: false
|
|
806
|
-
});
|
|
807
|
-
RBNotificationSchema.index({
|
|
808
|
-
userId: 1,
|
|
809
|
-
archivedAt: 1,
|
|
810
|
-
createdAt: -1
|
|
761
|
+
var ZRBNotification = z$1.object({
|
|
762
|
+
userId: z$1.string(),
|
|
763
|
+
topic: z$1.string().optional(),
|
|
764
|
+
tag: z$1.string().optional(),
|
|
765
|
+
deliveryId: z$1.string().optional(),
|
|
766
|
+
title: z$1.string(),
|
|
767
|
+
body: z$1.string().optional(),
|
|
768
|
+
image: z$1.string().optional(),
|
|
769
|
+
data: ZStringMap$1.optional(),
|
|
770
|
+
platform: ZRBNotificationPlatformPayload.optional(),
|
|
771
|
+
drawerActive: z$1.boolean().optional(),
|
|
772
|
+
createdAt: z$1.date(),
|
|
773
|
+
seenAt: z$1.date().optional(),
|
|
774
|
+
readAt: z$1.date().optional(),
|
|
775
|
+
archivedAt: z$1.date().optional()
|
|
811
776
|
});
|
|
777
|
+
var TTL_90_DAYS_S$1 = 3600 * 24 * 90;
|
|
778
|
+
var RBNotificationSchema = new Schema$1({
|
|
779
|
+
userId: {
|
|
780
|
+
type: String,
|
|
781
|
+
required: true,
|
|
782
|
+
index: true
|
|
783
|
+
},
|
|
784
|
+
topic: {
|
|
785
|
+
type: String,
|
|
786
|
+
required: false,
|
|
787
|
+
index: true
|
|
788
|
+
},
|
|
789
|
+
tag: {
|
|
790
|
+
type: String,
|
|
791
|
+
required: false
|
|
792
|
+
},
|
|
793
|
+
deliveryId: {
|
|
794
|
+
type: String,
|
|
795
|
+
required: false
|
|
796
|
+
},
|
|
797
|
+
title: {
|
|
798
|
+
type: String,
|
|
799
|
+
required: true
|
|
800
|
+
},
|
|
801
|
+
body: {
|
|
802
|
+
type: String,
|
|
803
|
+
required: false
|
|
804
|
+
},
|
|
805
|
+
image: {
|
|
806
|
+
type: String,
|
|
807
|
+
required: false
|
|
808
|
+
},
|
|
809
|
+
data: {
|
|
810
|
+
type: Schema$1.Types.Mixed,
|
|
811
|
+
required: false
|
|
812
|
+
},
|
|
813
|
+
platform: {
|
|
814
|
+
type: Schema$1.Types.Mixed,
|
|
815
|
+
required: false
|
|
816
|
+
},
|
|
817
|
+
drawerActive: {
|
|
818
|
+
type: Boolean,
|
|
819
|
+
required: false
|
|
820
|
+
},
|
|
821
|
+
createdAt: {
|
|
822
|
+
type: Date,
|
|
823
|
+
required: true,
|
|
824
|
+
default: Date.now,
|
|
825
|
+
index: true
|
|
826
|
+
},
|
|
827
|
+
seenAt: {
|
|
828
|
+
type: Date,
|
|
829
|
+
required: false,
|
|
830
|
+
index: true
|
|
831
|
+
},
|
|
832
|
+
readAt: {
|
|
833
|
+
type: Date,
|
|
834
|
+
required: false,
|
|
835
|
+
index: true
|
|
836
|
+
},
|
|
837
|
+
archivedAt: {
|
|
838
|
+
type: Date,
|
|
839
|
+
required: false
|
|
840
|
+
}
|
|
841
|
+
}, { versionKey: false });
|
|
812
842
|
RBNotificationSchema.index({
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
createdAt: -1
|
|
843
|
+
userId: 1,
|
|
844
|
+
archivedAt: 1,
|
|
845
|
+
createdAt: -1
|
|
817
846
|
});
|
|
818
847
|
RBNotificationSchema.index({
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
848
|
+
userId: 1,
|
|
849
|
+
seenAt: 1,
|
|
850
|
+
archivedAt: 1,
|
|
851
|
+
createdAt: -1
|
|
823
852
|
});
|
|
824
853
|
RBNotificationSchema.index({
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
partialFilterExpression: {
|
|
830
|
-
tag: {
|
|
831
|
-
$exists: true
|
|
832
|
-
},
|
|
833
|
-
drawerActive: true
|
|
834
|
-
}
|
|
854
|
+
userId: 1,
|
|
855
|
+
readAt: 1,
|
|
856
|
+
archivedAt: 1,
|
|
857
|
+
createdAt: -1
|
|
835
858
|
});
|
|
836
859
|
RBNotificationSchema.index({
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
expireAfterSeconds: TTL_90_DAYS_S$1
|
|
840
|
-
});
|
|
841
|
-
const RBNotificationPolicy = {
|
|
842
|
-
subject: "RBNotification",
|
|
843
|
-
define: (builder, ctx) => {
|
|
844
|
-
if (!ctx.userId) return;
|
|
845
|
-
builder.can("create", "RBNotification");
|
|
846
|
-
builder.can("read", "RBNotification", {
|
|
847
|
-
userId: ctx.userId
|
|
848
|
-
});
|
|
849
|
-
builder.can("update", "RBNotification", {
|
|
850
|
-
userId: ctx.userId
|
|
851
|
-
});
|
|
852
|
-
builder.can("delete", "RBNotification", {
|
|
853
|
-
userId: ctx.userId
|
|
854
|
-
});
|
|
855
|
-
}
|
|
856
|
-
};
|
|
857
|
-
const ZStringMap = z.record(z.string(), z.string());
|
|
858
|
-
const ZRBNotificationDelivery = z.object({
|
|
859
|
-
userId: z.string(),
|
|
860
|
-
notificationId: z.string().optional(),
|
|
861
|
-
deliveryId: z.string(),
|
|
862
|
-
topic: z.string().optional(),
|
|
863
|
-
tag: z.string().optional(),
|
|
864
|
-
title: z.string(),
|
|
865
|
-
body: z.string().optional(),
|
|
866
|
-
image: z.string().optional(),
|
|
867
|
-
data: ZStringMap.optional(),
|
|
868
|
-
platform: ZRBNotificationPlatformPayload.optional(),
|
|
869
|
-
createdAt: z.date()
|
|
870
|
-
});
|
|
871
|
-
const TTL_90_DAYS_S = 60 * 60 * 24 * 90;
|
|
872
|
-
const RBNotificationDeliverySchema = new Schema$1({
|
|
873
|
-
userId: {
|
|
874
|
-
type: String,
|
|
875
|
-
required: true,
|
|
876
|
-
index: true
|
|
877
|
-
},
|
|
878
|
-
notificationId: {
|
|
879
|
-
type: String,
|
|
880
|
-
required: false
|
|
881
|
-
},
|
|
882
|
-
deliveryId: {
|
|
883
|
-
type: String,
|
|
884
|
-
required: true,
|
|
885
|
-
unique: true
|
|
886
|
-
},
|
|
887
|
-
topic: {
|
|
888
|
-
type: String,
|
|
889
|
-
required: false
|
|
890
|
-
},
|
|
891
|
-
tag: {
|
|
892
|
-
type: String,
|
|
893
|
-
required: false
|
|
894
|
-
},
|
|
895
|
-
title: {
|
|
896
|
-
type: String,
|
|
897
|
-
required: true
|
|
898
|
-
},
|
|
899
|
-
body: {
|
|
900
|
-
type: String,
|
|
901
|
-
required: false
|
|
902
|
-
},
|
|
903
|
-
image: {
|
|
904
|
-
type: String,
|
|
905
|
-
required: false
|
|
906
|
-
},
|
|
907
|
-
data: {
|
|
908
|
-
type: Schema$1.Types.Mixed,
|
|
909
|
-
required: false
|
|
910
|
-
},
|
|
911
|
-
platform: {
|
|
912
|
-
type: Schema$1.Types.Mixed,
|
|
913
|
-
required: false
|
|
914
|
-
},
|
|
915
|
-
createdAt: {
|
|
916
|
-
type: Date,
|
|
917
|
-
required: true,
|
|
918
|
-
default: Date.now
|
|
919
|
-
}
|
|
860
|
+
userId: 1,
|
|
861
|
+
tag: 1
|
|
920
862
|
}, {
|
|
921
|
-
|
|
863
|
+
unique: true,
|
|
864
|
+
partialFilterExpression: {
|
|
865
|
+
tag: { $exists: true },
|
|
866
|
+
drawerActive: true
|
|
867
|
+
}
|
|
922
868
|
});
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
869
|
+
RBNotificationSchema.index({ archivedAt: 1 }, { expireAfterSeconds: TTL_90_DAYS_S$1 });
|
|
870
|
+
var RBNotificationPolicy = {
|
|
871
|
+
subject: "RBNotification",
|
|
872
|
+
define: (builder, ctx) => {
|
|
873
|
+
if (!ctx.userId) return;
|
|
874
|
+
builder.can("create", "RBNotification");
|
|
875
|
+
builder.can("read", "RBNotification", { userId: ctx.userId });
|
|
876
|
+
builder.can("update", "RBNotification", { userId: ctx.userId });
|
|
877
|
+
builder.can("delete", "RBNotification", { userId: ctx.userId });
|
|
878
|
+
}
|
|
879
|
+
};
|
|
880
|
+
//#endregion
|
|
881
|
+
//#region src/models/RBNotificationDelivery.ts
|
|
882
|
+
var ZStringMap = z$1.record(z$1.string(), z$1.string());
|
|
883
|
+
var ZRBNotificationDelivery = z$1.object({
|
|
884
|
+
userId: z$1.string(),
|
|
885
|
+
notificationId: z$1.string().optional(),
|
|
886
|
+
deliveryId: z$1.string(),
|
|
887
|
+
topic: z$1.string().optional(),
|
|
888
|
+
tag: z$1.string().optional(),
|
|
889
|
+
title: z$1.string(),
|
|
890
|
+
body: z$1.string().optional(),
|
|
891
|
+
image: z$1.string().optional(),
|
|
892
|
+
data: ZStringMap.optional(),
|
|
893
|
+
platform: ZRBNotificationPlatformPayload.optional(),
|
|
894
|
+
createdAt: z$1.date()
|
|
926
895
|
});
|
|
896
|
+
var TTL_90_DAYS_S = 3600 * 24 * 90;
|
|
897
|
+
var RBNotificationDeliverySchema = new Schema$1({
|
|
898
|
+
userId: {
|
|
899
|
+
type: String,
|
|
900
|
+
required: true,
|
|
901
|
+
index: true
|
|
902
|
+
},
|
|
903
|
+
notificationId: {
|
|
904
|
+
type: String,
|
|
905
|
+
required: false
|
|
906
|
+
},
|
|
907
|
+
deliveryId: {
|
|
908
|
+
type: String,
|
|
909
|
+
required: true,
|
|
910
|
+
unique: true
|
|
911
|
+
},
|
|
912
|
+
topic: {
|
|
913
|
+
type: String,
|
|
914
|
+
required: false
|
|
915
|
+
},
|
|
916
|
+
tag: {
|
|
917
|
+
type: String,
|
|
918
|
+
required: false
|
|
919
|
+
},
|
|
920
|
+
title: {
|
|
921
|
+
type: String,
|
|
922
|
+
required: true
|
|
923
|
+
},
|
|
924
|
+
body: {
|
|
925
|
+
type: String,
|
|
926
|
+
required: false
|
|
927
|
+
},
|
|
928
|
+
image: {
|
|
929
|
+
type: String,
|
|
930
|
+
required: false
|
|
931
|
+
},
|
|
932
|
+
data: {
|
|
933
|
+
type: Schema$1.Types.Mixed,
|
|
934
|
+
required: false
|
|
935
|
+
},
|
|
936
|
+
platform: {
|
|
937
|
+
type: Schema$1.Types.Mixed,
|
|
938
|
+
required: false
|
|
939
|
+
},
|
|
940
|
+
createdAt: {
|
|
941
|
+
type: Date,
|
|
942
|
+
required: true,
|
|
943
|
+
default: Date.now
|
|
944
|
+
}
|
|
945
|
+
}, { versionKey: false });
|
|
927
946
|
RBNotificationDeliverySchema.index({
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
expireAfterSeconds: TTL_90_DAYS_S
|
|
931
|
-
});
|
|
932
|
-
const RBNotificationDeliveryPolicy = {
|
|
933
|
-
subject: "RBNotificationDelivery",
|
|
934
|
-
define: (builder, ctx) => {
|
|
935
|
-
if (!ctx.userId) return;
|
|
936
|
-
builder.can("create", "RBNotificationDelivery");
|
|
937
|
-
builder.can("read", "RBNotificationDelivery", {
|
|
938
|
-
userId: ctx.userId
|
|
939
|
-
});
|
|
940
|
-
}
|
|
941
|
-
};
|
|
942
|
-
const ZRBNotificationDigestFrequency = z.enum(["off", "daily", "weekly"]);
|
|
943
|
-
const ZRBNotificationTopicPreference = z.object({
|
|
944
|
-
topic: z.string(),
|
|
945
|
-
inApp: z.boolean(),
|
|
946
|
-
emailDigest: z.boolean(),
|
|
947
|
-
push: z.boolean()
|
|
948
|
-
});
|
|
949
|
-
const ZRBNotificationSettings = z.object({
|
|
950
|
-
userId: z.string(),
|
|
951
|
-
digestFrequency: ZRBNotificationDigestFrequency,
|
|
952
|
-
topicPreferences: z.array(ZRBNotificationTopicPreference).optional(),
|
|
953
|
-
lastDigestSentAt: z.date().optional()
|
|
947
|
+
userId: 1,
|
|
948
|
+
createdAt: -1
|
|
954
949
|
});
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
_id: false
|
|
950
|
+
RBNotificationDeliverySchema.index({ createdAt: 1 }, { expireAfterSeconds: TTL_90_DAYS_S });
|
|
951
|
+
var RBNotificationDeliveryPolicy = {
|
|
952
|
+
subject: "RBNotificationDelivery",
|
|
953
|
+
define: (builder, ctx) => {
|
|
954
|
+
if (!ctx.userId) return;
|
|
955
|
+
builder.can("create", "RBNotificationDelivery");
|
|
956
|
+
builder.can("read", "RBNotificationDelivery", { userId: ctx.userId });
|
|
957
|
+
}
|
|
958
|
+
};
|
|
959
|
+
//#endregion
|
|
960
|
+
//#region src/models/RBNotificationSettings.ts
|
|
961
|
+
var ZRBNotificationDigestFrequency = z$1.enum([
|
|
962
|
+
"off",
|
|
963
|
+
"daily",
|
|
964
|
+
"weekly"
|
|
965
|
+
]);
|
|
966
|
+
var ZRBNotificationTopicPreference = z$1.object({
|
|
967
|
+
topic: z$1.string(),
|
|
968
|
+
inApp: z$1.boolean(),
|
|
969
|
+
emailDigest: z$1.boolean(),
|
|
970
|
+
push: z$1.boolean()
|
|
977
971
|
});
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
digestFrequency: {
|
|
984
|
-
type: String,
|
|
985
|
-
required: true,
|
|
986
|
-
enum: ZRBNotificationDigestFrequency.options,
|
|
987
|
-
default: "weekly"
|
|
988
|
-
},
|
|
989
|
-
topicPreferences: {
|
|
990
|
-
type: [TopicPreferenceSchema],
|
|
991
|
-
default: []
|
|
992
|
-
},
|
|
993
|
-
lastDigestSentAt: {
|
|
994
|
-
type: Date,
|
|
995
|
-
required: false
|
|
996
|
-
}
|
|
997
|
-
}, {
|
|
998
|
-
versionKey: false,
|
|
999
|
-
timestamps: true
|
|
972
|
+
var ZRBNotificationSettings = z$1.object({
|
|
973
|
+
userId: z$1.string(),
|
|
974
|
+
digestFrequency: ZRBNotificationDigestFrequency,
|
|
975
|
+
topicPreferences: z$1.array(ZRBNotificationTopicPreference).optional(),
|
|
976
|
+
lastDigestSentAt: z$1.date().optional()
|
|
1000
977
|
});
|
|
1001
|
-
|
|
1002
|
-
|
|
978
|
+
var TopicPreferenceSchema = new Schema$1({
|
|
979
|
+
topic: {
|
|
980
|
+
type: String,
|
|
981
|
+
required: true
|
|
982
|
+
},
|
|
983
|
+
inApp: {
|
|
984
|
+
type: Boolean,
|
|
985
|
+
required: true,
|
|
986
|
+
default: true
|
|
987
|
+
},
|
|
988
|
+
emailDigest: {
|
|
989
|
+
type: Boolean,
|
|
990
|
+
required: true,
|
|
991
|
+
default: true
|
|
992
|
+
},
|
|
993
|
+
push: {
|
|
994
|
+
type: Boolean,
|
|
995
|
+
required: true,
|
|
996
|
+
default: false
|
|
997
|
+
}
|
|
998
|
+
}, { _id: false });
|
|
999
|
+
var RBNotificationSettingsSchema = new Schema$1({
|
|
1000
|
+
userId: {
|
|
1001
|
+
type: String,
|
|
1002
|
+
required: true
|
|
1003
|
+
},
|
|
1004
|
+
digestFrequency: {
|
|
1005
|
+
type: String,
|
|
1006
|
+
required: true,
|
|
1007
|
+
enum: ZRBNotificationDigestFrequency.options,
|
|
1008
|
+
default: "weekly"
|
|
1009
|
+
},
|
|
1010
|
+
topicPreferences: {
|
|
1011
|
+
type: [TopicPreferenceSchema],
|
|
1012
|
+
default: []
|
|
1013
|
+
},
|
|
1014
|
+
lastDigestSentAt: {
|
|
1015
|
+
type: Date,
|
|
1016
|
+
required: false
|
|
1017
|
+
}
|
|
1003
1018
|
}, {
|
|
1004
|
-
|
|
1019
|
+
versionKey: false,
|
|
1020
|
+
timestamps: true
|
|
1005
1021
|
});
|
|
1022
|
+
RBNotificationSettingsSchema.index({ userId: 1 }, { unique: true });
|
|
1006
1023
|
RBNotificationSettingsSchema.index({
|
|
1007
|
-
|
|
1008
|
-
|
|
1024
|
+
userId: 1,
|
|
1025
|
+
"topicPreferences.topic": 1
|
|
1009
1026
|
});
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
createdAt: z.date(),
|
|
1029
|
-
expiresAt: z.date()
|
|
1027
|
+
var RBNotificationSettingsPolicy = {
|
|
1028
|
+
subject: "RBNotificationSettings",
|
|
1029
|
+
define: (builder, ctx) => {
|
|
1030
|
+
if (!ctx.userId) return;
|
|
1031
|
+
builder.can("create", "RBNotificationSettings");
|
|
1032
|
+
builder.can("read", "RBNotificationSettings", { userId: ctx.userId });
|
|
1033
|
+
builder.can("update", "RBNotificationSettings", { userId: ctx.userId });
|
|
1034
|
+
}
|
|
1035
|
+
};
|
|
1036
|
+
//#endregion
|
|
1037
|
+
//#region src/models/RBOAuthRequest.ts
|
|
1038
|
+
var ZRBOAuthRequest = z$1.object({
|
|
1039
|
+
_id: z$1.string(),
|
|
1040
|
+
providerId: z$1.string(),
|
|
1041
|
+
codeVerifier: z$1.string(),
|
|
1042
|
+
returnTo: z$1.string().optional(),
|
|
1043
|
+
createdAt: z$1.date(),
|
|
1044
|
+
expiresAt: z$1.date()
|
|
1030
1045
|
});
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
}, {
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1046
|
+
var RBOAuthRequestSchema = new Schema$1({
|
|
1047
|
+
_id: {
|
|
1048
|
+
type: String,
|
|
1049
|
+
required: true
|
|
1050
|
+
},
|
|
1051
|
+
providerId: {
|
|
1052
|
+
type: String,
|
|
1053
|
+
required: true,
|
|
1054
|
+
index: true
|
|
1055
|
+
},
|
|
1056
|
+
codeVerifier: {
|
|
1057
|
+
type: String,
|
|
1058
|
+
required: true
|
|
1059
|
+
},
|
|
1060
|
+
returnTo: {
|
|
1061
|
+
type: String,
|
|
1062
|
+
required: false
|
|
1063
|
+
},
|
|
1064
|
+
createdAt: {
|
|
1065
|
+
type: Date,
|
|
1066
|
+
required: true,
|
|
1067
|
+
default: Date.now
|
|
1068
|
+
},
|
|
1069
|
+
expiresAt: {
|
|
1070
|
+
type: Date,
|
|
1071
|
+
required: true
|
|
1072
|
+
}
|
|
1073
|
+
}, { versionKey: false });
|
|
1074
|
+
RBOAuthRequestSchema.index({ expiresAt: 1 }, { expireAfterSeconds: 0 });
|
|
1075
|
+
//#endregion
|
|
1076
|
+
//#region src/models/index.ts
|
|
1077
|
+
var models_exports = /* @__PURE__ */ __exportAll({
|
|
1078
|
+
RBNotificationDeliveryPolicy: () => RBNotificationDeliveryPolicy,
|
|
1079
|
+
RBNotificationDeliverySchema: () => RBNotificationDeliverySchema,
|
|
1080
|
+
RBNotificationPolicy: () => RBNotificationPolicy,
|
|
1081
|
+
RBNotificationSchema: () => RBNotificationSchema,
|
|
1082
|
+
RBNotificationSettingsPolicy: () => RBNotificationSettingsPolicy,
|
|
1083
|
+
RBNotificationSettingsSchema: () => RBNotificationSettingsSchema,
|
|
1084
|
+
RBOAuthRequestSchema: () => RBOAuthRequestSchema,
|
|
1085
|
+
RBRtsChangeSchema: () => RBRtsChangeSchema,
|
|
1086
|
+
RBRtsCounterSchema: () => RBRtsCounterSchema,
|
|
1087
|
+
RBTenantSchema: () => RBTenantSchema,
|
|
1088
|
+
RBTenantSubscriptionEventSchema: () => RBTenantSubscriptionEventSchema,
|
|
1089
|
+
RBTenantSubscriptionProjectionSchema: () => RBTenantSubscriptionProjectionSchema,
|
|
1090
|
+
RBUploadChunkSchema: () => RBUploadChunkSchema,
|
|
1091
|
+
RBUploadSessionPolicy: () => RBUploadSessionPolicy,
|
|
1092
|
+
RBUploadSessionSchema: () => RBUploadSessionSchema,
|
|
1093
|
+
RBUserSchema: () => RBUserSchema,
|
|
1094
|
+
ZRBNotification: () => ZRBNotification,
|
|
1095
|
+
ZRBNotificationDelivery: () => ZRBNotificationDelivery,
|
|
1096
|
+
ZRBNotificationDigestFrequency: () => ZRBNotificationDigestFrequency,
|
|
1097
|
+
ZRBNotificationPlatformPayload: () => ZRBNotificationPlatformPayload,
|
|
1098
|
+
ZRBNotificationSettings: () => ZRBNotificationSettings,
|
|
1099
|
+
ZRBNotificationTopicPreference: () => ZRBNotificationTopicPreference,
|
|
1100
|
+
ZRBOAuthRequest: () => ZRBOAuthRequest,
|
|
1101
|
+
ZRBRtsChange: () => ZRBRtsChange,
|
|
1102
|
+
ZRBRtsChangeOp: () => ZRBRtsChangeOp,
|
|
1103
|
+
ZRBRtsCounter: () => ZRBRtsCounter,
|
|
1104
|
+
ZRBTenant: () => ZRBTenant,
|
|
1105
|
+
ZRBTenantSubscriptionChangeDirection: () => ZRBTenantSubscriptionChangeDirection,
|
|
1106
|
+
ZRBTenantSubscriptionEvent: () => ZRBTenantSubscriptionEvent,
|
|
1107
|
+
ZRBTenantSubscriptionEventSource: () => ZRBTenantSubscriptionEventSource,
|
|
1108
|
+
ZRBTenantSubscriptionEventType: () => ZRBTenantSubscriptionEventType,
|
|
1109
|
+
ZRBTenantSubscriptionIntervalUnit: () => ZRBTenantSubscriptionIntervalUnit,
|
|
1110
|
+
ZRBTenantSubscriptionProjection: () => ZRBTenantSubscriptionProjection,
|
|
1111
|
+
ZRBTenantSubscriptionScope: () => ZRBTenantSubscriptionScope,
|
|
1112
|
+
ZRBTenantSubscriptionStatus: () => ZRBTenantSubscriptionStatus,
|
|
1113
|
+
ZRBTenantSubscriptionType: () => ZRBTenantSubscriptionType,
|
|
1114
|
+
ZRBUploadChunk: () => ZRBUploadChunk,
|
|
1115
|
+
ZRBUploadSession: () => ZRBUploadSession,
|
|
1116
|
+
ZRBUploadSessionStatus: () => ZRBUploadSessionStatus,
|
|
1117
|
+
ZRBUser: () => ZRBUser
|
|
1065
1118
|
});
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
RBNotificationDeliveryPolicy,
|
|
1069
|
-
RBNotificationDeliverySchema,
|
|
1070
|
-
RBNotificationPolicy,
|
|
1071
|
-
RBNotificationSchema,
|
|
1072
|
-
RBNotificationSettingsPolicy,
|
|
1073
|
-
RBNotificationSettingsSchema,
|
|
1074
|
-
RBOAuthRequestSchema,
|
|
1075
|
-
RBRtsChangeSchema,
|
|
1076
|
-
RBRtsCounterSchema,
|
|
1077
|
-
RBTenantSchema,
|
|
1078
|
-
RBTenantSubscriptionEventSchema,
|
|
1079
|
-
RBTenantSubscriptionProjectionSchema,
|
|
1080
|
-
RBUploadChunkSchema,
|
|
1081
|
-
RBUploadSessionPolicy,
|
|
1082
|
-
RBUploadSessionSchema,
|
|
1083
|
-
RBUserSchema,
|
|
1084
|
-
ZRBNotification,
|
|
1085
|
-
ZRBNotificationDelivery,
|
|
1086
|
-
ZRBNotificationDigestFrequency,
|
|
1087
|
-
ZRBNotificationPlatformPayload,
|
|
1088
|
-
ZRBNotificationSettings,
|
|
1089
|
-
ZRBNotificationTopicPreference,
|
|
1090
|
-
ZRBOAuthRequest,
|
|
1091
|
-
ZRBRtsChange,
|
|
1092
|
-
ZRBRtsChangeOp,
|
|
1093
|
-
ZRBRtsCounter,
|
|
1094
|
-
ZRBTenant,
|
|
1095
|
-
ZRBTenantSubscriptionChangeDirection,
|
|
1096
|
-
ZRBTenantSubscriptionEvent,
|
|
1097
|
-
ZRBTenantSubscriptionEventSource,
|
|
1098
|
-
ZRBTenantSubscriptionEventType,
|
|
1099
|
-
ZRBTenantSubscriptionIntervalUnit,
|
|
1100
|
-
ZRBTenantSubscriptionProjection,
|
|
1101
|
-
ZRBTenantSubscriptionScope,
|
|
1102
|
-
ZRBTenantSubscriptionStatus,
|
|
1103
|
-
ZRBTenantSubscriptionType,
|
|
1104
|
-
ZRBUploadChunk,
|
|
1105
|
-
ZRBUploadSession,
|
|
1106
|
-
ZRBUploadSessionStatus,
|
|
1107
|
-
ZRBUser
|
|
1108
|
-
}, Symbol.toStringTag, { value: "Module" }));
|
|
1119
|
+
//#endregion
|
|
1120
|
+
//#region src/mongoose/extendMongooseSchema.ts
|
|
1109
1121
|
function extendMongooseSchema(baseSchema, ...extensions) {
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1122
|
+
const schema = baseSchema.clone();
|
|
1123
|
+
extensions.forEach((extension) => schema.add(extension));
|
|
1124
|
+
return schema;
|
|
1113
1125
|
}
|
|
1114
1126
|
function omitMongooseSchemaPaths(schema, paths) {
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1127
|
+
const clone = schema.clone();
|
|
1128
|
+
paths.forEach((path) => clone.remove(path));
|
|
1129
|
+
return clone;
|
|
1118
1130
|
}
|
|
1131
|
+
//#endregion
|
|
1132
|
+
//#region src/mongoose/localizedStringField.ts
|
|
1119
1133
|
function localizedStringField(options) {
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1134
|
+
const userGet = options?.get;
|
|
1135
|
+
return {
|
|
1136
|
+
...options,
|
|
1137
|
+
type: Schema$1.Types.Mixed,
|
|
1138
|
+
get: (value) => withLocalizedStringFallback(userGet ? userGet(value) : value)
|
|
1139
|
+
};
|
|
1126
1140
|
}
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
}
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
};
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
}
|
|
1211
|
-
const
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
}
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
};
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
const
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
const
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
const
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
}
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
const
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
const
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
const
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
const
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
};
|
|
1625
|
-
|
|
1626
|
-
const
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
const
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
};
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
}
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
const
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
};
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
};
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
};
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
};
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
};
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
injectAggregateMatch(aggregate.pipeline(), accessQuery);
|
|
1901
|
-
};
|
|
1902
|
-
const patchAggregateAcl = () => {
|
|
1903
|
-
const globalKey = /* @__PURE__ */ Symbol.for("@rpcbase/db/acl/mongooseAggregateAclPatched");
|
|
1904
|
-
const globalState = globalThis;
|
|
1905
|
-
if (globalState[globalKey]) return;
|
|
1906
|
-
globalState[globalKey] = true;
|
|
1907
|
-
const AggregatePrototype = mongoose.Aggregate.prototype;
|
|
1908
|
-
if (typeof AggregatePrototype.acl === "function") return;
|
|
1909
|
-
AggregatePrototype.acl = function(ability, action = "read") {
|
|
1910
|
-
this.option({
|
|
1911
|
-
rbAcl: {
|
|
1912
|
-
ability,
|
|
1913
|
-
action
|
|
1914
|
-
}
|
|
1915
|
-
});
|
|
1916
|
-
return this;
|
|
1917
|
-
};
|
|
1918
|
-
};
|
|
1919
|
-
const createModelAclProxy = (model2, ability) => {
|
|
1920
|
-
return new Proxy(model2, {
|
|
1921
|
-
get(target, prop, receiver) {
|
|
1922
|
-
if (prop === "acl") {
|
|
1923
|
-
return () => {
|
|
1924
|
-
throw new Error(`Model "${target.modelName}" is already ACL-scoped. Do not call .acl(...) again.`);
|
|
1925
|
-
};
|
|
1926
|
-
}
|
|
1927
|
-
const value = Reflect.get(target, prop, receiver);
|
|
1928
|
-
if (typeof value !== "function") return value;
|
|
1929
|
-
return (...args) => {
|
|
1930
|
-
const result = Reflect.apply(value, target, args);
|
|
1931
|
-
if (result && typeof result === "object" && "acl" in result && typeof result.acl === "function") {
|
|
1932
|
-
return result.acl(ability);
|
|
1933
|
-
}
|
|
1934
|
-
return result;
|
|
1935
|
-
};
|
|
1936
|
-
}
|
|
1937
|
-
});
|
|
1938
|
-
};
|
|
1939
|
-
const mongooseAclPlugin = (schema) => {
|
|
1940
|
-
patchAggregateAcl();
|
|
1941
|
-
schema.query.acl = function(ability, action) {
|
|
1942
|
-
this.setOptions({
|
|
1943
|
-
rbAcl: {
|
|
1944
|
-
ability,
|
|
1945
|
-
action
|
|
1946
|
-
}
|
|
1947
|
-
});
|
|
1948
|
-
return this;
|
|
1949
|
-
};
|
|
1950
|
-
schema.statics.acl = function(ability) {
|
|
1951
|
-
return createModelAclProxy(this, ability);
|
|
1952
|
-
};
|
|
1953
|
-
schema.pre("aggregate", function() {
|
|
1954
|
-
addAggregateAclFilter(this, "read");
|
|
1955
|
-
});
|
|
1956
|
-
schema.pre("countDocuments", function() {
|
|
1957
|
-
addQueryAclFilter(this, "read");
|
|
1958
|
-
});
|
|
1959
|
-
schema.pre("deleteMany", function() {
|
|
1960
|
-
addQueryAclFilter(this, "delete");
|
|
1961
|
-
});
|
|
1962
|
-
schema.pre("deleteOne", function() {
|
|
1963
|
-
addQueryAclFilter(this, "delete");
|
|
1964
|
-
});
|
|
1965
|
-
schema.pre("distinct", function() {
|
|
1966
|
-
addQueryAclFilter(this, "read");
|
|
1967
|
-
});
|
|
1968
|
-
schema.pre("find", function() {
|
|
1969
|
-
addQueryAclFilter(this, "read");
|
|
1970
|
-
});
|
|
1971
|
-
schema.pre("findOne", function() {
|
|
1972
|
-
addQueryAclFilter(this, "read");
|
|
1973
|
-
});
|
|
1974
|
-
schema.pre("findOneAndDelete", function() {
|
|
1975
|
-
addQueryAclFilter(this, "delete");
|
|
1976
|
-
});
|
|
1977
|
-
schema.pre("findOneAndReplace", function() {
|
|
1978
|
-
addQueryAclFilter(this, "update");
|
|
1979
|
-
});
|
|
1980
|
-
schema.pre("findOneAndUpdate", function() {
|
|
1981
|
-
addQueryAclFilter(this, "update");
|
|
1982
|
-
});
|
|
1983
|
-
schema.pre("replaceOne", function() {
|
|
1984
|
-
addQueryAclFilter(this, "update");
|
|
1985
|
-
});
|
|
1986
|
-
schema.pre("updateMany", function() {
|
|
1987
|
-
addQueryAclFilter(this, "update");
|
|
1988
|
-
});
|
|
1989
|
-
schema.pre("updateOne", function() {
|
|
1990
|
-
addQueryAclFilter(this, "update");
|
|
1991
|
-
});
|
|
1992
|
-
};
|
|
1993
|
-
let cachedModels = null;
|
|
1994
|
-
const DEFAULT_GLOBAL_RB_MODEL_NAMES_SET = /* @__PURE__ */ new Set(["RBUser", "RBTenant", "RBOAuthRequest"]);
|
|
1995
|
-
const assertSchema = (exportName, value) => {
|
|
1996
|
-
if (value instanceof mongoose.Schema) return value;
|
|
1997
|
-
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(" "));
|
|
1998
|
-
};
|
|
1999
|
-
const getFrameworkSchemaForModelName = (modelName) => {
|
|
2000
|
-
const exportName = `${modelName}Schema`;
|
|
2001
|
-
const value = frameworkSchemas[exportName];
|
|
2002
|
-
if (!(value instanceof mongoose.Schema)) return null;
|
|
2003
|
-
return value;
|
|
2004
|
-
};
|
|
2005
|
-
const applyTenantPlugins = (schema) => {
|
|
2006
|
-
schema.plugin(accessibleRecordsPlugin);
|
|
2007
|
-
schema.plugin(mongooseAclPlugin);
|
|
2008
|
-
schema.plugin(mongoPaginationPlugin);
|
|
2009
|
-
schema.plugin(rtsChangeLogPlugin);
|
|
2010
|
-
};
|
|
2011
|
-
const registerSchema = (target, other, modelName, schema, scope) => {
|
|
2012
|
-
if (target[modelName] || other[modelName]) {
|
|
2013
|
-
throw new Error(`Duplicate model name "${modelName}" across tenant/global scopes`);
|
|
2014
|
-
}
|
|
2015
|
-
target[modelName] = schema;
|
|
2016
|
-
};
|
|
2017
|
-
const buildSchemasFromModules = (modules) => Object.entries(modules).filter(([key]) => key.endsWith("Schema")).map(([key, schemaValue]) => {
|
|
2018
|
-
const schema = assertSchema(key, schemaValue);
|
|
2019
|
-
const modelName = key.replace(/Schema$/, "");
|
|
2020
|
-
return {
|
|
2021
|
-
modelName,
|
|
2022
|
-
schema
|
|
2023
|
-
};
|
|
2024
|
-
});
|
|
2025
|
-
const registerModels = ({
|
|
2026
|
-
tenant,
|
|
2027
|
-
global
|
|
2028
|
-
}, options = {}) => {
|
|
2029
|
-
registerPoliciesFromModules(frameworkSchemas);
|
|
2030
|
-
registerPoliciesFromModules(tenant);
|
|
2031
|
-
const tenantSchemas = {};
|
|
2032
|
-
const globalSchemas = {};
|
|
2033
|
-
const allowReservedRbModelNames = options.allowReservedRbModelNames === true;
|
|
2034
|
-
for (const {
|
|
2035
|
-
modelName,
|
|
2036
|
-
schema
|
|
2037
|
-
} of buildSchemasFromModules(frameworkSchemas)) {
|
|
2038
|
-
if (DEFAULT_GLOBAL_RB_MODEL_NAMES_SET.has(modelName)) {
|
|
2039
|
-
const cloned = schema.clone();
|
|
2040
|
-
registerSchema(globalSchemas, tenantSchemas, modelName, cloned);
|
|
2041
|
-
} else {
|
|
2042
|
-
const cloned = schema.clone();
|
|
2043
|
-
applyTenantPlugins(cloned);
|
|
2044
|
-
registerSchema(tenantSchemas, globalSchemas, modelName, cloned);
|
|
2045
|
-
}
|
|
2046
|
-
}
|
|
2047
|
-
for (const {
|
|
2048
|
-
modelName,
|
|
2049
|
-
schema
|
|
2050
|
-
} of buildSchemasFromModules(tenant)) {
|
|
2051
|
-
if (modelName === "RBUser" || modelName === "RBTenant") {
|
|
2052
|
-
throw new Error(`Invalid tenant model name "${modelName}". RBUser/RBTenant are global models.`);
|
|
2053
|
-
}
|
|
2054
|
-
if (modelName.startsWith("RB")) {
|
|
2055
|
-
const frameworkSchema = getFrameworkSchemaForModelName(modelName);
|
|
2056
|
-
if (frameworkSchema && schema === frameworkSchema) continue;
|
|
2057
|
-
if (!allowReservedRbModelNames) {
|
|
2058
|
-
throw new Error(`Invalid tenant model name "${modelName}". RB* models are reserved for rpcbase.`);
|
|
2059
|
-
}
|
|
2060
|
-
}
|
|
2061
|
-
const cloned = schema.clone();
|
|
2062
|
-
applyTenantPlugins(cloned);
|
|
2063
|
-
registerSchema(tenantSchemas, globalSchemas, modelName, cloned);
|
|
2064
|
-
}
|
|
2065
|
-
for (const {
|
|
2066
|
-
modelName,
|
|
2067
|
-
schema
|
|
2068
|
-
} of buildSchemasFromModules(global ?? {})) {
|
|
2069
|
-
if (modelName.startsWith("RB")) {
|
|
2070
|
-
const frameworkSchema = getFrameworkSchemaForModelName(modelName);
|
|
2071
|
-
if (frameworkSchema && schema === frameworkSchema) continue;
|
|
2072
|
-
if (!allowReservedRbModelNames) {
|
|
2073
|
-
throw new Error(`Invalid global model name "${modelName}". RB* models are reserved for rpcbase.`);
|
|
2074
|
-
}
|
|
2075
|
-
}
|
|
2076
|
-
const cloned = schema.clone();
|
|
2077
|
-
registerSchema(globalSchemas, tenantSchemas, modelName, cloned);
|
|
2078
|
-
}
|
|
2079
|
-
const allSchemas = {
|
|
2080
|
-
...globalSchemas,
|
|
2081
|
-
...tenantSchemas
|
|
2082
|
-
};
|
|
2083
|
-
for (const [modelName, schema] of Object.entries(allSchemas)) {
|
|
2084
|
-
if (!mongoose.models[modelName]) {
|
|
2085
|
-
mongoose.model(modelName, schema);
|
|
2086
|
-
}
|
|
2087
|
-
}
|
|
2088
|
-
cachedModels = {
|
|
2089
|
-
tenant: {
|
|
2090
|
-
...cachedModels?.tenant ?? {},
|
|
2091
|
-
...tenantSchemas
|
|
2092
|
-
},
|
|
2093
|
-
global: {
|
|
2094
|
-
...cachedModels?.global ?? {},
|
|
2095
|
-
...globalSchemas
|
|
2096
|
-
}
|
|
2097
|
-
};
|
|
2098
|
-
};
|
|
2099
|
-
const getRegisteredModels = (scope) => {
|
|
2100
|
-
if (!cachedModels) {
|
|
2101
|
-
throw new Error("Models not registered. Call createModels(...) once at startup (or import your models module) before using models.get.");
|
|
2102
|
-
}
|
|
2103
|
-
return cachedModels[scope];
|
|
2104
|
-
};
|
|
2105
|
-
const loadModelFromDb = async (modelName, dbName, scope) => {
|
|
2106
|
-
const schemas = getRegisteredModels(scope);
|
|
2107
|
-
const schema = schemas[modelName];
|
|
2108
|
-
assert(schema, `Model ${modelName} not registered. Available models: ${Object.keys(schemas).join(", ")}`);
|
|
2109
|
-
const modelConnection = await ensureMongooseConnection(dbName);
|
|
2110
|
-
if (!modelConnection.models[modelName]) {
|
|
2111
|
-
modelConnection.model(modelName, schema);
|
|
2112
|
-
}
|
|
2113
|
-
return modelConnection.models[modelName];
|
|
2114
|
-
};
|
|
2115
|
-
const normalizeTenantId$1 = (value) => {
|
|
2116
|
-
if (typeof value !== "string") return null;
|
|
2117
|
-
const tenantId = value.trim();
|
|
2118
|
-
return tenantId || null;
|
|
2119
|
-
};
|
|
2120
|
-
const getTenantIdFromLoadModelCtx = (ctx) => {
|
|
2121
|
-
const tenantId = normalizeTenantId$1(ctx.tenantId) ?? normalizeTenantId$1(ctx.req?.session?.user?.currentTenantId);
|
|
2122
|
-
assert(tenantId, "Tenant ID is missing from ctx (expected ctx.tenantId or ctx.req.session.user.currentTenantId)");
|
|
2123
|
-
return tenantId;
|
|
2124
|
-
};
|
|
2125
|
-
const models = {
|
|
2126
|
-
register: registerModels,
|
|
2127
|
-
getUnsafe: async (modelName, ctx) => {
|
|
2128
|
-
const tenantId = getTenantIdFromLoadModelCtx(ctx);
|
|
2129
|
-
const dbName = getTenantDbName(tenantId);
|
|
2130
|
-
return loadModelFromDb(modelName, dbName, "tenant");
|
|
2131
|
-
},
|
|
2132
|
-
get: async (modelName, ctx) => {
|
|
2133
|
-
const model2 = await models.getUnsafe(modelName, ctx);
|
|
2134
|
-
const resolvedAbility = ctx.ability;
|
|
2135
|
-
const isProtected = hasRegisteredPolicy(modelName);
|
|
2136
|
-
if (!isProtected) {
|
|
2137
|
-
return model2;
|
|
2138
|
-
}
|
|
2139
|
-
if (!resolvedAbility) {
|
|
2140
|
-
throw new Error(`Model "${modelName}" is ACL-protected. Set ctx.ability or use models.getUnsafe(...) explicitly.`);
|
|
2141
|
-
}
|
|
2142
|
-
if (typeof model2.acl !== "function") return model2;
|
|
2143
|
-
return model2.acl(resolvedAbility);
|
|
2144
|
-
},
|
|
2145
|
-
getGlobal: async (modelName, ctx) => {
|
|
2146
|
-
const dbName = getGlobalDbName();
|
|
2147
|
-
return loadModelFromDb(modelName, dbName, "global");
|
|
2148
|
-
}
|
|
2149
|
-
};
|
|
2150
|
-
const createModels = (modules, options) => {
|
|
2151
|
-
registerModels(modules, options);
|
|
2152
|
-
const get = (async (modelNameOrNames, ctx) => {
|
|
2153
|
-
if (Array.isArray(modelNameOrNames)) {
|
|
2154
|
-
return Promise.all(modelNameOrNames.map((modelName) => models.get(modelName, ctx)));
|
|
2155
|
-
}
|
|
2156
|
-
return models.get(modelNameOrNames, ctx);
|
|
2157
|
-
});
|
|
2158
|
-
const getUnsafe = (async (modelNameOrNames, ctx) => {
|
|
2159
|
-
if (Array.isArray(modelNameOrNames)) {
|
|
2160
|
-
return Promise.all(modelNameOrNames.map((modelName) => models.getUnsafe(modelName, ctx)));
|
|
2161
|
-
}
|
|
2162
|
-
return models.getUnsafe(modelNameOrNames, ctx);
|
|
2163
|
-
});
|
|
2164
|
-
const getGlobal = (async (modelNameOrNames, ctx) => {
|
|
2165
|
-
if (Array.isArray(modelNameOrNames)) {
|
|
2166
|
-
return Promise.all(modelNameOrNames.map((modelName) => models.getGlobal(modelName, ctx)));
|
|
2167
|
-
}
|
|
2168
|
-
return models.getGlobal(modelNameOrNames, ctx);
|
|
2169
|
-
});
|
|
2170
|
-
return {
|
|
2171
|
-
register: (nextModules, nextOptions) => registerModels(nextModules, nextOptions),
|
|
2172
|
-
get,
|
|
2173
|
-
getUnsafe,
|
|
2174
|
-
getGlobal
|
|
2175
|
-
};
|
|
2176
|
-
};
|
|
2177
|
-
const getAppName = () => {
|
|
2178
|
-
const appName = process.env.APP_NAME?.trim();
|
|
2179
|
-
assert(appName, "Missing APP_NAME");
|
|
2180
|
-
return appName;
|
|
2181
|
-
};
|
|
2182
|
-
const normalizeTenantId = (tenantId) => {
|
|
2183
|
-
const normalized = tenantId.trim();
|
|
2184
|
-
assert(normalized, "Tenant ID is missing");
|
|
2185
|
-
return normalized;
|
|
2186
|
-
};
|
|
2187
|
-
const getTenantFilesystemDbName = (tenantId) => `${getAppName()}-${normalizeTenantId(tenantId)}-filesystem-db`;
|
|
2188
|
-
const getTenantFilesystemDb = async (tenantId) => ensureMongooseConnection(getTenantFilesystemDbName(tenantId));
|
|
2189
|
-
const getTenantFilesystemDbFromCtx = async (ctx) => {
|
|
2190
|
-
const tenantId = getTenantIdFromLoadModelCtx(ctx);
|
|
2191
|
-
return getTenantFilesystemDb(tenantId);
|
|
2192
|
-
};
|
|
2193
|
-
const buildTenantLoadModelCtx = (tenantId) => ({
|
|
2194
|
-
req: {
|
|
2195
|
-
session: {
|
|
2196
|
-
user: {
|
|
2197
|
-
currentTenantId: tenantId
|
|
2198
|
-
}
|
|
2199
|
-
}
|
|
2200
|
-
}
|
|
1141
|
+
//#endregion
|
|
1142
|
+
//#region src/mongoose/index.ts
|
|
1143
|
+
var { Schema, model } = mongoose;
|
|
1144
|
+
//#endregion
|
|
1145
|
+
//#region src/pagination/errors.ts
|
|
1146
|
+
var PaginationValidationError = class extends Error {
|
|
1147
|
+
code = "invalid_pagination";
|
|
1148
|
+
statusCode = 400;
|
|
1149
|
+
constructor(message, options) {
|
|
1150
|
+
super(message, options);
|
|
1151
|
+
this.name = "PaginationValidationError";
|
|
1152
|
+
}
|
|
1153
|
+
};
|
|
1154
|
+
var isPaginationValidationError = (error) => {
|
|
1155
|
+
if (!error || typeof error !== "object") return false;
|
|
1156
|
+
const anyError = error;
|
|
1157
|
+
return anyError.name === "PaginationValidationError" && anyError.code === "invalid_pagination" && anyError.statusCode === 400;
|
|
1158
|
+
};
|
|
1159
|
+
//#endregion
|
|
1160
|
+
//#region src/pagination/normalizeSpec.ts
|
|
1161
|
+
var DISALLOWED_MONGO_FIELD_SEGMENTS = /* @__PURE__ */ new Set([
|
|
1162
|
+
"__proto__",
|
|
1163
|
+
"constructor",
|
|
1164
|
+
"prototype"
|
|
1165
|
+
]);
|
|
1166
|
+
var PAGINATION_LIMIT_MAX = 128;
|
|
1167
|
+
var normalizePaginationSpec = (spec, options = {}) => {
|
|
1168
|
+
if (!spec || typeof spec !== "object") throw new PaginationValidationError("Invalid PaginationSpec");
|
|
1169
|
+
const limit = normalizeLimit(spec.limit, normalizeMaxLimit(options.maxLimit));
|
|
1170
|
+
const direction = spec.direction ?? "next";
|
|
1171
|
+
if (direction !== "next" && direction !== "prev") throw new PaginationValidationError("Invalid pagination direction");
|
|
1172
|
+
if (!Array.isArray(spec.sort) || spec.sort.length === 0) throw new PaginationValidationError("Invalid pagination sort");
|
|
1173
|
+
const sort = spec.sort.map(({ field, order }) => ({
|
|
1174
|
+
field: assertSafeMongoFieldPath(field),
|
|
1175
|
+
order: normalizeOrder(order)
|
|
1176
|
+
}));
|
|
1177
|
+
const seenFields = /* @__PURE__ */ new Set();
|
|
1178
|
+
for (const { field } of sort) {
|
|
1179
|
+
if (seenFields.has(field)) throw new PaginationValidationError(`Duplicate pagination sort field: ${field}`);
|
|
1180
|
+
seenFields.add(field);
|
|
1181
|
+
}
|
|
1182
|
+
const primaryOrder = sort[0]?.order;
|
|
1183
|
+
if (!seenFields.has("_id")) sort.push({
|
|
1184
|
+
field: "_id",
|
|
1185
|
+
order: primaryOrder
|
|
1186
|
+
});
|
|
1187
|
+
return {
|
|
1188
|
+
...spec,
|
|
1189
|
+
limit,
|
|
1190
|
+
direction,
|
|
1191
|
+
sort
|
|
1192
|
+
};
|
|
1193
|
+
};
|
|
1194
|
+
var normalizeMaxLimit = (maxLimit) => {
|
|
1195
|
+
if (maxLimit === void 0) return PAGINATION_LIMIT_MAX;
|
|
1196
|
+
if (!Number.isSafeInteger(maxLimit) || maxLimit <= 0) throw new PaginationValidationError("Invalid pagination max limit");
|
|
1197
|
+
return maxLimit;
|
|
1198
|
+
};
|
|
1199
|
+
var normalizeLimit = (limit, maxLimit) => {
|
|
1200
|
+
if (typeof limit !== "number" || !Number.isFinite(limit) || !Number.isInteger(limit) || limit <= 0) throw new PaginationValidationError("Invalid pagination limit");
|
|
1201
|
+
if (limit > maxLimit) throw new PaginationValidationError("Invalid pagination limit");
|
|
1202
|
+
return limit;
|
|
1203
|
+
};
|
|
1204
|
+
var normalizeOrder = (order) => {
|
|
1205
|
+
if (order !== "asc" && order !== "desc") throw new PaginationValidationError("Invalid pagination order");
|
|
1206
|
+
return order;
|
|
1207
|
+
};
|
|
1208
|
+
var assertSafeMongoFieldPath = (field) => {
|
|
1209
|
+
if (typeof field !== "string" || field.length === 0) throw new PaginationValidationError("Invalid pagination sort field");
|
|
1210
|
+
if (field.startsWith("$")) throw new PaginationValidationError("Invalid pagination sort field");
|
|
1211
|
+
const parts = field.split(".");
|
|
1212
|
+
for (const part of parts) {
|
|
1213
|
+
if (part.length === 0) throw new PaginationValidationError("Invalid pagination sort field");
|
|
1214
|
+
if (DISALLOWED_MONGO_FIELD_SEGMENTS.has(part)) throw new PaginationValidationError("Invalid pagination sort field");
|
|
1215
|
+
if (!/^[a-zA-Z0-9_]+$/.test(part)) throw new PaginationValidationError("Invalid pagination sort field");
|
|
1216
|
+
}
|
|
1217
|
+
return field;
|
|
1218
|
+
};
|
|
1219
|
+
//#endregion
|
|
1220
|
+
//#region src/pagination/cursor.ts
|
|
1221
|
+
var encodePaginationCursor = (spec, node, options) => {
|
|
1222
|
+
const normalized = normalizePaginationSpec(spec, { maxLimit: options.maxLimit });
|
|
1223
|
+
const values = Object.create(null);
|
|
1224
|
+
for (const { field } of normalized.sort) {
|
|
1225
|
+
const value = readFieldValue(node, field);
|
|
1226
|
+
if (typeof value === "undefined") throw new Error(`Pagination cursor encode failed (missing field: ${field})`);
|
|
1227
|
+
values[field] = encodeCursorValue(field, value);
|
|
1228
|
+
}
|
|
1229
|
+
const payload = {
|
|
1230
|
+
v: 1,
|
|
1231
|
+
values
|
|
1232
|
+
};
|
|
1233
|
+
const payloadB64 = Buffer.from(JSON.stringify(payload), "utf8").toString("base64url");
|
|
1234
|
+
return `${payloadB64}.${signCursorPayloadB64(payloadB64, options.signingSecret)}`;
|
|
1235
|
+
};
|
|
1236
|
+
var decodePaginationCursor = (spec, cursor, options) => {
|
|
1237
|
+
const normalized = normalizePaginationSpec(spec, { maxLimit: options.maxLimit });
|
|
1238
|
+
const [payloadB64, sigB64, ...rest] = cursor.split(".");
|
|
1239
|
+
if (rest.length > 0) throw new PaginationValidationError("Invalid pagination cursor format");
|
|
1240
|
+
if (!sigB64) throw new PaginationValidationError("Invalid pagination cursor format");
|
|
1241
|
+
verifyCursorSignature(payloadB64, sigB64, options.signingSecret);
|
|
1242
|
+
const payloadRaw = Buffer.from(payloadB64, "base64url").toString("utf8");
|
|
1243
|
+
let payloadUnknown;
|
|
1244
|
+
try {
|
|
1245
|
+
payloadUnknown = JSON.parse(payloadRaw);
|
|
1246
|
+
} catch {
|
|
1247
|
+
throw new PaginationValidationError("Invalid pagination cursor payload");
|
|
1248
|
+
}
|
|
1249
|
+
if (!payloadUnknown || typeof payloadUnknown !== "object") throw new PaginationValidationError("Invalid pagination cursor payload");
|
|
1250
|
+
const payload = payloadUnknown;
|
|
1251
|
+
if (payload.v !== 1) throw new PaginationValidationError("Unsupported pagination cursor version");
|
|
1252
|
+
if (!payload.values || typeof payload.values !== "object") throw new PaginationValidationError("Invalid pagination cursor payload");
|
|
1253
|
+
const decoded = Object.create(null);
|
|
1254
|
+
for (const { field } of normalized.sort) {
|
|
1255
|
+
if (!Object.prototype.hasOwnProperty.call(payload.values, field)) throw new PaginationValidationError(`Pagination cursor missing field: ${field}`);
|
|
1256
|
+
const encodedValue = payload.values[field];
|
|
1257
|
+
decoded[field] = decodeCursorValue(field, encodedValue);
|
|
1258
|
+
}
|
|
1259
|
+
return decoded;
|
|
1260
|
+
};
|
|
1261
|
+
var signCursorPayloadB64 = (payloadB64, secret) => {
|
|
1262
|
+
return createHmac("sha256", secret).update(payloadB64, "utf8").digest("base64url");
|
|
1263
|
+
};
|
|
1264
|
+
var verifyCursorSignature = (payloadB64, sigB64, secret) => {
|
|
1265
|
+
const expectedSigB64 = signCursorPayloadB64(payloadB64, secret);
|
|
1266
|
+
const a = Buffer.from(sigB64, "utf8");
|
|
1267
|
+
const b = Buffer.from(expectedSigB64, "utf8");
|
|
1268
|
+
if (a.length !== b.length || !timingSafeEqual(a, b)) throw new PaginationValidationError("Invalid pagination cursor signature");
|
|
1269
|
+
};
|
|
1270
|
+
var unwrapCursorComparableValue = (value) => {
|
|
1271
|
+
if (value === null || typeof value !== "object") return value;
|
|
1272
|
+
if (value instanceof Date || value instanceof Types.ObjectId) return value;
|
|
1273
|
+
let current = value;
|
|
1274
|
+
for (let depth = 0; depth < 4; depth += 1) {
|
|
1275
|
+
if (!current || typeof current !== "object") return current;
|
|
1276
|
+
if (current instanceof Date || current instanceof Types.ObjectId) return current;
|
|
1277
|
+
if (!("_id" in current)) return current;
|
|
1278
|
+
current = current._id;
|
|
1279
|
+
}
|
|
1280
|
+
return current;
|
|
1281
|
+
};
|
|
1282
|
+
var encodeCursorValue = (field, value) => {
|
|
1283
|
+
const comparableValue = unwrapCursorComparableValue(value);
|
|
1284
|
+
if (comparableValue === null) return null;
|
|
1285
|
+
if (field === "_id") {
|
|
1286
|
+
if (comparableValue instanceof Types.ObjectId) return { $oid: comparableValue.toHexString() };
|
|
1287
|
+
if (typeof comparableValue === "string") return comparableValue;
|
|
1288
|
+
throw new Error("Pagination cursor encode failed (_id must be an ObjectId or string)");
|
|
1289
|
+
}
|
|
1290
|
+
if (comparableValue instanceof Date) return { $date: comparableValue.toISOString() };
|
|
1291
|
+
if (typeof comparableValue === "string" || typeof comparableValue === "number" || typeof comparableValue === "boolean") return comparableValue;
|
|
1292
|
+
if (comparableValue instanceof Types.ObjectId) return { $oid: comparableValue.toHexString() };
|
|
1293
|
+
throw new Error(`Unsupported pagination cursor value type for field: ${field}`);
|
|
1294
|
+
};
|
|
1295
|
+
var decodeCursorValue = (field, value) => {
|
|
1296
|
+
if (value === null) return null;
|
|
1297
|
+
if (typeof value === "string") return value;
|
|
1298
|
+
if (typeof value === "number" || typeof value === "boolean") return value;
|
|
1299
|
+
if (!value || typeof value !== "object") throw new PaginationValidationError(`Invalid pagination cursor value for field: ${field}`);
|
|
1300
|
+
if ("$date" in value) {
|
|
1301
|
+
if (typeof value.$date !== "string") throw new PaginationValidationError(`Invalid pagination cursor date for field: ${field}`);
|
|
1302
|
+
const d = new Date(value.$date);
|
|
1303
|
+
if (Number.isNaN(d.getTime())) throw new PaginationValidationError(`Invalid pagination cursor date for field: ${field}`);
|
|
1304
|
+
return d;
|
|
1305
|
+
}
|
|
1306
|
+
if ("$oid" in value) {
|
|
1307
|
+
if (typeof value.$oid !== "string" || !Types.ObjectId.isValid(value.$oid)) throw new PaginationValidationError(`Invalid pagination cursor ObjectId for field: ${field}`);
|
|
1308
|
+
return new Types.ObjectId(value.$oid);
|
|
1309
|
+
}
|
|
1310
|
+
throw new PaginationValidationError(`Invalid pagination cursor value for field: ${field}`);
|
|
1311
|
+
};
|
|
1312
|
+
var readFieldValue = (node, field) => {
|
|
1313
|
+
if (!node || typeof node !== "object") return void 0;
|
|
1314
|
+
if ("get" in node && typeof node.get === "function") return node.get(field);
|
|
1315
|
+
return field.split(".").reduce((acc, key) => {
|
|
1316
|
+
if (!acc || typeof acc !== "object") return void 0;
|
|
1317
|
+
return acc[key];
|
|
1318
|
+
}, node);
|
|
1319
|
+
};
|
|
1320
|
+
//#endregion
|
|
1321
|
+
//#region src/pagination/compileMongoPagination.ts
|
|
1322
|
+
var compileMongoPagination = (spec, options) => {
|
|
1323
|
+
const normalized = normalizePaginationSpec(spec, { maxLimit: options.cursor.maxLimit });
|
|
1324
|
+
const mongoLimit = normalized.limit + 1;
|
|
1325
|
+
const mongoSort = toMongoSort(normalized);
|
|
1326
|
+
if (normalized.cursor == null) return {
|
|
1327
|
+
spec: normalized,
|
|
1328
|
+
mongoFilterDelta: {},
|
|
1329
|
+
mongoSort,
|
|
1330
|
+
mongoLimit
|
|
1331
|
+
};
|
|
1332
|
+
if (typeof normalized.cursor !== "string" || normalized.cursor.length === 0) throw new PaginationValidationError("Invalid pagination cursor");
|
|
1333
|
+
return {
|
|
1334
|
+
spec: normalized,
|
|
1335
|
+
mongoFilterDelta: buildKeysetFilterDelta(normalized, decodePaginationCursor(normalized, normalized.cursor, options.cursor)),
|
|
1336
|
+
mongoSort,
|
|
1337
|
+
mongoLimit
|
|
1338
|
+
};
|
|
1339
|
+
};
|
|
1340
|
+
var toMongoSort = (spec) => {
|
|
1341
|
+
const mongoSort = Object.create(null);
|
|
1342
|
+
for (const { field, order } of spec.sort) mongoSort[field] = (spec.direction === "prev" ? invertOrder(order) : order) === "asc" ? 1 : -1;
|
|
1343
|
+
return mongoSort;
|
|
1344
|
+
};
|
|
1345
|
+
var buildKeysetFilterDelta = (spec, cursorValues) => {
|
|
1346
|
+
const branches = [];
|
|
1347
|
+
for (let i = 0; i < spec.sort.length; i++) {
|
|
1348
|
+
const current = spec.sort[i];
|
|
1349
|
+
if (!current) continue;
|
|
1350
|
+
const and = [];
|
|
1351
|
+
for (let j = 0; j < i; j++) {
|
|
1352
|
+
const prev = spec.sort[j];
|
|
1353
|
+
if (!prev) continue;
|
|
1354
|
+
const eq = Object.create(null);
|
|
1355
|
+
eq[prev.field] = cursorValues[prev.field];
|
|
1356
|
+
and.push(eq);
|
|
1357
|
+
}
|
|
1358
|
+
const op = getKeysetOp(current.order, spec.direction);
|
|
1359
|
+
const cmpOp = Object.create(null);
|
|
1360
|
+
cmpOp[op] = cursorValues[current.field];
|
|
1361
|
+
const cmp = Object.create(null);
|
|
1362
|
+
cmp[current.field] = cmpOp;
|
|
1363
|
+
and.push(cmp);
|
|
1364
|
+
branches.push(and.length === 1 ? and[0] : { $and: and });
|
|
1365
|
+
}
|
|
1366
|
+
return { $or: branches };
|
|
1367
|
+
};
|
|
1368
|
+
var getKeysetOp = (order, direction) => {
|
|
1369
|
+
if (direction === "next") return order === "asc" ? "$gt" : "$lt";
|
|
1370
|
+
return order === "asc" ? "$lt" : "$gt";
|
|
1371
|
+
};
|
|
1372
|
+
var invertOrder = (order) => {
|
|
1373
|
+
return order === "asc" ? "desc" : "asc";
|
|
1374
|
+
};
|
|
1375
|
+
//#endregion
|
|
1376
|
+
//#region src/pagination/materializePagination.ts
|
|
1377
|
+
var materializeMongoPagination = (compiled, fetchedNodes, options) => {
|
|
1378
|
+
const limit = compiled.spec.limit;
|
|
1379
|
+
const hasMore = fetchedNodes.length > limit;
|
|
1380
|
+
const trimmed = fetchedNodes.slice(0, limit);
|
|
1381
|
+
const nodes = compiled.spec.direction === "prev" ? trimmed.reverse() : trimmed;
|
|
1382
|
+
const hasPrevPage = compiled.spec.direction === "next" ? Boolean(compiled.spec.cursor) : hasMore;
|
|
1383
|
+
const hasNextPage = compiled.spec.direction === "next" ? hasMore : Boolean(compiled.spec.cursor);
|
|
1384
|
+
const pageInfo = {
|
|
1385
|
+
hasNextPage,
|
|
1386
|
+
hasPrevPage
|
|
1387
|
+
};
|
|
1388
|
+
if (nodes.length === 0) return {
|
|
1389
|
+
nodes,
|
|
1390
|
+
pageInfo
|
|
1391
|
+
};
|
|
1392
|
+
if (options.includeCursors !== false && hasPrevPage) pageInfo.prevCursor = encodePaginationCursor(compiled.spec, nodes[0], options.cursor);
|
|
1393
|
+
if (options.includeCursors !== false && hasNextPage) pageInfo.nextCursor = encodePaginationCursor(compiled.spec, nodes[nodes.length - 1], options.cursor);
|
|
1394
|
+
return {
|
|
1395
|
+
nodes,
|
|
1396
|
+
pageInfo
|
|
1397
|
+
};
|
|
1398
|
+
};
|
|
1399
|
+
//#endregion
|
|
1400
|
+
//#region src/pagination/mongoAdapter.ts
|
|
1401
|
+
var MongoAdapter = { applyPagination: (query, compiled) => {
|
|
1402
|
+
query.where(compiled.mongoFilterDelta);
|
|
1403
|
+
query.sort(compiled.mongoSort);
|
|
1404
|
+
query.limit(compiled.mongoLimit);
|
|
1405
|
+
return query;
|
|
1406
|
+
} };
|
|
1407
|
+
//#endregion
|
|
1408
|
+
//#region src/pagination/paginateMongoQuery.ts
|
|
1409
|
+
var paginateMongoQuery = async (query, pagination, options) => {
|
|
1410
|
+
const compiled = compileMongoPagination(pagination, { cursor: options.cursor });
|
|
1411
|
+
MongoAdapter.applyPagination(query, compiled);
|
|
1412
|
+
const fetchedNodes = await query.exec();
|
|
1413
|
+
if (!Array.isArray(fetchedNodes)) throw new Error("paginateMongoQuery expects query.exec() to return an array");
|
|
1414
|
+
return materializeMongoPagination(compiled, fetchedNodes, {
|
|
1415
|
+
cursor: options.cursor,
|
|
1416
|
+
includeCursors: options.includeCursors
|
|
1417
|
+
});
|
|
1418
|
+
};
|
|
1419
|
+
//#endregion
|
|
1420
|
+
//#region src/pagination/mongoPaginationPlugin.ts
|
|
1421
|
+
var getQueryOptions$1 = (query) => {
|
|
1422
|
+
if (!query || typeof query !== "object") return void 0;
|
|
1423
|
+
if (!("getOptions" in query) || typeof query.getOptions !== "function") return void 0;
|
|
1424
|
+
return query.getOptions();
|
|
1425
|
+
};
|
|
1426
|
+
var getPaginationFromOptions = (query) => {
|
|
1427
|
+
return getQueryOptions$1(query)?.pagination;
|
|
1428
|
+
};
|
|
1429
|
+
var getCursorFromOptions = (query) => {
|
|
1430
|
+
return getQueryOptions$1(query)?.paginationCursor;
|
|
1431
|
+
};
|
|
1432
|
+
var mongoPaginationPlugin = (schema, pluginOptions) => {
|
|
1433
|
+
schema.query.paginate = async function(pagination, options) {
|
|
1434
|
+
const spec = pagination ?? getPaginationFromOptions(this);
|
|
1435
|
+
if (!spec) throw new Error("Missing pagination spec");
|
|
1436
|
+
const cursor = options?.cursor ?? getCursorFromOptions(this) ?? pluginOptions?.cursor;
|
|
1437
|
+
if (!cursor?.signingSecret) throw new Error("Missing pagination cursor signingSecret");
|
|
1438
|
+
return await paginateMongoQuery(this, spec, {
|
|
1439
|
+
cursor,
|
|
1440
|
+
includeCursors: options?.includeCursors ?? pluginOptions?.includeCursors
|
|
1441
|
+
});
|
|
1442
|
+
};
|
|
1443
|
+
};
|
|
1444
|
+
//#endregion
|
|
1445
|
+
//#region src/search/index.ts
|
|
1446
|
+
var buildSearchTextStage = (options) => {
|
|
1447
|
+
const index = options.index.trim();
|
|
1448
|
+
if (!index) throw new Error("Missing search index name");
|
|
1449
|
+
const query = options.query.trim();
|
|
1450
|
+
if (!query) throw new Error("Missing search query");
|
|
1451
|
+
const stage = { $search: {
|
|
1452
|
+
index,
|
|
1453
|
+
text: {
|
|
1454
|
+
query,
|
|
1455
|
+
path: options.path
|
|
1456
|
+
}
|
|
1457
|
+
} };
|
|
1458
|
+
if (options.highlightPath) stage.$search.highlight = { path: options.highlightPath };
|
|
1459
|
+
return stage;
|
|
1460
|
+
};
|
|
1461
|
+
var searchMetaProjection = () => {
|
|
1462
|
+
return {
|
|
1463
|
+
score: { $meta: "searchScore" },
|
|
1464
|
+
highlights: { $meta: "searchHighlights" }
|
|
1465
|
+
};
|
|
1466
|
+
};
|
|
1467
|
+
var listResultHasIndex = (listResult, name) => {
|
|
1468
|
+
if (!listResult || typeof listResult !== "object") return false;
|
|
1469
|
+
if (!("cursor" in listResult)) return false;
|
|
1470
|
+
const cursor = listResult.cursor;
|
|
1471
|
+
if (!cursor || typeof cursor !== "object") return false;
|
|
1472
|
+
const firstBatch = cursor.firstBatch;
|
|
1473
|
+
if (!Array.isArray(firstBatch)) return false;
|
|
1474
|
+
return firstBatch.some((idx) => idx && typeof idx === "object" && "name" in idx && idx.name === name);
|
|
1475
|
+
};
|
|
1476
|
+
var isIndexAlreadyExistsError = (error) => {
|
|
1477
|
+
if (!error || typeof error !== "object") return false;
|
|
1478
|
+
if (("codeName" in error ? error.codeName : void 0) === "IndexAlreadyExists") return true;
|
|
1479
|
+
const message = "message" in error ? String(error.message ?? "") : "";
|
|
1480
|
+
return /already exists/i.test(message);
|
|
1481
|
+
};
|
|
1482
|
+
var ensureSearchIndex = async (params) => {
|
|
1483
|
+
const collection = params.collection.trim();
|
|
1484
|
+
if (!collection) throw new Error("Missing collection name");
|
|
1485
|
+
const name = params.name.trim();
|
|
1486
|
+
if (!name) throw new Error("Missing search index name");
|
|
1487
|
+
let listResult;
|
|
1488
|
+
try {
|
|
1489
|
+
listResult = await params.db.command({ listSearchIndexes: collection });
|
|
1490
|
+
} catch (error) {
|
|
1491
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1492
|
+
throw new Error(`listSearchIndexes failed for "${collection}": ${message}`);
|
|
1493
|
+
}
|
|
1494
|
+
if (listResultHasIndex(listResult, name)) return { created: false };
|
|
1495
|
+
try {
|
|
1496
|
+
await params.db.command({
|
|
1497
|
+
createSearchIndexes: collection,
|
|
1498
|
+
indexes: [{
|
|
1499
|
+
name,
|
|
1500
|
+
definition: params.definition
|
|
1501
|
+
}]
|
|
1502
|
+
});
|
|
1503
|
+
} catch (error) {
|
|
1504
|
+
if (isIndexAlreadyExistsError(error)) return { created: false };
|
|
1505
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1506
|
+
throw new Error(`createSearchIndexes failed for "${collection}" (index "${name}"): ${message}`);
|
|
1507
|
+
}
|
|
1508
|
+
return { created: true };
|
|
1509
|
+
};
|
|
1510
|
+
//#endregion
|
|
1511
|
+
//#region src/dbNames.ts
|
|
1512
|
+
var getAppName$1 = (env = process.env) => {
|
|
1513
|
+
const appName = env.APP_NAME?.trim();
|
|
1514
|
+
if (!appName) throw new Error("Missing APP_NAME");
|
|
1515
|
+
return appName;
|
|
1516
|
+
};
|
|
1517
|
+
var GLOBAL_DB_SUFFIX = "-global-db";
|
|
1518
|
+
var getGlobalDbName = (env = process.env) => {
|
|
1519
|
+
return `${getAppName$1(env)}${GLOBAL_DB_SUFFIX}`;
|
|
1520
|
+
};
|
|
1521
|
+
var getTenantDbName = (tenantId, env = process.env) => {
|
|
1522
|
+
return `${getAppName$1(env)}-${tenantId.trim()}-db`;
|
|
1523
|
+
};
|
|
1524
|
+
//#endregion
|
|
1525
|
+
//#region src/ensureMongooseConnection.ts
|
|
1526
|
+
var connections = /* @__PURE__ */ new Map();
|
|
1527
|
+
var rootConnection = null;
|
|
1528
|
+
var CONNECTION_MAX_LISTENERS = 50;
|
|
1529
|
+
var waitForOpen = async (connection) => {
|
|
1530
|
+
if (connection.readyState === 1) return;
|
|
1531
|
+
if (connection.getMaxListeners() < CONNECTION_MAX_LISTENERS) connection.setMaxListeners(CONNECTION_MAX_LISTENERS);
|
|
1532
|
+
await new Promise((resolve, reject) => {
|
|
1533
|
+
connection.once("open", resolve);
|
|
1534
|
+
connection.once("error", reject);
|
|
1535
|
+
});
|
|
1536
|
+
};
|
|
1537
|
+
var ensureMongooseConnection = async (dbName) => {
|
|
1538
|
+
const normalizedDbName = dbName.trim();
|
|
1539
|
+
if (!normalizedDbName) throw new Error("Missing dbName");
|
|
1540
|
+
const existing = connections.get(normalizedDbName);
|
|
1541
|
+
if (existing) {
|
|
1542
|
+
await waitForOpen(existing);
|
|
1543
|
+
return existing;
|
|
1544
|
+
}
|
|
1545
|
+
if (!rootConnection) {
|
|
1546
|
+
const mongoUrl = getMongoUrl();
|
|
1547
|
+
rootConnection = mongoose$1.createConnection(mongoUrl, {
|
|
1548
|
+
sanitizeFilter: true,
|
|
1549
|
+
dbName: normalizedDbName,
|
|
1550
|
+
directConnection: getMongoDirectConnection()
|
|
1551
|
+
});
|
|
1552
|
+
}
|
|
1553
|
+
await waitForOpen(rootConnection);
|
|
1554
|
+
const connection = rootConnection.name === normalizedDbName ? rootConnection : rootConnection.useDb(normalizedDbName, { useCache: true });
|
|
1555
|
+
await waitForOpen(connection);
|
|
1556
|
+
connections.set(normalizedDbName, connection);
|
|
1557
|
+
return connection;
|
|
1558
|
+
};
|
|
1559
|
+
//#endregion
|
|
1560
|
+
//#region src/rtsChangeLogPlugin.ts
|
|
1561
|
+
var RTS_COUNTER_ID = "rts";
|
|
1562
|
+
var EXCLUDED_MODEL_NAMES = /* @__PURE__ */ new Set(["RBRtsChange", "RBRtsCounter"]);
|
|
1563
|
+
var maxDeleteIdsRaw = process.env.RB_RTS_DELETE_LOG_MAX_IDS ?? "";
|
|
1564
|
+
var maxDeleteIds = Number.isFinite(Number(maxDeleteIdsRaw)) ? Math.max(1, Math.floor(Number(maxDeleteIdsRaw))) : 5e3;
|
|
1565
|
+
var deleteMetaByQuery = /* @__PURE__ */ new WeakMap();
|
|
1566
|
+
var hasToString = (value) => {
|
|
1567
|
+
if (typeof value !== "object" || value === null) return false;
|
|
1568
|
+
return typeof value.toString === "function";
|
|
1569
|
+
};
|
|
1570
|
+
var normalizeId = (id) => {
|
|
1571
|
+
if (!id) return null;
|
|
1572
|
+
if (typeof id === "string") return id;
|
|
1573
|
+
if (hasToString(id)) return id.toString();
|
|
1574
|
+
return null;
|
|
1575
|
+
};
|
|
1576
|
+
var getDbName = (db) => {
|
|
1577
|
+
if (!db || typeof db !== "object") return "";
|
|
1578
|
+
const maybe = db;
|
|
1579
|
+
const raw = maybe.name ?? maybe.db?.databaseName;
|
|
1580
|
+
return typeof raw === "string" ? raw : "";
|
|
1581
|
+
};
|
|
1582
|
+
var isGlobalDb = (db) => getDbName(db).endsWith(GLOBAL_DB_SUFFIX);
|
|
1583
|
+
var getQuerySession = (query) => {
|
|
1584
|
+
const opts = typeof query.getOptions === "function" ? query.getOptions() : void 0;
|
|
1585
|
+
if (!opts || typeof opts !== "object") return void 0;
|
|
1586
|
+
const session = opts.session;
|
|
1587
|
+
if (!session || typeof session !== "object") return void 0;
|
|
1588
|
+
return session;
|
|
1589
|
+
};
|
|
1590
|
+
var getRtsModels = (db) => {
|
|
1591
|
+
return {
|
|
1592
|
+
RtsCounter: db.models.RBRtsCounter ?? db.model("RBRtsCounter", RBRtsCounterSchema),
|
|
1593
|
+
RtsChange: db.models.RBRtsChange ?? db.model("RBRtsChange", RBRtsChangeSchema)
|
|
1594
|
+
};
|
|
1595
|
+
};
|
|
1596
|
+
var allocateSeqRange = async (db, count, session) => {
|
|
1597
|
+
const { RtsCounter } = getRtsModels(db);
|
|
1598
|
+
const updated = await RtsCounter.findOneAndUpdate({ _id: RTS_COUNTER_ID }, { $inc: { seq: count } }, {
|
|
1599
|
+
upsert: true,
|
|
1600
|
+
returnDocument: "after",
|
|
1601
|
+
setDefaultsOnInsert: true,
|
|
1602
|
+
projection: { seq: 1 },
|
|
1603
|
+
session
|
|
1604
|
+
}).lean();
|
|
1605
|
+
const end = Number(updated?.seq ?? 0);
|
|
1606
|
+
return {
|
|
1607
|
+
start: end - count + 1,
|
|
1608
|
+
end
|
|
1609
|
+
};
|
|
1610
|
+
};
|
|
1611
|
+
var insertChanges = async (db, changes, session) => {
|
|
1612
|
+
if (!changes.length) return;
|
|
1613
|
+
const { RtsChange } = getRtsModels(db);
|
|
1614
|
+
const ts = /* @__PURE__ */ new Date();
|
|
1615
|
+
const docs = changes.map((c) => ({
|
|
1616
|
+
seq: c.seq,
|
|
1617
|
+
modelName: c.modelName,
|
|
1618
|
+
op: c.op,
|
|
1619
|
+
docId: c.docId ?? void 0,
|
|
1620
|
+
ts
|
|
1621
|
+
}));
|
|
1622
|
+
if (session) {
|
|
1623
|
+
await RtsChange.insertMany(docs, { session });
|
|
1624
|
+
return;
|
|
1625
|
+
}
|
|
1626
|
+
await RtsChange.insertMany(docs);
|
|
1627
|
+
};
|
|
1628
|
+
var recordDeleteChanges = async (db, modelName, ids, session) => {
|
|
1629
|
+
const uniqueIds = Array.from(new Set(ids)).filter(Boolean);
|
|
1630
|
+
if (!uniqueIds.length) return;
|
|
1631
|
+
const { start } = await allocateSeqRange(db, uniqueIds.length, session);
|
|
1632
|
+
await insertChanges(db, uniqueIds.map((docId, idx) => ({
|
|
1633
|
+
seq: start + idx,
|
|
1634
|
+
modelName,
|
|
1635
|
+
op: "delete",
|
|
1636
|
+
docId
|
|
1637
|
+
})), session);
|
|
1638
|
+
};
|
|
1639
|
+
var recordResetModel = async (db, modelName, session) => {
|
|
1640
|
+
const { start } = await allocateSeqRange(db, 1, session);
|
|
1641
|
+
await insertChanges(db, [{
|
|
1642
|
+
seq: start,
|
|
1643
|
+
modelName,
|
|
1644
|
+
op: "reset_model"
|
|
1645
|
+
}], session);
|
|
1646
|
+
};
|
|
1647
|
+
var captureDeleteMeta = async (query, mode) => {
|
|
1648
|
+
const modelName = String(query?.model?.modelName ?? "");
|
|
1649
|
+
if (!modelName || modelName.startsWith("RB") || EXCLUDED_MODEL_NAMES.has(modelName)) return;
|
|
1650
|
+
if (isGlobalDb(query?.model?.db)) return;
|
|
1651
|
+
const filter = typeof query.getFilter === "function" ? query.getFilter() : query.getQuery?.() ?? {};
|
|
1652
|
+
const session = getQuerySession(query);
|
|
1653
|
+
const findQuery = query.model.find(filter, { _id: 1 });
|
|
1654
|
+
if (session && typeof findQuery.session === "function") findQuery.session(session);
|
|
1655
|
+
findQuery.lean();
|
|
1656
|
+
if (mode === "one") findQuery.limit(1);
|
|
1657
|
+
else findQuery.limit(maxDeleteIds + 1);
|
|
1658
|
+
const docs = await findQuery;
|
|
1659
|
+
const ids = Array.isArray(docs) ? docs.map((d) => normalizeId(d?._id)).filter((id) => Boolean(id)) : [];
|
|
1660
|
+
const reset = mode === "many" && ids.length > maxDeleteIds;
|
|
1661
|
+
const meta = {
|
|
1662
|
+
modelName,
|
|
1663
|
+
ids: reset ? [] : ids,
|
|
1664
|
+
reset,
|
|
1665
|
+
session
|
|
1666
|
+
};
|
|
1667
|
+
deleteMetaByQuery.set(query, meta);
|
|
1668
|
+
};
|
|
1669
|
+
var flushDeleteMeta = async (query) => {
|
|
1670
|
+
const meta = deleteMetaByQuery.get(query);
|
|
1671
|
+
deleteMetaByQuery.delete(query);
|
|
1672
|
+
if (!meta) return;
|
|
1673
|
+
const db = query?.model?.db;
|
|
1674
|
+
if (!db) return;
|
|
1675
|
+
try {
|
|
1676
|
+
if (meta.reset) await recordResetModel(db, meta.modelName, meta.session);
|
|
1677
|
+
else await recordDeleteChanges(db, meta.modelName, meta.ids, meta.session);
|
|
1678
|
+
} catch {
|
|
1679
|
+
return;
|
|
1680
|
+
}
|
|
1681
|
+
};
|
|
1682
|
+
var rtsChangeLogPlugin = (schema) => {
|
|
1683
|
+
schema.pre("deleteOne", {
|
|
1684
|
+
query: true,
|
|
1685
|
+
document: false
|
|
1686
|
+
}, async function() {
|
|
1687
|
+
await captureDeleteMeta(this, "one");
|
|
1688
|
+
});
|
|
1689
|
+
schema.pre("deleteMany", {
|
|
1690
|
+
query: true,
|
|
1691
|
+
document: false
|
|
1692
|
+
}, async function() {
|
|
1693
|
+
await captureDeleteMeta(this, "many");
|
|
1694
|
+
});
|
|
1695
|
+
schema.post("deleteOne", {
|
|
1696
|
+
query: true,
|
|
1697
|
+
document: false
|
|
1698
|
+
}, async function() {
|
|
1699
|
+
await flushDeleteMeta(this);
|
|
1700
|
+
});
|
|
1701
|
+
schema.post("deleteMany", {
|
|
1702
|
+
query: true,
|
|
1703
|
+
document: false
|
|
1704
|
+
}, async function() {
|
|
1705
|
+
await flushDeleteMeta(this);
|
|
1706
|
+
});
|
|
1707
|
+
schema.post("findOneAndDelete", {
|
|
1708
|
+
query: true,
|
|
1709
|
+
document: false
|
|
1710
|
+
}, async function(doc) {
|
|
1711
|
+
const modelName = String(this?.model?.modelName ?? "");
|
|
1712
|
+
if (!modelName || modelName.startsWith("RB") || EXCLUDED_MODEL_NAMES.has(modelName)) return;
|
|
1713
|
+
const db = this?.model?.db;
|
|
1714
|
+
if (!db) return;
|
|
1715
|
+
if (isGlobalDb(db)) return;
|
|
1716
|
+
const docId = normalizeId(doc?._id);
|
|
1717
|
+
if (!docId) return;
|
|
1718
|
+
try {
|
|
1719
|
+
const session = getQuerySession(this);
|
|
1720
|
+
await recordDeleteChanges(db, modelName, [docId], session);
|
|
1721
|
+
} catch {
|
|
1722
|
+
return;
|
|
1723
|
+
}
|
|
1724
|
+
});
|
|
1725
|
+
};
|
|
1726
|
+
//#endregion
|
|
1727
|
+
//#region src/acl/mongooseAclPlugin.ts
|
|
1728
|
+
var isRecord = (value) => Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
1729
|
+
var mergeMongoQuery = (left, right) => {
|
|
1730
|
+
const leftQuery = isRecord(left) ? left : {};
|
|
1731
|
+
if (Object.keys(leftQuery).length === 0) return right;
|
|
1732
|
+
if (Object.keys(right).length === 0) return leftQuery;
|
|
1733
|
+
return { $and: [leftQuery, right] };
|
|
1734
|
+
};
|
|
1735
|
+
var getQueryOptions = (query) => {
|
|
1736
|
+
if (!query || typeof query !== "object") return void 0;
|
|
1737
|
+
if (!("getOptions" in query) || typeof query.getOptions !== "function") return void 0;
|
|
1738
|
+
return query.getOptions();
|
|
1739
|
+
};
|
|
1740
|
+
var getStoredAclFromQuery = (query) => {
|
|
1741
|
+
const raw = getQueryOptions(query)?.rbAcl;
|
|
1742
|
+
if (!isRecord(raw)) return null;
|
|
1743
|
+
if (!("ability" in raw)) return null;
|
|
1744
|
+
return raw;
|
|
1745
|
+
};
|
|
1746
|
+
var getStoredAclFromAggregate = (aggregate) => {
|
|
1747
|
+
if (!aggregate || typeof aggregate !== "object") return null;
|
|
1748
|
+
const raw = aggregate.options;
|
|
1749
|
+
if (!isRecord(raw)) return null;
|
|
1750
|
+
const acl = raw.rbAcl;
|
|
1751
|
+
if (!isRecord(acl)) return null;
|
|
1752
|
+
if (!("ability" in acl)) return null;
|
|
1753
|
+
return acl;
|
|
1754
|
+
};
|
|
1755
|
+
var addQueryAclFilter = (query, action) => {
|
|
1756
|
+
const storedAcl = getStoredAclFromQuery(query);
|
|
1757
|
+
if (!storedAcl) return;
|
|
1758
|
+
const ability = storedAcl.ability;
|
|
1759
|
+
const resolvedAction = storedAcl.action ?? action;
|
|
1760
|
+
const modelName = query.model.modelName;
|
|
1761
|
+
const accessQuery = accessibleBy(ability, resolvedAction).ofType(modelName);
|
|
1762
|
+
query.and([accessQuery]);
|
|
1763
|
+
};
|
|
1764
|
+
var injectAggregateMatch = (pipeline, match) => {
|
|
1765
|
+
if (pipeline.length === 0) {
|
|
1766
|
+
pipeline.unshift({ $match: match });
|
|
1767
|
+
return;
|
|
1768
|
+
}
|
|
1769
|
+
const first = pipeline[0];
|
|
1770
|
+
if (!isRecord(first)) {
|
|
1771
|
+
pipeline.unshift({ $match: match });
|
|
1772
|
+
return;
|
|
1773
|
+
}
|
|
1774
|
+
if ("$geoNear" in first) {
|
|
1775
|
+
const geoNear = first.$geoNear;
|
|
1776
|
+
if (isRecord(geoNear)) {
|
|
1777
|
+
geoNear.query = mergeMongoQuery(geoNear.query, match);
|
|
1778
|
+
return;
|
|
1779
|
+
}
|
|
1780
|
+
}
|
|
1781
|
+
if ("$search" in first || "$vectorSearch" in first || "$searchMeta" in first) {
|
|
1782
|
+
pipeline.splice(1, 0, { $match: match });
|
|
1783
|
+
return;
|
|
1784
|
+
}
|
|
1785
|
+
pipeline.unshift({ $match: match });
|
|
1786
|
+
};
|
|
1787
|
+
var addAggregateAclFilter = (aggregate, action) => {
|
|
1788
|
+
const storedAcl = getStoredAclFromAggregate(aggregate);
|
|
1789
|
+
if (!storedAcl) return;
|
|
1790
|
+
const ability = storedAcl.ability;
|
|
1791
|
+
const resolvedAction = storedAcl.action ?? action;
|
|
1792
|
+
const modelName = aggregate.model().modelName;
|
|
1793
|
+
const accessQuery = accessibleBy(ability, resolvedAction).ofType(modelName);
|
|
1794
|
+
injectAggregateMatch(aggregate.pipeline(), accessQuery);
|
|
1795
|
+
};
|
|
1796
|
+
var patchAggregateAcl = () => {
|
|
1797
|
+
const globalKey = Symbol.for("@rpcbase/db/acl/mongooseAggregateAclPatched");
|
|
1798
|
+
const globalState = globalThis;
|
|
1799
|
+
if (globalState[globalKey]) return;
|
|
1800
|
+
globalState[globalKey] = true;
|
|
1801
|
+
const AggregatePrototype = mongoose$1.Aggregate.prototype;
|
|
1802
|
+
if (typeof AggregatePrototype.acl === "function") return;
|
|
1803
|
+
AggregatePrototype.acl = function(ability, action = "read") {
|
|
1804
|
+
this.option({ rbAcl: {
|
|
1805
|
+
ability,
|
|
1806
|
+
action
|
|
1807
|
+
} });
|
|
1808
|
+
return this;
|
|
1809
|
+
};
|
|
1810
|
+
};
|
|
1811
|
+
var createModelAclProxy = (model, ability) => {
|
|
1812
|
+
return new Proxy(model, { get(target, prop, receiver) {
|
|
1813
|
+
if (prop === "acl") return () => {
|
|
1814
|
+
throw new Error(`Model "${target.modelName}" is already ACL-scoped. Do not call .acl(...) again.`);
|
|
1815
|
+
};
|
|
1816
|
+
const value = Reflect.get(target, prop, receiver);
|
|
1817
|
+
if (typeof value !== "function") return value;
|
|
1818
|
+
return (...args) => {
|
|
1819
|
+
const result = Reflect.apply(value, target, args);
|
|
1820
|
+
if (result && typeof result === "object" && "acl" in result && typeof result.acl === "function") return result.acl(ability);
|
|
1821
|
+
return result;
|
|
1822
|
+
};
|
|
1823
|
+
} });
|
|
1824
|
+
};
|
|
1825
|
+
var mongooseAclPlugin = (schema) => {
|
|
1826
|
+
patchAggregateAcl();
|
|
1827
|
+
schema.query.acl = function(ability, action) {
|
|
1828
|
+
this.setOptions({ rbAcl: {
|
|
1829
|
+
ability,
|
|
1830
|
+
action
|
|
1831
|
+
} });
|
|
1832
|
+
return this;
|
|
1833
|
+
};
|
|
1834
|
+
schema.statics.acl = function(ability) {
|
|
1835
|
+
return createModelAclProxy(this, ability);
|
|
1836
|
+
};
|
|
1837
|
+
schema.pre("aggregate", function() {
|
|
1838
|
+
addAggregateAclFilter(this, "read");
|
|
1839
|
+
});
|
|
1840
|
+
schema.pre("countDocuments", function() {
|
|
1841
|
+
addQueryAclFilter(this, "read");
|
|
1842
|
+
});
|
|
1843
|
+
schema.pre("deleteMany", function() {
|
|
1844
|
+
addQueryAclFilter(this, "delete");
|
|
1845
|
+
});
|
|
1846
|
+
schema.pre("deleteOne", function() {
|
|
1847
|
+
addQueryAclFilter(this, "delete");
|
|
1848
|
+
});
|
|
1849
|
+
schema.pre("distinct", function() {
|
|
1850
|
+
addQueryAclFilter(this, "read");
|
|
1851
|
+
});
|
|
1852
|
+
schema.pre("find", function() {
|
|
1853
|
+
addQueryAclFilter(this, "read");
|
|
1854
|
+
});
|
|
1855
|
+
schema.pre("findOne", function() {
|
|
1856
|
+
addQueryAclFilter(this, "read");
|
|
1857
|
+
});
|
|
1858
|
+
schema.pre("findOneAndDelete", function() {
|
|
1859
|
+
addQueryAclFilter(this, "delete");
|
|
1860
|
+
});
|
|
1861
|
+
schema.pre("findOneAndReplace", function() {
|
|
1862
|
+
addQueryAclFilter(this, "update");
|
|
1863
|
+
});
|
|
1864
|
+
schema.pre("findOneAndUpdate", function() {
|
|
1865
|
+
addQueryAclFilter(this, "update");
|
|
1866
|
+
});
|
|
1867
|
+
schema.pre("replaceOne", function() {
|
|
1868
|
+
addQueryAclFilter(this, "update");
|
|
1869
|
+
});
|
|
1870
|
+
schema.pre("updateMany", function() {
|
|
1871
|
+
addQueryAclFilter(this, "update");
|
|
1872
|
+
});
|
|
1873
|
+
schema.pre("updateOne", function() {
|
|
1874
|
+
addQueryAclFilter(this, "update");
|
|
1875
|
+
});
|
|
1876
|
+
};
|
|
1877
|
+
//#endregion
|
|
1878
|
+
//#region src/registerModels.ts
|
|
1879
|
+
var cachedModels = null;
|
|
1880
|
+
var DEFAULT_GLOBAL_RB_MODEL_NAMES_SET = /* @__PURE__ */ new Set([
|
|
1881
|
+
"RBUser",
|
|
1882
|
+
"RBTenant",
|
|
1883
|
+
"RBOAuthRequest"
|
|
1884
|
+
]);
|
|
1885
|
+
var assertSchema = (exportName, value) => {
|
|
1886
|
+
if (value instanceof mongoose$1.Schema) return value;
|
|
1887
|
+
throw new Error([
|
|
1888
|
+
`Expected ${exportName} to be an instance of mongoose.Schema, but it was not.`,
|
|
1889
|
+
"rpcbase supports mongoose 9+ only.",
|
|
1890
|
+
"Fix: ensure the project is using mongoose 9.x and that all packages resolve the same mongoose instance (try `npm ls mongoose`)."
|
|
1891
|
+
].join(" "));
|
|
1892
|
+
};
|
|
1893
|
+
var getFrameworkSchemaForModelName = (modelName) => {
|
|
1894
|
+
const value = models_exports[`${modelName}Schema`];
|
|
1895
|
+
if (!(value instanceof mongoose$1.Schema)) return null;
|
|
1896
|
+
return value;
|
|
1897
|
+
};
|
|
1898
|
+
var applyTenantPlugins = (schema) => {
|
|
1899
|
+
schema.plugin(accessibleRecordsPlugin);
|
|
1900
|
+
schema.plugin(mongooseAclPlugin);
|
|
1901
|
+
schema.plugin(mongoPaginationPlugin);
|
|
1902
|
+
schema.plugin(rtsChangeLogPlugin);
|
|
1903
|
+
};
|
|
1904
|
+
var registerSchema = (target, other, modelName, schema, scope) => {
|
|
1905
|
+
if (target[modelName] || other[modelName]) throw new Error(`Duplicate model name "${modelName}" across tenant/global scopes`);
|
|
1906
|
+
target[modelName] = schema;
|
|
1907
|
+
};
|
|
1908
|
+
var buildSchemasFromModules = (modules) => Object.entries(modules).filter(([key]) => key.endsWith("Schema")).map(([key, schemaValue]) => {
|
|
1909
|
+
const schema = assertSchema(key, schemaValue);
|
|
1910
|
+
return {
|
|
1911
|
+
modelName: key.replace(/Schema$/, ""),
|
|
1912
|
+
schema
|
|
1913
|
+
};
|
|
2201
1914
|
});
|
|
1915
|
+
var registerModels = ({ tenant, global }, options = {}) => {
|
|
1916
|
+
registerPoliciesFromModules(models_exports);
|
|
1917
|
+
registerPoliciesFromModules(tenant);
|
|
1918
|
+
const tenantSchemas = {};
|
|
1919
|
+
const globalSchemas = {};
|
|
1920
|
+
const allowReservedRbModelNames = options.allowReservedRbModelNames === true;
|
|
1921
|
+
for (const { modelName, schema } of buildSchemasFromModules(models_exports)) if (DEFAULT_GLOBAL_RB_MODEL_NAMES_SET.has(modelName)) registerSchema(globalSchemas, tenantSchemas, modelName, schema.clone(), "global");
|
|
1922
|
+
else {
|
|
1923
|
+
const cloned = schema.clone();
|
|
1924
|
+
applyTenantPlugins(cloned);
|
|
1925
|
+
registerSchema(tenantSchemas, globalSchemas, modelName, cloned, "tenant");
|
|
1926
|
+
}
|
|
1927
|
+
for (const { modelName, schema } of buildSchemasFromModules(tenant)) {
|
|
1928
|
+
if (modelName === "RBUser" || modelName === "RBTenant") throw new Error(`Invalid tenant model name "${modelName}". RBUser/RBTenant are global models.`);
|
|
1929
|
+
if (modelName.startsWith("RB")) {
|
|
1930
|
+
const frameworkSchema = getFrameworkSchemaForModelName(modelName);
|
|
1931
|
+
if (frameworkSchema && schema === frameworkSchema) continue;
|
|
1932
|
+
if (!allowReservedRbModelNames) throw new Error(`Invalid tenant model name "${modelName}". RB* models are reserved for rpcbase.`);
|
|
1933
|
+
}
|
|
1934
|
+
const cloned = schema.clone();
|
|
1935
|
+
applyTenantPlugins(cloned);
|
|
1936
|
+
registerSchema(tenantSchemas, globalSchemas, modelName, cloned, "tenant");
|
|
1937
|
+
}
|
|
1938
|
+
for (const { modelName, schema } of buildSchemasFromModules(global ?? {})) {
|
|
1939
|
+
if (modelName.startsWith("RB")) {
|
|
1940
|
+
const frameworkSchema = getFrameworkSchemaForModelName(modelName);
|
|
1941
|
+
if (frameworkSchema && schema === frameworkSchema) continue;
|
|
1942
|
+
if (!allowReservedRbModelNames) throw new Error(`Invalid global model name "${modelName}". RB* models are reserved for rpcbase.`);
|
|
1943
|
+
}
|
|
1944
|
+
registerSchema(globalSchemas, tenantSchemas, modelName, schema.clone(), "global");
|
|
1945
|
+
}
|
|
1946
|
+
const allSchemas = {
|
|
1947
|
+
...globalSchemas,
|
|
1948
|
+
...tenantSchemas
|
|
1949
|
+
};
|
|
1950
|
+
for (const [modelName, schema] of Object.entries(allSchemas)) if (!mongoose$1.models[modelName]) mongoose$1.model(modelName, schema);
|
|
1951
|
+
cachedModels = {
|
|
1952
|
+
tenant: {
|
|
1953
|
+
...cachedModels?.tenant ?? {},
|
|
1954
|
+
...tenantSchemas
|
|
1955
|
+
},
|
|
1956
|
+
global: {
|
|
1957
|
+
...cachedModels?.global ?? {},
|
|
1958
|
+
...globalSchemas
|
|
1959
|
+
}
|
|
1960
|
+
};
|
|
1961
|
+
};
|
|
1962
|
+
var getRegisteredModels = (scope) => {
|
|
1963
|
+
if (!cachedModels) throw new Error("Models not registered. Call createModels(...) once at startup (or import your models module) before using models.get.");
|
|
1964
|
+
return cachedModels[scope];
|
|
1965
|
+
};
|
|
1966
|
+
//#endregion
|
|
1967
|
+
//#region src/modelsApi.ts
|
|
1968
|
+
var loadModelFromDb = async (modelName, dbName, scope) => {
|
|
1969
|
+
const schemas = getRegisteredModels(scope);
|
|
1970
|
+
const schema = schemas[modelName];
|
|
1971
|
+
assert(schema, `Model ${modelName} not registered. Available models: ${Object.keys(schemas).join(", ")}`);
|
|
1972
|
+
const modelConnection = await ensureMongooseConnection(dbName);
|
|
1973
|
+
if (!modelConnection.models[modelName]) modelConnection.model(modelName, schema);
|
|
1974
|
+
return modelConnection.models[modelName];
|
|
1975
|
+
};
|
|
1976
|
+
var normalizeTenantId$1 = (value) => {
|
|
1977
|
+
if (typeof value !== "string") return null;
|
|
1978
|
+
return value.trim() || null;
|
|
1979
|
+
};
|
|
1980
|
+
var getTenantIdFromLoadModelCtx = (ctx) => {
|
|
1981
|
+
const tenantId = normalizeTenantId$1(ctx.tenantId) ?? normalizeTenantId$1(ctx.req?.session?.user?.currentTenantId);
|
|
1982
|
+
assert(tenantId, "Tenant ID is missing from ctx (expected ctx.tenantId or ctx.req.session.user.currentTenantId)");
|
|
1983
|
+
return tenantId;
|
|
1984
|
+
};
|
|
1985
|
+
var models = {
|
|
1986
|
+
register: registerModels,
|
|
1987
|
+
getUnsafe: async (modelName, ctx) => {
|
|
1988
|
+
return loadModelFromDb(modelName, getTenantDbName(getTenantIdFromLoadModelCtx(ctx)), "tenant");
|
|
1989
|
+
},
|
|
1990
|
+
get: async (modelName, ctx) => {
|
|
1991
|
+
const model = await models.getUnsafe(modelName, ctx);
|
|
1992
|
+
const resolvedAbility = ctx.ability;
|
|
1993
|
+
if (!hasRegisteredPolicy(modelName)) return model;
|
|
1994
|
+
if (!resolvedAbility) throw new Error(`Model "${modelName}" is ACL-protected. Set ctx.ability or use models.getUnsafe(...) explicitly.`);
|
|
1995
|
+
if (typeof model.acl !== "function") return model;
|
|
1996
|
+
return model.acl(resolvedAbility);
|
|
1997
|
+
},
|
|
1998
|
+
getGlobal: async (modelName, ctx) => {
|
|
1999
|
+
return loadModelFromDb(modelName, getGlobalDbName(), "global");
|
|
2000
|
+
}
|
|
2001
|
+
};
|
|
2002
|
+
//#endregion
|
|
2003
|
+
//#region src/createModels.ts
|
|
2004
|
+
var createModels = (modules, options) => {
|
|
2005
|
+
registerModels(modules, options);
|
|
2006
|
+
const get = (async (modelNameOrNames, ctx) => {
|
|
2007
|
+
if (Array.isArray(modelNameOrNames)) return Promise.all(modelNameOrNames.map((modelName) => models.get(modelName, ctx)));
|
|
2008
|
+
return models.get(modelNameOrNames, ctx);
|
|
2009
|
+
});
|
|
2010
|
+
const getUnsafe = (async (modelNameOrNames, ctx) => {
|
|
2011
|
+
if (Array.isArray(modelNameOrNames)) return Promise.all(modelNameOrNames.map((modelName) => models.getUnsafe(modelName, ctx)));
|
|
2012
|
+
return models.getUnsafe(modelNameOrNames, ctx);
|
|
2013
|
+
});
|
|
2014
|
+
const getGlobal = (async (modelNameOrNames, ctx) => {
|
|
2015
|
+
if (Array.isArray(modelNameOrNames)) return Promise.all(modelNameOrNames.map((modelName) => models.getGlobal(modelName, ctx)));
|
|
2016
|
+
return models.getGlobal(modelNameOrNames, ctx);
|
|
2017
|
+
});
|
|
2018
|
+
return {
|
|
2019
|
+
register: (nextModules, nextOptions) => registerModels(nextModules, nextOptions),
|
|
2020
|
+
get,
|
|
2021
|
+
getUnsafe,
|
|
2022
|
+
getGlobal
|
|
2023
|
+
};
|
|
2024
|
+
};
|
|
2025
|
+
//#endregion
|
|
2026
|
+
//#region src/tenantFilesystemDb.ts
|
|
2027
|
+
var getAppName = () => {
|
|
2028
|
+
const appName = process.env.APP_NAME?.trim();
|
|
2029
|
+
assert(appName, "Missing APP_NAME");
|
|
2030
|
+
return appName;
|
|
2031
|
+
};
|
|
2032
|
+
var normalizeTenantId = (tenantId) => {
|
|
2033
|
+
const normalized = tenantId.trim();
|
|
2034
|
+
assert(normalized, "Tenant ID is missing");
|
|
2035
|
+
return normalized;
|
|
2036
|
+
};
|
|
2037
|
+
var getTenantFilesystemDbName = (tenantId) => `${getAppName()}-${normalizeTenantId(tenantId)}-filesystem-db`;
|
|
2038
|
+
var getTenantFilesystemDb = async (tenantId) => ensureMongooseConnection(getTenantFilesystemDbName(tenantId));
|
|
2039
|
+
var getTenantFilesystemDbFromCtx = async (ctx) => {
|
|
2040
|
+
return getTenantFilesystemDb(getTenantIdFromLoadModelCtx(ctx));
|
|
2041
|
+
};
|
|
2042
|
+
//#endregion
|
|
2043
|
+
//#region src/transactions.ts
|
|
2044
|
+
var buildTenantLoadModelCtx = (tenantId) => ({ req: { session: { user: { currentTenantId: tenantId } } } });
|
|
2202
2045
|
async function withTransaction(scope, fn, options) {
|
|
2203
|
-
|
|
2204
|
-
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
}), options);
|
|
2236
|
-
} finally {
|
|
2237
|
-
await session.endSession();
|
|
2238
|
-
}
|
|
2046
|
+
const normalizedTenantId = (() => {
|
|
2047
|
+
if (typeof scope === "string") return scope.trim();
|
|
2048
|
+
if ("tenantId" in scope) return scope.tenantId.trim();
|
|
2049
|
+
return getTenantIdFromLoadModelCtx(scope.ctx);
|
|
2050
|
+
})();
|
|
2051
|
+
if (!normalizedTenantId) throw new Error("Tenant ID is missing");
|
|
2052
|
+
const tenantDbName = getTenantDbName(normalizedTenantId);
|
|
2053
|
+
const globalDbName = getGlobalDbName();
|
|
2054
|
+
const filesystemDbName = getTenantFilesystemDbName(normalizedTenantId);
|
|
2055
|
+
const tenantDb = await ensureMongooseConnection(tenantDbName);
|
|
2056
|
+
const globalDb = await ensureMongooseConnection(globalDbName);
|
|
2057
|
+
const filesystemDb = await ensureMongooseConnection(filesystemDbName);
|
|
2058
|
+
const session = await tenantDb.startSession();
|
|
2059
|
+
const tenantCtx = typeof scope === "object" && "ctx" in scope ? scope.ctx : buildTenantLoadModelCtx(normalizedTenantId);
|
|
2060
|
+
const globalCtx = { req: { session: null } };
|
|
2061
|
+
try {
|
|
2062
|
+
return await session.withTransaction(async () => fn({
|
|
2063
|
+
tenantId: normalizedTenantId,
|
|
2064
|
+
session,
|
|
2065
|
+
ctx: {
|
|
2066
|
+
tenant: tenantCtx,
|
|
2067
|
+
global: globalCtx
|
|
2068
|
+
},
|
|
2069
|
+
db: {
|
|
2070
|
+
tenant: tenantDb,
|
|
2071
|
+
global: globalDb,
|
|
2072
|
+
filesystem: filesystemDb
|
|
2073
|
+
}
|
|
2074
|
+
}), options);
|
|
2075
|
+
} finally {
|
|
2076
|
+
await session.endSession();
|
|
2077
|
+
}
|
|
2239
2078
|
}
|
|
2240
|
-
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
|
|
2246
|
-
|
|
2247
|
-
|
|
2248
|
-
|
|
2249
|
-
|
|
2250
|
-
|
|
2251
|
-
|
|
2252
|
-
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
cancelAt: projection.cancelAt ?? void 0,
|
|
2285
|
-
canceledAt: projection.canceledAt ?? void 0,
|
|
2286
|
-
scheduledPlanKey: projection.scheduledPlan?.planKey,
|
|
2287
|
-
scheduledPlanEffectiveAt: projection.scheduledPlan?.effectiveAt,
|
|
2288
|
-
provider: projection.provider ?? void 0,
|
|
2289
|
-
latestEventId: projection.latestEventId,
|
|
2290
|
-
latestEventAt: projection.latestEventAt,
|
|
2291
|
-
projectedAt: projection.projectedAt
|
|
2079
|
+
//#endregion
|
|
2080
|
+
//#region src/billingStorage.ts
|
|
2081
|
+
var getTransactionSession = (transaction) => {
|
|
2082
|
+
if (!transaction || typeof transaction !== "object" || !("session" in transaction)) return void 0;
|
|
2083
|
+
return transaction.session;
|
|
2084
|
+
};
|
|
2085
|
+
var toSubscriptionEvent = (document) => {
|
|
2086
|
+
const parsed = ZRBTenantSubscriptionEvent.parse(document);
|
|
2087
|
+
if (!document._id) throw new Error("Persisted subscription event is missing its id");
|
|
2088
|
+
return {
|
|
2089
|
+
...parsed,
|
|
2090
|
+
id: String(document._id)
|
|
2091
|
+
};
|
|
2092
|
+
};
|
|
2093
|
+
var getExistingEventQuery = (event, tenantId) => ({
|
|
2094
|
+
tenantId,
|
|
2095
|
+
idempotencyKey: event.idempotencyKey
|
|
2096
|
+
});
|
|
2097
|
+
var isDuplicateKeyError = (error) => Boolean(error && typeof error === "object" && "code" in error && error.code === 11e3);
|
|
2098
|
+
var toProjectionDocument = (projection) => ({
|
|
2099
|
+
tenantId: projection.tenantId,
|
|
2100
|
+
subscriptionId: projection.subscriptionId,
|
|
2101
|
+
type: projection.type,
|
|
2102
|
+
parentSubscriptionId: projection.parentSubscriptionId ?? void 0,
|
|
2103
|
+
scope: projection.scope,
|
|
2104
|
+
scopeId: projection.scopeId ?? void 0,
|
|
2105
|
+
planKey: projection.planKey,
|
|
2106
|
+
priceId: projection.priceId ?? void 0,
|
|
2107
|
+
status: projection.status,
|
|
2108
|
+
intervalUnit: projection.intervalUnit,
|
|
2109
|
+
intervalCount: projection.intervalCount,
|
|
2110
|
+
modules: projection.modules,
|
|
2111
|
+
billingAnchor: projection.billingAnchor,
|
|
2112
|
+
currentPeriodStart: projection.currentPeriodStart,
|
|
2113
|
+
currentPeriodEnd: projection.currentPeriodEnd,
|
|
2114
|
+
cancelAtPeriodEnd: projection.cancelAtPeriodEnd,
|
|
2115
|
+
cancelAt: projection.cancelAt ?? void 0,
|
|
2116
|
+
canceledAt: projection.canceledAt ?? void 0,
|
|
2117
|
+
scheduledPlanKey: projection.scheduledPlan?.planKey,
|
|
2118
|
+
scheduledPlanEffectiveAt: projection.scheduledPlan?.effectiveAt,
|
|
2119
|
+
provider: projection.provider ?? void 0,
|
|
2120
|
+
latestEventId: projection.latestEventId,
|
|
2121
|
+
latestEventAt: projection.latestEventAt,
|
|
2122
|
+
projectedAt: projection.projectedAt
|
|
2292
2123
|
});
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
|
-
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
|
|
2317
|
-
|
|
2318
|
-
|
|
2319
|
-
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
|
|
2327
|
-
|
|
2328
|
-
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
|
|
2334
|
-
|
|
2335
|
-
|
|
2336
|
-
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
|
|
2341
|
-
|
|
2342
|
-
|
|
2343
|
-
|
|
2344
|
-
|
|
2345
|
-
|
|
2346
|
-
|
|
2347
|
-
|
|
2348
|
-
|
|
2349
|
-
|
|
2350
|
-
|
|
2351
|
-
|
|
2352
|
-
|
|
2353
|
-
|
|
2354
|
-
|
|
2355
|
-
const session = getTransactionSession(transaction);
|
|
2356
|
-
await ProjectionModel.replaceOne({
|
|
2357
|
-
tenantId: params.tenantId,
|
|
2358
|
-
subscriptionId: projection.subscriptionId
|
|
2359
|
-
}, toProjectionDocument(projection), {
|
|
2360
|
-
upsert: true,
|
|
2361
|
-
runValidators: true,
|
|
2362
|
-
...session ? {
|
|
2363
|
-
session
|
|
2364
|
-
} : {}
|
|
2365
|
-
});
|
|
2366
|
-
}
|
|
2367
|
-
};
|
|
2368
|
-
};
|
|
2369
|
-
export {
|
|
2370
|
-
E as E164_PHONE_OR_EMPTY_REGEX,
|
|
2371
|
-
a2 as E164_PHONE_REGEX,
|
|
2372
|
-
L as LANGUAGE_CODE_REGEX,
|
|
2373
|
-
PaginationValidationError,
|
|
2374
|
-
RBNotificationDeliveryPolicy,
|
|
2375
|
-
RBNotificationDeliverySchema,
|
|
2376
|
-
RBNotificationPolicy,
|
|
2377
|
-
RBNotificationSchema,
|
|
2378
|
-
RBNotificationSettingsPolicy,
|
|
2379
|
-
RBNotificationSettingsSchema,
|
|
2380
|
-
RBOAuthRequestSchema,
|
|
2381
|
-
RBRtsChangeSchema,
|
|
2382
|
-
RBRtsCounterSchema,
|
|
2383
|
-
RBTenantSchema,
|
|
2384
|
-
RBTenantSubscriptionEventSchema,
|
|
2385
|
-
RBTenantSubscriptionProjectionSchema,
|
|
2386
|
-
RBUploadChunkSchema,
|
|
2387
|
-
RBUploadSessionPolicy,
|
|
2388
|
-
RBUploadSessionSchema,
|
|
2389
|
-
RBUserSchema,
|
|
2390
|
-
Schema,
|
|
2391
|
-
ZRBNotification,
|
|
2392
|
-
ZRBNotificationDelivery,
|
|
2393
|
-
ZRBNotificationDigestFrequency,
|
|
2394
|
-
ZRBNotificationPlatformPayload,
|
|
2395
|
-
ZRBNotificationSettings,
|
|
2396
|
-
ZRBNotificationTopicPreference,
|
|
2397
|
-
ZRBOAuthRequest,
|
|
2398
|
-
ZRBRtsChange,
|
|
2399
|
-
ZRBRtsChangeOp,
|
|
2400
|
-
ZRBRtsCounter,
|
|
2401
|
-
ZRBTenant,
|
|
2402
|
-
ZRBTenantSubscriptionChangeDirection,
|
|
2403
|
-
ZRBTenantSubscriptionEvent,
|
|
2404
|
-
ZRBTenantSubscriptionEventSource,
|
|
2405
|
-
ZRBTenantSubscriptionEventType,
|
|
2406
|
-
ZRBTenantSubscriptionIntervalUnit,
|
|
2407
|
-
ZRBTenantSubscriptionProjection,
|
|
2408
|
-
ZRBTenantSubscriptionScope,
|
|
2409
|
-
ZRBTenantSubscriptionStatus,
|
|
2410
|
-
ZRBTenantSubscriptionType,
|
|
2411
|
-
ZRBUploadChunk,
|
|
2412
|
-
ZRBUploadSession,
|
|
2413
|
-
ZRBUploadSessionStatus,
|
|
2414
|
-
ZRBUser,
|
|
2415
|
-
b as buildAbility,
|
|
2416
|
-
a as buildAbilityFromSession,
|
|
2417
|
-
b2 as buildLocaleFallbackChain,
|
|
2418
|
-
buildSearchTextStage,
|
|
2419
|
-
c as can,
|
|
2420
|
-
createModels,
|
|
2421
|
-
createTenantBillingStorage,
|
|
2422
|
-
ensureSearchIndex,
|
|
2423
|
-
extendMongooseSchema,
|
|
2424
|
-
e2 as extendZod,
|
|
2425
|
-
g as getAccessibleByQuery,
|
|
2426
|
-
d as getRegisteredPolicies,
|
|
2427
|
-
getTenantFilesystemDb,
|
|
2428
|
-
getTenantFilesystemDbFromCtx,
|
|
2429
|
-
getTenantFilesystemDbName,
|
|
2430
|
-
getTenantIdFromLoadModelCtx,
|
|
2431
|
-
e as getTenantRolesFromSessionUser,
|
|
2432
|
-
hasRegisteredPolicy,
|
|
2433
|
-
isPaginationValidationError,
|
|
2434
|
-
localizedStringField,
|
|
2435
|
-
m as makeZE164Phone,
|
|
2436
|
-
model,
|
|
2437
|
-
models,
|
|
2438
|
-
mongoPaginationPlugin,
|
|
2439
|
-
default2 as mongoose,
|
|
2440
|
-
omitMongooseSchemaPaths,
|
|
2441
|
-
registerPoliciesFromModules,
|
|
2442
|
-
f as registerPolicy,
|
|
2443
|
-
r as resolveLocalizedString,
|
|
2444
|
-
searchMetaProjection,
|
|
2445
|
-
withLocalizedStringFallback,
|
|
2446
|
-
withTransaction,
|
|
2447
|
-
z2 as z,
|
|
2448
|
-
c2 as zE164Phone,
|
|
2449
|
-
d2 as zI18nString,
|
|
2450
|
-
f2 as zLocalizedString
|
|
2451
|
-
};
|
|
2452
|
-
//# sourceMappingURL=index.js.map
|
|
2124
|
+
var createTenantBillingStorage = (params) => {
|
|
2125
|
+
const findExistingEvent = async (query, transaction) => {
|
|
2126
|
+
const request = (await models.get("RBTenantSubscriptionEvent", params.ctx)).findOne(query);
|
|
2127
|
+
const session = getTransactionSession(transaction);
|
|
2128
|
+
if (session) request.session(session);
|
|
2129
|
+
const document = await request.lean();
|
|
2130
|
+
return document ? toSubscriptionEvent(document) : null;
|
|
2131
|
+
};
|
|
2132
|
+
return {
|
|
2133
|
+
runInTransaction: (operation) => withTransaction({ ctx: params.ctx }, ({ session }) => operation({ session })),
|
|
2134
|
+
createEvent: async (event, transaction) => {
|
|
2135
|
+
if (event.tenantId !== params.tenantId) throw new Error("Billing event tenantId does not match the storage tenant");
|
|
2136
|
+
const existingQuery = getExistingEventQuery(event, params.tenantId);
|
|
2137
|
+
const existing = await findExistingEvent(existingQuery, transaction);
|
|
2138
|
+
if (existing) return existing;
|
|
2139
|
+
const EventModel = await models.get("RBTenantSubscriptionEvent", params.ctx);
|
|
2140
|
+
const eventDocument = ZRBTenantSubscriptionEvent.parse(event);
|
|
2141
|
+
const session = getTransactionSession(transaction);
|
|
2142
|
+
try {
|
|
2143
|
+
const document = (await EventModel.create([eventDocument], session ? { session } : void 0))[0]?.toObject();
|
|
2144
|
+
if (!document) throw new Error("Subscription event was not persisted");
|
|
2145
|
+
return toSubscriptionEvent(document);
|
|
2146
|
+
} catch (error) {
|
|
2147
|
+
if (!isDuplicateKeyError(error)) throw error;
|
|
2148
|
+
const duplicate = await findExistingEvent(existingQuery, transaction);
|
|
2149
|
+
if (!duplicate) throw error;
|
|
2150
|
+
return duplicate;
|
|
2151
|
+
}
|
|
2152
|
+
},
|
|
2153
|
+
listEvents: async (tenantId, subscriptionId, transaction) => {
|
|
2154
|
+
if (tenantId !== params.tenantId) throw new Error("Billing storage tenant mismatch");
|
|
2155
|
+
const request = (await models.get("RBTenantSubscriptionEvent", params.ctx)).find({
|
|
2156
|
+
tenantId,
|
|
2157
|
+
subscriptionId
|
|
2158
|
+
}).sort({
|
|
2159
|
+
effectiveAt: 1,
|
|
2160
|
+
occurredAt: 1,
|
|
2161
|
+
_id: 1
|
|
2162
|
+
});
|
|
2163
|
+
const session = getTransactionSession(transaction);
|
|
2164
|
+
if (session) request.session(session);
|
|
2165
|
+
return (await request.lean()).map(toSubscriptionEvent);
|
|
2166
|
+
},
|
|
2167
|
+
upsertProjection: async (projection, transaction) => {
|
|
2168
|
+
if (projection.tenantId !== params.tenantId) throw new Error("Billing projection tenant mismatch");
|
|
2169
|
+
const ProjectionModel = await models.get("RBTenantSubscriptionProjection", params.ctx);
|
|
2170
|
+
const session = getTransactionSession(transaction);
|
|
2171
|
+
await ProjectionModel.replaceOne({
|
|
2172
|
+
tenantId: params.tenantId,
|
|
2173
|
+
subscriptionId: projection.subscriptionId
|
|
2174
|
+
}, toProjectionDocument(projection), {
|
|
2175
|
+
upsert: true,
|
|
2176
|
+
runValidators: true,
|
|
2177
|
+
...session ? { session } : {}
|
|
2178
|
+
});
|
|
2179
|
+
}
|
|
2180
|
+
};
|
|
2181
|
+
};
|
|
2182
|
+
//#endregion
|
|
2183
|
+
export { E164_PHONE_OR_EMPTY_REGEX, E164_PHONE_REGEX, LANGUAGE_CODE_REGEX, PaginationValidationError, RBNotificationDeliveryPolicy, RBNotificationDeliverySchema, RBNotificationPolicy, RBNotificationSchema, RBNotificationSettingsPolicy, RBNotificationSettingsSchema, RBOAuthRequestSchema, RBRtsChangeSchema, RBRtsCounterSchema, RBTenantSchema, RBTenantSubscriptionEventSchema, RBTenantSubscriptionProjectionSchema, RBUploadChunkSchema, RBUploadSessionPolicy, RBUploadSessionSchema, RBUserSchema, Schema, ZRBNotification, ZRBNotificationDelivery, ZRBNotificationDigestFrequency, ZRBNotificationPlatformPayload, ZRBNotificationSettings, ZRBNotificationTopicPreference, ZRBOAuthRequest, ZRBRtsChange, ZRBRtsChangeOp, ZRBRtsCounter, ZRBTenant, ZRBTenantSubscriptionChangeDirection, ZRBTenantSubscriptionEvent, ZRBTenantSubscriptionEventSource, ZRBTenantSubscriptionEventType, ZRBTenantSubscriptionIntervalUnit, ZRBTenantSubscriptionProjection, ZRBTenantSubscriptionScope, ZRBTenantSubscriptionStatus, ZRBTenantSubscriptionType, ZRBUploadChunk, ZRBUploadSession, ZRBUploadSessionStatus, ZRBUser, buildAbility, buildAbilityFromSession, buildLocaleFallbackChain, buildSearchTextStage, can, createModels, createTenantBillingStorage, ensureSearchIndex, extendMongooseSchema, extendZod, getAccessibleByQuery, getRegisteredPolicies, getTenantFilesystemDb, getTenantFilesystemDbFromCtx, getTenantFilesystemDbName, getTenantIdFromLoadModelCtx, getTenantRolesFromSessionUser, hasRegisteredPolicy, isPaginationValidationError, localizedStringField, makeZE164Phone, model, models, mongoPaginationPlugin, mongoose, omitMongooseSchemaPaths, registerPoliciesFromModules, registerPolicy, resolveLocalizedString, searchMetaProjection, withLocalizedStringFallback, withTransaction, z, zE164Phone, zI18nString, zLocalizedString };
|
|
2184
|
+
|
|
2185
|
+
//# sourceMappingURL=index.js.map
|