@robelest/convex-auth 0.0.4-preview.28 → 0.0.4-preview.29
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/dist/bin.js +4 -1
- package/dist/component/_generated/component.d.ts +344 -0
- package/dist/component/convex.config.d.ts +2 -2
- package/dist/component/model.d.ts +25 -25
- package/dist/component/model.js +1 -0
- package/dist/component/public/factors/totp.js +12 -0
- package/dist/component/public/groups/core.js +89 -1
- package/dist/component/public/groups/members.js +39 -1
- package/dist/component/public/identity/accounts.js +22 -3
- package/dist/component/public/identity/users.js +79 -5
- package/dist/component/public/sso/audit.js +5 -2
- package/dist/component/public/sso/core.js +3 -3
- package/dist/component/public/sso/domains.js +7 -3
- package/dist/component/public/sso/scim.js +36 -1
- package/dist/component/public.js +5 -5
- package/dist/component/schema.d.ts +293 -289
- package/dist/component/schema.js +2 -1
- package/dist/core/index.d.ts +63 -27
- package/dist/core/index.js +1 -0
- package/dist/providers/credentials.d.ts +12 -0
- package/dist/providers/password.js +28 -7
- package/dist/server/auth-context.d.ts +17 -0
- package/dist/server/auth-context.js +1 -1
- package/dist/server/auth.d.ts +18 -6
- package/dist/server/auth.js +1 -0
- package/dist/server/context.js +11 -5
- package/dist/server/contract.js +44 -12
- package/dist/server/core.js +146 -149
- package/dist/server/ctxCache.js +94 -0
- package/dist/server/limits.js +39 -9
- package/dist/server/mounts.d.ts +85 -85
- package/dist/server/mutations/credentialsSignIn.js +114 -0
- package/dist/server/mutations/index.js +2 -1
- package/dist/server/mutations/refresh.js +25 -12
- package/dist/server/mutations/retrieve.js +2 -1
- package/dist/server/mutations/signin.js +27 -9
- package/dist/server/mutations/store.js +5 -0
- package/dist/server/mutations/verify.js +32 -8
- package/dist/server/runtime.d.ts +81 -47
- package/dist/server/services/group.js +23 -16
- package/dist/server/sessions.d.ts +21 -0
- package/dist/server/sessions.js +37 -27
- package/dist/server/signin.js +32 -9
- package/dist/server/sso/domain.js +1 -2
- package/dist/server/sso/oidc.js +1 -1
- package/dist/server/tokens.js +19 -3
- package/dist/server/users.js +3 -2
- package/dist/server/utils/span.js +18 -0
- package/package.json +1 -1
- package/README.md +0 -161
package/dist/component/schema.js
CHANGED
|
@@ -19,6 +19,7 @@ var schema_default = defineSchema({
|
|
|
19
19
|
phone: v.optional(v.string()),
|
|
20
20
|
phoneVerificationTime: v.optional(v.number()),
|
|
21
21
|
isAnonymous: v.optional(v.boolean()),
|
|
22
|
+
hasTotp: v.optional(v.boolean()),
|
|
22
23
|
extend: v.optional(v.any())
|
|
23
24
|
}).index("email", ["email"]).index("email_verified", ["email", "emailVerificationTime"]).index("phone", ["phone"]).index("phone_verified", ["phone", "phoneVerificationTime"]),
|
|
24
25
|
Session: defineTable({
|
|
@@ -136,7 +137,7 @@ var schema_default = defineSchema({
|
|
|
136
137
|
status: vGroupConnectionStatus,
|
|
137
138
|
config: v.optional(v.any()),
|
|
138
139
|
extend: v.optional(v.any())
|
|
139
|
-
}).index("group_id", ["groupId"]).index("slug", ["slug"]).index("status", ["status"]),
|
|
140
|
+
}).index("group_id", ["groupId"]).index("slug", ["slug"]).index("status", ["status"]).index("group_id_status", ["groupId", "status"]).index("group_id_slug", ["groupId", "slug"]),
|
|
140
141
|
GroupConnectionDomain: defineTable({
|
|
141
142
|
connectionId: v.id("GroupConnection"),
|
|
142
143
|
groupId: v.id("Group"),
|
package/dist/core/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ComponentCtx, ComponentReadCtx } from "../server/componentContext.js";
|
|
2
|
-
import { AuthAuthorizationConfig, ConvexAuthConfig, KeyDoc, KeyScope, ScopeChecker, UserOrderBy, UserWhere } from "../server/types.js";
|
|
2
|
+
import { AuthAuthorizationConfig, ConvexAuthConfig, Doc, KeyDoc, KeyScope, ScopeChecker, UserOrderBy, UserWhere } from "../server/types.js";
|
|
3
3
|
import { AuthProfile } from "../server/payloads.js";
|
|
4
4
|
import { AuthConfig, AuthContext, AuthContextConfig, AuthContextFactory as AuthContextFactory$1, AuthContextResolver as AuthContextResolver$1, OptionalAuthContext, UserDoc } from "../server/auth-context.js";
|
|
5
5
|
import "../component/index.js";
|
|
@@ -37,7 +37,10 @@ declare function createAuthContext(component: ConvexAuthConfig["component"], con
|
|
|
37
37
|
authorization?: AuthAuthorizationConfig;
|
|
38
38
|
}): {
|
|
39
39
|
user: {
|
|
40
|
-
get:
|
|
40
|
+
get: {
|
|
41
|
+
(ctx: ComponentReadCtx, userId: string): Promise<Doc<"User"> | null>;
|
|
42
|
+
(ctx: ComponentReadCtx, userIds: readonly string[]): Promise<Array<Doc<"User"> | null>>;
|
|
43
|
+
};
|
|
41
44
|
list: (ctx: ComponentReadCtx, opts?: {
|
|
42
45
|
where?: UserWhere;
|
|
43
46
|
limit?: number;
|
|
@@ -47,7 +50,7 @@ declare function createAuthContext(component: ConvexAuthConfig["component"], con
|
|
|
47
50
|
}) => Promise<any>;
|
|
48
51
|
viewer: (ctx: ComponentReadCtx & {
|
|
49
52
|
auth: convex_server0.Auth;
|
|
50
|
-
}) => Promise<
|
|
53
|
+
}) => Promise<Doc<"User"> | null>;
|
|
51
54
|
update: (ctx: ComponentCtx, userId: string, data: Record<string, unknown>) => Promise<{
|
|
52
55
|
userId: string;
|
|
53
56
|
}>;
|
|
@@ -74,6 +77,9 @@ declare function createAuthContext(component: ConvexAuthConfig["component"], con
|
|
|
74
77
|
current: (ctx: {
|
|
75
78
|
auth: convex_server0.Auth;
|
|
76
79
|
}) => Promise<convex_values0.GenericId<"Session"> | null>;
|
|
80
|
+
userId: (ctx: {
|
|
81
|
+
auth: convex_server0.Auth;
|
|
82
|
+
}) => Promise<convex_values0.GenericId<"User"> | null>;
|
|
77
83
|
invalidate: <DataModel extends fluent_convex0.GenericDataModel>(ctx: convex_server0.GenericActionCtx<DataModel>, args: {
|
|
78
84
|
userId: convex_values0.GenericId<"User">;
|
|
79
85
|
except?: convex_values0.GenericId<"Session">[];
|
|
@@ -160,7 +166,10 @@ declare function createAuthContext(component: ConvexAuthConfig["component"], con
|
|
|
160
166
|
}) => Promise<{
|
|
161
167
|
groupId: string;
|
|
162
168
|
}>;
|
|
163
|
-
get:
|
|
169
|
+
get: {
|
|
170
|
+
(ctx: ComponentReadCtx, groupId: string): Promise<Doc<"Group"> | null>;
|
|
171
|
+
(ctx: ComponentReadCtx, groupIds: readonly string[]): Promise<Array<Doc<"Group"> | null>>;
|
|
172
|
+
};
|
|
164
173
|
list: (ctx: ComponentReadCtx, opts?: {
|
|
165
174
|
where?: {
|
|
166
175
|
slug?: string;
|
|
@@ -193,7 +202,7 @@ declare function createAuthContext(component: ConvexAuthConfig["component"], con
|
|
|
193
202
|
maxDepth?: number;
|
|
194
203
|
includeSelf?: boolean;
|
|
195
204
|
}) => Promise<{
|
|
196
|
-
ancestors:
|
|
205
|
+
ancestors: Array<Exclude<Doc<"Group"> | null, null>>;
|
|
197
206
|
cycleDetected: boolean;
|
|
198
207
|
maxDepthReached: boolean;
|
|
199
208
|
}>;
|
|
@@ -227,29 +236,44 @@ declare function createAuthContext(component: ConvexAuthConfig["component"], con
|
|
|
227
236
|
update: (ctx: ComponentCtx, memberId: string, data: Record<string, unknown>) => Promise<{
|
|
228
237
|
memberId: string;
|
|
229
238
|
}>;
|
|
230
|
-
inspect:
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
ancestry?: boolean;
|
|
234
|
-
maxDepth?: number;
|
|
235
|
-
}) => Promise<{
|
|
236
|
-
membership: null;
|
|
237
|
-
roleIds: string[];
|
|
238
|
-
grants: string[];
|
|
239
|
-
} | {
|
|
240
|
-
membership: {
|
|
241
|
-
_id: string;
|
|
242
|
-
_creationTime: number;
|
|
239
|
+
inspect: {
|
|
240
|
+
(ctx: ComponentReadCtx, opts: {
|
|
241
|
+
userId: string;
|
|
243
242
|
groupId: string;
|
|
243
|
+
ancestry?: boolean;
|
|
244
|
+
maxDepth?: number;
|
|
245
|
+
}): Promise<{
|
|
246
|
+
membership: {
|
|
247
|
+
_id: string;
|
|
248
|
+
_creationTime: number;
|
|
249
|
+
groupId: string;
|
|
250
|
+
userId: string;
|
|
251
|
+
role?: string;
|
|
252
|
+
roleIds?: string[];
|
|
253
|
+
status?: string;
|
|
254
|
+
extend?: Record<string, unknown>;
|
|
255
|
+
} | null;
|
|
256
|
+
roleIds: string[];
|
|
257
|
+
grants: string[];
|
|
258
|
+
}>;
|
|
259
|
+
(ctx: ComponentReadCtx, opts: {
|
|
244
260
|
userId: string;
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
261
|
+
groupIds: readonly string[];
|
|
262
|
+
}): Promise<Array<{
|
|
263
|
+
membership: {
|
|
264
|
+
_id: string;
|
|
265
|
+
_creationTime: number;
|
|
266
|
+
groupId: string;
|
|
267
|
+
userId: string;
|
|
268
|
+
role?: string;
|
|
269
|
+
roleIds?: string[];
|
|
270
|
+
status?: string;
|
|
271
|
+
extend?: Record<string, unknown>;
|
|
272
|
+
} | null;
|
|
273
|
+
roleIds: string[];
|
|
274
|
+
grants: string[];
|
|
275
|
+
}>>;
|
|
276
|
+
};
|
|
253
277
|
require: (ctx: ComponentReadCtx, opts: {
|
|
254
278
|
userId: string;
|
|
255
279
|
groupId: string;
|
|
@@ -267,7 +291,7 @@ declare function createAuthContext(component: ConvexAuthConfig["component"], con
|
|
|
267
291
|
roleIds?: string[];
|
|
268
292
|
status?: string;
|
|
269
293
|
extend?: Record<string, unknown>;
|
|
270
|
-
};
|
|
294
|
+
} | null;
|
|
271
295
|
roleIds: string[];
|
|
272
296
|
grants: string[];
|
|
273
297
|
}>;
|
|
@@ -372,6 +396,18 @@ declare function createAuthContext(component: ConvexAuthConfig["component"], con
|
|
|
372
396
|
secret: string;
|
|
373
397
|
}>;
|
|
374
398
|
};
|
|
399
|
+
/**
|
|
400
|
+
* Zero-round-trip helper: parse the current user id straight from the
|
|
401
|
+
* JWT subject claim. No component read, no cache lookup — just the
|
|
402
|
+
* identity token. Returns `null` when unauthenticated.
|
|
403
|
+
*
|
|
404
|
+
* Prefer this over `auth.context(ctx)` when you only need the user's
|
|
405
|
+
* id (e.g. early guards, routing decisions, audit logging). For the
|
|
406
|
+
* full user document, follow up with `auth.user.get(ctx, userId)`.
|
|
407
|
+
*/
|
|
408
|
+
getUserId: (ctx: {
|
|
409
|
+
auth: convex_server0.Auth;
|
|
410
|
+
}) => Promise<convex_values0.GenericId<"User"> | null>;
|
|
375
411
|
context: AuthContextResolver;
|
|
376
412
|
ctx: AuthContextFactory;
|
|
377
413
|
};
|
package/dist/core/index.js
CHANGED
|
@@ -70,6 +70,7 @@ function createAuthContext(component, config) {
|
|
|
70
70
|
member: domains.member,
|
|
71
71
|
invite: domains.invite,
|
|
72
72
|
key: domains.key,
|
|
73
|
+
getUserId: domains.session.userId,
|
|
73
74
|
context: ((ctx, config$1) => {
|
|
74
75
|
assertAuthResolverContext(ctx);
|
|
75
76
|
return createPublicAuthContext(authLike, ctx, config$1);
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { SessionIssuance } from "../server/sessions.js";
|
|
1
2
|
import { AuthProviderConfig, ConvexCredentialsConfig, GenericActionCtxWithAuthConfig } from "../server/types.js";
|
|
2
3
|
import { GenericId, Value } from "convex/values";
|
|
3
4
|
import { GenericDataModel } from "convex/server";
|
|
@@ -14,6 +15,17 @@ interface CredentialsConfig<DataModel extends GenericDataModel = GenericDataMode
|
|
|
14
15
|
authorize: (credentials: Partial<Record<string, Value | undefined>>, ctx: GenericActionCtxWithAuthConfig<DataModel>) => Promise<{
|
|
15
16
|
userId: GenericId<"User">;
|
|
16
17
|
sessionId?: GenericId<"Session">;
|
|
18
|
+
/**
|
|
19
|
+
* TOTP step-up hint. `false` skips the `totpGetVerifiedByUserId` query;
|
|
20
|
+
* `true`/`undefined` falls back to it.
|
|
21
|
+
*/
|
|
22
|
+
hasTotp?: boolean;
|
|
23
|
+
/**
|
|
24
|
+
* Pre-issued session from a combined verify+issue mutation. When set,
|
|
25
|
+
* the framework skips the second `callSignIn` mutation and finalizes
|
|
26
|
+
* the issuance directly on the action side.
|
|
27
|
+
*/
|
|
28
|
+
issuance?: SessionIssuance;
|
|
17
29
|
} | null>;
|
|
18
30
|
/** Optional hashing helpers for password-style credential verification. */
|
|
19
31
|
crypto?: {
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
import { callCredentialsSignIn } from "../server/mutations/credentialsSignIn.js";
|
|
1
2
|
import { credentials } from "./credentials.js";
|
|
3
|
+
import { ConvexError } from "convex/values";
|
|
2
4
|
import { scryptAsync } from "@noble/hashes/scrypt.js";
|
|
3
5
|
import { bytesToHex } from "@noble/hashes/utils.js";
|
|
4
6
|
|
|
@@ -92,7 +94,11 @@ function password(config = {}) {
|
|
|
92
94
|
accountId: account._id,
|
|
93
95
|
params
|
|
94
96
|
});
|
|
95
|
-
|
|
97
|
+
const hasTotp = user.hasTotp;
|
|
98
|
+
return {
|
|
99
|
+
userId: user._id,
|
|
100
|
+
hasTotp
|
|
101
|
+
};
|
|
96
102
|
};
|
|
97
103
|
if (flowDispatch.tag === "signUp") {
|
|
98
104
|
const secret = requirePasswordParam(params.password, "signUp");
|
|
@@ -108,16 +114,31 @@ function password(config = {}) {
|
|
|
108
114
|
});
|
|
109
115
|
return await finalizeCredentialsResult(created.account, created.user);
|
|
110
116
|
} else if (flowDispatch.tag === "signIn") {
|
|
111
|
-
const
|
|
112
|
-
const retrieved = await ctx.auth.account.get(ctx, {
|
|
117
|
+
const result = await callCredentialsSignIn(ctx, {
|
|
113
118
|
provider,
|
|
114
119
|
account: {
|
|
115
120
|
id: email,
|
|
116
|
-
secret
|
|
117
|
-
}
|
|
121
|
+
secret: requirePasswordParam(params.password, "signIn")
|
|
122
|
+
},
|
|
123
|
+
generateTokens: true,
|
|
124
|
+
requireVerifiedEmail: verifyProvider !== void 0,
|
|
125
|
+
enforceTotp: true
|
|
118
126
|
});
|
|
119
|
-
if (
|
|
120
|
-
|
|
127
|
+
if (result.kind === "invalidAccount" || result.kind === "invalidSecret") throw new Error("Invalid credentials");
|
|
128
|
+
if (result.kind === "tooManyAttempts") throw new ConvexError({
|
|
129
|
+
code: "RATE_LIMITED",
|
|
130
|
+
message: "Too many failed sign-in attempts. Please try again later."
|
|
131
|
+
});
|
|
132
|
+
if (result.kind === "emailVerificationRequired") return await ctx.auth.provider.signIn(ctx, verifyProvider, {
|
|
133
|
+
accountId: result.account._id,
|
|
134
|
+
params
|
|
135
|
+
});
|
|
136
|
+
const hasTotp = result.kind === "signedIn" ? result.user.hasTotp : true;
|
|
137
|
+
return {
|
|
138
|
+
userId: result.user._id,
|
|
139
|
+
hasTotp,
|
|
140
|
+
issuance: result.issuance
|
|
141
|
+
};
|
|
121
142
|
} else if (flowDispatch.tag === "reset") {
|
|
122
143
|
if (!resetProvider) throw new Error(`Password reset is not enabled for ${provider}`);
|
|
123
144
|
const { account } = await ctx.auth.account.get(ctx, {
|
|
@@ -139,6 +139,23 @@ type AuthContextConfig<TResolve extends Record<string, unknown> = Record<string,
|
|
|
139
139
|
* of throwing `NOT_SIGNED_IN`.
|
|
140
140
|
*/
|
|
141
141
|
optional?: boolean;
|
|
142
|
+
/**
|
|
143
|
+
* Resolve the active group + membership when building `ctx.auth`.
|
|
144
|
+
*
|
|
145
|
+
* The full resolver fires three sequential component reads on every
|
|
146
|
+
* call: `user.get`, `user.getActiveGroup`, `member.inspect`. For
|
|
147
|
+
* handlers that only need `userId` / `user` (e.g. `account:listPasskeys`,
|
|
148
|
+
* profile reads, self-service settings), the second and third reads are
|
|
149
|
+
* pure overhead.
|
|
150
|
+
*
|
|
151
|
+
* Set `group: false` to skip them. `ctx.auth.groupId`, `ctx.auth.role`,
|
|
152
|
+
* and `ctx.auth.grants` come back as `null` / `[]` without any
|
|
153
|
+
* component round-trip. Saves ~10–30ms per auth-gated call on the
|
|
154
|
+
* lightweight path.
|
|
155
|
+
*
|
|
156
|
+
* @defaultValue true
|
|
157
|
+
*/
|
|
158
|
+
group?: boolean;
|
|
142
159
|
/**
|
|
143
160
|
* Attach additional derived fields to the auth context after the base auth
|
|
144
161
|
* context is resolved.
|
|
@@ -3,7 +3,7 @@ import { ConvexError } from "convex/values";
|
|
|
3
3
|
|
|
4
4
|
//#region src/server/auth-context.ts
|
|
5
5
|
async function resolveConfiguredAuthContext(auth, ctx, config) {
|
|
6
|
-
const fallback = () => getAuthContext(auth, ctx);
|
|
6
|
+
const fallback = () => getAuthContext(auth, ctx, { group: config?.group !== false });
|
|
7
7
|
const authOverride = config?.authResolve ? await config.authResolve(ctx, fallback) : void 0;
|
|
8
8
|
return authOverride === void 0 ? await fallback() : authOverride;
|
|
9
9
|
}
|
package/dist/server/auth.d.ts
CHANGED
|
@@ -34,12 +34,7 @@ type MemberApiWithAuthorization<TAuthorization extends AuthAuthorizationConfig |
|
|
|
34
34
|
}) => Promise<{
|
|
35
35
|
memberId: string;
|
|
36
36
|
}>;
|
|
37
|
-
inspect:
|
|
38
|
-
userId: string;
|
|
39
|
-
groupId: string;
|
|
40
|
-
ancestry?: boolean;
|
|
41
|
-
maxDepth?: number;
|
|
42
|
-
}) => ReturnType<ReturnType<typeof Auth>["auth"]["member"]["inspect"]>;
|
|
37
|
+
inspect: ReturnType<typeof Auth>["auth"]["member"]["inspect"];
|
|
43
38
|
require: (ctx: Parameters<ReturnType<typeof Auth>["auth"]["member"]["require"]>[0], opts: {
|
|
44
39
|
userId: string;
|
|
45
40
|
groupId: string;
|
|
@@ -77,6 +72,23 @@ type AuthApiBase<TAuthorization extends AuthAuthorizationConfig | undefined = un
|
|
|
77
72
|
invite: ReturnType<typeof Auth>["auth"]["invite"];
|
|
78
73
|
key: ReturnType<typeof Auth>["auth"]["key"];
|
|
79
74
|
http: ReturnType<typeof Auth>["auth"]["http"];
|
|
75
|
+
/**
|
|
76
|
+
* Zero-round-trip helper: parse the current user id from the JWT subject
|
|
77
|
+
* claim. No component read, no cache lookup. Returns `null` when
|
|
78
|
+
* unauthenticated.
|
|
79
|
+
*
|
|
80
|
+
* Prefer this over `auth.context(ctx)` when a handler only needs the
|
|
81
|
+
* user's id (audit logging, early guards, routing). For the full user
|
|
82
|
+
* document, follow up with `auth.user.get(ctx, userId)` — cached per
|
|
83
|
+
* request.
|
|
84
|
+
*
|
|
85
|
+
* @example
|
|
86
|
+
* ```ts
|
|
87
|
+
* const userId = await auth.getUserId(ctx);
|
|
88
|
+
* if (!userId) throw new Error("Not signed in");
|
|
89
|
+
* ```
|
|
90
|
+
*/
|
|
91
|
+
getUserId: ReturnType<typeof Auth>["auth"]["session"]["userId"];
|
|
80
92
|
/**
|
|
81
93
|
* Resolve the current request's auth context. Framework-agnostic — use
|
|
82
94
|
* this in fluent-convex middleware, custom wrappers, or anywhere you
|
package/dist/server/auth.js
CHANGED
|
@@ -145,6 +145,7 @@ function createAuth(component, config) {
|
|
|
145
145
|
invite: authResult.auth.invite,
|
|
146
146
|
key: authResult.auth.key,
|
|
147
147
|
http: authResult.auth.http,
|
|
148
|
+
getUserId: authResult.auth.session.userId,
|
|
148
149
|
context: ((ctx, config$1) => {
|
|
149
150
|
assertAuthResolverContext(ctx);
|
|
150
151
|
return createPublicAuthContext(authResult.auth, ctx, config$1);
|
package/dist/server/context.js
CHANGED
|
@@ -8,9 +8,15 @@ async function getSessionUserId(ctx) {
|
|
|
8
8
|
return userIdFromIdentitySubject(identity.subject);
|
|
9
9
|
}
|
|
10
10
|
/** @internal */
|
|
11
|
-
async function getAuthContextForUser(auth, ctx, userId) {
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
async function getAuthContextForUser(auth, ctx, userId, opts) {
|
|
12
|
+
if (opts?.group === false) return {
|
|
13
|
+
userId,
|
|
14
|
+
user: await auth.user.get(ctx, userId),
|
|
15
|
+
groupId: null,
|
|
16
|
+
role: null,
|
|
17
|
+
grants: []
|
|
18
|
+
};
|
|
19
|
+
const [user, groupId] = await Promise.all([auth.user.get(ctx, userId), auth.user.getActiveGroup(ctx, { userId })]);
|
|
14
20
|
let role = null;
|
|
15
21
|
let grants = [];
|
|
16
22
|
if (groupId) {
|
|
@@ -32,10 +38,10 @@ async function getAuthContextForUser(auth, ctx, userId) {
|
|
|
32
38
|
};
|
|
33
39
|
}
|
|
34
40
|
/** @internal */
|
|
35
|
-
async function getAuthContext(auth, ctx) {
|
|
41
|
+
async function getAuthContext(auth, ctx, opts) {
|
|
36
42
|
const userId = await getSessionUserId(ctx);
|
|
37
43
|
if (userId === null) return null;
|
|
38
|
-
return await getAuthContextForUser(auth, ctx, userId);
|
|
44
|
+
return await getAuthContextForUser(auth, ctx, userId, opts);
|
|
39
45
|
}
|
|
40
46
|
/** @internal */
|
|
41
47
|
function createUnauthenticatedAuthContext() {
|
package/dist/server/contract.js
CHANGED
|
@@ -1,25 +1,57 @@
|
|
|
1
|
+
import { cached, invalidateCtxCache } from "./ctxCache.js";
|
|
2
|
+
|
|
1
3
|
//#region src/server/contract.ts
|
|
2
4
|
const query = (ctx, ref, args) => ctx.runQuery(ref, args);
|
|
3
5
|
const mutate = (ctx, ref, args) => ctx.runMutation(ref, args);
|
|
4
|
-
const getGroupConnection = (ctx, componentPublic, connectionId) => query(ctx, componentPublic.groupConnectionGet, { connectionId });
|
|
5
|
-
const getGroupConnectionByDomain = (ctx, componentPublic, domain) => query(ctx, componentPublic.groupConnectionGetByDomain, { domain });
|
|
6
|
+
const getGroupConnection = (ctx, componentPublic, connectionId) => cached(ctx, `group-connection:${connectionId}`, () => query(ctx, componentPublic.groupConnectionGet, { connectionId }));
|
|
7
|
+
const getGroupConnectionByDomain = (ctx, componentPublic, domain) => cached(ctx, `group-connection-domain:${domain}`, () => query(ctx, componentPublic.groupConnectionGetByDomain, { domain }));
|
|
6
8
|
const listGroupConnections = (ctx, componentPublic, args) => query(ctx, componentPublic.groupConnectionList, args);
|
|
7
9
|
const createGroupConnection = (ctx, componentPublic, args) => mutate(ctx, componentPublic.groupConnectionCreate, args);
|
|
8
|
-
const updateGroupConnection = (ctx, componentPublic, args) =>
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
const
|
|
10
|
+
const updateGroupConnection = async (ctx, componentPublic, args) => {
|
|
11
|
+
const result = await mutate(ctx, componentPublic.groupConnectionUpdate, args);
|
|
12
|
+
invalidateCtxCache(ctx, `group-connection:${args.connectionId}`);
|
|
13
|
+
invalidateCtxCache(ctx, "group-connection-domain");
|
|
14
|
+
return result;
|
|
15
|
+
};
|
|
16
|
+
const deleteGroupConnection = async (ctx, componentPublic, connectionId) => {
|
|
17
|
+
const result = await mutate(ctx, componentPublic.groupConnectionDelete, { connectionId });
|
|
18
|
+
invalidateCtxCache(ctx, `group-connection:${connectionId}`);
|
|
19
|
+
invalidateCtxCache(ctx, "group-connection-domain");
|
|
20
|
+
invalidateCtxCache(ctx, `connection-domains:${connectionId}`);
|
|
21
|
+
invalidateCtxCache(ctx, "group-connection-secret");
|
|
22
|
+
return result;
|
|
23
|
+
};
|
|
24
|
+
const getGroup = (ctx, componentPublic, groupId) => cached(ctx, `group-record:${groupId}`, () => query(ctx, componentPublic.groupGet, { groupId }));
|
|
25
|
+
const listConnectionDomains = (ctx, componentPublic, connectionId) => cached(ctx, `connection-domains:${connectionId}`, () => query(ctx, componentPublic.groupConnectionDomainList, { connectionId }));
|
|
26
|
+
const addConnectionDomain = async (ctx, componentPublic, args) => {
|
|
27
|
+
const result = await mutate(ctx, componentPublic.groupConnectionDomainAdd, args);
|
|
28
|
+
invalidateCtxCache(ctx, `connection-domains:${args.connectionId}`);
|
|
29
|
+
invalidateCtxCache(ctx, "group-connection-domain");
|
|
30
|
+
return result;
|
|
31
|
+
};
|
|
32
|
+
const deleteConnectionDomain = async (ctx, componentPublic, domainId) => {
|
|
33
|
+
const result = await mutate(ctx, componentPublic.groupConnectionDomainDelete, { domainId });
|
|
34
|
+
invalidateCtxCache(ctx, "connection-domains");
|
|
35
|
+
invalidateCtxCache(ctx, "group-connection-domain");
|
|
36
|
+
return result;
|
|
37
|
+
};
|
|
38
|
+
const getScimConfigByConnection = (ctx, componentPublic, connectionId) => cached(ctx, `scim-config-by-connection:${connectionId}`, () => query(ctx, componentPublic.groupConnectionScimConfigGetByGroupConnection, { connectionId }));
|
|
15
39
|
const getScimConfigByTokenHash = (ctx, componentPublic, tokenHash) => query(ctx, componentPublic.groupConnectionScimConfigGetByTokenHash, { tokenHash });
|
|
16
|
-
const upsertScimConfig = (ctx, componentPublic, args) =>
|
|
40
|
+
const upsertScimConfig = async (ctx, componentPublic, args) => {
|
|
41
|
+
const result = await mutate(ctx, componentPublic.groupConnectionScimConfigUpsert, args);
|
|
42
|
+
invalidateCtxCache(ctx, `scim-config-by-connection:${args.connectionId}`);
|
|
43
|
+
return result;
|
|
44
|
+
};
|
|
17
45
|
const getConnectionDomainVerification = (ctx, componentPublic, domainId) => query(ctx, componentPublic.groupConnectionDomainVerificationGet, { domainId });
|
|
18
46
|
const upsertConnectionDomainVerification = (ctx, componentPublic, args) => mutate(ctx, componentPublic.groupConnectionDomainVerificationUpsert, args);
|
|
19
47
|
const deleteConnectionDomainVerification = (ctx, componentPublic, domainId) => mutate(ctx, componentPublic.groupConnectionDomainVerificationDelete, { domainId });
|
|
20
48
|
const verifyConnectionDomain = (ctx, componentPublic, args) => mutate(ctx, componentPublic.groupConnectionDomainVerify, args);
|
|
21
|
-
const getGroupConnectionSecret = (ctx, componentPublic, args) => query(ctx, componentPublic.groupConnectionSecretGet, args);
|
|
22
|
-
const upsertGroupConnectionSecret = (ctx, componentPublic, args) =>
|
|
49
|
+
const getGroupConnectionSecret = (ctx, componentPublic, args) => cached(ctx, `group-connection-secret:${args.connectionId}:${args.kind}`, () => query(ctx, componentPublic.groupConnectionSecretGet, args));
|
|
50
|
+
const upsertGroupConnectionSecret = async (ctx, componentPublic, args) => {
|
|
51
|
+
const result = await mutate(ctx, componentPublic.groupConnectionSecretUpsert, args);
|
|
52
|
+
invalidateCtxCache(ctx, `group-connection-secret:${args.connectionId}:${args.kind}`);
|
|
53
|
+
return result;
|
|
54
|
+
};
|
|
23
55
|
const listWebhookEndpoints = (ctx, componentPublic, connectionId) => query(ctx, componentPublic.groupWebhookEndpointList, { connectionId });
|
|
24
56
|
const listWebhookDeliveries = (ctx, componentPublic, args) => query(ctx, componentPublic["groupWebhookDeliveryList"], args);
|
|
25
57
|
const listScimIdentitiesByConnection = (ctx, componentPublic, connectionId) => query(ctx, componentPublic.groupConnectionScimIdentityListByGroupConnection, { connectionId });
|