@infuro/cms-core 1.0.38 → 1.0.40
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/admin.cjs +108 -5
- package/dist/admin.js +109 -6
- package/dist/api.cjs +32 -32
- package/dist/api.d.cts +4 -1
- package/dist/api.d.ts +4 -1
- package/dist/api.js +1 -1
- package/dist/auth.cjs +12 -12
- package/dist/auth.js +1 -1
- package/dist/{chunk-SBRBR3VO.js → chunk-4BG7XYSH.js} +1 -0
- package/dist/{chunk-E6WVP7BK.cjs → chunk-ETZN4OQI.cjs} +1 -0
- package/dist/{chunk-PYUXVU75.js → chunk-RCMUL6SZ.js} +530 -75
- package/dist/{chunk-VJDUKAJ3.cjs → chunk-T7GCOO5Y.cjs} +531 -73
- package/dist/cli.cjs +1 -1
- package/dist/cli.js +1 -1
- package/dist/index.cjs +210 -198
- package/dist/index.d.cts +84 -68
- package/dist/index.d.ts +84 -68
- package/dist/index.js +3 -3
- package/package.json +147 -147
|
@@ -12,7 +12,7 @@ import { isErpIntegrationEnabled } from './chunk-JC6DLWTE.js';
|
|
|
12
12
|
import { __name } from './chunk-SHUYVCID.js';
|
|
13
13
|
import { PrimaryGeneratedColumn, Column, Entity, ManyToOne, JoinColumn, OneToMany, Index, ManyToMany, JoinTable, Unique, CreateDateColumn, UpdateDateColumn, In, IsNull, ILike, Between, MoreThanOrEqual, LessThanOrEqual, Not, MoreThan } from 'typeorm';
|
|
14
14
|
import { Country, State, City } from 'country-state-city';
|
|
15
|
-
import crypto2, { randomUUID, createHmac, timingSafeEqual, randomInt } from 'crypto';
|
|
15
|
+
import crypto2, { randomBytes, randomUUID, createHmac, timingSafeEqual, randomInt } from 'crypto';
|
|
16
16
|
import Parser from 'rss-parser';
|
|
17
17
|
import fs from 'fs/promises';
|
|
18
18
|
import path from 'path';
|
|
@@ -6179,6 +6179,225 @@ function createCrudByIdHandler(dataSource, entityMap, options) {
|
|
|
6179
6179
|
};
|
|
6180
6180
|
}
|
|
6181
6181
|
__name(createCrudByIdHandler, "createCrudByIdHandler");
|
|
6182
|
+
var VENDOR_INVITE_METADATA_TOKEN = "inviteToken";
|
|
6183
|
+
var VENDOR_INVITE_METADATA_EXPIRES = "inviteExpiresAt";
|
|
6184
|
+
var VENDOR_INVITE_METADATA_SENT = "inviteSentAt";
|
|
6185
|
+
async function loadOwnerVendorForUser(dataSource, vendorEntity, userId) {
|
|
6186
|
+
const repo = dataSource.getRepository(vendorEntity);
|
|
6187
|
+
const row = await repo.findOne({
|
|
6188
|
+
where: {
|
|
6189
|
+
userId,
|
|
6190
|
+
deleted: false
|
|
6191
|
+
}
|
|
6192
|
+
});
|
|
6193
|
+
if (!row) return null;
|
|
6194
|
+
const v = row;
|
|
6195
|
+
return {
|
|
6196
|
+
id: v.id,
|
|
6197
|
+
inviteStatus: v.inviteStatus,
|
|
6198
|
+
metadata: v.metadata && typeof v.metadata === "object" && !Array.isArray(v.metadata) ? v.metadata : null
|
|
6199
|
+
};
|
|
6200
|
+
}
|
|
6201
|
+
__name(loadOwnerVendorForUser, "loadOwnerVendorForUser");
|
|
6202
|
+
function invalidatedInviteMessage() {
|
|
6203
|
+
return "This invitation is no longer valid. Ask an admin to resend the invite.";
|
|
6204
|
+
}
|
|
6205
|
+
__name(invalidatedInviteMessage, "invalidatedInviteMessage");
|
|
6206
|
+
async function validateInviteTokenForActivation(dataSource, entityMap, token) {
|
|
6207
|
+
const trimmedToken = String(token ?? "").trim();
|
|
6208
|
+
if (!trimmedToken) {
|
|
6209
|
+
return {
|
|
6210
|
+
ok: false,
|
|
6211
|
+
error: "Invalid invite link. Token is missing."
|
|
6212
|
+
};
|
|
6213
|
+
}
|
|
6214
|
+
const userRepo = entityMap.users ? dataSource.getRepository(entityMap.users) : null;
|
|
6215
|
+
if (entityMap.vendors && userRepo) {
|
|
6216
|
+
const vendorMatch = await findVendorByInviteToken(dataSource, entityMap.vendors, trimmedToken);
|
|
6217
|
+
if (vendorMatch) {
|
|
6218
|
+
const vendorRepo = dataSource.getRepository(entityMap.vendors);
|
|
6219
|
+
const freshVendor = await vendorRepo.findOne({
|
|
6220
|
+
where: {
|
|
6221
|
+
id: vendorMatch.id,
|
|
6222
|
+
deleted: false
|
|
6223
|
+
}
|
|
6224
|
+
});
|
|
6225
|
+
const v = freshVendor;
|
|
6226
|
+
if (!v?.userId) {
|
|
6227
|
+
return {
|
|
6228
|
+
ok: false,
|
|
6229
|
+
error: invalidatedInviteMessage()
|
|
6230
|
+
};
|
|
6231
|
+
}
|
|
6232
|
+
if (v.inviteStatus === "accepted") {
|
|
6233
|
+
return {
|
|
6234
|
+
ok: false,
|
|
6235
|
+
error: "This invitation has already been accepted"
|
|
6236
|
+
};
|
|
6237
|
+
}
|
|
6238
|
+
if (v.inviteStatus === "expired") {
|
|
6239
|
+
await vendorRepo.update(v.id, {
|
|
6240
|
+
inviteStatus: "pending"
|
|
6241
|
+
});
|
|
6242
|
+
v.inviteStatus = "pending";
|
|
6243
|
+
}
|
|
6244
|
+
const user2 = await userRepo.findOne({
|
|
6245
|
+
where: {
|
|
6246
|
+
id: v.userId
|
|
6247
|
+
},
|
|
6248
|
+
select: [
|
|
6249
|
+
"id",
|
|
6250
|
+
"email",
|
|
6251
|
+
"blocked",
|
|
6252
|
+
"password"
|
|
6253
|
+
]
|
|
6254
|
+
});
|
|
6255
|
+
if (!user2) return {
|
|
6256
|
+
ok: false,
|
|
6257
|
+
error: "User not found"
|
|
6258
|
+
};
|
|
6259
|
+
const hasPassword2 = !!user2.password;
|
|
6260
|
+
if (!user2.blocked && hasPassword2) {
|
|
6261
|
+
return {
|
|
6262
|
+
ok: false,
|
|
6263
|
+
error: "User is already active"
|
|
6264
|
+
};
|
|
6265
|
+
}
|
|
6266
|
+
return {
|
|
6267
|
+
ok: true,
|
|
6268
|
+
target: {
|
|
6269
|
+
userId: user2.id,
|
|
6270
|
+
email: String(user2.email),
|
|
6271
|
+
vendorId: v.id
|
|
6272
|
+
}
|
|
6273
|
+
};
|
|
6274
|
+
}
|
|
6275
|
+
}
|
|
6276
|
+
let email;
|
|
6277
|
+
try {
|
|
6278
|
+
email = Buffer.from(trimmedToken, "base64").toString("utf8").trim();
|
|
6279
|
+
} catch {
|
|
6280
|
+
return {
|
|
6281
|
+
ok: false,
|
|
6282
|
+
error: invalidatedInviteMessage()
|
|
6283
|
+
};
|
|
6284
|
+
}
|
|
6285
|
+
if (!email.includes("@")) {
|
|
6286
|
+
return {
|
|
6287
|
+
ok: false,
|
|
6288
|
+
error: invalidatedInviteMessage()
|
|
6289
|
+
};
|
|
6290
|
+
}
|
|
6291
|
+
if (!userRepo) {
|
|
6292
|
+
return {
|
|
6293
|
+
ok: false,
|
|
6294
|
+
error: "User not found"
|
|
6295
|
+
};
|
|
6296
|
+
}
|
|
6297
|
+
const user = await userRepo.findOne({
|
|
6298
|
+
where: {
|
|
6299
|
+
email
|
|
6300
|
+
},
|
|
6301
|
+
select: [
|
|
6302
|
+
"id",
|
|
6303
|
+
"email",
|
|
6304
|
+
"blocked",
|
|
6305
|
+
"password"
|
|
6306
|
+
]
|
|
6307
|
+
});
|
|
6308
|
+
if (!user) return {
|
|
6309
|
+
ok: false,
|
|
6310
|
+
error: "User not found"
|
|
6311
|
+
};
|
|
6312
|
+
const hasPassword = !!user.password;
|
|
6313
|
+
if (!user.blocked && hasPassword) {
|
|
6314
|
+
return {
|
|
6315
|
+
ok: false,
|
|
6316
|
+
error: "User is already active"
|
|
6317
|
+
};
|
|
6318
|
+
}
|
|
6319
|
+
if (entityMap.vendors) {
|
|
6320
|
+
const ownerVendor = await loadOwnerVendorForUser(dataSource, entityMap.vendors, user.id);
|
|
6321
|
+
if (ownerVendor && readVendorInviteToken(ownerVendor.metadata)) {
|
|
6322
|
+
return {
|
|
6323
|
+
ok: false,
|
|
6324
|
+
error: invalidatedInviteMessage()
|
|
6325
|
+
};
|
|
6326
|
+
}
|
|
6327
|
+
}
|
|
6328
|
+
return {
|
|
6329
|
+
ok: true,
|
|
6330
|
+
target: {
|
|
6331
|
+
userId: user.id,
|
|
6332
|
+
email: String(user.email)
|
|
6333
|
+
}
|
|
6334
|
+
};
|
|
6335
|
+
}
|
|
6336
|
+
__name(validateInviteTokenForActivation, "validateInviteTokenForActivation");
|
|
6337
|
+
function buildVendorInviteLink(baseUrl, token) {
|
|
6338
|
+
const base = baseUrl.replace(/\/+$/, "");
|
|
6339
|
+
return `${base}/admin/invite?token=${encodeURIComponent(token)}`;
|
|
6340
|
+
}
|
|
6341
|
+
__name(buildVendorInviteLink, "buildVendorInviteLink");
|
|
6342
|
+
function applyRotatingVendorInvite(existing) {
|
|
6343
|
+
const next = {
|
|
6344
|
+
...existing ?? {}
|
|
6345
|
+
};
|
|
6346
|
+
next[VENDOR_INVITE_METADATA_TOKEN] = randomBytes(32).toString("hex");
|
|
6347
|
+
next[VENDOR_INVITE_METADATA_SENT] = (/* @__PURE__ */ new Date()).toISOString();
|
|
6348
|
+
delete next[VENDOR_INVITE_METADATA_EXPIRES];
|
|
6349
|
+
return next;
|
|
6350
|
+
}
|
|
6351
|
+
__name(applyRotatingVendorInvite, "applyRotatingVendorInvite");
|
|
6352
|
+
function clearVendorInviteMetadata(existing) {
|
|
6353
|
+
const next = {
|
|
6354
|
+
...existing ?? {}
|
|
6355
|
+
};
|
|
6356
|
+
delete next[VENDOR_INVITE_METADATA_TOKEN];
|
|
6357
|
+
delete next[VENDOR_INVITE_METADATA_EXPIRES];
|
|
6358
|
+
delete next[VENDOR_INVITE_METADATA_SENT];
|
|
6359
|
+
return Object.keys(next).length > 0 ? next : null;
|
|
6360
|
+
}
|
|
6361
|
+
__name(clearVendorInviteMetadata, "clearVendorInviteMetadata");
|
|
6362
|
+
function readVendorInviteToken(metadata) {
|
|
6363
|
+
const raw = metadata?.[VENDOR_INVITE_METADATA_TOKEN];
|
|
6364
|
+
return typeof raw === "string" && raw.trim() ? raw.trim() : null;
|
|
6365
|
+
}
|
|
6366
|
+
__name(readVendorInviteToken, "readVendorInviteToken");
|
|
6367
|
+
async function findVendorByInviteToken(dataSource, vendorEntity, token) {
|
|
6368
|
+
const trimmed = token.trim();
|
|
6369
|
+
if (!trimmed) return null;
|
|
6370
|
+
const repo = dataSource.getRepository(vendorEntity);
|
|
6371
|
+
const row = await repo.createQueryBuilder("v").where("v.deleted = false").andWhere(`v.metadata->>'${VENDOR_INVITE_METADATA_TOKEN}' = :token`, {
|
|
6372
|
+
token: trimmed
|
|
6373
|
+
}).getOne();
|
|
6374
|
+
if (!row) return null;
|
|
6375
|
+
const v = row;
|
|
6376
|
+
return {
|
|
6377
|
+
id: v.id,
|
|
6378
|
+
userId: v.userId ?? null,
|
|
6379
|
+
inviteStatus: v.inviteStatus,
|
|
6380
|
+
metadata: v.metadata && typeof v.metadata === "object" && !Array.isArray(v.metadata) ? v.metadata : null
|
|
6381
|
+
};
|
|
6382
|
+
}
|
|
6383
|
+
__name(findVendorByInviteToken, "findVendorByInviteToken");
|
|
6384
|
+
async function completeVendorInviteAccept(dataSource, vendorEntity, vendorId) {
|
|
6385
|
+
const repo = dataSource.getRepository(vendorEntity);
|
|
6386
|
+
const row = await repo.findOne({
|
|
6387
|
+
where: {
|
|
6388
|
+
id: vendorId,
|
|
6389
|
+
deleted: false
|
|
6390
|
+
}
|
|
6391
|
+
});
|
|
6392
|
+
if (!row) return;
|
|
6393
|
+
const metadata = row.metadata;
|
|
6394
|
+
const cleared = clearVendorInviteMetadata(metadata);
|
|
6395
|
+
await repo.update(vendorId, {
|
|
6396
|
+
metadata: cleared,
|
|
6397
|
+
inviteStatus: "accepted"
|
|
6398
|
+
});
|
|
6399
|
+
}
|
|
6400
|
+
__name(completeVendorInviteAccept, "completeVendorInviteAccept");
|
|
6182
6401
|
|
|
6183
6402
|
// src/api/auth-handlers.ts
|
|
6184
6403
|
function createForgotPasswordHandler(config) {
|
|
@@ -6314,49 +6533,27 @@ function createInviteAcceptHandler(config) {
|
|
|
6314
6533
|
}, {
|
|
6315
6534
|
status: 400
|
|
6316
6535
|
});
|
|
6317
|
-
|
|
6318
|
-
|
|
6319
|
-
email = Buffer.from(token, "base64").toString("utf8");
|
|
6320
|
-
} catch {
|
|
6321
|
-
return json({
|
|
6322
|
-
error: "Invalid or expired invite token"
|
|
6323
|
-
}, {
|
|
6324
|
-
status: 400
|
|
6325
|
-
});
|
|
6326
|
-
}
|
|
6327
|
-
const userRepo = dataSource.getRepository(entityMap.users);
|
|
6328
|
-
const user = await userRepo.findOne({
|
|
6329
|
-
where: {
|
|
6330
|
-
email
|
|
6331
|
-
},
|
|
6332
|
-
select: [
|
|
6333
|
-
"id",
|
|
6334
|
-
"blocked",
|
|
6335
|
-
"password"
|
|
6336
|
-
]
|
|
6337
|
-
});
|
|
6338
|
-
if (!user) return json({
|
|
6339
|
-
error: "User not found"
|
|
6340
|
-
}, {
|
|
6341
|
-
status: 400
|
|
6342
|
-
});
|
|
6343
|
-
const hasPassword = !!user.password;
|
|
6344
|
-
if (!user.blocked && hasPassword) {
|
|
6536
|
+
const validation = await validateInviteTokenForActivation(dataSource, entityMap, token);
|
|
6537
|
+
if (!validation.ok) {
|
|
6345
6538
|
return json({
|
|
6346
|
-
error:
|
|
6539
|
+
error: validation.error
|
|
6347
6540
|
}, {
|
|
6348
6541
|
status: 400
|
|
6349
6542
|
});
|
|
6350
6543
|
}
|
|
6544
|
+
const { userId, email, vendorId } = validation.target;
|
|
6351
6545
|
if (entityMap.contacts) {
|
|
6352
|
-
await linkUnclaimedContactToUser(dataSource, entityMap.contacts,
|
|
6546
|
+
await linkUnclaimedContactToUser(dataSource, entityMap.contacts, userId, email);
|
|
6353
6547
|
}
|
|
6354
|
-
if (beforeActivate) await beforeActivate(email,
|
|
6548
|
+
if (beforeActivate) await beforeActivate(email, userId);
|
|
6355
6549
|
const hashedPassword = await hashPassword(password);
|
|
6356
|
-
await
|
|
6550
|
+
await dataSource.getRepository(entityMap.users).update(userId, {
|
|
6357
6551
|
password: hashedPassword,
|
|
6358
6552
|
blocked: false
|
|
6359
6553
|
});
|
|
6554
|
+
if (vendorId != null && entityMap.vendors) {
|
|
6555
|
+
await completeVendorInviteAccept(dataSource, entityMap.vendors, vendorId);
|
|
6556
|
+
}
|
|
6360
6557
|
return json({
|
|
6361
6558
|
message: "User account activated successfully"
|
|
6362
6559
|
}, {
|
|
@@ -6372,6 +6569,35 @@ function createInviteAcceptHandler(config) {
|
|
|
6372
6569
|
}, "POST");
|
|
6373
6570
|
}
|
|
6374
6571
|
__name(createInviteAcceptHandler, "createInviteAcceptHandler");
|
|
6572
|
+
function createInviteValidateHandler(config) {
|
|
6573
|
+
const { dataSource, entityMap, json } = config;
|
|
6574
|
+
return /* @__PURE__ */ __name(async function GET(request) {
|
|
6575
|
+
try {
|
|
6576
|
+
const token = new URL(request.url).searchParams.get("token");
|
|
6577
|
+
const validation = await validateInviteTokenForActivation(dataSource, entityMap, token ?? "");
|
|
6578
|
+
if (!validation.ok) {
|
|
6579
|
+
return json({
|
|
6580
|
+
valid: false,
|
|
6581
|
+
error: validation.error
|
|
6582
|
+
}, {
|
|
6583
|
+
status: 400
|
|
6584
|
+
});
|
|
6585
|
+
}
|
|
6586
|
+
return json({
|
|
6587
|
+
valid: true
|
|
6588
|
+
});
|
|
6589
|
+
} catch (err) {
|
|
6590
|
+
console.error("[users/invite GET] validate failed", err);
|
|
6591
|
+
return json({
|
|
6592
|
+
valid: false,
|
|
6593
|
+
error: "Server Error"
|
|
6594
|
+
}, {
|
|
6595
|
+
status: 500
|
|
6596
|
+
});
|
|
6597
|
+
}
|
|
6598
|
+
}, "GET");
|
|
6599
|
+
}
|
|
6600
|
+
__name(createInviteValidateHandler, "createInviteValidateHandler");
|
|
6375
6601
|
function createChangePasswordHandler(config) {
|
|
6376
6602
|
const { dataSource, entityMap, json, comparePassword, hashPassword, getSession, minPasswordLength = 6, beforeUpdate } = config;
|
|
6377
6603
|
return /* @__PURE__ */ __name(async function POST(request) {
|
|
@@ -6450,12 +6676,22 @@ function createUserAuthApiRouter(config) {
|
|
|
6450
6676
|
const forgot = createForgotPasswordHandler(config);
|
|
6451
6677
|
const setPass = createSetPasswordHandler(config);
|
|
6452
6678
|
const invite = createInviteAcceptHandler(config);
|
|
6679
|
+
const inviteValidate = createInviteValidateHandler(config);
|
|
6453
6680
|
const changePass = config.getSession ? createChangePasswordHandler({
|
|
6454
6681
|
...config,
|
|
6455
6682
|
getSession: config.getSession,
|
|
6456
6683
|
beforeUpdate: config.beforeChangePasswordUpdate
|
|
6457
6684
|
}) : null;
|
|
6458
6685
|
return {
|
|
6686
|
+
async GET(req, pathname) {
|
|
6687
|
+
const path2 = pathname.replace(/\/$/, "");
|
|
6688
|
+
if (path2 === "invite") return inviteValidate(req);
|
|
6689
|
+
return config.json({
|
|
6690
|
+
error: "Not found"
|
|
6691
|
+
}, {
|
|
6692
|
+
status: 404
|
|
6693
|
+
});
|
|
6694
|
+
},
|
|
6459
6695
|
async POST(req, pathname) {
|
|
6460
6696
|
const path2 = pathname.replace(/\/$/, "");
|
|
6461
6697
|
if (!USER_AUTH_PATHS.includes(path2)) {
|
|
@@ -8861,13 +9097,31 @@ function createUsersApiHandlers(config) {
|
|
|
8861
9097
|
}, {
|
|
8862
9098
|
status: 404
|
|
8863
9099
|
});
|
|
8864
|
-
|
|
8865
|
-
const inviteLink = `${baseUrl}/admin/invite?token=${emailToken}`;
|
|
8866
|
-
await trySendInviteEmail(user.email, inviteLink, user.name ?? "");
|
|
9100
|
+
let inviteLink = `${baseUrl}/admin/invite?token=${Buffer.from(user.email).toString("base64")}`;
|
|
8867
9101
|
if (entityMap.vendors) {
|
|
9102
|
+
const vendorRepo = dataSource.getRepository(entityMap.vendors);
|
|
9103
|
+
const vendor = await vendorRepo.findOne({
|
|
9104
|
+
where: {
|
|
9105
|
+
userId: user.id,
|
|
9106
|
+
deleted: false
|
|
9107
|
+
}
|
|
9108
|
+
});
|
|
9109
|
+
const v = vendor;
|
|
9110
|
+
if (v && (v.inviteStatus === "pending" || v.inviteStatus === "expired")) {
|
|
9111
|
+
const rotatedMetadata = applyRotatingVendorInvite(v.metadata);
|
|
9112
|
+
await vendorRepo.update(v.id, {
|
|
9113
|
+
metadata: rotatedMetadata,
|
|
9114
|
+
inviteStatus: "pending"
|
|
9115
|
+
});
|
|
9116
|
+
const token = readVendorInviteToken(rotatedMetadata);
|
|
9117
|
+
if (token) {
|
|
9118
|
+
inviteLink = buildVendorInviteLink(baseUrl, token);
|
|
9119
|
+
}
|
|
9120
|
+
}
|
|
8868
9121
|
const { markVendorInvitePendingForUser } = await import('./vendor-invite-status-PWJ3DE76.js');
|
|
8869
9122
|
await markVendorInvitePendingForUser(dataSource, entityMap.vendors, user.id);
|
|
8870
9123
|
}
|
|
9124
|
+
await trySendInviteEmail(user.email, inviteLink, user.name ?? "");
|
|
8871
9125
|
return json({
|
|
8872
9126
|
message: "New invite link generated successfully",
|
|
8873
9127
|
inviteLink
|
|
@@ -11811,6 +12065,84 @@ function slugify(input) {
|
|
|
11811
12065
|
return input.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 80);
|
|
11812
12066
|
}
|
|
11813
12067
|
__name(slugify, "slugify");
|
|
12068
|
+
function vendorOnboardErrorResponse(json, err) {
|
|
12069
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
12070
|
+
console.error("[vendor-onboard]", err);
|
|
12071
|
+
if (msg === "VENDOR_SLUG_EXISTS") {
|
|
12072
|
+
return json({
|
|
12073
|
+
error: "Vendor slug already exists"
|
|
12074
|
+
}, {
|
|
12075
|
+
status: 400
|
|
12076
|
+
});
|
|
12077
|
+
}
|
|
12078
|
+
if (msg === "USER_EMAIL_EXISTS") {
|
|
12079
|
+
return json({
|
|
12080
|
+
error: "User with this email already exists"
|
|
12081
|
+
}, {
|
|
12082
|
+
status: 400
|
|
12083
|
+
});
|
|
12084
|
+
}
|
|
12085
|
+
if (msg === "VENDOR_OWNER_GROUP_MISSING") {
|
|
12086
|
+
return json({
|
|
12087
|
+
error: "Vendor Owner group not found. Run migrations (VendorOwnerRbacSeed)."
|
|
12088
|
+
}, {
|
|
12089
|
+
status: 500
|
|
12090
|
+
});
|
|
12091
|
+
}
|
|
12092
|
+
if (msg === "VENDOR_ROLES_SEED_FAILED") {
|
|
12093
|
+
return json({
|
|
12094
|
+
error: "Failed to seed store roles for vendor. Run migrations."
|
|
12095
|
+
}, {
|
|
12096
|
+
status: 500
|
|
12097
|
+
});
|
|
12098
|
+
}
|
|
12099
|
+
if (/vendor_roles|vendor_role_permissions/i.test(msg)) {
|
|
12100
|
+
return json({
|
|
12101
|
+
error: "Vendor roles tables missing. Run migrations."
|
|
12102
|
+
}, {
|
|
12103
|
+
status: 500
|
|
12104
|
+
});
|
|
12105
|
+
}
|
|
12106
|
+
if (/relation .* does not exist|column .* does not exist/i.test(msg)) {
|
|
12107
|
+
return json({
|
|
12108
|
+
error: "Database schema is outdated on this environment. Run migrations.",
|
|
12109
|
+
detail: msg
|
|
12110
|
+
}, {
|
|
12111
|
+
status: 500
|
|
12112
|
+
});
|
|
12113
|
+
}
|
|
12114
|
+
if (/duplicate key|unique constraint/i.test(msg)) {
|
|
12115
|
+
if (/email/i.test(msg)) {
|
|
12116
|
+
return json({
|
|
12117
|
+
error: "A user or record with this email already exists",
|
|
12118
|
+
detail: msg
|
|
12119
|
+
}, {
|
|
12120
|
+
status: 409
|
|
12121
|
+
});
|
|
12122
|
+
}
|
|
12123
|
+
if (/slug/i.test(msg)) {
|
|
12124
|
+
return json({
|
|
12125
|
+
error: "Vendor slug already exists",
|
|
12126
|
+
detail: msg
|
|
12127
|
+
}, {
|
|
12128
|
+
status: 409
|
|
12129
|
+
});
|
|
12130
|
+
}
|
|
12131
|
+
return json({
|
|
12132
|
+
error: "Duplicate value conflicts with an existing record",
|
|
12133
|
+
detail: msg
|
|
12134
|
+
}, {
|
|
12135
|
+
status: 409
|
|
12136
|
+
});
|
|
12137
|
+
}
|
|
12138
|
+
return json({
|
|
12139
|
+
error: "Server error",
|
|
12140
|
+
detail: msg
|
|
12141
|
+
}, {
|
|
12142
|
+
status: 500
|
|
12143
|
+
});
|
|
12144
|
+
}
|
|
12145
|
+
__name(vendorOnboardErrorResponse, "vendorOnboardErrorResponse");
|
|
11814
12146
|
function createVendorOnboardHandlers(config) {
|
|
11815
12147
|
const { dataSource, entityMap, json, getSessionUser, baseUrl, getCms, hashPassword, minPasswordLength = 6 } = config;
|
|
11816
12148
|
async function gateAdmin() {
|
|
@@ -11979,12 +12311,28 @@ function createVendorOnboardHandlers(config) {
|
|
|
11979
12311
|
}
|
|
11980
12312
|
});
|
|
11981
12313
|
if (dupVendor) throw new Error("VENDOR_SLUG_EXISTS");
|
|
11982
|
-
|
|
12314
|
+
let ownerGroup = await groupRepo.findOne({
|
|
11983
12315
|
where: {
|
|
11984
12316
|
name: VENDOR_OWNER_GROUP_NAME,
|
|
11985
12317
|
deleted: false
|
|
11986
12318
|
}
|
|
11987
12319
|
});
|
|
12320
|
+
if (!ownerGroup) {
|
|
12321
|
+
try {
|
|
12322
|
+
await groupRepo.save(groupRepo.create({
|
|
12323
|
+
name: VENDOR_OWNER_GROUP_NAME,
|
|
12324
|
+
deleted: false
|
|
12325
|
+
}));
|
|
12326
|
+
ownerGroup = await groupRepo.findOne({
|
|
12327
|
+
where: {
|
|
12328
|
+
name: VENDOR_OWNER_GROUP_NAME,
|
|
12329
|
+
deleted: false
|
|
12330
|
+
}
|
|
12331
|
+
});
|
|
12332
|
+
} catch (seedErr) {
|
|
12333
|
+
console.error("[vendor-onboard] failed to seed Vendor Owner group", seedErr);
|
|
12334
|
+
}
|
|
12335
|
+
}
|
|
11988
12336
|
if (!ownerGroup) throw new Error("VENDOR_OWNER_GROUP_MISSING");
|
|
11989
12337
|
const existingUser = await userRepo.findOne({
|
|
11990
12338
|
where: {
|
|
@@ -12022,6 +12370,11 @@ function createVendorOnboardHandlers(config) {
|
|
|
12022
12370
|
groupId: ownerGroup.id,
|
|
12023
12371
|
adminAccess: true
|
|
12024
12372
|
}));
|
|
12373
|
+
const baseMetadata = buildVendorMetadata(null, {
|
|
12374
|
+
ownerDesignation,
|
|
12375
|
+
termsAccepted: true
|
|
12376
|
+
});
|
|
12377
|
+
const metadata = activation === "invite" ? applyRotatingVendorInvite(baseMetadata) : baseMetadata;
|
|
12025
12378
|
const vendor = await vendorRepo.save(vendorRepo.create({
|
|
12026
12379
|
name: vendorName,
|
|
12027
12380
|
slug,
|
|
@@ -12041,10 +12394,7 @@ function createVendorOnboardHandlers(config) {
|
|
|
12041
12394
|
gstin: profile.gstin,
|
|
12042
12395
|
pan: profile.pan,
|
|
12043
12396
|
registrationStatus: profile.registrationStatus,
|
|
12044
|
-
metadata
|
|
12045
|
-
ownerDesignation,
|
|
12046
|
-
termsAccepted: true
|
|
12047
|
-
}),
|
|
12397
|
+
metadata,
|
|
12048
12398
|
active: body.vendor?.active !== false,
|
|
12049
12399
|
deleted: false,
|
|
12050
12400
|
userId: newUser.id,
|
|
@@ -12073,14 +12423,18 @@ function createVendorOnboardHandlers(config) {
|
|
|
12073
12423
|
});
|
|
12074
12424
|
}
|
|
12075
12425
|
if (entityMap.customer) {
|
|
12076
|
-
|
|
12077
|
-
|
|
12078
|
-
|
|
12079
|
-
|
|
12080
|
-
|
|
12081
|
-
|
|
12082
|
-
|
|
12083
|
-
|
|
12426
|
+
try {
|
|
12427
|
+
await ensureCustomerForUser(em, entityMap.customer, {
|
|
12428
|
+
id: newUser.id,
|
|
12429
|
+
name: userName,
|
|
12430
|
+
email: userEmail,
|
|
12431
|
+
phone: trimOrNull(body.vendor?.phone) ?? ownerPhone
|
|
12432
|
+
}, {
|
|
12433
|
+
phone: trimOrNull(body.vendor?.phone) ?? ownerPhone
|
|
12434
|
+
});
|
|
12435
|
+
} catch (customerErr) {
|
|
12436
|
+
console.error("[vendor-onboard] ensureCustomerForUser skipped", customerErr);
|
|
12437
|
+
}
|
|
12084
12438
|
}
|
|
12085
12439
|
return {
|
|
12086
12440
|
vendor,
|
|
@@ -12090,8 +12444,10 @@ function createVendorOnboardHandlers(config) {
|
|
|
12090
12444
|
let inviteLink;
|
|
12091
12445
|
let emailSent = false;
|
|
12092
12446
|
if (activation === "invite") {
|
|
12093
|
-
const
|
|
12094
|
-
|
|
12447
|
+
const token = readVendorInviteToken(result.vendor.metadata);
|
|
12448
|
+
if (token) {
|
|
12449
|
+
inviteLink = buildVendorInviteLink(baseUrl, token);
|
|
12450
|
+
}
|
|
12095
12451
|
}
|
|
12096
12452
|
if (sendOwnerEmail) {
|
|
12097
12453
|
emailSent = await trySendVendorOnboardEmails({
|
|
@@ -12130,46 +12486,131 @@ function createVendorOnboardHandlers(config) {
|
|
|
12130
12486
|
status: 201
|
|
12131
12487
|
});
|
|
12132
12488
|
} catch (e) {
|
|
12133
|
-
|
|
12134
|
-
|
|
12135
|
-
|
|
12136
|
-
|
|
12137
|
-
|
|
12138
|
-
|
|
12489
|
+
return vendorOnboardErrorResponse(json, e);
|
|
12490
|
+
}
|
|
12491
|
+
},
|
|
12492
|
+
/** POST /api/admin/vendors/:id/resend-invite — rotate owner invite token and resend email */
|
|
12493
|
+
async resendInvite(req, vendorIdStr) {
|
|
12494
|
+
const err = await gateAdmin();
|
|
12495
|
+
if (err) return err;
|
|
12496
|
+
if (!entityMap.vendors || !entityMap.users) {
|
|
12497
|
+
return json({
|
|
12498
|
+
error: "Vendor entities not configured"
|
|
12139
12499
|
}, {
|
|
12140
|
-
status:
|
|
12500
|
+
status: 500
|
|
12141
12501
|
});
|
|
12142
|
-
|
|
12143
|
-
|
|
12502
|
+
}
|
|
12503
|
+
const vendorId = Number(vendorIdStr);
|
|
12504
|
+
if (!Number.isFinite(vendorId) || vendorId <= 0) {
|
|
12505
|
+
return json({
|
|
12506
|
+
error: "Invalid vendor id"
|
|
12144
12507
|
}, {
|
|
12145
12508
|
status: 400
|
|
12146
12509
|
});
|
|
12147
|
-
|
|
12510
|
+
}
|
|
12511
|
+
let sendEmail = true;
|
|
12512
|
+
try {
|
|
12513
|
+
const body = await req.json().catch(() => ({}));
|
|
12514
|
+
if (body.sendEmail === false) sendEmail = false;
|
|
12515
|
+
} catch {
|
|
12516
|
+
}
|
|
12517
|
+
try {
|
|
12518
|
+
const vendorRepo = dataSource.getRepository(entityMap.vendors);
|
|
12519
|
+
const vendor = await vendorRepo.findOne({
|
|
12520
|
+
where: {
|
|
12521
|
+
id: vendorId,
|
|
12522
|
+
deleted: false
|
|
12523
|
+
}
|
|
12524
|
+
});
|
|
12525
|
+
if (!vendor) return json({
|
|
12526
|
+
error: "Vendor not found"
|
|
12527
|
+
}, {
|
|
12528
|
+
status: 404
|
|
12529
|
+
});
|
|
12530
|
+
const v = vendor;
|
|
12531
|
+
if (v.inviteStatus === "accepted") {
|
|
12148
12532
|
return json({
|
|
12149
|
-
error: "
|
|
12533
|
+
error: "Owner has already accepted the invite"
|
|
12150
12534
|
}, {
|
|
12151
|
-
status:
|
|
12535
|
+
status: 400
|
|
12152
12536
|
});
|
|
12153
12537
|
}
|
|
12154
|
-
if (
|
|
12538
|
+
if (v.inviteStatus === "none") {
|
|
12155
12539
|
return json({
|
|
12156
|
-
error: "
|
|
12540
|
+
error: "This vendor was not created with an invite link"
|
|
12157
12541
|
}, {
|
|
12158
|
-
status:
|
|
12542
|
+
status: 400
|
|
12543
|
+
});
|
|
12544
|
+
}
|
|
12545
|
+
if (v.inviteStatus !== "pending" && v.inviteStatus !== "expired") {
|
|
12546
|
+
return json({
|
|
12547
|
+
error: "Invite cannot be resent for this vendor"
|
|
12548
|
+
}, {
|
|
12549
|
+
status: 400
|
|
12550
|
+
});
|
|
12551
|
+
}
|
|
12552
|
+
if (!v.userId) {
|
|
12553
|
+
return json({
|
|
12554
|
+
error: "Vendor has no owner user linked"
|
|
12555
|
+
}, {
|
|
12556
|
+
status: 400
|
|
12557
|
+
});
|
|
12558
|
+
}
|
|
12559
|
+
const userRepo = dataSource.getRepository(entityMap.users);
|
|
12560
|
+
const owner = await userRepo.findOne({
|
|
12561
|
+
where: {
|
|
12562
|
+
id: v.userId,
|
|
12563
|
+
deleted: false
|
|
12564
|
+
}
|
|
12565
|
+
});
|
|
12566
|
+
if (!owner) return json({
|
|
12567
|
+
error: "Owner user not found"
|
|
12568
|
+
}, {
|
|
12569
|
+
status: 404
|
|
12570
|
+
});
|
|
12571
|
+
const ownerRow = owner;
|
|
12572
|
+
const hasPassword = !!(ownerRow.password && String(ownerRow.password).trim());
|
|
12573
|
+
if (!ownerRow.blocked && hasPassword) {
|
|
12574
|
+
return json({
|
|
12575
|
+
error: "Owner account is already active"
|
|
12576
|
+
}, {
|
|
12577
|
+
status: 400
|
|
12159
12578
|
});
|
|
12160
12579
|
}
|
|
12161
|
-
|
|
12580
|
+
const rotatedMetadata = applyRotatingVendorInvite(v.metadata);
|
|
12581
|
+
await vendorRepo.update(vendorId, {
|
|
12582
|
+
metadata: rotatedMetadata,
|
|
12583
|
+
inviteStatus: "pending"
|
|
12584
|
+
});
|
|
12585
|
+
const token = readVendorInviteToken(rotatedMetadata);
|
|
12586
|
+
if (!token) {
|
|
12162
12587
|
return json({
|
|
12163
|
-
error: "
|
|
12588
|
+
error: "Failed to generate invite token"
|
|
12164
12589
|
}, {
|
|
12165
12590
|
status: 500
|
|
12166
12591
|
});
|
|
12167
12592
|
}
|
|
12593
|
+
const inviteLink = buildVendorInviteLink(baseUrl, token);
|
|
12594
|
+
let emailSent = false;
|
|
12595
|
+
if (sendEmail) {
|
|
12596
|
+
emailSent = await trySendVendorOnboardEmails({
|
|
12597
|
+
vendorName: v.name,
|
|
12598
|
+
vendorSlug: v.slug,
|
|
12599
|
+
ownerName: ownerRow.name,
|
|
12600
|
+
ownerEmail: ownerRow.email,
|
|
12601
|
+
activation: "invite",
|
|
12602
|
+
inviteLink,
|
|
12603
|
+
sendToOwner: true
|
|
12604
|
+
});
|
|
12605
|
+
}
|
|
12168
12606
|
return json({
|
|
12169
|
-
|
|
12170
|
-
|
|
12171
|
-
|
|
12607
|
+
message: emailSent ? "Invite resent. Previous invite link is no longer valid." : sendEmail ? "New invite link created (email may not have been sent \u2014 check email plugin). Previous link is invalid." : "New invite link created. Previous invite link is no longer valid.",
|
|
12608
|
+
emailSent,
|
|
12609
|
+
inviteLink,
|
|
12610
|
+
inviteStatus: "pending"
|
|
12172
12611
|
});
|
|
12612
|
+
} catch (e) {
|
|
12613
|
+
return vendorOnboardErrorResponse(json, e);
|
|
12173
12614
|
}
|
|
12174
12615
|
},
|
|
12175
12616
|
/** POST /api/admin/vendor/switch — set active vendor in session (JWT update via client) */
|
|
@@ -25533,6 +25974,14 @@ function createCmsApiHandler(config) {
|
|
|
25533
25974
|
});
|
|
25534
25975
|
return vendorHandlers.onboard(req);
|
|
25535
25976
|
}
|
|
25977
|
+
if (path2[0] === "admin" && path2[1] === "vendors" && path2.length === 4 && path2[3] === "resend-invite" && m === "POST") {
|
|
25978
|
+
if (!vendorHandlers) return config.json({
|
|
25979
|
+
error: "Not found"
|
|
25980
|
+
}, {
|
|
25981
|
+
status: 404
|
|
25982
|
+
});
|
|
25983
|
+
return vendorHandlers.resendInvite(req, path2[2]);
|
|
25984
|
+
}
|
|
25536
25985
|
if (path2[0] === "admin" && path2[1] === "vendor" && path2[2] === "switch" && path2.length === 3 && m === "POST") {
|
|
25537
25986
|
if (!vendorHandlers) return config.json({
|
|
25538
25987
|
error: "Not found"
|
|
@@ -26124,6 +26573,15 @@ function createCmsApiHandler(config) {
|
|
|
26124
26573
|
if (m === "PUT" || m === "PATCH") return formSaveHandlers.PUT(req, path2[1]);
|
|
26125
26574
|
}
|
|
26126
26575
|
}
|
|
26576
|
+
if (path2[0] === "users" && path2.length === 2 && userAuthRouter) {
|
|
26577
|
+
const authSegment = path2[1];
|
|
26578
|
+
if (m === "GET" && authSegment === "invite" && userAuthRouter.GET) {
|
|
26579
|
+
return userAuthRouter.GET(req, authSegment);
|
|
26580
|
+
}
|
|
26581
|
+
if (m === "POST" && (authSegment === "invite" || authSegment === "forgot-password" || authSegment === "set-password" || authSegment === "reset-password")) {
|
|
26582
|
+
return userAuthRouter.POST(req, authSegment);
|
|
26583
|
+
}
|
|
26584
|
+
}
|
|
26127
26585
|
if (path2[0] === "users" && usersHandlers) {
|
|
26128
26586
|
if (path2.length === 1) {
|
|
26129
26587
|
if (m === "GET") return usersHandlers.list(req);
|
|
@@ -26144,9 +26602,6 @@ function createCmsApiHandler(config) {
|
|
|
26144
26602
|
return usersHandlers.regenerateInvite(req, path2[1]);
|
|
26145
26603
|
}
|
|
26146
26604
|
}
|
|
26147
|
-
if (path2[0] === "users" && path2.length === 2 && userAuthRouter && m === "POST") {
|
|
26148
|
-
return userAuthRouter.POST(req, path2[1]);
|
|
26149
|
-
}
|
|
26150
26605
|
if (path2[0] === "social-media" && path2[1] === "linkedin" && socialMediaHandlers && path2.length === 3) {
|
|
26151
26606
|
const tail = path2[2];
|
|
26152
26607
|
if (tail === "status" && m === "GET") {
|
|
@@ -30529,4 +30984,4 @@ function createStorefrontApiHandler(config) {
|
|
|
30529
30984
|
}
|
|
30530
30985
|
__name(createStorefrontApiHandler, "createStorefrontApiHandler");
|
|
30531
30986
|
|
|
30532
|
-
export { Address, Attendee, Attribute, BLOG_GENERATOR_AGENT_NAME, BLOG_GENERATOR_DEFAULT_SYSTEM_INSTRUCTION, BLOG_GENERATOR_DEFAULT_VALIDATION_RULES, BLOG_GENERATOR_LLM_AGENT_SLUG, BLOG_GENERATOR_MARKDOWN_ARTICLE_SEPARATOR, BLOG_METADATA_ENRICHER_AGENT_NAME, BLOG_METADATA_ENRICHER_DEFAULT_SYSTEM_INSTRUCTION, BLOG_METADATA_ENRICHER_DEFAULT_VALIDATION_RULES, BLOG_METADATA_ENRICHER_LLM_AGENT_SLUG, Blog, BlogGeneratorService, Brand, CMS_ENTITY_MAP, Cart, CartItem, Category, ChatConversation, ChatMessage, Collection, Combo, ComboItem, Comment, Config, Contact, Currency, CurrencyExchange, Customer, Customer_Contacts, Discount, DiscountRules, Event, EventProduct, Form, FormField, FormSubmission, JobSchedule, JobScheduleRun, KnowledgeBaseChunk, KnowledgeBaseDocument, LlmAgent, Media, MessageTemplate, Order, OrderAddresses, OrderDiscounts, OrderItem, OrderNotificationBinding, OrderNotificationTrigger, OtpChallenge, Page, PasswordResetToken, Payment, Permission, Product, ProductAttribute, ProductCategory, ProductConfig, ProductVariant, RefundPolicy, RefundRequest, RssArticle, RssFeed, Seo, Tag, Tax, User, UserGroup, Vendor, VendorCustomer, VendorRole, VendorRolePermission, VendorUser, Wishlist, WishlistItem, ZIP_MIME_TYPES, applyVendorCustomersContactFilter, assertCaptchaOk, assertContactAllowedForVendorOrder, buildBlogMetadataUserPrompt, buildCronFromSchedule, buildRssUserPromptFromFeeds, calculateOrderRefundPreview, calculateRefundFromPolicy, checkEventsEnabled, checkMultiVendorEnabled, contactIsVendorCustomer, countRecentOtpSends, createAnalyticsHandlers, createBlogBySlugHandler, createChangePasswordHandler, createCmsApiHandler, createCmsApp, createCmsAppWithMessaging, createCrudByIdHandler, createCrudHandler, createDashboardStatsHandler, createEcommerceAnalyticsHandler, createEventOrderMessageTemplateHandlers, createForgotPasswordHandler, createFormBySlugHandler, createInviteAcceptHandler, createJobScheduleHandlers, createLlmAgentKnowledgeHandlers, createMediaZipExtractHandler, createMessageTemplateRowLoader, createOtpChallenge, createSetPasswordHandler, createSettingsApiHandlers, createSocialMediaHandlers, createStorefrontApiHandler, createUploadHandler, createUserAuthApiRouter, createUserAvatarHandler, createUserProfileHandler, createUsersApiHandlers, createVendorDashboardHandler, createVendorOnboardHandlers, customerPhoneForUser, daysBeforeEventStart, describeEventTierPolicy, ensureCustomerForUser, ensureMessagingPluginsOnCms, ensureScheduleQueueWorker, ensureVendorCustomerForOrderContact, findActiveRefundPolicyForVendor, formatTierRange, generateNumericOtp, getPublicSettingsGroup, getRssArticleSummaryFromItem, hashOtpCode, hydrateVendorSessionUser, invalidateEventsCache, invalidateMultiVendorCache, isCustomerTypeContact, isZipMedia, linkUnclaimedContactToUser, llmAgentToChatAgentOptions, loadSettingsGroupFromDb, loadUserVendorContext, mergeGuardrailsIntoSystemPrompt, messagingPlugins, metaFetchUserManagedPages, metaPostPageFeed, metaPostPagePhoto, metaResolvePageAccessToken, normalizePhoneE164, normalizeRefundTiers, overlayCmsPlugins, parseBlogGeneratorAgentContent, parseBlogGeneratorModelOutput, parseBlogMetadataEnrichmentJson, parseLlmAgentValidationRules, pgBossScheduleNameForId, queueErpCreateContactIfEnabled, queueJobScheduleNow, queuePlugin, queueSms, registerJobRunnerWorker, registerMessagingQueueProcessors, registerSmsQueueProcessor, relativePathFromMediaParentId, resolveBlogCategoryIdByName, resolveSettingsEncryptionKey, resolveVendorIdForContactCheck, sanitizeMediaFolderPath, sanitizeStorageSegment, sendVendorOnboardEmails, simpleDecrypt, simpleEncrypt, syncJobScheduleToPgBoss, validateRefundTiers, validateScheduleInput, validateUserMessageAgainstAgentRules, validateUserMessageAgainstStructuredRules, verifyAndConsumeOtpChallenge, verifyOtpCodeHash, whatsappPlugin, wrapGetCmsWithMessaging };
|
|
30987
|
+
export { Address, Attendee, Attribute, BLOG_GENERATOR_AGENT_NAME, BLOG_GENERATOR_DEFAULT_SYSTEM_INSTRUCTION, BLOG_GENERATOR_DEFAULT_VALIDATION_RULES, BLOG_GENERATOR_LLM_AGENT_SLUG, BLOG_GENERATOR_MARKDOWN_ARTICLE_SEPARATOR, BLOG_METADATA_ENRICHER_AGENT_NAME, BLOG_METADATA_ENRICHER_DEFAULT_SYSTEM_INSTRUCTION, BLOG_METADATA_ENRICHER_DEFAULT_VALIDATION_RULES, BLOG_METADATA_ENRICHER_LLM_AGENT_SLUG, Blog, BlogGeneratorService, Brand, CMS_ENTITY_MAP, Cart, CartItem, Category, ChatConversation, ChatMessage, Collection, Combo, ComboItem, Comment, Config, Contact, Currency, CurrencyExchange, Customer, Customer_Contacts, Discount, DiscountRules, Event, EventProduct, Form, FormField, FormSubmission, JobSchedule, JobScheduleRun, KnowledgeBaseChunk, KnowledgeBaseDocument, LlmAgent, Media, MessageTemplate, Order, OrderAddresses, OrderDiscounts, OrderItem, OrderNotificationBinding, OrderNotificationTrigger, OtpChallenge, Page, PasswordResetToken, Payment, Permission, Product, ProductAttribute, ProductCategory, ProductConfig, ProductVariant, RefundPolicy, RefundRequest, RssArticle, RssFeed, Seo, Tag, Tax, User, UserGroup, Vendor, VendorCustomer, VendorRole, VendorRolePermission, VendorUser, Wishlist, WishlistItem, ZIP_MIME_TYPES, applyRotatingVendorInvite, applyVendorCustomersContactFilter, assertCaptchaOk, assertContactAllowedForVendorOrder, buildBlogMetadataUserPrompt, buildCronFromSchedule, buildRssUserPromptFromFeeds, buildVendorInviteLink, calculateOrderRefundPreview, calculateRefundFromPolicy, checkEventsEnabled, checkMultiVendorEnabled, contactIsVendorCustomer, countRecentOtpSends, createAnalyticsHandlers, createBlogBySlugHandler, createChangePasswordHandler, createCmsApiHandler, createCmsApp, createCmsAppWithMessaging, createCrudByIdHandler, createCrudHandler, createDashboardStatsHandler, createEcommerceAnalyticsHandler, createEventOrderMessageTemplateHandlers, createForgotPasswordHandler, createFormBySlugHandler, createInviteAcceptHandler, createJobScheduleHandlers, createLlmAgentKnowledgeHandlers, createMediaZipExtractHandler, createMessageTemplateRowLoader, createOtpChallenge, createSetPasswordHandler, createSettingsApiHandlers, createSocialMediaHandlers, createStorefrontApiHandler, createUploadHandler, createUserAuthApiRouter, createUserAvatarHandler, createUserProfileHandler, createUsersApiHandlers, createVendorDashboardHandler, createVendorOnboardHandlers, customerPhoneForUser, daysBeforeEventStart, describeEventTierPolicy, ensureCustomerForUser, ensureMessagingPluginsOnCms, ensureScheduleQueueWorker, ensureVendorCustomerForOrderContact, findActiveRefundPolicyForVendor, findVendorByInviteToken, formatTierRange, generateNumericOtp, getPublicSettingsGroup, getRssArticleSummaryFromItem, hashOtpCode, hydrateVendorSessionUser, invalidateEventsCache, invalidateMultiVendorCache, isCustomerTypeContact, isZipMedia, linkUnclaimedContactToUser, llmAgentToChatAgentOptions, loadSettingsGroupFromDb, loadUserVendorContext, mergeGuardrailsIntoSystemPrompt, messagingPlugins, metaFetchUserManagedPages, metaPostPageFeed, metaPostPagePhoto, metaResolvePageAccessToken, normalizePhoneE164, normalizeRefundTiers, overlayCmsPlugins, parseBlogGeneratorAgentContent, parseBlogGeneratorModelOutput, parseBlogMetadataEnrichmentJson, parseLlmAgentValidationRules, pgBossScheduleNameForId, queueErpCreateContactIfEnabled, queueJobScheduleNow, queuePlugin, queueSms, registerJobRunnerWorker, registerMessagingQueueProcessors, registerSmsQueueProcessor, relativePathFromMediaParentId, resolveBlogCategoryIdByName, resolveSettingsEncryptionKey, resolveVendorIdForContactCheck, sanitizeMediaFolderPath, sanitizeStorageSegment, sendVendorOnboardEmails, simpleDecrypt, simpleEncrypt, syncJobScheduleToPgBoss, validateRefundTiers, validateScheduleInput, validateUserMessageAgainstAgentRules, validateUserMessageAgainstStructuredRules, verifyAndConsumeOtpChallenge, verifyOtpCodeHash, whatsappPlugin, wrapGetCmsWithMessaging };
|