najm-auth 6.1.0 → 6.3.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/README.md +34 -1
- package/dist/index.d.ts +58 -15
- package/dist/index.js +52 -11
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -186,12 +186,22 @@ auth({
|
|
|
186
186
|
}
|
|
187
187
|
}
|
|
188
188
|
|
|
189
|
-
// Dependencies
|
|
189
|
+
// Dependencies auth registers when the application has not
|
|
190
190
|
validation?: ValidationPluginConfig
|
|
191
191
|
rateLimit?: RateLimitPluginConfig
|
|
192
|
+
cache?: CachePluginConfig
|
|
193
|
+
email?: EmailPluginConfig
|
|
192
194
|
})
|
|
193
195
|
```
|
|
194
196
|
|
|
197
|
+
Auth depends on the `cache`, `validation`, `rate-limit` and `email` plugins and
|
|
198
|
+
builds each only when the application has not registered one of that name
|
|
199
|
+
before `auth()`. An application that registers its own configures it there and
|
|
200
|
+
passes nothing for it to `auth()`; config passed both ways is ignored on the
|
|
201
|
+
auth side, and the server warns once at startup naming the option. In
|
|
202
|
+
particular, `auth()` needs no `EMAIL_PROVIDER` when the application registers
|
|
203
|
+
`email()` itself.
|
|
204
|
+
|
|
195
205
|
---
|
|
196
206
|
|
|
197
207
|
## Auto-Registered Routes
|
|
@@ -625,6 +635,29 @@ An upgrade alone does not rewrite unsafe queries in consumers. Keep role
|
|
|
625
635
|
and cross-user integration tests in each app. `@Policy` and `@CanRead` check
|
|
626
636
|
permissions, not the ownership of a requested record ID.
|
|
627
637
|
|
|
638
|
+
### Row conditions and owned-id subqueries (6.3+)
|
|
639
|
+
|
|
640
|
+
A rule may also hold `when()` conditions on the owned row. After a join chain
|
|
641
|
+
they narrow it; on their own they are the whole rule, for rows that belong to
|
|
642
|
+
an audience rather than to one linked person. A function receives the user id
|
|
643
|
+
and the rule's role. `ownedIds(token, role, userId)` is the subquery of ids a
|
|
644
|
+
user owns through another token, for use inside a condition.
|
|
645
|
+
|
|
646
|
+
```typescript
|
|
647
|
+
import { own, join, where, when, ownedIds } from 'najm-auth';
|
|
648
|
+
|
|
649
|
+
export const Alert = own(alerts, { adminRoles: ['admin'] })
|
|
650
|
+
// Alerts about my children that are addressed to parents
|
|
651
|
+
.for('parent', join(alerts.studentId, students.id), where(students.parentUserId),
|
|
652
|
+
when(eq(alerts.audience, 'parents')))
|
|
653
|
+
// Alerts naming nobody, for classes I teach
|
|
654
|
+
.for('teacher', when(isNull(alerts.studentId),
|
|
655
|
+
(userId, role) => inArray(alerts.classId, ownedIds(Class, role, userId))));
|
|
656
|
+
```
|
|
657
|
+
|
|
658
|
+
`own(table, { name })` sets the token's resource name when it should differ
|
|
659
|
+
from the table's.
|
|
660
|
+
|
|
628
661
|
### Advanced Ownership: Multi-Role Scoping
|
|
629
662
|
|
|
630
663
|
```typescript
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { Container } from 'najm-core';
|
|
1
|
+
import { NajmPlugin, Container } from 'najm-core';
|
|
3
2
|
import { ValidationPluginConfig } from 'najm-validation';
|
|
4
3
|
import { RateLimitPluginConfig, RateLimitKeyContext, TimeWindow } from 'najm-rate';
|
|
5
4
|
import { CachePluginConfig, CacheService } from 'najm-cache';
|
|
@@ -315,20 +314,23 @@ type AuthPluginConfig = {
|
|
|
315
314
|
* a user has a durable setup requirement.
|
|
316
315
|
*/
|
|
317
316
|
credentialSetup?: CredentialSetupConfig;
|
|
318
|
-
/**
|
|
317
|
+
/** Config for the validation() plugin auth registers when the application has none. */
|
|
319
318
|
validation?: ValidationPluginConfig;
|
|
320
|
-
/**
|
|
319
|
+
/** Config for the rateLimit() plugin auth registers when the application has none. */
|
|
321
320
|
rateLimit?: RateLimitPluginConfig;
|
|
322
321
|
/**
|
|
323
|
-
*
|
|
324
|
-
*
|
|
325
|
-
*
|
|
326
|
-
*
|
|
327
|
-
* backend — required in production wherever the cache backs rate limiting,
|
|
328
|
-
* since a per-process memory bucket resets on every restart.
|
|
322
|
+
* Config for the cache() plugin auth registers when the application has
|
|
323
|
+
* none. Select a shared, durable backend — here or on the application's own
|
|
324
|
+
* `cache()` — in production wherever the cache backs rate limiting, since a
|
|
325
|
+
* per-process memory bucket resets on every restart.
|
|
329
326
|
*/
|
|
330
327
|
cache?: CachePluginConfig;
|
|
331
|
-
/**
|
|
328
|
+
/**
|
|
329
|
+
* Email transport for password reset and verification flows, used when the
|
|
330
|
+
* application registers no email() plugin. Auth builds its email plugin only
|
|
331
|
+
* in that case, so an application with its own needs no `EMAIL_PROVIDER`
|
|
332
|
+
* for auth to start.
|
|
333
|
+
*/
|
|
332
334
|
email?: EmailPluginConfig;
|
|
333
335
|
/** AES-256-GCM key for reversible encryption (e.g. API keys). Falls back to NAJM_ENCRYPTION_KEY env var. */
|
|
334
336
|
encryptionKey?: string;
|
|
@@ -384,7 +386,7 @@ interface AuthUser {
|
|
|
384
386
|
permissions?: string[];
|
|
385
387
|
}
|
|
386
388
|
|
|
387
|
-
declare const auth$1: (config?: AuthPluginConfig) =>
|
|
389
|
+
declare const auth$1: (config?: AuthPluginConfig) => NajmPlugin;
|
|
388
390
|
|
|
389
391
|
declare const AUTH_CONFIG: unique symbol;
|
|
390
392
|
declare const AUTH_SCHEMA: unique symbol;
|
|
@@ -2707,6 +2709,12 @@ interface OwnerStep {
|
|
|
2707
2709
|
col: any;
|
|
2708
2710
|
}
|
|
2709
2711
|
type OwnershipStep = JoinStep | OwnerStep;
|
|
2712
|
+
/** A condition on the owned row; a function receives the user id and the rule's role. */
|
|
2713
|
+
type RowRule = SQL | ((userId: string, role: string) => SQL);
|
|
2714
|
+
interface WhenStep {
|
|
2715
|
+
type: 'when';
|
|
2716
|
+
rules: RowRule[];
|
|
2717
|
+
}
|
|
2710
2718
|
/**
|
|
2711
2719
|
* JOIN step — links two columns across tables.
|
|
2712
2720
|
* The target table is inferred from the right column.
|
|
@@ -2720,6 +2728,21 @@ declare function join(left: any, right: any): JoinStep;
|
|
|
2720
2728
|
* @example where(teachers.userId)
|
|
2721
2729
|
*/
|
|
2722
2730
|
declare function where(col: any): OwnerStep;
|
|
2731
|
+
/**
|
|
2732
|
+
* Row-condition step — a condition on the owned row itself.
|
|
2733
|
+
*
|
|
2734
|
+
* After a join chain it narrows the rows the chain reaches ("…and the alert is
|
|
2735
|
+
* for parents"). On its own it is the whole rule, for rows that belong to an
|
|
2736
|
+
* audience rather than to one linked person ("every published notice for
|
|
2737
|
+
* parents"). Several rules in one step, and several steps, are AND-ed.
|
|
2738
|
+
*
|
|
2739
|
+
* @example
|
|
2740
|
+
* own(alerts)
|
|
2741
|
+
* .for('parent', join(alerts.studentId, students.id), where(students.parentUserId),
|
|
2742
|
+
* when(eq(alerts.audience, 'parents')))
|
|
2743
|
+
* .for('teacher', when(isNull(alerts.studentId), (userId) => eq(alerts.createdBy, userId)))
|
|
2744
|
+
*/
|
|
2745
|
+
declare function when(...rules: RowRule[]): WhenStep;
|
|
2723
2746
|
type ScopeResult = {
|
|
2724
2747
|
query: any;
|
|
2725
2748
|
condition: any;
|
|
@@ -2727,6 +2750,8 @@ type ScopeResult = {
|
|
|
2727
2750
|
interface OwnershipTokenOptions {
|
|
2728
2751
|
/** Admin roles that bypass all scoping. Falls back to global admin roles if not set. */
|
|
2729
2752
|
adminRoles?: string[];
|
|
2753
|
+
/** Resource name (default: the table's name), e.g. for permission and policy names. */
|
|
2754
|
+
name?: string;
|
|
2730
2755
|
}
|
|
2731
2756
|
declare class OwnershipToken {
|
|
2732
2757
|
readonly symbol: symbol;
|
|
@@ -2737,8 +2762,12 @@ declare class OwnershipToken {
|
|
|
2737
2762
|
private _adminRoles?;
|
|
2738
2763
|
constructor(table: any, opts?: OwnershipTokenOptions);
|
|
2739
2764
|
private isAdmin;
|
|
2740
|
-
/**
|
|
2741
|
-
|
|
2765
|
+
/**
|
|
2766
|
+
* Define the scope rule for a role: a join chain ending in `where()`, and/or
|
|
2767
|
+
* `when()` row conditions. A chain with conditions reaches the rows the
|
|
2768
|
+
* chain reaches that also satisfy them; conditions alone are the whole rule.
|
|
2769
|
+
*/
|
|
2770
|
+
for(role: string, ...steps: Array<OwnershipStep | WhenStep>): this;
|
|
2742
2771
|
/**
|
|
2743
2772
|
* Column to verify ownership before write operations (create/update).
|
|
2744
2773
|
* @example .writeBy(grades.studentId)
|
|
@@ -2756,6 +2785,17 @@ declare class OwnershipToken {
|
|
|
2756
2785
|
*/
|
|
2757
2786
|
applyScopeSplit(uid: string, role: string, query: any): ScopeResult;
|
|
2758
2787
|
}
|
|
2788
|
+
/**
|
|
2789
|
+
* The ids of `token`'s rows that a `role` user owns, as a subquery — for a
|
|
2790
|
+
* `when()` condition on another resource: "one of the classes this parent's
|
|
2791
|
+
* children are in". A role that bypasses scoping gets every id; a role with no
|
|
2792
|
+
* rule gets none.
|
|
2793
|
+
*
|
|
2794
|
+
* @example
|
|
2795
|
+
* own(announcements).for('parent', when((userId, role) =>
|
|
2796
|
+
* inArray(announcements.classId, ownedIds(Class, role, userId))))
|
|
2797
|
+
*/
|
|
2798
|
+
declare function ownedIds(token: OwnershipToken, role: string, userId: string): any;
|
|
2759
2799
|
/**
|
|
2760
2800
|
* Start an ownership definition chain.
|
|
2761
2801
|
*
|
|
@@ -2768,6 +2808,9 @@ declare class OwnershipToken {
|
|
|
2768
2808
|
* // With explicit admin roles (avoids global state):
|
|
2769
2809
|
* export const Grade = own(grades, { adminRoles: ['admin', 'principal'] })
|
|
2770
2810
|
* .for('teacher', join(grades.studentId, students.id), where(teachers.userId));
|
|
2811
|
+
*
|
|
2812
|
+
* // With a resource name other than the table's:
|
|
2813
|
+
* export const Report = own(reportRows, { name: 'reports' });
|
|
2771
2814
|
*/
|
|
2772
2815
|
declare function own(table: any, opts?: OwnershipTokenOptions): OwnershipToken;
|
|
2773
2816
|
|
|
@@ -3235,4 +3278,4 @@ declare const authSeed: (config: AuthSeedConfig) => Record<string, SeedEntry>;
|
|
|
3235
3278
|
*/
|
|
3236
3279
|
declare function seedAuthData(config: SeedAuthDataConfig): Promise<SeedAuthDataResult>;
|
|
3237
3280
|
|
|
3238
|
-
export { AUTH_CONFIG, AUTH_CORE_MODULE, en as AUTH_EN, AUTH_LOCALES, AUTH_LOGIN_RATE_LIMIT_ENV, AUTH_MODULE, AUTH_PERMISSIONS, AUTH_ROLE, AUTH_SCHEMA, AUTH_SUPPORTED_LANGUAGES, AUTH_USER, type AdministrativeDelivery, type AssignPermissionDto, type AssignRoleDto, type AssignRoleParams, type AuthConfig, AuthController, AuthGuard, type AuthLoginRateLimitConfig, type AuthPluginConfig, AuthQueries, type AuthRateLimitEnvironment, AuthResolver, type AuthSchema, type AuthSeedConfig, AuthService, AuthSessionService, type AuthUser, CREDENTIAL_SETUP_CODES, CREDENTIAL_SETUP_MODULE, Can, CanCreate, CanDelete, CanList, CanRead, CanUpdate, type ChainableGuard, type ChangePasswordDto, type CheckPermissionDto, type ConfiguredOwnership, type ConfirmResetPasswordDto, type ConsumedSetPasswordToken, CookieManager, type CreatePermissionDto, type CreateRoleDto, type CreateTokenDto, type CreateUserDto, type CredentialSetupChangeDto, type CredentialSetupCode, type CredentialSetupConfig, CredentialSetupController, type CredentialSetupOptions, type CredentialSetupPasswordOptions, type CredentialSetupPending, CredentialSetupRepository, CredentialSetupRequirementRepository, type CredentialSetupRequirementRow, CredentialSetupRequirementService, CredentialSetupService, type CredentialSetupSessionInfo, type CredentialSetupStarted, DEFAULT_AUTH_LOGIN_RATE_LIMIT, DEFAULT_CREDENTIAL_SETUP_COOKIE_NAME, DEFAULT_CREDENTIAL_SETUP_TTL_MS, type DefineRolesOptions, type EmailParam, EncryptionService, type GitHubOAuthConfig, type GoogleOAuthConfig, IdentityConfig, type IdentityResolver, type InviteUserDto, type JwtConfig, type JwtPayload, type LanguageParam, type LoginDto, type LoginResult, NewPermission, NewRoleEntity, NewUser, type OAuthConfig, type OAuthProvider, Owned, type OwnedMethods, type OwnedWhere, type OwnershipConditionMethods, type OwnershipConfig, type OwnershipProvider, type OwnershipReadContext, type OwnershipRule, OwnershipToken, type OwnershipTokenOptions, PASSWORD_SETUP_PURPOSE, PUBLIC_REGISTRATION_MODULE, PasswordSetupService, Permission, PermissionController, PermissionGuard, type PermissionIdParam, PermissionRepository, PermissionService, PermissionValidator, Policy, type ProvisionUserInput, type ProvisionUserWithPasswordInput, type ProvisionUserWithSetupInput, ROLES, ROLE_GROUPS, type RefreshTokenDto, type RefreshedSession, type RegisterDto, RegistrationController, type ResetPasswordDto, type ResolvedCredentialSetupConfig, ResolvedIdentityConfig, type ResourceAccessor, type ResourceGuards, type ResourceGuardsOptions, type RevokeTokenDto, Role, RoleController, RoleEntity, RoleGuard, type RoleIdParam, type RoleInput, RolePermission, RoleRepository, RoleService, type RoleType, RoleValidator, type RunAsUser, type SanitizedUser, ScopeContext, type ScopeResult, type SeedAuthDataConfig, type SeedAuthDataResult, type SeedUserConfig, type SessionCookieData, SessionInvalidationService, type SetPasswordToken, type SetPasswordTokenType, TOKEN_STATUS, TOKEN_TYPE, TemporaryCredentialInput, type TemporaryCredentialReset, type TokenIdParam, type TokenPair, TokenRepository, TokenService, USER_STATUS, type UpdatePermissionDto, type UpdateRoleDto, type UpdateTokenDto, type UpdateUserDto, User, UserController, type UserIdInParam, type UserIdParam, type UserListQuery, UserRepository, UserService, UserValidator, type UserWithPermissions, type VerifyTokenDto, assignPermissionDto, assignRoleDto, assignRoleParams, auth$1 as auth, authEmailRateLimitKey, authIdentityRateLimitKey, authSeed, avatarsPath, calculateAge, calculateYearsOfExperience, changePasswordDto, checkPermissionDto, clean, configureOwnership, confirmResetPasswordDto, createIdentityResolver, createPermissionDto, createRoleDto, createTokenDto, createUserDto, credentialSetupChangeDto, credentialSetupError, defaultCredentialSetupPasswordSchema, defineRoles, emailParam, formatDate, getAuthLocale, getAvatarFile, inviteUserDto, isAdmin, isAdministrator, isAuth, isEmailIdentifier, isEmpty, isFile, isPath, join, languageParam, loginDto, normalizeAuthIdentifier, normalizeSetupPurpose, own, ownershipCondition, parseSchema, permissionIdParam, pickProps, refreshTokenDto, registerDto, resetPasswordDto, resolveAuthLoginRateLimitConfig, revokeTokenDto, roleIdParam, runAsUser, seedAuthData, tokenIdParam, updatePermissionDto, updateRoleDto, updateTokenDto, updateUserDto, userIdInParam, userIdParam, userListQuery, verifyTokenDto, where };
|
|
3281
|
+
export { AUTH_CONFIG, AUTH_CORE_MODULE, en as AUTH_EN, AUTH_LOCALES, AUTH_LOGIN_RATE_LIMIT_ENV, AUTH_MODULE, AUTH_PERMISSIONS, AUTH_ROLE, AUTH_SCHEMA, AUTH_SUPPORTED_LANGUAGES, AUTH_USER, type AdministrativeDelivery, type AssignPermissionDto, type AssignRoleDto, type AssignRoleParams, type AuthConfig, AuthController, AuthGuard, type AuthLoginRateLimitConfig, type AuthPluginConfig, AuthQueries, type AuthRateLimitEnvironment, AuthResolver, type AuthSchema, type AuthSeedConfig, AuthService, AuthSessionService, type AuthUser, CREDENTIAL_SETUP_CODES, CREDENTIAL_SETUP_MODULE, Can, CanCreate, CanDelete, CanList, CanRead, CanUpdate, type ChainableGuard, type ChangePasswordDto, type CheckPermissionDto, type ConfiguredOwnership, type ConfirmResetPasswordDto, type ConsumedSetPasswordToken, CookieManager, type CreatePermissionDto, type CreateRoleDto, type CreateTokenDto, type CreateUserDto, type CredentialSetupChangeDto, type CredentialSetupCode, type CredentialSetupConfig, CredentialSetupController, type CredentialSetupOptions, type CredentialSetupPasswordOptions, type CredentialSetupPending, CredentialSetupRepository, CredentialSetupRequirementRepository, type CredentialSetupRequirementRow, CredentialSetupRequirementService, CredentialSetupService, type CredentialSetupSessionInfo, type CredentialSetupStarted, DEFAULT_AUTH_LOGIN_RATE_LIMIT, DEFAULT_CREDENTIAL_SETUP_COOKIE_NAME, DEFAULT_CREDENTIAL_SETUP_TTL_MS, type DefineRolesOptions, type EmailParam, EncryptionService, type GitHubOAuthConfig, type GoogleOAuthConfig, IdentityConfig, type IdentityResolver, type InviteUserDto, type JwtConfig, type JwtPayload, type LanguageParam, type LoginDto, type LoginResult, NewPermission, NewRoleEntity, NewUser, type OAuthConfig, type OAuthProvider, Owned, type OwnedMethods, type OwnedWhere, type OwnershipConditionMethods, type OwnershipConfig, type OwnershipProvider, type OwnershipReadContext, type OwnershipRule, OwnershipToken, type OwnershipTokenOptions, PASSWORD_SETUP_PURPOSE, PUBLIC_REGISTRATION_MODULE, PasswordSetupService, Permission, PermissionController, PermissionGuard, type PermissionIdParam, PermissionRepository, PermissionService, PermissionValidator, Policy, type ProvisionUserInput, type ProvisionUserWithPasswordInput, type ProvisionUserWithSetupInput, ROLES, ROLE_GROUPS, type RefreshTokenDto, type RefreshedSession, type RegisterDto, RegistrationController, type ResetPasswordDto, type ResolvedCredentialSetupConfig, ResolvedIdentityConfig, type ResourceAccessor, type ResourceGuards, type ResourceGuardsOptions, type RevokeTokenDto, Role, RoleController, RoleEntity, RoleGuard, type RoleIdParam, type RoleInput, RolePermission, RoleRepository, RoleService, type RoleType, RoleValidator, type RowRule, type RunAsUser, type SanitizedUser, ScopeContext, type ScopeResult, type SeedAuthDataConfig, type SeedAuthDataResult, type SeedUserConfig, type SessionCookieData, SessionInvalidationService, type SetPasswordToken, type SetPasswordTokenType, TOKEN_STATUS, TOKEN_TYPE, TemporaryCredentialInput, type TemporaryCredentialReset, type TokenIdParam, type TokenPair, TokenRepository, TokenService, USER_STATUS, type UpdatePermissionDto, type UpdateRoleDto, type UpdateTokenDto, type UpdateUserDto, User, UserController, type UserIdInParam, type UserIdParam, type UserListQuery, UserRepository, UserService, UserValidator, type UserWithPermissions, type VerifyTokenDto, type WhenStep, assignPermissionDto, assignRoleDto, assignRoleParams, auth$1 as auth, authEmailRateLimitKey, authIdentityRateLimitKey, authSeed, avatarsPath, calculateAge, calculateYearsOfExperience, changePasswordDto, checkPermissionDto, clean, configureOwnership, confirmResetPasswordDto, createIdentityResolver, createPermissionDto, createRoleDto, createTokenDto, createUserDto, credentialSetupChangeDto, credentialSetupError, defaultCredentialSetupPasswordSchema, defineRoles, emailParam, formatDate, getAuthLocale, getAvatarFile, inviteUserDto, isAdmin, isAdministrator, isAuth, isEmailIdentifier, isEmpty, isFile, isPath, join, languageParam, loginDto, normalizeAuthIdentifier, normalizeSetupPurpose, own, ownedIds, ownershipCondition, parseSchema, permissionIdParam, pickProps, refreshTokenDto, registerDto, resetPasswordDto, resolveAuthLoginRateLimitConfig, revokeTokenDto, roleIdParam, runAsUser, seedAuthData, tokenIdParam, updatePermissionDto, updateRoleDto, updateTokenDto, updateUserDto, userIdInParam, userIdParam, userListQuery, verifyTokenDto, when, where };
|
package/dist/index.js
CHANGED
|
@@ -6,7 +6,7 @@ var __export = (target, all) => {
|
|
|
6
6
|
};
|
|
7
7
|
|
|
8
8
|
// src/AuthPlugin.ts
|
|
9
|
-
import { Err as Err17, plugin } from "najm-core";
|
|
9
|
+
import { Err as Err17, lazyPlugin, plugin } from "najm-core";
|
|
10
10
|
import { cache } from "najm-cache";
|
|
11
11
|
|
|
12
12
|
// src/auth.tokens.ts
|
|
@@ -6193,7 +6193,9 @@ var revokeTokenDto = z4.object({
|
|
|
6193
6193
|
});
|
|
6194
6194
|
|
|
6195
6195
|
// src/ownership/scopedOwnership.ts
|
|
6196
|
-
import { aliasedTable, eq as eq8, getTableColumns, sql as sql5 } from "drizzle-orm";
|
|
6196
|
+
import { aliasedTable, and as and6, eq as eq8, getTableColumns, is, sql as sql5 } from "drizzle-orm";
|
|
6197
|
+
import { PgTable, QueryBuilder as PgQueryBuilder } from "drizzle-orm/pg-core";
|
|
6198
|
+
import { SQLiteTable, QueryBuilder as SQLiteQueryBuilder } from "drizzle-orm/sqlite-core";
|
|
6197
6199
|
var DEFAULT_ADMIN_ROLES = ["admin"];
|
|
6198
6200
|
var DRIZZLE_NAME = Symbol.for("drizzle:Name");
|
|
6199
6201
|
var DRIZZLE_BASE_NAME = Symbol.for("drizzle:BaseName");
|
|
@@ -6209,6 +6211,11 @@ function where(col) {
|
|
|
6209
6211
|
return { type: "owner", col };
|
|
6210
6212
|
}
|
|
6211
6213
|
__name(where, "where");
|
|
6214
|
+
function when(...rules) {
|
|
6215
|
+
return { type: "when", rules };
|
|
6216
|
+
}
|
|
6217
|
+
__name(when, "when");
|
|
6218
|
+
var resolveWhen = /* @__PURE__ */ __name((step, uid, role) => and6(...step.rules.map((rule) => typeof rule === "function" ? rule(uid, role) : rule)), "resolveWhen");
|
|
6212
6219
|
function isAliased(table) {
|
|
6213
6220
|
return table?.[DRIZZLE_IS_ALIAS] === true;
|
|
6214
6221
|
}
|
|
@@ -6296,7 +6303,7 @@ var OwnershipToken = class {
|
|
|
6296
6303
|
_writeScopeCol;
|
|
6297
6304
|
_adminRoles;
|
|
6298
6305
|
constructor(table, opts) {
|
|
6299
|
-
const name = table[DRIZZLE_NAME] ?? table?._.baseName ?? table?._.name ?? "resource";
|
|
6306
|
+
const name = opts?.name ?? table[DRIZZLE_NAME] ?? table?._.baseName ?? table?._.name ?? "resource";
|
|
6300
6307
|
this.name = name;
|
|
6301
6308
|
this.table = table;
|
|
6302
6309
|
this.symbol = Symbol(name);
|
|
@@ -6305,9 +6312,26 @@ var OwnershipToken = class {
|
|
|
6305
6312
|
isAdmin(role) {
|
|
6306
6313
|
return (this._adminRoles ?? DEFAULT_ADMIN_ROLES).includes(role);
|
|
6307
6314
|
}
|
|
6308
|
-
/**
|
|
6315
|
+
/**
|
|
6316
|
+
* Define the scope rule for a role: a join chain ending in `where()`, and/or
|
|
6317
|
+
* `when()` row conditions. A chain with conditions reaches the rows the
|
|
6318
|
+
* chain reaches that also satisfy them; conditions alone are the whole rule.
|
|
6319
|
+
*/
|
|
6309
6320
|
for(role, ...steps) {
|
|
6310
|
-
|
|
6321
|
+
const chain = steps.filter((step) => step.type !== "when");
|
|
6322
|
+
const conditions = steps.filter((step) => step.type === "when");
|
|
6323
|
+
if (!conditions.length) {
|
|
6324
|
+
this._rules[role] = compile(chain);
|
|
6325
|
+
return this;
|
|
6326
|
+
}
|
|
6327
|
+
const joined = chain.length ? compile(chain) : void 0;
|
|
6328
|
+
this._rules[role] = (uid, query) => {
|
|
6329
|
+
const narrowing = and6(...conditions.map((condition) => resolveWhen(condition, uid, role)));
|
|
6330
|
+
if (!joined)
|
|
6331
|
+
return { query, condition: narrowing };
|
|
6332
|
+
const scoped = joined(uid, query);
|
|
6333
|
+
return { query: scoped.query, condition: and6(scoped.condition, narrowing) };
|
|
6334
|
+
};
|
|
6311
6335
|
return this;
|
|
6312
6336
|
}
|
|
6313
6337
|
/**
|
|
@@ -6349,6 +6373,18 @@ var OwnershipToken = class {
|
|
|
6349
6373
|
return rule(uid, query);
|
|
6350
6374
|
}
|
|
6351
6375
|
};
|
|
6376
|
+
function ownedIds(token, role, userId) {
|
|
6377
|
+
const table = token.table;
|
|
6378
|
+
if (!table?.id)
|
|
6379
|
+
throw new Error(`ownedIds(): ${token.name} has no id column.`);
|
|
6380
|
+
const builder = is(table, SQLiteTable) ? new SQLiteQueryBuilder() : is(table, PgTable) ? new PgQueryBuilder() : null;
|
|
6381
|
+
if (!builder)
|
|
6382
|
+
throw new Error(`ownedIds(): ${token.name} is not a pg or sqlite table.`);
|
|
6383
|
+
const rows = builder.select({ id: table.id }).from(table);
|
|
6384
|
+
const { query, condition } = token.applyScopeSplit(userId, role, rows);
|
|
6385
|
+
return condition === null ? query : query.where(condition);
|
|
6386
|
+
}
|
|
6387
|
+
__name(ownedIds, "ownedIds");
|
|
6352
6388
|
function own(table, opts) {
|
|
6353
6389
|
return new OwnershipToken(table, opts);
|
|
6354
6390
|
}
|
|
@@ -6704,7 +6740,7 @@ __name(Policy, "Policy");
|
|
|
6704
6740
|
|
|
6705
6741
|
// src/ownership/OwnedDecorator.ts
|
|
6706
6742
|
import "reflect-metadata";
|
|
6707
|
-
import { sql as sql7, and as
|
|
6743
|
+
import { sql as sql7, and as and7 } from "drizzle-orm";
|
|
6708
6744
|
import { Injectable as Injectable17, Inject as Inject19, DI as DI3, Container as Container2, REQUEST_ID } from "najm-core";
|
|
6709
6745
|
import { USER as USER2 } from "najm-guard";
|
|
6710
6746
|
|
|
@@ -6866,7 +6902,7 @@ function Owned(token, ...alternatives) {
|
|
|
6866
6902
|
return null;
|
|
6867
6903
|
if (filtered.length === 1)
|
|
6868
6904
|
return filtered[0];
|
|
6869
|
-
return
|
|
6905
|
+
return and7(...filtered);
|
|
6870
6906
|
}
|
|
6871
6907
|
__name(combineConditions, "combineConditions");
|
|
6872
6908
|
function applyQueryOptions(query, opts = {}, whereCondition) {
|
|
@@ -7386,7 +7422,7 @@ import { Inject as Inject24, Injectable as Injectable21 } from "najm-core";
|
|
|
7386
7422
|
import { Transaction as Transaction5 } from "najm-database";
|
|
7387
7423
|
|
|
7388
7424
|
// src/oauth/OAuthAccountRepository.ts
|
|
7389
|
-
import { and as
|
|
7425
|
+
import { and as and8, eq as eq9 } from "drizzle-orm";
|
|
7390
7426
|
import { Inject as Inject23, Repository as Repository7 } from "najm-core";
|
|
7391
7427
|
import { DB as DB7 } from "najm-database";
|
|
7392
7428
|
var __decorate37 = function(decorators, target, key, desc) {
|
|
@@ -7411,11 +7447,11 @@ var OAuthAccountRepository = class OAuthAccountRepository2 {
|
|
|
7411
7447
|
return this.schema.oauthAccounts;
|
|
7412
7448
|
}
|
|
7413
7449
|
async getByProviderAccount(provider, providerAccountId) {
|
|
7414
|
-
const [account] = await this.db.select().from(this.accounts).where(
|
|
7450
|
+
const [account] = await this.db.select().from(this.accounts).where(and8(eq9(this.accounts.provider, provider), eq9(this.accounts.providerAccountId, providerAccountId))).limit(1);
|
|
7415
7451
|
return account;
|
|
7416
7452
|
}
|
|
7417
7453
|
async getByUserProvider(userId, provider) {
|
|
7418
|
-
const [account] = await this.db.select().from(this.accounts).where(
|
|
7454
|
+
const [account] = await this.db.select().from(this.accounts).where(and8(eq9(this.accounts.userId, userId), eq9(this.accounts.provider, provider))).limit(1);
|
|
7419
7455
|
return account;
|
|
7420
7456
|
}
|
|
7421
7457
|
async create(data) {
|
|
@@ -8281,7 +8317,10 @@ var selectAuthSchema = /* @__PURE__ */ __name((config) => {
|
|
|
8281
8317
|
return authSchema;
|
|
8282
8318
|
}
|
|
8283
8319
|
}, "selectAuthSchema");
|
|
8284
|
-
var
|
|
8320
|
+
var configurableDependency = /* @__PURE__ */ __name((config, option, name, create) => lazyPlugin(name, () => create(config?.[option]), {
|
|
8321
|
+
forwardedConfig: config?.[option] === void 0 ? void 0 : `auth({ ${option} })`
|
|
8322
|
+
}), "configurableDependency");
|
|
8323
|
+
var auth = /* @__PURE__ */ __name((config) => plugin("auth").version("1.0.0").depends(configurableDependency(config, "cache", "cache", cache), cookies(), i18n(), guards(), configurableDependency(config, "validation", "validation", validation), configurableDependency(config, "rateLimit", "rate-limit", rateLimit), configurableDependency(config, "email", "email", email)).requires("database").contributes(I18N_CONTRIBUTIONS, AUTH_LOCALES).services(AUTH_CORE_MODULE, config?.publicRegistration === false ? [] : PUBLIC_REGISTRATION_MODULE, OAUTH_MODULE, users_exports, roles_exports, permissions_exports, tokens_exports, CREDENTIAL_SETUP_MODULE, ScopeContext).config(AUTH_CONFIG, resolveAuthConfig(config)).set(AUTH_SCHEMA, selectAuthSchema(config)).set(AUTH_ENCRYPTION_KEY, config?.encryptionKey ?? null).build(), "auth");
|
|
8285
8324
|
|
|
8286
8325
|
// src/seed.ts
|
|
8287
8326
|
var toSeedId = /* @__PURE__ */ __name((prefix, value) => {
|
|
@@ -8545,6 +8584,7 @@ export {
|
|
|
8545
8584
|
normalizeTunisianPhone,
|
|
8546
8585
|
oauthAccountsTable,
|
|
8547
8586
|
own,
|
|
8587
|
+
ownedIds,
|
|
8548
8588
|
ownershipCondition,
|
|
8549
8589
|
parseSchema,
|
|
8550
8590
|
permissionIdParam,
|
|
@@ -8577,5 +8617,6 @@ export {
|
|
|
8577
8617
|
userStatusEnum,
|
|
8578
8618
|
usersTable,
|
|
8579
8619
|
verifyTokenDto,
|
|
8620
|
+
when,
|
|
8580
8621
|
where
|
|
8581
8622
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "najm-auth",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.3.0",
|
|
4
4
|
"description": "Authentication and authorization library for najm framework",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|
|
@@ -93,12 +93,12 @@
|
|
|
93
93
|
"dependencies": {
|
|
94
94
|
"bcryptjs": "^3.0.2",
|
|
95
95
|
"najm-cookies": "^2.0.3",
|
|
96
|
-
"najm-core": "^3.0
|
|
96
|
+
"najm-core": "^3.1.0",
|
|
97
97
|
"najm-database": "^2.2.1",
|
|
98
98
|
"najm-guard": "^2.2.1",
|
|
99
99
|
"najm-i18n": "^2.1.3",
|
|
100
|
-
"najm-cache": "^2.
|
|
101
|
-
"najm-email": "^3.
|
|
100
|
+
"najm-cache": "^2.3.0",
|
|
101
|
+
"najm-email": "^3.1.0",
|
|
102
102
|
"najm-rate": "^3.0.0",
|
|
103
103
|
"najm-validation": "^2.0.3",
|
|
104
104
|
"jsonwebtoken": "^9.0.3",
|