@classytic/mongokit 3.14.0 → 3.15.0
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.
|
@@ -145,5 +145,44 @@ interface BetterAuthOverlayOptions<TDoc = Record<string, unknown>> {
|
|
|
145
145
|
* would silently drop this call's `additionalFields` / `indexes`).
|
|
146
146
|
*/
|
|
147
147
|
declare function createBetterAuthOverlay<TDoc = Record<string, unknown>>(options: BetterAuthOverlayOptions<TDoc>): Promise<DataAdapter<TDoc>>;
|
|
148
|
+
/**
|
|
149
|
+
* Minimal structural surface for the one write we need. Satisfied by BOTH a
|
|
150
|
+
* native MongoDB `Collection` (`db.collection('session')`) and a Mongoose
|
|
151
|
+
* `Model` — so the host passes whichever it has, and mongokit keeps mongoose +
|
|
152
|
+
* the mongodb driver as peer deps with zero runtime import.
|
|
153
|
+
*/
|
|
154
|
+
interface SessionUpdaterLike {
|
|
155
|
+
updateMany(filter: Record<string, unknown>, update: Record<string, unknown>): Promise<{
|
|
156
|
+
modifiedCount?: number;
|
|
157
|
+
}>;
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Clear a dangling `activeOrganizationId` from Better Auth `session` rows.
|
|
161
|
+
*
|
|
162
|
+
* WHY THIS EXISTS: Better Auth purges its `member` / `invitation` rows when an
|
|
163
|
+
* org is deleted (or a member removed), but it NEVER clears
|
|
164
|
+
* `session.activeOrganizationId`. A session left pointing at an org the user is
|
|
165
|
+
* no longer a member of makes `organization.getActiveMember()` return
|
|
166
|
+
* `MEMBER_NOT_FOUND`, and any frontend that trusts that stale pointer hangs —
|
|
167
|
+
* amplified by `session.cookieCache`, which serves the dead pointer for minutes.
|
|
168
|
+
*
|
|
169
|
+
* This is intentionally a host-invoked helper, NOT part of the arc org-delete
|
|
170
|
+
* cascade: arc is DB-agnostic (it purges through `@classytic/repo-core`
|
|
171
|
+
* adapters and must not reach a raw collection), whereas the `session`
|
|
172
|
+
* collection is a Better-Auth/mongo concern this kit already owns. Hosts wire
|
|
173
|
+
* it into their `organizationHooks`:
|
|
174
|
+
* - `afterDeleteOrganization` → org-wide (omit `userId`)
|
|
175
|
+
* - `afterRemoveMember` → one user (pass `userId`)
|
|
176
|
+
*
|
|
177
|
+
* The mongodb adapter stores `activeOrganizationId` as a STRING, so the org id
|
|
178
|
+
* is matched as-is (no ObjectId construction). `session.userId` is an ObjectId,
|
|
179
|
+
* so for the member-removal path pass `userId` already in the form your driver
|
|
180
|
+
* compares against (a constructed ObjectId) — it's matched verbatim.
|
|
181
|
+
*
|
|
182
|
+
* @returns the number of sessions whose pointer was cleared.
|
|
183
|
+
*/
|
|
184
|
+
declare function clearActiveOrganizationFromSessions(sessions: SessionUpdaterLike, organizationId: string, options?: {
|
|
185
|
+
userId?: unknown;
|
|
186
|
+
}): Promise<number>;
|
|
148
187
|
//#endregion
|
|
149
|
-
export { BetterAuthInstance, BetterAuthOverlayOptions, type BetterAuthPluginKey, MongooseLike, RegisterBetterAuthStubsOptions, createBetterAuthOverlay, registerBetterAuthStubs };
|
|
188
|
+
export { BetterAuthInstance, BetterAuthOverlayOptions, type BetterAuthPluginKey, MongooseLike, RegisterBetterAuthStubsOptions, SessionUpdaterLike, clearActiveOrganizationFromSessions, createBetterAuthOverlay, registerBetterAuthStubs };
|
|
@@ -77,5 +77,35 @@ async function createBetterAuthOverlay(options) {
|
|
|
77
77
|
schemaGenerator
|
|
78
78
|
});
|
|
79
79
|
}
|
|
80
|
+
/**
|
|
81
|
+
* Clear a dangling `activeOrganizationId` from Better Auth `session` rows.
|
|
82
|
+
*
|
|
83
|
+
* WHY THIS EXISTS: Better Auth purges its `member` / `invitation` rows when an
|
|
84
|
+
* org is deleted (or a member removed), but it NEVER clears
|
|
85
|
+
* `session.activeOrganizationId`. A session left pointing at an org the user is
|
|
86
|
+
* no longer a member of makes `organization.getActiveMember()` return
|
|
87
|
+
* `MEMBER_NOT_FOUND`, and any frontend that trusts that stale pointer hangs —
|
|
88
|
+
* amplified by `session.cookieCache`, which serves the dead pointer for minutes.
|
|
89
|
+
*
|
|
90
|
+
* This is intentionally a host-invoked helper, NOT part of the arc org-delete
|
|
91
|
+
* cascade: arc is DB-agnostic (it purges through `@classytic/repo-core`
|
|
92
|
+
* adapters and must not reach a raw collection), whereas the `session`
|
|
93
|
+
* collection is a Better-Auth/mongo concern this kit already owns. Hosts wire
|
|
94
|
+
* it into their `organizationHooks`:
|
|
95
|
+
* - `afterDeleteOrganization` → org-wide (omit `userId`)
|
|
96
|
+
* - `afterRemoveMember` → one user (pass `userId`)
|
|
97
|
+
*
|
|
98
|
+
* The mongodb adapter stores `activeOrganizationId` as a STRING, so the org id
|
|
99
|
+
* is matched as-is (no ObjectId construction). `session.userId` is an ObjectId,
|
|
100
|
+
* so for the member-removal path pass `userId` already in the form your driver
|
|
101
|
+
* compares against (a constructed ObjectId) — it's matched verbatim.
|
|
102
|
+
*
|
|
103
|
+
* @returns the number of sessions whose pointer was cleared.
|
|
104
|
+
*/
|
|
105
|
+
async function clearActiveOrganizationFromSessions(sessions, organizationId, options) {
|
|
106
|
+
const filter = { activeOrganizationId: organizationId };
|
|
107
|
+
if (options?.userId != null) filter.userId = options.userId;
|
|
108
|
+
return (await sessions.updateMany(filter, { $set: { activeOrganizationId: null } })).modifiedCount ?? 0;
|
|
109
|
+
}
|
|
80
110
|
//#endregion
|
|
81
|
-
export { createBetterAuthOverlay, registerBetterAuthStubs };
|
|
111
|
+
export { clearActiveOrganizationFromSessions, createBetterAuthOverlay, registerBetterAuthStubs };
|
package/package.json
CHANGED