@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.
Files changed (112) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +554 -0
  3. package/dist/auth/config.d.ts +201 -0
  4. package/dist/auth/config.d.ts.map +1 -0
  5. package/dist/auth/context.d.ts +87 -0
  6. package/dist/auth/context.d.ts.map +1 -0
  7. package/dist/auth/hashers.d.ts +35 -0
  8. package/dist/auth/hashers.d.ts.map +1 -0
  9. package/dist/auth/index.d.ts +9 -0
  10. package/dist/auth/index.d.ts.map +1 -0
  11. package/dist/auth/janus.d.ts +38 -0
  12. package/dist/auth/janus.d.ts.map +1 -0
  13. package/dist/auth/outage.d.ts +61 -0
  14. package/dist/auth/outage.d.ts.map +1 -0
  15. package/dist/auth/port/assert-stores.d.ts +16 -0
  16. package/dist/auth/port/assert-stores.d.ts.map +1 -0
  17. package/dist/auth/port/memory.d.ts +25 -0
  18. package/dist/auth/port/memory.d.ts.map +1 -0
  19. package/dist/auth/port/types.d.ts +393 -0
  20. package/dist/auth/port/types.d.ts.map +1 -0
  21. package/dist/auth/secrets.d.ts +17 -0
  22. package/dist/auth/secrets.d.ts.map +1 -0
  23. package/dist/auth/sessions.d.ts +31 -0
  24. package/dist/auth/sessions.d.ts.map +1 -0
  25. package/dist/auth/standard-schema.d.ts +41 -0
  26. package/dist/auth/standard-schema.d.ts.map +1 -0
  27. package/dist/auth/types.d.ts +353 -0
  28. package/dist/auth/types.d.ts.map +1 -0
  29. package/dist/auth/users.d.ts +9 -0
  30. package/dist/auth/users.d.ts.map +1 -0
  31. package/dist/chunks/index-658b6mr2.js +269 -0
  32. package/dist/chunks/index-658b6mr2.js.map +11 -0
  33. package/dist/chunks/index-6dytvy3h.js +93 -0
  34. package/dist/chunks/index-6dytvy3h.js.map +11 -0
  35. package/dist/chunks/index-6p56fpbe.js +147 -0
  36. package/dist/chunks/index-6p56fpbe.js.map +12 -0
  37. package/dist/chunks/index-fgb3t64y.js +77 -0
  38. package/dist/chunks/index-fgb3t64y.js.map +10 -0
  39. package/dist/conformance/assert.d.ts +36 -0
  40. package/dist/conformance/assert.d.ts.map +1 -0
  41. package/dist/conformance/cases/outage.d.ts +3 -0
  42. package/dist/conformance/cases/outage.d.ts.map +1 -0
  43. package/dist/conformance/cases/sessions.d.ts +3 -0
  44. package/dist/conformance/cases/sessions.d.ts.map +1 -0
  45. package/dist/conformance/cases/tokens.d.ts +3 -0
  46. package/dist/conformance/cases/tokens.d.ts.map +1 -0
  47. package/dist/conformance/cases/users.d.ts +3 -0
  48. package/dist/conformance/cases/users.d.ts.map +1 -0
  49. package/dist/conformance/describe.d.ts +74 -0
  50. package/dist/conformance/describe.d.ts.map +1 -0
  51. package/dist/conformance/fixtures.d.ts +11 -0
  52. package/dist/conformance/fixtures.d.ts.map +1 -0
  53. package/dist/conformance/index.d.ts +33 -0
  54. package/dist/conformance/index.d.ts.map +1 -0
  55. package/dist/conformance/index.js +1113 -0
  56. package/dist/conformance/index.js.map +18 -0
  57. package/dist/conformance/reference.d.ts +13 -0
  58. package/dist/conformance/reference.d.ts.map +1 -0
  59. package/dist/conformance/relations.d.ts +67 -0
  60. package/dist/conformance/relations.d.ts.map +1 -0
  61. package/dist/conformance/types.d.ts +71 -0
  62. package/dist/conformance/types.d.ts.map +1 -0
  63. package/dist/errors/janus-error.d.ts +259 -0
  64. package/dist/errors/janus-error.d.ts.map +1 -0
  65. package/dist/ids/id.d.ts +55 -0
  66. package/dist/ids/id.d.ts.map +1 -0
  67. package/dist/index.d.ts +30 -0
  68. package/dist/index.d.ts.map +1 -0
  69. package/dist/index.js +962 -0
  70. package/dist/index.js.map +19 -0
  71. package/dist/pagination/cursor-page.d.ts +53 -0
  72. package/dist/pagination/cursor-page.d.ts.map +1 -0
  73. package/dist/permissions/engine.d.ts +46 -0
  74. package/dist/permissions/engine.d.ts.map +1 -0
  75. package/dist/permissions/index.d.ts +24 -0
  76. package/dist/permissions/index.d.ts.map +1 -0
  77. package/dist/permissions/index.js +685 -0
  78. package/dist/permissions/index.js.map +15 -0
  79. package/dist/permissions/input.d.ts +29 -0
  80. package/dist/permissions/input.d.ts.map +1 -0
  81. package/dist/permissions/model.d.ts +368 -0
  82. package/dist/permissions/model.d.ts.map +1 -0
  83. package/dist/permissions/port/memory.d.ts +17 -0
  84. package/dist/permissions/port/memory.d.ts.map +1 -0
  85. package/dist/permissions/port/types.d.ts +84 -0
  86. package/dist/permissions/port/types.d.ts.map +1 -0
  87. package/dist/permissions/resolve.d.ts +59 -0
  88. package/dist/permissions/resolve.d.ts.map +1 -0
  89. package/dist/permissions/reverse.d.ts +53 -0
  90. package/dist/permissions/reverse.d.ts.map +1 -0
  91. package/dist/permissions/walk.d.ts +29 -0
  92. package/dist/permissions/walk.d.ts.map +1 -0
  93. package/dist/subjects/notation.d.ts +35 -0
  94. package/dist/subjects/notation.d.ts.map +1 -0
  95. package/dist/subjects/subject.d.ts +75 -0
  96. package/dist/subjects/subject.d.ts.map +1 -0
  97. package/dist/time/clock.d.ts +31 -0
  98. package/dist/time/clock.d.ts.map +1 -0
  99. package/dist/time/duration.d.ts +23 -0
  100. package/dist/time/duration.d.ts.map +1 -0
  101. package/docs/README.md +17 -0
  102. package/docs/guide/adapters.md +296 -0
  103. package/docs/guide/email-flows.md +146 -0
  104. package/docs/guide/errors.md +146 -0
  105. package/docs/guide/passwords.md +136 -0
  106. package/docs/guide/permissions.md +347 -0
  107. package/docs/guide/sessions.md +211 -0
  108. package/docs/guide/users.md +277 -0
  109. package/docs/guide/vocabulary.md +163 -0
  110. package/docs/roadmap.md +93 -0
  111. package/docs/troubleshooting.md +648 -0
  112. package/package.json +70 -0
