@cedarjs/tenancy 8.0.0-canary.3536 → 8.0.0-canary.3539

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -76,23 +76,38 @@ import {
76
76
  ## Auth helpers
77
77
 
78
78
  ```ts
79
- import { hasOrgRole, requireMembership } from '@cedarjs/tenancy'
79
+ // api/src/lib/auth.ts, in place of the single-tenant hasRole/requireAuth
80
+ import { createTenancyAuth } from '@cedarjs/tenancy'
81
+
82
+ export const { hasUserRole, hasOrgRole, requireUserAuth, requireOrgAuth } =
83
+ createTenancyAuth()
80
84
 
81
85
  // In a service:
82
- requireMembership({ roles: ['owner', 'admin'] })
86
+ requireOrgAuth({ roles: ['owner', 'admin'] }) // in the current organization
87
+ requireUserAuth() // signed in, no organization needed
83
88
 
84
89
  // Anywhere:
85
- if (hasOrgRole('owner')) { ... }
90
+ if (hasOrgRole('owner')) { ... } // in the current organization
91
+ if (hasUserRole('superuser')) { ... } // currentUser.roles
86
92
  ```
87
93
 
88
- `requireMembership` throws `AuthenticationError` with no current user and
89
- `ForbiddenError` with no current organization or a role mismatch — the same
90
- error types `requireAuth` uses.
94
+ `requireOrgAuth` (and the `@requireOrgAuth` directive `setup tenancy` adds) is
95
+ about the current organization: it throws `AuthenticationError` with no
96
+ current user, and `ForbiddenError` with no current organization or when the
97
+ user's role there isn't one of `roles` when they're given. With no `roles`,
98
+ any member gets in. `requireUserAuth` (and `@requireUserAuth`) is for fields about the user
99
+ rather than an organization: it needs a signed-in user, and checks `roles`
100
+ against `currentUser.roles`. `hasOrgRole` and `hasUserRole` are the boolean
101
+ checks to match. There's no `requireAuth` or `hasRole`.
91
102
 
92
103
  ## Web
93
104
 
94
- `@cedarjs/tenancy/web` exports `OrgScope`, `useCurrentOrg`, `OrgContext` and
105
+ `@cedarjs/tenancy/web` exports `OrgScope`, `useCurrentOrg` and
95
106
  `getMemberships`/`hasOrgRole` for the client side: a per-organization Apollo
96
107
  client provided under organization routes, keyed by the immutable organization
97
- id so switching organizations never mixes caches. See the how-to for the full
108
+ id so switching organizations never mixes caches. `useCurrentOrg().hasOrgRole`
109
+ checks the user's role in the organization, and `OrgScope`'s `roles` and
110
+ `unauthorized` props guard routes by it. `useAuth().hasUserRole` checks
111
+ `currentUser.roles`; there's no `useAuth().hasRole` or `<PrivateSet roles>` in
112
+ an app with tenancy. See the how-to for the full
98
113
  `<Set wrap={OrgScope}>` setup `yarn cedar setup tenancy` generates.
package/dist/auth.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ type Roles = string | readonly string[];
1
2
  /**
2
3
  * Whether the current request holds one of `roles` in an organization.
3
4
  *
@@ -9,20 +10,56 @@
9
10
  *
10
11
  * Returns `false` when there's no authenticated user, no matching
11
12
  * organization, or no matching membership. An empty `roles` array returns
12
- * `true` as long as a matching membership exists, mirroring `hasRole()`'s
13
- * behavior for global roles.
13
+ * `true` as long as a matching membership exists.
14
14
  */
15
- export declare function hasOrgRole(roles: string | string[], organizationId?: string): boolean;
15
+ export declare function hasOrgRole(roles: Roles, organizationId?: string): boolean;
16
+ export interface TenancyAuth {
17
+ /**
18
+ * Whether the signed-in user holds one of `roles` in `currentUser.roles`,
19
+ * in any organization or none. What the single-tenant `hasRole()` checked;
20
+ * `hasOrgRole()` checks the role in an organization.
21
+ */
22
+ hasUserRole(roles: Roles): boolean;
23
+ /**
24
+ * Guards a service or directive on the current organization: signed in,
25
+ * a member of the current organization and, when `roles` are given, with
26
+ * one of them there. With no `roles`, any member gets in, as any
27
+ * signed-in user gets past the single-tenant `requireAuth()`: use `roles`
28
+ * or `requirePermission()` for anything narrower.
29
+ *
30
+ * Throws `AuthenticationError` when no one is signed in, and
31
+ * `ForbiddenError` otherwise.
32
+ */
33
+ requireOrgAuth(options?: {
34
+ roles?: Roles;
35
+ }): void;
36
+ /**
37
+ * Guards a service or directive on the signed-in user alone, in any
38
+ * organization or none: their account, their memberships, accepting an
39
+ * invitation. When `roles` are given, the user needs one of them in
40
+ * `currentUser.roles`.
41
+ *
42
+ * Throws `AuthenticationError` when no one is signed in, and
43
+ * `ForbiddenError` otherwise.
44
+ */
45
+ requireUserAuth(options?: {
46
+ roles?: Roles;
47
+ }): void;
48
+ /** The standalone `hasOrgRole`: with no roles, any membership */
49
+ hasOrgRole(roles?: Roles, organizationId?: string): boolean;
50
+ }
16
51
  /**
17
- * Guards a service or directive on the current request having a membership
18
- * in the current organization, optionally with one of `roles`.
52
+ * The auth checks for an app with tenancy, which `api/src/lib/auth.ts`
53
+ * exports in place of its single-tenant `hasRole` and `requireAuth`:
19
54
  *
20
- * Throws `AuthenticationError` when there's no authenticated user, and
21
- * `ForbiddenError` when there's no current organization or the membership's
22
- * role doesn't match — the same error types `requireAuth` uses, so existing
23
- * error handling on the web side applies unchanged.
55
+ * ```ts
56
+ * export const { hasUserRole, hasOrgRole, requireUserAuth, requireOrgAuth } =
57
+ * createTenancyAuth()
58
+ * ```
59
+ *
60
+ * There's no `hasRole` or `requireAuth`: every check says whether it's
61
+ * about the signed-in user alone or the current organization.
24
62
  */
25
- export declare function requireMembership(options?: {
26
- roles?: string | string[];
27
- }): void;
63
+ export declare function createTenancyAuth(): TenancyAuth;
64
+ export {};
28
65
  //# sourceMappingURL=auth.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AAKA;;;;;;;;;;;;;GAaG;AACH,wBAAgB,UAAU,CACxB,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,EACxB,cAAc,CAAC,EAAE,MAAM,GACtB,OAAO,CA4BT;AAED;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAC/B,OAAO,GAAE;IAAE,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAA;CAAO,GAC1C,IAAI,CAwBN"}
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AAKA,KAAK,KAAK,GAAG,MAAM,GAAG,SAAS,MAAM,EAAE,CAAA;AAwBvC;;;;;;;;;;;;GAYG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,KAAK,EAAE,cAAc,CAAC,EAAE,MAAM,GAAG,OAAO,CA4BzE;AAED,MAAM,WAAW,WAAW;IAC1B;;;;OAIG;IACH,WAAW,CAAC,KAAK,EAAE,KAAK,GAAG,OAAO,CAAA;IAClC;;;;;;;;;OASG;IACH,cAAc,CAAC,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,KAAK,CAAA;KAAE,GAAG,IAAI,CAAA;IACjD;;;;;;;;OAQG;IACH,eAAe,CAAC,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,KAAK,CAAA;KAAE,GAAG,IAAI,CAAA;IAClD,iEAAiE;IACjE,UAAU,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,cAAc,CAAC,EAAE,MAAM,GAAG,OAAO,CAAA;CAC5D;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,iBAAiB,IAAI,WAAW,CA8C/C"}
package/dist/auth.js CHANGED
@@ -1,8 +1,19 @@
1
1
  import { context } from "@cedarjs/context";
2
2
  import { AuthenticationError, ForbiddenError } from "@cedarjs/graphql-server";
3
3
  import { getCurrentOrg, isUserWithMemberships } from "./context.js";
4
+ const toList = (roles) => roles === void 0 ? [] : typeof roles === "string" ? [roles] : [...roles];
5
+ function userRoles() {
6
+ const roles = context.currentUser?.roles;
7
+ if (typeof roles === "string") {
8
+ return [roles];
9
+ }
10
+ if (Array.isArray(roles)) {
11
+ return roles.filter((role) => typeof role === "string");
12
+ }
13
+ return [];
14
+ }
4
15
  function hasOrgRole(roles, organizationId) {
5
- const roleList = Array.isArray(roles) ? roles : [roles];
16
+ const roleList = toList(roles);
6
17
  if (organizationId) {
7
18
  const currentUser = context.currentUser;
8
19
  if (!isUserWithMemberships(currentUser)) {
@@ -22,26 +33,40 @@ function hasOrgRole(roles, organizationId) {
22
33
  }
23
34
  return roleList.length === 0 || roleList.includes(currentOrg.role);
24
35
  }
25
- function requireMembership(options = {}) {
26
- if (!context.currentUser) {
27
- throw new AuthenticationError("You must be logged in to do that.");
28
- }
29
- const currentOrg = getCurrentOrg();
30
- if (!currentOrg) {
31
- throw new ForbiddenError(
32
- "You must be a member of an organization to do that."
33
- );
34
- }
35
- const { roles } = options;
36
- if (roles === void 0) {
37
- return;
38
- }
39
- const roleList = Array.isArray(roles) ? roles : [roles];
40
- if (roleList.length > 0 && !roleList.includes(currentOrg.role)) {
41
- throw new ForbiddenError("You do not have permission to do that.");
42
- }
36
+ function createTenancyAuth() {
37
+ return {
38
+ hasUserRole(roles) {
39
+ const roleList = toList(roles);
40
+ return !!context.currentUser && userRoles().some((role) => roleList.includes(role));
41
+ },
42
+ requireUserAuth({ roles } = {}) {
43
+ if (!context.currentUser) {
44
+ throw new AuthenticationError("You don't have permission to do that.");
45
+ }
46
+ if (roles && !userRoles().some((role) => toList(roles).includes(role))) {
47
+ throw new ForbiddenError("You don't have access to do that.");
48
+ }
49
+ },
50
+ requireOrgAuth({ roles } = {}) {
51
+ if (!context.currentUser) {
52
+ throw new AuthenticationError("You don't have permission to do that.");
53
+ }
54
+ const currentOrg = getCurrentOrg();
55
+ if (!currentOrg) {
56
+ throw new ForbiddenError(
57
+ "You must be a member of an organization to do that."
58
+ );
59
+ }
60
+ if (roles && !toList(roles).includes(currentOrg.role)) {
61
+ throw new ForbiddenError("You don't have access to do that.");
62
+ }
63
+ },
64
+ hasOrgRole(roles = [], organizationId) {
65
+ return hasOrgRole(roles, organizationId);
66
+ }
67
+ };
43
68
  }
44
69
  export {
45
- hasOrgRole,
46
- requireMembership
70
+ createTenancyAuth,
71
+ hasOrgRole
47
72
  };
@@ -5,6 +5,18 @@ export interface OrgScopeProps {
5
5
  orgSlug?: string;
6
6
  /** Rendered when the user has no membership matching the slug. */
7
7
  notAMember?: React.ReactNode;
8
+ /**
9
+ * Only members with one of these roles in the organization get in.
10
+ * Checked after the organization is resolved, which `<PrivateSet roles>`
11
+ * around `OrgScope` can't do.
12
+ */
13
+ roles?: string | string[];
14
+ /**
15
+ * The name of the route a member without one of `roles` is redirected to.
16
+ * It gets the `orgSlug` param when its path has one, so it can be a page
17
+ * of the same organization. Without it, they get `notAMember`.
18
+ */
19
+ unauthorized?: string;
8
20
  /**
9
21
  * The app's `useAuth`, so `OrgScope` can read `currentUser.memberships`
10
22
  * without importing app code. Defaults to `useNoAuth`.
@@ -21,9 +33,10 @@ export interface OrgScopeProps {
21
33
  * Provides the per-organization Apollo client and `OrgContext` for the
22
34
  * organization matching `orgSlug` (a prop, or else the `orgSlug` route
23
35
  * param). Renders `notAMember` when the current user has no membership in
24
- * that organization; otherwise wraps `children` in that organization's own
25
- * `ApolloProvider`, so every Cell, `useQuery` and `useMutation` under it
26
- * carries the `cedar-org` header and reads from that organization's cache.
36
+ * that organization (or not one with `roles`, see `unauthorized`);
37
+ * otherwise wraps `children` in that organization's own `ApolloProvider`,
38
+ * so every Cell, `useQuery` and `useMutation` under it carries the
39
+ * `cedar-org` header and reads from that organization's cache.
27
40
  */
28
- export declare function OrgScope({ orgSlug: orgSlugProp, notAMember, useAuth, onSetOrg, children, }: OrgScopeProps): React.JSX.Element;
41
+ export declare function OrgScope({ orgSlug: orgSlugProp, notAMember, roles, unauthorized, useAuth, onSetOrg, children, }: OrgScopeProps): React.JSX.Element;
29
42
  //# sourceMappingURL=OrgScope.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"OrgScope.d.ts","sourceRoot":"","sources":["../../src/web/OrgScope.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAIzB,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,eAAe,CAAA;AAe5C,MAAM,WAAW,aAAa;IAC5B,2CAA2C;IAC3C,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,kEAAkE;IAClE,UAAU,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IAC5B;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB;;;OAGG;IACH,QAAQ,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAA;IACrC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;CAC1B;AAYD;;;;;;;GAOG;AACH,wBAAgB,QAAQ,CAAC,EACvB,OAAO,EAAE,WAAW,EACpB,UAAiB,EACjB,OAAmB,EACnB,QAAQ,EACR,QAAQ,GACT,EAAE,aAAa,GAAG,KAAK,CAAC,GAAG,CAAC,OAAO,CAyInC"}
1
+ {"version":3,"file":"OrgScope.d.ts","sourceRoot":"","sources":["../../src/web/OrgScope.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAIzB,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,eAAe,CAAA;AAqB5C,MAAM,WAAW,aAAa;IAC5B,2CAA2C;IAC3C,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,kEAAkE;IAClE,UAAU,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IAC5B;;;;OAIG;IACH,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAA;IACzB;;;;OAIG;IACH,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB;;;OAGG;IACH,QAAQ,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAA;IACrC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;CAC1B;AAwCD;;;;;;;;GAQG;AACH,wBAAgB,QAAQ,CAAC,EACvB,OAAO,EAAE,WAAW,EACpB,UAAiB,EACjB,KAAK,EACL,YAAY,EACZ,OAAmB,EACnB,QAAQ,EACR,QAAQ,GACT,EAAE,aAAa,GAAG,KAAK,CAAC,GAAG,CAAC,OAAO,CA4JnC"}
@@ -2,19 +2,42 @@ import { Fragment, jsx } from "react/jsx-runtime";
2
2
  import React from "react";
3
3
  import { ApolloProvider } from "@apollo/client/react";
4
4
  import { useNoAuth } from "@cedarjs/auth";
5
- import { navigate, useLocation, useParams } from "@cedarjs/router";
5
+ import {
6
+ navigate,
7
+ Redirect,
8
+ routes,
9
+ useLocation,
10
+ useParams
11
+ } from "@cedarjs/router";
6
12
  import { useCreateApolloClient } from "@cedarjs/web/apollo";
7
13
  import { getMemberships } from "./getMemberships.js";
8
14
  import { hasOrgRole } from "./hasOrgRole.js";
9
15
  import { clearOrgClients, dropOrgClient, getOrgClient } from "./orgClients.js";
10
16
  import { OrgContext } from "./OrgContext.js";
11
17
  const CEDAR_ORG_HEADER = "cedar-org";
18
+ const toList = (roles) => Array.isArray(roles) ? roles : [roles];
19
+ const REPLACE = { replace: true };
20
+ function isNamedRoute(value) {
21
+ return typeof value === "function";
22
+ }
23
+ function unauthorizedPath(route, orgSlug) {
24
+ try {
25
+ return route();
26
+ } catch (e) {
27
+ if (e instanceof Error && e.message.includes("Missing parameter")) {
28
+ return route({ orgSlug });
29
+ }
30
+ throw e;
31
+ }
32
+ }
12
33
  function membershipRoleMap(memberships) {
13
34
  return new Map(memberships.map((m) => [m.organizationId, m.role]));
14
35
  }
15
36
  function OrgScope({
16
37
  orgSlug: orgSlugProp,
17
38
  notAMember = null,
39
+ roles,
40
+ unauthorized,
18
41
  useAuth = useNoAuth,
19
42
  onSetOrg,
20
43
  children
@@ -77,9 +100,19 @@ function OrgScope({
77
100
  [onSetOrg, params, location.pathname, location.search, location.hash]
78
101
  );
79
102
  const membership = orgSlug ? memberships.find((m) => m.organization.slug === orgSlug) : void 0;
80
- if (!membership || !userId) {
103
+ if (!membership || !userId || !orgSlug) {
81
104
  return /* @__PURE__ */ jsx(Fragment, { children: notAMember });
82
105
  }
106
+ if (roles !== void 0 && !toList(roles).includes(membership.role)) {
107
+ if (!unauthorized) {
108
+ return /* @__PURE__ */ jsx(Fragment, { children: notAMember });
109
+ }
110
+ const route = Object.hasOwn(routes, unauthorized) ? Reflect.get(routes, unauthorized) : void 0;
111
+ if (!isNamedRoute(route)) {
112
+ throw new Error(`We could not find a route named ${unauthorized}`);
113
+ }
114
+ return /* @__PURE__ */ jsx(Redirect, { to: unauthorizedPath(route, orgSlug), options: REPLACE });
115
+ }
83
116
  const org = {
84
117
  id: membership.organizationId,
85
118
  slug: membership.organization.slug,
@@ -97,7 +130,7 @@ function OrgScope({
97
130
  const contextValue = {
98
131
  org,
99
132
  memberships,
100
- hasOrgRole: (roles, organizationId) => hasOrgRole(memberships, roles, organizationId ?? org.id),
133
+ hasOrgRole: (roles2, organizationId) => hasOrgRole(memberships, roles2, organizationId ?? org.id),
101
134
  setOrg
102
135
  };
103
136
  return /* @__PURE__ */ jsx(ApolloProvider, { client: orgClient, children: /* @__PURE__ */ jsx(OrgContext.Provider, { value: contextValue, children }) });
@@ -1,6 +1,5 @@
1
1
  export { getMemberships } from './getMemberships.js';
2
2
  export { hasOrgRole } from './hasOrgRole.js';
3
- export { OrgContext } from './OrgContext.js';
4
3
  export type { OrgScopeProps } from './OrgScope.js';
5
4
  export { OrgScope } from './OrgScope.js';
6
5
  export { clearOrgClients } from './orgClients.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/web/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAA;AACpD,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAC5C,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAC5C,YAAY,EAAE,aAAa,EAAE,MAAM,eAAe,CAAA;AAClD,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AACxC,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AACjD,YAAY,EACV,iBAAiB,EACjB,eAAe,EACf,aAAa,GACd,MAAM,YAAY,CAAA;AACnB,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/web/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAA;AACpD,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAC5C,YAAY,EAAE,aAAa,EAAE,MAAM,eAAe,CAAA;AAClD,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AACxC,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AACjD,YAAY,EACV,iBAAiB,EACjB,eAAe,EACf,aAAa,GACd,MAAM,YAAY,CAAA;AACnB,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA"}
package/dist/web/index.js CHANGED
@@ -1,11 +1,9 @@
1
1
  import { getMemberships } from "./getMemberships.js";
2
2
  import { hasOrgRole } from "./hasOrgRole.js";
3
- import { OrgContext } from "./OrgContext.js";
4
3
  import { OrgScope } from "./OrgScope.js";
5
4
  import { clearOrgClients } from "./orgClients.js";
6
5
  import { useCurrentOrg } from "./useCurrentOrg.js";
7
6
  export {
8
- OrgContext,
9
7
  OrgScope,
10
8
  clearOrgClients,
11
9
  getMemberships,
@@ -25,7 +25,7 @@ export interface CurrentOrgSummary {
25
25
  membershipId: string;
26
26
  }
27
27
  /**
28
- * The value `OrgContext` carries, read through `useCurrentOrg()`.
28
+ * What `OrgScope` provides below it, read through `useCurrentOrg()`.
29
29
  */
30
30
  export interface OrgContextValue {
31
31
  org: CurrentOrgSummary | undefined;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cedarjs/tenancy",
3
- "version": "8.0.0-canary.3536",
3
+ "version": "8.0.0-canary.3539",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/cedarjs/cedar.git",
@@ -38,17 +38,17 @@
38
38
  "test:watch": "vitest watch"
39
39
  },
40
40
  "dependencies": {
41
- "@cedarjs/api": "8.0.0-canary.3536",
42
- "@cedarjs/context": "8.0.0-canary.3536",
43
- "@cedarjs/graphql-server": "8.0.0-canary.3536"
41
+ "@cedarjs/api": "8.0.0-canary.3539",
42
+ "@cedarjs/context": "8.0.0-canary.3539",
43
+ "@cedarjs/graphql-server": "8.0.0-canary.3539"
44
44
  },
45
45
  "devDependencies": {
46
46
  "@apollo/client": "4.3.5",
47
47
  "@arethetypeswrong/cli": "0.18.5",
48
- "@cedarjs/auth": "8.0.0-canary.3536",
49
- "@cedarjs/framework-tools": "8.0.0-canary.3536",
50
- "@cedarjs/router": "8.0.0-canary.3536",
51
- "@cedarjs/web": "8.0.0-canary.3536",
48
+ "@cedarjs/auth": "8.0.0-canary.3539",
49
+ "@cedarjs/framework-tools": "8.0.0-canary.3539",
50
+ "@cedarjs/router": "8.0.0-canary.3539",
51
+ "@cedarjs/web": "8.0.0-canary.3539",
52
52
  "@prisma/adapter-better-sqlite3": "7.10.1",
53
53
  "@prisma/client": "7.10.1",
54
54
  "@testing-library/dom": "10.4.2",
@@ -74,9 +74,9 @@
74
74
  },
75
75
  "peerDependencies": {
76
76
  "@apollo/client": "4.3.5",
77
- "@cedarjs/auth": "8.0.0-canary.3536",
78
- "@cedarjs/router": "8.0.0-canary.3536",
79
- "@cedarjs/web": "8.0.0-canary.3536",
77
+ "@cedarjs/auth": "8.0.0-canary.3539",
78
+ "@cedarjs/router": "8.0.0-canary.3539",
79
+ "@cedarjs/web": "8.0.0-canary.3539",
80
80
  "@prisma/client": "7.10.1",
81
81
  "react": "19.3.1"
82
82
  },