@open-mercato/core 0.7.1-develop.7154.1.981330c924 → 0.7.1-develop.7171.1.9b31dbba45
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/.turbo/turbo-build.log +1 -1
- package/AGENTS.md +2 -2
- package/dist/modules/auth/commands/users.js +14 -1
- package/dist/modules/auth/commands/users.js.map +2 -2
- package/dist/modules/auth/data/entities.js +2 -2
- package/dist/modules/auth/data/entities.js.map +2 -2
- package/dist/modules/auth/lib/backendChrome.js +26 -3
- package/dist/modules/auth/lib/backendChrome.js.map +2 -2
- package/dist/modules/auth/lib/profile-sections.js +1 -1
- package/dist/modules/auth/lib/profile-sections.js.map +2 -2
- package/dist/modules/auth/migrations/Migration20260907120000_auth.js +19 -0
- package/dist/modules/auth/migrations/Migration20260907120000_auth.js.map +7 -0
- package/dist/modules/communication_channels/backend/profile/communication-channels/page.meta.js +2 -2
- package/dist/modules/communication_channels/backend/profile/communication-channels/page.meta.js.map +1 -1
- package/dist/modules/customer_accounts/api/admin/demo-accounts.js +118 -0
- package/dist/modules/customer_accounts/api/admin/demo-accounts.js.map +7 -0
- package/dist/modules/customer_accounts/api/invitations/accept.js +23 -6
- package/dist/modules/customer_accounts/api/invitations/accept.js.map +2 -2
- package/dist/modules/customer_accounts/backend/customer_accounts/settings/CustomerAccountsSettingsPageClient.js +10 -13
- package/dist/modules/customer_accounts/backend/customer_accounts/settings/CustomerAccountsSettingsPageClient.js.map +2 -2
- package/dist/modules/customer_accounts/backend/customer_accounts/useDemoPortalAccounts.js +28 -0
- package/dist/modules/customer_accounts/backend/customer_accounts/useDemoPortalAccounts.js.map +7 -0
- package/dist/modules/customer_accounts/backend/customer_accounts/users/PortalUsersPageClient.js +6 -1
- package/dist/modules/customer_accounts/backend/customer_accounts/users/PortalUsersPageClient.js.map +2 -2
- package/dist/modules/customer_accounts/data/entities.js +4 -1
- package/dist/modules/customer_accounts/data/entities.js.map +2 -2
- package/dist/modules/customer_accounts/lib/exampleAccounts.js +9 -0
- package/dist/modules/customer_accounts/lib/exampleAccounts.js.map +7 -0
- package/dist/modules/customer_accounts/migrations/Migration20260827160000_customer_accounts.js +16 -0
- package/dist/modules/customer_accounts/migrations/Migration20260827160000_customer_accounts.js.map +7 -0
- package/dist/modules/customer_accounts/services/customerInvitationService.js +53 -6
- package/dist/modules/customer_accounts/services/customerInvitationService.js.map +2 -2
- package/dist/modules/customer_accounts/setup.js +2 -6
- package/dist/modules/customer_accounts/setup.js.map +2 -2
- package/dist/modules/customer_accounts/widgets/injection/account-status/widget.client.js +55 -40
- package/dist/modules/customer_accounts/widgets/injection/account-status/widget.client.js.map +2 -2
- package/dist/modules/customers/commands/people.js +16 -1
- package/dist/modules/customers/commands/people.js.map +2 -2
- package/dist/modules/data_sync/backend/data-sync/runs/[id]/page.js +18 -36
- package/dist/modules/data_sync/backend/data-sync/runs/[id]/page.js.map +2 -2
- package/dist/modules/entities/api/records.js +18 -15
- package/dist/modules/entities/api/records.js.map +3 -3
- package/dist/modules/entities/lib/scoped-field-defs.js +52 -0
- package/dist/modules/entities/lib/scoped-field-defs.js.map +7 -0
- package/dist/modules/entities/lib/validation.js +4 -35
- package/dist/modules/entities/lib/validation.js.map +2 -2
- package/dist/modules/integrations/backend/integrations/[id]/page.js +32 -54
- package/dist/modules/integrations/backend/integrations/[id]/page.js.map +2 -2
- package/dist/modules/integrations/backend/integrations/bundle/[id]/page.js +12 -29
- package/dist/modules/integrations/backend/integrations/bundle/[id]/page.js.map +2 -2
- package/dist/modules/notifications/backend/profile/notification-preferences/page.meta.js +2 -2
- package/dist/modules/notifications/backend/profile/notification-preferences/page.meta.js.map +1 -1
- package/dist/modules/progress/lib/progressServiceImpl.js +14 -3
- package/dist/modules/progress/lib/progressServiceImpl.js.map +2 -2
- package/dist/modules/sales/backend/sales/documents/[id]/page.js +9 -9
- package/dist/modules/sales/backend/sales/documents/[id]/page.js.map +2 -2
- package/dist/modules/sales/components/documents/LineItemDialog.js +50 -10
- package/dist/modules/sales/components/documents/LineItemDialog.js.map +2 -2
- package/dist/modules/sales/components/documents/PaymentsSection.js +8 -3
- package/dist/modules/sales/components/documents/PaymentsSection.js.map +2 -2
- package/dist/modules/sales/components/documents/ReturnEditDialog.js +2 -7
- package/dist/modules/sales/components/documents/ReturnEditDialog.js.map +2 -2
- package/dist/modules/sales/components/documents/ReturnsSection.js +2 -7
- package/dist/modules/sales/components/documents/ReturnsSection.js.map +2 -2
- package/dist/modules/sales/components/documents/ShipmentsSection.js +3 -8
- package/dist/modules/sales/components/documents/ShipmentsSection.js.map +2 -2
- package/dist/modules/wms/commands/sales-order-assignment.js +12 -0
- package/dist/modules/wms/commands/sales-order-assignment.js.map +2 -2
- package/dist/modules/wms/data/enrichers.js +25 -0
- package/dist/modules/wms/data/enrichers.js.map +2 -2
- package/dist/modules/wms/lib/enricherCacheTags.js +9 -0
- package/dist/modules/wms/lib/enricherCacheTags.js.map +7 -0
- package/dist/modules/wms/lib/invalidateInventoryEnricherCache.js +37 -0
- package/dist/modules/wms/lib/invalidateInventoryEnricherCache.js.map +7 -0
- package/dist/modules/wms/lib/inventoryEnricherCacheSubscriber.js +14 -0
- package/dist/modules/wms/lib/inventoryEnricherCacheSubscriber.js.map +7 -0
- package/dist/modules/wms/subscribers/invalidate-enricher-cache-balance.js +12 -0
- package/dist/modules/wms/subscribers/invalidate-enricher-cache-balance.js.map +7 -0
- package/dist/modules/wms/subscribers/invalidate-enricher-cache-inventory.js +12 -0
- package/dist/modules/wms/subscribers/invalidate-enricher-cache-inventory.js.map +7 -0
- package/dist/modules/wms/subscribers/invalidate-enricher-cache-movement.js +12 -0
- package/dist/modules/wms/subscribers/invalidate-enricher-cache-movement.js.map +7 -0
- package/dist/modules/wms/subscribers/invalidate-enricher-cache-profile.js +12 -0
- package/dist/modules/wms/subscribers/invalidate-enricher-cache-profile.js.map +7 -0
- package/dist/modules/wms/subscribers/invalidate-enricher-cache-reservation.js +12 -0
- package/dist/modules/wms/subscribers/invalidate-enricher-cache-reservation.js.map +7 -0
- package/dist/modules/wms/subscribers/invalidate-enricher-cache-sales-line.js +12 -0
- package/dist/modules/wms/subscribers/invalidate-enricher-cache-sales-line.js.map +7 -0
- package/dist/modules/wms/subscribers/invalidate-enricher-cache-sales-order.js +12 -0
- package/dist/modules/wms/subscribers/invalidate-enricher-cache-sales-order.js.map +7 -0
- package/dist/modules/wms/subscribers/invalidate-enricher-cache-variant.js +12 -0
- package/dist/modules/wms/subscribers/invalidate-enricher-cache-variant.js.map +7 -0
- package/dist/modules/wms/subscribers/invalidate-enricher-cache-warehouse.js +12 -0
- package/dist/modules/wms/subscribers/invalidate-enricher-cache-warehouse.js.map +7 -0
- package/package.json +7 -7
- package/src/modules/auth/commands/users.ts +14 -1
- package/src/modules/auth/data/entities.ts +2 -2
- package/src/modules/auth/lib/backendChrome.tsx +46 -2
- package/src/modules/auth/lib/profile-sections.tsx +14 -3
- package/src/modules/auth/migrations/.snapshot-open-mercato.json +4 -2
- package/src/modules/auth/migrations/Migration20260907120000_auth.ts +21 -0
- package/src/modules/communication_channels/backend/profile/communication-channels/page.meta.ts +2 -2
- package/src/modules/customer_accounts/AGENTS.md +3 -1
- package/src/modules/customer_accounts/api/admin/demo-accounts.ts +149 -0
- package/src/modules/customer_accounts/api/invitations/accept.ts +23 -6
- package/src/modules/customer_accounts/backend/customer_accounts/settings/CustomerAccountsSettingsPageClient.tsx +43 -41
- package/src/modules/customer_accounts/backend/customer_accounts/useDemoPortalAccounts.ts +42 -0
- package/src/modules/customer_accounts/backend/customer_accounts/users/PortalUsersPageClient.tsx +10 -3
- package/src/modules/customer_accounts/data/entities.ts +5 -1
- package/src/modules/customer_accounts/i18n/de.json +4 -2
- package/src/modules/customer_accounts/i18n/en.json +4 -2
- package/src/modules/customer_accounts/i18n/es.json +4 -2
- package/src/modules/customer_accounts/i18n/ko.json +4 -2
- package/src/modules/customer_accounts/i18n/pl.json +4 -2
- package/src/modules/customer_accounts/lib/exampleAccounts.ts +18 -0
- package/src/modules/customer_accounts/migrations/.snapshot-open-mercato.json +5 -7
- package/src/modules/customer_accounts/migrations/Migration20260827160000_customer_accounts.ts +23 -0
- package/src/modules/customer_accounts/services/customerInvitationService.ts +89 -5
- package/src/modules/customer_accounts/setup.ts +2 -6
- package/src/modules/customer_accounts/widgets/injection/account-status/widget.client.tsx +74 -41
- package/src/modules/customers/commands/people.ts +15 -0
- package/src/modules/data_sync/backend/data-sync/runs/[id]/page.tsx +19 -44
- package/src/modules/entities/api/records.ts +24 -15
- package/src/modules/entities/lib/scoped-field-defs.ts +76 -0
- package/src/modules/entities/lib/validation.ts +5 -45
- package/src/modules/integrations/backend/integrations/[id]/page.tsx +33 -62
- package/src/modules/integrations/backend/integrations/bundle/[id]/page.tsx +13 -37
- package/src/modules/notifications/backend/profile/notification-preferences/page.meta.ts +2 -2
- package/src/modules/progress/AGENTS.md +1 -1
- package/src/modules/progress/lib/progressServiceImpl.ts +26 -3
- package/src/modules/sales/backend/sales/documents/[id]/page.tsx +19 -25
- package/src/modules/sales/components/documents/LineItemDialog.tsx +53 -9
- package/src/modules/sales/components/documents/PaymentsSection.tsx +8 -8
- package/src/modules/sales/components/documents/ReturnEditDialog.tsx +2 -8
- package/src/modules/sales/components/documents/ReturnsSection.tsx +8 -7
- package/src/modules/sales/components/documents/ShipmentsSection.tsx +9 -8
- package/src/modules/sales/i18n/de.json +2 -0
- package/src/modules/sales/i18n/en.json +2 -0
- package/src/modules/sales/i18n/es.json +2 -0
- package/src/modules/sales/i18n/ko.json +2 -0
- package/src/modules/sales/i18n/pl.json +2 -0
- package/src/modules/wms/commands/sales-order-assignment.ts +20 -0
- package/src/modules/wms/data/enrichers.ts +25 -0
- package/src/modules/wms/lib/enricherCacheTags.ts +29 -0
- package/src/modules/wms/lib/invalidateInventoryEnricherCache.ts +71 -0
- package/src/modules/wms/lib/inventoryEnricherCacheSubscriber.ts +30 -0
- package/src/modules/wms/subscribers/invalidate-enricher-cache-balance.ts +9 -0
- package/src/modules/wms/subscribers/invalidate-enricher-cache-inventory.ts +9 -0
- package/src/modules/wms/subscribers/invalidate-enricher-cache-movement.ts +9 -0
- package/src/modules/wms/subscribers/invalidate-enricher-cache-profile.ts +9 -0
- package/src/modules/wms/subscribers/invalidate-enricher-cache-reservation.ts +9 -0
- package/src/modules/wms/subscribers/invalidate-enricher-cache-sales-line.ts +14 -0
- package/src/modules/wms/subscribers/invalidate-enricher-cache-sales-order.ts +18 -0
- package/src/modules/wms/subscribers/invalidate-enricher-cache-variant.ts +9 -0
- package/src/modules/wms/subscribers/invalidate-enricher-cache-warehouse.ts +9 -0
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/modules/wms/lib/enricherCacheTags.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Cache tags shared by the WMS inventory enrichers and the write surfaces that\n * invalidate them. Read side and write side MUST use these constants so the two\n * cannot drift \u2014 a tag typo on either side is silent, and the only symptom is\n * inventory that stays stale until the TTL expires.\n *\n * The enricher runner adds `tenant:`, `organization:` and `enricher:` tags of\n * its own, and the cache service prefixes every tag with the current cache\n * tenant, so these are deliberately coarse collection tags rather than\n * per-warehouse ones: `ResponseEnricher.cache.tags` is a static array read from\n * the enricher definition and cannot vary per call. Collection tags\n * over-invalidate slightly; a per-warehouse scheme that the write side could\n * miss would under-invalidate, which is the failure that actually shows wrong\n * stock to a user.\n */\n\n/** Inventory quantities: balances, reservations, movements and profiles. */\nexport const WMS_INVENTORY_CACHE_TAG = 'wms:inventory'\n\n/** Warehouse identity and sales-order warehouse assignment. */\nexport const WMS_WAREHOUSE_CACHE_TAG = 'wms:warehouse'\n\n/**\n * Short by design. The tag invalidations below are the primary freshness\n * mechanism; this TTL is the unconditional backstop for anything they miss \u2014\n * a write that failed to resolve the cache service, a cross-process race, or a\n * write surface added later without wiring invalidation.\n */\nexport const WMS_ENRICHER_CACHE_TTL_MS = 30_000\n"],
|
|
5
|
+
"mappings": "AAiBO,MAAM,0BAA0B;AAGhC,MAAM,0BAA0B;AAQhC,MAAM,4BAA4B;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { runWithCacheTenant } from "@open-mercato/cache";
|
|
2
|
+
import { createLogger } from "@open-mercato/shared/lib/logger";
|
|
3
|
+
import {
|
|
4
|
+
WMS_INVENTORY_CACHE_TAG,
|
|
5
|
+
WMS_WAREHOUSE_CACHE_TAG
|
|
6
|
+
} from "./enricherCacheTags.js";
|
|
7
|
+
const logger = createLogger("wms").child({ component: "enricher-cache" });
|
|
8
|
+
function resolveCache(container) {
|
|
9
|
+
if (!container?.resolve) return null;
|
|
10
|
+
for (const name of ["cache", "cacheService"]) {
|
|
11
|
+
try {
|
|
12
|
+
const candidate = container.resolve(name);
|
|
13
|
+
if (candidate && typeof candidate.deleteByTags === "function") return candidate;
|
|
14
|
+
} catch {
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
function tagsForScope(scope) {
|
|
20
|
+
if (scope === "inventory") return [WMS_INVENTORY_CACHE_TAG];
|
|
21
|
+
if (scope === "warehouse") return [WMS_WAREHOUSE_CACHE_TAG];
|
|
22
|
+
return [WMS_INVENTORY_CACHE_TAG, WMS_WAREHOUSE_CACHE_TAG];
|
|
23
|
+
}
|
|
24
|
+
async function invalidateWmsInventoryEnricherCache(container, tenantId, scope = "all") {
|
|
25
|
+
if (!tenantId) return;
|
|
26
|
+
const cache = resolveCache(container);
|
|
27
|
+
if (!cache) return;
|
|
28
|
+
try {
|
|
29
|
+
await runWithCacheTenant(tenantId, () => cache.deleteByTags(tagsForScope(scope)));
|
|
30
|
+
} catch (err) {
|
|
31
|
+
logger.warn("Failed to invalidate WMS inventory enricher cache", { tenantId, scope, err });
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
export {
|
|
35
|
+
invalidateWmsInventoryEnricherCache
|
|
36
|
+
};
|
|
37
|
+
//# sourceMappingURL=invalidateInventoryEnricherCache.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/modules/wms/lib/invalidateInventoryEnricherCache.ts"],
|
|
4
|
+
"sourcesContent": ["// Drop the cached WMS inventory enrichment for a tenant after a write that\n// changed the data it was derived from.\n//\n// The three WMS inventory enrichers cache their cross-module reads read-through\n// with a short TTL (see `enricherCacheTags.ts`). Every write surface that moves\n// balances, reservations, movements, profiles, warehouses or the sales-order\n// warehouse assignment drops the matching tags here, so a user sees the new\n// stock on the next request rather than after the TTL.\n//\n// The cache service prefixes tags with the *current* cache tenant, which is an\n// AsyncLocalStorage value set on the request path. A subscriber or command side\n// effect running outside that scope would otherwise write its invalidation\n// against the `tenant:global:` prefix and silently miss every entry the request\n// path stored. `runWithCacheTenant` re-enters the right scope, mirroring\n// `directory/subscribers/invalidateOrgScopeCache.ts`.\n\nimport { runWithCacheTenant } from '@open-mercato/cache'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\nimport {\n WMS_INVENTORY_CACHE_TAG,\n WMS_WAREHOUSE_CACHE_TAG,\n} from './enricherCacheTags'\n\nconst logger = createLogger('wms').child({ component: 'enricher-cache' })\n\ntype CacheService = {\n deleteByTags(tags: string[]): Promise<number>\n}\n\nexport type EnricherCacheScope = 'inventory' | 'warehouse' | 'all'\n\ntype Resolver = { resolve: <T = unknown>(name: string) => T }\n\nfunction resolveCache(container: Resolver | null | undefined): CacheService | null {\n if (!container?.resolve) return null\n for (const name of ['cache', 'cacheService']) {\n try {\n const candidate = container.resolve<CacheService>(name)\n if (candidate && typeof candidate.deleteByTags === 'function') return candidate\n } catch {\n // try the next registration name\n }\n }\n return null\n}\n\nfunction tagsForScope(scope: EnricherCacheScope): string[] {\n if (scope === 'inventory') return [WMS_INVENTORY_CACHE_TAG]\n if (scope === 'warehouse') return [WMS_WAREHOUSE_CACHE_TAG]\n return [WMS_INVENTORY_CACHE_TAG, WMS_WAREHOUSE_CACHE_TAG]\n}\n\n/**\n * Best-effort tag invalidation. A failure is logged and swallowed: an\n * invalidation that throws must never fail the write that triggered it, and the\n * enricher TTL bounds how long a missed drop can serve stale data.\n */\nexport async function invalidateWmsInventoryEnricherCache(\n container: Resolver | null | undefined,\n tenantId: string | null | undefined,\n scope: EnricherCacheScope = 'all',\n): Promise<void> {\n if (!tenantId) return\n const cache = resolveCache(container)\n if (!cache) return\n try {\n await runWithCacheTenant(tenantId, () => cache.deleteByTags(tagsForScope(scope)))\n } catch (err) {\n logger.warn('Failed to invalidate WMS inventory enricher cache', { tenantId, scope, err })\n }\n}\n"],
|
|
5
|
+
"mappings": "AAgBA,SAAS,0BAA0B;AACnC,SAAS,oBAAoB;AAC7B;AAAA,EACE;AAAA,EACA;AAAA,OACK;AAEP,MAAM,SAAS,aAAa,KAAK,EAAE,MAAM,EAAE,WAAW,iBAAiB,CAAC;AAUxE,SAAS,aAAa,WAA6D;AACjF,MAAI,CAAC,WAAW,QAAS,QAAO;AAChC,aAAW,QAAQ,CAAC,SAAS,cAAc,GAAG;AAC5C,QAAI;AACF,YAAM,YAAY,UAAU,QAAsB,IAAI;AACtD,UAAI,aAAa,OAAO,UAAU,iBAAiB,WAAY,QAAO;AAAA,IACxE,QAAQ;AAAA,IAER;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,aAAa,OAAqC;AACzD,MAAI,UAAU,YAAa,QAAO,CAAC,uBAAuB;AAC1D,MAAI,UAAU,YAAa,QAAO,CAAC,uBAAuB;AAC1D,SAAO,CAAC,yBAAyB,uBAAuB;AAC1D;AAOA,eAAsB,oCACpB,WACA,UACA,QAA4B,OACb;AACf,MAAI,CAAC,SAAU;AACf,QAAM,QAAQ,aAAa,SAAS;AACpC,MAAI,CAAC,MAAO;AACZ,MAAI;AACF,UAAM,mBAAmB,UAAU,MAAM,MAAM,aAAa,aAAa,KAAK,CAAC,CAAC;AAAA,EAClF,SAAS,KAAK;AACZ,WAAO,KAAK,qDAAqD,EAAE,UAAU,OAAO,IAAI,CAAC;AAAA,EAC3F;AACF;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import {
|
|
2
|
+
invalidateWmsInventoryEnricherCache
|
|
3
|
+
} from "./invalidateInventoryEnricherCache.js";
|
|
4
|
+
function createInventoryEnricherCacheHandler(scope) {
|
|
5
|
+
return async function handle(payload, ctx) {
|
|
6
|
+
const data = payload ?? {};
|
|
7
|
+
const tenantId = typeof data.tenantId === "string" && data.tenantId.length > 0 ? data.tenantId : ctx.tenantId ?? null;
|
|
8
|
+
await invalidateWmsInventoryEnricherCache(ctx, tenantId, scope);
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
export {
|
|
12
|
+
createInventoryEnricherCacheHandler
|
|
13
|
+
};
|
|
14
|
+
//# sourceMappingURL=inventoryEnricherCacheSubscriber.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/modules/wms/lib/inventoryEnricherCacheSubscriber.ts"],
|
|
4
|
+
"sourcesContent": ["// Shared handler behind the WMS inventory enricher-cache invalidation\n// subscribers. Each subscriber file binds it to one event pattern, because\n// `metadata.event` takes a single pattern and the matcher is single-segment \u2014\n// `wms.*` does NOT match `wms.inventory_balance.created`, so every event family\n// the enrichers read from is registered explicitly.\n//\n// It lives here rather than under `subscribers/` because the module generator\n// scans that directory recursively and treats every file it finds as a\n// subscriber.\n\nimport {\n invalidateWmsInventoryEnricherCache,\n type EnricherCacheScope,\n} from './invalidateInventoryEnricherCache'\n\ntype SubscriberContext = {\n resolve: <T = unknown>(name: string) => T\n tenantId?: string | null\n}\n\nexport function createInventoryEnricherCacheHandler(scope: EnricherCacheScope) {\n return async function handle(payload: unknown, ctx: SubscriberContext): Promise<void> {\n const data = (payload ?? {}) as Record<string, unknown>\n const tenantId =\n typeof data.tenantId === 'string' && data.tenantId.length > 0\n ? data.tenantId\n : ctx.tenantId ?? null\n await invalidateWmsInventoryEnricherCache(ctx, tenantId, scope)\n }\n}\n"],
|
|
5
|
+
"mappings": "AAUA;AAAA,EACE;AAAA,OAEK;AAOA,SAAS,oCAAoC,OAA2B;AAC7E,SAAO,eAAe,OAAO,SAAkB,KAAuC;AACpF,UAAM,OAAQ,WAAW,CAAC;AAC1B,UAAM,WACJ,OAAO,KAAK,aAAa,YAAY,KAAK,SAAS,SAAS,IACxD,KAAK,WACL,IAAI,YAAY;AACtB,UAAM,oCAAoC,KAAK,UAAU,KAAK;AAAA,EAChE;AACF;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { createInventoryEnricherCacheHandler } from "../lib/inventoryEnricherCacheSubscriber.js";
|
|
2
|
+
const metadata = {
|
|
3
|
+
event: "wms.inventory_balance.*",
|
|
4
|
+
persistent: false,
|
|
5
|
+
id: "wms:invalidate-enricher-cache-balance"
|
|
6
|
+
};
|
|
7
|
+
var invalidate_enricher_cache_balance_default = createInventoryEnricherCacheHandler("inventory");
|
|
8
|
+
export {
|
|
9
|
+
invalidate_enricher_cache_balance_default as default,
|
|
10
|
+
metadata
|
|
11
|
+
};
|
|
12
|
+
//# sourceMappingURL=invalidate-enricher-cache-balance.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/modules/wms/subscribers/invalidate-enricher-cache-balance.ts"],
|
|
4
|
+
"sourcesContent": ["import { createInventoryEnricherCacheHandler } from '../lib/inventoryEnricherCacheSubscriber'\n\nexport const metadata = {\n event: 'wms.inventory_balance.*',\n persistent: false,\n id: 'wms:invalidate-enricher-cache-balance',\n}\n\nexport default createInventoryEnricherCacheHandler('inventory')\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,2CAA2C;AAE7C,MAAM,WAAW;AAAA,EACtB,OAAO;AAAA,EACP,YAAY;AAAA,EACZ,IAAI;AACN;AAEA,IAAO,4CAAQ,oCAAoC,WAAW;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { createInventoryEnricherCacheHandler } from "../lib/inventoryEnricherCacheSubscriber.js";
|
|
2
|
+
const metadata = {
|
|
3
|
+
event: "wms.inventory.*",
|
|
4
|
+
persistent: false,
|
|
5
|
+
id: "wms:invalidate-enricher-cache-inventory"
|
|
6
|
+
};
|
|
7
|
+
var invalidate_enricher_cache_inventory_default = createInventoryEnricherCacheHandler("inventory");
|
|
8
|
+
export {
|
|
9
|
+
invalidate_enricher_cache_inventory_default as default,
|
|
10
|
+
metadata
|
|
11
|
+
};
|
|
12
|
+
//# sourceMappingURL=invalidate-enricher-cache-inventory.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/modules/wms/subscribers/invalidate-enricher-cache-inventory.ts"],
|
|
4
|
+
"sourcesContent": ["import { createInventoryEnricherCacheHandler } from '../lib/inventoryEnricherCacheSubscriber'\n\nexport const metadata = {\n event: 'wms.inventory.*',\n persistent: false,\n id: 'wms:invalidate-enricher-cache-inventory',\n}\n\nexport default createInventoryEnricherCacheHandler('inventory')\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,2CAA2C;AAE7C,MAAM,WAAW;AAAA,EACtB,OAAO;AAAA,EACP,YAAY;AAAA,EACZ,IAAI;AACN;AAEA,IAAO,8CAAQ,oCAAoC,WAAW;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { createInventoryEnricherCacheHandler } from "../lib/inventoryEnricherCacheSubscriber.js";
|
|
2
|
+
const metadata = {
|
|
3
|
+
event: "wms.inventory_movement.*",
|
|
4
|
+
persistent: false,
|
|
5
|
+
id: "wms:invalidate-enricher-cache-movement"
|
|
6
|
+
};
|
|
7
|
+
var invalidate_enricher_cache_movement_default = createInventoryEnricherCacheHandler("inventory");
|
|
8
|
+
export {
|
|
9
|
+
invalidate_enricher_cache_movement_default as default,
|
|
10
|
+
metadata
|
|
11
|
+
};
|
|
12
|
+
//# sourceMappingURL=invalidate-enricher-cache-movement.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/modules/wms/subscribers/invalidate-enricher-cache-movement.ts"],
|
|
4
|
+
"sourcesContent": ["import { createInventoryEnricherCacheHandler } from '../lib/inventoryEnricherCacheSubscriber'\n\nexport const metadata = {\n event: 'wms.inventory_movement.*',\n persistent: false,\n id: 'wms:invalidate-enricher-cache-movement',\n}\n\nexport default createInventoryEnricherCacheHandler('inventory')\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,2CAA2C;AAE7C,MAAM,WAAW;AAAA,EACtB,OAAO;AAAA,EACP,YAAY;AAAA,EACZ,IAAI;AACN;AAEA,IAAO,6CAAQ,oCAAoC,WAAW;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { createInventoryEnricherCacheHandler } from "../lib/inventoryEnricherCacheSubscriber.js";
|
|
2
|
+
const metadata = {
|
|
3
|
+
event: "wms.inventory_profile.*",
|
|
4
|
+
persistent: false,
|
|
5
|
+
id: "wms:invalidate-enricher-cache-profile"
|
|
6
|
+
};
|
|
7
|
+
var invalidate_enricher_cache_profile_default = createInventoryEnricherCacheHandler("inventory");
|
|
8
|
+
export {
|
|
9
|
+
invalidate_enricher_cache_profile_default as default,
|
|
10
|
+
metadata
|
|
11
|
+
};
|
|
12
|
+
//# sourceMappingURL=invalidate-enricher-cache-profile.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/modules/wms/subscribers/invalidate-enricher-cache-profile.ts"],
|
|
4
|
+
"sourcesContent": ["import { createInventoryEnricherCacheHandler } from '../lib/inventoryEnricherCacheSubscriber'\n\nexport const metadata = {\n event: 'wms.inventory_profile.*',\n persistent: false,\n id: 'wms:invalidate-enricher-cache-profile',\n}\n\nexport default createInventoryEnricherCacheHandler('inventory')\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,2CAA2C;AAE7C,MAAM,WAAW;AAAA,EACtB,OAAO;AAAA,EACP,YAAY;AAAA,EACZ,IAAI;AACN;AAEA,IAAO,4CAAQ,oCAAoC,WAAW;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { createInventoryEnricherCacheHandler } from "../lib/inventoryEnricherCacheSubscriber.js";
|
|
2
|
+
const metadata = {
|
|
3
|
+
event: "wms.inventory_reservation.*",
|
|
4
|
+
persistent: false,
|
|
5
|
+
id: "wms:invalidate-enricher-cache-reservation"
|
|
6
|
+
};
|
|
7
|
+
var invalidate_enricher_cache_reservation_default = createInventoryEnricherCacheHandler("inventory");
|
|
8
|
+
export {
|
|
9
|
+
invalidate_enricher_cache_reservation_default as default,
|
|
10
|
+
metadata
|
|
11
|
+
};
|
|
12
|
+
//# sourceMappingURL=invalidate-enricher-cache-reservation.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/modules/wms/subscribers/invalidate-enricher-cache-reservation.ts"],
|
|
4
|
+
"sourcesContent": ["import { createInventoryEnricherCacheHandler } from '../lib/inventoryEnricherCacheSubscriber'\n\nexport const metadata = {\n event: 'wms.inventory_reservation.*',\n persistent: false,\n id: 'wms:invalidate-enricher-cache-reservation',\n}\n\nexport default createInventoryEnricherCacheHandler('inventory')\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,2CAA2C;AAE7C,MAAM,WAAW;AAAA,EACtB,OAAO;AAAA,EACP,YAAY;AAAA,EACZ,IAAI;AACN;AAEA,IAAO,gDAAQ,oCAAoC,WAAW;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { createInventoryEnricherCacheHandler } from "../lib/inventoryEnricherCacheSubscriber.js";
|
|
2
|
+
const metadata = {
|
|
3
|
+
event: "sales.line.*",
|
|
4
|
+
persistent: false,
|
|
5
|
+
id: "wms:invalidate-enricher-cache-sales-line"
|
|
6
|
+
};
|
|
7
|
+
var invalidate_enricher_cache_sales_line_default = createInventoryEnricherCacheHandler("warehouse");
|
|
8
|
+
export {
|
|
9
|
+
invalidate_enricher_cache_sales_line_default as default,
|
|
10
|
+
metadata
|
|
11
|
+
};
|
|
12
|
+
//# sourceMappingURL=invalidate-enricher-cache-sales-line.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/modules/wms/subscribers/invalidate-enricher-cache-sales-line.ts"],
|
|
4
|
+
"sourcesContent": ["import { createInventoryEnricherCacheHandler } from '../lib/inventoryEnricherCacheSubscriber'\n\n// The sales module declares `sales.line.*` in its event registry and documents\n// it publicly, but no write surface emits it today \u2014 line writes ride the order\n// commands' `sales.order.*`. Registering the pattern anyway costs one ephemeral\n// subscription and means that wiring those events later cannot silently\n// reintroduce the staleness `invalidate-enricher-cache-sales-order.ts` closes.\nexport const metadata = {\n event: 'sales.line.*',\n persistent: false,\n id: 'wms:invalidate-enricher-cache-sales-line',\n}\n\nexport default createInventoryEnricherCacheHandler('warehouse')\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,2CAA2C;AAO7C,MAAM,WAAW;AAAA,EACtB,OAAO;AAAA,EACP,YAAY;AAAA,EACZ,IAAI;AACN;AAEA,IAAO,+CAAQ,oCAAoC,WAAW;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { createInventoryEnricherCacheHandler } from "../lib/inventoryEnricherCacheSubscriber.js";
|
|
2
|
+
const metadata = {
|
|
3
|
+
event: "sales.order.*",
|
|
4
|
+
persistent: false,
|
|
5
|
+
id: "wms:invalidate-enricher-cache-sales-order"
|
|
6
|
+
};
|
|
7
|
+
var invalidate_enricher_cache_sales_order_default = createInventoryEnricherCacheHandler("warehouse");
|
|
8
|
+
export {
|
|
9
|
+
invalidate_enricher_cache_sales_order_default as default,
|
|
10
|
+
metadata
|
|
11
|
+
};
|
|
12
|
+
//# sourceMappingURL=invalidate-enricher-cache-sales-order.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/modules/wms/subscribers/invalidate-enricher-cache-sales-order.ts"],
|
|
4
|
+
"sourcesContent": ["import { createInventoryEnricherCacheHandler } from '../lib/inventoryEnricherCacheSubscriber'\n\n// `wms.sales-order-inventory` reads the order's lines, and both the required\n// quantity behind `reservationSummary.status` and the variant list behind\n// `stockSummary` come from them. Order lines are written inside the sales order\n// commands, which emit `sales.order.*` \u2014 not a WMS event \u2014 so without this the\n// enrichment would stay stale for the whole TTL after a line edit.\n//\n// Scope `warehouse` rather than `inventory`: `wms:warehouse` is declared by the\n// sales-order enricher alone, so this drops exactly its entries and leaves the\n// two catalog enrichers' caches intact.\nexport const metadata = {\n event: 'sales.order.*',\n persistent: false,\n id: 'wms:invalidate-enricher-cache-sales-order',\n}\n\nexport default createInventoryEnricherCacheHandler('warehouse')\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,2CAA2C;AAW7C,MAAM,WAAW;AAAA,EACtB,OAAO;AAAA,EACP,YAAY;AAAA,EACZ,IAAI;AACN;AAEA,IAAO,gDAAQ,oCAAoC,WAAW;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { createInventoryEnricherCacheHandler } from "../lib/inventoryEnricherCacheSubscriber.js";
|
|
2
|
+
const metadata = {
|
|
3
|
+
event: "catalog.variant.*",
|
|
4
|
+
persistent: false,
|
|
5
|
+
id: "wms:invalidate-enricher-cache-variant"
|
|
6
|
+
};
|
|
7
|
+
var invalidate_enricher_cache_variant_default = createInventoryEnricherCacheHandler("inventory");
|
|
8
|
+
export {
|
|
9
|
+
invalidate_enricher_cache_variant_default as default,
|
|
10
|
+
metadata
|
|
11
|
+
};
|
|
12
|
+
//# sourceMappingURL=invalidate-enricher-cache-variant.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/modules/wms/subscribers/invalidate-enricher-cache-variant.ts"],
|
|
4
|
+
"sourcesContent": ["import { createInventoryEnricherCacheHandler } from '../lib/inventoryEnricherCacheSubscriber'\n\nexport const metadata = {\n event: 'catalog.variant.*',\n persistent: false,\n id: 'wms:invalidate-enricher-cache-variant',\n}\n\nexport default createInventoryEnricherCacheHandler('inventory')\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,2CAA2C;AAE7C,MAAM,WAAW;AAAA,EACtB,OAAO;AAAA,EACP,YAAY;AAAA,EACZ,IAAI;AACN;AAEA,IAAO,4CAAQ,oCAAoC,WAAW;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { createInventoryEnricherCacheHandler } from "../lib/inventoryEnricherCacheSubscriber.js";
|
|
2
|
+
const metadata = {
|
|
3
|
+
event: "wms.warehouse.*",
|
|
4
|
+
persistent: false,
|
|
5
|
+
id: "wms:invalidate-enricher-cache-warehouse"
|
|
6
|
+
};
|
|
7
|
+
var invalidate_enricher_cache_warehouse_default = createInventoryEnricherCacheHandler("warehouse");
|
|
8
|
+
export {
|
|
9
|
+
invalidate_enricher_cache_warehouse_default as default,
|
|
10
|
+
metadata
|
|
11
|
+
};
|
|
12
|
+
//# sourceMappingURL=invalidate-enricher-cache-warehouse.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/modules/wms/subscribers/invalidate-enricher-cache-warehouse.ts"],
|
|
4
|
+
"sourcesContent": ["import { createInventoryEnricherCacheHandler } from '../lib/inventoryEnricherCacheSubscriber'\n\nexport const metadata = {\n event: 'wms.warehouse.*',\n persistent: false,\n id: 'wms:invalidate-enricher-cache-warehouse',\n}\n\nexport default createInventoryEnricherCacheHandler('warehouse')\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,2CAA2C;AAE7C,MAAM,WAAW;AAAA,EACtB,OAAO;AAAA,EACP,YAAY;AAAA,EACZ,IAAI;AACN;AAEA,IAAO,8CAAQ,oCAAoC,WAAW;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@open-mercato/core",
|
|
3
|
-
"version": "0.7.1-develop.
|
|
3
|
+
"version": "0.7.1-develop.7171.1.9b31dbba45",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -252,16 +252,16 @@
|
|
|
252
252
|
"zod": "^4.4.3"
|
|
253
253
|
},
|
|
254
254
|
"peerDependencies": {
|
|
255
|
-
"@open-mercato/ai-assistant": "0.7.1-develop.
|
|
256
|
-
"@open-mercato/shared": "0.7.1-develop.
|
|
257
|
-
"@open-mercato/ui": "0.7.1-develop.
|
|
255
|
+
"@open-mercato/ai-assistant": "0.7.1-develop.7171.1.9b31dbba45",
|
|
256
|
+
"@open-mercato/shared": "0.7.1-develop.7171.1.9b31dbba45",
|
|
257
|
+
"@open-mercato/ui": "0.7.1-develop.7171.1.9b31dbba45",
|
|
258
258
|
"react": "^19.0.0",
|
|
259
259
|
"react-dom": "^19.0.0"
|
|
260
260
|
},
|
|
261
261
|
"devDependencies": {
|
|
262
|
-
"@open-mercato/ai-assistant": "0.7.1-develop.
|
|
263
|
-
"@open-mercato/shared": "0.7.1-develop.
|
|
264
|
-
"@open-mercato/ui": "0.7.1-develop.
|
|
262
|
+
"@open-mercato/ai-assistant": "0.7.1-develop.7171.1.9b31dbba45",
|
|
263
|
+
"@open-mercato/shared": "0.7.1-develop.7171.1.9b31dbba45",
|
|
264
|
+
"@open-mercato/ui": "0.7.1-develop.7171.1.9b31dbba45",
|
|
265
265
|
"@testing-library/dom": "^10.4.1",
|
|
266
266
|
"@testing-library/jest-dom": "^7.0.0",
|
|
267
267
|
"@testing-library/react": "^16.3.1",
|
|
@@ -15,7 +15,16 @@ import type { CommandRuntimeContext } from '@open-mercato/shared/lib/commands'
|
|
|
15
15
|
import { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'
|
|
16
16
|
import { UniqueConstraintViolationException, LockMode } from '@mikro-orm/core'
|
|
17
17
|
import type { EntityManager, FilterQuery } from '@mikro-orm/postgresql'
|
|
18
|
-
import {
|
|
18
|
+
import {
|
|
19
|
+
User,
|
|
20
|
+
UserRole,
|
|
21
|
+
Role,
|
|
22
|
+
UserAcl,
|
|
23
|
+
Session,
|
|
24
|
+
PasswordReset,
|
|
25
|
+
UserSidebarPreference,
|
|
26
|
+
SidebarVariant,
|
|
27
|
+
} from '@open-mercato/core/modules/auth/data/entities'
|
|
19
28
|
import { Organization } from '@open-mercato/core/modules/directory/data/entities'
|
|
20
29
|
import { resolveOrganizationScope } from '@open-mercato/core/modules/directory/utils/organizationScope'
|
|
21
30
|
import { E } from '#generated/entities.ids.generated'
|
|
@@ -358,6 +367,8 @@ const createUserCommand: CommandHandler<Record<string, unknown>, CreateUserResul
|
|
|
358
367
|
await em.nativeDelete(UserRole, { user: userId })
|
|
359
368
|
await em.nativeDelete(Session, { user: userId })
|
|
360
369
|
await em.nativeDelete(PasswordReset, { user: userId })
|
|
370
|
+
await em.nativeDelete(UserSidebarPreference, { user: userId })
|
|
371
|
+
await em.nativeDelete(SidebarVariant, { user: userId })
|
|
361
372
|
|
|
362
373
|
if (snapshot?.custom && Object.keys(snapshot.custom).length) {
|
|
363
374
|
const reset = buildCustomFieldResetMap(undefined, snapshot.custom)
|
|
@@ -937,6 +948,8 @@ const deleteUserCommand: CommandHandler<{ body?: Record<string, unknown>; query?
|
|
|
937
948
|
await em.nativeDelete(UserRole, { user: id })
|
|
938
949
|
await em.nativeDelete(Session, { user: id })
|
|
939
950
|
await em.nativeDelete(PasswordReset, { user: id })
|
|
951
|
+
await em.nativeDelete(UserSidebarPreference, { user: id })
|
|
952
|
+
await em.nativeDelete(SidebarVariant, { user: id })
|
|
940
953
|
const removed = await de.deleteOrmEntity({
|
|
941
954
|
entity: User,
|
|
942
955
|
where: deleteWhere as FilterQuery<User>,
|
|
@@ -84,7 +84,7 @@ export class UserSidebarPreference {
|
|
|
84
84
|
@PrimaryKey({ type: 'uuid', defaultRaw: 'gen_random_uuid()' })
|
|
85
85
|
id!: string
|
|
86
86
|
|
|
87
|
-
@ManyToOne(() => User)
|
|
87
|
+
@ManyToOne(() => User, { deleteRule: 'cascade' })
|
|
88
88
|
user!: User
|
|
89
89
|
|
|
90
90
|
@Property({ name: 'tenant_id', type: 'uuid', nullable: true })
|
|
@@ -149,7 +149,7 @@ export class SidebarVariant {
|
|
|
149
149
|
@PrimaryKey({ type: 'uuid', defaultRaw: 'gen_random_uuid()' })
|
|
150
150
|
id!: string
|
|
151
151
|
|
|
152
|
-
@ManyToOne(() => User)
|
|
152
|
+
@ManyToOne(() => User, { deleteRule: 'cascade' })
|
|
153
153
|
user!: User
|
|
154
154
|
|
|
155
155
|
@Property({ name: 'tenant_id', type: 'uuid', nullable: true })
|
|
@@ -13,10 +13,14 @@ import type {
|
|
|
13
13
|
} from '@open-mercato/shared/modules/navigation/backendChrome'
|
|
14
14
|
import {
|
|
15
15
|
buildAdminNav,
|
|
16
|
+
buildProfileSections,
|
|
16
17
|
buildSettingsSections,
|
|
17
18
|
computeSettingsPathPrefixes,
|
|
18
19
|
convertToSectionNavGroups,
|
|
20
|
+
mergeSectionsWithDiscovered,
|
|
19
21
|
type AdminNavItem,
|
|
22
|
+
type SettingsSection,
|
|
23
|
+
type SettingsSectionItem,
|
|
20
24
|
} from '@open-mercato/ui/backend/utils/nav'
|
|
21
25
|
import { resolveRegisteredLucideIconNode } from '@open-mercato/ui/backend/icons/lucideRegistry'
|
|
22
26
|
import { profilePathPrefixes, profileSections } from './profile-sections'
|
|
@@ -106,6 +110,36 @@ export const settingsSectionOrder: Record<string, number> = {
|
|
|
106
110
|
'settings.sections.featureToggles': 8,
|
|
107
111
|
}
|
|
108
112
|
|
|
113
|
+
/**
|
|
114
|
+
* Profile section weights, keyed by the untranslated group id, exactly like `settingsSectionOrder`.
|
|
115
|
+
*
|
|
116
|
+
* Only the built-in account section is ranked; a module contributing its own profile group sorts
|
|
117
|
+
* after it on the shared 999 fallback rather than displacing the account pages.
|
|
118
|
+
*/
|
|
119
|
+
export const profileSectionOrder: Record<string, number> = {
|
|
120
|
+
'profile.sections.account': 1,
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Path prefixes that put the shell into profile mode: the static list plus every href the resolved
|
|
125
|
+
* profile sections actually link to.
|
|
126
|
+
*
|
|
127
|
+
* `computeSettingsPathPrefixes` is deliberately not reused — it also registers each item's parent
|
|
128
|
+
* directory, which is harmless for `/backend/settings/*` but would hand profile mode a whole
|
|
129
|
+
* unrelated subtree if a module hosts its profile page outside `/backend/profile/`.
|
|
130
|
+
*/
|
|
131
|
+
function resolveProfilePathPrefixes(sections: SettingsSection[]): string[] {
|
|
132
|
+
const prefixes = new Set(profilePathPrefixes)
|
|
133
|
+
const visitItems = (items: SettingsSectionItem[]) => {
|
|
134
|
+
for (const item of items) {
|
|
135
|
+
prefixes.add(item.href)
|
|
136
|
+
if (item.children?.length) visitItems(item.children)
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
for (const section of sections) visitItems(section.items)
|
|
140
|
+
return Array.from(prefixes)
|
|
141
|
+
}
|
|
142
|
+
|
|
109
143
|
type NavGroupWithWeight = Omit<BackendChromeNavGroup, 'id' | 'defaultName' | 'items'> & {
|
|
110
144
|
id: string
|
|
111
145
|
defaultName: string
|
|
@@ -460,6 +494,14 @@ export async function resolveBackendChromePayload({
|
|
|
460
494
|
),
|
|
461
495
|
)
|
|
462
496
|
|
|
497
|
+
// The profile sidebar mirrors the profile dropdown: the static baseline covers the `navHidden`
|
|
498
|
+
// pages route discovery drops, and every other `pageContext: 'profile'` page is derived from the
|
|
499
|
+
// manifest so a module adding one lands in both surfaces at once (#5594).
|
|
500
|
+
const resolvedProfileSections = mergeSectionsWithDiscovered(
|
|
501
|
+
profileSections,
|
|
502
|
+
buildProfileSections(entries, profileSectionOrder),
|
|
503
|
+
)
|
|
504
|
+
|
|
463
505
|
const requestOrganizationId = request ? getSelectedOrganizationFromRequest(request) : null
|
|
464
506
|
const fallbackOrganizationId = selectedOrganizationId ?? requestOrganizationId ?? auth.orgId ?? null
|
|
465
507
|
const brandOrganizationId = scopedOrganizationId
|
|
@@ -507,8 +549,10 @@ export async function resolveBackendChromePayload({
|
|
|
507
549
|
groups: appliedGroups.map(({ weight: _weight, ...group }) => group),
|
|
508
550
|
settingsSections,
|
|
509
551
|
settingsPathPrefixes: computeSettingsPathPrefixes(buildSettingsSections(entries, settingsSectionOrder)),
|
|
510
|
-
profileSections: await serializeSectionGroups(
|
|
511
|
-
|
|
552
|
+
profileSections: await serializeSectionGroups(
|
|
553
|
+
convertToSectionNavGroups(resolvedProfileSections, translate),
|
|
554
|
+
),
|
|
555
|
+
profilePathPrefixes: resolveProfilePathPrefixes(resolvedProfileSections),
|
|
512
556
|
grantedFeatures,
|
|
513
557
|
roles: Array.isArray(auth.roles) ? auth.roles : [],
|
|
514
558
|
brand,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as React from 'react'
|
|
2
|
-
import type {
|
|
2
|
+
import type { SettingsSection } from '@open-mercato/ui/backend/utils/nav'
|
|
3
3
|
|
|
4
4
|
const KeyIcon = (
|
|
5
5
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
|
@@ -7,9 +7,20 @@ const KeyIcon = (
|
|
|
7
7
|
</svg>
|
|
8
8
|
)
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
/**
|
|
11
|
+
* Baseline profile sidebar sections for pages route discovery cannot see.
|
|
12
|
+
*
|
|
13
|
+
* `/backend/profile/change-password` is `navHidden`, so `buildAdminNav` drops it and
|
|
14
|
+
* `buildProfileSections` can never derive it. Everything else in the profile sidebar comes from
|
|
15
|
+
* pages declaring `pageContext: 'profile'` and is merged in by `resolveBackendChromePayload`.
|
|
16
|
+
*
|
|
17
|
+
* The section id is the untranslated group id (`profile.sections.account`) — the same convention the
|
|
18
|
+
* settings sidebar adopted in 0.6.8 — so a page declaring `pageGroupKey: 'profile.sections.account'`
|
|
19
|
+
* lands in this section instead of opening a duplicate one.
|
|
20
|
+
*/
|
|
21
|
+
export const profileSections: SettingsSection[] = [
|
|
11
22
|
{
|
|
12
|
-
id: 'account',
|
|
23
|
+
id: 'profile.sections.account',
|
|
13
24
|
label: 'Account',
|
|
14
25
|
labelKey: 'profile.sections.account',
|
|
15
26
|
order: 1,
|
|
@@ -913,7 +913,8 @@
|
|
|
913
913
|
"referencedColumnNames": [
|
|
914
914
|
"id"
|
|
915
915
|
],
|
|
916
|
-
"referencedTableName": "public.users"
|
|
916
|
+
"referencedTableName": "public.users",
|
|
917
|
+
"deleteRule": "cascade"
|
|
917
918
|
}
|
|
918
919
|
},
|
|
919
920
|
"nativeEnums": {}
|
|
@@ -1978,7 +1979,8 @@
|
|
|
1978
1979
|
"referencedColumnNames": [
|
|
1979
1980
|
"id"
|
|
1980
1981
|
],
|
|
1981
|
-
"referencedTableName": "public.users"
|
|
1982
|
+
"referencedTableName": "public.users",
|
|
1983
|
+
"deleteRule": "cascade"
|
|
1982
1984
|
}
|
|
1983
1985
|
},
|
|
1984
1986
|
"nativeEnums": {}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Migration } from '@mikro-orm/migrations';
|
|
2
|
+
|
|
3
|
+
export class Migration20260907120000_auth extends Migration {
|
|
4
|
+
|
|
5
|
+
override up(): void | Promise<void> {
|
|
6
|
+
this.addSql(`alter table "user_sidebar_preferences" drop constraint "user_sidebar_preferences_user_id_foreign";`);
|
|
7
|
+
this.addSql(`alter table "user_sidebar_preferences" add constraint "user_sidebar_preferences_user_id_foreign" foreign key ("user_id") references "users" ("id") on update cascade on delete cascade;`);
|
|
8
|
+
|
|
9
|
+
this.addSql(`alter table "sidebar_variants" drop constraint "sidebar_variants_user_id_foreign";`);
|
|
10
|
+
this.addSql(`alter table "sidebar_variants" add constraint "sidebar_variants_user_id_foreign" foreign key ("user_id") references "users" ("id") on update cascade on delete cascade;`);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
override down(): void | Promise<void> {
|
|
14
|
+
this.addSql(`alter table "user_sidebar_preferences" drop constraint "user_sidebar_preferences_user_id_foreign";`);
|
|
15
|
+
this.addSql(`alter table "user_sidebar_preferences" add constraint "user_sidebar_preferences_user_id_foreign" foreign key ("user_id") references "users" ("id") on update cascade;`);
|
|
16
|
+
|
|
17
|
+
this.addSql(`alter table "sidebar_variants" drop constraint "sidebar_variants_user_id_foreign";`);
|
|
18
|
+
this.addSql(`alter table "sidebar_variants" add constraint "sidebar_variants_user_id_foreign" foreign key ("user_id") references "users" ("id");`);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
}
|
package/src/modules/communication_channels/backend/profile/communication-channels/page.meta.ts
CHANGED
|
@@ -21,8 +21,8 @@ export const metadata = {
|
|
|
21
21
|
requireFeatures: ['communication_channels.connect_user_channel'],
|
|
22
22
|
pageTitle: 'My communication channels',
|
|
23
23
|
pageTitleKey: 'communication_channels.profile.title',
|
|
24
|
-
pageGroup: '
|
|
25
|
-
pageGroupKey: '
|
|
24
|
+
pageGroup: 'Account',
|
|
25
|
+
pageGroupKey: 'profile.sections.account',
|
|
26
26
|
pageOrder: 20,
|
|
27
27
|
icon: channelsIcon,
|
|
28
28
|
pageContext: 'profile' as const,
|
|
@@ -371,7 +371,9 @@ Configurable via environment variables (`CUSTOMER_LOGIN_POINTS`, `CUSTOMER_LOGIN
|
|
|
371
371
|
### Email Privacy
|
|
372
372
|
|
|
373
373
|
- Emails stored in plaintext but lookups use `hashForLookup` (deterministic hash)
|
|
374
|
-
-
|
|
374
|
+
- Partial unique index on `(tenantId, emailHash) WHERE deleted_at IS NULL` prevents duplicate **active** accounts — a soft-deleted row no longer blocks re-inviting its email (#5532)
|
|
375
|
+
- Every `CustomerUser` email lookup MUST therefore filter `deletedAt: null`; that predicate is load-bearing, not defensive, because two rows can legitimately share `(tenantId, emailHash)` once one is soft-deleted
|
|
376
|
+
- Match lookups against `lookupHashCandidates(email)` rather than a single `hashForLookup(email)`, so rows still carrying the legacy digest are found
|
|
375
377
|
- Error messages never confirm whether an email is registered
|
|
376
378
|
|
|
377
379
|
## Lib Utilities
|