@cedarjs/router 8.0.0-canary.3542 → 8.0.0-canary.3546

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,9 +1,10 @@
1
1
  import React from 'react';
2
2
  interface AuthenticatedRouteProps {
3
- children: React.ReactNode | Thenable<React.ReactNode>;
3
+ children: React.ReactNode;
4
4
  roles?: string | string[];
5
5
  userRoles?: string | string[];
6
6
  orgRoles?: string | string[];
7
+ orgPermission?: string;
7
8
  unauthenticated: string;
8
9
  unauthorized?: string;
9
10
  whileLoadingAuth?: () => React.ReactElement | null;
@@ -1 +1 @@
1
- {"version":3,"file":"AuthenticatedRoute.d.ts","sourceRoot":"","sources":["../src/AuthenticatedRoute.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAQzB,UAAU,uBAAuB;IAC/B,QAAQ,EAAE,KAAK,CAAC,SAAS,GAAG,QAAQ,CAAC,KAAK,CAAC,SAAS,CAAC,CAAA;IACrD,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAA;IACzB,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAA;IAC7B,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAA;IAC5B,eAAe,EAAE,MAAM,CAAA;IACvB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,gBAAgB,CAAC,EAAE,MAAM,KAAK,CAAC,YAAY,GAAG,IAAI,CAAA;CACnD;AAsED,eAAO,MAAM,kBAAkB,EAAE,KAAK,CAAC,EAAE,CAAC,uBAAuB,CA4FhE,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,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAA;IAC7B,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAA;IAC5B,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;AAgFD,eAAO,MAAM,kBAAkB,EAAE,KAAK,CAAC,EAAE,CAAC,uBAAuB,CAkJhE,CAAA"}
@@ -1,10 +1,12 @@
1
- import React from "react";
1
+ import React, { createContext, useContext } from "react";
2
2
  import { useLocation } from "./location.js";
3
3
  import { Redirect } from "./redirect.js";
4
4
  import { useRouterState } from "./router-context.js";
5
5
  import { paramsForRoute, pathParamsText } from "./util.js";
6
6
  const REPLACE = { replace: true };
7
- const useNoOrgRoles = () => null;
7
+ const useNoOrg = () => null;
8
+ const MountedOrgContext = createContext(void 0);
9
+ const toList = (roles) => Array.isArray(roles) ? roles : [roles];
8
10
  function currentPathParams(routerState, pathname) {
9
11
  const route = Object.values(routerState.routes.pathRouteMap).find(
10
12
  (candidate) => candidate.name === routerState.activeRouteName
@@ -46,10 +48,12 @@ const AuthenticatedRoute = ({
46
48
  roles,
47
49
  userRoles,
48
50
  orgRoles,
51
+ orgPermission,
49
52
  whileLoadingAuth,
50
53
  children
51
54
  }) => {
52
55
  const routerState = useRouterState();
56
+ const mountedOrgId = useContext(MountedOrgContext);
53
57
  const {
54
58
  loading: authLoading,
55
59
  isAuthenticated,
@@ -57,26 +61,57 @@ const AuthenticatedRoute = ({
57
61
  } = routerState.useAuth();
58
62
  const { pathname } = useLocation();
59
63
  const pathParams = currentPathParams(routerState, pathname);
60
- const useOrgRoles = routerState.useOrgRoles ?? useNoOrgRoles;
61
- const hasOrgRole = useOrgRoles(routerState.useAuth, pathParams);
62
- if (orgRoles !== void 0 && !hasOrgRole) {
63
- if (!routerState.useOrgRoles) {
64
+ const { tenancy } = routerState;
65
+ const useOrg = tenancy?.useOrg ?? useNoOrg;
66
+ const org = useOrg(routerState.useAuth, pathParams);
67
+ const needsOrg = orgRoles !== void 0 || orgPermission !== void 0;
68
+ if (needsOrg && !org) {
69
+ const prop = orgRoles !== void 0 ? "orgRoles" : "orgPermission";
70
+ if (!tenancy) {
64
71
  throw new Error(
65
- "A PrivateSet with `orgRoles` needs `useOrgRoles` on the Router to check the role with. Please pass `useOrgRoles` from `@cedarjs/tenancy/web`: <Router useAuth={useAuth} useOrgRoles={useOrgRoles}>"
72
+ `A PrivateSet with \`${prop}\` needs \`tenancy\` on the Router to find the organization with. Please pass \`tenancy\` from \`@cedarjs/tenancy/web\`: <Router useAuth={useAuth} tenancy={tenancy}>`
66
73
  );
67
74
  }
75
+ if (authLoading) {
76
+ return whileLoadingAuth?.() || null;
77
+ }
68
78
  if (pathParams["orgSlug"] === void 0) {
69
79
  throw new Error(
70
- "A PrivateSet with `orgRoles` needs an organization to check the role in, and the route has no `orgSlug` param. Please only use `orgRoles` on routes with `{orgSlug}` in their path, or pass the Router a `useOrgRoles` that finds the organization another way"
80
+ `A PrivateSet with \`${prop}\` needs an organization to check it in, and the route has no \`orgSlug\` param. Please only use \`${prop}\` on routes with \`{orgSlug}\` in their path, or pass \`createTenancy\` a \`useOrg\` that finds the organization another way`
71
81
  );
72
82
  }
73
83
  throw new Error(
74
- "A PrivateSet with `orgRoles` got no role check from the Router's `useOrgRoles` for this route, so there is no organization to check the role in"
84
+ `A PrivateSet with \`${prop}\` got no organization from the Router's \`tenancy\` for this route, so there is nothing to check it in`
75
85
  );
76
86
  }
77
- const hasRequiredRoles = (!roles || hasRole(roles)) && (!userRoles || hasRole(userRoles)) && (orgRoles === void 0 || !!hasOrgRole && hasOrgRole(orgRoles));
78
- if (isAuthenticated && hasRequiredRoles) {
79
- return /* @__PURE__ */ React.createElement(React.Fragment, null, children);
87
+ const hasRequiredUserRoles = (!roles || hasRole(roles)) && (!userRoles || hasRole(userRoles));
88
+ if (isAuthenticated && hasRequiredUserRoles) {
89
+ if (!tenancy || !org) {
90
+ return /* @__PURE__ */ React.createElement(React.Fragment, null, children);
91
+ }
92
+ const { membership, memberships } = org;
93
+ if (!membership) {
94
+ if (authLoading) {
95
+ return whileLoadingAuth?.() || null;
96
+ }
97
+ return /* @__PURE__ */ React.createElement(React.Fragment, null, tenancy.notAMember ?? null);
98
+ }
99
+ const hasRequiredOrgAccess = (orgRoles === void 0 || toList(orgRoles).includes(membership.role)) && (orgPermission === void 0 || (membership.permissions?.includes(orgPermission) ?? false));
100
+ if (hasRequiredOrgAccess) {
101
+ if (mountedOrgId === membership.organizationId) {
102
+ return /* @__PURE__ */ React.createElement(React.Fragment, null, children);
103
+ }
104
+ return /* @__PURE__ */ React.createElement(
105
+ tenancy.OrgProvider,
106
+ {
107
+ key: membership.organizationId,
108
+ useAuth: routerState.useAuth,
109
+ membership,
110
+ memberships
111
+ },
112
+ /* @__PURE__ */ React.createElement(MountedOrgContext.Provider, { value: membership.organizationId }, children)
113
+ );
114
+ }
80
115
  }
81
116
  if (authLoading) {
82
117
  return whileLoadingAuth?.() || null;
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 } from '@cedarjs/auth' with {
3
+ import type { AuthTenancy, PermissionName } from '@cedarjs/auth' with {
4
4
  'resolution-mode': 'import'
5
5
  };
6
6
  /**
@@ -28,7 +28,7 @@ export type WrapperType = ComponentType<WrapperProps>;
28
28
  /**
29
29
  * The role props. An app with tenancy (see `AuthTenancy`) has `userRoles` and
30
30
  * `orgRoles` instead of `roles`: there, every role check says which kind it
31
- * is.
31
+ * is. It also has `orgPermission`.
32
32
  */
33
33
  type SetRoles = AuthTenancy extends {
34
34
  enabled: true;
@@ -45,15 +45,22 @@ type SetRoles = AuthTenancy extends {
45
45
  * provided roles such as "owner" or ["owner", "admin"] in the current
46
46
  * organization. With `userRoles` as well, they need both.
47
47
  *
48
- * The organization is the one with the route's `orgSlug` param, and
49
- * the router checks the role with the `useOrgRoles` passed to it:
48
+ * The organization is the one the Router's `tenancy` finds for the
49
+ * route, by default the one with the route's `orgSlug` param:
50
50
  *
51
- * <Router useAuth={useAuth} useOrgRoles={useOrgRoles}>
51
+ * <Router useAuth={useAuth} tenancy={tenancy}>
52
52
  *
53
- * A `PrivateSet` with `orgRoles` throws without `useOrgRoles` on the
54
- * router, or on a route without `{orgSlug}` in its path.
53
+ * A `PrivateSet` with `orgRoles` throws without `tenancy` on the
54
+ * router, or on a route that isn't in an organization.
55
55
  */
56
56
  orgRoles?: string | string[];
57
+ /**
58
+ * Route is permitted when authenticated and the user's membership in
59
+ * the current organization has this permission (see
60
+ * `createPermissions` in `@cedarjs/tenancy`). The organization is found
61
+ * like for `orgRoles`, which it can be combined with: they need both.
62
+ */
63
+ orgPermission?: PermissionName;
57
64
  } : {
58
65
  /**
59
66
  * Route is permitted when authenticated and user has any of the
@@ -130,6 +137,10 @@ export declare function Private(props: PrivateSetProps): React.JSX.Element;
130
137
  * `unauthorized`. Either route can have path params the current route has,
131
138
  * like `orgSlug`: they're filled in from the current route.
132
139
  *
140
+ * In an app with tenancy, a `PrivateSet` whose routes have `{orgSlug}` in
141
+ * their path provides the organization to its layouts and page, see `tenancy`
142
+ * on the `Router`.
143
+ *
133
144
  * Coming from React Router or a similar library and looking for something
134
145
  * like `RequireAuth` or `ProtectedRoute`? This is the Cedar equivalent.
135
146
  */
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,MAAM,eAAe,CAAC;IAC/C,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;;;;GAIG;AACH,KAAK,QAAQ,GAAG,WAAW,SAAS;IAAE,OAAO,EAAE,IAAI,CAAA;CAAE,GACjD;IACE;;;;;OAKG;IACH,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAA;IAC7B;;;;;;;;;;;;OAYG;IACH,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAA;CAC7B,GACD;IACE;;;;OAIG;IACH,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAA;CAC1B,CAAA;AAEL,UAAU,QAAS,SAAQ,QAAQ;IACjC;;;;;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;;;;;;;;;GASG;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,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;;;;GAIG;AACH,KAAK,QAAQ,GAAG,WAAW,SAAS;IAAE,OAAO,EAAE,IAAI,CAAA;CAAE,GACjD;IACE;;;;;OAKG;IACH,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAA;IAC7B;;;;;;;;;;;;OAYG;IACH,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAA;IAC5B;;;;;OAKG;IACH,aAAa,CAAC,EAAE,cAAc,CAAA;CAC/B,GACD;IACE;;;;OAIG;IACH,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAA;CAC1B,CAAA;AAEL,UAAU,QAAS,SAAQ,QAAQ;IACjC;;;;;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"}
@@ -18,6 +18,7 @@ interface SetRenderProps {
18
18
  roles?: string | string[];
19
19
  userRoles?: string | string[];
20
20
  orgRoles?: string | string[];
21
+ orgPermission?: string;
21
22
  whileLoadingAuth?: () => ReactElement | null;
22
23
  }
23
24
  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,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAA;IAC7B,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAA;IAC5B,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;AAmDD,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;IAEzB,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAA;IAC7B,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAA;IAC5B,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;AAuDD,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"}
@@ -31,6 +31,9 @@ function pickSetRenderProps(props) {
31
31
  if (props.orgRoles !== void 0) {
32
32
  picked.orgRoles = props.orgRoles;
33
33
  }
34
+ if (props.orgPermission !== void 0) {
35
+ picked.orgPermission = props.orgPermission;
36
+ }
34
37
  if (props.whileLoadingAuth !== void 0) {
35
38
  picked.whileLoadingAuth = props.whileLoadingAuth;
36
39
  }
package/dist/index.d.ts CHANGED
@@ -6,7 +6,7 @@ export { Redirect } from './redirect.js';
6
6
  export { usePageLoadingContext, PageLoadingContextProvider, } from './PageLoadingContext.js';
7
7
  export { useParams, ParamsProvider, ParamsContext } from './params.js';
8
8
  export { Router } from './router.js';
9
- export type { UseOrgRoles } from './router-context.js';
9
+ export type { OrgProviderProps, RouterMembership, RouterOrg, Tenancy, UseOrg, } from './router-context.js';
10
10
  export { Route } from './Route.js';
11
11
  export { namedRoutes as routes } from './namedRoutes.js';
12
12
  export { Set, Private, PrivateSet, isSetNode, isPrivateSetNode, isPrivateNode, } from './Set.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,cAAc,CAAA;AAC7C,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AACtC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAChC,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAA;AAC7D,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AACxC,OAAO,EACL,qBAAqB,EACrB,0BAA0B,GAC3B,MAAM,yBAAyB,CAAA;AAChC,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AACtE,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AACpC,YAAY,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAA;AACtD,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAA;AAClC,OAAO,EAAE,WAAW,IAAI,MAAM,EAAE,MAAM,kBAAkB,CAAA;AAExD,OAAO,EACL,GAAG,EACH,OAAO,EACP,UAAU,EACV,SAAS,EACT,gBAAgB,EAChB,aAAa,GACd,MAAM,UAAU,CAAA;AACjB,YAAY,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,UAAU,CAAA;AAEzD,OAAO,EAAE,OAAO,IAAI,iBAAiB,EAAE,MAAM,yBAAyB,CAAA;AACtE,cAAc,yBAAyB,CAAA;AACvC,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,kBAAkB,CAAA;AACxD,cAAc,kBAAkB,CAAA;AAChC,cAAc,mBAAmB,CAAA;AACjC,cAAc,oBAAoB,CAAA;AAClC,cAAc,eAAe,CAAA;AAC7B,cAAc,iBAAiB,CAAA;AAE/B,OAAO,EAAE,WAAW,EAAE,sBAAsB,EAAE,SAAS,EAAE,MAAM,WAAW,CAAA;AAE1E,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,cAAc,CAAA;AAE1D;;;;;;;;;GASG;AAGH,MAAM,WAAW,eAAe;CAAG;AAGnC,cAAc,uBAAuB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,cAAc,CAAA;AAC7C,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AACtC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAChC,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAA;AAC7D,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AACxC,OAAO,EACL,qBAAqB,EACrB,0BAA0B,GAC3B,MAAM,yBAAyB,CAAA;AAChC,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AACtE,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AACpC,YAAY,EACV,gBAAgB,EAChB,gBAAgB,EAChB,SAAS,EACT,OAAO,EACP,MAAM,GACP,MAAM,qBAAqB,CAAA;AAC5B,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAA;AAClC,OAAO,EAAE,WAAW,IAAI,MAAM,EAAE,MAAM,kBAAkB,CAAA;AAExD,OAAO,EACL,GAAG,EACH,OAAO,EACP,UAAU,EACV,SAAS,EACT,gBAAgB,EAChB,aAAa,GACd,MAAM,UAAU,CAAA;AACjB,YAAY,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,UAAU,CAAA;AAEzD,OAAO,EAAE,OAAO,IAAI,iBAAiB,EAAE,MAAM,yBAAyB,CAAA;AACtE,cAAc,yBAAyB,CAAA;AACvC,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,kBAAkB,CAAA;AACxD,cAAc,kBAAkB,CAAA;AAChC,cAAc,mBAAmB,CAAA;AACjC,cAAc,oBAAoB,CAAA;AAClC,cAAc,eAAe,CAAA;AAC7B,cAAc,iBAAiB,CAAA;AAE/B,OAAO,EAAE,WAAW,EAAE,sBAAsB,EAAE,SAAS,EAAE,MAAM,WAAW,CAAA;AAE1E,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,cAAc,CAAA;AAE1D;;;;;;;;;GASG;AAGH,MAAM,WAAW,eAAe;CAAG;AAGnC,cAAc,uBAAuB,CAAA"}
@@ -4,29 +4,72 @@ import type { AuthContextInterface } from '@cedarjs/auth' with {
4
4
  };
5
5
  import type { analyzeRoutes } from './analyzeRoutes.js';
6
6
  import type { ParamType } from './util.js';
7
- type UseAuth = () => AuthContextInterface<unknown, unknown, unknown, unknown, unknown, unknown, unknown, unknown, unknown, unknown, unknown, unknown>;
7
+ export type UseAuth = () => AuthContextInterface<unknown, unknown, unknown, unknown, unknown, unknown, unknown, unknown, unknown, unknown, unknown, unknown>;
8
8
  /**
9
- * Checks the user's role in the organization of the current route, for
10
- * `<PrivateSet orgRoles>`, given the router's `useAuth` and the route's path
11
- * params: `null` when the route isn't in an organization. In apps with
12
- * tenancy, `useOrgRoles` from `@cedarjs/tenancy/web` is one. The router
13
- * calls it like a hook, on every render of a private set.
9
+ * What the router reads of a membership in an organization. A tenancy's
10
+ * memberships can have more; the router passes them on to its `OrgProvider`
11
+ * as they are.
12
+ */
13
+ export interface RouterMembership {
14
+ /** Identifies the organization, so one provider stays mounted across it */
15
+ organizationId: string;
16
+ /** The user's role in the organization, for `<PrivateSet orgRoles>` */
17
+ role: string;
18
+ /** What the membership may do, for `<PrivateSet orgPermission>` */
19
+ permissions?: readonly string[] | undefined;
20
+ }
21
+ /**
22
+ * What a tenancy's `useOrg` found for a route in an organization. A
23
+ * `membership` of `null` means the signed-in user isn't a member of it, or
24
+ * isn't signed in.
25
+ */
26
+ export interface RouterOrg {
27
+ membership: RouterMembership | null;
28
+ memberships: readonly RouterMembership[];
29
+ }
30
+ /**
31
+ * Finds the organization of the current route, given the router's `useAuth`
32
+ * and the route's path params: `null` when the route isn't in an
33
+ * organization. The router calls it like a hook, on every render of a
34
+ * private set.
14
35
  *
15
36
  * One of the app's own can answer in three ways:
16
- * - a check, which the router uses for `orgRoles`. One that always returns
17
- * `false` denies access and redirects to `unauthorized`.
18
- * - `null`, for no organization: a set with `orgRoles` then throws the
19
- * router's own error.
37
+ * - an organization, with the user's membership in it or `null` for none.
38
+ * A set with `orgRoles` or `orgPermission` denies a user with no
39
+ * membership, and the router renders the tenancy's `notAMember`.
40
+ * - `null`, for no organization: a set with `orgRoles` or `orgPermission`
41
+ * then throws the router's own error.
20
42
  * - throw an error of its own, such as for an organization that's been
21
43
  * suspended. It reaches the app's error boundary like any error thrown
22
44
  * while rendering.
23
45
  */
24
- export type UseOrgRoles = (useAuth: UseAuth, params: Record<string, string>) => ((roles: string | string[]) => boolean) | null;
46
+ export type UseOrg = (useAuth: UseAuth, params: Record<string, string>) => RouterOrg | null;
47
+ /** What the router gives a tenancy's `OrgProvider` */
48
+ export interface OrgProviderProps {
49
+ useAuth: UseAuth;
50
+ membership: RouterMembership;
51
+ memberships: readonly RouterMembership[];
52
+ children: React.ReactNode;
53
+ }
54
+ /**
55
+ * How the router handles organizations. `createTenancy` from
56
+ * `@cedarjs/tenancy/web` makes one. The router renders its `OrgProvider`
57
+ * around the layouts and page of a `PrivateSet` whose route is in an
58
+ * organization, and checks `orgRoles` and `orgPermission` against the
59
+ * membership its `useOrg` finds.
60
+ */
61
+ export interface Tenancy {
62
+ useOrg: UseOrg;
63
+ /** Provides the organization to everything below it */
64
+ OrgProvider: React.ComponentType<OrgProviderProps>;
65
+ /** Rendered for a signed-in user who isn't a member of the route's organization */
66
+ notAMember?: React.ReactNode;
67
+ }
25
68
  export interface RouterState {
26
69
  paramTypes?: Record<string, ParamType>;
27
70
  useAuth: UseAuth;
28
71
  /** Unset in apps that don't pass one to the router */
29
- useOrgRoles?: UseOrgRoles;
72
+ tenancy?: Tenancy;
30
73
  routes: ReturnType<typeof analyzeRoutes>;
31
74
  activeRouteName?: string | undefined | null;
32
75
  }
@@ -38,5 +81,4 @@ export interface RouterContextProviderProps extends Omit<RouterState, 'useAuth'>
38
81
  }
39
82
  export declare const RouterContextProvider: React.FC<RouterContextProviderProps>;
40
83
  export declare const useRouterState: () => RouterState;
41
- export {};
42
84
  //# sourceMappingURL=router-context.d.ts.map
@@ -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,KAAK,OAAO,GAAG,MAAM,oBAAoB,CACvC,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;;;;;;;;;;;;;;;GAeG;AACH,MAAM,MAAM,WAAW,GAAG,CACxB,OAAO,EAAE,OAAO,EAChB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,KAC3B,CAAC,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,KAAK,OAAO,CAAC,GAAG,IAAI,CAAA;AAEnD,MAAM,WAAW,WAAW;IAC1B,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAA;IACtC,OAAO,EAAE,OAAO,CAAA;IAChB,sDAAsD;IACtD,WAAW,CAAC,EAAE,WAAW,CAAA;IACzB,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,uEAAuE;IACvE,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"}
@@ -3,7 +3,7 @@ import { useNoAuth } from "@cedarjs/auth";
3
3
  const RouterStateContext = createContext(void 0);
4
4
  const RouterContextProvider = ({
5
5
  useAuth,
6
- useOrgRoles,
6
+ tenancy,
7
7
  paramTypes,
8
8
  routes,
9
9
  activeRouteName,
@@ -12,12 +12,12 @@ const RouterContextProvider = ({
12
12
  const state = useMemo(
13
13
  () => ({
14
14
  useAuth: useAuth || useNoAuth,
15
- useOrgRoles,
15
+ tenancy,
16
16
  paramTypes,
17
17
  routes,
18
18
  activeRouteName
19
19
  }),
20
- [useAuth, useOrgRoles, paramTypes, routes, activeRouteName]
20
+ [useAuth, tenancy, paramTypes, routes, activeRouteName]
21
21
  );
22
22
  return /* @__PURE__ */ React.createElement(RouterStateContext.Provider, { value: state }, children);
23
23
  };
package/dist/router.d.ts CHANGED
@@ -3,25 +3,26 @@ import React from 'react';
3
3
  import type { AuthTenancy } from '@cedarjs/auth' with {
4
4
  'resolution-mode': 'import'
5
5
  };
6
- import type { RouterContextProviderProps, UseOrgRoles } from './router-context.js';
6
+ import type { RouterContextProviderProps, Tenancy } from './router-context.js';
7
7
  import type { TrailingSlashesTypes } from './util.js';
8
8
  /**
9
- * `useOrgRoles`, only in an app with tenancy (see `AuthTenancy`), where sets
10
- * have `orgRoles`
9
+ * `tenancy`, only in an app with tenancy (see `AuthTenancy`), where sets have
10
+ * `orgRoles` and `orgPermission`
11
11
  */
12
- type RouterOrgRoles = AuthTenancy extends {
12
+ type RouterTenancy = AuthTenancy extends {
13
13
  enabled: true;
14
14
  } ? {
15
15
  /**
16
- * Checks the user's role in the organization of the current route, for
17
- * `<PrivateSet orgRoles>`. Pass `useOrgRoles` from
18
- * `@cedarjs/tenancy/web`:
16
+ * How the router handles organizations: finding the one of the current
17
+ * route, checking `orgRoles` and `orgPermission` in it, and providing
18
+ * it to the layouts and page of a `PrivateSet`. Pass the `tenancy` from
19
+ * `createTenancy` in `@cedarjs/tenancy/web`:
19
20
  *
20
- * <Router useAuth={useAuth} useOrgRoles={useOrgRoles}>
21
+ * <Router useAuth={useAuth} tenancy={tenancy}>
21
22
  */
22
- useOrgRoles?: UseOrgRoles;
23
+ tenancy?: Tenancy;
23
24
  } : Record<never, never>;
24
- export interface RouterProps extends Omit<RouterContextProviderProps, 'routes' | 'activeRouteName' | 'useOrgRoles'>, RouterOrgRoles {
25
+ export interface RouterProps extends Omit<RouterContextProviderProps, 'routes' | 'activeRouteName' | 'tenancy'>, RouterTenancy {
25
26
  trailingSlashes?: TrailingSlashesTypes;
26
27
  pageLoadingDelay?: number;
27
28
  children: ReactNode;
@@ -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,EACV,0BAA0B,EAC1B,WAAW,EACZ,MAAM,qBAAqB,CAAA;AAK5B,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAA;AAErD;;;GAGG;AACH,KAAK,cAAc,GAAG,WAAW,SAAS;IAAE,OAAO,EAAE,IAAI,CAAA;CAAE,GACvD;IACE;;;;;;OAMG;IACH,WAAW,CAAC,EAAE,WAAW,CAAA;CAC1B,GACD,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,CAAA;AAExB,MAAM,WAAW,WACf,SACE,IAAI,CACF,0BAA0B,EAC1B,QAAQ,GAAG,iBAAiB,GAAG,aAAa,CAC7C,EACD,cAAc;IAChB,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;;;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"}
package/dist/router.js CHANGED
@@ -14,7 +14,7 @@ import { SplashPage } from "./splash-page.js";
14
14
  import { matchPath, parseSearch, replaceParams, validatePath } from "./util.js";
15
15
  const RouterImplementation = ({
16
16
  useAuth,
17
- useOrgRoles,
17
+ tenancy,
18
18
  paramTypes,
19
19
  pageLoadingDelay,
20
20
  trailingSlashes = "never",
@@ -27,7 +27,7 @@ const RouterImplementation = ({
27
27
  LocationAwareRouter,
28
28
  {
29
29
  useAuth,
30
- useOrgRoles,
30
+ tenancy,
31
31
  paramTypes,
32
32
  pageLoadingDelay
33
33
  },
@@ -39,7 +39,7 @@ RouterImplementation.displayName = "Router";
39
39
  const Router = RouterImplementation;
40
40
  const LocationAwareRouter = ({
41
41
  useAuth,
42
- useOrgRoles,
42
+ tenancy,
43
43
  paramTypes,
44
44
  pageLoadingDelay,
45
45
  children
@@ -83,7 +83,7 @@ const LocationAwareRouter = ({
83
83
  RouterContextProvider,
84
84
  {
85
85
  useAuth,
86
- useOrgRoles,
86
+ tenancy,
87
87
  paramTypes,
88
88
  routes: analyzeRoutesResult
89
89
  },
@@ -128,7 +128,7 @@ const LocationAwareRouter = ({
128
128
  RouterContextProvider,
129
129
  {
130
130
  useAuth,
131
- useOrgRoles,
131
+ tenancy,
132
132
  paramTypes,
133
133
  routes: analyzeRoutesResult,
134
134
  activeRouteName: name
@@ -165,6 +165,7 @@ const WrappedPage = memo(({ sets, children }) => {
165
165
  roles: set.props.roles,
166
166
  userRoles: set.props.userRoles,
167
167
  orgRoles: set.props.orgRoles,
168
+ orgPermission: set.props.orgPermission,
168
169
  whileLoadingAuth: set.props.whileLoadingAuth
169
170
  },
170
171
  wrapped
@@ -1,4 +1,4 @@
1
1
  import React from 'react';
2
2
  import type { RouterProps } from '../router.js';
3
- export declare const Router: ({ useAuth, paramTypes, children }: RouterProps) => React.JSX.Element;
3
+ export declare const Router: (props: RouterProps) => React.JSX.Element;
4
4
  //# sourceMappingURL=ClientRouter.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ClientRouter.d.ts","sourceRoot":"","sources":["../../src/rsc/ClientRouter.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAkB,MAAM,OAAO,CAAA;AAOtC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAI/C,eAAO,MAAM,MAAM,GAAI,mCAAmC,WAAW,sBASpE,CAAA"}
1
+ {"version":3,"file":"ClientRouter.d.ts","sourceRoot":"","sources":["../../src/rsc/ClientRouter.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAkB,MAAM,OAAO,CAAA;AAOtC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAI/C,eAAO,MAAM,MAAM,GAAI,OAAO,WAAW,sBAiBxC,CAAA"}
@@ -5,7 +5,11 @@ import { LocationProvider, useLocation } from "../location.js";
5
5
  import { namedRoutes } from "../namedRoutes.js";
6
6
  import { RouterContextProvider } from "../router-context.js";
7
7
  import { RscRoutes } from "./RscRoutes.js";
8
- const Router = ({ useAuth, paramTypes, children }) => {
8
+ const Router = (props) => {
9
+ const { useAuth, paramTypes, children } = props;
10
+ if ("tenancy" in props && props.tenancy) {
11
+ throw new Error("`tenancy` is not supported with RSC yet");
12
+ }
9
13
  return (
10
14
  // Wrap it in the provider so that useLocation can be used
11
15
  /* @__PURE__ */ React.createElement(LocationProvider, null, /* @__PURE__ */ React.createElement(LocationAwareRouter, { paramTypes, useAuth }, children))
@@ -29,6 +33,14 @@ const LocationAwareRouter = ({
29
33
  return /* @__PURE__ */ React.createElement(RscRoutes, { pathname, search });
30
34
  }
31
35
  const requestedRoute = pathRouteMap[activeRoutePath];
36
+ for (const set of requestedRoute.sets) {
37
+ if (set.props.orgRoles !== void 0) {
38
+ throw new Error("`orgRoles` is not supported with RSC yet");
39
+ }
40
+ if (set.props.orgPermission !== void 0) {
41
+ throw new Error("`orgPermission` is not supported with RSC yet");
42
+ }
43
+ }
32
44
  const reversedSets = requestedRoute.sets.toReversed();
33
45
  const privateSet = reversedSets.find((set) => set.isPrivate);
34
46
  if (privateSet) {
@@ -1 +1 @@
1
- {"version":3,"file":"ServerRouter.d.ts","sourceRoot":"","sources":["../../src/rsc/ServerRouter.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAgB,SAAS,EAAE,MAAM,OAAO,CAAA;AACpD,OAAO,KAAK,MAAM,OAAO,CAAA;AAQzB,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,sBAAsB,CAAA;AAGtE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAA;AAKtD,MAAM,WAAW,WAAY,SAAQ,IAAI,CACvC,0BAA0B,EAC1B,QAAQ,GAAG,iBAAiB,CAC7B;IACC,eAAe,CAAC,EAAE,oBAAoB,CAAA;IACtC,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,QAAQ,EAAE,SAAS,CAAA;CACpB;AAED,eAAO,MAAM,MAAM,EAAE,KAAK,CAAC,EAAE,CAAC,WAAW,CA4GxC,CAAA"}
1
+ {"version":3,"file":"ServerRouter.d.ts","sourceRoot":"","sources":["../../src/rsc/ServerRouter.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAgB,SAAS,EAAE,MAAM,OAAO,CAAA;AACpD,OAAO,KAAK,MAAM,OAAO,CAAA;AAQzB,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,sBAAsB,CAAA;AAGtE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAA;AAKtD,MAAM,WAAW,WAAY,SAAQ,IAAI,CACvC,0BAA0B,EAC1B,QAAQ,GAAG,iBAAiB,CAC7B;IACC,eAAe,CAAC,EAAE,oBAAoB,CAAA;IACtC,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,QAAQ,EAAE,SAAS,CAAA;CACpB;AAED,eAAO,MAAM,MAAM,EAAE,KAAK,CAAC,EAAE,CAAC,WAAW,CAqHxC,CAAA"}
@@ -7,7 +7,14 @@ import { wrapWithSetWrappers } from "../Set.js";
7
7
  import { SplashPage } from "../splash-page.js";
8
8
  import { matchPath, parseSearch, replaceParams, validatePath } from "../util.js";
9
9
  import { ServerRouteLoader } from "./ServerRouteLoader.js";
10
- const Router = ({ paramTypes, children }) => {
10
+ const Router = ({
11
+ paramTypes,
12
+ tenancy,
13
+ children
14
+ }) => {
15
+ if (tenancy) {
16
+ throw new Error("`tenancy` is not supported with RSC yet");
17
+ }
11
18
  const location = getLocation();
12
19
  console.log("ServerRouter.tsx location", location);
13
20
  const analyzedRoutes = analyzeRoutes(children, {
@@ -98,12 +105,16 @@ const AuthenticatedRoute = ({
98
105
  children,
99
106
  roles,
100
107
  userRoles,
101
- orgRoles
108
+ orgRoles,
109
+ orgPermission
102
110
  }) => {
103
111
  const { isAuthenticated } = getAuthState();
104
112
  if (orgRoles !== void 0) {
105
113
  throw new Error("`orgRoles` is not supported with RSC yet");
106
114
  }
115
+ if (orgPermission !== void 0) {
116
+ throw new Error("`orgPermission` is not supported with RSC yet");
117
+ }
107
118
  const isAuthorized = isAuthenticated && (!roles || hasRole(roles)) && (!userRoles || hasRole(userRoles));
108
119
  if (isAuthorized) {
109
120
  return /* @__PURE__ */ React.createElement(React.Fragment, null, children);
@@ -133,6 +144,7 @@ const WrappedPage = ({ routeLoaderElement, sets }) => {
133
144
  roles: set.props.roles,
134
145
  userRoles: set.props.userRoles,
135
146
  orgRoles: set.props.orgRoles,
147
+ orgPermission: set.props.orgPermission,
136
148
  whileLoadingAuth: set.props.whileLoadingAuth
137
149
  },
138
150
  wrapped
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cedarjs/router",
3
- "version": "8.0.0-canary.3542",
3
+ "version": "8.0.0-canary.3546",
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.3542",
56
- "@cedarjs/server-store": "8.0.0-canary.3542",
55
+ "@cedarjs/project-config": "8.0.0-canary.3546",
56
+ "@cedarjs/server-store": "8.0.0-canary.3546",
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.3542",
63
- "@cedarjs/framework-tools": "8.0.0-canary.3542",
62
+ "@cedarjs/auth": "8.0.0-canary.3546",
63
+ "@cedarjs/framework-tools": "8.0.0-canary.3546",
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.3542",
77
+ "@cedarjs/auth": "8.0.0-canary.3546",
78
78
  "react": "19.3.1",
79
79
  "react-dom": "19.3.1"
80
80
  },