@open-mercato/shared 0.6.8-develop.7048.1.b011912b63 → 0.6.8-develop.7049.1.b41427429a

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.
@@ -1,10 +1,13 @@
1
+ function isUnrestrictedOrganizationScope(input) {
2
+ return input.isSuperAdmin || input.allowedOrganizationIds === null;
3
+ }
1
4
  function isOrganizationAccessAllowed(input) {
2
- if (input.isSuperAdmin) return true;
3
- if (input.allowedOrganizationIds === null) return true;
5
+ if (isUnrestrictedOrganizationScope(input)) return true;
4
6
  if (!input.targetOrganizationId) return false;
5
- return input.allowedOrganizationIds.includes(input.targetOrganizationId);
7
+ return (input.allowedOrganizationIds ?? []).includes(input.targetOrganizationId);
6
8
  }
7
9
  export {
8
- isOrganizationAccessAllowed
10
+ isOrganizationAccessAllowed,
11
+ isUnrestrictedOrganizationScope
9
12
  };
10
13
  //# sourceMappingURL=organizationAccess.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/lib/auth/organizationAccess.ts"],
4
- "sourcesContent": ["export type OrganizationAccessDecisionInput = {\n isSuperAdmin: boolean\n allowedOrganizationIds: readonly string[] | null\n targetOrganizationId: string | null\n}\n\n/**\n * Fail-closed organization-access predicate. The single source of truth for\n * \"may this principal act on `targetOrganizationId`\".\n *\n * Decision table:\n * - `isSuperAdmin === true` -> allow (global access)\n * - `allowedOrganizationIds === null` -> allow (truly unrestricted)\n * - restricted + no target org -> deny (empty/unknown scope is not a bypass)\n * - restricted + target org -> allow iff the target is a member of the allowed set\n */\nexport function isOrganizationAccessAllowed(input: OrganizationAccessDecisionInput): boolean {\n if (input.isSuperAdmin) return true\n if (input.allowedOrganizationIds === null) return true\n if (!input.targetOrganizationId) return false\n return input.allowedOrganizationIds.includes(input.targetOrganizationId)\n}\n"],
5
- "mappings": "AAgBO,SAAS,4BAA4B,OAAiD;AAC3F,MAAI,MAAM,aAAc,QAAO;AAC/B,MAAI,MAAM,2BAA2B,KAAM,QAAO;AAClD,MAAI,CAAC,MAAM,qBAAsB,QAAO;AACxC,SAAO,MAAM,uBAAuB,SAAS,MAAM,oBAAoB;AACzE;",
4
+ "sourcesContent": ["export type OrganizationAccessDecisionInput = {\n isSuperAdmin: boolean\n allowedOrganizationIds: readonly string[] | null\n targetOrganizationId: string | null\n}\n\nexport type UnrestrictedOrganizationScopeInput = {\n isSuperAdmin: boolean\n allowedOrganizationIds: readonly string[] | null | undefined\n}\n\nexport function isUnrestrictedOrganizationScope(input: UnrestrictedOrganizationScopeInput): boolean {\n return input.isSuperAdmin || input.allowedOrganizationIds === null\n}\n\n/**\n * Fail-closed organization-access predicate. The single source of truth for\n * \"may this principal act on `targetOrganizationId`\".\n *\n * Decision table:\n * - `isSuperAdmin === true` -> allow (global access)\n * - `allowedOrganizationIds === null` -> allow (truly unrestricted)\n * - restricted + no target org -> deny (empty/unknown scope is not a bypass)\n * - restricted + target org -> allow iff the target is a member of the allowed set\n */\nexport function isOrganizationAccessAllowed(input: OrganizationAccessDecisionInput): boolean {\n if (isUnrestrictedOrganizationScope(input)) return true\n if (!input.targetOrganizationId) return false\n return (input.allowedOrganizationIds ?? []).includes(input.targetOrganizationId)\n}\n"],
5
+ "mappings": "AAWO,SAAS,gCAAgC,OAAoD;AAClG,SAAO,MAAM,gBAAgB,MAAM,2BAA2B;AAChE;AAYO,SAAS,4BAA4B,OAAiD;AAC3F,MAAI,gCAAgC,KAAK,EAAG,QAAO;AACnD,MAAI,CAAC,MAAM,qBAAsB,QAAO;AACxC,UAAQ,MAAM,0BAA0B,CAAC,GAAG,SAAS,MAAM,oBAAoB;AACjF;",
6
6
  "names": []
7
7
  }