@@ -0,0 +1,201 @@
1
+ /**
2
+ * What `janus()` accepts, and how it is resolved at run time.
3
+ *
4
+ * The types refuse first, on the offending key (`checks.ts`). What follows at
5
+ * run time is the net for JavaScript callers, and every refusal is a bare
6
+ * `TypeError`: a configuration is written when the application is wired, never
7
+ * from a request.
8
+ */
9
+ import type { RelationStore } from '../permissions/port/types';
10
+ import type { Clock } from '../time/clock';
11
+ import { type Duration } from '../time/duration';
12
+ import type { JanusStores } from './port/types';
13
+ import type { StandardSchemaV1 } from './standard-schema';
14
+ /**
15
+ * How a login is normalised before any store sees it. `'lowercaseTrim'` when
16
+ * absent — right for an e-mail and for most usernames.
17
+ *
18
+ * A function is accepted for anything else. It must be deterministic: the same
19
+ * rule normalises at sign-up and at sign-in.
20
+ */
21
+ export type Normalize = 'none' | 'lowercase' | 'lowercaseTrim' | 'nfkcLowercaseTrim' | ((value: string) => string);
22
+ /**
23
+ * What a user schema may produce: JSON, where an object property may also be
24
+ * `undefined` — which is what every validator's optional field produces.
25
+ *
26
+ * The core drops an `undefined` property before a store sees the fields, so the
27
+ * port stays strict JSON: an optional field left out is **absent** in the
28
+ * store, and reads back absent, which the schema's output type already allows.
29
+ */
30
+ export type FieldsJson = string | number | boolean | null | readonly FieldsJson[] | {
31
+ readonly [key: string]: FieldsJson | undefined;
32
+ };
33
+ /**
34
+ * A user type's schema: any Standard Schema — Zod 4, Valibot, ArkType — whose
35
+ * output is an object of JSON. A `Date` round-trips through one store and not
36
+ * the next, so a schema that produces one is refused at compile time.
37
+ */
38
+ export type UserSchema = StandardSchemaV1<unknown, {
39
+ readonly [key: string]: FieldsJson | undefined;
40
+ }>;
41
+ /**
42
+ * A password hashing scheme — the second port.
43
+ *
44
+ * Hashes are self-describing, so **every wired hasher can verify, and exactly
45
+ * one hashes** new passwords. A database written under Bun reads under Node and
46
+ * back, as long as a verifier for each prefix is wired.
47
+ */
48
+ export interface PasswordHasher {
49
+ /** The prefix every hash it writes starts with: `'$argon2id$'`, `'$scrypt$'`. */
50
+ readonly prefix: string;
51
+ hash(plain: string): Promise<string>;
52
+ verify(plain: string, hash: string): Promise<boolean>;
53
+ /**
54
+ * Whether a hash **this hasher** wrote should be written again: its
55
+ * parameters are not the ones `hash` uses now — a raised `cost`, say.
56
+ * Optional; without it only a hash from another hasher (a `verifiers` one)
57
+ * is rewritten. Called with hashes carrying this hasher's prefix only.
58
+ */
59
+ needsRehash?(hash: string): boolean;
60
+ }
61
+ /** Signing in with a password. */
62
+ export interface PasswordConfig {
63
+ /**
64
+ * The field users sign in with: a **top-level, required string** field of
65
+ * the schema — `'email'`, `'username'`. A typo is a compile error.
66
+ */
67
+ readonly login: string;
68
+ /** `'lowercaseTrim'` when absent. */
69
+ readonly normalize?: Normalize;
70
+ /** At least 1. `8` when absent. */
71
+ readonly minLength?: number;
72
+ }
73
+ /** How long a session lives, and when it is renewed. */
74
+ export interface SessionConfig {
75
+ /** `'7d'` when absent. */
76
+ readonly lifespan?: Duration;
77
+ /**
78
+ * `authenticate` renews a session once this much has passed since it was
79
+ * opened or last renewed — a sliding session, written at most once per
80
+ * period. `'1d'` when absent; `false` for a fixed lifespan.
81
+ */
82
+ readonly renewAfter?: Duration | false;
83
+ }
84
+ /** One kind of user: its schema, and how it signs in. */
85
+ export interface UserTypeConfig {
86
+ readonly schema: UserSchema;
87
+ readonly password?: PasswordConfig;
88
+ /**
89
+ * The field holding the user's e-mail, which `verifyEmail` and
90
+ * `resetPassword` send to. `'email'` when absent — and when the schema has
91
+ * no required string `email` either, those two flows do not exist on the
92
+ * type.
93
+ */
94
+ readonly email?: string;
95
+ readonly session?: SessionConfig;
96
+ /**
97
+ * Recorded on every user written, and read by nothing yet. Bump it when the
98
+ * schema tightens, and the users validated against the old one can be found.
99
+ * `'1'` when absent.
100
+ */
101
+ readonly schemaVersion?: string;
102
+ }
103
+ /** The session cookie. Every default is the strict one. */
104
+ export interface CookieConfig {
105
+ /** `'janus-session'` when absent. A cookie-name token: no space, no `;`, no `=`. */
106
+ readonly name?: string;
107
+ readonly domain?: string;
108
+ /** `'/'` when absent. */
109
+ readonly path?: string;
110
+ /** `'lax'` when absent. */
111
+ readonly sameSite?: 'lax' | 'strict' | 'none';
112
+ /** `true` when absent. `sameSite: 'none'` requires it. */
113
+ readonly secure?: boolean;
114
+ }
115
+ interface SharedConfig {
116
+ /** The three stores: `createMemoryStores()`, or an adapter's. */
117
+ readonly store: JanusStores;
118
+ /**
119
+ * The relation store `permissions()` is given, when the application has
120
+ * one. Wired here, deleting a user deletes every tuple naming them too — as
121
+ * a subject, and through no one else's memory of it.
122
+ */
123
+ readonly relations?: RelationStore;
124
+ /**
125
+ * Hashes new passwords. **Required as soon as a type signs in with a
126
+ * password** — there is no silent fallback. `scryptHasher()` runs on Node and
127
+ * Bun; `bunHasher()` is argon2id, on Bun only.
128
+ */
129
+ readonly hasher?: PasswordHasher;
130
+ /** Hashers that only verify: those a database was written with before. */
131
+ readonly verifiers?: readonly PasswordHasher[];
132
+ readonly clock?: Clock;
133
+ readonly cookie?: CookieConfig;
134
+ readonly tokens?: {
135
+ /** `'24h'` when absent. */
136
+ readonly verifyEmail?: Duration;
137
+ /** `'1h'` when absent. */
138
+ readonly resetPassword?: Duration;
139
+ };
140
+ }
141
+ /** An application with one kind of user: `user` is its schema. */
142
+ export interface SingleTypeConfig extends SharedConfig, Omit<UserTypeConfig, 'schema'> {
143
+ readonly user: UserSchema;
144
+ readonly users?: never;
145
+ }
146
+ /** An application with several kinds of user — patients and staff. */
147
+ export interface MultiTypeConfig extends SharedConfig {
148
+ readonly users: {
149
+ readonly [type: string]: UserTypeConfig;
150
+ };
151
+ readonly user?: never;
152
+ readonly password?: never;
153
+ readonly email?: never;
154
+ readonly session?: never;
155
+ readonly schemaVersion?: never;
156
+ }
157
+ export type JanusConfig = SingleTypeConfig | MultiTypeConfig;
158
+ /** The type name the single-type form gives its users. */
159
+ export declare const SINGLE_TYPE = "user";
160
+ /**
161
+ * Keys `janus` sets on every user, so a schema may not declare them.
162
+ * `password` too: it is taken beside the fields, and never stored among them.
163
+ */
164
+ export declare const RESERVED_FIELDS: readonly ["id", "type", "emailVerified", "active", "hasPassword", "version", "createdAt", "updatedAt", "password"];
165
+ /** Names on `janus()`'s answer, so a user type may not take one. */
166
+ export declare const RESERVED_TYPES: readonly ["authenticate", "signOut", "signOutEverywhere", "findUser", "getUser", "cookie", "collectExpired", "types"];
167
+ /** One user type, with every default applied and every duration in milliseconds. */
168
+ export interface ResolvedType {
169
+ readonly name: string;
170
+ readonly schema: UserSchema;
171
+ readonly schemaVersion: string;
172
+ readonly password: {
173
+ readonly login: string;
174
+ readonly normalize: (value: string) => string;
175
+ readonly minLength: number;
176
+ } | null;
177
+ readonly email: string;
178
+ readonly lifespanMs: number;
179
+ readonly renewAfterMs: number | null;
180
+ }
181
+ export interface ResolvedConfig {
182
+ readonly single: boolean;
183
+ readonly types: ReadonlyMap<string, ResolvedType>;
184
+ readonly tokenTtlMs: {
185
+ readonly verifyEmail: number;
186
+ readonly resetPassword: number;
187
+ };
188
+ readonly cookie: {
189
+ readonly name: string;
190
+ readonly domain: string | null;
191
+ readonly path: string;
192
+ readonly sameSite: 'lax' | 'strict' | 'none';
193
+ readonly secure: boolean;
194
+ };
195
+ }
196
+ /** How an e-mail is compared: always the same rule, whatever the login's. */
197
+ export declare const normalizeEmail: (value: string) => string;
198
+ /** Applies the defaults and refuses what cannot be wired. `where` names the call. */
199
+ export declare function resolveConfig(config: JanusConfig, where: string): ResolvedConfig;
200
+ export {};
201
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/auth/config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,87 @@
1
+ /**
2
+ * What every operation of the core shares: the resolved configuration, the
3
+ * guarded stores, the clock, the hashers — and the handful of steps every
4
+ * operation takes the same way.
5
+ *
6
+ * Internal and degenericised: fields are a `JsonObject` here, and `janus()`
7
+ * casts once, at the boundary, after the schema has validated them.
8
+ */
9
+ import type { RelationStore } from '../permissions/port/types';
10
+ import type { Clock } from '../time/clock';
11
+ import { type PasswordHasher, type ResolvedConfig, type ResolvedType } from './config';
12
+ import type { JanusStores, JsonObject, StoreCapabilities, UserPatch, UserRecord } from './port/types';
13
+ import type { User, UserRef, WriteOptions } from './types';
14
+ export interface Context {
15
+ readonly config: ResolvedConfig;
16
+ /** Already guarded by `outage.ts`. */
17
+ readonly store: JanusStores;
18
+ /** Already guarded. `null` when no relation store is wired. */
19
+ readonly relations: RelationStore | null;
20
+ readonly capabilities: StoreCapabilities;
21
+ readonly clock: Clock;
22
+ readonly hasher: PasswordHasher | null;
23
+ /** The hasher first, then every verifier: whoever claims a prefix verifies it. */
24
+ readonly verifiers: readonly PasswordHasher[];
25
+ /** Hashed once, lazily: what a missing user's password is compared against. */
26
+ dummyHash(): Promise<string>;
27
+ }
28
+ export declare function createContext(config: ResolvedConfig, store: JanusStores, relations: RelationStore | null, capabilities: StoreCapabilities, clock: Clock, hasher: PasswordHasher | null, verifiers: readonly PasswordHasher[]): Context;
29
+ /** A user of any type, as the degenericised core handles them. */
30
+ export type AnyUser = User<string, Record<string, unknown>>;
31
+ /**
32
+ * A user as application code sees it: their fields at the top level, then
33
+ * what `janus` sets — written last, so no stored key can shadow it. No password
34
+ * hash, ever.
35
+ */
36
+ export declare function toUser(record: UserRecord): AnyUser;
37
+ /** The id a {@link UserRef} names. */
38
+ export declare const idOf: (user: UserRef) => string;
39
+ /**
40
+ * Validates fields against the type's schema, and answers them as the port
41
+ * holds them: an `undefined` property dropped, at every depth.
42
+ */
43
+ export declare function validateFields(type: ResolvedType, input: unknown, where: string): Promise<JsonObject>;
44
+ /** The user's e-mail, as stored, or `null` when the schema let it be absent. */
45
+ export declare function emailOf(type: ResolvedType, fields: JsonObject): string | null;
46
+ /**
47
+ * What a user signs in with, normalised: the login field, by its own rule,
48
+ * and the e-mail, by the e-mail rule — so a user whose login is a username can
49
+ * still be found by the e-mail a reset is requested for.
50
+ */
51
+ export declare function loginsOf(type: ResolvedType, fields: JsonObject): string[];
52
+ /** Refuses a password shorter than the policy. Reports the policy, never the password. */
53
+ export declare function checkPassword(type: ResolvedType, password: string, where: string): void;
54
+ /** The hasher. `janus()` refused a password type without one, so this is a wiring net. */
55
+ export declare function requireHasher(context: Context, where: string): PasswordHasher;
56
+ /**
57
+ * Whether `password` matches the stored hash. A hash whose prefix no wired
58
+ * verifier claims is `HASH_UNSUPPORTED`, reporting the prefix, never the hash.
59
+ */
60
+ export declare function passwordMatches(context: Context, record: UserRecord, password: string, where: string): Promise<boolean>;
61
+ /**
62
+ * The record, with its password hash rewritten by the current hasher when the
63
+ * stored one is stale: written by another hasher — a `verifiers` one — or by
64
+ * this one with other parameters. Called only once `password` has matched.
65
+ *
66
+ * The rewrite is conditioned on the version just read. Losing that race to a
67
+ * concurrent update is not the sign-in's failure: the record is answered as
68
+ * read, and the next sign-in tries again. A store failure still throws.
69
+ */
70
+ export declare function rehashed(context: Context, record: UserRecord, password: string): Promise<UserRecord>;
71
+ /**
72
+ * The user — of this type, when one is given — or `null`. A malformed id is an
73
+ * absence decided without reaching the store: it arrives off a URL, and it is
74
+ * "no such user", not a query and not an outage. A user of another type is
75
+ * absent too: `auth.staff.find(patientId)` finds nobody.
76
+ */
77
+ export declare function findRecord(context: Context, id: string, type: string | null): Promise<UserRecord | null>;
78
+ /** The user, or `NOT_FOUND`. */
79
+ export declare function getRecord(context: Context, id: string, type: string | null, where: string): Promise<UserRecord>;
80
+ /**
81
+ * One write that follows a read, under a version: the core reads the user,
82
+ * checks `ifVersion` against what it read, computes the patch from the record,
83
+ * and writes under the version it read. A user who changed in between is
84
+ * `VERSION_CONFLICT`, and nothing is written.
85
+ */
86
+ export declare function writeUser(context: Context, user: UserRef, type: ResolvedType, options: WriteOptions | undefined, where: string, patchOf: (record: UserRecord, now: Date) => Omit<UserPatch, 'updatedAt'> | Promise<Omit<UserPatch, 'updatedAt'>>): Promise<UserRecord>;
87
+ //# sourceMappingURL=context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../src/auth/context.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,35 @@
1
+ import type { PasswordHasher } from './config';
2
+ /**
3
+ * scrypt through `node:crypto` — the hasher that runs **everywhere**: Node and
4
+ * Bun both implement it, and it needs no dependency.
5
+ *
6
+ * Measured before choosing it: `bun build --target node` leaves `Bun.password`
7
+ * in the output as it is — a target changes the bundle's format, not which
8
+ * APIs exist — and `crypto.argon2` is absent from Node 22. scrypt is the one
9
+ * memory-hard function both runtimes ship.
10
+ *
11
+ * The defaults are OWASP's: N = 2^17, r = 8, p = 1, about 128 MiB per hash.
12
+ * The parameters are written into the hash —
13
+ * `$scrypt$ln=17,r=8,p=1$<salt>$<key>` — and read back from it to verify, so
14
+ * raising `cost` later leaves every existing hash readable.
15
+ *
16
+ * `cost` is log2(N). Lower it only in tests: 10 is fast and still exercises
17
+ * every line.
18
+ *
19
+ * A hash written with other parameters than these is rewritten with these the
20
+ * next time its owner signs in (`needsRehash`), so raising `cost` reaches every
21
+ * active user without a migration.
22
+ */
23
+ export declare function scryptHasher(options?: {
24
+ readonly cost?: number;
25
+ }): PasswordHasher;
26
+ /**
27
+ * argon2id through `Bun.password`.
28
+ *
29
+ * **Loaded only when named**: nothing reads `Bun` until this function is called,
30
+ * so the package imports cleanly under Node. On Node, `scryptHasher()` is the
31
+ * hasher; a hash written here reads anywhere a verifier for `$argon2id$` is
32
+ * wired, so a database can move between the two runtimes.
33
+ */
34
+ export declare function bunHasher(): PasswordHasher;
35
+ //# sourceMappingURL=hashers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hashers.d.ts","sourceRoot":"","sources":["../../src/auth/hashers.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAE/C;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,YAAY,CAAC,OAAO,CAAC,EAAE;IACtC,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;CACvB,GAAG,cAAc,CAoDjB;AA+BD;;;;;;;GAOG;AACH,wBAAgB,SAAS,IAAI,cAAc,CAkB1C"}
@@ -0,0 +1,9 @@
1
+ export type { CookieConfig, FieldsJson, JanusConfig, MultiTypeConfig, Normalize, PasswordConfig, PasswordHasher, SessionConfig, SingleTypeConfig, UserSchema, UserTypeConfig, } from './config';
2
+ export { bunHasher, scryptHasher } from './hashers';
3
+ export { janus } from './janus';
4
+ export { assertStores } from './port/assert-stores';
5
+ export { createMemoryStores } from './port/memory';
6
+ export type { JanusStores, Json, JsonObject, PasswordRecord, SessionId, SessionRecord, SessionStore, StoreCapabilities, TokenKind, TokenRecord, TokenStore, UserPageRequest, UserPatch, UserRecord, UserStore, } from './port/types';
7
+ export type { StandardSchemaV1 } from './standard-schema';
8
+ export type { Authenticated, Checked, EmailOf, HeaderRecord, IssuedToken, Janus, LoginOf, PasswordApi, RequestLike, RequiredStringKeys, ResetPasswordApi, Session, SharedApi, SignedIn, TypeApi, TypesOf, User, UserBase, UserOf, UserRef, UserTypeApi, VerifyEmailApi, WriteOptions, } from './types';
9
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/auth/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACX,YAAY,EACZ,UAAU,EACV,WAAW,EACX,eAAe,EACf,SAAS,EACT,cAAc,EACd,cAAc,EACd,aAAa,EACb,gBAAgB,EAChB,UAAU,EACV,cAAc,GACd,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACpD,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACpD,OAAO,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AACnD,YAAY,EACX,WAAW,EACX,IAAI,EACJ,UAAU,EACV,cAAc,EACd,SAAS,EACT,aAAa,EACb,YAAY,EACZ,iBAAiB,EACjB,SAAS,EACT,WAAW,EACX,UAAU,EACV,eAAe,EACf,SAAS,EACT,UAAU,EACV,SAAS,GACT,MAAM,cAAc,CAAC;AACtB,YAAY,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAC1D,YAAY,EACX,aAAa,EACb,OAAO,EACP,OAAO,EACP,YAAY,EACZ,WAAW,EACX,KAAK,EACL,OAAO,EACP,WAAW,EACX,WAAW,EACX,kBAAkB,EAClB,gBAAgB,EAChB,OAAO,EACP,SAAS,EACT,QAAQ,EACR,OAAO,EACP,OAAO,EACP,IAAI,EACJ,QAAQ,EACR,MAAM,EACN,OAAO,EACP,WAAW,EACX,cAAc,EACd,YAAY,GACZ,MAAM,SAAS,CAAC"}
@@ -0,0 +1,38 @@
1
+ import { type JanusConfig } from './config';
2
+ import type { Checked, Janus } from './types';
3
+ /**
4
+ * Wires authentication over the store the application opened. **Synchronous,
5
+ * and does no I/O**: it connects to nothing.
6
+ *
7
+ * ```ts
8
+ * // One kind of user
9
+ * const auth = janus({
10
+ * user: z.object({ email: z.email(), name: z.string() }),
11
+ * password: { login: 'email' },
12
+ * store: createMemoryStores(),
13
+ * hasher: scryptHasher(),
14
+ * });
15
+ * const { user, token } = await auth.signUp({ email, name, password });
16
+ *
17
+ * // Several
18
+ * const auth = janus({
19
+ * users: {
20
+ * patient: { schema: Patient, password: { login: 'email' } },
21
+ * staff: { schema: Staff, password: { login: 'email' }, session: { lifespan: '8h' } },
22
+ * },
23
+ * store, hasher,
24
+ * });
25
+ * await auth.staff.signIn({ email, password });
26
+ * const current = await auth.authenticate(request, { type: 'staff' });
27
+ * ```
28
+ *
29
+ * The types refuse first, on the offending key: a login or an e-mail that
30
+ * names no required string field, a schema declaring a field `janus` sets, a
31
+ * user type named like a method. What follows at run time is the net for
32
+ * JavaScript callers, each a bare `TypeError` because only wiring produces one:
33
+ * a store slot missing or incomplete; a password type with no hasher — there
34
+ * is no silent fallback; two hashers claiming the same prefix, which would make
35
+ * verification depend on the order they were listed in.
36
+ */
37
+ export declare function janus<const C extends JanusConfig>(config: C & Checked<C>): Janus<C>;
38
+ //# sourceMappingURL=janus.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"janus.d.ts","sourceRoot":"","sources":["../../src/auth/janus.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,WAAW,EAAiB,MAAM,UAAU,CAAC;AAK3D,OAAO,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAG9C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,wBAAgB,KAAK,CAAC,KAAK,CAAC,CAAC,SAAS,WAAW,EAChD,MAAM,EAAE,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,GACpB,KAAK,CAAC,CAAC,CAAC,CAyDV"}
@@ -0,0 +1,61 @@
1
+ /**
2
+ * **The one place a store call is caught, and the one place a `null` becomes an
3
+ * error.**
4
+ *
5
+ * The transposition of `call.ts` in `nxgt-ory`'s SDK — "the only place a call
6
+ * is unwrapped" — into a core with no status codes. The invariant this whole
7
+ * package is built around is checked by reading this file:
8
+ *
9
+ * > An absence is `null`. A failure throws.
10
+ *
11
+ * `outage.spec.ts` reads every other file of `src/auth/` and fails if a
12
+ * `catch` appears in one, because the failure this design exists to prevent is
13
+ * a single careless `catch { return null }`. There are two `catch`es below: the
14
+ * guard's always rethrows, and {@link unlessVersionConflict}'s absorbs one
15
+ * named conflict and rethrows everything else. The spec holds both to that.
16
+ */
17
+ import { type JanusError } from '../errors/janus-error';
18
+ import type { RelationStore } from '../permissions/port/types';
19
+ import type { JanusStores } from './port/types';
20
+ /**
21
+ * The stores, with every method guarded.
22
+ *
23
+ * - A `JanusError` the adapter threw — `StoreFailure`, `StoreConflict`,
24
+ * `NotFoundError` — passes through untouched, so `instanceof` still holds.
25
+ * - **Anything else it threw is a failure**: a driver error, a `TypeError` from
26
+ * a bug in the adapter, a string. It becomes `StoreFailure` with the original
27
+ * as `cause`, naming the slot and the method. It is never an absence.
28
+ * - A method that answers `undefined` where the port says `null` is a store
29
+ * that forgot to answer, and becomes `StoreFailure` rather than "not found".
30
+ * Rule 2 of the port, enforced at run time for the JavaScript adapter the
31
+ * compiler never saw.
32
+ *
33
+ * The optional `deleteExpiredSessions` is guarded when present and left absent
34
+ * when absent, so capability detection still reads the truth.
35
+ */
36
+ export declare function guardStores(stores: JanusStores): JanusStores;
37
+ /**
38
+ * The relation store, guarded the same way: the permission engine's only way
39
+ * to a store, so a failure there is `STORE_FAILED` and never a denial.
40
+ */
41
+ export declare function guardRelations(store: RelationStore): RelationStore;
42
+ /**
43
+ * A value the caller requires, or the refusal an absence deserves.
44
+ *
45
+ * The only place in the core where a `null` from a store turns into an error —
46
+ * `get` becoming `NOT_FOUND`. Written as a function so that the conversion is
47
+ * visible at every call site and nowhere else.
48
+ */
49
+ export declare function required<T>(value: T | null, absent: () => JanusError): T;
50
+ /**
51
+ * A write that may lose a race, and is allowed to: its answer, or `null` when
52
+ * the record's version moved under it.
53
+ *
54
+ * **Only `StoreConflict('version')` is absorbed.** A failure still throws, a
55
+ * taken login still throws, `NOT_FOUND` still throws: an outage never reads as
56
+ * "somebody else wrote first". It exists for writes the caller did not ask for
57
+ * — rewriting a password hash on sign-in — where losing to a concurrent update
58
+ * means only that the next sign-in tries again.
59
+ */
60
+ export declare function unlessVersionConflict<T>(write: Promise<T>): Promise<T | null>;
61
+ //# sourceMappingURL=outage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"outage.d.ts","sourceRoot":"","sources":["../../src/auth/outage.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EACN,KAAK,UAAU,EAIf,MAAM,uBAAuB,CAAC;AAC/B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAWhD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,WAAW,GAAG,WAAW,CAM5D;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,aAAa,GAAG,aAAa,CAElE;AA+DD;;;;;;GAMG;AACH,wBAAgB,QAAQ,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,GAAG,IAAI,EAAE,MAAM,EAAE,MAAM,UAAU,GAAG,CAAC,CAGxE;AAED;;;;;;;;;GASG;AACH,wBAAsB,qBAAqB,CAAC,CAAC,EAC5C,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC,GACf,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,CAOnB"}
@@ -0,0 +1,16 @@
1
+ import type { StoreCapabilities } from './types';
2
+ /**
3
+ * Checks that every slot answers every method the port declares, and reports
4
+ * the optional capabilities found.
5
+ *
6
+ * TypeScript already refuses a partial store and names the missing method;
7
+ * this is the net for a JavaScript caller, and for a store assembled from
8
+ * `any`. A bare `TypeError`, because a missing method can only come from how
9
+ * the application was wired — no request produces one, and no handler should
10
+ * answer one.
11
+ *
12
+ * `where` names the call the consumer wrote — `janus` — so the
13
+ * sentence says which call to fix and which slot to change.
14
+ */
15
+ export declare function assertStores(stores: unknown, where: string): StoreCapabilities;
16
+ //# sourceMappingURL=assert-stores.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"assert-stores.d.ts","sourceRoot":"","sources":["../../../src/auth/port/assert-stores.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAe,iBAAiB,EAAE,MAAM,SAAS,CAAC;AA6B9D;;;;;;;;;;;;GAYG;AACH,wBAAgB,YAAY,CAC3B,MAAM,EAAE,OAAO,EACf,KAAK,EAAE,MAAM,GACX,iBAAiB,CAmCnB"}
@@ -0,0 +1,25 @@
1
+ import type { JanusStores } from './types';
2
+ /**
3
+ * The reference implementation of the store port, in memory.
4
+ *
5
+ * **Shipped and documented, not a test helper.** It is what a consumer uses in
6
+ * their own unit tests, and what an adapter author compares against when a
7
+ * conformance case they do not understand turns red. So it keeps the six rules
8
+ * for real rather than approximately:
9
+ *
10
+ * - uniqueness is a constraint — an index checked and written inside the same
11
+ * synchronous step, which is what atomic means on one event loop;
12
+ * - `consumeToken` reads and writes with no `await` between the two, so twenty
13
+ * concurrent calls see exactly one unspent token;
14
+ * - every record is **copied in and copied out**, so a caller that mutates what
15
+ * it passed or what it got back cannot reach the store — the in-memory
16
+ * version of "bytes round-trip";
17
+ * - a patch applies only the fields it names, and only the fields the port
18
+ * declares: a stray `version` or `id` in a patch from JavaScript is ignored,
19
+ * not written.
20
+ *
21
+ * Every method is `async` even though none waits on anything: a caller that
22
+ * forgot an `await` must fail here the way it would against a real database.
23
+ */
24
+ export declare function createMemoryStores(): JanusStores;
25
+ //# sourceMappingURL=memory.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memory.d.ts","sourceRoot":"","sources":["../../../src/auth/port/memory.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACX,WAAW,EASX,MAAM,SAAS,CAAC;AAEjB;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,kBAAkB,IAAI,WAAW,CAMhD"}