@infuro/cms-core 1.0.23 → 1.0.24
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 +2595 -1681
- package/dist/admin.cjs.map +1 -1
- package/dist/admin.d.cts +29 -7
- package/dist/admin.d.ts +29 -7
- package/dist/admin.js +2585 -1668
- package/dist/admin.js.map +1 -1
- package/dist/api.cjs +183 -18
- package/dist/api.cjs.map +1 -1
- package/dist/api.js +183 -18
- package/dist/api.js.map +1 -1
- package/dist/index.cjs +185 -18
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +185 -18
- package/dist/index.js.map +1 -1
- package/package.json +130 -129
package/dist/index.cjs
CHANGED
|
@@ -4160,11 +4160,11 @@ async function readBufferFromPublicUrl(url) {
|
|
|
4160
4160
|
throw new Error("Unsupported media URL");
|
|
4161
4161
|
}
|
|
4162
4162
|
function sanitizeZipPath(entryName) {
|
|
4163
|
-
const
|
|
4164
|
-
for (const seg of
|
|
4163
|
+
const norm3 = entryName.replace(/\\/g, "/").split("/").filter(Boolean);
|
|
4164
|
+
for (const seg of norm3) {
|
|
4165
4165
|
if (seg === ".." || seg === ".") return null;
|
|
4166
4166
|
}
|
|
4167
|
-
return
|
|
4167
|
+
return norm3;
|
|
4168
4168
|
}
|
|
4169
4169
|
function shouldSkipEntry(parts) {
|
|
4170
4170
|
if (parts[0] === "__MACOSX") return true;
|
|
@@ -8716,6 +8716,66 @@ function getNextAuthOptions(config) {
|
|
|
8716
8716
|
|
|
8717
8717
|
// src/api/crud.ts
|
|
8718
8718
|
var import_typeorm46 = require("typeorm");
|
|
8719
|
+
|
|
8720
|
+
// src/lib/address-geo-validation.ts
|
|
8721
|
+
var import_country_state_city = require("country-state-city");
|
|
8722
|
+
function norm2(s) {
|
|
8723
|
+
return typeof s === "string" ? s.trim() : "";
|
|
8724
|
+
}
|
|
8725
|
+
function resolveCountry(input) {
|
|
8726
|
+
const t = input.trim();
|
|
8727
|
+
if (!t) return void 0;
|
|
8728
|
+
if (t.length === 2) {
|
|
8729
|
+
const byCode = import_country_state_city.Country.getCountryByCode(t.toUpperCase());
|
|
8730
|
+
if (byCode) return byCode;
|
|
8731
|
+
}
|
|
8732
|
+
const lower = t.toLowerCase();
|
|
8733
|
+
return import_country_state_city.Country.getAllCountries().find((c) => c.name.toLowerCase() === lower);
|
|
8734
|
+
}
|
|
8735
|
+
function resolveState(countryIso, input) {
|
|
8736
|
+
const t = input.trim();
|
|
8737
|
+
if (!t || !countryIso) return void 0;
|
|
8738
|
+
const states = import_country_state_city.State.getStatesOfCountry(countryIso);
|
|
8739
|
+
const lower = t.toLowerCase();
|
|
8740
|
+
return states.find((s) => s.isoCode.toLowerCase() === t.toLowerCase() || s.name.toLowerCase() === lower);
|
|
8741
|
+
}
|
|
8742
|
+
function resolveCity(countryIso, stateIso, input) {
|
|
8743
|
+
const t = input.trim();
|
|
8744
|
+
if (!t || !countryIso || !stateIso) return void 0;
|
|
8745
|
+
const lower = t.toLowerCase();
|
|
8746
|
+
const cities = import_country_state_city.City.getCitiesOfState(countryIso, stateIso);
|
|
8747
|
+
return cities.find((c) => c.name.toLowerCase() === lower);
|
|
8748
|
+
}
|
|
8749
|
+
function assertValidAddressHierarchy(country, state, city) {
|
|
8750
|
+
const c = resolveCountry(country);
|
|
8751
|
+
if (!c) return { ok: false, error: "Invalid or unknown country." };
|
|
8752
|
+
const st = resolveState(c.isoCode, state);
|
|
8753
|
+
if (!st) return { ok: false, error: "State or province does not match the selected country." };
|
|
8754
|
+
const ct = resolveCity(c.isoCode, st.isoCode, city);
|
|
8755
|
+
if (!ct) return { ok: false, error: "City does not match the selected state." };
|
|
8756
|
+
return { ok: true, country: c.name, state: st.name, city: ct.name };
|
|
8757
|
+
}
|
|
8758
|
+
function validateAndNormalizeAddressRow(row) {
|
|
8759
|
+
const line1 = norm2(row.line1);
|
|
8760
|
+
const postalCode = norm2(row.postalCode);
|
|
8761
|
+
const countryIn = norm2(row.country);
|
|
8762
|
+
const stateIn = norm2(row.state);
|
|
8763
|
+
const cityIn = norm2(row.city);
|
|
8764
|
+
if (!line1) return "Street address (line 1) is required.";
|
|
8765
|
+
if (!postalCode) return "Postal code is required.";
|
|
8766
|
+
if (!countryIn || !stateIn || !cityIn) return "Country, state, and city are required.";
|
|
8767
|
+
const geo = assertValidAddressHierarchy(countryIn, stateIn, cityIn);
|
|
8768
|
+
if (!geo.ok) return geo.error;
|
|
8769
|
+
row.line1 = line1;
|
|
8770
|
+
row.line2 = norm2(row.line2) || null;
|
|
8771
|
+
row.postalCode = postalCode;
|
|
8772
|
+
row.country = geo.country;
|
|
8773
|
+
row.state = geo.state;
|
|
8774
|
+
row.city = geo.city;
|
|
8775
|
+
return null;
|
|
8776
|
+
}
|
|
8777
|
+
|
|
8778
|
+
// src/api/crud.ts
|
|
8719
8779
|
var CRUD_LOG = "[cms-crud]";
|
|
8720
8780
|
function logCrudClientError(op, detail) {
|
|
8721
8781
|
console.warn(CRUD_LOG, op, detail);
|
|
@@ -8985,6 +9045,17 @@ function createCrudHandler(dataSource, entityMap, options) {
|
|
|
8985
9045
|
if (statusFilter) productWhere.status = statusFilter;
|
|
8986
9046
|
if (inventory === "in_stock") productWhere.quantity = (0, import_typeorm46.MoreThan)(0);
|
|
8987
9047
|
if (inventory === "out_of_stock") productWhere.quantity = 0;
|
|
9048
|
+
for (const key of ["brandId", "categoryId", "collectionId"]) {
|
|
9049
|
+
const raw = searchParams.get(key)?.trim();
|
|
9050
|
+
if (raw) {
|
|
9051
|
+
const n = Number(raw);
|
|
9052
|
+
if (Number.isFinite(n)) productWhere[key] = n;
|
|
9053
|
+
}
|
|
9054
|
+
}
|
|
9055
|
+
const featuredRaw = searchParams.get("featured")?.trim();
|
|
9056
|
+
if (featuredRaw === "true" || featuredRaw === "false") {
|
|
9057
|
+
productWhere.featured = featuredRaw === "true";
|
|
9058
|
+
}
|
|
8988
9059
|
if (search && typeof search === "string" && search.trim()) {
|
|
8989
9060
|
productWhere.name = (0, import_typeorm46.ILike)(`%${search.trim()}%`);
|
|
8990
9061
|
}
|
|
@@ -9090,7 +9161,7 @@ function createCrudHandler(dataSource, entityMap, options) {
|
|
|
9090
9161
|
if (search) {
|
|
9091
9162
|
where = buildSearchWhereClause(repo, search);
|
|
9092
9163
|
}
|
|
9093
|
-
const intFilterKeys = ["productId", "attributeId", "taxId"];
|
|
9164
|
+
const intFilterKeys = ["productId", "attributeId", "taxId", "brandId", "categoryId", "collectionId", "parentId"];
|
|
9094
9165
|
const extraWhere = {};
|
|
9095
9166
|
for (const key of intFilterKeys) {
|
|
9096
9167
|
const v = searchParams.get(key);
|
|
@@ -9099,6 +9170,15 @@ function createCrudHandler(dataSource, entityMap, options) {
|
|
|
9099
9170
|
if (Number.isFinite(n)) extraWhere[key] = n;
|
|
9100
9171
|
}
|
|
9101
9172
|
}
|
|
9173
|
+
for (const col of repo.metadata.columns) {
|
|
9174
|
+
if (String(col.type) !== "boolean") continue;
|
|
9175
|
+
const name = col.propertyName;
|
|
9176
|
+
if (!columnNames.has(name)) continue;
|
|
9177
|
+
const raw = searchParams.get(name)?.trim();
|
|
9178
|
+
if (raw === "true" || raw === "false") {
|
|
9179
|
+
extraWhere[name] = raw === "true";
|
|
9180
|
+
}
|
|
9181
|
+
}
|
|
9102
9182
|
if (Object.keys(extraWhere).length > 0) {
|
|
9103
9183
|
if (Array.isArray(where)) {
|
|
9104
9184
|
where = where.map((w) => ({ ...w, ...extraWhere }));
|
|
@@ -9207,6 +9287,17 @@ function createCrudHandler(dataSource, entityMap, options) {
|
|
|
9207
9287
|
}
|
|
9208
9288
|
}
|
|
9209
9289
|
}
|
|
9290
|
+
if (resource === "addresses") {
|
|
9291
|
+
const cid = Number(persistBody.contactId);
|
|
9292
|
+
if (!Number.isFinite(cid)) {
|
|
9293
|
+
return json({ error: "Valid contactId is required." }, { status: 400 });
|
|
9294
|
+
}
|
|
9295
|
+
if (persistBody.tag === "") persistBody.tag = null;
|
|
9296
|
+
const addrErr = validateAndNormalizeAddressRow(persistBody);
|
|
9297
|
+
if (addrErr) {
|
|
9298
|
+
return json({ error: addrErr }, { status: 400 });
|
|
9299
|
+
}
|
|
9300
|
+
}
|
|
9210
9301
|
sanitizeBodyForEntity(repo, persistBody);
|
|
9211
9302
|
let created;
|
|
9212
9303
|
try {
|
|
@@ -9526,8 +9617,54 @@ function createCrudByIdHandler(dataSource, entityMap, options) {
|
|
|
9526
9617
|
const updatePayload = rawBody && typeof rawBody === "object" ? pickColumnUpdates(repo, rawBody) : {};
|
|
9527
9618
|
if (resource === "media") {
|
|
9528
9619
|
const u = updatePayload;
|
|
9529
|
-
delete u.parentId;
|
|
9530
9620
|
delete u.kind;
|
|
9621
|
+
if (rawBody && typeof rawBody === "object" && "parentId" in rawBody) {
|
|
9622
|
+
let pid = null;
|
|
9623
|
+
const p = rawBody.parentId;
|
|
9624
|
+
if (p != null && p !== "") {
|
|
9625
|
+
const n = Number(p);
|
|
9626
|
+
if (!Number.isFinite(n)) {
|
|
9627
|
+
return json({ error: "Invalid parentId" }, { status: 400 });
|
|
9628
|
+
}
|
|
9629
|
+
pid = n;
|
|
9630
|
+
}
|
|
9631
|
+
if (pid != null) {
|
|
9632
|
+
const parent = await repo.findOne({
|
|
9633
|
+
where: { id: pid, deleted: false }
|
|
9634
|
+
});
|
|
9635
|
+
if (!parent || parent.kind !== "folder") {
|
|
9636
|
+
return json({ error: "parent must be a folder" }, { status: 400 });
|
|
9637
|
+
}
|
|
9638
|
+
}
|
|
9639
|
+
const row = await repo.findOne({
|
|
9640
|
+
where: { id: numericId, deleted: false }
|
|
9641
|
+
});
|
|
9642
|
+
if (!row) return json({ message: "Not found" }, { status: 404 });
|
|
9643
|
+
if (pid === numericId) {
|
|
9644
|
+
return json({ error: "Invalid parentId" }, { status: 400 });
|
|
9645
|
+
}
|
|
9646
|
+
if (row.kind === "folder" && pid != null) {
|
|
9647
|
+
let walk = pid;
|
|
9648
|
+
const seen = /* @__PURE__ */ new Set();
|
|
9649
|
+
while (walk != null) {
|
|
9650
|
+
if (walk === numericId) {
|
|
9651
|
+
return json(
|
|
9652
|
+
{ error: "Cannot move a folder into itself or a descendant folder" },
|
|
9653
|
+
{ status: 400 }
|
|
9654
|
+
);
|
|
9655
|
+
}
|
|
9656
|
+
if (seen.has(walk)) break;
|
|
9657
|
+
seen.add(walk);
|
|
9658
|
+
const anc = await repo.findOne({
|
|
9659
|
+
where: { id: walk, deleted: false }
|
|
9660
|
+
});
|
|
9661
|
+
walk = anc ? anc.parentId ?? null : null;
|
|
9662
|
+
}
|
|
9663
|
+
}
|
|
9664
|
+
u.parentId = pid;
|
|
9665
|
+
} else {
|
|
9666
|
+
delete u.parentId;
|
|
9667
|
+
}
|
|
9531
9668
|
}
|
|
9532
9669
|
if (resource === "products") {
|
|
9533
9670
|
const currentRow = await repo.findOne({
|
|
@@ -9546,6 +9683,26 @@ function createCrudByIdHandler(dataSource, entityMap, options) {
|
|
|
9546
9683
|
updatePayload.sku = effSku;
|
|
9547
9684
|
}
|
|
9548
9685
|
}
|
|
9686
|
+
if (resource === "addresses" && Object.keys(updatePayload).length > 0) {
|
|
9687
|
+
const currentRow = await repo.findOne({
|
|
9688
|
+
where: { id: numericId }
|
|
9689
|
+
});
|
|
9690
|
+
if (!currentRow) return json({ message: "Not found" }, { status: 404 });
|
|
9691
|
+
const merged = {
|
|
9692
|
+
...currentRow,
|
|
9693
|
+
...updatePayload
|
|
9694
|
+
};
|
|
9695
|
+
if (merged.tag === "") merged.tag = null;
|
|
9696
|
+
const addrErr = validateAndNormalizeAddressRow(merged);
|
|
9697
|
+
if (addrErr) {
|
|
9698
|
+
return json({ error: addrErr }, { status: 400 });
|
|
9699
|
+
}
|
|
9700
|
+
for (const k of Object.keys(updatePayload)) {
|
|
9701
|
+
if (k in merged) {
|
|
9702
|
+
updatePayload[k] = merged[k];
|
|
9703
|
+
}
|
|
9704
|
+
}
|
|
9705
|
+
}
|
|
9549
9706
|
if (Object.keys(updatePayload).length > 0) {
|
|
9550
9707
|
sanitizeBodyForEntity(repo, updatePayload);
|
|
9551
9708
|
await repo.update(numericId, updatePayload);
|
|
@@ -11547,18 +11704,19 @@ function createStorefrontApiHandler(config) {
|
|
|
11547
11704
|
const contactOrErr = await getContactForAddresses();
|
|
11548
11705
|
if (contactOrErr instanceof Response) return contactOrErr;
|
|
11549
11706
|
const b = await req.json().catch(() => ({}));
|
|
11550
|
-
const
|
|
11551
|
-
|
|
11552
|
-
|
|
11553
|
-
|
|
11554
|
-
|
|
11555
|
-
|
|
11556
|
-
|
|
11557
|
-
|
|
11558
|
-
|
|
11559
|
-
|
|
11560
|
-
|
|
11561
|
-
);
|
|
11707
|
+
const row = {
|
|
11708
|
+
contactId: contactOrErr.contactId,
|
|
11709
|
+
tag: typeof b.tag === "string" ? b.tag.trim() || null : null,
|
|
11710
|
+
line1: typeof b.line1 === "string" ? b.line1 : "",
|
|
11711
|
+
line2: typeof b.line2 === "string" ? b.line2.trim() || null : null,
|
|
11712
|
+
city: typeof b.city === "string" ? b.city : "",
|
|
11713
|
+
state: typeof b.state === "string" ? b.state : "",
|
|
11714
|
+
postalCode: typeof b.postalCode === "string" ? b.postalCode : "",
|
|
11715
|
+
country: typeof b.country === "string" ? b.country : ""
|
|
11716
|
+
};
|
|
11717
|
+
const addrErr = validateAndNormalizeAddressRow(row);
|
|
11718
|
+
if (addrErr) return json({ error: addrErr }, { status: 400 });
|
|
11719
|
+
const created = await addressRepo().save(addressRepo().create(row));
|
|
11562
11720
|
return json(serializeAddress2(created));
|
|
11563
11721
|
}
|
|
11564
11722
|
if (path[0] === "addresses" && path.length === 2 && (method === "PATCH" || method === "PUT")) {
|
|
@@ -11577,7 +11735,16 @@ function createStorefrontApiHandler(config) {
|
|
|
11577
11735
|
if (b.state !== void 0) updates.state = typeof b.state === "string" ? b.state.trim() || null : null;
|
|
11578
11736
|
if (b.postalCode !== void 0) updates.postalCode = typeof b.postalCode === "string" ? b.postalCode.trim() || null : null;
|
|
11579
11737
|
if (b.country !== void 0) updates.country = typeof b.country === "string" ? b.country.trim() || null : null;
|
|
11580
|
-
if (Object.keys(updates).length)
|
|
11738
|
+
if (Object.keys(updates).length) {
|
|
11739
|
+
const merged = { ...existing, ...updates };
|
|
11740
|
+
if (merged.tag === "") merged.tag = null;
|
|
11741
|
+
const addrErr = validateAndNormalizeAddressRow(merged);
|
|
11742
|
+
if (addrErr) return json({ error: addrErr }, { status: 400 });
|
|
11743
|
+
for (const k of Object.keys(updates)) {
|
|
11744
|
+
if (k in merged) updates[k] = merged[k];
|
|
11745
|
+
}
|
|
11746
|
+
await addressRepo().update(id, updates);
|
|
11747
|
+
}
|
|
11581
11748
|
const updated = await addressRepo().findOne({ where: { id } });
|
|
11582
11749
|
return json(serializeAddress2(updated));
|
|
11583
11750
|
}
|