@@ -1,4 +1,4 @@
1
- const APP_VERSION = "0.6.8-develop.7048.1.b011912b63";
1
+ const APP_VERSION = "0.6.8-develop.7049.1.b41427429a";
2
2
  const appVersion = APP_VERSION;
3
3
  export {
4
4
  APP_VERSION,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/lib/version.ts"],
4
- "sourcesContent": ["// Build-time generated version\nexport const APP_VERSION = '0.6.8-develop.7048.1.b011912b63';\nexport const appVersion = APP_VERSION;\n"],
4
+ "sourcesContent": ["// Build-time generated version\nexport const APP_VERSION = '0.6.8-develop.7049.1.b41427429a';\nexport const appVersion = APP_VERSION;\n"],
5
5
  "mappings": "AACO,MAAM,cAAc;AACpB,MAAM,aAAa;",
6
6
  "names": []
7
7
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@open-mercato/shared",
3
- "version": "0.6.8-develop.7048.1.b011912b63",
3
+ "version": "0.6.8-develop.7049.1.b41427429a",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -109,7 +109,7 @@
109
109
  "@mikro-orm/core": "^7.1.8",
110
110
  "@mikro-orm/decorators": "^7.1.8",
111
111
  "@mikro-orm/postgresql": "^7.1.8",
112
- "@open-mercato/cache": "0.6.8-develop.7048.1.b011912b63",
112
+ "@open-mercato/cache": "0.6.8-develop.7049.1.b41427429a",
113
113
  "@types/html-to-text": "^9.0.4",
114
114
  "@types/sanitize-html": "^2.16.1",
115
115
  "dotenv": "^17.4.2",
@@ -1,4 +1,39 @@
1
- import { isOrganizationAccessAllowed } from '@open-mercato/shared/lib/auth/organizationAccess'
1
+ import {
2
+ isOrganizationAccessAllowed,
3
+ isUnrestrictedOrganizationScope,
4
+ } from '@open-mercato/shared/lib/auth/organizationAccess'
5
+
6
+ describe('isUnrestrictedOrganizationScope', () => {
7
+ it('allows super admins regardless of allowed organizations', () => {
8
+ expect(
9
+ isUnrestrictedOrganizationScope({
10
+ isSuperAdmin: true,
11
+ allowedOrganizationIds: [],
12
+ }),
13
+ ).toBe(true)
14
+ })
15
+
16
+ it('allows truly unrestricted non-superadmin scopes', () => {
17
+ expect(
18
+ isUnrestrictedOrganizationScope({
19
+ isSuperAdmin: false,
20
+ allowedOrganizationIds: null,
21
+ }),
22
+ ).toBe(true)
23
+ })
24
+
25
+ it.each([undefined, [] as string[], ['org-a']])(
26
+ 'denies restricted non-superadmin scopes with allowedOrganizationIds=%p',
27
+ (allowedOrganizationIds) => {
28
+ expect(
29
+ isUnrestrictedOrganizationScope({
30
+ isSuperAdmin: false,
31
+ allowedOrganizationIds,
32
+ }),
33
+ ).toBe(false)
34
+ },
35
+ )
36
+ })
2
37
 
3
38
  describe('isOrganizationAccessAllowed', () => {
4
39
  it('allows super admins regardless of scope', () => {
@@ -4,6 +4,15 @@ export type OrganizationAccessDecisionInput = {
4
4
  targetOrganizationId: string | null
5
5
  }
6
6
 
7
+ export type UnrestrictedOrganizationScopeInput = {
8
+ isSuperAdmin: boolean
9
+ allowedOrganizationIds: readonly string[] | null | undefined
10
+ }
11
+
12
+ export function isUnrestrictedOrganizationScope(input: UnrestrictedOrganizationScopeInput): boolean {
13
+ return input.isSuperAdmin || input.allowedOrganizationIds === null
14
+ }
15
+
7
16
  /**
8
17
  * Fail-closed organization-access predicate. The single source of truth for
9
18
  * "may this principal act on `targetOrganizationId`".
@@ -15,8 +24,7 @@ export type OrganizationAccessDecisionInput = {
15
24
  * - restricted + target org -> allow iff the target is a member of the allowed set
16
25
  */
17
26
  export function isOrganizationAccessAllowed(input: OrganizationAccessDecisionInput): boolean {
18
- if (input.isSuperAdmin) return true
19
- if (input.allowedOrganizationIds === null) return true
27
+ if (isUnrestrictedOrganizationScope(input)) return true
20
28
  if (!input.targetOrganizationId) return false
21
- return input.allowedOrganizationIds.includes(input.targetOrganizationId)
29
+ return (input.allowedOrganizationIds ?? []).includes(input.targetOrganizationId)
22
30
  }