@infuro/cms-core 1.0.46 → 1.0.50
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/README.md +30 -16
- package/dist/admin.cjs +4568 -2716
- package/dist/admin.d.cts +18 -4
- package/dist/admin.d.ts +18 -4
- package/dist/admin.js +3475 -1625
- package/dist/api.cjs +38 -39
- package/dist/api.d.cts +9 -3
- package/dist/api.d.ts +9 -3
- package/dist/api.js +6 -7
- package/dist/auth.cjs +84 -51
- package/dist/auth.d.cts +105 -4
- package/dist/auth.d.ts +105 -4
- package/dist/auth.js +4 -3
- package/dist/chunk-2IAXTKQN.cjs +19 -0
- package/dist/chunk-3EOM4V2M.cjs +452 -0
- package/dist/{chunk-X6UQFV4X.cjs → chunk-77NUXO6A.cjs} +14 -12
- package/dist/{chunk-KFFB6EMZ.js → chunk-AYERBA7I.js} +3 -7
- package/dist/chunk-EIZKW2PF.js +13 -0
- package/dist/{chunk-CRYKVJTO.js → chunk-IPDHT2UV.js} +1420 -3
- package/dist/{chunk-UDVLFVEC.cjs → chunk-JCMOOPNX.cjs} +3820 -2907
- package/dist/{chunk-X47PBV4I.js → chunk-JE22VP6S.js} +1 -0
- package/dist/{chunk-DN65KDIA.js → chunk-JIWUVQ6B.js} +14 -13
- package/dist/{chunk-HT5DI3XW.cjs → chunk-KOTXDSQB.cjs} +1 -0
- package/dist/{chunk-UKC3HYXI.js → chunk-LT2WOPKA.js} +3733 -2813
- package/dist/chunk-RK5ETF2I.js +434 -0
- package/dist/{chunk-SPQFNIYJ.cjs → chunk-TJ2MIQUT.cjs} +3 -7
- package/dist/{chunk-TCSGFAWB.cjs → chunk-UUWAUHUW.cjs} +1451 -3
- package/dist/{chunk-57O3HZPG.js → chunk-WRKV6MHB.js} +415 -3
- package/dist/{chunk-FBKDMRQL.cjs → chunk-YV5PK4JW.cjs} +427 -7
- package/dist/cli.cjs +13 -22
- package/dist/cli.js +13 -22
- package/dist/{emit-order-notification-trigger-IVLWKKJL.js → emit-order-notification-trigger-6XX7LSC4.js} +1 -1
- package/dist/{emit-order-notification-trigger-D2N3KFHL.cjs → emit-order-notification-trigger-NASG7ZEO.cjs} +3 -3
- package/dist/{event-order-defaults-EMWBIGL3.cjs → event-order-defaults-DU7V3YND.cjs} +9 -9
- package/dist/{event-order-defaults-SDRNAZHC.js → event-order-defaults-H4RT7NMR.js} +1 -1
- package/dist/hooks.cjs +43 -0
- package/dist/hooks.d.cts +10 -1
- package/dist/hooks.d.ts +10 -1
- package/dist/hooks.js +39 -1
- package/dist/index.cjs +479 -339
- package/dist/index.d.cts +181 -20
- package/dist/index.d.ts +181 -20
- package/dist/index.js +115 -13
- package/dist/migrations/1782200000000-VendorTeamProfiles.ts +233 -0
- package/dist/migrations/1782300000000-AddTypeToOrderNotificationBindings.ts +75 -0
- package/dist/migrations/1782400000000-CreateUserDeviceTokens.ts +36 -0
- package/dist/migrations/1782500000000-AddPushToOrderNotificationBindingsChannelEnum.ts +15 -0
- package/dist/{order-notification-dispatcher-ZJZB2HUN.js → order-notification-dispatcher-3TA4ETYJ.js} +1 -2
- package/dist/{order-notification-dispatcher-SBQAMM5V.cjs → order-notification-dispatcher-ZEAZ5SHV.cjs} +7 -4
- package/dist/{rbac-debug-db-2SGNLANF.js → rbac-debug-db-6EMIVMGF.js} +1 -1
- package/dist/{rbac-debug-db-4Z6A425H.cjs → rbac-debug-db-6PWTLBEL.cjs} +2 -2
- package/dist/theme.cjs +6 -1
- package/dist/theme.d.cts +4 -1
- package/dist/theme.d.ts +4 -1
- package/dist/theme.js +3 -1
- package/package.json +1 -1
- package/src/admin/admin.css +7 -0
- package/dist/chunk-7PMHZRF3.cjs +0 -872
- package/dist/chunk-CQHXW4TR.js +0 -107
- package/dist/chunk-GUSHM5HN.js +0 -862
- package/dist/chunk-NBY4NVTY.cjs +0 -182
- package/dist/chunk-SF2XKMCI.js +0 -171
- package/dist/chunk-XMRMZ6NQ.cjs +0 -109
- package/dist/send-order-placed-emails-B5ZVJT7T.cjs +0 -15
- package/dist/send-order-placed-emails-WPI37KRZ.js +0 -6
|
@@ -0,0 +1,452 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var chunk77NUXO6A_cjs = require('./chunk-77NUXO6A.cjs');
|
|
4
|
+
var chunkUSNT2KNT_cjs = require('./chunk-USNT2KNT.cjs');
|
|
5
|
+
var typeorm = require('typeorm');
|
|
6
|
+
|
|
7
|
+
async function linkUnclaimedContactToUser(dataSource, contactsEntity, userId, email) {
|
|
8
|
+
const repo = dataSource.getRepository(contactsEntity);
|
|
9
|
+
const found = await repo.findOne({
|
|
10
|
+
where: {
|
|
11
|
+
email,
|
|
12
|
+
userId: typeorm.IsNull(),
|
|
13
|
+
deleted: false
|
|
14
|
+
}
|
|
15
|
+
});
|
|
16
|
+
if (found) await repo.update(found.id, {
|
|
17
|
+
userId
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
chunkUSNT2KNT_cjs.__name(linkUnclaimedContactToUser, "linkUnclaimedContactToUser");
|
|
21
|
+
|
|
22
|
+
// src/lib/ensure-customer-for-user.ts
|
|
23
|
+
function normalizeEmail(email) {
|
|
24
|
+
return email.trim().toLowerCase();
|
|
25
|
+
}
|
|
26
|
+
chunkUSNT2KNT_cjs.__name(normalizeEmail, "normalizeEmail");
|
|
27
|
+
function pgErrorCode(err) {
|
|
28
|
+
if (!err || typeof err !== "object") return void 0;
|
|
29
|
+
const driver = err.driverError;
|
|
30
|
+
return driver?.code ?? err.code;
|
|
31
|
+
}
|
|
32
|
+
chunkUSNT2KNT_cjs.__name(pgErrorCode, "pgErrorCode");
|
|
33
|
+
function normalizeCustomerPhone(phone) {
|
|
34
|
+
const p = typeof phone === "string" ? phone.trim() : "";
|
|
35
|
+
return p || null;
|
|
36
|
+
}
|
|
37
|
+
chunkUSNT2KNT_cjs.__name(normalizeCustomerPhone, "normalizeCustomerPhone");
|
|
38
|
+
function isSyntheticCustomerPhone(phone) {
|
|
39
|
+
const p = String(phone ?? "").trim();
|
|
40
|
+
if (!p) return true;
|
|
41
|
+
if (p.startsWith("e-") || p.startsWith("u-")) return true;
|
|
42
|
+
if (p.includes("@")) return true;
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
chunkUSNT2KNT_cjs.__name(isSyntheticCustomerPhone, "isSyntheticCustomerPhone");
|
|
46
|
+
function customerPhoneForUser(_userId, phone) {
|
|
47
|
+
return normalizeCustomerPhone(phone);
|
|
48
|
+
}
|
|
49
|
+
chunkUSNT2KNT_cjs.__name(customerPhoneForUser, "customerPhoneForUser");
|
|
50
|
+
function customerPhoneForEmail(_email, phone) {
|
|
51
|
+
return normalizeCustomerPhone(phone);
|
|
52
|
+
}
|
|
53
|
+
chunkUSNT2KNT_cjs.__name(customerPhoneForEmail, "customerPhoneForEmail");
|
|
54
|
+
function resolveNextPhone(inputPhone, existingPhone) {
|
|
55
|
+
if (inputPhone) return inputPhone;
|
|
56
|
+
const existing = normalizeCustomerPhone(existingPhone);
|
|
57
|
+
if (!existing || isSyntheticCustomerPhone(existing)) return null;
|
|
58
|
+
return existing;
|
|
59
|
+
}
|
|
60
|
+
chunkUSNT2KNT_cjs.__name(resolveNextPhone, "resolveNextPhone");
|
|
61
|
+
async function ensureCustomerRecord(dsOrEm, customerEntity, input) {
|
|
62
|
+
const repo = dsOrEm.getRepository(customerEntity);
|
|
63
|
+
const email = normalizeEmail(input.email);
|
|
64
|
+
if (!email) return null;
|
|
65
|
+
const name = String(input.name ?? "").trim() || email.split("@")[0] || "Customer";
|
|
66
|
+
const userId = input.userId != null && Number.isFinite(Number(input.userId)) && Number(input.userId) > 0 ? Number(input.userId) : null;
|
|
67
|
+
const phone = normalizeCustomerPhone(input.phone);
|
|
68
|
+
let row = await repo.findOne({
|
|
69
|
+
where: {
|
|
70
|
+
email,
|
|
71
|
+
deleted: false
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
if (!row) {
|
|
75
|
+
row = await repo.findOne({
|
|
76
|
+
where: {
|
|
77
|
+
email
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
if (row) {
|
|
82
|
+
const existingUserId = row.userId;
|
|
83
|
+
if (userId != null && existingUserId != null && existingUserId !== userId) {
|
|
84
|
+
return null;
|
|
85
|
+
}
|
|
86
|
+
const nextPhone = resolveNextPhone(phone, row.phone);
|
|
87
|
+
const patch = {
|
|
88
|
+
name,
|
|
89
|
+
phone: nextPhone,
|
|
90
|
+
deleted: false,
|
|
91
|
+
deletedAt: null,
|
|
92
|
+
deletedBy: null,
|
|
93
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
94
|
+
};
|
|
95
|
+
if (userId != null && existingUserId == null) {
|
|
96
|
+
patch.userId = userId;
|
|
97
|
+
}
|
|
98
|
+
await repo.update(row.id, patch);
|
|
99
|
+
return {
|
|
100
|
+
id: row.id
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
try {
|
|
104
|
+
const created = await repo.save(repo.create({
|
|
105
|
+
userId,
|
|
106
|
+
name,
|
|
107
|
+
email,
|
|
108
|
+
phone,
|
|
109
|
+
deleted: false
|
|
110
|
+
}));
|
|
111
|
+
return {
|
|
112
|
+
id: created.id
|
|
113
|
+
};
|
|
114
|
+
} catch (err) {
|
|
115
|
+
const code = pgErrorCode(err);
|
|
116
|
+
if (code === "25P02") throw err;
|
|
117
|
+
row = await repo.findOne({
|
|
118
|
+
where: {
|
|
119
|
+
email
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
if (row) {
|
|
123
|
+
const existingUserId = row.userId;
|
|
124
|
+
if (userId != null && existingUserId != null && existingUserId !== userId) return null;
|
|
125
|
+
await repo.update(row.id, {
|
|
126
|
+
name,
|
|
127
|
+
phone: resolveNextPhone(phone, row.phone),
|
|
128
|
+
...userId != null && existingUserId == null ? {
|
|
129
|
+
userId
|
|
130
|
+
} : {},
|
|
131
|
+
deleted: false,
|
|
132
|
+
deletedAt: null,
|
|
133
|
+
deletedBy: null,
|
|
134
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
135
|
+
});
|
|
136
|
+
return {
|
|
137
|
+
id: row.id
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
if (code === "23505") return null;
|
|
141
|
+
throw err;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
chunkUSNT2KNT_cjs.__name(ensureCustomerRecord, "ensureCustomerRecord");
|
|
145
|
+
async function restoreCustomerRow(repo, row, user, name, email, phone) {
|
|
146
|
+
const id = row.id;
|
|
147
|
+
await repo.update(id, {
|
|
148
|
+
userId: user.id,
|
|
149
|
+
name,
|
|
150
|
+
email,
|
|
151
|
+
phone,
|
|
152
|
+
deleted: false,
|
|
153
|
+
deletedAt: null,
|
|
154
|
+
deletedBy: null,
|
|
155
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
156
|
+
});
|
|
157
|
+
return {
|
|
158
|
+
id
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
chunkUSNT2KNT_cjs.__name(restoreCustomerRow, "restoreCustomerRow");
|
|
162
|
+
async function ensureCustomerForUser(dsOrEm, customerEntity, user, overrides) {
|
|
163
|
+
const repo = dsOrEm.getRepository(customerEntity);
|
|
164
|
+
const email = normalizeEmail(user.email);
|
|
165
|
+
const name = String(user.name ?? "").trim() || email.split("@")[0] || "User";
|
|
166
|
+
const phone = normalizeCustomerPhone(overrides?.phone ?? user.phone);
|
|
167
|
+
let row = await repo.findOne({
|
|
168
|
+
where: {
|
|
169
|
+
userId: user.id,
|
|
170
|
+
deleted: false
|
|
171
|
+
}
|
|
172
|
+
});
|
|
173
|
+
if (row) {
|
|
174
|
+
const nextPhone = resolveNextPhone(phone, row.phone);
|
|
175
|
+
await repo.update(row.id, {
|
|
176
|
+
name,
|
|
177
|
+
email,
|
|
178
|
+
phone: nextPhone,
|
|
179
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
180
|
+
});
|
|
181
|
+
return {
|
|
182
|
+
id: row.id
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
row = await repo.findOne({
|
|
186
|
+
where: {
|
|
187
|
+
email,
|
|
188
|
+
deleted: false
|
|
189
|
+
}
|
|
190
|
+
});
|
|
191
|
+
if (row) {
|
|
192
|
+
const existingUserId = row.userId;
|
|
193
|
+
if (existingUserId != null && existingUserId !== user.id) {
|
|
194
|
+
return null;
|
|
195
|
+
}
|
|
196
|
+
const nextPhone = resolveNextPhone(phone, row.phone);
|
|
197
|
+
await repo.update(row.id, {
|
|
198
|
+
userId: user.id,
|
|
199
|
+
name,
|
|
200
|
+
phone: nextPhone,
|
|
201
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
202
|
+
});
|
|
203
|
+
return {
|
|
204
|
+
id: row.id
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
const deletedByEmail = await repo.findOne({
|
|
208
|
+
where: {
|
|
209
|
+
email
|
|
210
|
+
}
|
|
211
|
+
});
|
|
212
|
+
if (deletedByEmail) {
|
|
213
|
+
const existingUserId = deletedByEmail.userId;
|
|
214
|
+
if (existingUserId != null && existingUserId !== user.id) return null;
|
|
215
|
+
return restoreCustomerRow(repo, deletedByEmail, user, name, email, resolveNextPhone(phone, deletedByEmail.phone));
|
|
216
|
+
}
|
|
217
|
+
if (phone) {
|
|
218
|
+
const deletedByPhone = await repo.findOne({
|
|
219
|
+
where: {
|
|
220
|
+
phone
|
|
221
|
+
}
|
|
222
|
+
});
|
|
223
|
+
if (deletedByPhone) {
|
|
224
|
+
const existingUserId = deletedByPhone.userId;
|
|
225
|
+
if (existingUserId != null && existingUserId !== user.id) {
|
|
226
|
+
return ensureCustomerForUser(dsOrEm, customerEntity, user, {
|
|
227
|
+
phone: null
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
return restoreCustomerRow(repo, deletedByPhone, user, name, email, phone);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
try {
|
|
234
|
+
const created = await repo.save(repo.create({
|
|
235
|
+
userId: user.id,
|
|
236
|
+
name,
|
|
237
|
+
email,
|
|
238
|
+
phone,
|
|
239
|
+
deleted: false
|
|
240
|
+
}));
|
|
241
|
+
return {
|
|
242
|
+
id: created.id
|
|
243
|
+
};
|
|
244
|
+
} catch (err) {
|
|
245
|
+
const code = pgErrorCode(err);
|
|
246
|
+
if (code === "25P02") throw err;
|
|
247
|
+
row = await repo.findOne({
|
|
248
|
+
where: {
|
|
249
|
+
userId: user.id
|
|
250
|
+
}
|
|
251
|
+
});
|
|
252
|
+
if (row) {
|
|
253
|
+
return restoreCustomerRow(repo, row, user, name, email, resolveNextPhone(phone, row.phone));
|
|
254
|
+
}
|
|
255
|
+
row = await repo.findOne({
|
|
256
|
+
where: {
|
|
257
|
+
email
|
|
258
|
+
}
|
|
259
|
+
});
|
|
260
|
+
if (row && (row.userId ?? user.id) === user.id) {
|
|
261
|
+
return restoreCustomerRow(repo, row, user, name, email, resolveNextPhone(phone, row.phone));
|
|
262
|
+
}
|
|
263
|
+
if (code === "23505") return null;
|
|
264
|
+
throw err;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
chunkUSNT2KNT_cjs.__name(ensureCustomerForUser, "ensureCustomerForUser");
|
|
268
|
+
|
|
269
|
+
// src/auth/helpers.ts
|
|
270
|
+
var RBAC_ADMIN_ONLY_ENTITIES = /* @__PURE__ */ new Set([
|
|
271
|
+
"users",
|
|
272
|
+
"user_groups",
|
|
273
|
+
"permissions"
|
|
274
|
+
]);
|
|
275
|
+
function sessionHasEntityAccess(user, entity, action) {
|
|
276
|
+
return chunk77NUXO6A_cjs.explainSessionEntityAccess(user, entity, action).allowed;
|
|
277
|
+
}
|
|
278
|
+
chunkUSNT2KNT_cjs.__name(sessionHasEntityAccess, "sessionHasEntityAccess");
|
|
279
|
+
function canManageRoles(user) {
|
|
280
|
+
return !!(user?.email && user.isRBACAdmin);
|
|
281
|
+
}
|
|
282
|
+
chunkUSNT2KNT_cjs.__name(canManageRoles, "canManageRoles");
|
|
283
|
+
var OPEN_ENDPOINTS = [
|
|
284
|
+
{
|
|
285
|
+
"/api/contacts": [
|
|
286
|
+
"POST"
|
|
287
|
+
]
|
|
288
|
+
},
|
|
289
|
+
{
|
|
290
|
+
"/api/form-submissions": [
|
|
291
|
+
"POST"
|
|
292
|
+
]
|
|
293
|
+
},
|
|
294
|
+
{
|
|
295
|
+
"/api/blogs": [
|
|
296
|
+
"GET"
|
|
297
|
+
]
|
|
298
|
+
}
|
|
299
|
+
];
|
|
300
|
+
var PERMISSION_REQUIRED_ENDPOINTS = {};
|
|
301
|
+
function isOpenEndpoint(pathname) {
|
|
302
|
+
return OPEN_ENDPOINTS.some((endpoint) => pathname.startsWith(Object.keys(endpoint)[0]));
|
|
303
|
+
}
|
|
304
|
+
chunkUSNT2KNT_cjs.__name(isOpenEndpoint, "isOpenEndpoint");
|
|
305
|
+
function getRequiredPermission(pathname) {
|
|
306
|
+
return null;
|
|
307
|
+
}
|
|
308
|
+
chunkUSNT2KNT_cjs.__name(getRequiredPermission, "getRequiredPermission");
|
|
309
|
+
function isPublicMethod(pathname, method) {
|
|
310
|
+
for (const endpoint of OPEN_ENDPOINTS) {
|
|
311
|
+
const key = Object.keys(endpoint)[0];
|
|
312
|
+
if (pathname.startsWith(key) && endpoint[key].includes(method)) return true;
|
|
313
|
+
}
|
|
314
|
+
return false;
|
|
315
|
+
}
|
|
316
|
+
chunkUSNT2KNT_cjs.__name(isPublicMethod, "isPublicMethod");
|
|
317
|
+
function createAuthHelpers(getSession, NextResponse) {
|
|
318
|
+
return createAuthHelpersFromGetSession(getSession, NextResponse);
|
|
319
|
+
}
|
|
320
|
+
chunkUSNT2KNT_cjs.__name(createAuthHelpers, "createAuthHelpers");
|
|
321
|
+
function createCmsAuthBundle(getSession, NextResponse) {
|
|
322
|
+
const auth = createAuthHelpers(getSession, NextResponse);
|
|
323
|
+
return {
|
|
324
|
+
requireAuth: auth.requireAuth,
|
|
325
|
+
requireAdminAccess: auth.requireAdminAccess,
|
|
326
|
+
requireEntityPermission: auth.requireEntityPermission,
|
|
327
|
+
getSessionUser: auth.getAuthenticatedUser,
|
|
328
|
+
getAuthenticatedUser: auth.getAuthenticatedUser
|
|
329
|
+
};
|
|
330
|
+
}
|
|
331
|
+
chunkUSNT2KNT_cjs.__name(createCmsAuthBundle, "createCmsAuthBundle");
|
|
332
|
+
function createAuthHelpersFromGetSession(getSession, NextResponse) {
|
|
333
|
+
return {
|
|
334
|
+
async requireAuth(_req) {
|
|
335
|
+
const session = await getSession();
|
|
336
|
+
if (!session?.user?.email) {
|
|
337
|
+
return NextResponse.json({
|
|
338
|
+
error: "Unauthorized"
|
|
339
|
+
}, {
|
|
340
|
+
status: 401
|
|
341
|
+
});
|
|
342
|
+
}
|
|
343
|
+
return null;
|
|
344
|
+
},
|
|
345
|
+
async requirePermission(_req, _permission) {
|
|
346
|
+
const session = await getSession();
|
|
347
|
+
if (!session?.user?.email) {
|
|
348
|
+
return NextResponse.json({
|
|
349
|
+
error: "Unauthorized"
|
|
350
|
+
}, {
|
|
351
|
+
status: 401
|
|
352
|
+
});
|
|
353
|
+
}
|
|
354
|
+
return null;
|
|
355
|
+
},
|
|
356
|
+
async requireEntityPermission(_req, entity, action) {
|
|
357
|
+
const session = await getSession();
|
|
358
|
+
if (!session?.user?.email) {
|
|
359
|
+
return NextResponse.json({
|
|
360
|
+
error: "Unauthorized"
|
|
361
|
+
}, {
|
|
362
|
+
status: 401
|
|
363
|
+
});
|
|
364
|
+
}
|
|
365
|
+
const u = session.user;
|
|
366
|
+
const allowed = sessionHasEntityAccess(u, entity, action);
|
|
367
|
+
const { reason } = chunk77NUXO6A_cjs.explainSessionEntityAccess(u, entity, action);
|
|
368
|
+
chunk77NUXO6A_cjs.logRbac("authHelpers.requireEntityPermission", {
|
|
369
|
+
entity,
|
|
370
|
+
action,
|
|
371
|
+
allowed,
|
|
372
|
+
reason,
|
|
373
|
+
email: u.email,
|
|
374
|
+
groupName: u.groupName,
|
|
375
|
+
vendorIds: u.vendorIds,
|
|
376
|
+
isVendorPortal: u.isVendorPortal,
|
|
377
|
+
isVendorOwner: u.isVendorOwner
|
|
378
|
+
});
|
|
379
|
+
if (allowed) return null;
|
|
380
|
+
return NextResponse.json({
|
|
381
|
+
error: "Forbidden",
|
|
382
|
+
entity,
|
|
383
|
+
action,
|
|
384
|
+
reason
|
|
385
|
+
}, {
|
|
386
|
+
status: 403
|
|
387
|
+
});
|
|
388
|
+
},
|
|
389
|
+
async requireAdminAccess(_req) {
|
|
390
|
+
const session = await getSession();
|
|
391
|
+
if (!session?.user?.email) {
|
|
392
|
+
return NextResponse.json({
|
|
393
|
+
error: "Unauthorized"
|
|
394
|
+
}, {
|
|
395
|
+
status: 401
|
|
396
|
+
});
|
|
397
|
+
}
|
|
398
|
+
const u = session.user;
|
|
399
|
+
if (u.isRBACAdmin) return null;
|
|
400
|
+
if (chunk77NUXO6A_cjs.isVendorPortalUser(u)) return null;
|
|
401
|
+
if (u.adminAccess === true) return null;
|
|
402
|
+
if (u.adminAccess === false) {
|
|
403
|
+
chunk77NUXO6A_cjs.logRbac("requireAdminAccess denied (adminAccess:false)", {
|
|
404
|
+
email: u.email,
|
|
405
|
+
groupName: u.groupName,
|
|
406
|
+
isVendorPortal: u.isVendorPortal
|
|
407
|
+
});
|
|
408
|
+
return NextResponse.json({
|
|
409
|
+
error: "Forbidden",
|
|
410
|
+
reason: "admin_access"
|
|
411
|
+
}, {
|
|
412
|
+
status: 403
|
|
413
|
+
});
|
|
414
|
+
}
|
|
415
|
+
chunk77NUXO6A_cjs.logRbac("requireAdminAccess denied (no matching rule)", {
|
|
416
|
+
email: u.email,
|
|
417
|
+
adminAccess: u.adminAccess,
|
|
418
|
+
groupName: u.groupName,
|
|
419
|
+
isVendorPortal: u.isVendorPortal
|
|
420
|
+
});
|
|
421
|
+
return NextResponse.json({
|
|
422
|
+
error: "Forbidden",
|
|
423
|
+
reason: "admin_access"
|
|
424
|
+
}, {
|
|
425
|
+
status: 403
|
|
426
|
+
});
|
|
427
|
+
},
|
|
428
|
+
async getAuthenticatedUser() {
|
|
429
|
+
const session = await getSession();
|
|
430
|
+
return session?.user ?? null;
|
|
431
|
+
}
|
|
432
|
+
};
|
|
433
|
+
}
|
|
434
|
+
chunkUSNT2KNT_cjs.__name(createAuthHelpersFromGetSession, "createAuthHelpersFromGetSession");
|
|
435
|
+
|
|
436
|
+
exports.OPEN_ENDPOINTS = OPEN_ENDPOINTS;
|
|
437
|
+
exports.PERMISSION_REQUIRED_ENDPOINTS = PERMISSION_REQUIRED_ENDPOINTS;
|
|
438
|
+
exports.RBAC_ADMIN_ONLY_ENTITIES = RBAC_ADMIN_ONLY_ENTITIES;
|
|
439
|
+
exports.canManageRoles = canManageRoles;
|
|
440
|
+
exports.createAuthHelpers = createAuthHelpers;
|
|
441
|
+
exports.createCmsAuthBundle = createCmsAuthBundle;
|
|
442
|
+
exports.customerPhoneForEmail = customerPhoneForEmail;
|
|
443
|
+
exports.customerPhoneForUser = customerPhoneForUser;
|
|
444
|
+
exports.ensureCustomerForUser = ensureCustomerForUser;
|
|
445
|
+
exports.ensureCustomerRecord = ensureCustomerRecord;
|
|
446
|
+
exports.getRequiredPermission = getRequiredPermission;
|
|
447
|
+
exports.isOpenEndpoint = isOpenEndpoint;
|
|
448
|
+
exports.isPublicMethod = isPublicMethod;
|
|
449
|
+
exports.isSyntheticCustomerPhone = isSyntheticCustomerPhone;
|
|
450
|
+
exports.linkUnclaimedContactToUser = linkUnclaimedContactToUser;
|
|
451
|
+
exports.normalizeCustomerPhone = normalizeCustomerPhone;
|
|
452
|
+
exports.sessionHasEntityAccess = sessionHasEntityAccess;
|
|
@@ -50,12 +50,13 @@ chunkUSNT2KNT_cjs.__name(getPermissionableEntityKeys, "getPermissionableEntityKe
|
|
|
50
50
|
function permissionRowsToRecord(rows) {
|
|
51
51
|
const out = {};
|
|
52
52
|
if (!rows?.length) return out;
|
|
53
|
+
const flag = /* @__PURE__ */ chunkUSNT2KNT_cjs.__name((v) => v === true || v === 1 || v === "1" || v === "t" || v === "true", "flag");
|
|
53
54
|
for (const p of rows) {
|
|
54
55
|
out[p.entity] = {
|
|
55
|
-
c:
|
|
56
|
-
r:
|
|
57
|
-
u:
|
|
58
|
-
d:
|
|
56
|
+
c: flag(p.canCreate),
|
|
57
|
+
r: flag(p.canRead),
|
|
58
|
+
u: flag(p.canUpdate),
|
|
59
|
+
d: flag(p.canDelete)
|
|
59
60
|
};
|
|
60
61
|
}
|
|
61
62
|
return out;
|
|
@@ -138,11 +139,12 @@ var VENDOR_STORE_RBAC_ENTITIES = /* @__PURE__ */ new Set([
|
|
|
138
139
|
"order_addresses",
|
|
139
140
|
"event_products"
|
|
140
141
|
]);
|
|
141
|
-
var
|
|
142
|
+
var VENDOR_GROUP_NAME = "Vendor";
|
|
143
|
+
var VENDOR_OWNER_GROUP_NAME = VENDOR_GROUP_NAME;
|
|
142
144
|
function isVendorGroupName(name) {
|
|
143
145
|
if (!name?.trim()) return false;
|
|
144
146
|
const n = name.trim().toLowerCase();
|
|
145
|
-
return n ===
|
|
147
|
+
return n === "vendor" || n === "vendor owner" || n.includes("vendor");
|
|
146
148
|
}
|
|
147
149
|
chunkUSNT2KNT_cjs.__name(isVendorGroupName, "isVendorGroupName");
|
|
148
150
|
function isPlatformAdministrator(user) {
|
|
@@ -165,10 +167,8 @@ function isVendorOwner(user) {
|
|
|
165
167
|
if (user?.isVendorOwner === true) return true;
|
|
166
168
|
if (!user?.email || isPlatformAdministrator(user)) return false;
|
|
167
169
|
if (user.isVendorRoleOwner === true) return true;
|
|
168
|
-
if (user.vendorRole === "staff") return false;
|
|
169
170
|
if (user.vendorRole === "owner") return true;
|
|
170
|
-
|
|
171
|
-
return user.groupName?.trim().toLowerCase() === VENDOR_OWNER_GROUP_NAME.toLowerCase();
|
|
171
|
+
return false;
|
|
172
172
|
}
|
|
173
173
|
chunkUSNT2KNT_cjs.__name(isVendorOwner, "isVendorOwner");
|
|
174
174
|
function canManageVendorTeam(user) {
|
|
@@ -206,7 +206,7 @@ chunkUSNT2KNT_cjs.__name(resolveVendorScopeFromSessionUser, "resolveVendorScopeF
|
|
|
206
206
|
function vendorPortalFlagsFromUser(input) {
|
|
207
207
|
const vendorIds = input.vendorIds ?? [];
|
|
208
208
|
const isVendorPortal = !input.isRBACAdmin && (vendorIds.length > 0 || isVendorGroupName(input.groupName));
|
|
209
|
-
const isVendorOwner2 = isVendorPortal && (input.isVendorRoleOwner === true || input.vendorRole
|
|
209
|
+
const isVendorOwner2 = isVendorPortal && (input.isVendorRoleOwner === true || input.vendorRole === "owner");
|
|
210
210
|
return {
|
|
211
211
|
isVendorPortal,
|
|
212
212
|
isVendorOwner: isVendorOwner2
|
|
@@ -463,7 +463,8 @@ function explainSessionEntityAccess(user, entity, action) {
|
|
|
463
463
|
const isStaff = user.vendorRole === "staff";
|
|
464
464
|
const vendorPerms = user.vendorEntityPerms;
|
|
465
465
|
const hasVendorRolePerms = vendorPerms != null && Object.keys(vendorPerms).length > 0;
|
|
466
|
-
|
|
466
|
+
const enforceVendorRoleMatrix = vendorIds.length > 0 && (hasVendorRolePerms || user.vendorRoleId != null);
|
|
467
|
+
if (enforceVendorRoleMatrix) {
|
|
467
468
|
const vendorRbacSet = new Set(VENDOR_RBAC_ENTITIES);
|
|
468
469
|
if (vendorRbacSet.has(entity) || entity === "analytics") {
|
|
469
470
|
if (entity === "analytics" && action === "read") {
|
|
@@ -605,7 +606,7 @@ async function logEntityAccessDecision(dataSource, context, user, entity, action
|
|
|
605
606
|
const id = Number(user.id);
|
|
606
607
|
if (Number.isFinite(id)) {
|
|
607
608
|
try {
|
|
608
|
-
const { loadDbPermissionsForUser } = await import('./rbac-debug-db-
|
|
609
|
+
const { loadDbPermissionsForUser } = await import('./rbac-debug-db-6PWTLBEL.cjs');
|
|
609
610
|
dbPermissions = await loadDbPermissionsForUser(dataSource, id);
|
|
610
611
|
} catch (e) {
|
|
611
612
|
dbPermissions = {
|
|
@@ -630,6 +631,7 @@ exports.ADMIN_GROUP_NAME = ADMIN_GROUP_NAME;
|
|
|
630
631
|
exports.DEFAULT_VENDOR_ROLE_DEFS = DEFAULT_VENDOR_ROLE_DEFS;
|
|
631
632
|
exports.SUPER_ADMIN_GROUP_ID = SUPER_ADMIN_GROUP_ID;
|
|
632
633
|
exports.VENDOR_ADMIN_GROUP_ID = VENDOR_ADMIN_GROUP_ID;
|
|
634
|
+
exports.VENDOR_GROUP_NAME = VENDOR_GROUP_NAME;
|
|
633
635
|
exports.VENDOR_OWNER_GROUP_NAME = VENDOR_OWNER_GROUP_NAME;
|
|
634
636
|
exports.VENDOR_RBAC_ENTITIES = VENDOR_RBAC_ENTITIES;
|
|
635
637
|
exports.VENDOR_SCOPED_STORE_ENTITIES = VENDOR_SCOPED_STORE_ENTITIES;
|
|
@@ -4,6 +4,7 @@ import { __name } from './chunk-SHUYVCID.js';
|
|
|
4
4
|
var EVENT_ORDER_TEMPLATE_KEY = "eventOrderPlaced";
|
|
5
5
|
var EVENT_ORDER_TEMPLATE_VARIABLES = [
|
|
6
6
|
"eventName",
|
|
7
|
+
"vendorName",
|
|
7
8
|
"eventSlug",
|
|
8
9
|
"venue",
|
|
9
10
|
"startDate",
|
|
@@ -15,7 +16,6 @@ var EVENT_ORDER_TEMPLATE_VARIABLES = [
|
|
|
15
16
|
"customerPhone",
|
|
16
17
|
"productNames",
|
|
17
18
|
"trackUrl",
|
|
18
|
-
"qrImageUrl",
|
|
19
19
|
"orderDetails",
|
|
20
20
|
"orderDetailsHtml"
|
|
21
21
|
];
|
|
@@ -31,6 +31,7 @@ var EVENT_ORDER_WHATSAPP_PARAM_KEYS = [
|
|
|
31
31
|
];
|
|
32
32
|
var EVENT_ORDER_TEMPLATE_VARIABLE_HINTS = {
|
|
33
33
|
eventName: "Event title",
|
|
34
|
+
vendorName: "Vendor / store name",
|
|
34
35
|
eventSlug: "Event URL slug",
|
|
35
36
|
venue: "Venue name",
|
|
36
37
|
startDate: "Formatted event start",
|
|
@@ -41,8 +42,7 @@ var EVENT_ORDER_TEMPLATE_VARIABLE_HINTS = {
|
|
|
41
42
|
customerEmail: "Buyer email",
|
|
42
43
|
customerPhone: "Buyer phone",
|
|
43
44
|
productNames: "Comma-separated ticket names",
|
|
44
|
-
trackUrl: "Public order tracking link
|
|
45
|
-
qrImageUrl: 'QR code image URL for email (use in <img src="\u2026">)',
|
|
45
|
+
trackUrl: "Public order tracking link",
|
|
46
46
|
orderDetails: "Plain-text order summary with line items",
|
|
47
47
|
orderDetailsHtml: "HTML order summary block",
|
|
48
48
|
trackUrlWhatsApp: "Same as trackUrl \u2014 include in Meta template as last param"
|
|
@@ -58,10 +58,6 @@ var EVENT_ORDER_MESSAGE_TEMPLATE_DEFAULTS = [
|
|
|
58
58
|
{{orderDetailsHtml}}
|
|
59
59
|
<p><strong>Venue:</strong> {{venue}}<br/>
|
|
60
60
|
<strong>Date:</strong> {{startDate}}</p>
|
|
61
|
-
<p>Show this QR code at the venue or scan to open your order:</p>
|
|
62
|
-
<p style="text-align:center;margin:20px 0">
|
|
63
|
-
<img src="{{qrImageUrl}}" alt="Order QR" width="180" height="180" style="border:1px solid #e5e7eb;border-radius:8px" />
|
|
64
|
-
</p>
|
|
65
61
|
<p style="text-align:center"><a href="{{trackUrl}}">View order online</a></p>
|
|
66
62
|
<p>We look forward to seeing you there.</p>`
|
|
67
63
|
},
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { __name } from './chunk-SHUYVCID.js';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
|
|
4
|
+
function ForceLightMode() {
|
|
5
|
+
return React.createElement("script", {
|
|
6
|
+
dangerouslySetInnerHTML: {
|
|
7
|
+
__html: `(function(){try{var r=document.documentElement,b=document.body;if(r){r.classList.remove('dark');r.style.colorScheme='light';}if(b){b.classList.remove('dark');b.style.colorScheme='light';}}catch(e){}})();`
|
|
8
|
+
}
|
|
9
|
+
});
|
|
10
|
+
}
|
|
11
|
+
__name(ForceLightMode, "ForceLightMode");
|
|
12
|
+
|
|
13
|
+
export { ForceLightMode };
|