@open-mercato/core 0.6.4-develop.4239.1.4a264a5828 → 0.6.4-develop.4254.1.7a123d970c
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/dist/helpers/integration/authFixtures.js +70 -1
- package/dist/helpers/integration/authFixtures.js.map +2 -2
- package/dist/helpers/integration/dbFixtures.js +98 -0
- package/dist/helpers/integration/dbFixtures.js.map +7 -0
- package/dist/modules/business_rules/api/execute/route.js +2 -1
- package/dist/modules/business_rules/api/execute/route.js.map +2 -2
- package/dist/modules/business_rules/api/rules/route.js +10 -0
- package/dist/modules/business_rules/api/rules/route.js.map +2 -2
- package/dist/modules/business_rules/cli.js +6 -0
- package/dist/modules/business_rules/cli.js.map +2 -2
- package/dist/modules/business_rules/lib/rule-engine.js +116 -9
- package/dist/modules/business_rules/lib/rule-engine.js.map +2 -2
- package/dist/modules/business_rules/subscribers/crud-rule-trigger.js +3 -2
- package/dist/modules/business_rules/subscribers/crud-rule-trigger.js.map +2 -2
- package/dist/modules/catalog/api/products/route.js +21 -4
- package/dist/modules/catalog/api/products/route.js.map +2 -2
- package/dist/modules/catalog/lib/pricing.js +6 -0
- package/dist/modules/catalog/lib/pricing.js.map +2 -2
- package/dist/modules/catalog/services/catalogPricingService.js +5 -1
- package/dist/modules/catalog/services/catalogPricingService.js.map +2 -2
- package/dist/modules/customers/api/activities/route.js +15 -2
- package/dist/modules/customers/api/activities/route.js.map +2 -2
- package/dist/modules/customers/api/comments/route.js +15 -3
- package/dist/modules/customers/api/comments/route.js.map +2 -2
- package/dist/modules/customers/api/companies/[id]/people/route.js +2 -4
- package/dist/modules/customers/api/companies/[id]/people/route.js.map +2 -2
- package/dist/modules/customers/api/companies/[id]/route.js +2 -4
- package/dist/modules/customers/api/companies/[id]/route.js.map +2 -2
- package/dist/modules/customers/api/deals/[id]/companies/route.js +2 -4
- package/dist/modules/customers/api/deals/[id]/companies/route.js.map +2 -2
- package/dist/modules/customers/api/deals/[id]/people/route.js +2 -4
- package/dist/modules/customers/api/deals/[id]/people/route.js.map +2 -2
- package/dist/modules/customers/api/deals/[id]/route.js +2 -9
- package/dist/modules/customers/api/deals/[id]/route.js.map +2 -2
- package/dist/modules/customers/api/deals/[id]/stats/route.js +2 -9
- package/dist/modules/customers/api/deals/[id]/stats/route.js.map +2 -2
- package/dist/modules/customers/api/entity-roles-factory.js +2 -8
- package/dist/modules/customers/api/entity-roles-factory.js.map +2 -2
- package/dist/modules/customers/api/people/[id]/companies/context.js +2 -4
- package/dist/modules/customers/api/people/[id]/companies/context.js.map +2 -2
- package/dist/modules/customers/api/people/[id]/companies/enriched/route.js +2 -4
- package/dist/modules/customers/api/people/[id]/companies/enriched/route.js.map +2 -2
- package/dist/modules/customers/api/people/[id]/route.js +2 -4
- package/dist/modules/customers/api/people/[id]/route.js.map +2 -2
- package/dist/modules/directory/utils/organizationScopeGuard.js +22 -0
- package/dist/modules/directory/utils/organizationScopeGuard.js.map +7 -0
- package/dist/modules/workflows/cli.js +8 -0
- package/dist/modules/workflows/cli.js.map +2 -2
- package/dist/modules/workflows/lib/seeds.js +8 -4
- package/dist/modules/workflows/lib/seeds.js.map +2 -2
- package/dist/modules/workflows/setup.js +3 -1
- package/dist/modules/workflows/setup.js.map +2 -2
- package/package.json +7 -7
- package/src/helpers/integration/authFixtures.ts +98 -0
- package/src/helpers/integration/dbFixtures.ts +144 -0
- package/src/modules/business_rules/api/execute/route.ts +2 -1
- package/src/modules/business_rules/api/rules/route.ts +10 -0
- package/src/modules/business_rules/cli.ts +6 -0
- package/src/modules/business_rules/lib/rule-engine.ts +163 -9
- package/src/modules/business_rules/subscribers/crud-rule-trigger.ts +3 -2
- package/src/modules/catalog/api/products/route.ts +23 -4
- package/src/modules/catalog/lib/pricing.ts +9 -0
- package/src/modules/catalog/services/catalogPricingService.ts +6 -0
- package/src/modules/customers/api/activities/route.ts +16 -5
- package/src/modules/customers/api/comments/route.ts +15 -5
- package/src/modules/customers/api/companies/[id]/people/route.ts +2 -4
- package/src/modules/customers/api/companies/[id]/route.ts +2 -5
- package/src/modules/customers/api/deals/[id]/companies/route.ts +2 -4
- package/src/modules/customers/api/deals/[id]/people/route.ts +2 -4
- package/src/modules/customers/api/deals/[id]/route.ts +2 -9
- package/src/modules/customers/api/deals/[id]/stats/route.ts +2 -9
- package/src/modules/customers/api/entity-roles-factory.ts +2 -12
- package/src/modules/customers/api/people/[id]/companies/context.ts +2 -5
- package/src/modules/customers/api/people/[id]/companies/enriched/route.ts +2 -5
- package/src/modules/customers/api/people/[id]/route.ts +2 -5
- package/src/modules/directory/utils/organizationScopeGuard.ts +39 -0
- package/src/modules/workflows/cli.ts +8 -0
- package/src/modules/workflows/lib/seeds.ts +13 -3
- package/src/modules/workflows/setup.ts +3 -1
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { AuthContext } from '@open-mercato/shared/lib/auth/server'
|
|
2
|
+
import { isOrganizationAccessAllowed } from '@open-mercato/shared/lib/auth/organizationAccess'
|
|
3
|
+
import type { OrganizationScope } from './organizationScope'
|
|
4
|
+
|
|
5
|
+
export type OrganizationReadAccessInput = {
|
|
6
|
+
scope: OrganizationScope | null | undefined
|
|
7
|
+
auth: AuthContext
|
|
8
|
+
organizationId: string | null
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Fail-closed read guard for single-record detail routes. Centralizes the
|
|
13
|
+
* decision so callers keep their own deny mechanism (throw / return response)
|
|
14
|
+
* and their own i18n key.
|
|
15
|
+
*
|
|
16
|
+
* Unrestricted access (super admin or `scope.allowedIds === null`) is the only
|
|
17
|
+
* bypass. For a restricted principal the allowed set is derived the same way
|
|
18
|
+
* the detail routes always have (`filterIds` narrows the active view, else the
|
|
19
|
+
* principal's home org); an empty derived set denies instead of skipping.
|
|
20
|
+
*/
|
|
21
|
+
export function isOrganizationReadAccessAllowed(input: OrganizationReadAccessInput): boolean {
|
|
22
|
+
const isSuperAdmin = input.auth?.isSuperAdmin === true
|
|
23
|
+
if (isSuperAdmin || input.scope?.allowedIds === null) return true
|
|
24
|
+
|
|
25
|
+
const allowedOrganizationIds = new Set<string>()
|
|
26
|
+
if (input.scope?.filterIds?.length) {
|
|
27
|
+
for (const id of input.scope.filterIds) {
|
|
28
|
+
if (typeof id === 'string' && id.trim().length) allowedOrganizationIds.add(id)
|
|
29
|
+
}
|
|
30
|
+
} else if (input.auth?.orgId) {
|
|
31
|
+
allowedOrganizationIds.add(input.auth.orgId)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return isOrganizationAccessAllowed({
|
|
35
|
+
isSuperAdmin,
|
|
36
|
+
allowedOrganizationIds: Array.from(allowedOrganizationIds),
|
|
37
|
+
targetOrganizationId: input.organizationId,
|
|
38
|
+
})
|
|
39
|
+
}
|
|
@@ -4,6 +4,10 @@ import { getRedisUrl, getRedisUrlOrThrow } from '@open-mercato/shared/lib/redis/
|
|
|
4
4
|
import type { EntityManager } from '@mikro-orm/postgresql'
|
|
5
5
|
import { WorkflowDefinition } from './data/entities'
|
|
6
6
|
import { BusinessRule, type RuleType } from '@open-mercato/core/modules/business_rules/data/entities'
|
|
7
|
+
import {
|
|
8
|
+
invalidateBusinessRuleDiscoveryCache,
|
|
9
|
+
resolveBusinessRuleDiscoveryCache,
|
|
10
|
+
} from '@open-mercato/core/modules/business_rules/lib/rule-engine'
|
|
7
11
|
import * as fs from 'fs'
|
|
8
12
|
import * as path from 'path'
|
|
9
13
|
import { fileURLToPath } from 'url'
|
|
@@ -69,6 +73,7 @@ const seedDemoWithRules: ModuleCli = {
|
|
|
69
73
|
try {
|
|
70
74
|
const { resolve } = await createRequestContainer()
|
|
71
75
|
const em = resolve<EntityManager>('em')
|
|
76
|
+
const cache = resolveBusinessRuleDiscoveryCache(resolve)
|
|
72
77
|
|
|
73
78
|
// Import BusinessRule entity
|
|
74
79
|
const { BusinessRule } = await import('../business_rules/data/entities')
|
|
@@ -100,6 +105,7 @@ const seedDemoWithRules: ModuleCli = {
|
|
|
100
105
|
})
|
|
101
106
|
|
|
102
107
|
await em.persist(rule).flush()
|
|
108
|
+
await invalidateBusinessRuleDiscoveryCache(cache, tenantId, organizationId)
|
|
103
109
|
console.log(` ✓ Seeded guard rule: ${rule.ruleName}`)
|
|
104
110
|
seededCount++
|
|
105
111
|
}
|
|
@@ -211,6 +217,7 @@ const seedOrderApproval: ModuleCli = {
|
|
|
211
217
|
try {
|
|
212
218
|
const { resolve } = await createRequestContainer()
|
|
213
219
|
const em = resolve<EntityManager>('em')
|
|
220
|
+
const cache = resolveBusinessRuleDiscoveryCache(resolve)
|
|
214
221
|
|
|
215
222
|
// 1. Seed order approval guard rules first
|
|
216
223
|
const guardRulesPath = path.join(__dirname, 'examples', 'order-approval-guard-rules.json')
|
|
@@ -252,6 +259,7 @@ const seedOrderApproval: ModuleCli = {
|
|
|
252
259
|
|
|
253
260
|
if (rulesSeeded > 0) {
|
|
254
261
|
await em.flush()
|
|
262
|
+
await invalidateBusinessRuleDiscoveryCache(cache, tenantId, organizationId)
|
|
255
263
|
}
|
|
256
264
|
|
|
257
265
|
console.log(`✅ Seeded order approval guard rules`)
|
|
@@ -4,6 +4,10 @@ import * as path from 'path'
|
|
|
4
4
|
import { fileURLToPath } from 'node:url'
|
|
5
5
|
import { WorkflowDefinition, type WorkflowDefinitionData } from '../data/entities'
|
|
6
6
|
import { BusinessRule, type RuleType } from '@open-mercato/core/modules/business_rules/data/entities'
|
|
7
|
+
import {
|
|
8
|
+
invalidateBusinessRuleDiscoveryCache,
|
|
9
|
+
type RuleDiscoveryCache,
|
|
10
|
+
} from '@open-mercato/core/modules/business_rules/lib/rule-engine'
|
|
7
11
|
|
|
8
12
|
const __esmDirname = path.dirname(fileURLToPath(import.meta.url))
|
|
9
13
|
|
|
@@ -130,6 +134,7 @@ async function seedGuardRules(
|
|
|
130
134
|
em: EntityManager,
|
|
131
135
|
scope: WorkflowSeedScope,
|
|
132
136
|
fileName: string,
|
|
137
|
+
cache?: RuleDiscoveryCache | null,
|
|
133
138
|
): Promise<{ seeded: number; skipped: number; updated: number }> {
|
|
134
139
|
const seeds = readExampleJson<GuardRuleSeed[]>(fileName)
|
|
135
140
|
if (!Array.isArray(seeds)) {
|
|
@@ -185,16 +190,21 @@ async function seedGuardRules(
|
|
|
185
190
|
}
|
|
186
191
|
if (seeded > 0 || updated > 0) {
|
|
187
192
|
await em.flush()
|
|
193
|
+
await invalidateBusinessRuleDiscoveryCache(cache, scope.tenantId, scope.organizationId)
|
|
188
194
|
}
|
|
189
195
|
return { seeded, skipped, updated }
|
|
190
196
|
}
|
|
191
197
|
|
|
192
|
-
export async function seedExampleWorkflows(
|
|
198
|
+
export async function seedExampleWorkflows(
|
|
199
|
+
em: EntityManager,
|
|
200
|
+
scope: WorkflowSeedScope,
|
|
201
|
+
options: { cache?: RuleDiscoveryCache | null } = {},
|
|
202
|
+
): Promise<void> {
|
|
193
203
|
// workflows.checkout-demo and workflows.simple-approval are now code-defined
|
|
194
204
|
// (see packages/core/src/modules/workflows/workflows.ts). Seeding DB rows for
|
|
195
205
|
// them would shadow the code definitions in the merge layer, so they are no
|
|
196
206
|
// longer seeded here. Existing tenants are migrated via Migration20260428102318.
|
|
197
|
-
await seedGuardRules(em, scope, 'guard-rules-example.json')
|
|
207
|
+
await seedGuardRules(em, scope, 'guard-rules-example.json', options.cache)
|
|
198
208
|
await seedWorkflowDefinition(em, scope, 'sales-pipeline-definition.json')
|
|
199
|
-
await seedGuardRules(em, scope, 'order-approval-guard-rules.json')
|
|
209
|
+
await seedGuardRules(em, scope, 'order-approval-guard-rules.json', options.cache)
|
|
200
210
|
}
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import type { ModuleSetupConfig } from '@open-mercato/shared/modules/setup'
|
|
2
|
+
import { resolveBusinessRuleDiscoveryCache } from '@open-mercato/core/modules/business_rules/lib/rule-engine'
|
|
2
3
|
import { seedExampleWorkflows } from './lib/seeds'
|
|
3
4
|
|
|
4
5
|
export const setup: ModuleSetupConfig = {
|
|
5
6
|
seedDefaults: async (ctx) => {
|
|
6
7
|
const scope = { tenantId: ctx.tenantId, organizationId: ctx.organizationId }
|
|
7
|
-
|
|
8
|
+
const cache = resolveBusinessRuleDiscoveryCache(ctx.container.resolve.bind(ctx.container))
|
|
9
|
+
await seedExampleWorkflows(ctx.em, scope, { cache })
|
|
8
10
|
},
|
|
9
11
|
|
|
10
12
|
defaultRoleFeatures: {
|