@nxgt/janus 0.1.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/LICENSE +21 -0
- package/README.md +554 -0
- package/dist/auth/config.d.ts +201 -0
- package/dist/auth/config.d.ts.map +1 -0
- package/dist/auth/context.d.ts +87 -0
- package/dist/auth/context.d.ts.map +1 -0
- package/dist/auth/hashers.d.ts +35 -0
- package/dist/auth/hashers.d.ts.map +1 -0
- package/dist/auth/index.d.ts +9 -0
- package/dist/auth/index.d.ts.map +1 -0
- package/dist/auth/janus.d.ts +38 -0
- package/dist/auth/janus.d.ts.map +1 -0
- package/dist/auth/outage.d.ts +61 -0
- package/dist/auth/outage.d.ts.map +1 -0
- package/dist/auth/port/assert-stores.d.ts +16 -0
- package/dist/auth/port/assert-stores.d.ts.map +1 -0
- package/dist/auth/port/memory.d.ts +25 -0
- package/dist/auth/port/memory.d.ts.map +1 -0
- package/dist/auth/port/types.d.ts +393 -0
- package/dist/auth/port/types.d.ts.map +1 -0
- package/dist/auth/secrets.d.ts +17 -0
- package/dist/auth/secrets.d.ts.map +1 -0
- package/dist/auth/sessions.d.ts +31 -0
- package/dist/auth/sessions.d.ts.map +1 -0
- package/dist/auth/standard-schema.d.ts +41 -0
- package/dist/auth/standard-schema.d.ts.map +1 -0
- package/dist/auth/types.d.ts +353 -0
- package/dist/auth/types.d.ts.map +1 -0
- package/dist/auth/users.d.ts +9 -0
- package/dist/auth/users.d.ts.map +1 -0
- package/dist/chunks/index-658b6mr2.js +269 -0
- package/dist/chunks/index-658b6mr2.js.map +11 -0
- package/dist/chunks/index-6dytvy3h.js +93 -0
- package/dist/chunks/index-6dytvy3h.js.map +11 -0
- package/dist/chunks/index-6p56fpbe.js +147 -0
- package/dist/chunks/index-6p56fpbe.js.map +12 -0
- package/dist/chunks/index-fgb3t64y.js +77 -0
- package/dist/chunks/index-fgb3t64y.js.map +10 -0
- package/dist/conformance/assert.d.ts +36 -0
- package/dist/conformance/assert.d.ts.map +1 -0
- package/dist/conformance/cases/outage.d.ts +3 -0
- package/dist/conformance/cases/outage.d.ts.map +1 -0
- package/dist/conformance/cases/sessions.d.ts +3 -0
- package/dist/conformance/cases/sessions.d.ts.map +1 -0
- package/dist/conformance/cases/tokens.d.ts +3 -0
- package/dist/conformance/cases/tokens.d.ts.map +1 -0
- package/dist/conformance/cases/users.d.ts +3 -0
- package/dist/conformance/cases/users.d.ts.map +1 -0
- package/dist/conformance/describe.d.ts +74 -0
- package/dist/conformance/describe.d.ts.map +1 -0
- package/dist/conformance/fixtures.d.ts +11 -0
- package/dist/conformance/fixtures.d.ts.map +1 -0
- package/dist/conformance/index.d.ts +33 -0
- package/dist/conformance/index.d.ts.map +1 -0
- package/dist/conformance/index.js +1113 -0
- package/dist/conformance/index.js.map +18 -0
- package/dist/conformance/reference.d.ts +13 -0
- package/dist/conformance/reference.d.ts.map +1 -0
- package/dist/conformance/relations.d.ts +67 -0
- package/dist/conformance/relations.d.ts.map +1 -0
- package/dist/conformance/types.d.ts +71 -0
- package/dist/conformance/types.d.ts.map +1 -0
- package/dist/errors/janus-error.d.ts +259 -0
- package/dist/errors/janus-error.d.ts.map +1 -0
- package/dist/ids/id.d.ts +55 -0
- package/dist/ids/id.d.ts.map +1 -0
- package/dist/index.d.ts +30 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +962 -0
- package/dist/index.js.map +19 -0
- package/dist/pagination/cursor-page.d.ts +53 -0
- package/dist/pagination/cursor-page.d.ts.map +1 -0
- package/dist/permissions/engine.d.ts +46 -0
- package/dist/permissions/engine.d.ts.map +1 -0
- package/dist/permissions/index.d.ts +24 -0
- package/dist/permissions/index.d.ts.map +1 -0
- package/dist/permissions/index.js +685 -0
- package/dist/permissions/index.js.map +15 -0
- package/dist/permissions/input.d.ts +29 -0
- package/dist/permissions/input.d.ts.map +1 -0
- package/dist/permissions/model.d.ts +368 -0
- package/dist/permissions/model.d.ts.map +1 -0
- package/dist/permissions/port/memory.d.ts +17 -0
- package/dist/permissions/port/memory.d.ts.map +1 -0
- package/dist/permissions/port/types.d.ts +84 -0
- package/dist/permissions/port/types.d.ts.map +1 -0
- package/dist/permissions/resolve.d.ts +59 -0
- package/dist/permissions/resolve.d.ts.map +1 -0
- package/dist/permissions/reverse.d.ts +53 -0
- package/dist/permissions/reverse.d.ts.map +1 -0
- package/dist/permissions/walk.d.ts +29 -0
- package/dist/permissions/walk.d.ts.map +1 -0
- package/dist/subjects/notation.d.ts +35 -0
- package/dist/subjects/notation.d.ts.map +1 -0
- package/dist/subjects/subject.d.ts +75 -0
- package/dist/subjects/subject.d.ts.map +1 -0
- package/dist/time/clock.d.ts +31 -0
- package/dist/time/clock.d.ts.map +1 -0
- package/dist/time/duration.d.ts +23 -0
- package/dist/time/duration.d.ts.map +1 -0
- package/docs/README.md +17 -0
- package/docs/guide/adapters.md +296 -0
- package/docs/guide/email-flows.md +146 -0
- package/docs/guide/errors.md +146 -0
- package/docs/guide/passwords.md +136 -0
- package/docs/guide/permissions.md +347 -0
- package/docs/guide/sessions.md +211 -0
- package/docs/guide/users.md +277 -0
- package/docs/guide/vocabulary.md +163 -0
- package/docs/roadmap.md +93 -0
- package/docs/troubleshooting.md +648 -0
- package/package.json +70 -0
|
@@ -0,0 +1,353 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What `janus()` hands back, typed from the configuration it was given.
|
|
3
|
+
*
|
|
4
|
+
* The generic form lives here; the implementation works on a degenericised
|
|
5
|
+
* mirror and casts once, in `janus.ts`. That is `nxgt-data`'s shape, and it
|
|
6
|
+
* keeps each schema's type travelling through every public method without
|
|
7
|
+
* dragging a type parameter through every internal function.
|
|
8
|
+
*/
|
|
9
|
+
import type { Id } from '../ids/id';
|
|
10
|
+
import type { CursorPage } from '../pagination/cursor-page';
|
|
11
|
+
import type { JanusConfig, MultiTypeConfig, RESERVED_FIELDS, RESERVED_TYPES, SingleTypeConfig, UserSchema } from './config';
|
|
12
|
+
import type { SessionRecord } from './port/types';
|
|
13
|
+
import type { StandardSchemaV1 } from './standard-schema';
|
|
14
|
+
/** What every user carries beside the application's own fields. */
|
|
15
|
+
export interface UserBase<Type extends string = string> {
|
|
16
|
+
readonly id: Id;
|
|
17
|
+
/** Which user type — `'patient'`, `'staff'`, or `'user'` in the one-type form. */
|
|
18
|
+
readonly type: Type;
|
|
19
|
+
/** Whether the user proved they hold their current e-mail. */
|
|
20
|
+
readonly emailVerified: boolean;
|
|
21
|
+
/** `false`: the user is kept, and every sign-in is refused. */
|
|
22
|
+
readonly active: boolean;
|
|
23
|
+
/**
|
|
24
|
+
* Whether a password is set. **The hash itself never reaches a user**: no
|
|
25
|
+
* type that reaches a request handler carries it, and `test/types/` pins
|
|
26
|
+
* that.
|
|
27
|
+
*/
|
|
28
|
+
readonly hasPassword: boolean;
|
|
29
|
+
/** One more on every write: what `ifVersion` is compared against. */
|
|
30
|
+
readonly version: number;
|
|
31
|
+
readonly createdAt: Date;
|
|
32
|
+
readonly updatedAt: Date;
|
|
33
|
+
}
|
|
34
|
+
/** A user as application code sees it: their fields, at the top level, and {@link UserBase}. */
|
|
35
|
+
export type User<Type extends string = string, Fields = object> = Readonly<Fields> & UserBase<Type>;
|
|
36
|
+
/** A user, or their id: every method that takes one takes either. */
|
|
37
|
+
export type UserRef = string | {
|
|
38
|
+
readonly id: string;
|
|
39
|
+
};
|
|
40
|
+
/** A session, as application code sees it: everything but the token's hash. */
|
|
41
|
+
export type Session = Omit<SessionRecord, 'tokenHash'>;
|
|
42
|
+
/**
|
|
43
|
+
* A session just opened. **The token is here and nowhere else**: the store
|
|
44
|
+
* holds its hash. Put it in a cookie with `auth.cookie.serialize`, or hand it
|
|
45
|
+
* to a client that sends it as `Authorization: Bearer`.
|
|
46
|
+
*/
|
|
47
|
+
export interface SignedIn<U> {
|
|
48
|
+
readonly user: U;
|
|
49
|
+
readonly session: Session;
|
|
50
|
+
readonly token: string;
|
|
51
|
+
}
|
|
52
|
+
/** Who a request belongs to. */
|
|
53
|
+
export interface Authenticated<U> {
|
|
54
|
+
readonly user: U;
|
|
55
|
+
readonly session: Session;
|
|
56
|
+
/** The token the request presented. */
|
|
57
|
+
readonly token: string;
|
|
58
|
+
/**
|
|
59
|
+
* Whether this call renewed the session. When it did, `session.expiresAt`
|
|
60
|
+
* moved: send the cookie again with `auth.cookie.serialize(token, session)`.
|
|
61
|
+
*/
|
|
62
|
+
readonly renewed: boolean;
|
|
63
|
+
}
|
|
64
|
+
/** A one-time token, given to the application once, to send by e-mail. */
|
|
65
|
+
export interface IssuedToken {
|
|
66
|
+
readonly token: string;
|
|
67
|
+
/** The address to send it to. */
|
|
68
|
+
readonly email: string;
|
|
69
|
+
readonly expiresAt: Date;
|
|
70
|
+
}
|
|
71
|
+
/** What `authenticate` and `signOut` read a session token from. */
|
|
72
|
+
export type RequestLike = Request | Headers | {
|
|
73
|
+
readonly headers: Headers | HeaderRecord;
|
|
74
|
+
} | HeaderRecord;
|
|
75
|
+
/** Headers as Node's `IncomingMessage` and most frameworks hold them. */
|
|
76
|
+
export type HeaderRecord = {
|
|
77
|
+
readonly [name: string]: string | readonly string[] | undefined;
|
|
78
|
+
};
|
|
79
|
+
/** Options every write that follows a read may take. */
|
|
80
|
+
export interface WriteOptions {
|
|
81
|
+
/**
|
|
82
|
+
* The version the user must still hold, as read. A write to a user who
|
|
83
|
+
* changed since is `VERSION_CONFLICT`, and nothing is written.
|
|
84
|
+
*/
|
|
85
|
+
readonly ifVersion?: number;
|
|
86
|
+
}
|
|
87
|
+
type OutputOf<S> = S extends StandardSchemaV1 ? StandardSchemaV1.InferOutput<S> : never;
|
|
88
|
+
type InputOf<S> = S extends StandardSchemaV1 ? StandardSchemaV1.InferInput<S> : never;
|
|
89
|
+
/** The single-type form, seen as one entry of `users`. */
|
|
90
|
+
type SingleAsType<C extends SingleTypeConfig> = {
|
|
91
|
+
readonly schema: C['user'];
|
|
92
|
+
readonly password: C['password'];
|
|
93
|
+
readonly email: C['email'];
|
|
94
|
+
};
|
|
95
|
+
/** Every user type a configuration declares, by name. */
|
|
96
|
+
export type TypesOf<C> = C extends MultiTypeConfig ? C['users'] : C extends SingleTypeConfig ? {
|
|
97
|
+
readonly user: SingleAsType<C>;
|
|
98
|
+
} : never;
|
|
99
|
+
/**
|
|
100
|
+
* Every **top-level, required** key of `T` whose value is a string: what a
|
|
101
|
+
* login or an e-mail may name. Required, because a login read from an
|
|
102
|
+
* optional field is a user who may have no way to sign in.
|
|
103
|
+
*/
|
|
104
|
+
export type RequiredStringKeys<T> = {
|
|
105
|
+
[K in keyof T & string]-?: object extends Pick<T, K> ? never : T[K] extends string ? K : never;
|
|
106
|
+
}[keyof T & string];
|
|
107
|
+
/** The login field of one user type, or `never` without a password. */
|
|
108
|
+
export type LoginOf<Def> = Def extends {
|
|
109
|
+
readonly password: {
|
|
110
|
+
readonly login: infer L extends string;
|
|
111
|
+
};
|
|
112
|
+
} ? L : never;
|
|
113
|
+
/**
|
|
114
|
+
* The e-mail field of one user type: the one it names, or `'email'` when the
|
|
115
|
+
* schema has a required string `email` — or `never`, and then the e-mail flows
|
|
116
|
+
* do not exist on it.
|
|
117
|
+
*/
|
|
118
|
+
export type EmailOf<Def> = Def extends {
|
|
119
|
+
readonly email: infer E extends string;
|
|
120
|
+
} ? E : Def extends {
|
|
121
|
+
readonly schema: infer S;
|
|
122
|
+
} ? 'email' extends RequiredStringKeys<OutputOf<S>> ? 'email' : never : never;
|
|
123
|
+
type UserOfType<Name extends string, Def> = Def extends {
|
|
124
|
+
readonly schema: infer S;
|
|
125
|
+
} ? User<Name, OutputOf<S>> : never;
|
|
126
|
+
/** Every user of a configuration: a union discriminated by `type`. */
|
|
127
|
+
export type UserOf<C> = {
|
|
128
|
+
[K in keyof TypesOf<C> & string]: UserOfType<K, TypesOf<C>[K]>;
|
|
129
|
+
}[keyof TypesOf<C> & string];
|
|
130
|
+
/** What `create`, `signUp` and `update` take for one user type. */
|
|
131
|
+
type FieldsInput<Def> = Def extends {
|
|
132
|
+
readonly schema: infer S;
|
|
133
|
+
} ? InputOf<S> : never;
|
|
134
|
+
/** What every user type answers. */
|
|
135
|
+
export interface UserTypeApi<U, In> {
|
|
136
|
+
/**
|
|
137
|
+
* Creates a user without signing them in — for an import, an admin screen,
|
|
138
|
+
* an invitation. Validates the fields, and hashes the password when one is
|
|
139
|
+
* given.
|
|
140
|
+
*
|
|
141
|
+
* Rejects with `USER_INVALID`, `PASSWORD_TOO_SHORT`, `LOGIN_TAKEN`, or
|
|
142
|
+
* `STORE_FAILED`.
|
|
143
|
+
*/
|
|
144
|
+
create(input: In & {
|
|
145
|
+
readonly password?: string;
|
|
146
|
+
readonly active?: boolean;
|
|
147
|
+
}): Promise<U>;
|
|
148
|
+
/** The user of this type, or `null` — for a malformed id, an unknown one, or one of another type. */
|
|
149
|
+
find(id: string): Promise<U | null>;
|
|
150
|
+
/** The user of this type, or `NOT_FOUND`. */
|
|
151
|
+
get(id: string): Promise<U>;
|
|
152
|
+
/** One page of users of this type, in creation order. A cursor this package did not mint is `INVALID_CURSOR`. */
|
|
153
|
+
list(page?: {
|
|
154
|
+
readonly after?: string | null;
|
|
155
|
+
readonly limit?: number;
|
|
156
|
+
}): Promise<CursorPage<U>>;
|
|
157
|
+
/**
|
|
158
|
+
* Changes some fields and keeps the others: the patch is merged over the
|
|
159
|
+
* stored fields, then **the whole result is validated**. Changing the e-mail
|
|
160
|
+
* sets `emailVerified` back to `false`.
|
|
161
|
+
*/
|
|
162
|
+
update(user: UserRef, patch: Partial<In>, options?: WriteOptions): Promise<U>;
|
|
163
|
+
/** Activates or deactivates. An inactive user's sessions stop authenticating. */
|
|
164
|
+
setActive(user: UserRef, active: boolean, options?: WriteOptions): Promise<U>;
|
|
165
|
+
/**
|
|
166
|
+
* Deletes the user, **with every session and one-time token they had** —
|
|
167
|
+
* nothing of theirs is kept, the e-mail a token was sent to included.
|
|
168
|
+
* `true` when this call deleted them; `false` for a malformed id, an
|
|
169
|
+
* unknown one, or one of another type, which is left untouched.
|
|
170
|
+
*
|
|
171
|
+
* With `relations` wired into `janus()`, every tuple naming the user goes
|
|
172
|
+
* too, last.
|
|
173
|
+
*
|
|
174
|
+
* Idempotent: an outage half-way leaves sessions, tokens and tuples that
|
|
175
|
+
* name somebody who no longer exists, and calling it again deletes them.
|
|
176
|
+
*/
|
|
177
|
+
delete(user: UserRef): Promise<boolean>;
|
|
178
|
+
}
|
|
179
|
+
/** What a user type that signs in with a password answers besides. */
|
|
180
|
+
export interface PasswordApi<U, In, Login extends string> {
|
|
181
|
+
/**
|
|
182
|
+
* Creates the user and signs them in.
|
|
183
|
+
*
|
|
184
|
+
* Rejects with `USER_INVALID`, `PASSWORD_TOO_SHORT`, `LOGIN_TAKEN`, or
|
|
185
|
+
* `STORE_FAILED`.
|
|
186
|
+
*/
|
|
187
|
+
signUp(input: In & {
|
|
188
|
+
readonly password: string;
|
|
189
|
+
}): Promise<SignedIn<U>>;
|
|
190
|
+
/**
|
|
191
|
+
* Checks the password and opens a session.
|
|
192
|
+
*
|
|
193
|
+
* Rejects with `CREDENTIALS_INVALID` — one code for an unknown login, a user
|
|
194
|
+
* with no password and a wrong password, so a response cannot tell which
|
|
195
|
+
* accounts exist; `reason` tells them apart for your logs. When nobody holds
|
|
196
|
+
* the login, a dummy hash is still compared, so the time taken does not say
|
|
197
|
+
* so either. **The store's own latency stays observable**, and that limit is
|
|
198
|
+
* documented rather than denied. An inactive user who gave the right
|
|
199
|
+
* password is `USER_INACTIVE`.
|
|
200
|
+
*/
|
|
201
|
+
signIn(input: {
|
|
202
|
+
readonly [K in Login]: string;
|
|
203
|
+
} & {
|
|
204
|
+
readonly password: string;
|
|
205
|
+
}): Promise<SignedIn<U>>;
|
|
206
|
+
/** The user holding this login, normalised as sign-up normalised it, or `null`. */
|
|
207
|
+
findByLogin(login: string): Promise<U | null>;
|
|
208
|
+
/** Sets or replaces the password — an admin's call. `PASSWORD_TOO_SHORT` below the policy. */
|
|
209
|
+
setPassword(user: UserRef, password: string, options?: WriteOptions): Promise<U>;
|
|
210
|
+
/**
|
|
211
|
+
* Replaces the password after checking the current one — the user's call.
|
|
212
|
+
* `CREDENTIALS_INVALID` when `current` is wrong. Other sessions stay open:
|
|
213
|
+
* call `signOutEverywhere(user, { except })` for that.
|
|
214
|
+
*/
|
|
215
|
+
changePassword(user: UserRef, change: {
|
|
216
|
+
readonly current: string;
|
|
217
|
+
readonly next: string;
|
|
218
|
+
}, options?: WriteOptions): Promise<U>;
|
|
219
|
+
}
|
|
220
|
+
/** What a user type with an e-mail answers besides. */
|
|
221
|
+
export interface VerifyEmailApi<U> {
|
|
222
|
+
readonly verifyEmail: {
|
|
223
|
+
/** Issues a token for the user's current e-mail. Sending it is yours. */
|
|
224
|
+
send(user: UserRef): Promise<IssuedToken>;
|
|
225
|
+
/**
|
|
226
|
+
* Redeems a token and marks the e-mail verified. A token sent to an
|
|
227
|
+
* e-mail the user has since changed is `TOKEN_STALE`.
|
|
228
|
+
*/
|
|
229
|
+
confirm(token: string): Promise<U>;
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
/** What a user type with an e-mail and a password answers besides. */
|
|
233
|
+
export interface ResetPasswordApi<U> {
|
|
234
|
+
readonly resetPassword: {
|
|
235
|
+
/**
|
|
236
|
+
* Issues a reset token for the user of this type holding this e-mail, or
|
|
237
|
+
* answers `null` when there is none. **Never tell the visitor which**:
|
|
238
|
+
* answer the same page either way.
|
|
239
|
+
*/
|
|
240
|
+
request(email: string): Promise<(IssuedToken & {
|
|
241
|
+
readonly user: U;
|
|
242
|
+
}) | null>;
|
|
243
|
+
/**
|
|
244
|
+
* Redeems the token, sets the password, marks the e-mail verified — the
|
|
245
|
+
* link proved it — and **signs the user out everywhere**. Opens no
|
|
246
|
+
* session: call `signIn` next if that is your policy.
|
|
247
|
+
*/
|
|
248
|
+
confirm(token: string, password: string): Promise<U>;
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
/** The whole surface of one user type, with only the flows its configuration allows. */
|
|
252
|
+
export type TypeApi<Name extends string, Def> = UserTypeApi<UserOfType<Name, Def>, FieldsInput<Def>> & ([LoginOf<Def>] extends [never] ? unknown : PasswordApi<UserOfType<Name, Def>, FieldsInput<Def>, LoginOf<Def>>) & ([EmailOf<Def>] extends [never] ? unknown : VerifyEmailApi<UserOfType<Name, Def>>) & ([LoginOf<Def>] extends [never] ? unknown : [EmailOf<Def>] extends [never] ? unknown : ResetPasswordApi<UserOfType<Name, Def>>);
|
|
253
|
+
/** What every configuration answers, whatever its user types. */
|
|
254
|
+
export interface SharedApi<U extends {
|
|
255
|
+
readonly type: string;
|
|
256
|
+
}> {
|
|
257
|
+
/**
|
|
258
|
+
* Who a request belongs to, or `null` for an anonymous one.
|
|
259
|
+
*
|
|
260
|
+
* Reads `Authorization: Bearer`, then `X-Session-Token`, then the cookie:
|
|
261
|
+
* **the first credential present wins, not the first valid one.** A lapsed
|
|
262
|
+
* or revoked session, a user gone or inactive, or a user of another type
|
|
263
|
+
* than `options.type` is anonymous. Renews a sliding session in passing.
|
|
264
|
+
*
|
|
265
|
+
* **An outage is not anonymous**: a store that cannot answer rejects with
|
|
266
|
+
* `STORE_FAILED`. Answer 503, never 401.
|
|
267
|
+
*/
|
|
268
|
+
authenticate<T extends U['type'] = U['type']>(request: RequestLike, options?: {
|
|
269
|
+
readonly type?: T;
|
|
270
|
+
}): Promise<Authenticated<Extract<U, {
|
|
271
|
+
readonly type: T;
|
|
272
|
+
}>> | null>;
|
|
273
|
+
/** Revokes the session a request presents. `false` when it presents none, or an unknown one. */
|
|
274
|
+
signOut(request: RequestLike): Promise<boolean>;
|
|
275
|
+
/** Revokes every session of a user, but `except`. Answers how many. */
|
|
276
|
+
signOutEverywhere(user: UserRef, options?: {
|
|
277
|
+
readonly except?: string;
|
|
278
|
+
}): Promise<number>;
|
|
279
|
+
/** The user with this id, whatever their type, or `null`. */
|
|
280
|
+
findUser(id: string): Promise<U | null>;
|
|
281
|
+
/** The user with this id, whatever their type, or `NOT_FOUND`. */
|
|
282
|
+
getUser(id: string): Promise<U>;
|
|
283
|
+
/** The session cookie, as `Set-Cookie` values. Synchronous. */
|
|
284
|
+
readonly cookie: {
|
|
285
|
+
readonly name: string;
|
|
286
|
+
serialize(token: string, session: Session): string;
|
|
287
|
+
clear(): string;
|
|
288
|
+
};
|
|
289
|
+
/**
|
|
290
|
+
* Deletes lapsed sessions. `UNSUPPORTED` when the sessions store does not
|
|
291
|
+
* implement `deleteExpiredSessions` — a store with its own TTL does not need
|
|
292
|
+
* to.
|
|
293
|
+
*/
|
|
294
|
+
collectExpired(): Promise<number>;
|
|
295
|
+
/** The user type names, in the order they were declared. */
|
|
296
|
+
readonly types: readonly U['type'][];
|
|
297
|
+
}
|
|
298
|
+
/** What `janus(config)` answers. */
|
|
299
|
+
export type Janus<C extends JanusConfig> = SharedApi<UserOf<C>> & (C extends MultiTypeConfig ? {
|
|
300
|
+
readonly [K in keyof C['users'] & string]: TypeApi<K, C['users'][K]>;
|
|
301
|
+
} : C extends SingleTypeConfig ? TypeApi<'user', SingleAsType<C>> : never);
|
|
302
|
+
/**
|
|
303
|
+
* Makes a value that names no key of `Keys` unassignable, and says why on that
|
|
304
|
+
* key.
|
|
305
|
+
*
|
|
306
|
+
* The reason is the **key** of an object type, and the valid names its value.
|
|
307
|
+
* A string-literal message would not survive: `'emial' & 'message'` reduces to
|
|
308
|
+
* `never`, which collapses the whole object and loses the sentence — measured
|
|
309
|
+
* while writing `from` in the first surface. A string intersected with an
|
|
310
|
+
* object does not reduce, so the compiler prints both.
|
|
311
|
+
*/
|
|
312
|
+
type CheckName<V, Keys extends string, What extends string> = [V] extends [Keys] ? unknown : {
|
|
313
|
+
readonly [K in `"${V & string}" is not ${What}; name one of`]: Keys;
|
|
314
|
+
};
|
|
315
|
+
type Reserved<S> = Extract<keyof OutputOf<S>, (typeof RESERVED_FIELDS)[number]>;
|
|
316
|
+
/** The checks on one user type: its login, its e-mail, and its field names. */
|
|
317
|
+
type CheckType<Def, SchemaKey extends string> = (Def extends {
|
|
318
|
+
readonly password: {
|
|
319
|
+
readonly login: infer L;
|
|
320
|
+
};
|
|
321
|
+
} ? {
|
|
322
|
+
readonly password: {
|
|
323
|
+
readonly login: CheckName<L, RequiredStringKeys<OutputOf<SchemaOf<Def, SchemaKey>>>, 'a required string field'>;
|
|
324
|
+
};
|
|
325
|
+
} : unknown) & (Def extends {
|
|
326
|
+
readonly email: infer E;
|
|
327
|
+
} ? {
|
|
328
|
+
readonly email: CheckName<E, RequiredStringKeys<OutputOf<SchemaOf<Def, SchemaKey>>>, 'a required string field'>;
|
|
329
|
+
} : unknown) & ([Reserved<SchemaOf<Def, SchemaKey>>] extends [never] ? unknown : {
|
|
330
|
+
readonly [K in SchemaKey]: {
|
|
331
|
+
readonly [M in `"${Reserved<SchemaOf<Def, SchemaKey>> & string}" is a field janus sets itself; rename it`]: never;
|
|
332
|
+
};
|
|
333
|
+
});
|
|
334
|
+
type SchemaOf<Def, SchemaKey extends string> = Def extends {
|
|
335
|
+
readonly [K in SchemaKey]: infer S extends UserSchema;
|
|
336
|
+
} ? S : never;
|
|
337
|
+
/**
|
|
338
|
+
* The compile-time checks `janus` intersects into its parameter.
|
|
339
|
+
*
|
|
340
|
+
* `janus` infers its argument, so an excess-property check never fires;
|
|
341
|
+
* intersecting `C & Checked<C>` makes a wrong value unassignable **on the
|
|
342
|
+
* offending key**, with the reason as the type the compiler prints. The pattern
|
|
343
|
+
* is measured in `nxgt-data/packages/mongo-kit/src/config/types.ts`.
|
|
344
|
+
*/
|
|
345
|
+
export type Checked<C> = C extends MultiTypeConfig ? {
|
|
346
|
+
readonly users: {
|
|
347
|
+
readonly [K in keyof C['users']]: K extends (typeof RESERVED_TYPES)[number] ? {
|
|
348
|
+
readonly [M in `"${K & string}" cannot name a user type: janus() answers a method of that name`]: never;
|
|
349
|
+
} : CheckType<C['users'][K], 'schema'>;
|
|
350
|
+
};
|
|
351
|
+
} : CheckType<C, 'user'>;
|
|
352
|
+
export {};
|
|
353
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/auth/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type ResolvedType } from './config';
|
|
2
|
+
import { type AnyUser, type Context } from './context';
|
|
3
|
+
import type { PasswordApi, ResetPasswordApi, UserTypeApi, VerifyEmailApi } from './types';
|
|
4
|
+
type Input = Record<string, unknown>;
|
|
5
|
+
/** Everything one user type answers. Which flows it has is decided by its types; all are built. */
|
|
6
|
+
export type AnyTypeApi = UserTypeApi<AnyUser, Input> & PasswordApi<AnyUser, Input, string> & VerifyEmailApi<AnyUser> & ResetPasswordApi<AnyUser>;
|
|
7
|
+
export declare function typeApi(context: Context, type: ResolvedType): AnyTypeApi;
|
|
8
|
+
export {};
|
|
9
|
+
//# sourceMappingURL=users.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"users.d.ts","sourceRoot":"","sources":["../../src/auth/users.ts"],"names":[],"mappings":"AAQA,OAAO,EAAkB,KAAK,YAAY,EAAE,MAAM,UAAU,CAAC;AAC7D,OAAO,EACN,KAAK,OAAO,EACZ,KAAK,OAAO,EAaZ,MAAM,WAAW,CAAC;AAInB,OAAO,KAAK,EAEX,WAAW,EACX,gBAAgB,EAChB,WAAW,EACX,cAAc,EACd,MAAM,SAAS,CAAC;AAEjB,KAAK,KAAK,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAErC,mGAAmG;AACnG,MAAM,MAAM,UAAU,GAAG,WAAW,CAAC,OAAO,EAAE,KAAK,CAAC,GACnD,WAAW,CAAC,OAAO,EAAE,KAAK,EAAE,MAAM,CAAC,GACnC,cAAc,CAAC,OAAO,CAAC,GACvB,gBAAgB,CAAC,OAAO,CAAC,CAAC;AAE3B,wBAAgB,OAAO,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,YAAY,GAAG,UAAU,CA2axE"}
|
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
import {
|
|
2
|
+
StoreConflict2,
|
|
3
|
+
NotFoundError2
|
|
4
|
+
} from "./index-6p56fpbe.js";
|
|
5
|
+
|
|
6
|
+
// src/ids/id.ts
|
|
7
|
+
var HEX = Array.from({ length: 256 }, (_, i) => i.toString(16).padStart(2, "0"));
|
|
8
|
+
var lastMs = -1;
|
|
9
|
+
var sequence = 0;
|
|
10
|
+
var SEQUENCE_MAX = 4095;
|
|
11
|
+
function mintId2(now = Date.now()) {
|
|
12
|
+
let ms = now;
|
|
13
|
+
if (ms === lastMs) {
|
|
14
|
+
sequence += 1;
|
|
15
|
+
if (sequence > SEQUENCE_MAX) {
|
|
16
|
+
ms = lastMs + 1;
|
|
17
|
+
sequence = 0;
|
|
18
|
+
}
|
|
19
|
+
} else if (ms > lastMs) {
|
|
20
|
+
sequence = 0;
|
|
21
|
+
} else {
|
|
22
|
+
ms = lastMs;
|
|
23
|
+
sequence += 1;
|
|
24
|
+
if (sequence > SEQUENCE_MAX) {
|
|
25
|
+
ms = lastMs + 1;
|
|
26
|
+
sequence = 0;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
lastMs = ms;
|
|
30
|
+
const bytes = new Uint8Array(16);
|
|
31
|
+
crypto.getRandomValues(bytes.subarray(8));
|
|
32
|
+
bytes[0] = ms / 2 ** 40 & 255;
|
|
33
|
+
bytes[1] = ms / 2 ** 32 & 255;
|
|
34
|
+
bytes[2] = ms / 2 ** 24 & 255;
|
|
35
|
+
bytes[3] = ms / 2 ** 16 & 255;
|
|
36
|
+
bytes[4] = ms / 2 ** 8 & 255;
|
|
37
|
+
bytes[5] = ms & 255;
|
|
38
|
+
bytes[6] = 112 | sequence >> 8 & 15;
|
|
39
|
+
bytes[7] = sequence & 255;
|
|
40
|
+
bytes[8] = 128 | bytes[8] & 63;
|
|
41
|
+
return `${HEX[bytes[0]]}${HEX[bytes[1]]}${HEX[bytes[2]]}${HEX[bytes[3]]}-${HEX[bytes[4]]}${HEX[bytes[5]]}-${HEX[bytes[6]]}${HEX[bytes[7]]}-${HEX[bytes[8]]}${HEX[bytes[9]]}-${HEX[bytes[10]]}${HEX[bytes[11]]}${HEX[bytes[12]]}${HEX[bytes[13]]}${HEX[bytes[14]]}${HEX[bytes[15]]}`;
|
|
42
|
+
}
|
|
43
|
+
var UUID_V7 = /^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/;
|
|
44
|
+
function isId2(value) {
|
|
45
|
+
return UUID_V7.test(value);
|
|
46
|
+
}
|
|
47
|
+
function mintedAt2(id) {
|
|
48
|
+
const hex = id.replace(/-/g, "").slice(0, 12);
|
|
49
|
+
return new Date(Number.parseInt(hex, 16));
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// src/auth/port/memory.ts
|
|
53
|
+
function createMemoryStores2() {
|
|
54
|
+
return {
|
|
55
|
+
users: memoryUserStore(),
|
|
56
|
+
sessions: memorySessionStore(),
|
|
57
|
+
tokens: memoryTokenStore()
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
var copy = (value) => structuredClone(value);
|
|
61
|
+
var keyOf = (type, login) => `${type}\x00${login}`;
|
|
62
|
+
function memoryUserStore() {
|
|
63
|
+
const byId = new Map;
|
|
64
|
+
const byLogin = new Map;
|
|
65
|
+
const takenBy = (type, logins, id) => logins.find((login) => {
|
|
66
|
+
const holder = byLogin.get(keyOf(type, login));
|
|
67
|
+
return holder !== undefined && holder !== id;
|
|
68
|
+
});
|
|
69
|
+
const taken = (operation, type, login) => new StoreConflict2("login", `${operation}: the login "${login}" is taken by another ${type}`, { login, userType: type, operation });
|
|
70
|
+
return {
|
|
71
|
+
async insertUser(record) {
|
|
72
|
+
const stored = byId.get(record.id);
|
|
73
|
+
if (stored !== undefined)
|
|
74
|
+
return copy(stored);
|
|
75
|
+
const collision = takenBy(record.type, record.logins, record.id);
|
|
76
|
+
if (collision !== undefined) {
|
|
77
|
+
throw taken("insertUser", record.type, collision);
|
|
78
|
+
}
|
|
79
|
+
const written = copy(record);
|
|
80
|
+
byId.set(written.id, written);
|
|
81
|
+
for (const login of written.logins) {
|
|
82
|
+
byLogin.set(keyOf(written.type, login), written.id);
|
|
83
|
+
}
|
|
84
|
+
return copy(written);
|
|
85
|
+
},
|
|
86
|
+
async findUser(id) {
|
|
87
|
+
const stored = byId.get(id);
|
|
88
|
+
return stored === undefined ? null : copy(stored);
|
|
89
|
+
},
|
|
90
|
+
async findUserByLogin(type, login) {
|
|
91
|
+
const id = byLogin.get(keyOf(type, login));
|
|
92
|
+
const stored = id === undefined ? undefined : byId.get(id);
|
|
93
|
+
return stored === undefined ? null : copy(stored);
|
|
94
|
+
},
|
|
95
|
+
async listUsers({ type, after, limit }) {
|
|
96
|
+
const ids = [...byId.values()].filter((user) => user.type === type).map((user) => user.id).filter((id) => after === null || id > after).sort();
|
|
97
|
+
const pageIds = ids.slice(0, limit);
|
|
98
|
+
const last = pageIds.at(-1);
|
|
99
|
+
return {
|
|
100
|
+
items: pageIds.map((id) => copy(byId.get(id))),
|
|
101
|
+
nextCursor: ids.length > limit && last !== undefined ? last : null
|
|
102
|
+
};
|
|
103
|
+
},
|
|
104
|
+
async updateUser(id, patch, ifVersion) {
|
|
105
|
+
const stored = byId.get(id);
|
|
106
|
+
if (stored === undefined) {
|
|
107
|
+
throw new NotFoundError2("updateUser: no user has this id", {
|
|
108
|
+
userId: id,
|
|
109
|
+
operation: "updateUser"
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
if (stored.version !== ifVersion) {
|
|
113
|
+
throw new StoreConflict2("version", `updateUser: expected version ${ifVersion}, found ${stored.version}`, {
|
|
114
|
+
userId: id,
|
|
115
|
+
expectedVersion: ifVersion,
|
|
116
|
+
actualVersion: stored.version,
|
|
117
|
+
operation: "updateUser"
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
if (patch.logins !== undefined) {
|
|
121
|
+
const collision = takenBy(stored.type, patch.logins, id);
|
|
122
|
+
if (collision !== undefined) {
|
|
123
|
+
throw taken("updateUser", stored.type, collision);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
const written = applyPatch(stored, copy(patch));
|
|
127
|
+
byId.set(id, written);
|
|
128
|
+
if (patch.logins !== undefined) {
|
|
129
|
+
for (const login of stored.logins) {
|
|
130
|
+
byLogin.delete(keyOf(stored.type, login));
|
|
131
|
+
}
|
|
132
|
+
for (const login of written.logins) {
|
|
133
|
+
byLogin.set(keyOf(written.type, login), id);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
return copy(written);
|
|
137
|
+
},
|
|
138
|
+
async deleteUser(id) {
|
|
139
|
+
const stored = byId.get(id);
|
|
140
|
+
if (stored === undefined)
|
|
141
|
+
return false;
|
|
142
|
+
byId.delete(id);
|
|
143
|
+
for (const login of stored.logins) {
|
|
144
|
+
byLogin.delete(keyOf(stored.type, login));
|
|
145
|
+
}
|
|
146
|
+
return true;
|
|
147
|
+
}
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
function applyPatch(stored, patch) {
|
|
151
|
+
return {
|
|
152
|
+
...stored,
|
|
153
|
+
schemaVersion: patch.schemaVersion ?? stored.schemaVersion,
|
|
154
|
+
active: patch.active ?? stored.active,
|
|
155
|
+
fields: patch.fields ?? stored.fields,
|
|
156
|
+
logins: patch.logins ?? stored.logins,
|
|
157
|
+
password: patch.password === undefined ? stored.password : patch.password,
|
|
158
|
+
emailVerifiedAt: patch.emailVerifiedAt === undefined ? stored.emailVerifiedAt : patch.emailVerifiedAt,
|
|
159
|
+
version: stored.version + 1,
|
|
160
|
+
updatedAt: patch.updatedAt
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
function memorySessionStore() {
|
|
164
|
+
const byId = new Map;
|
|
165
|
+
const byTokenHash = new Map;
|
|
166
|
+
const revoke = (id, stored, at) => {
|
|
167
|
+
byId.set(id, { ...stored, revokedAt: new Date(at) });
|
|
168
|
+
};
|
|
169
|
+
return {
|
|
170
|
+
async insertSession(record) {
|
|
171
|
+
if (byId.has(record.id))
|
|
172
|
+
return;
|
|
173
|
+
const written = copy(record);
|
|
174
|
+
byId.set(written.id, written);
|
|
175
|
+
byTokenHash.set(written.tokenHash, written.id);
|
|
176
|
+
},
|
|
177
|
+
async findSessionByTokenHash(tokenHash) {
|
|
178
|
+
const id = byTokenHash.get(tokenHash);
|
|
179
|
+
const stored = id === undefined ? undefined : byId.get(id);
|
|
180
|
+
return stored === undefined ? null : copy(stored);
|
|
181
|
+
},
|
|
182
|
+
async extendSession(id, expiresAt) {
|
|
183
|
+
const stored = byId.get(id);
|
|
184
|
+
if (stored === undefined || stored.revokedAt !== null)
|
|
185
|
+
return null;
|
|
186
|
+
const written = {
|
|
187
|
+
...stored,
|
|
188
|
+
expiresAt: new Date(expiresAt)
|
|
189
|
+
};
|
|
190
|
+
byId.set(id, written);
|
|
191
|
+
return copy(written);
|
|
192
|
+
},
|
|
193
|
+
async revokeSession(id, at) {
|
|
194
|
+
const stored = byId.get(id);
|
|
195
|
+
if (stored === undefined)
|
|
196
|
+
return false;
|
|
197
|
+
if (stored.revokedAt === null)
|
|
198
|
+
revoke(id, stored, at);
|
|
199
|
+
return true;
|
|
200
|
+
},
|
|
201
|
+
async revokeUserSessions(userId, at, except) {
|
|
202
|
+
let revoked = 0;
|
|
203
|
+
for (const [id, stored] of byId) {
|
|
204
|
+
if (stored.userId === userId && stored.revokedAt === null && id !== except) {
|
|
205
|
+
revoke(id, stored, at);
|
|
206
|
+
revoked += 1;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
return revoked;
|
|
210
|
+
},
|
|
211
|
+
async deleteUserSessions(userId) {
|
|
212
|
+
let deleted = 0;
|
|
213
|
+
for (const [id, stored] of byId) {
|
|
214
|
+
if (stored.userId === userId) {
|
|
215
|
+
byId.delete(id);
|
|
216
|
+
byTokenHash.delete(stored.tokenHash);
|
|
217
|
+
deleted += 1;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
return deleted;
|
|
221
|
+
},
|
|
222
|
+
async deleteExpiredSessions(before) {
|
|
223
|
+
let deleted = 0;
|
|
224
|
+
for (const [id, stored] of byId) {
|
|
225
|
+
if (stored.expiresAt.getTime() <= before.getTime()) {
|
|
226
|
+
byId.delete(id);
|
|
227
|
+
byTokenHash.delete(stored.tokenHash);
|
|
228
|
+
deleted += 1;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
return deleted;
|
|
232
|
+
}
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
function memoryTokenStore() {
|
|
236
|
+
const byTokenHash = new Map;
|
|
237
|
+
return {
|
|
238
|
+
async insertToken(record) {
|
|
239
|
+
if (byTokenHash.has(record.tokenHash))
|
|
240
|
+
return;
|
|
241
|
+
byTokenHash.set(record.tokenHash, copy(record));
|
|
242
|
+
},
|
|
243
|
+
async consumeToken(tokenHash, kind, at) {
|
|
244
|
+
const stored = byTokenHash.get(tokenHash);
|
|
245
|
+
if (stored === undefined || stored.kind !== kind)
|
|
246
|
+
return null;
|
|
247
|
+
const before = copy(stored);
|
|
248
|
+
if (stored.spentAt === null) {
|
|
249
|
+
byTokenHash.set(tokenHash, { ...stored, spentAt: new Date(at) });
|
|
250
|
+
}
|
|
251
|
+
return before;
|
|
252
|
+
},
|
|
253
|
+
async deleteUserTokens(userId) {
|
|
254
|
+
let deleted = 0;
|
|
255
|
+
for (const [tokenHash, stored] of byTokenHash) {
|
|
256
|
+
if (stored.userId === userId) {
|
|
257
|
+
byTokenHash.delete(tokenHash);
|
|
258
|
+
deleted += 1;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
return deleted;
|
|
262
|
+
}
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
export { mintId2, isId2, mintedAt2, createMemoryStores2 };
|
|
267
|
+
|
|
268
|
+
//# debugId=127433514BF2BB4B64756E2164756E21
|
|
269
|
+
//# sourceMappingURL=index-658b6mr2.js.map
|