@open-mercato/shared 0.4.2-canary-c02407ff85
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/build.mjs +101 -0
- package/dist/index.js +1 -0
- package/dist/index.js.map +7 -0
- package/dist/lib/api/crud.js +47 -0
- package/dist/lib/api/crud.js.map +7 -0
- package/dist/lib/api/scoped.js +140 -0
- package/dist/lib/api/scoped.js.map +7 -0
- package/dist/lib/auth/jwt.js +34 -0
- package/dist/lib/auth/jwt.js.map +7 -0
- package/dist/lib/auth/server.js +157 -0
- package/dist/lib/auth/server.js.map +7 -0
- package/dist/lib/boolean.js +22 -0
- package/dist/lib/boolean.js.map +7 -0
- package/dist/lib/bootstrap/appResolver.js +43 -0
- package/dist/lib/bootstrap/appResolver.js.map +7 -0
- package/dist/lib/bootstrap/dynamicLoader.js +108 -0
- package/dist/lib/bootstrap/dynamicLoader.js.map +7 -0
- package/dist/lib/bootstrap/factory.js +59 -0
- package/dist/lib/bootstrap/factory.js.map +7 -0
- package/dist/lib/bootstrap/index.js +11 -0
- package/dist/lib/bootstrap/index.js.map +7 -0
- package/dist/lib/bootstrap/types.js +1 -0
- package/dist/lib/bootstrap/types.js.map +7 -0
- package/dist/lib/cache/segments.js +36 -0
- package/dist/lib/cache/segments.js.map +7 -0
- package/dist/lib/cli/progress.js +46 -0
- package/dist/lib/cli/progress.js.map +7 -0
- package/dist/lib/commands/command-bus.js +285 -0
- package/dist/lib/commands/command-bus.js.map +7 -0
- package/dist/lib/commands/customFieldSnapshots.js +66 -0
- package/dist/lib/commands/customFieldSnapshots.js.map +7 -0
- package/dist/lib/commands/helpers.js +98 -0
- package/dist/lib/commands/helpers.js.map +7 -0
- package/dist/lib/commands/index.js +8 -0
- package/dist/lib/commands/index.js.map +7 -0
- package/dist/lib/commands/operationMetadata.js +32 -0
- package/dist/lib/commands/operationMetadata.js.map +7 -0
- package/dist/lib/commands/registry.js +43 -0
- package/dist/lib/commands/registry.js.map +7 -0
- package/dist/lib/commands/scope.js +44 -0
- package/dist/lib/commands/scope.js.map +7 -0
- package/dist/lib/commands/types.js +8 -0
- package/dist/lib/commands/types.js.map +7 -0
- package/dist/lib/crud/cache-stats.js +98 -0
- package/dist/lib/crud/cache-stats.js.map +7 -0
- package/dist/lib/crud/cache.js +175 -0
- package/dist/lib/crud/cache.js.map +7 -0
- package/dist/lib/crud/custom-fields-client.js +52 -0
- package/dist/lib/crud/custom-fields-client.js.map +7 -0
- package/dist/lib/crud/custom-fields.js +467 -0
- package/dist/lib/crud/custom-fields.js.map +7 -0
- package/dist/lib/crud/errors.js +24 -0
- package/dist/lib/crud/errors.js.map +7 -0
- package/dist/lib/crud/exporters.js +154 -0
- package/dist/lib/crud/exporters.js.map +7 -0
- package/dist/lib/crud/factory.js +1311 -0
- package/dist/lib/crud/factory.js.map +7 -0
- package/dist/lib/crud/types.js +1 -0
- package/dist/lib/crud/types.js.map +7 -0
- package/dist/lib/custom-fields/normalize.js +36 -0
- package/dist/lib/custom-fields/normalize.js.map +7 -0
- package/dist/lib/data/engine.js +396 -0
- package/dist/lib/data/engine.js.map +7 -0
- package/dist/lib/db/escapeLikePattern.js +5 -0
- package/dist/lib/db/escapeLikePattern.js.map +7 -0
- package/dist/lib/db/mikro.js +82 -0
- package/dist/lib/db/mikro.js.map +7 -0
- package/dist/lib/di/container.js +94 -0
- package/dist/lib/di/container.js.map +7 -0
- package/dist/lib/email/send.js +12 -0
- package/dist/lib/email/send.js.map +7 -0
- package/dist/lib/encryption/aes.js +58 -0
- package/dist/lib/encryption/aes.js.map +7 -0
- package/dist/lib/encryption/customFieldValues.js +49 -0
- package/dist/lib/encryption/customFieldValues.js.map +7 -0
- package/dist/lib/encryption/entityFields.js +26 -0
- package/dist/lib/encryption/entityFields.js.map +7 -0
- package/dist/lib/encryption/entityIds.js +80 -0
- package/dist/lib/encryption/entityIds.js.map +7 -0
- package/dist/lib/encryption/find.js +45 -0
- package/dist/lib/encryption/find.js.map +7 -0
- package/dist/lib/encryption/indexDoc.js +69 -0
- package/dist/lib/encryption/indexDoc.js.map +7 -0
- package/dist/lib/encryption/kms.js +282 -0
- package/dist/lib/encryption/kms.js.map +7 -0
- package/dist/lib/encryption/subscriber.js +330 -0
- package/dist/lib/encryption/subscriber.js.map +7 -0
- package/dist/lib/encryption/tenantDataEncryptionService.js +252 -0
- package/dist/lib/encryption/tenantDataEncryptionService.js.map +7 -0
- package/dist/lib/encryption/toggles.js +18 -0
- package/dist/lib/encryption/toggles.js.map +7 -0
- package/dist/lib/entities/naming.js +9 -0
- package/dist/lib/entities/naming.js.map +7 -0
- package/dist/lib/entities/system-entities.js +43 -0
- package/dist/lib/entities/system-entities.js.map +7 -0
- package/dist/lib/frontend/organizationEvents.js +41 -0
- package/dist/lib/frontend/organizationEvents.js.map +7 -0
- package/dist/lib/frontend/useOrganizationScope.js +32 -0
- package/dist/lib/frontend/useOrganizationScope.js.map +7 -0
- package/dist/lib/hotkeys/index.js +128 -0
- package/dist/lib/hotkeys/index.js.map +7 -0
- package/dist/lib/i18n/app-dictionaries.js +17 -0
- package/dist/lib/i18n/app-dictionaries.js.map +7 -0
- package/dist/lib/i18n/config.js +7 -0
- package/dist/lib/i18n/config.js.map +7 -0
- package/dist/lib/i18n/context.js +50 -0
- package/dist/lib/i18n/context.js.map +7 -0
- package/dist/lib/i18n/server.js +68 -0
- package/dist/lib/i18n/server.js.map +7 -0
- package/dist/lib/i18n/translate.js +45 -0
- package/dist/lib/i18n/translate.js.map +7 -0
- package/dist/lib/indexers/error-log.js +82 -0
- package/dist/lib/indexers/error-log.js.map +7 -0
- package/dist/lib/indexers/status-log.js +80 -0
- package/dist/lib/indexers/status-log.js.map +7 -0
- package/dist/lib/lib/auth/jwt.js +34 -0
- package/dist/lib/lib/auth/jwt.js.map +7 -0
- package/dist/lib/lib/auth/server.js +77 -0
- package/dist/lib/lib/auth/server.js.map +7 -0
- package/dist/lib/lib/email/send.js +12 -0
- package/dist/lib/lib/email/send.js.map +7 -0
- package/dist/lib/lib/i18n/config.js +7 -0
- package/dist/lib/lib/i18n/config.js.map +7 -0
- package/dist/lib/lib/i18n/context.js +31 -0
- package/dist/lib/lib/i18n/context.js.map +7 -0
- package/dist/lib/lib/utils.js +9 -0
- package/dist/lib/lib/utils.js.map +7 -0
- package/dist/lib/location/countries.js +68 -0
- package/dist/lib/location/countries.js.map +7 -0
- package/dist/lib/modules/index.js +6 -0
- package/dist/lib/modules/index.js.map +7 -0
- package/dist/lib/modules/registry.js +18 -0
- package/dist/lib/modules/registry.js.map +7 -0
- package/dist/lib/openapi/crud.js +137 -0
- package/dist/lib/openapi/crud.js.map +7 -0
- package/dist/lib/openapi/generator.js +1131 -0
- package/dist/lib/openapi/generator.js.map +7 -0
- package/dist/lib/openapi/index.js +10 -0
- package/dist/lib/openapi/index.js.map +7 -0
- package/dist/lib/openapi/sanitize.js +110 -0
- package/dist/lib/openapi/sanitize.js.map +7 -0
- package/dist/lib/openapi/types.js +1 -0
- package/dist/lib/openapi/types.js.map +7 -0
- package/dist/lib/profiler/index.js +258 -0
- package/dist/lib/profiler/index.js.map +7 -0
- package/dist/lib/query/engine.js +729 -0
- package/dist/lib/query/engine.js.map +7 -0
- package/dist/lib/query/join-utils.js +195 -0
- package/dist/lib/query/join-utils.js.map +7 -0
- package/dist/lib/query/types.js +9 -0
- package/dist/lib/query/types.js.map +7 -0
- package/dist/lib/search/config.js +32 -0
- package/dist/lib/search/config.js.map +7 -0
- package/dist/lib/search/tokenize.js +34 -0
- package/dist/lib/search/tokenize.js.map +7 -0
- package/dist/lib/slugify.js +24 -0
- package/dist/lib/slugify.js.map +7 -0
- package/dist/lib/testing/bootstrap.js +51 -0
- package/dist/lib/testing/bootstrap.js.map +7 -0
- package/dist/lib/testing/index.js +17 -0
- package/dist/lib/testing/index.js.map +7 -0
- package/dist/lib/testing/renderWithProviders.js +15 -0
- package/dist/lib/testing/renderWithProviders.js.map +7 -0
- package/dist/lib/url.js +12 -0
- package/dist/lib/url.js.map +7 -0
- package/dist/lib/utils.js +13 -0
- package/dist/lib/utils.js.map +7 -0
- package/dist/lib/version.js +7 -0
- package/dist/lib/version.js.map +7 -0
- package/dist/modules/dashboard/widgets.js +1 -0
- package/dist/modules/dashboard/widgets.js.map +7 -0
- package/dist/modules/dsl.js +30 -0
- package/dist/modules/dsl.js.map +7 -0
- package/dist/modules/entities/kinds.js +22 -0
- package/dist/modules/entities/kinds.js.map +7 -0
- package/dist/modules/entities/options.js +26 -0
- package/dist/modules/entities/options.js.map +7 -0
- package/dist/modules/entities/validation.js +102 -0
- package/dist/modules/entities/validation.js.map +7 -0
- package/dist/modules/entities/validators.js +88 -0
- package/dist/modules/entities/validators.js.map +7 -0
- package/dist/modules/entities.js +1 -0
- package/dist/modules/entities.js.map +7 -0
- package/dist/modules/navigation/sidebarPreferences.js +50 -0
- package/dist/modules/navigation/sidebarPreferences.js.map +7 -0
- package/dist/modules/perspectives/types.js +1 -0
- package/dist/modules/perspectives/types.js.map +7 -0
- package/dist/modules/registry.js +96 -0
- package/dist/modules/registry.js.map +7 -0
- package/dist/modules/search.js +15 -0
- package/dist/modules/search.js.map +7 -0
- package/dist/modules/vector.js +1 -0
- package/dist/modules/vector.js.map +7 -0
- package/dist/modules/widgets/injection-loader.js +180 -0
- package/dist/modules/widgets/injection-loader.js.map +7 -0
- package/dist/modules/widgets/injection.js +1 -0
- package/dist/modules/widgets/injection.js.map +7 -0
- package/dist/security/features.js +23 -0
- package/dist/security/features.js.map +7 -0
- package/dist/types/pg.d.js +1 -0
- package/dist/types/pg.d.js.map +7 -0
- package/dist/types/react-email.d.js +1 -0
- package/dist/types/react-email.d.js.map +7 -0
- package/dist/types/resend.d.js +1 -0
- package/dist/types/resend.d.js.map +7 -0
- package/jest.config.cjs +22 -0
- package/package.json +88 -0
- package/src/index.ts +0 -0
- package/src/lib/api/__tests__/scoped.test.ts +38 -0
- package/src/lib/api/crud.ts +59 -0
- package/src/lib/api/scoped.ts +239 -0
- package/src/lib/auth/jwt.ts +39 -0
- package/src/lib/auth/server.ts +199 -0
- package/src/lib/boolean.ts +17 -0
- package/src/lib/bootstrap/appResolver.ts +85 -0
- package/src/lib/bootstrap/dynamicLoader.ts +177 -0
- package/src/lib/bootstrap/factory.ts +108 -0
- package/src/lib/bootstrap/index.ts +23 -0
- package/src/lib/bootstrap/types.ts +31 -0
- package/src/lib/cache/segments.ts +56 -0
- package/src/lib/cli/progress.ts +55 -0
- package/src/lib/commands/__tests__/command-bus.test.ts +84 -0
- package/src/lib/commands/__tests__/helpers.test.ts +42 -0
- package/src/lib/commands/command-bus.ts +349 -0
- package/src/lib/commands/customFieldSnapshots.ts +86 -0
- package/src/lib/commands/helpers.ts +143 -0
- package/src/lib/commands/index.ts +4 -0
- package/src/lib/commands/operationMetadata.ts +40 -0
- package/src/lib/commands/registry.ts +46 -0
- package/src/lib/commands/scope.ts +59 -0
- package/src/lib/commands/types.ts +63 -0
- package/src/lib/crud/__tests__/crud-factory.test.ts +333 -0
- package/src/lib/crud/__tests__/custom-fields.test.ts +150 -0
- package/src/lib/crud/cache-stats.ts +127 -0
- package/src/lib/crud/cache.ts +205 -0
- package/src/lib/crud/custom-fields-client.ts +54 -0
- package/src/lib/crud/custom-fields.ts +607 -0
- package/src/lib/crud/errors.ts +23 -0
- package/src/lib/crud/exporters.ts +188 -0
- package/src/lib/crud/factory.ts +1622 -0
- package/src/lib/crud/types.ts +29 -0
- package/src/lib/custom-fields/normalize.ts +45 -0
- package/src/lib/data/engine.ts +562 -0
- package/src/lib/db/escapeLikePattern.ts +2 -0
- package/src/lib/db/mikro.ts +100 -0
- package/src/lib/di/container.ts +105 -0
- package/src/lib/email/send.ts +18 -0
- package/src/lib/encryption/__tests__/customFieldValues.test.ts +63 -0
- package/src/lib/encryption/__tests__/indexDoc.test.ts +115 -0
- package/src/lib/encryption/aes.ts +64 -0
- package/src/lib/encryption/customFieldValues.ts +67 -0
- package/src/lib/encryption/entityFields.ts +39 -0
- package/src/lib/encryption/entityIds.ts +107 -0
- package/src/lib/encryption/find.ts +81 -0
- package/src/lib/encryption/indexDoc.ts +104 -0
- package/src/lib/encryption/kms.ts +337 -0
- package/src/lib/encryption/subscriber.ts +416 -0
- package/src/lib/encryption/tenantDataEncryptionService.ts +313 -0
- package/src/lib/encryption/toggles.ts +15 -0
- package/src/lib/entities/naming.ts +6 -0
- package/src/lib/entities/system-entities.ts +43 -0
- package/src/lib/frontend/organizationEvents.ts +55 -0
- package/src/lib/frontend/useOrganizationScope.ts +30 -0
- package/src/lib/hotkeys/index.ts +168 -0
- package/src/lib/i18n/app-dictionaries.ts +18 -0
- package/src/lib/i18n/config.ts +4 -0
- package/src/lib/i18n/context.tsx +66 -0
- package/src/lib/i18n/server.ts +74 -0
- package/src/lib/i18n/translate.ts +54 -0
- package/src/lib/indexers/error-log.ts +106 -0
- package/src/lib/indexers/status-log.ts +119 -0
- package/src/lib/lib/auth/jwt.ts +39 -0
- package/src/lib/lib/auth/server.ts +94 -0
- package/src/lib/lib/email/send.ts +18 -0
- package/src/lib/lib/i18n/config.ts +4 -0
- package/src/lib/lib/i18n/context.tsx +38 -0
- package/src/lib/lib/utils.ts +6 -0
- package/src/lib/location/countries.ts +97 -0
- package/src/lib/modules/index.ts +1 -0
- package/src/lib/modules/registry.ts +18 -0
- package/src/lib/openapi/crud.ts +218 -0
- package/src/lib/openapi/generator.ts +1311 -0
- package/src/lib/openapi/index.ts +4 -0
- package/src/lib/openapi/sanitize.ts +137 -0
- package/src/lib/openapi/types.ts +79 -0
- package/src/lib/profiler/index.ts +371 -0
- package/src/lib/query/__tests__/engine.test.ts +274 -0
- package/src/lib/query/engine.ts +837 -0
- package/src/lib/query/join-utils.ts +238 -0
- package/src/lib/query/types.ts +121 -0
- package/src/lib/search/config.ts +49 -0
- package/src/lib/search/tokenize.ts +45 -0
- package/src/lib/slugify.ts +28 -0
- package/src/lib/testing/bootstrap.ts +124 -0
- package/src/lib/testing/index.ts +15 -0
- package/src/lib/testing/renderWithProviders.tsx +31 -0
- package/src/lib/url.ts +12 -0
- package/src/lib/utils.ts +17 -0
- package/src/lib/version.ts +5 -0
- package/src/modules/__tests__/dsl.test.ts +35 -0
- package/src/modules/__tests__/registry.test.ts +300 -0
- package/src/modules/dashboard/widgets.ts +57 -0
- package/src/modules/dsl.ts +32 -0
- package/src/modules/entities/__tests__/validation.test.ts +52 -0
- package/src/modules/entities/kinds.ts +20 -0
- package/src/modules/entities/options.ts +36 -0
- package/src/modules/entities/validation.ts +118 -0
- package/src/modules/entities/validators.ts +93 -0
- package/src/modules/entities.ts +102 -0
- package/src/modules/navigation/sidebarPreferences.ts +62 -0
- package/src/modules/perspectives/types.ts +40 -0
- package/src/modules/registry.ts +249 -0
- package/src/modules/search.ts +325 -0
- package/src/modules/vector.ts +122 -0
- package/src/modules/widgets/__tests__/injection.test.ts +48 -0
- package/src/modules/widgets/injection-loader.ts +235 -0
- package/src/modules/widgets/injection.ts +120 -0
- package/src/security/features.ts +22 -0
- package/src/types/pg.d.ts +2 -0
- package/src/types/react-email.d.ts +2 -0
- package/src/types/resend.d.ts +2 -0
- package/tsconfig.build.json +11 -0
- package/tsconfig.json +9 -0
- package/watch.mjs +6 -0
|
@@ -0,0 +1,467 @@
|
|
|
1
|
+
import { CustomFieldDef, CustomFieldValue } from "@open-mercato/core/modules/entities/data/entities";
|
|
2
|
+
import { decryptCustomFieldValue, resolveTenantEncryptionService } from "../encryption/customFieldValues.js";
|
|
3
|
+
import { parseBooleanToken } from "../boolean.js";
|
|
4
|
+
import { extractCustomFieldEntries } from "./custom-fields-client.js";
|
|
5
|
+
function buildCustomFieldSelectorsForEntity(entityId, sets) {
|
|
6
|
+
const keys = Array.from(new Set(
|
|
7
|
+
(sets || []).filter((s) => s.entity === entityId).flatMap((s) => (s.fields || []).map((f) => f.key))
|
|
8
|
+
));
|
|
9
|
+
const selectors = keys.map((k) => `cf:${k}`);
|
|
10
|
+
const outputKeys = keys.map((k) => `cf_${k}`);
|
|
11
|
+
return { keys, selectors, outputKeys };
|
|
12
|
+
}
|
|
13
|
+
function normalizeCustomFieldValue(val) {
|
|
14
|
+
if (Array.isArray(val)) return val;
|
|
15
|
+
if (typeof val === "string") {
|
|
16
|
+
const s = val.trim();
|
|
17
|
+
if (s.startsWith("{") && s.endsWith("}")) {
|
|
18
|
+
const inner = s.slice(1, -1).trim();
|
|
19
|
+
if (!inner) return [];
|
|
20
|
+
return inner.split(/[\s,]+/).map((x) => x.trim()).filter(Boolean);
|
|
21
|
+
}
|
|
22
|
+
return s;
|
|
23
|
+
}
|
|
24
|
+
return val;
|
|
25
|
+
}
|
|
26
|
+
function extractCustomFieldsFromItem(item, keys) {
|
|
27
|
+
const out = {};
|
|
28
|
+
for (const key of keys) {
|
|
29
|
+
const colon = item[`cf:${key}`];
|
|
30
|
+
const snake = item[`cf_${key}`];
|
|
31
|
+
const value = colon !== void 0 ? colon : snake;
|
|
32
|
+
if (value !== void 0) out[`cf_${key}`] = normalizeCustomFieldValue(value);
|
|
33
|
+
}
|
|
34
|
+
return out;
|
|
35
|
+
}
|
|
36
|
+
function extractAllCustomFieldEntries(item) {
|
|
37
|
+
return extractCustomFieldEntries(item);
|
|
38
|
+
}
|
|
39
|
+
function normalizeFieldsetFilter(input) {
|
|
40
|
+
if (input == null) return null;
|
|
41
|
+
const values = Array.isArray(input) ? input : [input];
|
|
42
|
+
const normalized = /* @__PURE__ */ new Set();
|
|
43
|
+
for (const raw of values) {
|
|
44
|
+
if (raw == null) continue;
|
|
45
|
+
const trimmed = String(raw).trim();
|
|
46
|
+
if (!trimmed) {
|
|
47
|
+
normalized.add(null);
|
|
48
|
+
} else {
|
|
49
|
+
normalized.add(trimmed);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return normalized.size ? normalized : null;
|
|
53
|
+
}
|
|
54
|
+
async function buildCustomFieldFiltersFromQuery(opts) {
|
|
55
|
+
const out = {};
|
|
56
|
+
const entries = Object.entries(opts.query).filter(([k]) => k.startsWith("cf_"));
|
|
57
|
+
if (!entries.length) return out;
|
|
58
|
+
const entityIdList = Array.isArray(opts.entityIds) && opts.entityIds.length ? opts.entityIds : opts.entityId ? [opts.entityId] : [];
|
|
59
|
+
if (!entityIdList.length) return out;
|
|
60
|
+
const defs = await opts.em.find(CustomFieldDef, {
|
|
61
|
+
entityId: { $in: entityIdList },
|
|
62
|
+
isActive: true,
|
|
63
|
+
$and: [
|
|
64
|
+
{ $or: [{ tenantId: opts.tenantId }, { tenantId: null }] }
|
|
65
|
+
]
|
|
66
|
+
});
|
|
67
|
+
const fieldsetFilter = normalizeFieldsetFilter(opts.fieldset);
|
|
68
|
+
const order = /* @__PURE__ */ new Map();
|
|
69
|
+
entityIdList.map(String).forEach((id, index) => order.set(id, index));
|
|
70
|
+
const byKey = {};
|
|
71
|
+
for (const d of defs) {
|
|
72
|
+
if (fieldsetFilter) {
|
|
73
|
+
const rawFieldset = typeof d.configJson?.fieldset === "string" ? d.configJson.fieldset.trim() : "";
|
|
74
|
+
const normalizedFieldset = rawFieldset.length ? rawFieldset : null;
|
|
75
|
+
if (!fieldsetFilter.has(normalizedFieldset)) continue;
|
|
76
|
+
}
|
|
77
|
+
const key = d.key;
|
|
78
|
+
const entityId = String(d.entityId);
|
|
79
|
+
const current = byKey[key];
|
|
80
|
+
const rankNew = order.get(entityId) ?? Number.MAX_SAFE_INTEGER;
|
|
81
|
+
if (!current) {
|
|
82
|
+
byKey[key] = { kind: d.kind, multi: Boolean(d.configJson?.multi), entityId };
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
const rankOld = order.get(current.entityId) ?? Number.MAX_SAFE_INTEGER;
|
|
86
|
+
if (rankNew < rankOld) {
|
|
87
|
+
byKey[key] = { kind: d.kind, multi: Boolean(d.configJson?.multi), entityId };
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
const coerce = (kind, v) => {
|
|
91
|
+
if (v == null) return v;
|
|
92
|
+
switch (kind) {
|
|
93
|
+
case "integer":
|
|
94
|
+
return Number.parseInt(String(v), 10);
|
|
95
|
+
case "float":
|
|
96
|
+
return Number.parseFloat(String(v));
|
|
97
|
+
case "boolean":
|
|
98
|
+
return parseBooleanToken(String(v)) === true;
|
|
99
|
+
default:
|
|
100
|
+
return String(v);
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
for (const [rawKey, rawVal] of entries) {
|
|
104
|
+
const isIn = rawKey.endsWith("In");
|
|
105
|
+
const key = isIn ? rawKey.replace(/^cf_/, "").replace(/In$/, "") : rawKey.replace(/^cf_/, "");
|
|
106
|
+
const def = byKey[key];
|
|
107
|
+
const fieldId = `cf:${key}`;
|
|
108
|
+
if (!def) continue;
|
|
109
|
+
if (isIn) {
|
|
110
|
+
const list = Array.isArray(rawVal) ? rawVal : String(rawVal).split(",").map((s) => s.trim()).filter(Boolean);
|
|
111
|
+
if (list.length) out[fieldId] = { $in: list.map((x) => coerce(def.kind, x)) };
|
|
112
|
+
} else {
|
|
113
|
+
out[fieldId] = coerce(def.kind, rawVal);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
return out;
|
|
117
|
+
}
|
|
118
|
+
function splitCustomFieldPayload(raw) {
|
|
119
|
+
const base = {};
|
|
120
|
+
const custom = {};
|
|
121
|
+
if (!raw || typeof raw !== "object") return { base, custom };
|
|
122
|
+
for (const [key, value] of Object.entries(raw)) {
|
|
123
|
+
if (key === "customFields") {
|
|
124
|
+
if (Array.isArray(value)) {
|
|
125
|
+
value.forEach((entry) => {
|
|
126
|
+
if (!entry || typeof entry !== "object") return;
|
|
127
|
+
const entryKey = typeof entry.key === "string" ? entry.key.trim() : "";
|
|
128
|
+
if (!entryKey) return;
|
|
129
|
+
custom[entryKey] = entry.value;
|
|
130
|
+
});
|
|
131
|
+
continue;
|
|
132
|
+
}
|
|
133
|
+
if (value && typeof value === "object") {
|
|
134
|
+
for (const [ck, cv] of Object.entries(value)) {
|
|
135
|
+
const normalizedKey = typeof ck === "string" ? ck.trim() : "";
|
|
136
|
+
if (!normalizedKey) continue;
|
|
137
|
+
custom[normalizedKey] = cv;
|
|
138
|
+
}
|
|
139
|
+
continue;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
if (key === "customValues" && value && typeof value === "object" && !Array.isArray(value)) {
|
|
143
|
+
for (const [ck, cv] of Object.entries(value)) {
|
|
144
|
+
custom[String(ck)] = cv;
|
|
145
|
+
}
|
|
146
|
+
continue;
|
|
147
|
+
}
|
|
148
|
+
if (key.startsWith("cf_")) {
|
|
149
|
+
custom[key.slice(3)] = value;
|
|
150
|
+
continue;
|
|
151
|
+
}
|
|
152
|
+
if (key.startsWith("cf:")) {
|
|
153
|
+
custom[key.slice(3)] = value;
|
|
154
|
+
continue;
|
|
155
|
+
}
|
|
156
|
+
base[key] = value;
|
|
157
|
+
}
|
|
158
|
+
return { base, custom };
|
|
159
|
+
}
|
|
160
|
+
function extractCustomFieldValuesFromPayload(raw) {
|
|
161
|
+
return splitCustomFieldPayload(raw).custom;
|
|
162
|
+
}
|
|
163
|
+
function normalizeDefinitionKey(key) {
|
|
164
|
+
if (typeof key !== "string") return "";
|
|
165
|
+
const trimmed = key.trim();
|
|
166
|
+
return trimmed.length ? trimmed.toLowerCase() : "";
|
|
167
|
+
}
|
|
168
|
+
function normalizeDefinitionConfig(raw) {
|
|
169
|
+
if (!raw) return {};
|
|
170
|
+
if (typeof raw === "string") {
|
|
171
|
+
try {
|
|
172
|
+
const parsed = JSON.parse(raw);
|
|
173
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
174
|
+
return { ...parsed };
|
|
175
|
+
}
|
|
176
|
+
return {};
|
|
177
|
+
} catch {
|
|
178
|
+
return {};
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
if (typeof raw === "object" && !Array.isArray(raw)) {
|
|
182
|
+
return { ...raw };
|
|
183
|
+
}
|
|
184
|
+
return {};
|
|
185
|
+
}
|
|
186
|
+
function summarizeDefinition(def) {
|
|
187
|
+
const normalizedKey = normalizeDefinitionKey(def.key);
|
|
188
|
+
if (!normalizedKey) return null;
|
|
189
|
+
const cfg = normalizeDefinitionConfig(def.configJson);
|
|
190
|
+
const label = typeof cfg.label === "string" && cfg.label.trim().length ? cfg.label.trim() : def.key;
|
|
191
|
+
const dictionaryId = typeof cfg.dictionaryId === "string" && cfg.dictionaryId.trim().length ? cfg.dictionaryId.trim() : null;
|
|
192
|
+
const multi = cfg.multi !== void 0 ? Boolean(cfg.multi) : false;
|
|
193
|
+
const priority = typeof cfg.priority === "number" ? cfg.priority : 0;
|
|
194
|
+
const updatedAt = def.updatedAt instanceof Date ? def.updatedAt.getTime() : new Date(def.updatedAt).getTime();
|
|
195
|
+
return {
|
|
196
|
+
key: def.key,
|
|
197
|
+
label,
|
|
198
|
+
kind: typeof def.kind === "string" ? def.kind : null,
|
|
199
|
+
multi,
|
|
200
|
+
dictionaryId,
|
|
201
|
+
organizationId: def.organizationId ?? null,
|
|
202
|
+
tenantId: def.tenantId ?? null,
|
|
203
|
+
priority,
|
|
204
|
+
updatedAt: Number.isNaN(updatedAt) ? 0 : updatedAt
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
function sortDefinitionSummaries(defs) {
|
|
208
|
+
return [...defs].sort((a, b) => {
|
|
209
|
+
const priorityDiff = (a.priority ?? 0) - (b.priority ?? 0);
|
|
210
|
+
if (priorityDiff !== 0) return priorityDiff;
|
|
211
|
+
const updatedDiff = (b.updatedAt ?? 0) - (a.updatedAt ?? 0);
|
|
212
|
+
if (updatedDiff !== 0) return updatedDiff;
|
|
213
|
+
return a.key.localeCompare(b.key);
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
function selectDefinitionForRecord(defs, organizationId, tenantId) {
|
|
217
|
+
if (!defs.length) return null;
|
|
218
|
+
const prioritizedForOrg = defs.filter(
|
|
219
|
+
(def) => def.organizationId && organizationId && def.organizationId === organizationId
|
|
220
|
+
);
|
|
221
|
+
if (prioritizedForOrg.length) return sortDefinitionSummaries(prioritizedForOrg)[0];
|
|
222
|
+
const prioritizedForTenant = defs.filter(
|
|
223
|
+
(def) => def.tenantId && tenantId && def.tenantId === tenantId && !def.organizationId
|
|
224
|
+
);
|
|
225
|
+
if (prioritizedForTenant.length) return sortDefinitionSummaries(prioritizedForTenant)[0];
|
|
226
|
+
const global = defs.filter((def) => !def.organizationId);
|
|
227
|
+
if (global.length) return sortDefinitionSummaries(global)[0];
|
|
228
|
+
return sortDefinitionSummaries(defs)[0] ?? null;
|
|
229
|
+
}
|
|
230
|
+
async function loadCustomFieldDefinitionIndex(opts) {
|
|
231
|
+
const list = Array.isArray(opts.entityIds) ? opts.entityIds : [opts.entityIds];
|
|
232
|
+
const entityIds = list.map((id) => typeof id === "string" ? id.trim() : String(id ?? "")).filter((id) => id.length > 0);
|
|
233
|
+
if (!entityIds.length) return /* @__PURE__ */ new Map();
|
|
234
|
+
const tenantId = opts.tenantId ?? null;
|
|
235
|
+
const orgCandidates = Array.isArray(opts.organizationIds) ? opts.organizationIds.map((id) => typeof id === "string" ? id.trim() : id).filter((id) => typeof id === "string" && id.length > 0) : [];
|
|
236
|
+
const scopeClauses = [
|
|
237
|
+
tenantId ? { $or: [{ tenantId }, { tenantId: null }] } : { tenantId: null }
|
|
238
|
+
];
|
|
239
|
+
if (orgCandidates.length) {
|
|
240
|
+
scopeClauses.push({
|
|
241
|
+
$or: [{ organizationId: { $in: orgCandidates } }, { organizationId: null }]
|
|
242
|
+
});
|
|
243
|
+
} else {
|
|
244
|
+
scopeClauses.push({ organizationId: null });
|
|
245
|
+
}
|
|
246
|
+
const where = {
|
|
247
|
+
entityId: { $in: entityIds },
|
|
248
|
+
deletedAt: null,
|
|
249
|
+
isActive: true,
|
|
250
|
+
$and: scopeClauses
|
|
251
|
+
};
|
|
252
|
+
const defs = await opts.em.find(CustomFieldDef, where);
|
|
253
|
+
const index = /* @__PURE__ */ new Map();
|
|
254
|
+
defs.forEach((def) => {
|
|
255
|
+
const summary = summarizeDefinition(def);
|
|
256
|
+
if (!summary) return;
|
|
257
|
+
const normalizedKey = normalizeDefinitionKey(summary.key);
|
|
258
|
+
if (!normalizedKey) return;
|
|
259
|
+
if (!index.has(normalizedKey)) index.set(normalizedKey, []);
|
|
260
|
+
index.get(normalizedKey).push(summary);
|
|
261
|
+
});
|
|
262
|
+
index.forEach((entries, key) => {
|
|
263
|
+
index.set(key, sortDefinitionSummaries(entries));
|
|
264
|
+
});
|
|
265
|
+
return index;
|
|
266
|
+
}
|
|
267
|
+
function decorateRecordWithCustomFields(record, definitions, context = {}) {
|
|
268
|
+
const rawEntries = extractAllCustomFieldEntries(record);
|
|
269
|
+
if (!Object.keys(rawEntries).length) {
|
|
270
|
+
return { customValues: null, customFields: [] };
|
|
271
|
+
}
|
|
272
|
+
const values = {};
|
|
273
|
+
const entries = [];
|
|
274
|
+
const organizationId = context.organizationId ?? null;
|
|
275
|
+
const tenantId = context.tenantId ?? null;
|
|
276
|
+
Object.entries(rawEntries).forEach(([prefixedKey, value]) => {
|
|
277
|
+
const bareKey = prefixedKey.replace(/^cf_/, "");
|
|
278
|
+
const normalizedKey = normalizeDefinitionKey(bareKey);
|
|
279
|
+
if (!normalizedKey) return;
|
|
280
|
+
values[bareKey] = value;
|
|
281
|
+
const defsForKey = definitions.get(normalizedKey) ?? [];
|
|
282
|
+
const resolvedDef = selectDefinitionForRecord(defsForKey, organizationId, tenantId);
|
|
283
|
+
const entry = {
|
|
284
|
+
key: bareKey,
|
|
285
|
+
label: resolvedDef?.label ?? bareKey,
|
|
286
|
+
value,
|
|
287
|
+
kind: resolvedDef?.kind ?? null,
|
|
288
|
+
multi: resolvedDef?.multi ?? Array.isArray(value)
|
|
289
|
+
};
|
|
290
|
+
entries.push({
|
|
291
|
+
entry,
|
|
292
|
+
priority: resolvedDef?.priority ?? Number.MAX_SAFE_INTEGER,
|
|
293
|
+
updatedAt: resolvedDef?.updatedAt ?? 0
|
|
294
|
+
});
|
|
295
|
+
});
|
|
296
|
+
const ordered = entries.sort((a, b) => {
|
|
297
|
+
const priorityDiff = a.priority - b.priority;
|
|
298
|
+
if (priorityDiff !== 0) return priorityDiff;
|
|
299
|
+
const updatedDiff = b.updatedAt - a.updatedAt;
|
|
300
|
+
if (updatedDiff !== 0) return updatedDiff;
|
|
301
|
+
return a.entry.key.localeCompare(b.entry.key);
|
|
302
|
+
}).map((item) => item.entry);
|
|
303
|
+
return {
|
|
304
|
+
customValues: Object.keys(values).length ? values : null,
|
|
305
|
+
customFields: ordered
|
|
306
|
+
};
|
|
307
|
+
}
|
|
308
|
+
async function loadCustomFieldValues(opts) {
|
|
309
|
+
const { em, entityId, recordIds } = opts;
|
|
310
|
+
if (!Array.isArray(recordIds) || recordIds.length === 0) return {};
|
|
311
|
+
const normalizedRecordIds = recordIds.map((id) => String(id));
|
|
312
|
+
let encryptionService;
|
|
313
|
+
const encryptionCache = /* @__PURE__ */ new Map();
|
|
314
|
+
const getEncryptionService = () => {
|
|
315
|
+
if (encryptionService !== void 0) return encryptionService;
|
|
316
|
+
encryptionService = resolveTenantEncryptionService(em, opts.encryptionService);
|
|
317
|
+
return encryptionService;
|
|
318
|
+
};
|
|
319
|
+
const tenantCandidates = /* @__PURE__ */ new Set();
|
|
320
|
+
tenantCandidates.add(null);
|
|
321
|
+
if (opts.tenantIdByRecord) {
|
|
322
|
+
for (const val of Object.values(opts.tenantIdByRecord)) {
|
|
323
|
+
tenantCandidates.add(val ? String(val) : null);
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
if (opts.tenantFallbacks) {
|
|
327
|
+
for (const val of opts.tenantFallbacks) tenantCandidates.add(val ? String(val) : null);
|
|
328
|
+
}
|
|
329
|
+
const fallbackTenant = (opts.tenantFallbacks || []).find((t) => t != null) ?? null;
|
|
330
|
+
const tenantList = Array.from(tenantCandidates);
|
|
331
|
+
const tenantNonNull = tenantList.filter((t) => t !== null);
|
|
332
|
+
const tenantFilter = tenantNonNull.length ? { tenantId: { $in: [...tenantNonNull, null] } } : { tenantId: null };
|
|
333
|
+
const cfRows = await em.find(CustomFieldValue, {
|
|
334
|
+
entityId,
|
|
335
|
+
recordId: { $in: normalizedRecordIds },
|
|
336
|
+
deletedAt: null,
|
|
337
|
+
...tenantList.length ? tenantFilter : {}
|
|
338
|
+
});
|
|
339
|
+
if (!cfRows.length) return {};
|
|
340
|
+
const allKeys = Array.from(new Set(cfRows.map((row) => String(row.fieldKey))));
|
|
341
|
+
const organizationCandidates = /* @__PURE__ */ new Set();
|
|
342
|
+
organizationCandidates.add(null);
|
|
343
|
+
if (opts.organizationIdByRecord) {
|
|
344
|
+
for (const val of Object.values(opts.organizationIdByRecord)) {
|
|
345
|
+
organizationCandidates.add(val ? String(val) : null);
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
for (const row of cfRows) {
|
|
349
|
+
organizationCandidates.add(row.organizationId ? String(row.organizationId) : null);
|
|
350
|
+
}
|
|
351
|
+
const orgList = Array.from(organizationCandidates);
|
|
352
|
+
const defs = allKeys.length ? await em.find(CustomFieldDef, {
|
|
353
|
+
entityId,
|
|
354
|
+
key: { $in: allKeys },
|
|
355
|
+
deletedAt: null,
|
|
356
|
+
isActive: true,
|
|
357
|
+
...tenantList.length ? { tenantId: tenantFilter.tenantId } : {},
|
|
358
|
+
organizationId: { $in: orgList }
|
|
359
|
+
}) : [];
|
|
360
|
+
const defsByKey = /* @__PURE__ */ new Map();
|
|
361
|
+
for (const def of defs) {
|
|
362
|
+
const list = defsByKey.get(def.key) || [];
|
|
363
|
+
list.push(def);
|
|
364
|
+
defsByKey.set(def.key, list);
|
|
365
|
+
}
|
|
366
|
+
const pickDefinition = (fieldKey, organizationId, tenantId) => {
|
|
367
|
+
const candidates = defsByKey.get(fieldKey);
|
|
368
|
+
if (!candidates || candidates.length === 0) return null;
|
|
369
|
+
const active = candidates.filter((opt) => opt.isActive !== false && !opt.deletedAt);
|
|
370
|
+
const list = active.length ? active : candidates;
|
|
371
|
+
if (organizationId && tenantId) {
|
|
372
|
+
const exact = list.find((opt) => opt.organizationId === organizationId && opt.tenantId === tenantId);
|
|
373
|
+
if (exact) return exact;
|
|
374
|
+
}
|
|
375
|
+
if (organizationId) {
|
|
376
|
+
const orgMatch = list.find((opt) => opt.organizationId === organizationId && (!tenantId || opt.tenantId == null || opt.tenantId === tenantId));
|
|
377
|
+
if (orgMatch) return orgMatch;
|
|
378
|
+
}
|
|
379
|
+
if (tenantId) {
|
|
380
|
+
const tenantMatch = list.find((opt) => opt.organizationId == null && opt.tenantId === tenantId);
|
|
381
|
+
if (tenantMatch) return tenantMatch;
|
|
382
|
+
}
|
|
383
|
+
const global = list.find((opt) => opt.organizationId == null && opt.tenantId == null);
|
|
384
|
+
return global ?? list[0];
|
|
385
|
+
};
|
|
386
|
+
const valueFromRow = (row) => {
|
|
387
|
+
if (row.valueMultiline !== null && row.valueMultiline !== void 0) return row.valueMultiline;
|
|
388
|
+
if (row.valueText !== null && row.valueText !== void 0) return row.valueText;
|
|
389
|
+
if (row.valueInt !== null && row.valueInt !== void 0) return row.valueInt;
|
|
390
|
+
if (row.valueFloat !== null && row.valueFloat !== void 0) return row.valueFloat;
|
|
391
|
+
if (row.valueBool !== null && row.valueBool !== void 0) return row.valueBool;
|
|
392
|
+
return null;
|
|
393
|
+
};
|
|
394
|
+
const buckets = /* @__PURE__ */ new Map();
|
|
395
|
+
for (const row of cfRows) {
|
|
396
|
+
const recordId = String(row.recordId);
|
|
397
|
+
const key = String(row.fieldKey);
|
|
398
|
+
const bucketKey = `${recordId}::${key}`;
|
|
399
|
+
const orgId = row.organizationId ? String(row.organizationId) : null;
|
|
400
|
+
const tenantId = row.tenantId ? String(row.tenantId) : null;
|
|
401
|
+
const resolvedOrgId = orgId ?? (opts.organizationIdByRecord?.[recordId] ?? null);
|
|
402
|
+
const resolvedTenantId = tenantId ?? (opts.tenantIdByRecord?.[recordId] ?? fallbackTenant);
|
|
403
|
+
const def = pickDefinition(key, resolvedOrgId, resolvedTenantId);
|
|
404
|
+
const encrypted = Boolean(def?.configJson && def.configJson?.encrypted);
|
|
405
|
+
const value = valueFromRow(row);
|
|
406
|
+
const decrypted = encrypted ? await decryptCustomFieldValue(value, resolvedTenantId ?? tenantId ?? null, getEncryptionService(), encryptionCache) : value;
|
|
407
|
+
const existing = buckets.get(bucketKey);
|
|
408
|
+
if (existing) {
|
|
409
|
+
if (existing.orgId == null && resolvedOrgId) existing.orgId = resolvedOrgId;
|
|
410
|
+
if (existing.tenantId == null && resolvedTenantId) existing.tenantId = resolvedTenantId;
|
|
411
|
+
if (existing.def == null && def) existing.def = def;
|
|
412
|
+
existing.encrypted = existing.encrypted || encrypted;
|
|
413
|
+
existing.values.push(decrypted);
|
|
414
|
+
} else {
|
|
415
|
+
buckets.set(bucketKey, { orgId: resolvedOrgId, tenantId: resolvedTenantId, values: [decrypted], def: def ?? null, encrypted });
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
const result = {};
|
|
419
|
+
for (const [compoundKey, bucket] of buckets.entries()) {
|
|
420
|
+
const [recordId, fieldKey] = compoundKey.split("::");
|
|
421
|
+
if (!result[recordId]) result[recordId] = {};
|
|
422
|
+
const prefixed = `cf_${fieldKey}`;
|
|
423
|
+
const def = bucket.def ?? pickDefinition(fieldKey, bucket.orgId ?? (opts.organizationIdByRecord?.[recordId] ?? null), bucket.tenantId ?? (opts.tenantIdByRecord?.[recordId] ?? null));
|
|
424
|
+
if (def && def.configJson && typeof def.configJson === "object" && def.configJson.multi) {
|
|
425
|
+
const cleaned = bucket.values.filter((v) => v !== void 0 && v !== null);
|
|
426
|
+
result[recordId][prefixed] = cleaned;
|
|
427
|
+
} else if (bucket.values.length > 1) {
|
|
428
|
+
const cleaned = bucket.values.filter((v) => v !== void 0);
|
|
429
|
+
result[recordId][prefixed] = cleaned;
|
|
430
|
+
} else {
|
|
431
|
+
result[recordId][prefixed] = bucket.values[0] ?? null;
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
return result;
|
|
435
|
+
}
|
|
436
|
+
function summarizeCustomFields(record) {
|
|
437
|
+
const entries = extractAllCustomFieldEntries(record);
|
|
438
|
+
const values = Object.fromEntries(
|
|
439
|
+
Object.entries(entries).map(([prefixedKey, value]) => [
|
|
440
|
+
prefixedKey.replace(/^cf_/, ""),
|
|
441
|
+
value
|
|
442
|
+
])
|
|
443
|
+
);
|
|
444
|
+
const customValues = Object.keys(values).length ? values : null;
|
|
445
|
+
const customFields = Object.entries(values).map(([key, value]) => ({
|
|
446
|
+
key,
|
|
447
|
+
label: key,
|
|
448
|
+
value,
|
|
449
|
+
kind: null,
|
|
450
|
+
multi: Array.isArray(value)
|
|
451
|
+
}));
|
|
452
|
+
return { entries, customValues, customFields };
|
|
453
|
+
}
|
|
454
|
+
export {
|
|
455
|
+
buildCustomFieldFiltersFromQuery,
|
|
456
|
+
buildCustomFieldSelectorsForEntity,
|
|
457
|
+
decorateRecordWithCustomFields,
|
|
458
|
+
extractAllCustomFieldEntries,
|
|
459
|
+
extractCustomFieldValuesFromPayload,
|
|
460
|
+
extractCustomFieldsFromItem,
|
|
461
|
+
loadCustomFieldDefinitionIndex,
|
|
462
|
+
loadCustomFieldValues,
|
|
463
|
+
normalizeCustomFieldValue,
|
|
464
|
+
splitCustomFieldPayload,
|
|
465
|
+
summarizeCustomFields
|
|
466
|
+
};
|
|
467
|
+
//# sourceMappingURL=custom-fields.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/lib/crud/custom-fields.ts"],
|
|
4
|
+
"sourcesContent": ["import type { CustomFieldSet, EntityId } from '@open-mercato/shared/modules/entities'\nimport type { EntityManager } from '@mikro-orm/core'\nimport { CustomFieldDef, CustomFieldValue } from '@open-mercato/core/modules/entities/data/entities'\nimport type { WhereValue } from '@open-mercato/shared/lib/query/types'\nimport type { TenantDataEncryptionService } from '../encryption/tenantDataEncryptionService'\nimport { decryptCustomFieldValue, resolveTenantEncryptionService } from '../encryption/customFieldValues'\nimport { parseBooleanToken } from '../boolean'\nimport { extractCustomFieldEntries } from './custom-fields-client'\n\nexport type CustomFieldSelectors = {\n keys: string[]\n selectors: string[] // e.g. ['cf:priority', 'cf:severity']\n outputKeys: string[] // e.g. ['cf_priority', 'cf_severity']\n}\n\nexport type SplitCustomFieldPayload = {\n base: Record<string, unknown>\n custom: Record<string, unknown>\n}\n\nexport type CustomFieldDefinitionSummary = {\n key: string\n label: string | null\n kind: string | null\n multi: boolean\n dictionaryId?: string | null\n organizationId?: string | null\n tenantId?: string | null\n priority: number\n updatedAt: number\n}\n\nexport type CustomFieldDefinitionIndex = Map<string, CustomFieldDefinitionSummary[]>\n\nexport type CustomFieldDisplayEntry = {\n key: string\n label: string | null\n value: unknown\n kind: string | null\n multi: boolean\n}\n\nexport type CustomFieldDisplayPayload = {\n customValues: Record<string, unknown> | null\n customFields: CustomFieldDisplayEntry[]\n}\n\nexport type CustomFieldSnapshot = {\n entries: Record<string, unknown>\n customValues: Record<string, unknown> | null\n customFields: CustomFieldDisplayEntry[]\n}\n\nexport function buildCustomFieldSelectorsForEntity(entityId: EntityId, sets: CustomFieldSet[]): CustomFieldSelectors {\n const keys = Array.from(new Set(\n (sets || [])\n .filter((s) => s.entity === entityId)\n .flatMap((s) => (s.fields || []).map((f) => f.key))\n ))\n const selectors = keys.map((k) => `cf:${k}`)\n const outputKeys = keys.map((k) => `cf_${k}`)\n return { keys, selectors, outputKeys }\n}\n\nexport function normalizeCustomFieldValue(val: unknown): unknown {\n if (Array.isArray(val)) return val\n if (typeof val === 'string') {\n const s = val.trim()\n // Parse Postgres array-like '{a,b,c}' to string[] when present\n if (s.startsWith('{') && s.endsWith('}')) {\n const inner = s.slice(1, -1).trim()\n if (!inner) return []\n return inner.split(/[\\s,]+/).map((x) => x.trim()).filter(Boolean)\n }\n return s\n }\n return val as any\n}\n\n// Extracts cf_* fields from a record that may contain both 'cf:<key>' and/or 'cf_<key>'\nexport function extractCustomFieldsFromItem(item: Record<string, unknown>, keys: string[]): Record<string, unknown> {\n const out: Record<string, unknown> = {}\n for (const key of keys) {\n const colon = item[`cf:${key}` as keyof typeof item]\n const snake = item[`cf_${key}` as keyof typeof item]\n const value = colon !== undefined ? colon : snake\n if (value !== undefined) out[`cf_${key}`] = normalizeCustomFieldValue(value)\n }\n return out\n}\n\nexport function extractAllCustomFieldEntries(item: Record<string, unknown>): Record<string, unknown> {\n return extractCustomFieldEntries(item)\n}\n\nfunction normalizeFieldsetFilter(input?: string | string[] | null): Set<string | null> | null {\n if (input == null) return null\n const values = Array.isArray(input) ? input : [input]\n const normalized = new Set<string | null>()\n for (const raw of values) {\n if (raw == null) continue\n const trimmed = String(raw).trim()\n if (!trimmed) {\n normalized.add(null)\n } else {\n normalized.add(trimmed)\n }\n }\n return normalized.size ? normalized : null\n}\n\nexport async function buildCustomFieldFiltersFromQuery(opts: {\n entityId?: EntityId\n entityIds?: EntityId[]\n query: Record<string, unknown>\n em: EntityManager\n tenantId: string | null | undefined\n fieldset?: string | string[] | null\n}): Promise<Record<string, WhereValue>> {\n const out: Record<string, WhereValue> = {}\n const entries = Object.entries(opts.query).filter(([k]) => k.startsWith('cf_'))\n if (!entries.length) return out\n\n const entityIdList = Array.isArray(opts.entityIds) && opts.entityIds.length\n ? opts.entityIds\n : opts.entityId\n ? [opts.entityId]\n : []\n if (!entityIdList.length) return out\n\n // Tenant-only scope: allow global (null) or tenant match; ignore organization here\n const defs = await opts.em.find(CustomFieldDef, {\n entityId: { $in: entityIdList as any },\n isActive: true,\n $and: [\n { $or: [ { tenantId: opts.tenantId as any }, { tenantId: null } ] },\n ],\n })\n const fieldsetFilter = normalizeFieldsetFilter(opts.fieldset)\n const order = new Map<string, number>()\n entityIdList.map(String).forEach((id, index) => order.set(id, index))\n const byKey: Record<string, { kind: string; multi?: boolean; entityId: string }> = {}\n for (const d of defs) {\n if (fieldsetFilter) {\n const rawFieldset = typeof d.configJson?.fieldset === 'string' ? d.configJson.fieldset.trim() : ''\n const normalizedFieldset = rawFieldset.length ? rawFieldset : null\n if (!fieldsetFilter.has(normalizedFieldset)) continue\n }\n const key = d.key\n const entityId = String(d.entityId)\n const current = byKey[key]\n const rankNew = order.get(entityId) ?? Number.MAX_SAFE_INTEGER\n if (!current) {\n byKey[key] = { kind: d.kind, multi: Boolean((d as any).configJson?.multi), entityId }\n continue\n }\n const rankOld = order.get(current.entityId) ?? Number.MAX_SAFE_INTEGER\n if (rankNew < rankOld) {\n byKey[key] = { kind: d.kind, multi: Boolean((d as any).configJson?.multi), entityId }\n }\n }\n\n const coerce = (kind: string, v: unknown) => {\n if (v == null) return v as undefined\n switch (kind) {\n case 'integer': return Number.parseInt(String(v), 10)\n case 'float': return Number.parseFloat(String(v))\n case 'boolean': return parseBooleanToken(String(v)) === true\n default: return String(v)\n }\n }\n\n for (const [rawKey, rawVal] of entries) {\n const isIn = rawKey.endsWith('In')\n const key = isIn ? rawKey.replace(/^cf_/, '').replace(/In$/, '') : rawKey.replace(/^cf_/, '')\n const def = byKey[key]\n const fieldId = `cf:${key}`\n if (!def) continue\n if (isIn) {\n const list = Array.isArray(rawVal)\n ? (rawVal as unknown[])\n : String(rawVal)\n .split(',')\n .map((s) => s.trim())\n .filter(Boolean)\n if (list.length) out[fieldId] = { $in: list.map((x) => coerce(def.kind, x)) as (string[] | number[] | boolean[]) }\n } else {\n out[fieldId] = coerce(def.kind, rawVal)\n }\n }\n\n return out\n}\n\nexport function splitCustomFieldPayload(raw: unknown): SplitCustomFieldPayload {\n const base: Record<string, unknown> = {}\n const custom: Record<string, unknown> = {}\n if (!raw || typeof raw !== 'object') return { base, custom }\n for (const [key, value] of Object.entries(raw as Record<string, unknown>)) {\n if (key === 'customFields') {\n if (Array.isArray(value)) {\n value.forEach((entry) => {\n if (!entry || typeof entry !== 'object') return\n const entryKey = typeof (entry as any).key === 'string' ? (entry as any).key.trim() : ''\n if (!entryKey) return\n custom[entryKey] = (entry as any).value\n })\n continue\n }\n if (value && typeof value === 'object') {\n for (const [ck, cv] of Object.entries(value as Record<string, unknown>)) {\n const normalizedKey = typeof ck === 'string' ? ck.trim() : ''\n if (!normalizedKey) continue\n custom[normalizedKey] = cv\n }\n continue\n }\n }\n if (key === 'customValues' && value && typeof value === 'object' && !Array.isArray(value)) {\n for (const [ck, cv] of Object.entries(value as Record<string, unknown>)) {\n custom[String(ck)] = cv\n }\n continue\n }\n if (key.startsWith('cf_')) {\n custom[key.slice(3)] = value\n continue\n }\n if (key.startsWith('cf:')) {\n custom[key.slice(3)] = value\n continue\n }\n base[key] = value\n }\n return { base, custom }\n}\n\nexport function extractCustomFieldValuesFromPayload(raw: Record<string, unknown>): Record<string, unknown> {\n return splitCustomFieldPayload(raw).custom\n}\n\nfunction normalizeDefinitionKey(key: unknown): string {\n if (typeof key !== 'string') return ''\n const trimmed = key.trim()\n return trimmed.length ? trimmed.toLowerCase() : ''\n}\n\nfunction normalizeDefinitionConfig(raw: unknown): Record<string, any> {\n if (!raw) return {}\n if (typeof raw === 'string') {\n try {\n const parsed = JSON.parse(raw)\n if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {\n return { ...(parsed as Record<string, any>) }\n }\n return {}\n } catch {\n return {}\n }\n }\n if (typeof raw === 'object' && !Array.isArray(raw)) {\n return { ...(raw as Record<string, any>) }\n }\n return {}\n}\n\nfunction summarizeDefinition(def: CustomFieldDef): CustomFieldDefinitionSummary | null {\n const normalizedKey = normalizeDefinitionKey(def.key)\n if (!normalizedKey) return null\n const cfg = normalizeDefinitionConfig((def as any).configJson)\n const label =\n typeof cfg.label === 'string' && cfg.label.trim().length\n ? cfg.label.trim()\n : def.key\n const dictionaryId =\n typeof cfg.dictionaryId === 'string' && cfg.dictionaryId.trim().length\n ? cfg.dictionaryId.trim()\n : null\n const multi =\n cfg.multi !== undefined ? Boolean(cfg.multi) : false\n const priority =\n typeof cfg.priority === 'number' ? cfg.priority : 0\n const updatedAt =\n def.updatedAt instanceof Date\n ? def.updatedAt.getTime()\n : new Date(def.updatedAt as any).getTime()\n return {\n key: def.key,\n label,\n kind: typeof def.kind === 'string' ? def.kind : null,\n multi,\n dictionaryId,\n organizationId: def.organizationId ?? null,\n tenantId: def.tenantId ?? null,\n priority,\n updatedAt: Number.isNaN(updatedAt) ? 0 : updatedAt,\n }\n}\n\nfunction sortDefinitionSummaries(defs: CustomFieldDefinitionSummary[]): CustomFieldDefinitionSummary[] {\n return [...defs].sort((a, b) => {\n const priorityDiff = (a.priority ?? 0) - (b.priority ?? 0)\n if (priorityDiff !== 0) return priorityDiff\n const updatedDiff = (b.updatedAt ?? 0) - (a.updatedAt ?? 0)\n if (updatedDiff !== 0) return updatedDiff\n return a.key.localeCompare(b.key)\n })\n}\n\nfunction selectDefinitionForRecord(\n defs: CustomFieldDefinitionSummary[],\n organizationId: string | null,\n tenantId: string | null,\n): CustomFieldDefinitionSummary | null {\n if (!defs.length) return null\n const prioritizedForOrg = defs.filter(\n (def) => def.organizationId && organizationId && def.organizationId === organizationId,\n )\n if (prioritizedForOrg.length) return sortDefinitionSummaries(prioritizedForOrg)[0]\n const prioritizedForTenant = defs.filter(\n (def) => def.tenantId && tenantId && def.tenantId === tenantId && !def.organizationId,\n )\n if (prioritizedForTenant.length) return sortDefinitionSummaries(prioritizedForTenant)[0]\n const global = defs.filter((def) => !def.organizationId)\n if (global.length) return sortDefinitionSummaries(global)[0]\n return sortDefinitionSummaries(defs)[0] ?? null\n}\n\nexport async function loadCustomFieldDefinitionIndex(opts: {\n em: EntityManager\n entityIds: string | string[]\n tenantId?: string | null | undefined\n organizationIds?: Array<string | null | undefined> | null\n}): Promise<CustomFieldDefinitionIndex> {\n const list = Array.isArray(opts.entityIds) ? opts.entityIds : [opts.entityIds]\n const entityIds = list\n .map((id) => (typeof id === 'string' ? id.trim() : String(id ?? '')))\n .filter((id) => id.length > 0)\n if (!entityIds.length) return new Map()\n const tenantId = opts.tenantId ?? null\n const orgCandidates = Array.isArray(opts.organizationIds)\n ? opts.organizationIds\n .map((id) => (typeof id === 'string' ? id.trim() : id))\n .filter((id): id is string => typeof id === 'string' && id.length > 0)\n : []\n const scopeClauses: Record<string, unknown>[] = [\n tenantId\n ? { $or: [{ tenantId: tenantId as any }, { tenantId: null }] }\n : { tenantId: null },\n ]\n if (orgCandidates.length) {\n scopeClauses.push({\n $or: [{ organizationId: { $in: orgCandidates as any } }, { organizationId: null }],\n })\n } else {\n scopeClauses.push({ organizationId: null })\n }\n const where: Record<string, unknown> = {\n entityId: { $in: entityIds as any },\n deletedAt: null,\n isActive: true,\n $and: scopeClauses,\n }\n const defs = await opts.em.find(CustomFieldDef, where as any)\n const index: CustomFieldDefinitionIndex = new Map()\n defs.forEach((def) => {\n const summary = summarizeDefinition(def)\n if (!summary) return\n const normalizedKey = normalizeDefinitionKey(summary.key)\n if (!normalizedKey) return\n if (!index.has(normalizedKey)) index.set(normalizedKey, [])\n index.get(normalizedKey)!.push(summary)\n })\n index.forEach((entries, key) => {\n index.set(key, sortDefinitionSummaries(entries))\n })\n return index\n}\n\nexport function decorateRecordWithCustomFields(\n record: Record<string, unknown>,\n definitions: CustomFieldDefinitionIndex,\n context: {\n organizationId?: string | null\n tenantId?: string | null\n } = {},\n): CustomFieldDisplayPayload {\n const rawEntries = extractAllCustomFieldEntries(record)\n if (!Object.keys(rawEntries).length) {\n return { customValues: null, customFields: [] }\n }\n const values: Record<string, unknown> = {}\n const entries: Array<{ entry: CustomFieldDisplayEntry; priority: number; updatedAt: number }> = []\n const organizationId = context.organizationId ?? null\n const tenantId = context.tenantId ?? null\n\n Object.entries(rawEntries).forEach(([prefixedKey, value]) => {\n const bareKey = prefixedKey.replace(/^cf_/, '')\n const normalizedKey = normalizeDefinitionKey(bareKey)\n if (!normalizedKey) return\n values[bareKey] = value\n const defsForKey = definitions.get(normalizedKey) ?? []\n const resolvedDef = selectDefinitionForRecord(defsForKey, organizationId, tenantId)\n const entry: CustomFieldDisplayEntry = {\n key: bareKey,\n label: resolvedDef?.label ?? bareKey,\n value,\n kind: resolvedDef?.kind ?? null,\n multi: resolvedDef?.multi ?? Array.isArray(value),\n }\n entries.push({\n entry,\n priority: resolvedDef?.priority ?? Number.MAX_SAFE_INTEGER,\n updatedAt: resolvedDef?.updatedAt ?? 0,\n })\n })\n\n const ordered = entries\n .sort((a, b) => {\n const priorityDiff = a.priority - b.priority\n if (priorityDiff !== 0) return priorityDiff\n const updatedDiff = b.updatedAt - a.updatedAt\n if (updatedDiff !== 0) return updatedDiff\n return a.entry.key.localeCompare(b.entry.key)\n })\n .map((item) => item.entry)\n\n return {\n customValues: Object.keys(values).length ? values : null,\n customFields: ordered,\n }\n}\n\nexport async function loadCustomFieldValues(opts: {\n em: EntityManager\n entityId: EntityId\n recordIds: string[]\n tenantIdByRecord?: Record<string, string | null | undefined>\n organizationIdByRecord?: Record<string, string | null | undefined>\n tenantFallbacks?: (string | null | undefined)[]\n encryptionService?: TenantDataEncryptionService | null\n}): Promise<Record<string, Record<string, unknown>>> {\n const { em, entityId, recordIds } = opts\n if (!Array.isArray(recordIds) || recordIds.length === 0) return {}\n\n const normalizedRecordIds = recordIds.map((id) => String(id))\n let encryptionService: TenantDataEncryptionService | null | undefined\n const encryptionCache = new Map<string | null, string | null>()\n const getEncryptionService = () => {\n if (encryptionService !== undefined) return encryptionService\n encryptionService = resolveTenantEncryptionService(em, opts.encryptionService)\n return encryptionService\n }\n const tenantCandidates = new Set<string | null>()\n tenantCandidates.add(null)\n if (opts.tenantIdByRecord) {\n for (const val of Object.values(opts.tenantIdByRecord)) {\n tenantCandidates.add(val ? String(val) : null)\n }\n }\n if (opts.tenantFallbacks) {\n for (const val of opts.tenantFallbacks) tenantCandidates.add(val ? String(val) : null)\n }\n const fallbackTenant = (opts.tenantFallbacks || []).find((t) => t != null) ?? null\n\n const tenantList = Array.from(tenantCandidates)\n const tenantNonNull = tenantList.filter((t): t is string => t !== null)\n const tenantFilter = tenantNonNull.length\n ? { tenantId: { $in: [...tenantNonNull, null] as any } }\n : { tenantId: null }\n const cfRows = await em.find(CustomFieldValue, {\n entityId: entityId as any,\n recordId: { $in: normalizedRecordIds as any },\n deletedAt: null,\n ...(tenantList.length ? tenantFilter : {}),\n })\n\n if (!cfRows.length) return {}\n\n const allKeys = Array.from(new Set(cfRows.map((row) => String(row.fieldKey))))\n const organizationCandidates = new Set<string | null>()\n organizationCandidates.add(null)\n if (opts.organizationIdByRecord) {\n for (const val of Object.values(opts.organizationIdByRecord)) {\n organizationCandidates.add(val ? String(val) : null)\n }\n }\n for (const row of cfRows) {\n organizationCandidates.add(row.organizationId ? String(row.organizationId) : null)\n }\n const orgList = Array.from(organizationCandidates)\n\n const defs = allKeys.length\n ? await em.find(CustomFieldDef, {\n entityId: entityId as any,\n key: { $in: allKeys as any },\n deletedAt: null,\n isActive: true,\n ...(tenantList.length ? { tenantId: tenantFilter.tenantId } : {}),\n organizationId: { $in: orgList as any },\n })\n : []\n\n const defsByKey = new Map<string, CustomFieldDef[]>()\n for (const def of defs) {\n const list = defsByKey.get(def.key) || []\n list.push(def)\n defsByKey.set(def.key, list)\n }\n\n const pickDefinition = (fieldKey: string, organizationId: string | null, tenantId: string | null) => {\n const candidates = defsByKey.get(fieldKey)\n if (!candidates || candidates.length === 0) return null\n const active = candidates.filter((opt) => opt.isActive !== false && !opt.deletedAt)\n const list = active.length ? active : candidates\n if (organizationId && tenantId) {\n const exact = list.find((opt) => opt.organizationId === organizationId && opt.tenantId === tenantId)\n if (exact) return exact\n }\n if (organizationId) {\n const orgMatch = list.find((opt) => opt.organizationId === organizationId && (!tenantId || opt.tenantId == null || opt.tenantId === tenantId))\n if (orgMatch) return orgMatch\n }\n if (tenantId) {\n const tenantMatch = list.find((opt) => opt.organizationId == null && opt.tenantId === tenantId)\n if (tenantMatch) return tenantMatch\n }\n const global = list.find((opt) => opt.organizationId == null && opt.tenantId == null)\n return global ?? list[0]\n }\n\n const valueFromRow = (row: CustomFieldValue): unknown => {\n if (row.valueMultiline !== null && row.valueMultiline !== undefined) return row.valueMultiline\n if (row.valueText !== null && row.valueText !== undefined) return row.valueText\n if (row.valueInt !== null && row.valueInt !== undefined) return row.valueInt\n if (row.valueFloat !== null && row.valueFloat !== undefined) return row.valueFloat\n if (row.valueBool !== null && row.valueBool !== undefined) return row.valueBool\n return null\n }\n\n type Bucket = { orgId: string | null; tenantId: string | null; values: unknown[]; def?: CustomFieldDef | null; encrypted?: boolean }\n const buckets = new Map<string, Bucket>()\n\n for (const row of cfRows) {\n const recordId = String(row.recordId)\n const key = String(row.fieldKey)\n const bucketKey = `${recordId}::${key}`\n const orgId = row.organizationId ? String(row.organizationId) : null\n const tenantId = row.tenantId ? String(row.tenantId) : null\n const resolvedOrgId = orgId ?? (opts.organizationIdByRecord?.[recordId] ?? null)\n const resolvedTenantId = tenantId ?? (opts.tenantIdByRecord?.[recordId] ?? fallbackTenant)\n const def = pickDefinition(key, resolvedOrgId, resolvedTenantId)\n const encrypted = Boolean(def?.configJson && (def as any).configJson?.encrypted)\n const value = valueFromRow(row)\n const decrypted = encrypted\n ? await decryptCustomFieldValue(value, resolvedTenantId ?? tenantId ?? null, getEncryptionService(), encryptionCache)\n : value\n const existing = buckets.get(bucketKey)\n if (existing) {\n if (existing.orgId == null && resolvedOrgId) existing.orgId = resolvedOrgId\n if (existing.tenantId == null && resolvedTenantId) existing.tenantId = resolvedTenantId\n if (existing.def == null && def) existing.def = def\n existing.encrypted = existing.encrypted || encrypted\n existing.values.push(decrypted)\n } else {\n buckets.set(bucketKey, { orgId: resolvedOrgId, tenantId: resolvedTenantId, values: [decrypted], def: def ?? null, encrypted })\n }\n }\n\n const result: Record<string, Record<string, unknown>> = {}\n for (const [compoundKey, bucket] of buckets.entries()) {\n const [recordId, fieldKey] = compoundKey.split('::')\n if (!result[recordId]) result[recordId] = {}\n const prefixed = `cf_${fieldKey}`\n const def = bucket.def ?? pickDefinition(fieldKey, bucket.orgId ?? (opts.organizationIdByRecord?.[recordId] ?? null), bucket.tenantId ?? (opts.tenantIdByRecord?.[recordId] ?? null))\n if (def && def.configJson && typeof def.configJson === 'object' && (def.configJson as any).multi) {\n const cleaned = bucket.values.filter((v) => v !== undefined && v !== null)\n result[recordId][prefixed] = cleaned\n } else if (bucket.values.length > 1) {\n const cleaned = bucket.values.filter((v) => v !== undefined)\n result[recordId][prefixed] = cleaned\n } else {\n result[recordId][prefixed] = bucket.values[0] ?? null\n }\n }\n\n return result\n}\n\nexport function summarizeCustomFields(record: Record<string, unknown>): CustomFieldSnapshot {\n const entries = extractAllCustomFieldEntries(record)\n const values = Object.fromEntries(\n Object.entries(entries).map(([prefixedKey, value]) => [\n prefixedKey.replace(/^cf_/, ''),\n value,\n ]),\n )\n const customValues = Object.keys(values).length ? values : null\n const customFields = Object.entries(values).map(([key, value]) => ({\n key,\n label: key,\n value,\n kind: null,\n multi: Array.isArray(value),\n }))\n return { entries, customValues, customFields }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
class CrudHttpError extends Error {
|
|
2
|
+
constructor(status, body) {
|
|
3
|
+
const normalizedBody = typeof body === "string" ? { error: body } : body ?? {};
|
|
4
|
+
super(typeof body === "string" ? body : normalizedBody.error ?? "Request failed");
|
|
5
|
+
this.status = status;
|
|
6
|
+
this.body = normalizedBody;
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
function badRequest(message) {
|
|
10
|
+
return new CrudHttpError(400, { error: message });
|
|
11
|
+
}
|
|
12
|
+
function forbidden(message = "Forbidden") {
|
|
13
|
+
return new CrudHttpError(403, { error: message });
|
|
14
|
+
}
|
|
15
|
+
function notFound(message = "Not found") {
|
|
16
|
+
return new CrudHttpError(404, { error: message });
|
|
17
|
+
}
|
|
18
|
+
export {
|
|
19
|
+
CrudHttpError,
|
|
20
|
+
badRequest,
|
|
21
|
+
forbidden,
|
|
22
|
+
notFound
|
|
23
|
+
};
|
|
24
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/lib/crud/errors.ts"],
|
|
4
|
+
"sourcesContent": ["export class CrudHttpError extends Error {\n status: number\n body: Record<string, any>\n\n constructor(status: number, body?: Record<string, any> | string) {\n const normalizedBody = typeof body === 'string' ? { error: body } : body ?? {}\n super(typeof body === 'string' ? body : normalizedBody.error ?? 'Request failed')\n this.status = status\n this.body = normalizedBody\n }\n}\n\nexport function badRequest(message: string): CrudHttpError {\n return new CrudHttpError(400, { error: message })\n}\n\nexport function forbidden(message = 'Forbidden'): CrudHttpError {\n return new CrudHttpError(403, { error: message })\n}\n\nexport function notFound(message = 'Not found'): CrudHttpError {\n return new CrudHttpError(404, { error: message })\n}\n"],
|
|
5
|
+
"mappings": "AAAO,MAAM,sBAAsB,MAAM;AAAA,EAIvC,YAAY,QAAgB,MAAqC;AAC/D,UAAM,iBAAiB,OAAO,SAAS,WAAW,EAAE,OAAO,KAAK,IAAI,QAAQ,CAAC;AAC7E,UAAM,OAAO,SAAS,WAAW,OAAO,eAAe,SAAS,gBAAgB;AAChF,SAAK,SAAS;AACd,SAAK,OAAO;AAAA,EACd;AACF;AAEO,SAAS,WAAW,SAAgC;AACzD,SAAO,IAAI,cAAc,KAAK,EAAE,OAAO,QAAQ,CAAC;AAClD;AAEO,SAAS,UAAU,UAAU,aAA4B;AAC9D,SAAO,IAAI,cAAc,KAAK,EAAE,OAAO,QAAQ,CAAC;AAClD;AAEO,SAAS,SAAS,UAAU,aAA4B;AAC7D,SAAO,IAAI,cAAc,KAAK,EAAE,OAAO,QAAQ,CAAC;AAClD;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|