Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
862610e
feat(inventory): implement inventory vertical (#794)
JiProchazka Sep 25, 2026
bbe2046
fix(inventory): remove unsupported privacy contract
JiProchazka Sep 25, 2026
32c5103
fix(inventory): address implementation audit
JiProchazka Sep 25, 2026
4df7221
fix(inventory): satisfy CI checks
JiProchazka Sep 25, 2026
4939f99
test(inventory): stabilize CI coverage
JiProchazka Sep 25, 2026
1d1c293
fix(inventory): align binding authorization scope
JiProchazka Sep 25, 2026
6118cf8
fix(inventory): preserve binding correction proof history
JiProchazka Sep 25, 2026
d11730c
test(shell): start inventory remote for e2e
JiProchazka Sep 25, 2026
d7d0922
fix(shell): bind inventory worker in Cloudflare
JiProchazka Sep 25, 2026
90487be
test(shell): scroll mobile dashboard assertions
JiProchazka Sep 25, 2026
10ab013
Merge origin/main into codex/issue-794-inventory
JiProchazka Sep 26, 2026
f0042fe
fix(inventory): align with latest runtime APIs
JiProchazka Sep 26, 2026
20d0ec6
test(inventory): use native database clients
JiProchazka Sep 26, 2026
879f3ee
fix(inventory): use shared build context
JiProchazka Sep 26, 2026
4907f90
fix(inventory): address PR review findings
JiProchazka Sep 29, 2026
7dca958
Merge remote-tracking branch 'origin/main' into codex/issue-794-inven…
JiProchazka Sep 29, 2026
b58708c
Merge remote-tracking branch 'origin/main' into codex/issue-794-inven…
JiProchazka Sep 29, 2026
b48d1e0
fix(ci): satisfy inventory PR checks
JiProchazka Sep 29, 2026
e4e7e54
fix(ci): update inventory integration fixtures
JiProchazka Sep 29, 2026
922928f
fix(ci): clear remaining inventory gates
JiProchazka Sep 29, 2026
5c94d40
fix(ci): align inventory readiness marker schema
JiProchazka Sep 29, 2026
bd0f932
fix(ci): remove obsolete inventory lint suppression
JiProchazka Sep 29, 2026
1e8a269
fix(ci): update lint suppression baseline
JiProchazka Sep 29, 2026
fd03e4b
fix(ci): stabilize protection recovery clock
JiProchazka Sep 29, 2026
f89d471
fix(ci): use checked-out revision in browser tests
JiProchazka Sep 29, 2026
080dc5b
test(outbox): seed the host test's deliveries instead of racing other…
BleedingDev Sep 29, 2026
0f301bf
Merge remote-tracking branch 'origin/main' into codex/issue-794-inven…
JiProchazka Sep 29, 2026
888bb73
fix(inventory): provide HTTP schema problem layer
JiProchazka Sep 29, 2026
cfe8a64
Merge remote-tracking branch 'origin/main' into codex/issue-794-inven…
JiProchazka Sep 29, 2026
200a38c
fix(inventory): complete HTTP schema problem wiring
JiProchazka Sep 29, 2026
15cfdee
fix(inventory): keep router requirement type-only
JiProchazka Sep 30, 2026
cd8b7cf
Merge remote-tracking branch 'origin/main' into codex/issue-794-inven…
JiProchazka Sep 30, 2026
133d57b
fix(inventory): use TLS for SpiceDB deployment
JiProchazka Sep 30, 2026
e52b2b8
test(ops): cover Inventory in stage cost guard
JiProchazka Sep 30, 2026
6ebd92e
fix(inventory): align browser federation singletons
JiProchazka Sep 30, 2026
68a29ef
fix(inventory): bind Cloudflare data plane
JiProchazka Sep 30, 2026
8bf1d2c
ci: serialize Cloudflare artifact builds
JiProchazka Sep 30, 2026
59fa020
Merge origin/main into codex/issue-794-inventory
JiProchazka Sep 30, 2026
6eee2e6
fix(ci): align inventory deployment projections
JiProchazka Sep 30, 2026
0fa2acd
Merge origin/main into codex/issue-794-inventory
JiProchazka Sep 30, 2026
30c1725
fix(ci): complete inventory stage fixtures
JiProchazka Sep 30, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
2 changes: 2 additions & 0 deletions .github/workflows/ultramodern-workspace-gates.yml
Original file line number Diff line number Diff line change
Expand Up @@ -401,10 +401,12 @@ jobs:
working-directory: app
env:
MODERN_PUBLIC_SITE_URL: https://shell-super-app.invalid
pnpm_config_workspace_concurrency: "1"
ULTRAMODERN_PUBLIC_URL_ASSORTMENT: https://assortment.invalid
ULTRAMODERN_PUBLIC_URL_CATALOG: https://catalog.invalid
ULTRAMODERN_PUBLIC_URL_COMMERCE_CUSTOMER_CONTEXT: https://commerce-customer-context.invalid
ULTRAMODERN_PUBLIC_URL_COMMERCE_MARKET_CATALOG: https://commerce-market-catalog.invalid
ULTRAMODERN_PUBLIC_URL_INVENTORY: https://inventory.invalid
ULTRAMODERN_PUBLIC_URL_PARTY_REGISTRY: https://party-registry.invalid
ULTRAMODERN_PUBLIC_URL_PAYMENT_TERM_CATALOG: https://payment-term-catalog.invalid
ULTRAMODERN_PUBLIC_URL_PRICE_GROUP_CATALOG: https://price-group-catalog.invalid
Expand Down
7 changes: 7 additions & 0 deletions app/apps/shell-super-app/module-federation.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,13 @@ const moduleFederationConfig: Parameters<typeof createModuleFederationConfig>[0]
filename: 'remoteEntry.js',
name: 'shellSuperApp',
remotes: {
inventory: createRemoteManifestUrl({
manifestEnv: 'VERTICAL_INVENTORY_MF_MANIFEST',
mfName: 'verticalInventory',
port: 4109,
publicUrlEnv: 'ULTRAMODERN_PUBLIC_URL_INVENTORY',
workerName: 'app-inventory',
}),
partyRegistry: createRemoteManifestUrl({
manifestEnv: 'VERTICAL_PARTY_REGISTRY_MF_MANIFEST',
mfName: 'verticalPartyRegistry',
Expand Down
10 changes: 6 additions & 4 deletions app/apps/shell-super-app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,15 @@
},
"dependencies": {
"@app/assortment": "workspace:*",
"@app/better-auth-effect-drizzle": "workspace:*",
"@app/catalog": "workspace:*",
"@app/commerce-customer-context": "workspace:*",
"@app/commerce-market-catalog": "workspace:*",
"@app/core-runtime": "workspace:*",
"@app/inventory": "workspace:*",
"@app/party-registry": "workspace:*",
"@app/payment-term-catalog": "workspace:*",
"@app/price-group-catalog": "workspace:*",
"@app/pricing": "workspace:*",
"@app/shared-contracts": "workspace:*",
"@app/shared-design-tokens": "workspace:*",
Expand Down Expand Up @@ -61,9 +64,7 @@
"i18next": "26.4.2",
"jose": "6.2.5",
"react": "19.2.8",
"react-dom": "19.2.8",
"@app/price-group-catalog": "workspace:*",
"@app/better-auth-effect-drizzle": "workspace:*"
"react-dom": "19.2.8"
},
"devDependencies": {
"@cloudflare/workers-types": "5.20260923.1",
Expand Down Expand Up @@ -101,6 +102,7 @@
"partyRegistry": "@app/party-registry@workspace:*",
"commerceMarketCatalog": "@app/commerce-market-catalog@workspace:*",
"catalog": "@app/catalog@workspace:*",
"assortment": "@app/assortment@workspace:*"
"assortment": "@app/assortment@workspace:*",
"inventory": "@app/inventory@workspace:*"
}
}
9 changes: 9 additions & 0 deletions app/apps/shell-super-app/playwright.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,15 @@ export default defineConfig({
reuseExistingServer: !continuousIntegration,
url: 'http://127.0.0.1:4102/party-registry-api/party-registry/readiness',
},
{
command: 'pnpm dev',
cwd: '../../verticals/inventory',
env: {
ULTRAMODERN_MF_DEV_ORIGIN: origin,
},
reuseExistingServer: !continuousIntegration,
url: 'http://127.0.0.1:4109/inventory-api/inventory/readiness',
},
{
command: 'pnpm dev',
reuseExistingServer: !continuousIntegration,
Expand Down
2 changes: 2 additions & 0 deletions app/apps/shell-super-app/src/api/vertical-clients.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ export { createPaymentTermCatalogClient, getPaymentTermCatalogReadiness } from '
export type { PaymentTermCatalogClientOptions } from '@app/payment-term-catalog/api/client';
export { createPriceGroupCatalogClient, getPriceGroupCatalogReadiness } from '@app/price-group-catalog/api/client';
export type { PriceGroupCatalogClientOptions } from '@app/price-group-catalog/api/client';
export { createInventoryClient, getInventoryReadiness } from '@app/inventory/api/client';
export type { InventoryClientOptions } from '@app/inventory/api/client';
export { createPricingClient, getPricingReadiness } from '@app/pricing/api/client';
export type { PricingClientOptions } from '@app/pricing/api/client';
export { createStorefrontRegistryClient, getStorefrontRegistryReadiness } from '@app/storefront-registry/api/client';
Expand Down
4 changes: 4 additions & 0 deletions app/apps/shell-super-app/src/modern-app-env.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ declare module 'catalog/Widget' {
export default CatalogWidget;
}

declare module 'inventory/Widget' {
export { default } from '@app/inventory/Widget';
}

declare module 'partyRegistry/Page*' {
const VerticalPage: React.FunctionComponent<{
readonly routeParams: Readonly<Record<string, string>>;
Expand Down
7 changes: 5 additions & 2 deletions app/apps/shell-super-app/tests/e2e/login.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -492,10 +492,13 @@ test('keeps the authenticated dashboard reachable without horizontal overflow at
);

await expect(page.getByRole('complementary', { name: 'Dashboard sidebar' })).toBeInViewport();
await expect(page.locator('header[aria-label="Dashboard header"]')).toBeInViewport();
await expect(page.getByRole('button', { name: 'E2E user' })).toBeInViewport();
await expect(page.getByRole('link', { name: 'Home' })).toBeInViewport();
const dashboardHeader = page.locator('header[aria-label="Dashboard header"]');
await dashboardHeader.scrollIntoViewIfNeeded();
await expect(dashboardHeader).toBeInViewport();
await expect(page.getByRole('button', { name: 'E2E user' })).toBeInViewport();
const tenant = page.getByRole('combobox', { name: 'Current tenant' });
await tenant.scrollIntoViewIfNeeded();
await expect(tenant).toBeInViewport();
await tenant.click();
const secondTenant = page.getByRole('option', {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,14 @@ registerHooks({
});

describe('module-federation-i18n-runtime', () => {
it.effect('registers the Inventory widget remote from the generated topology contract', () =>
Effect.gen(function* registersInventoryRemote() {
const { default: shellConfig } = yield* Effect.promise(() => import(shellConfigUrl.href));

expect(shellConfig.remotes?.inventory).toBe('verticalInventory@http://localhost:4109/mf-manifest.json');
}),
);

it.effect('Shell and Party Registry share the i18n runtime that owns the federated provider context', () =>
Effect.gen(function* sharesFederatedI18nRuntime() {
const [{ default: shellConfig }, { default: partyRegistryConfig }] = yield* Effect.promise(() =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ it.effect('derives installed vertical IDs from the injected topology without har
'pricing',
'storefront-registry',
'price-group-catalog',
'inventory',
'assortment',
]);
expect(expectedInstalledIds.has('party.registry')).toBe(false);
Expand Down
9 changes: 5 additions & 4 deletions app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,15 +51,15 @@
"sandbox:new": "sh ./scripts/locki-feature.sh",
"env:local:ensure": "node ./scripts/ensure-local-environment.mts",
"spicedb:tls:local": "node ./scripts/local-spicedb-tls.mts",
"db:generate": "pnpm --filter @app/core-runtime db:generate && pnpm --filter @app/shell-super-app db:generate && pnpm --filter @app/party-registry db:generate && pnpm --filter @app/payment-term-catalog db:generate && pnpm --filter @app/price-group-catalog db:generate && pnpm --filter @app/commerce-customer-context db:generate && pnpm --filter @app/commerce-market-catalog db:generate && pnpm --filter @app/catalog db:generate && pnpm --filter @app/pricing db:generate && pnpm --filter @app/storefront-registry db:generate && pnpm --filter @app/assortment db:generate && pnpm db:portal-auth:generate",
"db:generate": "pnpm --filter @app/core-runtime db:generate && pnpm --filter @app/shell-super-app db:generate && pnpm --filter @app/party-registry db:generate && pnpm --filter @app/payment-term-catalog db:generate && pnpm --filter @app/price-group-catalog db:generate && pnpm --filter @app/commerce-customer-context db:generate && pnpm --filter @app/commerce-market-catalog db:generate && pnpm --filter @app/catalog db:generate && pnpm --filter @app/inventory db:generate && pnpm --filter @app/pricing db:generate && pnpm --filter @app/storefront-registry db:generate && pnpm --filter @app/assortment db:generate && pnpm db:portal-auth:generate",
"db:bootstrap-runtime-role": "node ./scripts/postgres/bootstrap-runtime-role.mts",
"db:portal-auth:check": "node ./scripts/run-optional-commerce-portal-auth-db.mts check",
"db:portal-auth:generate": "node ./scripts/run-optional-commerce-portal-auth-db.mts generate",
"db:portal-auth:migrate": "node ./scripts/run-optional-commerce-portal-auth-db.mts migrate",
"db:bootstrap-spicedb": "node ./scripts/postgres/bootstrap-spicedb-database.mts",
"db:check": "pnpm --filter @app/core-runtime db:check && pnpm --filter @app/shell-super-app db:check && pnpm --filter @app/party-registry db:check && pnpm --filter @app/payment-term-catalog db:check && pnpm --filter @app/price-group-catalog db:check && pnpm --filter @app/commerce-customer-context db:check && pnpm --filter @app/commerce-market-catalog db:check && pnpm --filter @app/catalog db:check && pnpm --filter @app/assortment db:check && pnpm db:portal-auth:check",
"db:migrate": "pnpm db:bootstrap-runtime-role && pnpm --filter @app/core-runtime db:migrate && pnpm --filter @app/shell-super-app db:migrate && pnpm --filter @app/party-registry db:migrate && pnpm --filter @app/payment-term-catalog db:migrate && pnpm --filter @app/price-group-catalog db:migrate && pnpm --filter @app/commerce-customer-context db:migrate && pnpm --filter @app/commerce-market-catalog db:migrate && pnpm --filter @app/catalog db:migrate && pnpm --filter @app/pricing db:migrate && pnpm --filter @app/storefront-registry db:migrate && pnpm --filter @app/assortment db:migrate && pnpm db:bootstrap-runtime-role && pnpm db:portal-auth:migrate",
"db:test": "pnpm --filter @app/core-runtime db:test && pnpm --filter @app/shell-super-app test:integration && pnpm --filter @app/party-registry db:test && pnpm --filter @app/payment-term-catalog db:test && pnpm --filter @app/price-group-catalog db:test && pnpm --filter @app/commerce-customer-context db:test && pnpm --filter @app/commerce-market-catalog db:test && pnpm --filter @app/catalog db:test && pnpm --filter @app/assortment db:test",
"db:check": "pnpm --filter @app/core-runtime db:check && pnpm --filter @app/shell-super-app db:check && pnpm --filter @app/party-registry db:check && pnpm --filter @app/payment-term-catalog db:check && pnpm --filter @app/price-group-catalog db:check && pnpm --filter @app/commerce-customer-context db:check && pnpm --filter @app/commerce-market-catalog db:check && pnpm --filter @app/catalog db:check && pnpm --filter @app/inventory db:check && pnpm --filter @app/assortment db:check && pnpm db:portal-auth:check",
"db:migrate": "pnpm db:bootstrap-runtime-role && pnpm --filter @app/core-runtime db:migrate && pnpm --filter @app/shell-super-app db:migrate && pnpm --filter @app/party-registry db:migrate && pnpm --filter @app/payment-term-catalog db:migrate && pnpm --filter @app/price-group-catalog db:migrate && pnpm --filter @app/commerce-customer-context db:migrate && pnpm --filter @app/commerce-market-catalog db:migrate && pnpm --filter @app/catalog db:migrate && pnpm --filter @app/inventory db:migrate && pnpm --filter @app/pricing db:migrate && pnpm --filter @app/storefront-registry db:migrate && pnpm --filter @app/assortment db:migrate && pnpm db:bootstrap-runtime-role && pnpm db:portal-auth:migrate",
"db:test": "pnpm --filter @app/core-runtime db:test && pnpm --filter @app/shell-super-app test:integration && pnpm --filter @app/party-registry db:test && pnpm --filter @app/payment-term-catalog db:test && pnpm --filter @app/price-group-catalog db:test && pnpm --filter @app/commerce-customer-context db:test && pnpm --filter @app/commerce-market-catalog db:test && pnpm --filter @app/catalog db:test && pnpm --filter @app/inventory db:test && pnpm --filter @app/assortment db:test",
"database-trust:audit": "node ./scripts/audit-database-trust-boundaries.mts",
"db:verify": "node ./scripts/verify-application-db-schema.mts",
"local:initialize": "node ./scripts/initialize-local-development.mts",
Expand Down Expand Up @@ -118,6 +118,7 @@
"dependencies": {
"@app/commerce-customer-context": "workspace:*",
"@app/core-runtime": "workspace:*",
"@app/inventory": "workspace:*",
"@app/party-registry": "workspace:*",
"@app/price-group-catalog": "workspace:*",
"@authzed/authzed-node": "1.6.1",
Expand Down
32 changes: 29 additions & 3 deletions app/packages/core-runtime/src/actions/runtime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ import type { OperationalScope, OperationalScopeResolverService } from '../opera
import { OperationalScopeResolver } from '../operations/context.ts';
import {
ContextAccess,
InventoryAuthorizationResourceIdSchema,
InventoryAuthorizationResourceTypeSchema,
PricingAuthorizationResourceIdSchema,
isBusinessPermissionTargetCompatible,
toAssortmentPermissionAccessKey,
Expand Down Expand Up @@ -489,6 +491,15 @@ const BusinessAccessTargetSchema = Schema.Union([
pricingCatalogId: PricingAuthorizationResourceIdSchema,
tenantId: BusinessTenantIdSchema,
}),
Schema.Struct({
kind: Schema.Literal('inventory_resource'),
resource: Schema.Struct({
moduleId: Schema.Literal('commerce.inventory'),
resourceId: InventoryAuthorizationResourceIdSchema,
resourceType: InventoryAuthorizationResourceTypeSchema,
}),
tenantId: BusinessTenantIdSchema,
}),
]);
const ActionBusinessPermissionTargetSchema = Schema.Struct({
permission: BusinessPermissionCodeSchema,
Expand All @@ -506,9 +517,13 @@ const businessTargetResourceId = (target: ActionBusinessPermissionTarget['target
if (target.kind === 'counterparty_storefront') {
return `${target.counterpartyId}:${target.storefrontId}`;
}
return target.kind === 'pricing_catalog'
? target.pricingCatalogId
: `${target.pricingCatalogId}:${target.priceGroupId}`;
if (target.kind === 'pricing_catalog') {
return target.pricingCatalogId;
}
if (target.kind === 'price_group') {
return `${target.pricingCatalogId}:${target.priceGroupId}`;
}
return target.resource.resourceId;
};

const resolveActionBusinessPermissionTarget = <Payload>(
Expand Down Expand Up @@ -547,6 +562,9 @@ const resolveActionBusinessPermissionTarget = <Payload>(
resolved.trustedStorefrontId === undefined
);
}
if (resolved.target.kind === 'inventory_resource') {
return resolved.trustedStorefrontId === undefined;
}
return (
resolved.target.legalEntityId === scope.legalEntityId &&
(resolved.target.kind === 'counterparty_storefront'
Expand Down Expand Up @@ -1249,6 +1267,14 @@ export const makeActionRuntime = (...construction: ActionRuntimeConstruction): A
}> => {
if (Option.isSome(businessPermissionTarget)) {
const { permission: targetPermission, target } = businessPermissionTarget.value;
if (target.kind === 'inventory_resource') {
const actionTarget = {
targetModuleKey: target.resource.moduleId,
targetResourceId: target.resource.resourceId,
targetResourceType: target.resource.resourceType,
};
return { actionTarget, governedTransport: buildGovernedTransport(transport, actionTarget) };
}
const actionTarget = {
targetModuleKey: input.registration.descriptor.owningModuleKey,
targetResourceId: businessTargetResourceId(target),
Expand Down
1 change: 1 addition & 0 deletions app/packages/core-runtime/src/outbox/worker-entrypoint.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/** Focused server-only entrypoint used to bundle the combined Outbox Worker host and its MicroVertical entries. */
export { defineTenantModuleEntrypoint } from '../modules/module-entrypoint.ts';
export { defineScopedRoutine } from '../db/scoped-routine.ts';
export { findPostgresFailure } from '../database/postgres-failure.ts';
export { BusinessPermissionCodeSchema, defineBusinessPermissionCatalog } from '../permissions/business-permission.ts';
export { AuthorizationMutationReconciliationUnavailable } from '../permissions/authorization-reconciler.ts';
export {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@ import { Effect } from 'effect';
import type { AuthorizationMutationJournalEntry, AuthorizationMutationState } from './authorization-mutation.ts';
import { canTransitionAuthorizationMutation } from './authorization-mutation.ts';
import { AuthorizationMutationSagaError } from './authorization-mutation-saga-error.ts';
import { hasCanonicalPricingAuthorizationTargetIds, isBusinessPermissionTargetCompatible } from './context-access.ts';
import {
hasCanonicalInventoryAuthorizationTarget,
hasCanonicalPricingAuthorizationTargetIds,
isBusinessPermissionTargetCompatible,
} from './context-access.ts';
import type {
BusinessPermissionRelationshipMutationInput,
BusinessPermissionRelationshipMutationService,
Expand Down Expand Up @@ -50,27 +54,33 @@ const expectedPendingState = (
operation: AuthorizationMutationJournalEntry['operation'],
): 'PENDING_GRANT' | 'PENDING_REVOKE' => (operation === 'grant' ? 'PENDING_GRANT' : 'PENDING_REVOKE');

type CounterpartyBusinessTarget = Extract<
AuthorizationMutationJournalEntry['businessTarget'],
{ readonly kind: 'counterparty' | 'counterparty_storefront' }
>;

const sameCounterpartyTarget = (
left: CounterpartyBusinessTarget,
right: AuthorizationMutationJournalEntry['businessTarget'],
): boolean =>
left.kind === 'counterparty'
? right.kind === 'counterparty' &&
left.legalEntityId === right.legalEntityId &&
left.counterpartyId === right.counterpartyId
: right.kind === 'counterparty_storefront' &&
left.legalEntityId === right.legalEntityId &&
left.counterpartyId === right.counterpartyId &&
left.storefrontId === right.storefrontId;

const sameBusinessTarget = (
left: AuthorizationMutationJournalEntry['businessTarget'],
right: AuthorizationMutationJournalEntry['businessTarget'],
): boolean => {
if (left.kind !== right.kind || left.tenantId !== right.tenantId) {
return false;
}
if (left.kind === 'counterparty') {
return (
right.kind === 'counterparty' &&
left.legalEntityId === right.legalEntityId &&
left.counterpartyId === right.counterpartyId
);
}
if (left.kind === 'counterparty_storefront') {
return (
right.kind === 'counterparty_storefront' &&
left.legalEntityId === right.legalEntityId &&
left.counterpartyId === right.counterpartyId &&
left.storefrontId === right.storefrontId
);
if (left.kind === 'counterparty' || left.kind === 'counterparty_storefront') {
return sameCounterpartyTarget(left, right);
}
if (left.kind === 'retail_profile') {
return (
Expand All @@ -82,6 +92,14 @@ const sameBusinessTarget = (
if (left.kind === 'pricing_catalog') {
return right.kind === 'pricing_catalog' && left.pricingCatalogId === right.pricingCatalogId;
}
if (left.kind === 'inventory_resource') {
return (
right.kind === 'inventory_resource' &&
left.resource.moduleId === right.resource.moduleId &&
left.resource.resourceId === right.resource.resourceId &&
left.resource.resourceType === right.resource.resourceType
);
}
return (
right.kind === 'price_group' &&
left.pricingCatalogId === right.pricingCatalogId &&
Expand All @@ -97,7 +115,8 @@ const validIntentScope = (entry: AuthorizationMutationJournalEntry): boolean =>
entry.principal.tenantId !== target.tenantId ||
target.tenantId.length === 0 ||
!isBusinessPermissionTargetCompatible({ permission: entry.permission, target }) ||
!hasCanonicalPricingAuthorizationTargetIds(target)
!hasCanonicalPricingAuthorizationTargetIds(target) ||
!hasCanonicalInventoryAuthorizationTarget(target)
) {
return false;
}
Expand All @@ -107,6 +126,9 @@ const validIntentScope = (entry: AuthorizationMutationJournalEntry): boolean =>
if (target.kind === 'price_group') {
return true;
}
if (target.kind === 'inventory_resource') {
return true;
}
if (target.legalEntityId.length === 0) {
return false;
}
Expand Down
Loading
Loading