@infuro/cms-core 1.0.39 → 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-SFDZMGHD.js → chunk-RCMUL6SZ.js} +442 -46
- package/dist/{chunk-ERJK5QXN.cjs → chunk-T7GCOO5Y.cjs} +443 -44
- 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 +2 -2
|
@@ -6189,6 +6189,225 @@ function createCrudByIdHandler(dataSource, entityMap, options) {
|
|
|
6189
6189
|
};
|
|
6190
6190
|
}
|
|
6191
6191
|
chunkUSNT2KNT_cjs.__name(createCrudByIdHandler, "createCrudByIdHandler");
|
|
6192
|
+
var VENDOR_INVITE_METADATA_TOKEN = "inviteToken";
|
|
6193
|
+
var VENDOR_INVITE_METADATA_EXPIRES = "inviteExpiresAt";
|
|
6194
|
+
var VENDOR_INVITE_METADATA_SENT = "inviteSentAt";
|
|
6195
|
+
async function loadOwnerVendorForUser(dataSource, vendorEntity, userId) {
|
|
6196
|
+
const repo = dataSource.getRepository(vendorEntity);
|
|
6197
|
+
const row = await repo.findOne({
|
|
6198
|
+
where: {
|
|
6199
|
+
userId,
|
|
6200
|
+
deleted: false
|
|
6201
|
+
}
|
|
6202
|
+
});
|
|
6203
|
+
if (!row) return null;
|
|
6204
|
+
const v = row;
|
|
6205
|
+
return {
|
|
6206
|
+
id: v.id,
|
|
6207
|
+
inviteStatus: v.inviteStatus,
|
|
6208
|
+
metadata: v.metadata && typeof v.metadata === "object" && !Array.isArray(v.metadata) ? v.metadata : null
|
|
6209
|
+
};
|
|
6210
|
+
}
|
|
6211
|
+
chunkUSNT2KNT_cjs.__name(loadOwnerVendorForUser, "loadOwnerVendorForUser");
|
|
6212
|
+
function invalidatedInviteMessage() {
|
|
6213
|
+
return "This invitation is no longer valid. Ask an admin to resend the invite.";
|
|
6214
|
+
}
|
|
6215
|
+
chunkUSNT2KNT_cjs.__name(invalidatedInviteMessage, "invalidatedInviteMessage");
|
|
6216
|
+
async function validateInviteTokenForActivation(dataSource, entityMap, token) {
|
|
6217
|
+
const trimmedToken = String(token ?? "").trim();
|
|
6218
|
+
if (!trimmedToken) {
|
|
6219
|
+
return {
|
|
6220
|
+
ok: false,
|
|
6221
|
+
error: "Invalid invite link. Token is missing."
|
|
6222
|
+
};
|
|
6223
|
+
}
|
|
6224
|
+
const userRepo = entityMap.users ? dataSource.getRepository(entityMap.users) : null;
|
|
6225
|
+
if (entityMap.vendors && userRepo) {
|
|
6226
|
+
const vendorMatch = await findVendorByInviteToken(dataSource, entityMap.vendors, trimmedToken);
|
|
6227
|
+
if (vendorMatch) {
|
|
6228
|
+
const vendorRepo = dataSource.getRepository(entityMap.vendors);
|
|
6229
|
+
const freshVendor = await vendorRepo.findOne({
|
|
6230
|
+
where: {
|
|
6231
|
+
id: vendorMatch.id,
|
|
6232
|
+
deleted: false
|
|
6233
|
+
}
|
|
6234
|
+
});
|
|
6235
|
+
const v = freshVendor;
|
|
6236
|
+
if (!v?.userId) {
|
|
6237
|
+
return {
|
|
6238
|
+
ok: false,
|
|
6239
|
+
error: invalidatedInviteMessage()
|
|
6240
|
+
};
|
|
6241
|
+
}
|
|
6242
|
+
if (v.inviteStatus === "accepted") {
|
|
6243
|
+
return {
|
|
6244
|
+
ok: false,
|
|
6245
|
+
error: "This invitation has already been accepted"
|
|
6246
|
+
};
|
|
6247
|
+
}
|
|
6248
|
+
if (v.inviteStatus === "expired") {
|
|
6249
|
+
await vendorRepo.update(v.id, {
|
|
6250
|
+
inviteStatus: "pending"
|
|
6251
|
+
});
|
|
6252
|
+
v.inviteStatus = "pending";
|
|
6253
|
+
}
|
|
6254
|
+
const user2 = await userRepo.findOne({
|
|
6255
|
+
where: {
|
|
6256
|
+
id: v.userId
|
|
6257
|
+
},
|
|
6258
|
+
select: [
|
|
6259
|
+
"id",
|
|
6260
|
+
"email",
|
|
6261
|
+
"blocked",
|
|
6262
|
+
"password"
|
|
6263
|
+
]
|
|
6264
|
+
});
|
|
6265
|
+
if (!user2) return {
|
|
6266
|
+
ok: false,
|
|
6267
|
+
error: "User not found"
|
|
6268
|
+
};
|
|
6269
|
+
const hasPassword2 = !!user2.password;
|
|
6270
|
+
if (!user2.blocked && hasPassword2) {
|
|
6271
|
+
return {
|
|
6272
|
+
ok: false,
|
|
6273
|
+
error: "User is already active"
|
|
6274
|
+
};
|
|
6275
|
+
}
|
|
6276
|
+
return {
|
|
6277
|
+
ok: true,
|
|
6278
|
+
target: {
|
|
6279
|
+
userId: user2.id,
|
|
6280
|
+
email: String(user2.email),
|
|
6281
|
+
vendorId: v.id
|
|
6282
|
+
}
|
|
6283
|
+
};
|
|
6284
|
+
}
|
|
6285
|
+
}
|
|
6286
|
+
let email;
|
|
6287
|
+
try {
|
|
6288
|
+
email = Buffer.from(trimmedToken, "base64").toString("utf8").trim();
|
|
6289
|
+
} catch {
|
|
6290
|
+
return {
|
|
6291
|
+
ok: false,
|
|
6292
|
+
error: invalidatedInviteMessage()
|
|
6293
|
+
};
|
|
6294
|
+
}
|
|
6295
|
+
if (!email.includes("@")) {
|
|
6296
|
+
return {
|
|
6297
|
+
ok: false,
|
|
6298
|
+
error: invalidatedInviteMessage()
|
|
6299
|
+
};
|
|
6300
|
+
}
|
|
6301
|
+
if (!userRepo) {
|
|
6302
|
+
return {
|
|
6303
|
+
ok: false,
|
|
6304
|
+
error: "User not found"
|
|
6305
|
+
};
|
|
6306
|
+
}
|
|
6307
|
+
const user = await userRepo.findOne({
|
|
6308
|
+
where: {
|
|
6309
|
+
email
|
|
6310
|
+
},
|
|
6311
|
+
select: [
|
|
6312
|
+
"id",
|
|
6313
|
+
"email",
|
|
6314
|
+
"blocked",
|
|
6315
|
+
"password"
|
|
6316
|
+
]
|
|
6317
|
+
});
|
|
6318
|
+
if (!user) return {
|
|
6319
|
+
ok: false,
|
|
6320
|
+
error: "User not found"
|
|
6321
|
+
};
|
|
6322
|
+
const hasPassword = !!user.password;
|
|
6323
|
+
if (!user.blocked && hasPassword) {
|
|
6324
|
+
return {
|
|
6325
|
+
ok: false,
|
|
6326
|
+
error: "User is already active"
|
|
6327
|
+
};
|
|
6328
|
+
}
|
|
6329
|
+
if (entityMap.vendors) {
|
|
6330
|
+
const ownerVendor = await loadOwnerVendorForUser(dataSource, entityMap.vendors, user.id);
|
|
6331
|
+
if (ownerVendor && readVendorInviteToken(ownerVendor.metadata)) {
|
|
6332
|
+
return {
|
|
6333
|
+
ok: false,
|
|
6334
|
+
error: invalidatedInviteMessage()
|
|
6335
|
+
};
|
|
6336
|
+
}
|
|
6337
|
+
}
|
|
6338
|
+
return {
|
|
6339
|
+
ok: true,
|
|
6340
|
+
target: {
|
|
6341
|
+
userId: user.id,
|
|
6342
|
+
email: String(user.email)
|
|
6343
|
+
}
|
|
6344
|
+
};
|
|
6345
|
+
}
|
|
6346
|
+
chunkUSNT2KNT_cjs.__name(validateInviteTokenForActivation, "validateInviteTokenForActivation");
|
|
6347
|
+
function buildVendorInviteLink(baseUrl, token) {
|
|
6348
|
+
const base = baseUrl.replace(/\/+$/, "");
|
|
6349
|
+
return `${base}/admin/invite?token=${encodeURIComponent(token)}`;
|
|
6350
|
+
}
|
|
6351
|
+
chunkUSNT2KNT_cjs.__name(buildVendorInviteLink, "buildVendorInviteLink");
|
|
6352
|
+
function applyRotatingVendorInvite(existing) {
|
|
6353
|
+
const next = {
|
|
6354
|
+
...existing ?? {}
|
|
6355
|
+
};
|
|
6356
|
+
next[VENDOR_INVITE_METADATA_TOKEN] = crypto2.randomBytes(32).toString("hex");
|
|
6357
|
+
next[VENDOR_INVITE_METADATA_SENT] = (/* @__PURE__ */ new Date()).toISOString();
|
|
6358
|
+
delete next[VENDOR_INVITE_METADATA_EXPIRES];
|
|
6359
|
+
return next;
|
|
6360
|
+
}
|
|
6361
|
+
chunkUSNT2KNT_cjs.__name(applyRotatingVendorInvite, "applyRotatingVendorInvite");
|
|
6362
|
+
function clearVendorInviteMetadata(existing) {
|
|
6363
|
+
const next = {
|
|
6364
|
+
...existing ?? {}
|
|
6365
|
+
};
|
|
6366
|
+
delete next[VENDOR_INVITE_METADATA_TOKEN];
|
|
6367
|
+
delete next[VENDOR_INVITE_METADATA_EXPIRES];
|
|
6368
|
+
delete next[VENDOR_INVITE_METADATA_SENT];
|
|
6369
|
+
return Object.keys(next).length > 0 ? next : null;
|
|
6370
|
+
}
|
|
6371
|
+
chunkUSNT2KNT_cjs.__name(clearVendorInviteMetadata, "clearVendorInviteMetadata");
|
|
6372
|
+
function readVendorInviteToken(metadata) {
|
|
6373
|
+
const raw = metadata?.[VENDOR_INVITE_METADATA_TOKEN];
|
|
6374
|
+
return typeof raw === "string" && raw.trim() ? raw.trim() : null;
|
|
6375
|
+
}
|
|
6376
|
+
chunkUSNT2KNT_cjs.__name(readVendorInviteToken, "readVendorInviteToken");
|
|
6377
|
+
async function findVendorByInviteToken(dataSource, vendorEntity, token) {
|
|
6378
|
+
const trimmed = token.trim();
|
|
6379
|
+
if (!trimmed) return null;
|
|
6380
|
+
const repo = dataSource.getRepository(vendorEntity);
|
|
6381
|
+
const row = await repo.createQueryBuilder("v").where("v.deleted = false").andWhere(`v.metadata->>'${VENDOR_INVITE_METADATA_TOKEN}' = :token`, {
|
|
6382
|
+
token: trimmed
|
|
6383
|
+
}).getOne();
|
|
6384
|
+
if (!row) return null;
|
|
6385
|
+
const v = row;
|
|
6386
|
+
return {
|
|
6387
|
+
id: v.id,
|
|
6388
|
+
userId: v.userId ?? null,
|
|
6389
|
+
inviteStatus: v.inviteStatus,
|
|
6390
|
+
metadata: v.metadata && typeof v.metadata === "object" && !Array.isArray(v.metadata) ? v.metadata : null
|
|
6391
|
+
};
|
|
6392
|
+
}
|
|
6393
|
+
chunkUSNT2KNT_cjs.__name(findVendorByInviteToken, "findVendorByInviteToken");
|
|
6394
|
+
async function completeVendorInviteAccept(dataSource, vendorEntity, vendorId) {
|
|
6395
|
+
const repo = dataSource.getRepository(vendorEntity);
|
|
6396
|
+
const row = await repo.findOne({
|
|
6397
|
+
where: {
|
|
6398
|
+
id: vendorId,
|
|
6399
|
+
deleted: false
|
|
6400
|
+
}
|
|
6401
|
+
});
|
|
6402
|
+
if (!row) return;
|
|
6403
|
+
const metadata = row.metadata;
|
|
6404
|
+
const cleared = clearVendorInviteMetadata(metadata);
|
|
6405
|
+
await repo.update(vendorId, {
|
|
6406
|
+
metadata: cleared,
|
|
6407
|
+
inviteStatus: "accepted"
|
|
6408
|
+
});
|
|
6409
|
+
}
|
|
6410
|
+
chunkUSNT2KNT_cjs.__name(completeVendorInviteAccept, "completeVendorInviteAccept");
|
|
6192
6411
|
|
|
6193
6412
|
// src/api/auth-handlers.ts
|
|
6194
6413
|
function createForgotPasswordHandler(config) {
|
|
@@ -6324,49 +6543,27 @@ function createInviteAcceptHandler(config) {
|
|
|
6324
6543
|
}, {
|
|
6325
6544
|
status: 400
|
|
6326
6545
|
});
|
|
6327
|
-
|
|
6328
|
-
|
|
6329
|
-
email = Buffer.from(token, "base64").toString("utf8");
|
|
6330
|
-
} catch {
|
|
6546
|
+
const validation = await validateInviteTokenForActivation(dataSource, entityMap, token);
|
|
6547
|
+
if (!validation.ok) {
|
|
6331
6548
|
return json({
|
|
6332
|
-
error:
|
|
6333
|
-
}, {
|
|
6334
|
-
status: 400
|
|
6335
|
-
});
|
|
6336
|
-
}
|
|
6337
|
-
const userRepo = dataSource.getRepository(entityMap.users);
|
|
6338
|
-
const user = await userRepo.findOne({
|
|
6339
|
-
where: {
|
|
6340
|
-
email
|
|
6341
|
-
},
|
|
6342
|
-
select: [
|
|
6343
|
-
"id",
|
|
6344
|
-
"blocked",
|
|
6345
|
-
"password"
|
|
6346
|
-
]
|
|
6347
|
-
});
|
|
6348
|
-
if (!user) return json({
|
|
6349
|
-
error: "User not found"
|
|
6350
|
-
}, {
|
|
6351
|
-
status: 400
|
|
6352
|
-
});
|
|
6353
|
-
const hasPassword = !!user.password;
|
|
6354
|
-
if (!user.blocked && hasPassword) {
|
|
6355
|
-
return json({
|
|
6356
|
-
error: "User is already active"
|
|
6549
|
+
error: validation.error
|
|
6357
6550
|
}, {
|
|
6358
6551
|
status: 400
|
|
6359
6552
|
});
|
|
6360
6553
|
}
|
|
6554
|
+
const { userId, email, vendorId } = validation.target;
|
|
6361
6555
|
if (entityMap.contacts) {
|
|
6362
|
-
await linkUnclaimedContactToUser(dataSource, entityMap.contacts,
|
|
6556
|
+
await linkUnclaimedContactToUser(dataSource, entityMap.contacts, userId, email);
|
|
6363
6557
|
}
|
|
6364
|
-
if (beforeActivate) await beforeActivate(email,
|
|
6558
|
+
if (beforeActivate) await beforeActivate(email, userId);
|
|
6365
6559
|
const hashedPassword = await hashPassword(password);
|
|
6366
|
-
await
|
|
6560
|
+
await dataSource.getRepository(entityMap.users).update(userId, {
|
|
6367
6561
|
password: hashedPassword,
|
|
6368
6562
|
blocked: false
|
|
6369
6563
|
});
|
|
6564
|
+
if (vendorId != null && entityMap.vendors) {
|
|
6565
|
+
await completeVendorInviteAccept(dataSource, entityMap.vendors, vendorId);
|
|
6566
|
+
}
|
|
6370
6567
|
return json({
|
|
6371
6568
|
message: "User account activated successfully"
|
|
6372
6569
|
}, {
|
|
@@ -6382,6 +6579,35 @@ function createInviteAcceptHandler(config) {
|
|
|
6382
6579
|
}, "POST");
|
|
6383
6580
|
}
|
|
6384
6581
|
chunkUSNT2KNT_cjs.__name(createInviteAcceptHandler, "createInviteAcceptHandler");
|
|
6582
|
+
function createInviteValidateHandler(config) {
|
|
6583
|
+
const { dataSource, entityMap, json } = config;
|
|
6584
|
+
return /* @__PURE__ */ chunkUSNT2KNT_cjs.__name(async function GET(request) {
|
|
6585
|
+
try {
|
|
6586
|
+
const token = new URL(request.url).searchParams.get("token");
|
|
6587
|
+
const validation = await validateInviteTokenForActivation(dataSource, entityMap, token ?? "");
|
|
6588
|
+
if (!validation.ok) {
|
|
6589
|
+
return json({
|
|
6590
|
+
valid: false,
|
|
6591
|
+
error: validation.error
|
|
6592
|
+
}, {
|
|
6593
|
+
status: 400
|
|
6594
|
+
});
|
|
6595
|
+
}
|
|
6596
|
+
return json({
|
|
6597
|
+
valid: true
|
|
6598
|
+
});
|
|
6599
|
+
} catch (err) {
|
|
6600
|
+
console.error("[users/invite GET] validate failed", err);
|
|
6601
|
+
return json({
|
|
6602
|
+
valid: false,
|
|
6603
|
+
error: "Server Error"
|
|
6604
|
+
}, {
|
|
6605
|
+
status: 500
|
|
6606
|
+
});
|
|
6607
|
+
}
|
|
6608
|
+
}, "GET");
|
|
6609
|
+
}
|
|
6610
|
+
chunkUSNT2KNT_cjs.__name(createInviteValidateHandler, "createInviteValidateHandler");
|
|
6385
6611
|
function createChangePasswordHandler(config) {
|
|
6386
6612
|
const { dataSource, entityMap, json, comparePassword, hashPassword, getSession, minPasswordLength = 6, beforeUpdate } = config;
|
|
6387
6613
|
return /* @__PURE__ */ chunkUSNT2KNT_cjs.__name(async function POST(request) {
|
|
@@ -6460,12 +6686,22 @@ function createUserAuthApiRouter(config) {
|
|
|
6460
6686
|
const forgot = createForgotPasswordHandler(config);
|
|
6461
6687
|
const setPass = createSetPasswordHandler(config);
|
|
6462
6688
|
const invite = createInviteAcceptHandler(config);
|
|
6689
|
+
const inviteValidate = createInviteValidateHandler(config);
|
|
6463
6690
|
const changePass = config.getSession ? createChangePasswordHandler({
|
|
6464
6691
|
...config,
|
|
6465
6692
|
getSession: config.getSession,
|
|
6466
6693
|
beforeUpdate: config.beforeChangePasswordUpdate
|
|
6467
6694
|
}) : null;
|
|
6468
6695
|
return {
|
|
6696
|
+
async GET(req, pathname) {
|
|
6697
|
+
const path2 = pathname.replace(/\/$/, "");
|
|
6698
|
+
if (path2 === "invite") return inviteValidate(req);
|
|
6699
|
+
return config.json({
|
|
6700
|
+
error: "Not found"
|
|
6701
|
+
}, {
|
|
6702
|
+
status: 404
|
|
6703
|
+
});
|
|
6704
|
+
},
|
|
6469
6705
|
async POST(req, pathname) {
|
|
6470
6706
|
const path2 = pathname.replace(/\/$/, "");
|
|
6471
6707
|
if (!USER_AUTH_PATHS.includes(path2)) {
|
|
@@ -8871,13 +9107,31 @@ function createUsersApiHandlers(config) {
|
|
|
8871
9107
|
}, {
|
|
8872
9108
|
status: 404
|
|
8873
9109
|
});
|
|
8874
|
-
|
|
8875
|
-
const inviteLink = `${baseUrl}/admin/invite?token=${emailToken}`;
|
|
8876
|
-
await trySendInviteEmail(user.email, inviteLink, user.name ?? "");
|
|
9110
|
+
let inviteLink = `${baseUrl}/admin/invite?token=${Buffer.from(user.email).toString("base64")}`;
|
|
8877
9111
|
if (entityMap.vendors) {
|
|
9112
|
+
const vendorRepo = dataSource.getRepository(entityMap.vendors);
|
|
9113
|
+
const vendor = await vendorRepo.findOne({
|
|
9114
|
+
where: {
|
|
9115
|
+
userId: user.id,
|
|
9116
|
+
deleted: false
|
|
9117
|
+
}
|
|
9118
|
+
});
|
|
9119
|
+
const v = vendor;
|
|
9120
|
+
if (v && (v.inviteStatus === "pending" || v.inviteStatus === "expired")) {
|
|
9121
|
+
const rotatedMetadata = applyRotatingVendorInvite(v.metadata);
|
|
9122
|
+
await vendorRepo.update(v.id, {
|
|
9123
|
+
metadata: rotatedMetadata,
|
|
9124
|
+
inviteStatus: "pending"
|
|
9125
|
+
});
|
|
9126
|
+
const token = readVendorInviteToken(rotatedMetadata);
|
|
9127
|
+
if (token) {
|
|
9128
|
+
inviteLink = buildVendorInviteLink(baseUrl, token);
|
|
9129
|
+
}
|
|
9130
|
+
}
|
|
8878
9131
|
const { markVendorInvitePendingForUser } = await import('./vendor-invite-status-77O7ZQ3U.cjs');
|
|
8879
9132
|
await markVendorInvitePendingForUser(dataSource, entityMap.vendors, user.id);
|
|
8880
9133
|
}
|
|
9134
|
+
await trySendInviteEmail(user.email, inviteLink, user.name ?? "");
|
|
8881
9135
|
return json({
|
|
8882
9136
|
message: "New invite link generated successfully",
|
|
8883
9137
|
inviteLink
|
|
@@ -12126,6 +12380,11 @@ function createVendorOnboardHandlers(config) {
|
|
|
12126
12380
|
groupId: ownerGroup.id,
|
|
12127
12381
|
adminAccess: true
|
|
12128
12382
|
}));
|
|
12383
|
+
const baseMetadata = buildVendorMetadata(null, {
|
|
12384
|
+
ownerDesignation,
|
|
12385
|
+
termsAccepted: true
|
|
12386
|
+
});
|
|
12387
|
+
const metadata = activation === "invite" ? applyRotatingVendorInvite(baseMetadata) : baseMetadata;
|
|
12129
12388
|
const vendor = await vendorRepo.save(vendorRepo.create({
|
|
12130
12389
|
name: vendorName,
|
|
12131
12390
|
slug,
|
|
@@ -12145,10 +12404,7 @@ function createVendorOnboardHandlers(config) {
|
|
|
12145
12404
|
gstin: profile.gstin,
|
|
12146
12405
|
pan: profile.pan,
|
|
12147
12406
|
registrationStatus: profile.registrationStatus,
|
|
12148
|
-
metadata
|
|
12149
|
-
ownerDesignation,
|
|
12150
|
-
termsAccepted: true
|
|
12151
|
-
}),
|
|
12407
|
+
metadata,
|
|
12152
12408
|
active: body.vendor?.active !== false,
|
|
12153
12409
|
deleted: false,
|
|
12154
12410
|
userId: newUser.id,
|
|
@@ -12198,8 +12454,10 @@ function createVendorOnboardHandlers(config) {
|
|
|
12198
12454
|
let inviteLink;
|
|
12199
12455
|
let emailSent = false;
|
|
12200
12456
|
if (activation === "invite") {
|
|
12201
|
-
const
|
|
12202
|
-
|
|
12457
|
+
const token = readVendorInviteToken(result.vendor.metadata);
|
|
12458
|
+
if (token) {
|
|
12459
|
+
inviteLink = buildVendorInviteLink(baseUrl, token);
|
|
12460
|
+
}
|
|
12203
12461
|
}
|
|
12204
12462
|
if (sendOwnerEmail) {
|
|
12205
12463
|
emailSent = await trySendVendorOnboardEmails({
|
|
@@ -12241,6 +12499,130 @@ function createVendorOnboardHandlers(config) {
|
|
|
12241
12499
|
return vendorOnboardErrorResponse(json, e);
|
|
12242
12500
|
}
|
|
12243
12501
|
},
|
|
12502
|
+
/** POST /api/admin/vendors/:id/resend-invite — rotate owner invite token and resend email */
|
|
12503
|
+
async resendInvite(req, vendorIdStr) {
|
|
12504
|
+
const err = await gateAdmin();
|
|
12505
|
+
if (err) return err;
|
|
12506
|
+
if (!entityMap.vendors || !entityMap.users) {
|
|
12507
|
+
return json({
|
|
12508
|
+
error: "Vendor entities not configured"
|
|
12509
|
+
}, {
|
|
12510
|
+
status: 500
|
|
12511
|
+
});
|
|
12512
|
+
}
|
|
12513
|
+
const vendorId = Number(vendorIdStr);
|
|
12514
|
+
if (!Number.isFinite(vendorId) || vendorId <= 0) {
|
|
12515
|
+
return json({
|
|
12516
|
+
error: "Invalid vendor id"
|
|
12517
|
+
}, {
|
|
12518
|
+
status: 400
|
|
12519
|
+
});
|
|
12520
|
+
}
|
|
12521
|
+
let sendEmail = true;
|
|
12522
|
+
try {
|
|
12523
|
+
const body = await req.json().catch(() => ({}));
|
|
12524
|
+
if (body.sendEmail === false) sendEmail = false;
|
|
12525
|
+
} catch {
|
|
12526
|
+
}
|
|
12527
|
+
try {
|
|
12528
|
+
const vendorRepo = dataSource.getRepository(entityMap.vendors);
|
|
12529
|
+
const vendor = await vendorRepo.findOne({
|
|
12530
|
+
where: {
|
|
12531
|
+
id: vendorId,
|
|
12532
|
+
deleted: false
|
|
12533
|
+
}
|
|
12534
|
+
});
|
|
12535
|
+
if (!vendor) return json({
|
|
12536
|
+
error: "Vendor not found"
|
|
12537
|
+
}, {
|
|
12538
|
+
status: 404
|
|
12539
|
+
});
|
|
12540
|
+
const v = vendor;
|
|
12541
|
+
if (v.inviteStatus === "accepted") {
|
|
12542
|
+
return json({
|
|
12543
|
+
error: "Owner has already accepted the invite"
|
|
12544
|
+
}, {
|
|
12545
|
+
status: 400
|
|
12546
|
+
});
|
|
12547
|
+
}
|
|
12548
|
+
if (v.inviteStatus === "none") {
|
|
12549
|
+
return json({
|
|
12550
|
+
error: "This vendor was not created with an invite link"
|
|
12551
|
+
}, {
|
|
12552
|
+
status: 400
|
|
12553
|
+
});
|
|
12554
|
+
}
|
|
12555
|
+
if (v.inviteStatus !== "pending" && v.inviteStatus !== "expired") {
|
|
12556
|
+
return json({
|
|
12557
|
+
error: "Invite cannot be resent for this vendor"
|
|
12558
|
+
}, {
|
|
12559
|
+
status: 400
|
|
12560
|
+
});
|
|
12561
|
+
}
|
|
12562
|
+
if (!v.userId) {
|
|
12563
|
+
return json({
|
|
12564
|
+
error: "Vendor has no owner user linked"
|
|
12565
|
+
}, {
|
|
12566
|
+
status: 400
|
|
12567
|
+
});
|
|
12568
|
+
}
|
|
12569
|
+
const userRepo = dataSource.getRepository(entityMap.users);
|
|
12570
|
+
const owner = await userRepo.findOne({
|
|
12571
|
+
where: {
|
|
12572
|
+
id: v.userId,
|
|
12573
|
+
deleted: false
|
|
12574
|
+
}
|
|
12575
|
+
});
|
|
12576
|
+
if (!owner) return json({
|
|
12577
|
+
error: "Owner user not found"
|
|
12578
|
+
}, {
|
|
12579
|
+
status: 404
|
|
12580
|
+
});
|
|
12581
|
+
const ownerRow = owner;
|
|
12582
|
+
const hasPassword = !!(ownerRow.password && String(ownerRow.password).trim());
|
|
12583
|
+
if (!ownerRow.blocked && hasPassword) {
|
|
12584
|
+
return json({
|
|
12585
|
+
error: "Owner account is already active"
|
|
12586
|
+
}, {
|
|
12587
|
+
status: 400
|
|
12588
|
+
});
|
|
12589
|
+
}
|
|
12590
|
+
const rotatedMetadata = applyRotatingVendorInvite(v.metadata);
|
|
12591
|
+
await vendorRepo.update(vendorId, {
|
|
12592
|
+
metadata: rotatedMetadata,
|
|
12593
|
+
inviteStatus: "pending"
|
|
12594
|
+
});
|
|
12595
|
+
const token = readVendorInviteToken(rotatedMetadata);
|
|
12596
|
+
if (!token) {
|
|
12597
|
+
return json({
|
|
12598
|
+
error: "Failed to generate invite token"
|
|
12599
|
+
}, {
|
|
12600
|
+
status: 500
|
|
12601
|
+
});
|
|
12602
|
+
}
|
|
12603
|
+
const inviteLink = buildVendorInviteLink(baseUrl, token);
|
|
12604
|
+
let emailSent = false;
|
|
12605
|
+
if (sendEmail) {
|
|
12606
|
+
emailSent = await trySendVendorOnboardEmails({
|
|
12607
|
+
vendorName: v.name,
|
|
12608
|
+
vendorSlug: v.slug,
|
|
12609
|
+
ownerName: ownerRow.name,
|
|
12610
|
+
ownerEmail: ownerRow.email,
|
|
12611
|
+
activation: "invite",
|
|
12612
|
+
inviteLink,
|
|
12613
|
+
sendToOwner: true
|
|
12614
|
+
});
|
|
12615
|
+
}
|
|
12616
|
+
return json({
|
|
12617
|
+
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.",
|
|
12618
|
+
emailSent,
|
|
12619
|
+
inviteLink,
|
|
12620
|
+
inviteStatus: "pending"
|
|
12621
|
+
});
|
|
12622
|
+
} catch (e) {
|
|
12623
|
+
return vendorOnboardErrorResponse(json, e);
|
|
12624
|
+
}
|
|
12625
|
+
},
|
|
12244
12626
|
/** POST /api/admin/vendor/switch — set active vendor in session (JWT update via client) */
|
|
12245
12627
|
async switchVendor(req) {
|
|
12246
12628
|
const u = await getSessionUser();
|
|
@@ -25602,6 +25984,14 @@ function createCmsApiHandler(config) {
|
|
|
25602
25984
|
});
|
|
25603
25985
|
return vendorHandlers.onboard(req);
|
|
25604
25986
|
}
|
|
25987
|
+
if (path2[0] === "admin" && path2[1] === "vendors" && path2.length === 4 && path2[3] === "resend-invite" && m === "POST") {
|
|
25988
|
+
if (!vendorHandlers) return config.json({
|
|
25989
|
+
error: "Not found"
|
|
25990
|
+
}, {
|
|
25991
|
+
status: 404
|
|
25992
|
+
});
|
|
25993
|
+
return vendorHandlers.resendInvite(req, path2[2]);
|
|
25994
|
+
}
|
|
25605
25995
|
if (path2[0] === "admin" && path2[1] === "vendor" && path2[2] === "switch" && path2.length === 3 && m === "POST") {
|
|
25606
25996
|
if (!vendorHandlers) return config.json({
|
|
25607
25997
|
error: "Not found"
|
|
@@ -26193,6 +26583,15 @@ function createCmsApiHandler(config) {
|
|
|
26193
26583
|
if (m === "PUT" || m === "PATCH") return formSaveHandlers.PUT(req, path2[1]);
|
|
26194
26584
|
}
|
|
26195
26585
|
}
|
|
26586
|
+
if (path2[0] === "users" && path2.length === 2 && userAuthRouter) {
|
|
26587
|
+
const authSegment = path2[1];
|
|
26588
|
+
if (m === "GET" && authSegment === "invite" && userAuthRouter.GET) {
|
|
26589
|
+
return userAuthRouter.GET(req, authSegment);
|
|
26590
|
+
}
|
|
26591
|
+
if (m === "POST" && (authSegment === "invite" || authSegment === "forgot-password" || authSegment === "set-password" || authSegment === "reset-password")) {
|
|
26592
|
+
return userAuthRouter.POST(req, authSegment);
|
|
26593
|
+
}
|
|
26594
|
+
}
|
|
26196
26595
|
if (path2[0] === "users" && usersHandlers) {
|
|
26197
26596
|
if (path2.length === 1) {
|
|
26198
26597
|
if (m === "GET") return usersHandlers.list(req);
|
|
@@ -26213,9 +26612,6 @@ function createCmsApiHandler(config) {
|
|
|
26213
26612
|
return usersHandlers.regenerateInvite(req, path2[1]);
|
|
26214
26613
|
}
|
|
26215
26614
|
}
|
|
26216
|
-
if (path2[0] === "users" && path2.length === 2 && userAuthRouter && m === "POST") {
|
|
26217
|
-
return userAuthRouter.POST(req, path2[1]);
|
|
26218
|
-
}
|
|
26219
26615
|
if (path2[0] === "social-media" && path2[1] === "linkedin" && socialMediaHandlers && path2.length === 3) {
|
|
26220
26616
|
const tail = path2[2];
|
|
26221
26617
|
if (tail === "status" && m === "GET") {
|
|
@@ -30610,12 +31006,14 @@ exports.BLOG_METADATA_ENRICHER_LLM_AGENT_SLUG = BLOG_METADATA_ENRICHER_LLM_AGENT
|
|
|
30610
31006
|
exports.BlogGeneratorService = BlogGeneratorService;
|
|
30611
31007
|
exports.CMS_ENTITY_MAP = CMS_ENTITY_MAP;
|
|
30612
31008
|
exports.ZIP_MIME_TYPES = ZIP_MIME_TYPES;
|
|
31009
|
+
exports.applyRotatingVendorInvite = applyRotatingVendorInvite;
|
|
30613
31010
|
exports.applyVendorCustomersContactFilter = applyVendorCustomersContactFilter;
|
|
30614
31011
|
exports.assertCaptchaOk = assertCaptchaOk;
|
|
30615
31012
|
exports.assertContactAllowedForVendorOrder = assertContactAllowedForVendorOrder;
|
|
30616
31013
|
exports.buildBlogMetadataUserPrompt = buildBlogMetadataUserPrompt;
|
|
30617
31014
|
exports.buildCronFromSchedule = buildCronFromSchedule;
|
|
30618
31015
|
exports.buildRssUserPromptFromFeeds = buildRssUserPromptFromFeeds;
|
|
31016
|
+
exports.buildVendorInviteLink = buildVendorInviteLink;
|
|
30619
31017
|
exports.calculateOrderRefundPreview = calculateOrderRefundPreview;
|
|
30620
31018
|
exports.calculateRefundFromPolicy = calculateRefundFromPolicy;
|
|
30621
31019
|
exports.checkEventsEnabled = checkEventsEnabled;
|
|
@@ -30660,6 +31058,7 @@ exports.ensureMessagingPluginsOnCms = ensureMessagingPluginsOnCms;
|
|
|
30660
31058
|
exports.ensureScheduleQueueWorker = ensureScheduleQueueWorker;
|
|
30661
31059
|
exports.ensureVendorCustomerForOrderContact = ensureVendorCustomerForOrderContact;
|
|
30662
31060
|
exports.findActiveRefundPolicyForVendor = findActiveRefundPolicyForVendor;
|
|
31061
|
+
exports.findVendorByInviteToken = findVendorByInviteToken;
|
|
30663
31062
|
exports.formatTierRange = formatTierRange;
|
|
30664
31063
|
exports.generateNumericOtp = generateNumericOtp;
|
|
30665
31064
|
exports.getPublicSettingsGroup = getPublicSettingsGroup;
|
package/dist/cli.cjs
CHANGED
|
@@ -321,7 +321,7 @@ const cmsMiddleware = createCmsMiddleware({
|
|
|
321
321
|
'/api/auth': ['GET', 'POST'],
|
|
322
322
|
'/api/users/forgot-password': ['POST'],
|
|
323
323
|
'/api/users/set-password': ['POST'],
|
|
324
|
-
'/api/users/invite': ['POST'],
|
|
324
|
+
'/api/users/invite': ['GET', 'POST'],
|
|
325
325
|
},
|
|
326
326
|
});
|
|
327
327
|
|
package/dist/cli.js
CHANGED
|
@@ -314,7 +314,7 @@ const cmsMiddleware = createCmsMiddleware({
|
|
|
314
314
|
'/api/auth': ['GET', 'POST'],
|
|
315
315
|
'/api/users/forgot-password': ['POST'],
|
|
316
316
|
'/api/users/set-password': ['POST'],
|
|
317
|
-
'/api/users/invite': ['POST'],
|
|
317
|
+
'/api/users/invite': ['GET', 'POST'],
|
|
318
318
|
},
|
|
319
319
|
});
|
|
320
320
|
|