@rebasepro/server-mongo 0.22.0 → 0.24.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.
- package/dist/auth/services.d.ts +11 -23
- package/dist/db/MongoConditionBuilder.d.ts +28 -3
- package/dist/db/MongoDataService.d.ts +46 -3
- package/dist/{ensure-collections-Bl12bSwO.js → ensure-collections-DHTVMlxf.js} +1 -57
- package/dist/ensure-collections-DHTVMlxf.js.map +1 -0
- package/dist/index.es.js +268 -121
- package/dist/index.es.js.map +1 -1
- package/dist/services/MongoDriver.d.ts +16 -2
- package/dist/{websocket-C3iT6srl.js → websocket-CXSVz4oq.js} +29 -23
- package/dist/websocket-CXSVz4oq.js.map +1 -0
- package/package.json +5 -5
- package/dist/ensure-collections-Bl12bSwO.js.map +0 -1
- package/dist/websocket-C3iT6srl.js.map +0 -1
package/dist/auth/services.d.ts
CHANGED
|
@@ -4,15 +4,13 @@ export interface MongoDoc {
|
|
|
4
4
|
_id?: string;
|
|
5
5
|
[key: string]: any;
|
|
6
6
|
}
|
|
7
|
-
import { UserRepository,
|
|
8
|
-
export type Role = RoleData;
|
|
7
|
+
import { UserRepository, TokenRepository, AuthRepository, UserData, CreateUserData, RefreshTokenInfo, RefreshTokenSession, PasswordResetTokenInfo, MagicLinkTokenInfo, UserIdentityData, ListUsersOptions, PaginatedUsersResult, MfaFactor, MfaChallengeInfo } from "@rebasepro/server";
|
|
9
8
|
export declare class MongoUserService implements UserRepository {
|
|
10
9
|
private db;
|
|
11
10
|
constructor(db: Db);
|
|
12
11
|
private get collection();
|
|
13
12
|
private get identitiesCollection();
|
|
14
13
|
private get userRolesCollection();
|
|
15
|
-
private get rolesCollection();
|
|
16
14
|
createUser(data: CreateUserData): Promise<UserData>;
|
|
17
15
|
getUserById(id: string): Promise<UserData | null>;
|
|
18
16
|
getUserByEmail(email: string): Promise<UserData | null>;
|
|
@@ -20,6 +18,14 @@ export declare class MongoUserService implements UserRepository {
|
|
|
20
18
|
getUserIdentities(uid: string): Promise<UserIdentityData[]>;
|
|
21
19
|
linkUserIdentity(uid: string, provider: string, providerId: string, profileData?: Record<string, unknown>): Promise<void>;
|
|
22
20
|
updateUser(id: string, data: Partial<Omit<CreateUserData, "id">>): Promise<UserData | null>;
|
|
21
|
+
/**
|
|
22
|
+
* Everything keyed by the user goes with them. Postgres does this by
|
|
23
|
+
* foreign-key cascade; Mongo has none, so it is spelled out — and the
|
|
24
|
+
* refresh tokens are the part that matters: left behind, a deleted user's
|
|
25
|
+
* session kept minting access tokens for a uid that no longer exists.
|
|
26
|
+
* Sessions first, so a failure part-way leaves an account that cannot sign
|
|
27
|
+
* in rather than a session with no account.
|
|
28
|
+
*/
|
|
23
29
|
deleteUser(id: string): Promise<void>;
|
|
24
30
|
listUsers(): Promise<UserData[]>;
|
|
25
31
|
listUsersPaginated(options?: ListUsersOptions): Promise<PaginatedUsersResult>;
|
|
@@ -27,25 +33,14 @@ export declare class MongoUserService implements UserRepository {
|
|
|
27
33
|
setEmailVerified(id: string, verified: boolean): Promise<void>;
|
|
28
34
|
setVerificationToken(id: string, token: string | null): Promise<void>;
|
|
29
35
|
getUserByVerificationToken(token: string): Promise<UserData | null>;
|
|
30
|
-
getUserRoles(uid: string): Promise<RoleData[]>;
|
|
31
36
|
getUserRoleIds(uid: string): Promise<string[]>;
|
|
32
37
|
setUserRoles(uid: string, roleIds: string[]): Promise<void>;
|
|
33
38
|
assignDefaultRole(uid: string, roleId: string): Promise<void>;
|
|
34
39
|
getUserWithRoles(uid: string): Promise<{
|
|
35
40
|
user: UserData;
|
|
36
|
-
roles:
|
|
41
|
+
roles: string[];
|
|
37
42
|
} | null>;
|
|
38
43
|
}
|
|
39
|
-
export declare class MongoRoleService implements RoleRepository {
|
|
40
|
-
private db;
|
|
41
|
-
constructor(db: Db);
|
|
42
|
-
private get collection();
|
|
43
|
-
getRoleById(id: string): Promise<RoleData | null>;
|
|
44
|
-
listRoles(): Promise<RoleData[]>;
|
|
45
|
-
createRole(data: CreateRoleData): Promise<RoleData>;
|
|
46
|
-
updateRole(id: string, data: Partial<Omit<RoleData, "id">>): Promise<RoleData | null>;
|
|
47
|
-
deleteRole(id: string): Promise<void>;
|
|
48
|
-
}
|
|
49
44
|
export declare class MongoRefreshTokenService {
|
|
50
45
|
private db;
|
|
51
46
|
constructor(db: Db);
|
|
@@ -105,7 +100,6 @@ export declare class MongoTokenRepository implements TokenRepository {
|
|
|
105
100
|
export declare class MongoAuthRepository implements AuthRepository {
|
|
106
101
|
private db;
|
|
107
102
|
private userService;
|
|
108
|
-
private roleService;
|
|
109
103
|
private tokenRepository;
|
|
110
104
|
constructor(db: Db);
|
|
111
105
|
createUser(data: CreateUserData): Promise<UserData>;
|
|
@@ -122,19 +116,13 @@ export declare class MongoAuthRepository implements AuthRepository {
|
|
|
122
116
|
setEmailVerified(id: string, verified: boolean): Promise<void>;
|
|
123
117
|
setVerificationToken(id: string, token: string | null): Promise<void>;
|
|
124
118
|
getUserByVerificationToken(token: string): Promise<UserData | null>;
|
|
125
|
-
getUserRoles(uid: string): Promise<RoleData[]>;
|
|
126
119
|
getUserRoleIds(uid: string): Promise<string[]>;
|
|
127
120
|
setUserRoles(uid: string, roleIds: string[]): Promise<void>;
|
|
128
121
|
assignDefaultRole(uid: string, roleId: string): Promise<void>;
|
|
129
122
|
getUserWithRoles(uid: string): Promise<{
|
|
130
123
|
user: UserData;
|
|
131
|
-
roles:
|
|
124
|
+
roles: string[];
|
|
132
125
|
} | null>;
|
|
133
|
-
getRoleById(id: string): Promise<RoleData | null>;
|
|
134
|
-
listRoles(): Promise<RoleData[]>;
|
|
135
|
-
createRole(data: CreateRoleData): Promise<RoleData>;
|
|
136
|
-
updateRole(id: string, data: Partial<Omit<RoleData, "id">>): Promise<RoleData | null>;
|
|
137
|
-
deleteRole(id: string): Promise<void>;
|
|
138
126
|
createRefreshToken(uid: string, tokenHash: string, expiresAt: Date, userAgent?: string, ipAddress?: string, session?: RefreshTokenSession): Promise<void>;
|
|
139
127
|
markRefreshTokenRotated(tokenHash: string): Promise<void>;
|
|
140
128
|
revokeRefreshTokenSession(sessionId: string): Promise<void>;
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* Translates Rebase filter conditions to MongoDB query operators.
|
|
5
5
|
*/
|
|
6
6
|
import { CollectionConfig, FilterValues, LogicalCondition, OrderByTuple } from "@rebasepro/types";
|
|
7
|
+
import { type FieldViewer } from "@rebasepro/common";
|
|
7
8
|
import { Filter, Document } from "mongodb";
|
|
8
9
|
/**
|
|
9
10
|
* MongoDB Condition Builder
|
|
@@ -29,16 +30,32 @@ export declare class MongoConditionBuilder {
|
|
|
29
30
|
*
|
|
30
31
|
* Always returns a condition or throws: there is no operator this can be
|
|
31
32
|
* given that legitimately means "no condition".
|
|
33
|
+
*
|
|
34
|
+
* `negated` asks for the documents where the condition is *false* — not
|
|
35
|
+
* merely not true. The two differ by the documents where it is unknown,
|
|
36
|
+
* which in SQL is a comparison against NULL: `NOT (status = 'draft')` does
|
|
37
|
+
* not return a row whose status is NULL, and the Postgres driver is the
|
|
38
|
+
* reference every caller of this API writes against. So a comparison is
|
|
39
|
+
* false only where the field holds a value and the comparison fails on it.
|
|
40
|
+
* The null tests are never unknown, and negate to each other.
|
|
32
41
|
*/
|
|
33
42
|
private static buildCondition;
|
|
34
43
|
/**
|
|
35
|
-
* Translate an `or(...)` / `and(...)` group, nesting included.
|
|
44
|
+
* Translate an `or(...)` / `and(...)` / `not(...)` group, nesting included.
|
|
45
|
+
*
|
|
46
|
+
* `not` negates the conjunction of its conditions — the rule stated on
|
|
47
|
+
* `LogicalCondition`. It used to fall through to the `and` branch, so
|
|
48
|
+
* `not(status = 'draft')` returned exactly the drafts. It is compiled by
|
|
49
|
+
* pushing the negation down to the leaves (De Morgan), each of which knows
|
|
50
|
+
* which documents make it false rather than merely not true — see
|
|
51
|
+
* {@link buildCondition}. A `$nor` around the group would be shorter and
|
|
52
|
+
* wrong: it also matches every document where the condition is unknown.
|
|
36
53
|
*
|
|
37
54
|
* Returns `undefined` for a group with nothing in it. `$or: []` is an error
|
|
38
55
|
* in Mongo and `$and: []` matches every document, so neither is a
|
|
39
56
|
* defensible reading of "no conditions".
|
|
40
57
|
*/
|
|
41
|
-
static buildLogicalConditions(logical: LogicalCondition | undefined): Filter<Document> | undefined;
|
|
58
|
+
static buildLogicalConditions(logical: LogicalCondition | undefined, negated?: boolean): Filter<Document> | undefined;
|
|
42
59
|
/**
|
|
43
60
|
* Build search conditions for text search.
|
|
44
61
|
*
|
|
@@ -50,10 +67,16 @@ export declare class MongoConditionBuilder {
|
|
|
50
67
|
*
|
|
51
68
|
* @param searchString - Text to search for
|
|
52
69
|
* @param properties - The collection's properties, searched for string fields
|
|
70
|
+
* @param viewer - Who the search is for. A field they cannot read is not
|
|
71
|
+
* one they may search: the strip keeps its value out of the response, and
|
|
72
|
+
* without this the value is still recoverable a substring at a time by
|
|
73
|
+
* watching which searches return the row. Absent is the trusted server
|
|
74
|
+
* plane, which still does not search an `excludeFromApi` field — the same
|
|
75
|
+
* answer the Postgres builder gives.
|
|
53
76
|
* @returns At most one MongoDB filter — callers OR what they get back, which
|
|
54
77
|
* is right across fields and wrong across terms, so the AND is built here
|
|
55
78
|
*/
|
|
56
|
-
static buildSearchConditions(searchString: string, properties: CollectionConfig["properties"]): Filter<Document>[];
|
|
79
|
+
static buildSearchConditions(searchString: string, properties: CollectionConfig["properties"], viewer?: FieldViewer): Filter<Document>[];
|
|
57
80
|
/**
|
|
58
81
|
* Combine multiple conditions with AND operator
|
|
59
82
|
*
|
|
@@ -85,6 +108,8 @@ export declare class MongoConditionBuilder {
|
|
|
85
108
|
logical?: LogicalCondition;
|
|
86
109
|
searchString?: string;
|
|
87
110
|
properties?: CollectionConfig["properties"];
|
|
111
|
+
/** Who the query is for — see {@link buildSearchConditions}. */
|
|
112
|
+
viewer?: FieldViewer;
|
|
88
113
|
}): Filter<Document>;
|
|
89
114
|
/**
|
|
90
115
|
* The primary key's name in a stored document.
|
|
@@ -96,8 +96,39 @@ export declare class MongoDataService implements DataRepository {
|
|
|
96
96
|
* partial row everywhere it went: the REST response, `afterSave`, the
|
|
97
97
|
* history entry a revert restores from, and the row pushed to realtime
|
|
98
98
|
* subscribers. Postgres returns the whole row here (`RETURNING *`).
|
|
99
|
+
*
|
|
100
|
+
* `mode` is which write the caller means when it names an `id`:
|
|
101
|
+
*
|
|
102
|
+
* - `"create"` inserts under that id, and a taken id is a 409. The driver
|
|
103
|
+
* authorizes a create as an insert, against the values sent — so a
|
|
104
|
+
* create that could land on an existing row is an update no update rule
|
|
105
|
+
* ever saw. It was one: an upsert with `$set`, which let a caller name
|
|
106
|
+
* another user's id with `status: "new"` and rewrite their row.
|
|
107
|
+
* - `"update"` updates that row and nothing else, and a missing one is a
|
|
108
|
+
* 404 — never a row conjured under an id nobody created.
|
|
109
|
+
* - absent, the repository's own "create or update": an upsert. Only the
|
|
110
|
+
* repository's direct callers reach it; the driver always says which.
|
|
111
|
+
*
|
|
112
|
+
* `values` may carry field operations (`{ views: { $inc: 1 } }`), which
|
|
113
|
+
* change the stored value in the same write rather than replace it — see
|
|
114
|
+
* {@link compileFieldOp}. They were written into the document as literal
|
|
115
|
+
* objects, so a counter became `{ "$inc": 1 }` behind a 200. Only an
|
|
116
|
+
* update can carry one: there is no stored value for an insert to act on,
|
|
117
|
+
* and an upsert may be an insert.
|
|
118
|
+
*/
|
|
119
|
+
save<M extends Record<string, any>>(collectionPath: string, values: Partial<M>, id?: string | number, _databaseId?: string, mode?: "create" | "update"): Promise<Record<string, unknown>>;
|
|
120
|
+
/**
|
|
121
|
+
* The aggregation expression one field operation compiles to, in an update
|
|
122
|
+
* pipeline's `$set`.
|
|
123
|
+
*
|
|
124
|
+
* The same meaning the Postgres compiler gives each one, NULL-safety
|
|
125
|
+
* included: an unset or null counter increments from zero and an absent
|
|
126
|
+
* array is pushed onto as an empty one, rather than the write failing on
|
|
127
|
+
* the first use of a field. `$push` and `$pull` take a value or a list of
|
|
128
|
+
* values, `$pull` removes every occurrence, and `$merge` is shallow — a
|
|
129
|
+
* nested object replaces, it is not merged into.
|
|
99
130
|
*/
|
|
100
|
-
|
|
131
|
+
private compileFieldOp;
|
|
101
132
|
/**
|
|
102
133
|
* Read the document back after a write, falling back to the caller's own
|
|
103
134
|
* values if it has already been removed by a concurrent delete.
|
|
@@ -115,9 +146,21 @@ export declare class MongoDataService implements DataRepository {
|
|
|
115
146
|
*/
|
|
116
147
|
delete(collectionPath: string, id: string | number, _databaseId?: string): Promise<void>;
|
|
117
148
|
/**
|
|
118
|
-
* Check if a field value is unique in a collection
|
|
149
|
+
* Check if a field value is unique in a collection.
|
|
150
|
+
*
|
|
151
|
+
* An equality test on one field, and nothing else a query can express. The
|
|
152
|
+
* name and the value arrive from a socket frame, and this used to be
|
|
153
|
+
* `countDocuments({ [name]: value })`: a value of `{ $regex: "^123" }`
|
|
154
|
+
* answered, one prefix at a time, what a field of a row the caller cannot
|
|
155
|
+
* see begins with, and a name of `$expr` evaluated an aggregation
|
|
156
|
+
* expression. So an operator name is refused, the value must be a scalar,
|
|
157
|
+
* and it is compared with `$eq` — which reads an object as a literal even
|
|
158
|
+
* if one got this far.
|
|
159
|
+
*
|
|
160
|
+
* An absent value is unique, as it is on Postgres: an empty optional field
|
|
161
|
+
* is not "taken" by every row that also left it empty.
|
|
119
162
|
*/
|
|
120
|
-
checkUniqueField(collectionPath: string, fieldName: string, value:
|
|
163
|
+
checkUniqueField(collectionPath: string, fieldName: string, value: unknown, excludeEntityId?: string, _databaseId?: string): Promise<boolean>;
|
|
121
164
|
/**
|
|
122
165
|
* Generate a new row ID
|
|
123
166
|
*/
|
|
@@ -1,50 +1,6 @@
|
|
|
1
1
|
import { logger } from "@rebasepro/server";
|
|
2
2
|
//#region src/auth/ensure-collections.ts
|
|
3
3
|
/**
|
|
4
|
-
* Default roles to seed on first run
|
|
5
|
-
*/
|
|
6
|
-
var DEFAULT_ROLES = [
|
|
7
|
-
{
|
|
8
|
-
_id: "admin",
|
|
9
|
-
id: "admin",
|
|
10
|
-
name: "Admin",
|
|
11
|
-
isAdmin: true,
|
|
12
|
-
defaultPermissions: {
|
|
13
|
-
read: true,
|
|
14
|
-
create: true,
|
|
15
|
-
edit: true,
|
|
16
|
-
delete: true
|
|
17
|
-
},
|
|
18
|
-
createdAt: /* @__PURE__ */ new Date()
|
|
19
|
-
},
|
|
20
|
-
{
|
|
21
|
-
_id: "editor",
|
|
22
|
-
id: "editor",
|
|
23
|
-
name: "Editor",
|
|
24
|
-
isAdmin: false,
|
|
25
|
-
defaultPermissions: {
|
|
26
|
-
read: true,
|
|
27
|
-
create: true,
|
|
28
|
-
edit: true,
|
|
29
|
-
delete: true
|
|
30
|
-
},
|
|
31
|
-
createdAt: /* @__PURE__ */ new Date()
|
|
32
|
-
},
|
|
33
|
-
{
|
|
34
|
-
_id: "viewer",
|
|
35
|
-
id: "viewer",
|
|
36
|
-
name: "Viewer",
|
|
37
|
-
isAdmin: false,
|
|
38
|
-
defaultPermissions: {
|
|
39
|
-
read: true,
|
|
40
|
-
create: false,
|
|
41
|
-
edit: false,
|
|
42
|
-
delete: false
|
|
43
|
-
},
|
|
44
|
-
createdAt: /* @__PURE__ */ new Date()
|
|
45
|
-
}
|
|
46
|
-
];
|
|
47
|
-
/**
|
|
48
4
|
* Indexes created by releases up to 0.13.0, on snake_case field names the auth
|
|
49
5
|
* services never wrote.
|
|
50
6
|
*
|
|
@@ -96,7 +52,6 @@ async function ensureAuthCollectionsExist(db) {
|
|
|
96
52
|
const resetTokens = db.collection("rebase_password_reset_tokens");
|
|
97
53
|
await resetTokens.createIndex({ tokenHash: 1 }, { unique: true });
|
|
98
54
|
await resetTokens.createIndex({ uid: 1 });
|
|
99
|
-
await seedDefaultRoles(db);
|
|
100
55
|
logger.info("✅ MongoDB Auth collections ready");
|
|
101
56
|
} catch (error) {
|
|
102
57
|
logger.error("❌ Failed to set up MongoDB auth collections", { error });
|
|
@@ -113,18 +68,7 @@ async function dropLegacyIndexes(db) {
|
|
|
113
68
|
} catch {}
|
|
114
69
|
}
|
|
115
70
|
}
|
|
116
|
-
async function seedDefaultRoles(db) {
|
|
117
|
-
const roles = db.collection("rebase_roles");
|
|
118
|
-
const count = await roles.countDocuments();
|
|
119
|
-
if (count > 0) {
|
|
120
|
-
logger.info(`📋 Found ${count} existing roles`);
|
|
121
|
-
return;
|
|
122
|
-
}
|
|
123
|
-
logger.info("🌱 Seeding default roles...");
|
|
124
|
-
for (const role of DEFAULT_ROLES) await roles.updateOne({ id: role.id }, { $setOnInsert: role }, { upsert: true });
|
|
125
|
-
logger.info("✅ Default roles created: admin, editor, viewer");
|
|
126
|
-
}
|
|
127
71
|
//#endregion
|
|
128
72
|
export { ensureAuthCollectionsExist };
|
|
129
73
|
|
|
130
|
-
//# sourceMappingURL=ensure-collections-
|
|
74
|
+
//# sourceMappingURL=ensure-collections-DHTVMlxf.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ensure-collections-DHTVMlxf.js","names":[],"sources":["../src/auth/ensure-collections.ts"],"sourcesContent":["import { Db } from \"mongodb\";\nimport { logger } from \"@rebasepro/server\";\n\n/**\n * Indexes created by releases up to 0.13.0, on snake_case field names the auth\n * services never wrote.\n *\n * MongoDB indexes an absent field as `null`, so a unique index whose every key\n * component is always missing admits exactly **one** document per collection:\n * the second login on the whole deployment failed with `E11000`, as did the\n * second role assignment and the second outstanding password-reset token.\n * Dropping them is therefore part of the fix, not tidying — creating the\n * correct index alongside a broken one leaves the deployment just as broken.\n *\n * `{user_id, user_agent, ip_address}` has a second reason to go: it is the\n * reverted Postgres constraint. `MongoRefreshTokenService.createToken` explains\n * why evicting by that triple signs a second browser out; the unique index\n * expressing the same rule was left behind here.\n */\nconst LEGACY_INDEX_NAMES: Record<string, string[]> = {\n rebase_user_identities: [\"provider_1_provider_id_1\", \"user_id_1\"],\n rebase_user_roles: [\"user_id_1_role_id_1\", \"user_id_1\"],\n rebase_refresh_tokens: [\"token_hash_1\", \"user_id_1_user_agent_1_ip_address_1\", \"user_id_1\"],\n rebase_password_reset_tokens: [\"token_hash_1\", \"user_id_1\"]\n};\n\nexport async function ensureAuthCollectionsExist(db: Db): Promise<void> {\n logger.info(\"🔍 Checking MongoDB auth collections and indexes...\");\n\n try {\n await dropLegacyIndexes(db);\n\n // Every key below is a field `auth/services.ts` actually writes —\n // camelCase, matching the documents. Verified by\n // `test/MongoAuthServices.test.ts`, which now runs this function.\n\n // Users\n const users = db.collection(\"rebase_users\");\n await users.createIndex({ email: 1 }, { unique: true });\n await users.createIndex({ id: 1 });\n\n // User Identities\n const identities = db.collection(\"rebase_user_identities\");\n await identities.createIndex({ provider: 1,\nproviderId: 1 }, { unique: true });\n await identities.createIndex({ uid: 1 });\n\n // User Roles (junction collection)\n const userRoles = db.collection(\"rebase_user_roles\");\n await userRoles.createIndex({ uid: 1,\nroleId: 1 }, { unique: true });\n await userRoles.createIndex({ roleId: 1 });\n\n // Refresh Tokens. No unique index on (uid, userAgent, ipAddress):\n // tokens of one sign-in accumulate under a shared sessionId.\n const refreshTokens = db.collection(\"rebase_refresh_tokens\");\n await refreshTokens.createIndex({ tokenHash: 1 }, { unique: true });\n await refreshTokens.createIndex({ uid: 1 });\n await refreshTokens.createIndex({ sessionId: 1 });\n\n // Password Reset Tokens\n const resetTokens = db.collection(\"rebase_password_reset_tokens\");\n await resetTokens.createIndex({ tokenHash: 1 }, { unique: true });\n await resetTokens.createIndex({ uid: 1 });\n\n logger.info(\"✅ MongoDB Auth collections ready\");\n } catch (error) {\n // Not swallowed. Every index here is load-bearing for auth — a boot\n // that logs this and carries on is a deployment whose second login\n // fails, with a green boot log to say nothing is wrong.\n logger.error(\"❌ Failed to set up MongoDB auth collections\", { error: error });\n throw error;\n }\n}\n\n/** Drop the indexes of {@link LEGACY_INDEX_NAMES} that this database still has. */\nasync function dropLegacyIndexes(db: Db): Promise<void> {\n for (const [collectionName, indexNames] of Object.entries(LEGACY_INDEX_NAMES)) {\n const collection = db.collection(collectionName);\n for (const indexName of indexNames) {\n try {\n await collection.dropIndex(indexName);\n logger.info(`🧹 Dropped stale auth index ${collectionName}.${indexName}`);\n } catch {\n // NamespaceNotFound / IndexNotFound — nothing to drop here.\n }\n }\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAmBA,IAAM,qBAA+C;CACjD,wBAAwB,CAAC,4BAA4B,WAAW;CAChE,mBAAmB,CAAC,uBAAuB,WAAW;CACtD,uBAAuB;EAAC;EAAgB;EAAuC;CAAW;CAC1F,8BAA8B,CAAC,gBAAgB,WAAW;AAC9D;AAEA,eAAsB,2BAA2B,IAAuB;CACpE,OAAO,KAAK,qDAAqD;CAEjE,IAAI;EACA,MAAM,kBAAkB,EAAE;EAO1B,MAAM,QAAQ,GAAG,WAAW,cAAc;EAC1C,MAAM,MAAM,YAAY,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,KAAK,CAAC;EACtD,MAAM,MAAM,YAAY,EAAE,IAAI,EAAE,CAAC;EAGjC,MAAM,aAAa,GAAG,WAAW,wBAAwB;EACzD,MAAM,WAAW,YAAY;GAAE,UAAU;GACjD,YAAY;EAAE,GAAG,EAAE,QAAQ,KAAK,CAAC;EACzB,MAAM,WAAW,YAAY,EAAE,KAAK,EAAE,CAAC;EAGvC,MAAM,YAAY,GAAG,WAAW,mBAAmB;EACnD,MAAM,UAAU,YAAY;GAAE,KAAK;GAC3C,QAAQ;EAAE,GAAG,EAAE,QAAQ,KAAK,CAAC;EACrB,MAAM,UAAU,YAAY,EAAE,QAAQ,EAAE,CAAC;EAIzC,MAAM,gBAAgB,GAAG,WAAW,uBAAuB;EAC3D,MAAM,cAAc,YAAY,EAAE,WAAW,EAAE,GAAG,EAAE,QAAQ,KAAK,CAAC;EAClE,MAAM,cAAc,YAAY,EAAE,KAAK,EAAE,CAAC;EAC1C,MAAM,cAAc,YAAY,EAAE,WAAW,EAAE,CAAC;EAGhD,MAAM,cAAc,GAAG,WAAW,8BAA8B;EAChE,MAAM,YAAY,YAAY,EAAE,WAAW,EAAE,GAAG,EAAE,QAAQ,KAAK,CAAC;EAChE,MAAM,YAAY,YAAY,EAAE,KAAK,EAAE,CAAC;EAExC,OAAO,KAAK,kCAAkC;CAClD,SAAS,OAAO;EAIZ,OAAO,MAAM,+CAA+C,EAAS,MAAM,CAAC;EAC5E,MAAM;CACV;AACJ;;AAGA,eAAe,kBAAkB,IAAuB;CACpD,KAAK,MAAM,CAAC,gBAAgB,eAAe,OAAO,QAAQ,kBAAkB,GAAG;EAC3E,MAAM,aAAa,GAAG,WAAW,cAAc;EAC/C,KAAK,MAAM,aAAa,YACpB,IAAI;GACA,MAAM,WAAW,UAAU,SAAS;GACpC,OAAO,KAAK,+BAA+B,eAAe,GAAG,WAAW;EAC5E,QAAQ,CAER;CAER;AACJ"}
|