@cedarjs/router 8.0.0-canary.3569 → 8.0.0-canary.3571

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.
@@ -2,7 +2,7 @@ import React from 'react';
2
2
  interface AuthenticatedRouteProps {
3
3
  children: React.ReactNode;
4
4
  roles?: string | string[];
5
- orgPermission?: string;
5
+ permission?: string;
6
6
  unauthenticated: string;
7
7
  unauthorized?: string;
8
8
  whileLoadingAuth?: () => React.ReactElement | null;
@@ -1 +1 @@
1
- {"version":3,"file":"AuthenticatedRoute.d.ts","sourceRoot":"","sources":["../src/AuthenticatedRoute.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAoC,MAAM,OAAO,CAAA;AAQxD,UAAU,uBAAuB;IAC/B,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;IACzB,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAA;IACzB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,eAAe,EAAE,MAAM,CAAA;IACvB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,gBAAgB,CAAC,EAAE,MAAM,KAAK,CAAC,YAAY,GAAG,IAAI,CAAA;CACnD;AA6ED,eAAO,MAAM,kBAAkB,EAAE,KAAK,CAAC,EAAE,CAAC,uBAAuB,CAwIhE,CAAA"}
1
+ {"version":3,"file":"AuthenticatedRoute.d.ts","sourceRoot":"","sources":["../src/AuthenticatedRoute.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAoC,MAAM,OAAO,CAAA;AAQxD,UAAU,uBAAuB;IAC/B,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;IACzB,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAA;IACzB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,eAAe,EAAE,MAAM,CAAA;IACvB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,gBAAgB,CAAC,EAAE,MAAM,KAAK,CAAC,YAAY,GAAG,IAAI,CAAA;CACnD;AA6ED,eAAO,MAAM,kBAAkB,EAAE,KAAK,CAAC,EAAE,CAAC,uBAAuB,CA2IhE,CAAA"}
@@ -45,7 +45,7 @@ const AuthenticatedRoute = ({
45
45
  unauthenticated,
46
46
  unauthorized,
47
47
  roles,
48
- orgPermission,
48
+ permission,
49
49
  whileLoadingAuth,
50
50
  children
51
51
  }) => {
@@ -54,34 +54,34 @@ const AuthenticatedRoute = ({
54
54
  const {
55
55
  loading: authLoading,
56
56
  isAuthenticated,
57
- hasRole
57
+ hasRole,
58
+ hasPermission
58
59
  } = routerState.useAuth();
59
60
  const { pathname } = useLocation();
60
61
  const pathParams = currentPathParams(routerState, pathname);
61
62
  const { tenancy } = routerState;
62
63
  const useOrg = tenancy?.useOrg ?? useNoOrg;
63
64
  const org = useOrg(routerState.useAuth, pathParams);
64
- const needsOrg = orgPermission !== void 0;
65
+ const needsOrg = permission !== void 0 && !!tenancy;
65
66
  if (needsOrg && !org) {
66
- if (!tenancy) {
67
- throw new Error(
68
- "A PrivateSet with `orgPermission` needs `tenancy` on the Router to find the organization with. Please pass `tenancy` from `@cedarjs/tenancy/web`: <Router useAuth={useAuth} tenancy={tenancy}>"
69
- );
70
- }
71
67
  if (authLoading) {
72
68
  return whileLoadingAuth?.() || null;
73
69
  }
74
70
  if (pathParams["orgSlug"] === void 0) {
75
71
  throw new Error(
76
- "A PrivateSet with `orgPermission` needs an organization to check it in, and the route has no `orgSlug` param. Please only use `orgPermission` on routes with `{orgSlug}` in their path, or pass `createTenancy` a `useOrg` that finds the organization another way"
72
+ "A PrivateSet with `permission` needs an organization to check it in, and the route has no `orgSlug` param. Please only use `permission` on routes with `{orgSlug}` in their path, or pass `createTenancy` a `useOrg` that finds the organization another way"
77
73
  );
78
74
  }
79
75
  throw new Error(
80
- "A PrivateSet with `orgPermission` got no organization from the Router's `tenancy` for this route, so there is nothing to check it in"
76
+ "A PrivateSet with `permission` got no organization from the Router's `tenancy` for this route, so there is nothing to check it in"
81
77
  );
82
78
  }
79
+ const auth = {
80
+ hasPermission
81
+ };
83
82
  const hasRequiredRoles = !roles || hasRole(roles);
84
- if (isAuthenticated && hasRequiredRoles) {
83
+ const hasRequiredPermission = !!tenancy || permission === void 0 || auth.hasPermission(permission);
84
+ if (isAuthenticated && hasRequiredRoles && hasRequiredPermission) {
85
85
  if (!tenancy || !org) {
86
86
  return /* @__PURE__ */ React.createElement(React.Fragment, null, children);
87
87
  }
@@ -92,7 +92,7 @@ const AuthenticatedRoute = ({
92
92
  }
93
93
  return /* @__PURE__ */ React.createElement(React.Fragment, null, tenancy.notAMember ?? null);
94
94
  }
95
- const hasRequiredOrgAccess = orgPermission === void 0 || (membership.permissions?.includes(orgPermission) ?? false);
95
+ const hasRequiredOrgAccess = permission === void 0 || (membership.permissions?.includes(permission) ?? false);
96
96
  if (hasRequiredOrgAccess) {
97
97
  if (mountedOrgId === membership.organizationId) {
98
98
  return /* @__PURE__ */ React.createElement(React.Fragment, null, children);
package/dist/Set.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import type { ComponentType, ReactElement, ReactNode } from 'react';
2
2
  import React from 'react';
3
- import type { AuthTenancy, PermissionName } from '@cedarjs/auth' with {
3
+ import type { PermissionName } from '@cedarjs/auth' with {
4
4
  'resolution-mode': 'import'
5
5
  };
6
6
  /**
@@ -25,34 +25,26 @@ export interface WrapperProps {
25
25
  * <Set wrap={PostsScaffoldLayout}>
26
26
  */
27
27
  export type WrapperType = ComponentType<WrapperProps>;
28
- /**
29
- * `orgPermission`, only in an app with tenancy (see `AuthTenancy`)
30
- */
31
- type SetOrgPermission = AuthTenancy extends {
32
- enabled: true;
33
- } ? {
34
- /**
35
- * Route is permitted when authenticated and the user's membership in
36
- * the current organization has this permission (see
37
- * `createPermissions` in `@cedarjs/tenancy`). With `roles` as well,
38
- * they need both.
39
- *
40
- * The organization is the one the Router's `tenancy` finds for the
41
- * route, by default the one with the route's `orgSlug` param:
42
- *
43
- * <Router useAuth={useAuth} tenancy={tenancy}>
44
- *
45
- * A `PrivateSet` with `orgPermission` throws without `tenancy` on the
46
- * router, or on a route that isn't in an organization.
47
- */
48
- orgPermission?: PermissionName;
49
- } : Record<never, never>;
50
- interface SetProps extends SetOrgPermission {
28
+ interface SetProps {
51
29
  /**
52
30
  * Route is permitted when authenticated and user has any of the provided
53
31
  * roles such as "admin" or ["admin", "editor"], in `currentUser.roles`
54
32
  */
55
33
  roles?: string | string[];
34
+ /**
35
+ * Route is permitted when authenticated and the user has this permission
36
+ * (see `cedar setup permissions`). With `roles` as well, they need both.
37
+ *
38
+ * Without tenancy, it's one of the user's own permissions, in
39
+ * `currentUser.permissions`.
40
+ *
41
+ * With `tenancy` on the Router, it's a permission of the user's membership
42
+ * in the route's organization: the one the Router's `tenancy` finds, by
43
+ * default the one with the route's `orgSlug` param. A signed-in user who
44
+ * isn't a member gets the tenancy's `notAMember`. A `PrivateSet` with
45
+ * `permission` throws on a route that isn't in an organization.
46
+ */
47
+ permission?: PermissionName;
56
48
  /**
57
49
  * Components to wrap all routes in this set with, like layouts. The first
58
50
  * one in an array is the outermost one.
@@ -106,8 +98,8 @@ type PrivateSetProps = Omit<SetProps, 'private' | 'unauthenticated' | 'unauthori
106
98
  unauthenticated: string;
107
99
  /**
108
100
  * The page name where a user will be redirected when authenticated but
109
- * without the required roles. Without it, they're redirected to
110
- * `unauthenticated`.
101
+ * without the required roles or permission. Without it, they're
102
+ * redirected to `unauthenticated`.
111
103
  */
112
104
  unauthorized?: string;
113
105
  };
package/dist/Set.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"Set.d.ts","sourceRoot":"","sources":["../src/Set.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AACnE,OAAO,KAAK,MAAM,OAAO,CAAA;AAEzB,OAAO,KAAK,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;IAC/D,iBAAiB,EAAE,QAAQ;CAC5B,CAAA;AAED;;;GAGG;AACH,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,SAAS,CAAA;CACpB;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,MAAM,WAAW,GAAG,aAAa,CAAC,YAAY,CAAC,CAAA;AAErD;;GAEG;AACH,KAAK,gBAAgB,GAAG,WAAW,SAAS;IAAE,OAAO,EAAE,IAAI,CAAA;CAAE,GACzD;IACE;;;;;;;;;;;;;OAaG;IACH,aAAa,CAAC,EAAE,cAAc,CAAA;CAC/B,GACD,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,CAAA;AAExB,UAAU,QAAS,SAAQ,gBAAgB;IACzC;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAA;IACzB;;;;;OAKG;IACH,IAAI,CAAC,EAAE,WAAW,GAAG,SAAS,WAAW,EAAE,CAAA;IAC3C;;;;;;OAMG;IACH,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB;;;;OAIG;IACH,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB;;;;;OAKG;IACH,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,qCAAqC;IACrC,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,QAAQ,EAAE,SAAS,CAAA;IACnB,8DAA8D;IAC9D,gBAAgB,CAAC,EAAE,MAAM,YAAY,GAAG,IAAI,CAAA;IAC5C,gBAAgB,CAAC,EAAE,MAAM,YAAY,GAAG,IAAI,CAAA;CAC7C;AAED;;;;;;;GAOG;AACH,wBAAgB,GAAG,CAAC,KAAK,EAAE,QAAQ,qBAIlC;AAED,KAAK,eAAe,GAAG,IAAI,CACzB,QAAQ,EACR,SAAS,GAAG,iBAAiB,GAAG,cAAc,CAC/C,GAAG;IACF;;;;OAIG;IACH,eAAe,EAAE,MAAM,CAAA;IACvB;;;;OAIG;IACH,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB,CAAA;AAED,oDAAoD;AACpD,wBAAgB,OAAO,CAAC,KAAK,EAAE,eAAe,qBAI7C;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,eAAe,qBAIhD;AAED,eAAO,MAAM,SAAS,GAAI,MAAM,SAAS,KAAG,IAAI,IAAI,YAAY,CAAC,QAAQ,CAOxE,CAAA;AAED,eAAO,MAAM,gBAAgB,GAC3B,MAAM,SAAS,KACd,IAAI,IAAI,YAAY,CAAC,eAAe,CAEtC,CAAA;AAGD,eAAO,MAAM,aAAa,GACxB,MAAM,SAAS,KACd,IAAI,IAAI,YAAY,CAAC,eAAe,CAEtC,CAAA;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,SAAS,WAAW,EAAE,EAChC,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,SAAS,aAKpB"}
1
+ {"version":3,"file":"Set.d.ts","sourceRoot":"","sources":["../src/Set.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AACnE,OAAO,KAAK,MAAM,OAAO,CAAA;AAEzB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;IAClD,iBAAiB,EAAE,QAAQ;CAC5B,CAAA;AAED;;;GAGG;AACH,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,SAAS,CAAA;CACpB;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,MAAM,WAAW,GAAG,aAAa,CAAC,YAAY,CAAC,CAAA;AAErD,UAAU,QAAQ;IAChB;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAA;IACzB;;;;;;;;;;;;OAYG;IACH,UAAU,CAAC,EAAE,cAAc,CAAA;IAC3B;;;;;OAKG;IACH,IAAI,CAAC,EAAE,WAAW,GAAG,SAAS,WAAW,EAAE,CAAA;IAC3C;;;;;;OAMG;IACH,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB;;;;OAIG;IACH,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB;;;;;OAKG;IACH,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,qCAAqC;IACrC,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,QAAQ,EAAE,SAAS,CAAA;IACnB,8DAA8D;IAC9D,gBAAgB,CAAC,EAAE,MAAM,YAAY,GAAG,IAAI,CAAA;IAC5C,gBAAgB,CAAC,EAAE,MAAM,YAAY,GAAG,IAAI,CAAA;CAC7C;AAED;;;;;;;GAOG;AACH,wBAAgB,GAAG,CAAC,KAAK,EAAE,QAAQ,qBAIlC;AAED,KAAK,eAAe,GAAG,IAAI,CACzB,QAAQ,EACR,SAAS,GAAG,iBAAiB,GAAG,cAAc,CAC/C,GAAG;IACF;;;;OAIG;IACH,eAAe,EAAE,MAAM,CAAA;IACvB;;;;OAIG;IACH,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB,CAAA;AAED,oDAAoD;AACpD,wBAAgB,OAAO,CAAC,KAAK,EAAE,eAAe,qBAI7C;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,eAAe,qBAIhD;AAED,eAAO,MAAM,SAAS,GAAI,MAAM,SAAS,KAAG,IAAI,IAAI,YAAY,CAAC,QAAQ,CAOxE,CAAA;AAED,eAAO,MAAM,gBAAgB,GAC3B,MAAM,SAAS,KACd,IAAI,IAAI,YAAY,CAAC,eAAe,CAEtC,CAAA;AAGD,eAAO,MAAM,aAAa,GACxB,MAAM,SAAS,KACd,IAAI,IAAI,YAAY,CAAC,eAAe,CAEtC,CAAA;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,SAAS,WAAW,EAAE,EAChC,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,SAAS,aAKpB"}
@@ -16,7 +16,7 @@ interface SetRenderProps {
16
16
  unauthenticated?: string;
17
17
  unauthorized?: string;
18
18
  roles?: string | string[];
19
- orgPermission?: string;
19
+ permission?: string;
20
20
  whileLoadingAuth?: () => ReactElement | null;
21
21
  }
22
22
  interface Set {
@@ -1 +1 @@
1
- {"version":3,"file":"analyzeRoutes.d.ts","sourceRoot":"","sources":["../src/analyzeRoutes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAGpD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAA;AAQzC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAA;AAC3C,OAAO,EAIL,KAAK,SAAS,EACf,MAAM,WAAW,CAAA;AAElB,KAAK,gBAAgB,GAAG,MAAM,YAAY,GAAG,IAAI,CAAA;AAIjD,MAAM,MAAM,kBAAkB,GAAG;IAC/B,CAAC,GAAG,EAAE,MAAM,GAAG,CACb,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,GAAG,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,KACtD,MAAM,CAAA;CACZ,CAAA;AAED,MAAM,MAAM,QAAQ,GAAG,SAAS,WAAW,EAAE,CAAA;AAE7C;;;GAGG;AACH,UAAU,cAAc;IACtB,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAA;IAEzB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,gBAAgB,CAAC,EAAE,MAAM,YAAY,GAAG,IAAI,CAAA;CAC7C;AAED,UAAU,GAAG;IACX,EAAE,EAAE,MAAM,CAAA;IACV,QAAQ,EAAE,QAAQ,CAAA;IAClB,SAAS,EAAE,OAAO,CAAA;IAClB,KAAK,EAAE,cAAc,CAAA;CACtB;AA+CD,KAAK,SAAS,GAAG,MAAM,CAAA;AAEvB;;;;GAIG;AACH,UAAU,aAAa;IACrB,IAAI,EAAE,SAAS,CAAA;IACf,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;IACnB,gBAAgB,CAAC,EAAE,gBAAgB,CAAA;IACnC,IAAI,EAAE,QAAQ,GAAG,IAAI,CAAA;IACrB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;IACvB,IAAI,EAAE,GAAG,EAAE,CAAA;CACZ;AAED,UAAU,oBAAoB;IAC5B,eAAe,EAAE,MAAM,CAAA;IACvB,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAA;CAC3C;AAED,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,SAAS,EACnB,EAAE,eAAe,EAAE,cAAc,EAAE,EAAE,oBAAoB;;;;;;EAqK1D"}
1
+ {"version":3,"file":"analyzeRoutes.d.ts","sourceRoot":"","sources":["../src/analyzeRoutes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAGpD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAA;AAQzC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAA;AAC3C,OAAO,EAIL,KAAK,SAAS,EACf,MAAM,WAAW,CAAA;AAElB,KAAK,gBAAgB,GAAG,MAAM,YAAY,GAAG,IAAI,CAAA;AAIjD,MAAM,MAAM,kBAAkB,GAAG;IAC/B,CAAC,GAAG,EAAE,MAAM,GAAG,CACb,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,GAAG,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,KACtD,MAAM,CAAA;CACZ,CAAA;AAED,MAAM,MAAM,QAAQ,GAAG,SAAS,WAAW,EAAE,CAAA;AAE7C;;;GAGG;AACH,UAAU,cAAc;IACtB,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAA;IACzB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,gBAAgB,CAAC,EAAE,MAAM,YAAY,GAAG,IAAI,CAAA;CAC7C;AAED,UAAU,GAAG;IACX,EAAE,EAAE,MAAM,CAAA;IACV,QAAQ,EAAE,QAAQ,CAAA;IAClB,SAAS,EAAE,OAAO,CAAA;IAClB,KAAK,EAAE,cAAc,CAAA;CACtB;AA+CD,KAAK,SAAS,GAAG,MAAM,CAAA;AAEvB;;;;GAIG;AACH,UAAU,aAAa;IACrB,IAAI,EAAE,SAAS,CAAA;IACf,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;IACnB,gBAAgB,CAAC,EAAE,gBAAgB,CAAA;IACnC,IAAI,EAAE,QAAQ,GAAG,IAAI,CAAA;IACrB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;IACvB,IAAI,EAAE,GAAG,EAAE,CAAA;CACZ;AAED,UAAU,oBAAoB;IAC5B,eAAe,EAAE,MAAM,CAAA;IACvB,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAA;CAC3C;AAED,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,SAAS,EACnB,EAAE,eAAe,EAAE,cAAc,EAAE,EAAE,oBAAoB;;;;;;EAqK1D"}
@@ -25,8 +25,8 @@ function pickSetRenderProps(props) {
25
25
  if (props.roles !== void 0) {
26
26
  picked.roles = props.roles;
27
27
  }
28
- if (props.orgPermission !== void 0) {
29
- picked.orgPermission = props.orgPermission;
28
+ if (props.permission !== void 0) {
29
+ picked.permission = props.permission;
30
30
  }
31
31
  if (props.whileLoadingAuth !== void 0) {
32
32
  picked.whileLoadingAuth = props.whileLoadingAuth;
@@ -15,7 +15,7 @@ export interface RouterMembership {
15
15
  organizationId: string;
16
16
  /** The user's role in the organization, passed on to the `OrgProvider` */
17
17
  role: string;
18
- /** What the membership may do, for `<PrivateSet orgPermission>` */
18
+ /** What the membership may do, for `<PrivateSet permission>` */
19
19
  permissions?: readonly string[] | undefined;
20
20
  }
21
21
  /**
@@ -35,9 +35,9 @@ export interface RouterOrg {
35
35
  *
36
36
  * One of the app's own can answer in three ways:
37
37
  * - an organization, with the user's membership in it or `null` for none.
38
- * A set with `orgPermission` denies a user with no
38
+ * A set with `permission` denies a user with no
39
39
  * membership, and the router renders the tenancy's `notAMember`.
40
- * - `null`, for no organization: a set with `orgPermission` then
40
+ * - `null`, for no organization: a set with `permission` then
41
41
  * throws the router's own error.
42
42
  * - throw an error of its own, such as for an organization that's been
43
43
  * suspended. It reaches the app's error boundary like any error thrown
@@ -55,7 +55,7 @@ export interface OrgProviderProps {
55
55
  * How the router handles organizations. `createTenancy` from
56
56
  * `@cedarjs/tenancy/web` makes one. The router renders its `OrgProvider`
57
57
  * around the layouts and page of a `PrivateSet` whose route is in an
58
- * organization, and checks `orgPermission` against the
58
+ * organization, and checks a set's `permission` against the
59
59
  * membership its `useOrg` finds.
60
60
  */
61
61
  export interface Tenancy {
@@ -1 +1 @@
1
- {"version":3,"file":"router-context.d.ts","sourceRoot":"","sources":["../src/router-context.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA6C,MAAM,OAAO,CAAA;AAEjE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;IACxD,iBAAiB,EAAE,QAAQ;CAC5B,CAAA;AAGD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AACvD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAA;AAE1C,MAAM,MAAM,OAAO,GAAG,MAAM,oBAAoB,CAC9C,OAAO,EACP,OAAO,EACP,OAAO,EACP,OAAO,EACP,OAAO,EACP,OAAO,EACP,OAAO,EACP,OAAO,EACP,OAAO,EACP,OAAO,EACP,OAAO,EACP,OAAO,CACR,CAAA;AAED;;;;GAIG;AACH,MAAM,WAAW,gBAAgB;IAC/B,2EAA2E;IAC3E,cAAc,EAAE,MAAM,CAAA;IACtB,0EAA0E;IAC1E,IAAI,EAAE,MAAM,CAAA;IACZ,mEAAmE;IACnE,WAAW,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,CAAA;CAC5C;AAED;;;;GAIG;AACH,MAAM,WAAW,SAAS;IACxB,UAAU,EAAE,gBAAgB,GAAG,IAAI,CAAA;IACnC,WAAW,EAAE,SAAS,gBAAgB,EAAE,CAAA;CACzC;AAED;;;;;;;;;;;;;;;GAeG;AACH,MAAM,MAAM,MAAM,GAAG,CACnB,OAAO,EAAE,OAAO,EAChB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,KAC3B,SAAS,GAAG,IAAI,CAAA;AAErB,sDAAsD;AACtD,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,OAAO,CAAA;IAChB,UAAU,EAAE,gBAAgB,CAAA;IAC5B,WAAW,EAAE,SAAS,gBAAgB,EAAE,CAAA;IACxC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;CAC1B;AAED;;;;;;GAMG;AACH,MAAM,WAAW,OAAO;IACtB,MAAM,EAAE,MAAM,CAAA;IACd,uDAAuD;IACvD,WAAW,EAAE,KAAK,CAAC,aAAa,CAAC,gBAAgB,CAAC,CAAA;IAClD,mFAAmF;IACnF,UAAU,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;CAC7B;AAED,MAAM,WAAW,WAAW;IAC1B,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAA;IACtC,OAAO,EAAE,OAAO,CAAA;IAChB,sDAAsD;IACtD,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,MAAM,EAAE,UAAU,CAAC,OAAO,aAAa,CAAC,CAAA;IACxC,eAAe,CAAC,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAAA;CAC5C;AAID,MAAM,WAAW,0BAA2B,SAAQ,IAAI,CACtD,WAAW,EACX,SAAS,CACV;IACC,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,MAAM,EAAE,UAAU,CAAC,OAAO,aAAa,CAAC,CAAA;IACxC,eAAe,CAAC,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAAA;IAC3C,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;CAC1B;AAED,eAAO,MAAM,qBAAqB,EAAE,KAAK,CAAC,EAAE,CAAC,0BAA0B,CAwBtE,CAAA;AAED,eAAO,MAAM,cAAc,mBAU1B,CAAA"}
1
+ {"version":3,"file":"router-context.d.ts","sourceRoot":"","sources":["../src/router-context.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA6C,MAAM,OAAO,CAAA;AAEjE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;IACxD,iBAAiB,EAAE,QAAQ;CAC5B,CAAA;AAGD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AACvD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAA;AAE1C,MAAM,MAAM,OAAO,GAAG,MAAM,oBAAoB,CAC9C,OAAO,EACP,OAAO,EACP,OAAO,EACP,OAAO,EACP,OAAO,EACP,OAAO,EACP,OAAO,EACP,OAAO,EACP,OAAO,EACP,OAAO,EACP,OAAO,EACP,OAAO,CACR,CAAA;AAED;;;;GAIG;AACH,MAAM,WAAW,gBAAgB;IAC/B,2EAA2E;IAC3E,cAAc,EAAE,MAAM,CAAA;IACtB,0EAA0E;IAC1E,IAAI,EAAE,MAAM,CAAA;IACZ,gEAAgE;IAChE,WAAW,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,CAAA;CAC5C;AAED;;;;GAIG;AACH,MAAM,WAAW,SAAS;IACxB,UAAU,EAAE,gBAAgB,GAAG,IAAI,CAAA;IACnC,WAAW,EAAE,SAAS,gBAAgB,EAAE,CAAA;CACzC;AAED;;;;;;;;;;;;;;;GAeG;AACH,MAAM,MAAM,MAAM,GAAG,CACnB,OAAO,EAAE,OAAO,EAChB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,KAC3B,SAAS,GAAG,IAAI,CAAA;AAErB,sDAAsD;AACtD,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,OAAO,CAAA;IAChB,UAAU,EAAE,gBAAgB,CAAA;IAC5B,WAAW,EAAE,SAAS,gBAAgB,EAAE,CAAA;IACxC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;CAC1B;AAED;;;;;;GAMG;AACH,MAAM,WAAW,OAAO;IACtB,MAAM,EAAE,MAAM,CAAA;IACd,uDAAuD;IACvD,WAAW,EAAE,KAAK,CAAC,aAAa,CAAC,gBAAgB,CAAC,CAAA;IAClD,mFAAmF;IACnF,UAAU,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;CAC7B;AAED,MAAM,WAAW,WAAW;IAC1B,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAA;IACtC,OAAO,EAAE,OAAO,CAAA;IAChB,sDAAsD;IACtD,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,MAAM,EAAE,UAAU,CAAC,OAAO,aAAa,CAAC,CAAA;IACxC,eAAe,CAAC,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAAA;CAC5C;AAID,MAAM,WAAW,0BAA2B,SAAQ,IAAI,CACtD,WAAW,EACX,SAAS,CACV;IACC,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,MAAM,EAAE,UAAU,CAAC,OAAO,aAAa,CAAC,CAAA;IACxC,eAAe,CAAC,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAAA;IAC3C,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;CAC1B;AAED,eAAO,MAAM,qBAAqB,EAAE,KAAK,CAAC,EAAE,CAAC,0BAA0B,CAwBtE,CAAA;AAED,eAAO,MAAM,cAAc,mBAU1B,CAAA"}
package/dist/router.d.ts CHANGED
@@ -6,15 +6,14 @@ import type { AuthTenancy } from '@cedarjs/auth' with {
6
6
  import type { RouterContextProviderProps, Tenancy } from './router-context.js';
7
7
  import type { TrailingSlashesTypes } from './util.js';
8
8
  /**
9
- * `tenancy`, only in an app with tenancy (see `AuthTenancy`), where sets have
10
- * `orgPermission`
9
+ * `tenancy`, only in an app with tenancy (see `AuthTenancy`)
11
10
  */
12
11
  type RouterTenancy = AuthTenancy extends {
13
12
  enabled: true;
14
13
  } ? {
15
14
  /**
16
15
  * How the router handles organizations: finding the one of the current
17
- * route, checking `orgPermission` in it, and providing
16
+ * route, checking a set's `permission` in it, and providing
18
17
  * it to the layouts and page of a `PrivateSet`. Pass the `tenancy` from
19
18
  * `createTenancy` in `@cedarjs/tenancy/web`:
20
19
  *
@@ -1 +1 @@
1
- {"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../src/router.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAgB,SAAS,EAAE,MAAM,OAAO,CAAA;AACpD,OAAO,KAAwB,MAAM,OAAO,CAAA;AAE5C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;IAC/C,iBAAiB,EAAE,QAAQ;CAC5B,CAAA;AAYD,OAAO,KAAK,EAAE,0BAA0B,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAK9E,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAA;AAErD;;;GAGG;AACH,KAAK,aAAa,GAAG,WAAW,SAAS;IAAE,OAAO,EAAE,IAAI,CAAA;CAAE,GACtD;IACE;;;;;;;OAOG;IACH,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB,GACD,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,CAAA;AAExB,MAAM,WAAW,WACf,SACE,IAAI,CAAC,0BAA0B,EAAE,QAAQ,GAAG,iBAAiB,GAAG,SAAS,CAAC,EAC1E,aAAa;IACf,eAAe,CAAC,EAAE,oBAAoB,CAAA;IACtC,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,QAAQ,EAAE,SAAS,CAAA;CACpB;AAsCD,eAAO,MAAM,MAAM,EAAE,KAAK,CAAC,EAAE,CAAC,WAAW,CAAwB,CAAA"}
1
+ {"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../src/router.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAgB,SAAS,EAAE,MAAM,OAAO,CAAA;AACpD,OAAO,KAAwB,MAAM,OAAO,CAAA;AAE5C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;IAC/C,iBAAiB,EAAE,QAAQ;CAC5B,CAAA;AAYD,OAAO,KAAK,EAAE,0BAA0B,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAK9E,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAA;AAErD;;GAEG;AACH,KAAK,aAAa,GAAG,WAAW,SAAS;IAAE,OAAO,EAAE,IAAI,CAAA;CAAE,GACtD;IACE;;;;;;;OAOG;IACH,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB,GACD,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,CAAA;AAExB,MAAM,WAAW,WACf,SACE,IAAI,CAAC,0BAA0B,EAAE,QAAQ,GAAG,iBAAiB,GAAG,SAAS,CAAC,EAC1E,aAAa;IACf,eAAe,CAAC,EAAE,oBAAoB,CAAA;IACtC,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,QAAQ,EAAE,SAAS,CAAA;CACpB;AAsCD,eAAO,MAAM,MAAM,EAAE,KAAK,CAAC,EAAE,CAAC,WAAW,CAAwB,CAAA"}
package/dist/router.js CHANGED
@@ -163,7 +163,7 @@ const WrappedPage = memo(({ sets, children }) => {
163
163
  unauthenticated,
164
164
  unauthorized: set.props.unauthorized,
165
165
  roles: set.props.roles,
166
- orgPermission: set.props.orgPermission,
166
+ permission: set.props.permission,
167
167
  whileLoadingAuth: set.props.whileLoadingAuth
168
168
  },
169
169
  wrapped
@@ -33,11 +33,6 @@ const LocationAwareRouter = ({
33
33
  return /* @__PURE__ */ React.createElement(RscRoutes, { pathname, search });
34
34
  }
35
35
  const requestedRoute = pathRouteMap[activeRoutePath];
36
- for (const set of requestedRoute.sets) {
37
- if (set.props.orgPermission !== void 0) {
38
- throw new Error("`orgPermission` is not supported with RSC yet");
39
- }
40
- }
41
36
  const reversedSets = requestedRoute.sets.toReversed();
42
37
  const privateSet = reversedSets.find((set) => set.isPrivate);
43
38
  if (privateSet) {
@@ -101,16 +101,18 @@ function hasRole(requiredRoles) {
101
101
  const requiredRolesArray = Array.isArray(requiredRoles) ? requiredRoles : [requiredRoles];
102
102
  return requiredRolesArray.some((role) => roles.includes(role));
103
103
  }
104
+ function hasPermission(permission) {
105
+ const { currentUser } = getAuthState();
106
+ const permissions = currentUser && typeof currentUser === "object" && "permissions" in currentUser ? currentUser.permissions : void 0;
107
+ return Array.isArray(permissions) && permissions.includes(permission);
108
+ }
104
109
  const AuthenticatedRoute = ({
105
110
  children,
106
111
  roles,
107
- orgPermission
112
+ permission
108
113
  }) => {
109
114
  const { isAuthenticated } = getAuthState();
110
- if (orgPermission !== void 0) {
111
- throw new Error("`orgPermission` is not supported with RSC yet");
112
- }
113
- const isAuthorized = isAuthenticated && (!roles || hasRole(roles));
115
+ const isAuthorized = isAuthenticated && (!roles || hasRole(roles)) && (permission === void 0 || hasPermission(permission));
114
116
  if (isAuthorized) {
115
117
  return /* @__PURE__ */ React.createElement(React.Fragment, null, children);
116
118
  }
@@ -137,7 +139,7 @@ const WrappedPage = ({ routeLoaderElement, sets }) => {
137
139
  {
138
140
  unauthenticated,
139
141
  roles: set.props.roles,
140
- orgPermission: set.props.orgPermission,
142
+ permission: set.props.permission,
141
143
  whileLoadingAuth: set.props.whileLoadingAuth
142
144
  },
143
145
  wrapped
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cedarjs/router",
3
- "version": "8.0.0-canary.3569",
3
+ "version": "8.0.0-canary.3571",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/cedarjs/cedar.git",
@@ -52,15 +52,15 @@
52
52
  "test:watch": "vitest watch"
53
53
  },
54
54
  "dependencies": {
55
- "@cedarjs/project-config": "8.0.0-canary.3569",
56
- "@cedarjs/server-store": "8.0.0-canary.3569",
55
+ "@cedarjs/project-config": "8.0.0-canary.3571",
56
+ "@cedarjs/server-store": "8.0.0-canary.3571",
57
57
  "react-server-dom-webpack": "19.3.1",
58
58
  "ts-toolbelt": "9.6.0"
59
59
  },
60
60
  "devDependencies": {
61
61
  "@arethetypeswrong/cli": "0.18.5",
62
- "@cedarjs/auth": "8.0.0-canary.3569",
63
- "@cedarjs/framework-tools": "8.0.0-canary.3569",
62
+ "@cedarjs/auth": "8.0.0-canary.3571",
63
+ "@cedarjs/framework-tools": "8.0.0-canary.3571",
64
64
  "@testing-library/jest-dom": "6.9.1",
65
65
  "@types/react": "^19.2.0",
66
66
  "@types/react-dom": "^19.2.0",
@@ -74,7 +74,7 @@
74
74
  "vitest": "4.1.12"
75
75
  },
76
76
  "peerDependencies": {
77
- "@cedarjs/auth": "8.0.0-canary.3569",
77
+ "@cedarjs/auth": "8.0.0-canary.3571",
78
78
  "react": "19.3.1",
79
79
  "react-dom": "19.3.1"
80
80
  },