@robelest/convex-auth 0.0.4-preview.32 → 0.0.4-preview.34
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/component/_generated/component.d.ts +1611 -2039
- package/dist/component/account.js +3 -0
- package/dist/component/convex.config.d.ts +2 -2
- package/dist/component/factor/device.js +3 -0
- package/dist/component/factor/passkey.js +3 -0
- package/dist/component/factor/totp.js +3 -0
- package/dist/component/group/invite.js +3 -0
- package/dist/component/group/member.js +3 -0
- package/dist/component/group.js +3 -0
- package/dist/component/model.d.ts +342 -30
- package/dist/component/model.js +22 -4
- package/dist/component/modules.js +24 -21
- package/dist/component/public/factors/devices.js +37 -106
- package/dist/component/public/factors/passkeys.js +29 -149
- package/dist/component/public/factors/totp.js +32 -159
- package/dist/component/public/groups/core.js +19 -82
- package/dist/component/public/groups/invites.js +15 -104
- package/dist/component/public/groups/members.js +26 -149
- package/dist/component/public/identity/accounts.js +12 -94
- package/dist/component/public/identity/codes.js +13 -73
- package/dist/component/public/identity/sessions.js +5 -107
- package/dist/component/public/identity/tokens.js +13 -103
- package/dist/component/public/identity/users.js +188 -185
- package/dist/component/public/identity/verifiers.js +17 -80
- package/dist/component/public/security/keys.js +13 -120
- package/dist/component/public/security/limits.js +0 -43
- package/dist/component/public/sso/audit.js +0 -28
- package/dist/component/public/sso/core.js +31 -104
- package/dist/component/public/sso/domains.js +0 -71
- package/dist/component/public/sso/scim.js +63 -239
- package/dist/component/public/sso/secrets.js +0 -30
- package/dist/component/public/sso/webhooks.js +23 -128
- package/dist/component/rateLimit.js +3 -0
- package/dist/component/schema.d.ts +378 -342
- package/dist/component/schema.js +11 -1
- package/dist/component/session.js +3 -0
- package/dist/component/sso/audit.js +3 -0
- package/dist/component/sso/connection/domain/verification.js +3 -0
- package/dist/component/sso/connection/domain.js +3 -0
- package/dist/component/sso/connection/scim/config.js +3 -0
- package/dist/component/sso/connection/scim/identity.js +3 -0
- package/dist/component/sso/connection/secret.js +3 -0
- package/dist/component/sso/connection.js +3 -0
- package/dist/component/sso/webhook/delivery.js +3 -0
- package/dist/component/sso/webhook/endpoint.js +3 -0
- package/dist/component/token/pkce.js +3 -0
- package/dist/component/token/refresh.js +3 -0
- package/dist/component/token/verification.js +3 -0
- package/dist/component/user/email.js +3 -0
- package/dist/component/user/key.js +3 -0
- package/dist/component/user.js +62 -0
- package/dist/core/index.d.ts +131 -28
- package/dist/core/index.js +2 -0
- package/dist/model.js +391 -0
- package/dist/providers/credentials.d.ts +1 -1
- package/dist/providers/github.js +6 -0
- package/dist/providers/password.js +1 -2
- package/dist/server/auth.d.ts +73 -7
- package/dist/server/auth.js +4 -1
- package/dist/server/context.js +30 -3
- package/dist/server/contract.js +42 -42
- package/dist/server/core.js +224 -86
- package/dist/server/db.js +45 -37
- package/dist/server/facade.d.ts +39 -0
- package/dist/server/facade.js +16 -0
- package/dist/server/index.d.ts +5 -3
- package/dist/server/index.js +3 -1
- package/dist/server/mounts.d.ts +101 -101
- package/dist/server/mutations/credentials/signin.js +3 -7
- package/dist/server/mutations/oauth.js +9 -6
- package/dist/server/runtime.d.ts +147 -46
- package/dist/server/runtime.js +10 -8
- package/dist/server/services/group.js +9 -9
- package/dist/server/sso/domain.d.ts +1 -1
- package/dist/server/sso/domain.js +40 -40
- package/dist/server/sso/http.js +18 -18
- package/dist/server/sso/oidc.js +1 -1
- package/dist/server/sso/policies.js +3 -3
- package/dist/server/sso/policy.js +12 -4
- package/dist/server/sso/provision.js +9 -9
- package/dist/server/sso/validators.js +2 -2
- package/dist/server/sso/webhook.js +8 -8
- package/dist/server/types.d.ts +185 -124
- package/dist/server/types.js +29 -24
- package/dist/server/users.js +49 -2
- package/dist/server/validators.d.ts +745 -0
- package/dist/server/validators.js +60 -0
- package/package.json +1 -1
- package/dist/component/public.js +0 -22
|
@@ -19,20 +19,6 @@ import { v } from "convex/values";
|
|
|
19
19
|
* @param args.extend - An optional arbitrary extension object for custom SCIM settings.
|
|
20
20
|
* @returns The ID of the created or updated `GroupConnectionScimConfig` document.
|
|
21
21
|
*
|
|
22
|
-
* @example
|
|
23
|
-
* ```ts
|
|
24
|
-
* const configId = await ctx.runMutation(
|
|
25
|
-
* components.auth.group.sso.groupConnectionScimConfigUpsert,
|
|
26
|
-
* {
|
|
27
|
-
* connectionId,
|
|
28
|
-
* groupId: orgGroupId,
|
|
29
|
-
* status: "active",
|
|
30
|
-
* basePath: "/scim/v2",
|
|
31
|
-
* tokenHash: "sha256:abc123...",
|
|
32
|
-
* lastRotatedAt: Date.now(),
|
|
33
|
-
* },
|
|
34
|
-
* );
|
|
35
|
-
* ```
|
|
36
22
|
*/
|
|
37
23
|
const groupConnectionScimConfigUpsert = mutation({
|
|
38
24
|
args: {
|
|
@@ -55,212 +41,82 @@ const groupConnectionScimConfigUpsert = mutation({
|
|
|
55
41
|
}
|
|
56
42
|
});
|
|
57
43
|
/**
|
|
58
|
-
*
|
|
44
|
+
* Read a SCIM configuration by identity.
|
|
59
45
|
*
|
|
60
|
-
*
|
|
61
|
-
* `
|
|
46
|
+
* Accepts exactly one selector:
|
|
47
|
+
* - `connectionId` — the SCIM config for a group connection, via the
|
|
48
|
+
* `group_connection_id` index.
|
|
49
|
+
* - `tokenHash` — resolve which connection a bearer token belongs to,
|
|
50
|
+
* via the `token_hash` index (used during SCIM request auth).
|
|
62
51
|
*
|
|
63
|
-
* @param
|
|
64
|
-
* @
|
|
52
|
+
* @param connectionId - Optional `_id` of the `GroupConnection`.
|
|
53
|
+
* @param tokenHash - Optional bearer-token hash from an incoming request.
|
|
54
|
+
* @returns The matching SCIM configuration document, or `null`.
|
|
65
55
|
*
|
|
66
|
-
* @example
|
|
67
|
-
* ```ts
|
|
68
|
-
* const config = await ctx.runQuery(
|
|
69
|
-
* components.auth.public.groupConnectionScimConfigGetByGroupConnection,
|
|
70
|
-
* { connectionId },
|
|
71
|
-
* );
|
|
72
|
-
* if (config) {
|
|
73
|
-
* console.log(config.status, config.basePath);
|
|
74
|
-
* }
|
|
75
|
-
* ```
|
|
76
56
|
*/
|
|
77
|
-
const
|
|
78
|
-
args: { connectionId: v.id("GroupConnection") },
|
|
79
|
-
returns: v.union(vGroupConnectionScimConfigDoc, v.null()),
|
|
80
|
-
handler: async (ctx, { connectionId }) => {
|
|
81
|
-
return await ctx.db.query("GroupConnectionScimConfig").withIndex("group_connection_id", (idx) => idx.eq("connectionId", connectionId)).first();
|
|
82
|
-
}
|
|
83
|
-
});
|
|
84
|
-
/**
|
|
85
|
-
* Look up a SCIM configuration by its bearer token hash.
|
|
86
|
-
*
|
|
87
|
-
* Used during SCIM request authentication to resolve which group connection a
|
|
88
|
-
* given bearer token belongs to. Returns `null` if no config matches.
|
|
89
|
-
*
|
|
90
|
-
* @param args.tokenHash - The hash of the bearer token from the incoming SCIM request.
|
|
91
|
-
* @returns The matching SCIM configuration document, or `null` if not found.
|
|
92
|
-
*
|
|
93
|
-
* @example
|
|
94
|
-
* ```ts
|
|
95
|
-
* const config = await ctx.runQuery(
|
|
96
|
-
* components.auth.group.sso.groupConnectionScimConfigGetByTokenHash,
|
|
97
|
-
* { tokenHash: "sha256:abc123..." },
|
|
98
|
-
* );
|
|
99
|
-
* if (config) {
|
|
100
|
-
* console.log("Authenticated group:", config.connectionId);
|
|
101
|
-
* }
|
|
102
|
-
* ```
|
|
103
|
-
*/
|
|
104
|
-
const groupConnectionScimConfigGetByTokenHash = query({
|
|
105
|
-
args: { tokenHash: v.string() },
|
|
106
|
-
returns: v.union(vGroupConnectionScimConfigDoc, v.null()),
|
|
107
|
-
handler: async (ctx, { tokenHash }) => {
|
|
108
|
-
return await ctx.db.query("GroupConnectionScimConfig").withIndex("token_hash", (idx) => idx.eq("tokenHash", tokenHash)).first();
|
|
109
|
-
}
|
|
110
|
-
});
|
|
111
|
-
/**
|
|
112
|
-
* Retrieve a SCIM identity by group connection, resource type, and external ID.
|
|
113
|
-
*
|
|
114
|
-
* Looks up a SCIM-provisioned identity using the composite index on
|
|
115
|
-
* `(connectionId, resourceType, externalId)`. This is the primary lookup
|
|
116
|
-
* used when processing incoming SCIM user or group operations.
|
|
117
|
-
*
|
|
118
|
-
* @param args.connectionId - The ID of the group connection that owns the SCIM identity.
|
|
119
|
-
* @param args.resourceType - The SCIM resource type: `"user"` or `"group"`.
|
|
120
|
-
* @param args.externalId - The external identifier assigned by the identity provider.
|
|
121
|
-
* @returns The SCIM identity document, or `null` if not found.
|
|
122
|
-
*
|
|
123
|
-
* @example
|
|
124
|
-
* ```ts
|
|
125
|
-
* const identity = await ctx.runQuery(
|
|
126
|
-
* components.auth.group.sso.groupConnectionScimIdentityGet,
|
|
127
|
-
* {
|
|
128
|
-
* connectionId,
|
|
129
|
-
* resourceType: "user",
|
|
130
|
-
* externalId: "okta-user-abc123",
|
|
131
|
-
* },
|
|
132
|
-
* );
|
|
133
|
-
* ```
|
|
134
|
-
*/
|
|
135
|
-
const groupConnectionScimIdentityGet = query({
|
|
57
|
+
const groupConnectionScimConfigGet = query({
|
|
136
58
|
args: {
|
|
137
|
-
connectionId: v.id("GroupConnection"),
|
|
138
|
-
|
|
139
|
-
externalId: v.string()
|
|
59
|
+
connectionId: v.optional(v.id("GroupConnection")),
|
|
60
|
+
tokenHash: v.optional(v.string())
|
|
140
61
|
},
|
|
141
|
-
returns: v.union(
|
|
62
|
+
returns: v.union(vGroupConnectionScimConfigDoc, v.null()),
|
|
142
63
|
handler: async (ctx, args) => {
|
|
143
|
-
return await ctx.db.query("
|
|
64
|
+
if (args.tokenHash !== void 0) return await ctx.db.query("GroupConnectionScimConfig").withIndex("token_hash", (idx) => idx.eq("tokenHash", args.tokenHash)).first();
|
|
65
|
+
if (args.connectionId === void 0) return null;
|
|
66
|
+
return await ctx.db.query("GroupConnectionScimConfig").withIndex("group_connection_id", (idx) => idx.eq("connectionId", args.connectionId)).first();
|
|
144
67
|
}
|
|
145
68
|
});
|
|
146
69
|
/**
|
|
147
|
-
*
|
|
148
|
-
*
|
|
149
|
-
*
|
|
150
|
-
*
|
|
151
|
-
*
|
|
70
|
+
* Read a single SCIM identity by identity.
|
|
71
|
+
*
|
|
72
|
+
* Accepts exactly one selector (checked most-specific first):
|
|
73
|
+
* - `connectionId` + `resourceType` + `externalId` — the composite
|
|
74
|
+
* `(connectionId, resourceType, externalId)` index. Primary lookup for
|
|
75
|
+
* incoming SCIM user/group operations.
|
|
76
|
+
* - `connectionId` + `userId` — the `(connectionId, userId)` index, for
|
|
77
|
+
* a user's identity scoped to one connection.
|
|
78
|
+
* - `userId` — the first identity for a user, via the `user_id` index.
|
|
79
|
+
* - `mappedGroupId` — the identity mapped to an internal group, via the
|
|
80
|
+
* `mapped_group_id` index.
|
|
81
|
+
* - `connectionId` + `userIds` — batch: resolve each user's identity
|
|
82
|
+
* under the connection, returning `(Doc | null)[]` aligned to
|
|
83
|
+
* `userIds` order (duplicates de-duplicated internally). One round-trip
|
|
84
|
+
* for large SCIM syncs instead of a per-user fan-out.
|
|
85
|
+
*
|
|
86
|
+
* @param connectionId - Optional `_id` of the `GroupConnection`.
|
|
87
|
+
* @param resourceType - Optional SCIM resource type (`"user"` | `"group"`).
|
|
88
|
+
* @param externalId - Optional external identifier from the IdP.
|
|
89
|
+
* @param userId - Optional `_id` of the linked `User`.
|
|
90
|
+
* @param userIds - Optional `_id[]` for a batched per-user lookup.
|
|
91
|
+
* @param mappedGroupId - Optional `_id` of the mapped internal `Group`.
|
|
92
|
+
* @returns The matching SCIM identity document or `null`; for `userIds`,
|
|
93
|
+
* an aligned `(Doc | null)[]`.
|
|
152
94
|
*
|
|
153
|
-
* @param args.userId - The document ID of the user whose SCIM identity to retrieve.
|
|
154
|
-
* @returns The SCIM identity document, or `null` if the user has no SCIM identity.
|
|
155
|
-
*
|
|
156
|
-
* @example
|
|
157
|
-
* ```ts
|
|
158
|
-
* const scimIdentity = await ctx.runQuery(
|
|
159
|
-
* components.auth.group.sso.groupConnectionScimIdentityGetByUser,
|
|
160
|
-
* { userId },
|
|
161
|
-
* );
|
|
162
|
-
* if (scimIdentity) {
|
|
163
|
-
* console.log("User provisioned via SCIM:", scimIdentity.externalId);
|
|
164
|
-
* }
|
|
165
|
-
* ```
|
|
166
95
|
*/
|
|
167
|
-
const
|
|
168
|
-
args: { userId: v.id("User") },
|
|
169
|
-
returns: v.union(vGroupConnectionScimIdentityDoc, v.null()),
|
|
170
|
-
handler: async (ctx, { userId }) => {
|
|
171
|
-
return await ctx.db.query("GroupConnectionScimIdentity").withIndex("user_id", (idx) => idx.eq("userId", userId)).first();
|
|
172
|
-
}
|
|
173
|
-
});
|
|
174
|
-
/**
|
|
175
|
-
* Retrieve the SCIM identity for a specific user within a specific group.sso.
|
|
176
|
-
*
|
|
177
|
-
* Uses the composite `(connectionId, userId)` index to find the SCIM identity
|
|
178
|
-
* that links a user to a particular group.sso. This is useful when a user may
|
|
179
|
-
* belong to multiple group connections.
|
|
180
|
-
*
|
|
181
|
-
* @param args.connectionId - The ID of the group connection to scope the lookup to.
|
|
182
|
-
* @param args.userId - The document ID of the user.
|
|
183
|
-
* @returns The SCIM identity document, or `null` if not found.
|
|
184
|
-
*
|
|
185
|
-
* @example
|
|
186
|
-
* ```ts
|
|
187
|
-
* const identity = await ctx.runQuery(
|
|
188
|
-
* components.auth.public.groupConnectionScimIdentityGetByGroupConnectionAndUser,
|
|
189
|
-
* { connectionId, userId },
|
|
190
|
-
* );
|
|
191
|
-
* ```
|
|
192
|
-
*/
|
|
193
|
-
const groupConnectionScimIdentityGetByGroupConnectionAndUser = query({
|
|
194
|
-
args: {
|
|
195
|
-
connectionId: v.id("GroupConnection"),
|
|
196
|
-
userId: v.id("User")
|
|
197
|
-
},
|
|
198
|
-
returns: v.union(vGroupConnectionScimIdentityDoc, v.null()),
|
|
199
|
-
handler: async (ctx, { connectionId, userId }) => {
|
|
200
|
-
return await ctx.db.query("GroupConnectionScimIdentity").withIndex("group_connection_id_user_id", (idx) => idx.eq("connectionId", connectionId).eq("userId", userId)).first();
|
|
201
|
-
}
|
|
202
|
-
});
|
|
203
|
-
/**
|
|
204
|
-
* Batched variant of
|
|
205
|
-
* {@link groupConnectionScimIdentityGetByGroupConnectionAndUser}. Resolves
|
|
206
|
-
* SCIM identities for many users under the same connection in a single
|
|
207
|
-
* component round-trip.
|
|
208
|
-
*
|
|
209
|
-
* Used by large SCIM syncs that previously walked the user list one at a
|
|
210
|
-
* time — a 1000-user import was 1000 lookups. With this helper it's one.
|
|
211
|
-
*
|
|
212
|
-
* @param args.connectionId - The ID of the connection to scope to.
|
|
213
|
-
* @param args.userIds - One or more user ids to look up. Duplicates are
|
|
214
|
-
* tolerated.
|
|
215
|
-
* @returns Array of `{ userId, identity }` pairs in the input order; when
|
|
216
|
-
* a user has no SCIM identity under this connection, `identity` is `null`.
|
|
217
|
-
*/
|
|
218
|
-
const groupConnectionScimIdentityGetByGroupConnectionAndUsers = query({
|
|
96
|
+
const groupConnectionScimIdentityGet = query({
|
|
219
97
|
args: {
|
|
220
|
-
connectionId: v.id("GroupConnection"),
|
|
221
|
-
|
|
98
|
+
connectionId: v.optional(v.id("GroupConnection")),
|
|
99
|
+
resourceType: v.optional(vScimResourceType),
|
|
100
|
+
externalId: v.optional(v.string()),
|
|
101
|
+
userId: v.optional(v.id("User")),
|
|
102
|
+
userIds: v.optional(v.array(v.id("User"))),
|
|
103
|
+
mappedGroupId: v.optional(v.id("Group"))
|
|
222
104
|
},
|
|
223
|
-
returns: v.array(v.
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
/**
|
|
239
|
-
* Retrieve the SCIM identity that is mapped to a specific group.
|
|
240
|
-
*
|
|
241
|
-
* Looks up a SCIM identity by its `mappedGroupId` field. This is used when
|
|
242
|
-
* a SCIM group resource has been mapped to an internal group, and you need
|
|
243
|
-
* to find the corresponding SCIM identity record.
|
|
244
|
-
*
|
|
245
|
-
* @param args.mappedGroupId - The document ID of the internal group that a SCIM group is mapped to.
|
|
246
|
-
* @returns The SCIM identity document, or `null` if no mapping exists.
|
|
247
|
-
*
|
|
248
|
-
* @example
|
|
249
|
-
* ```ts
|
|
250
|
-
* const scimGroup = await ctx.runQuery(
|
|
251
|
-
* components.auth.public.groupConnectionScimIdentityGetByMappedGroup,
|
|
252
|
-
* { mappedGroupId: teamGroupId },
|
|
253
|
-
* );
|
|
254
|
-
* if (scimGroup) {
|
|
255
|
-
* console.log("SCIM external group ID:", scimGroup.externalId);
|
|
256
|
-
* }
|
|
257
|
-
* ```
|
|
258
|
-
*/
|
|
259
|
-
const groupConnectionScimIdentityGetByMappedGroup = query({
|
|
260
|
-
args: { mappedGroupId: v.id("Group") },
|
|
261
|
-
returns: v.union(vGroupConnectionScimIdentityDoc, v.null()),
|
|
262
|
-
handler: async (ctx, { mappedGroupId }) => {
|
|
263
|
-
return await ctx.db.query("GroupConnectionScimIdentity").withIndex("mapped_group_id", (idx) => idx.eq("mappedGroupId", mappedGroupId)).first();
|
|
105
|
+
returns: v.union(vGroupConnectionScimIdentityDoc, v.null(), v.array(v.union(vGroupConnectionScimIdentityDoc, v.null()))),
|
|
106
|
+
handler: async (ctx, args) => {
|
|
107
|
+
if (args.connectionId !== void 0 && args.userIds !== void 0) {
|
|
108
|
+
const userIds = args.userIds;
|
|
109
|
+
if (userIds.length === 0) return [];
|
|
110
|
+
const unique = Array.from(new Set(userIds));
|
|
111
|
+
const docs = await Promise.all(unique.map((userId) => ctx.db.query("GroupConnectionScimIdentity").withIndex("group_connection_id_user_id", (idx) => idx.eq("connectionId", args.connectionId).eq("userId", userId)).first()));
|
|
112
|
+
const byUserId = new Map(unique.map((id, i) => [id, docs[i] ?? null]));
|
|
113
|
+
return userIds.map((userId) => byUserId.get(userId) ?? null);
|
|
114
|
+
}
|
|
115
|
+
if (args.connectionId !== void 0 && args.resourceType !== void 0 && args.externalId !== void 0) return await ctx.db.query("GroupConnectionScimIdentity").withIndex("group_connection_id_resource_type_external_id", (idx) => idx.eq("connectionId", args.connectionId).eq("resourceType", args.resourceType).eq("externalId", args.externalId)).first();
|
|
116
|
+
if (args.connectionId !== void 0 && args.userId !== void 0) return await ctx.db.query("GroupConnectionScimIdentity").withIndex("group_connection_id_user_id", (idx) => idx.eq("connectionId", args.connectionId).eq("userId", args.userId)).first();
|
|
117
|
+
if (args.userId !== void 0) return await ctx.db.query("GroupConnectionScimIdentity").withIndex("user_id", (idx) => idx.eq("userId", args.userId)).first();
|
|
118
|
+
if (args.mappedGroupId !== void 0) return await ctx.db.query("GroupConnectionScimIdentity").withIndex("mapped_group_id", (idx) => idx.eq("mappedGroupId", args.mappedGroupId)).first();
|
|
119
|
+
return null;
|
|
264
120
|
}
|
|
265
121
|
});
|
|
266
122
|
/**
|
|
@@ -273,15 +129,6 @@ const groupConnectionScimIdentityGetByMappedGroup = query({
|
|
|
273
129
|
* @param args.connectionId - The ID of the group connection whose SCIM identities to list.
|
|
274
130
|
* @returns An array of SCIM identity documents.
|
|
275
131
|
*
|
|
276
|
-
* @example
|
|
277
|
-
* ```ts
|
|
278
|
-
* const identities = await ctx.runQuery(
|
|
279
|
-
* components.auth.public.groupConnectionScimIdentityListByGroupConnection,
|
|
280
|
-
* { connectionId },
|
|
281
|
-
* );
|
|
282
|
-
* const users = identities.filter((i) => i.resourceType === "user");
|
|
283
|
-
* const groups = identities.filter((i) => i.resourceType === "group");
|
|
284
|
-
* ```
|
|
285
132
|
*/
|
|
286
133
|
const groupConnectionScimIdentityListByGroupConnection = query({
|
|
287
134
|
args: { connectionId: v.id("GroupConnection") },
|
|
@@ -309,22 +156,6 @@ const groupConnectionScimIdentityListByGroupConnection = query({
|
|
|
309
156
|
* @param args.raw - An optional raw SCIM payload stored for debugging or re-processing.
|
|
310
157
|
* @returns The ID of the created or updated `GroupConnectionScimIdentity` document.
|
|
311
158
|
*
|
|
312
|
-
* @example
|
|
313
|
-
* ```ts
|
|
314
|
-
* const identityId = await ctx.runMutation(
|
|
315
|
-
* components.auth.group.sso.groupConnectionScimIdentityUpsert,
|
|
316
|
-
* {
|
|
317
|
-
* connectionId,
|
|
318
|
-
* groupId: orgGroupId,
|
|
319
|
-
* resourceType: "user",
|
|
320
|
-
* externalId: "okta-user-abc123",
|
|
321
|
-
* userId,
|
|
322
|
-
* active: true,
|
|
323
|
-
* lastProvisionedAt: Date.now(),
|
|
324
|
-
* raw: { schemas: ["urn:ietf:params:scim:schemas:core:2.0:User"], userName: "jane@acme.com" },
|
|
325
|
-
* },
|
|
326
|
-
* );
|
|
327
|
-
* ```
|
|
328
159
|
*/
|
|
329
160
|
const groupConnectionScimIdentityUpsert = mutation({
|
|
330
161
|
args: {
|
|
@@ -357,13 +188,6 @@ const groupConnectionScimIdentityUpsert = mutation({
|
|
|
357
188
|
* @param args.identityId - The document ID of the SCIM identity to delete.
|
|
358
189
|
* @returns `null` on success.
|
|
359
190
|
*
|
|
360
|
-
* @example
|
|
361
|
-
* ```ts
|
|
362
|
-
* await ctx.runMutation(
|
|
363
|
-
* components.auth.group.sso.groupConnectionScimIdentityDelete,
|
|
364
|
-
* { identityId: scimIdentity._id },
|
|
365
|
-
* );
|
|
366
|
-
* ```
|
|
367
191
|
*/
|
|
368
192
|
const groupConnectionScimIdentityDelete = mutation({
|
|
369
193
|
args: { identityId: v.id("GroupConnectionScimIdentity") },
|
|
@@ -375,5 +199,5 @@ const groupConnectionScimIdentityDelete = mutation({
|
|
|
375
199
|
});
|
|
376
200
|
|
|
377
201
|
//#endregion
|
|
378
|
-
export {
|
|
202
|
+
export { groupConnectionScimConfigGet, groupConnectionScimConfigUpsert, groupConnectionScimIdentityDelete, groupConnectionScimIdentityGet, groupConnectionScimIdentityListByGroupConnection, groupConnectionScimIdentityUpsert };
|
|
379
203
|
//# sourceMappingURL=scim.js.map
|
|
@@ -18,19 +18,6 @@ import { v } from "convex/values";
|
|
|
18
18
|
* @param args.updatedAt - Epoch timestamp (ms) when the secret was last updated.
|
|
19
19
|
* @returns The ID of the created or updated `GroupConnectionSecret` document.
|
|
20
20
|
*
|
|
21
|
-
* @example
|
|
22
|
-
* ```ts
|
|
23
|
-
* const secretId = await ctx.runMutation(
|
|
24
|
-
* components.auth.connection.groupConnectionSecretUpsert,
|
|
25
|
-
* {
|
|
26
|
-
* connectionId,
|
|
27
|
-
* groupId: orgGroupId,
|
|
28
|
-
* kind: "oidc_client_secret",
|
|
29
|
-
* ciphertext: "encrypted:aes256:...",
|
|
30
|
-
* updatedAt: Date.now(),
|
|
31
|
-
* },
|
|
32
|
-
* );
|
|
33
|
-
* ```
|
|
34
21
|
*/
|
|
35
22
|
const groupConnectionSecretUpsert = mutation({
|
|
36
23
|
args: {
|
|
@@ -68,16 +55,6 @@ const groupConnectionSecretUpsert = mutation({
|
|
|
68
55
|
* @param args.kind - The type of secret to look up (e.g. `"oidc_client_secret"`).
|
|
69
56
|
* @returns The connection secret document, or `null` if not found.
|
|
70
57
|
*
|
|
71
|
-
* @example
|
|
72
|
-
* ```ts
|
|
73
|
-
* const secret = await ctx.runQuery(
|
|
74
|
-
* components.auth.connection.groupConnectionSecretGet,
|
|
75
|
-
* { connectionId, kind: "oidc_client_secret" },
|
|
76
|
-
* );
|
|
77
|
-
* if (secret) {
|
|
78
|
-
* const plaintext = decrypt(secret.ciphertext);
|
|
79
|
-
* }
|
|
80
|
-
* ```
|
|
81
58
|
*/
|
|
82
59
|
const groupConnectionSecretGet = query({
|
|
83
60
|
args: {
|
|
@@ -99,13 +76,6 @@ const groupConnectionSecretGet = query({
|
|
|
99
76
|
* @param args.kind - The type of secret to remove (e.g. `"oidc_client_secret"`).
|
|
100
77
|
* @returns `null` on success.
|
|
101
78
|
*
|
|
102
|
-
* @example
|
|
103
|
-
* ```ts
|
|
104
|
-
* await ctx.runMutation(
|
|
105
|
-
* components.auth.connection.groupConnectionSecretDelete,
|
|
106
|
-
* { connectionId, kind: "oidc_client_secret" },
|
|
107
|
-
* );
|
|
108
|
-
* ```
|
|
109
79
|
*/
|
|
110
80
|
const groupConnectionSecretDelete = mutation({
|
|
111
81
|
args: {
|
|
@@ -21,19 +21,6 @@ import { v } from "convex/values";
|
|
|
21
21
|
* @param args.extend - An optional arbitrary extension object for custom endpoint metadata.
|
|
22
22
|
* @returns The ID of the newly created `GroupWebhookEndpoint` document.
|
|
23
23
|
*
|
|
24
|
-
* @example
|
|
25
|
-
* ```ts
|
|
26
|
-
* const endpointId = await ctx.runMutation(
|
|
27
|
-
* components.auth.group.sso.groupWebhookEndpointCreate,
|
|
28
|
-
* {
|
|
29
|
-
* connectionId,
|
|
30
|
-
* groupId: orgGroupId,
|
|
31
|
-
* url: "https://acme.com/webhooks/auth",
|
|
32
|
-
* secretHash: "sha256:whsec_...",
|
|
33
|
-
* subscriptions: ["user.login", "user.created", "scim.provision"],
|
|
34
|
-
* },
|
|
35
|
-
* );
|
|
36
|
-
* ```
|
|
37
24
|
*/
|
|
38
25
|
const groupWebhookEndpointCreate = mutation({
|
|
39
26
|
args: {
|
|
@@ -64,16 +51,6 @@ const groupWebhookEndpointCreate = mutation({
|
|
|
64
51
|
* @param args.connectionId - The ID of the group connection whose webhook endpoints to list.
|
|
65
52
|
* @returns An array of webhook endpoint documents.
|
|
66
53
|
*
|
|
67
|
-
* @example
|
|
68
|
-
* ```ts
|
|
69
|
-
* const endpoints = await ctx.runQuery(
|
|
70
|
-
* components.auth.group.sso.groupWebhookEndpointList,
|
|
71
|
-
* { connectionId },
|
|
72
|
-
* );
|
|
73
|
-
* for (const ep of endpoints) {
|
|
74
|
-
* console.log(ep.url, ep.status, ep.subscriptions);
|
|
75
|
-
* }
|
|
76
|
-
* ```
|
|
77
54
|
*/
|
|
78
55
|
const groupWebhookEndpointList = query({
|
|
79
56
|
args: { connectionId: v.id("GroupConnection") },
|
|
@@ -91,16 +68,6 @@ const groupWebhookEndpointList = query({
|
|
|
91
68
|
* @param args.endpointId - The document ID of the webhook endpoint to retrieve.
|
|
92
69
|
* @returns The webhook endpoint document, or `null` if not found.
|
|
93
70
|
*
|
|
94
|
-
* @example
|
|
95
|
-
* ```ts
|
|
96
|
-
* const endpoint = await ctx.runQuery(
|
|
97
|
-
* components.auth.group.sso.groupWebhookEndpointGet,
|
|
98
|
-
* { endpointId },
|
|
99
|
-
* );
|
|
100
|
-
* if (endpoint) {
|
|
101
|
-
* console.log(endpoint.url, endpoint.failureCount);
|
|
102
|
-
* }
|
|
103
|
-
* ```
|
|
104
71
|
*/
|
|
105
72
|
const groupWebhookEndpointGet = query({
|
|
106
73
|
args: { endpointId: v.id("GroupWebhookEndpoint") },
|
|
@@ -121,19 +88,6 @@ const groupWebhookEndpointGet = query({
|
|
|
121
88
|
* @param args.data - An object containing the fields to update (e.g. `{ url, status, subscriptions }`).
|
|
122
89
|
* @returns `null` on success.
|
|
123
90
|
*
|
|
124
|
-
* @example
|
|
125
|
-
* ```ts
|
|
126
|
-
* await ctx.runMutation(
|
|
127
|
-
* components.auth.group.sso.groupWebhookEndpointUpdate,
|
|
128
|
-
* {
|
|
129
|
-
* endpointId,
|
|
130
|
-
* data: {
|
|
131
|
-
* status: "paused",
|
|
132
|
-
* subscriptions: ["user.login"],
|
|
133
|
-
* },
|
|
134
|
-
* },
|
|
135
|
-
* );
|
|
136
|
-
* ```
|
|
137
91
|
*/
|
|
138
92
|
const groupWebhookEndpointUpdate = mutation({
|
|
139
93
|
args: {
|
|
@@ -147,9 +101,9 @@ const groupWebhookEndpointUpdate = mutation({
|
|
|
147
101
|
}
|
|
148
102
|
});
|
|
149
103
|
/**
|
|
150
|
-
*
|
|
104
|
+
* Create a webhook delivery for a specific endpoint.
|
|
151
105
|
*
|
|
152
|
-
*
|
|
106
|
+
* Inserts a new `GroupWebhookDelivery` document with an initial status
|
|
153
107
|
* of `"pending"` and an attempt count of `0`. The delivery will be picked up
|
|
154
108
|
* by the delivery worker once `nextAttemptAt` is reached.
|
|
155
109
|
*
|
|
@@ -161,22 +115,8 @@ const groupWebhookEndpointUpdate = mutation({
|
|
|
161
115
|
* @param args.nextAttemptAt - Epoch timestamp (ms) when the delivery should first be attempted.
|
|
162
116
|
* @returns The ID of the newly created `GroupWebhookDelivery` document.
|
|
163
117
|
*
|
|
164
|
-
* @example
|
|
165
|
-
* ```ts
|
|
166
|
-
* const deliveryId = await ctx.runMutation(
|
|
167
|
-
* components.auth.group.sso.groupWebhookDeliveryEnqueue,
|
|
168
|
-
* {
|
|
169
|
-
* connectionId,
|
|
170
|
-
* endpointId,
|
|
171
|
-
* auditEventId,
|
|
172
|
-
* eventType: "user.created",
|
|
173
|
-
* payload: { userId, email: "jane@acme.com" },
|
|
174
|
-
* nextAttemptAt: Date.now(),
|
|
175
|
-
* },
|
|
176
|
-
* );
|
|
177
|
-
* ```
|
|
178
118
|
*/
|
|
179
|
-
const
|
|
119
|
+
const groupWebhookDeliveryCreate = mutation({
|
|
180
120
|
args: {
|
|
181
121
|
connectionId: v.id("GroupConnection"),
|
|
182
122
|
endpointId: v.id("GroupWebhookEndpoint"),
|
|
@@ -195,66 +135,34 @@ const groupWebhookDeliveryEnqueue = mutation({
|
|
|
195
135
|
}
|
|
196
136
|
});
|
|
197
137
|
/**
|
|
198
|
-
* List
|
|
138
|
+
* List webhook deliveries.
|
|
199
139
|
*
|
|
200
|
-
*
|
|
201
|
-
* `
|
|
202
|
-
*
|
|
140
|
+
* Accepts exactly one selector:
|
|
141
|
+
* - `connectionId` — all deliveries for a connection, most recent first
|
|
142
|
+
* (via `group_connection_id`). Includes every status; useful for an
|
|
143
|
+
* admin delivery-history view.
|
|
144
|
+
* - `now` — pending deliveries due for dispatch: status `"pending"` with
|
|
145
|
+
* `nextAttemptAt <= now` (via `status_next_attempt_at`). Used by the
|
|
146
|
+
* delivery worker to find work.
|
|
203
147
|
*
|
|
204
|
-
* @param
|
|
205
|
-
* @param
|
|
206
|
-
* @
|
|
148
|
+
* @param connectionId - Optional `_id` of the `GroupConnection`.
|
|
149
|
+
* @param now - Optional epoch timestamp (ms) cutoff for `nextAttemptAt`.
|
|
150
|
+
* @param limit - Max deliveries to return (clamped 1–100, default 50).
|
|
151
|
+
* @returns An array of webhook delivery documents.
|
|
207
152
|
*
|
|
208
|
-
* @example
|
|
209
|
-
* ```ts
|
|
210
|
-
* const ready = await ctx.runQuery(
|
|
211
|
-
* components.auth.group.sso.groupWebhookDeliveryListReady,
|
|
212
|
-
* { now: Date.now(), limit: 10 },
|
|
213
|
-
* );
|
|
214
|
-
* for (const delivery of ready) {
|
|
215
|
-
* await dispatchWebhook(delivery);
|
|
216
|
-
* }
|
|
217
|
-
* ```
|
|
218
|
-
*/
|
|
219
|
-
const groupWebhookDeliveryListReady = query({
|
|
220
|
-
args: {
|
|
221
|
-
now: v.number(),
|
|
222
|
-
limit: v.optional(v.number())
|
|
223
|
-
},
|
|
224
|
-
returns: v.array(vGroupWebhookDeliveryDoc),
|
|
225
|
-
handler: async (ctx, { now, limit }) => {
|
|
226
|
-
return await ctx.db.query("GroupWebhookDelivery").withIndex("status_next_attempt_at", (idx) => idx.eq("status", "pending").lte("nextAttemptAt", now)).take(Math.min(Math.max(limit ?? 50, 1), 100));
|
|
227
|
-
}
|
|
228
|
-
});
|
|
229
|
-
/**
|
|
230
|
-
* List webhook deliveries for a specific group connection, ordered by most recent first.
|
|
231
|
-
*
|
|
232
|
-
* Returns deliveries in reverse chronological order, useful for displaying
|
|
233
|
-
* delivery history in an admin dashboard. Includes deliveries of all statuses.
|
|
234
|
-
*
|
|
235
|
-
* @param args.connectionId - The ID of the group connection whose deliveries to list.
|
|
236
|
-
* @param args.limit - Maximum number of deliveries to return (clamped between 1 and 100, defaults to 50).
|
|
237
|
-
* @returns An array of webhook delivery documents, most recent first.
|
|
238
|
-
*
|
|
239
|
-
* @example
|
|
240
|
-
* ```ts
|
|
241
|
-
* const deliveries = await ctx.runQuery(
|
|
242
|
-
* components.auth.group.sso.groupWebhookDeliveryList,
|
|
243
|
-
* { connectionId, limit: 25 },
|
|
244
|
-
* );
|
|
245
|
-
* for (const d of deliveries) {
|
|
246
|
-
* console.log(d.eventType, d.status, d.attemptCount);
|
|
247
|
-
* }
|
|
248
|
-
* ```
|
|
249
153
|
*/
|
|
250
154
|
const groupWebhookDeliveryList = query({
|
|
251
155
|
args: {
|
|
252
|
-
connectionId: v.id("GroupConnection"),
|
|
156
|
+
connectionId: v.optional(v.id("GroupConnection")),
|
|
157
|
+
now: v.optional(v.number()),
|
|
253
158
|
limit: v.optional(v.number())
|
|
254
159
|
},
|
|
255
160
|
returns: v.array(vGroupWebhookDeliveryDoc),
|
|
256
|
-
handler: async (ctx,
|
|
257
|
-
|
|
161
|
+
handler: async (ctx, args) => {
|
|
162
|
+
const take = Math.min(Math.max(args.limit ?? 50, 1), 100);
|
|
163
|
+
if (args.now !== void 0) return await ctx.db.query("GroupWebhookDelivery").withIndex("status_next_attempt_at", (idx) => idx.eq("status", "pending").lte("nextAttemptAt", args.now)).take(take);
|
|
164
|
+
if (args.connectionId === void 0) return [];
|
|
165
|
+
return await ctx.db.query("GroupWebhookDelivery").withIndex("group_connection_id", (idx) => idx.eq("connectionId", args.connectionId)).order("desc").take(take);
|
|
258
166
|
}
|
|
259
167
|
});
|
|
260
168
|
/**
|
|
@@ -269,19 +177,6 @@ const groupWebhookDeliveryList = query({
|
|
|
269
177
|
* @param args.data - An object containing the fields to update (e.g. `{ status, attemptCount, nextAttemptAt }`).
|
|
270
178
|
* @returns `null` on success.
|
|
271
179
|
*
|
|
272
|
-
* @example
|
|
273
|
-
* ```ts
|
|
274
|
-
* await ctx.runMutation(
|
|
275
|
-
* components.auth.group.sso.groupWebhookDeliveryPatch,
|
|
276
|
-
* {
|
|
277
|
-
* deliveryId,
|
|
278
|
-
* data: {
|
|
279
|
-
* status: "delivered",
|
|
280
|
-
* attemptCount: 1,
|
|
281
|
-
* },
|
|
282
|
-
* },
|
|
283
|
-
* );
|
|
284
|
-
* ```
|
|
285
180
|
*/
|
|
286
181
|
const groupWebhookDeliveryPatch = mutation({
|
|
287
182
|
args: {
|
|
@@ -296,5 +191,5 @@ const groupWebhookDeliveryPatch = mutation({
|
|
|
296
191
|
});
|
|
297
192
|
|
|
298
193
|
//#endregion
|
|
299
|
-
export {
|
|
194
|
+
export { groupWebhookDeliveryCreate, groupWebhookDeliveryList, groupWebhookDeliveryPatch, groupWebhookEndpointCreate, groupWebhookEndpointGet, groupWebhookEndpointList, groupWebhookEndpointUpdate };
|
|
300
195
|
//# sourceMappingURL=webhooks.js.map
|