@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,259 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What this package refuses, as a string a caller can switch on.
|
|
3
|
+
*
|
|
4
|
+
* Every code is a **refusal at call time, on a value that could have come from
|
|
5
|
+
* a request** — which is the rule that decides whether something belongs here
|
|
6
|
+
* or stays a bare `TypeError`. A refusal that can only come from how the
|
|
7
|
+
* application was wired (`janus()` with no schema, a lifespan that is
|
|
8
|
+
* not a duration, a store missing a method) throws a plain `TypeError`
|
|
9
|
+
* instead: no request handler should ever answer one, so no handler needs to
|
|
10
|
+
* tell it apart from the others.
|
|
11
|
+
*
|
|
12
|
+
* The codes are `SCREAMING_SNAKE`, and that is not an exception to this
|
|
13
|
+
* repository's camelCase rule — they are data values, not API identifiers, the
|
|
14
|
+
* same shape `code` has in `@nxgt/mongo` and `@nxgt/redis`. Every *key* in
|
|
15
|
+
* this package is camelCase.
|
|
16
|
+
*/
|
|
17
|
+
export type JanusErrorCode =
|
|
18
|
+
/**
|
|
19
|
+
* The store could not answer — a refused connection, a timeout, a primary
|
|
20
|
+
* stepping down, a deserialisation failure, a bug in the adapter.
|
|
21
|
+
*
|
|
22
|
+
* **Never a negative answer.** A handler answers 503 and lets the visitor
|
|
23
|
+
* retry. Mapping this to a 404, to `null` or to `false` turns an outage
|
|
24
|
+
* into a silent lockout: everybody who has an account is told they do not.
|
|
25
|
+
* That failure has been measured twice in this organisation, two days
|
|
26
|
+
* apart, and it is the reason this package's port is specified rather than
|
|
27
|
+
* merely documented.
|
|
28
|
+
*/
|
|
29
|
+
'STORE_FAILED'
|
|
30
|
+
/**
|
|
31
|
+
* The store answered, and there is no such record.
|
|
32
|
+
*
|
|
33
|
+
* Raised by the `get*` calls, never by the `find*` calls — those return
|
|
34
|
+
* `null`, which is a value the caller decides what to do with.
|
|
35
|
+
*/
|
|
36
|
+
| 'NOT_FOUND'
|
|
37
|
+
/**
|
|
38
|
+
* The login — an e-mail, a username — is already held by another user of
|
|
39
|
+
* the same type.
|
|
40
|
+
*
|
|
41
|
+
* Raised by the **store's own unique constraint** and surfaced here, never
|
|
42
|
+
* decided by reading first: two concurrent sign-ups both pass a read, and
|
|
43
|
+
* only a constraint refuses one of them. Carries `login` and `userType`.
|
|
44
|
+
*/
|
|
45
|
+
| 'LOGIN_TAKEN'
|
|
46
|
+
/**
|
|
47
|
+
* The record changed since it was read: the version it was expected to
|
|
48
|
+
* hold is no longer the version it holds, and **nothing was written**.
|
|
49
|
+
* Read it again and retry. Carries `expectedVersion` and `actualVersion`.
|
|
50
|
+
*/
|
|
51
|
+
| 'VERSION_CONFLICT'
|
|
52
|
+
/**
|
|
53
|
+
* The fields failed the user type's schema. Carries `issues`, whose paths
|
|
54
|
+
* are the fields' own, so a handler can answer 400 field by field.
|
|
55
|
+
*/
|
|
56
|
+
| 'USER_INVALID'
|
|
57
|
+
/**
|
|
58
|
+
* The password is shorter than the policy's minimum. Reports the policy,
|
|
59
|
+
* never the password.
|
|
60
|
+
*/
|
|
61
|
+
| 'PASSWORD_TOO_SHORT'
|
|
62
|
+
/**
|
|
63
|
+
* The login and the password do not match: no such login, no password set,
|
|
64
|
+
* or the wrong one — **one code for the three**, so a response cannot tell
|
|
65
|
+
* which accounts exist. `reason` tells them apart for your logs and your
|
|
66
|
+
* rate limiter, and never belongs in a response body.
|
|
67
|
+
*/
|
|
68
|
+
| 'CREDENTIALS_INVALID'
|
|
69
|
+
/**
|
|
70
|
+
* A stored hash whose prefix names no wired verifier — typically an import
|
|
71
|
+
* from a system whose format this core cannot read. Reports the prefix,
|
|
72
|
+
* never the hash.
|
|
73
|
+
*/
|
|
74
|
+
| 'HASH_UNSUPPORTED'
|
|
75
|
+
/**
|
|
76
|
+
* The user is inactive: the record and its password are kept, and every
|
|
77
|
+
* sign-in is refused. Only told to somebody who gave the right password.
|
|
78
|
+
*/
|
|
79
|
+
| 'USER_INACTIVE'
|
|
80
|
+
/** No token holds that secret. */
|
|
81
|
+
| 'TOKEN_UNKNOWN'
|
|
82
|
+
/**
|
|
83
|
+
* The token was already spent. Told apart from `TOKEN_UNKNOWN` for the
|
|
84
|
+
* message only — both are refusals, and the outcome is the same.
|
|
85
|
+
*/
|
|
86
|
+
| 'TOKEN_SPENT'
|
|
87
|
+
/**
|
|
88
|
+
* The token existed and its expiry has passed. It is spent all the same,
|
|
89
|
+
* so it cannot be retried.
|
|
90
|
+
*/
|
|
91
|
+
| 'TOKEN_EXPIRED'
|
|
92
|
+
/**
|
|
93
|
+
* The token was sent to an e-mail the user no longer has. Confirming it
|
|
94
|
+
* would verify an address nobody holds any more, so it is spent and refused.
|
|
95
|
+
*/
|
|
96
|
+
| 'TOKEN_STALE'
|
|
97
|
+
/** A cursor this store did not mint, or one written for another ordering.
|
|
98
|
+
* Never a silent first page: a caller paging a list would loop for ever. */
|
|
99
|
+
| 'INVALID_CURSOR'
|
|
100
|
+
/**
|
|
101
|
+
* The wired store does not implement the optional capability this call
|
|
102
|
+
* needs. Names the method and the slot, so the sentence says which store to
|
|
103
|
+
* change or which call to stop making.
|
|
104
|
+
*/
|
|
105
|
+
| 'UNSUPPORTED'
|
|
106
|
+
/**
|
|
107
|
+
* A permission check walked deeper than `maxDepth` relations without an
|
|
108
|
+
* answer. **Not a refusal**: an evaluation that stopped half-way has not
|
|
109
|
+
* decided anything, and answering `false` would hide a model that is too
|
|
110
|
+
* deep behind denials nobody can explain. A cycle in the data is not this —
|
|
111
|
+
* it is cut, silently. Carries `permission` and `maxDepth`.
|
|
112
|
+
*/
|
|
113
|
+
| 'PERMISSION_DEPTH';
|
|
114
|
+
/** One thing that was wrong with a user's fields, at one path. */
|
|
115
|
+
export interface Issue {
|
|
116
|
+
/** The path inside the fields, as the schema reported it: `['address', 'city']`. */
|
|
117
|
+
readonly path: readonly (string | number)[];
|
|
118
|
+
readonly message: string;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Why a sign-in was refused, for your logs and rate limiter.
|
|
122
|
+
*
|
|
123
|
+
* **Never put it in a response body.** `unknownLogin` is an account
|
|
124
|
+
* enumeration oracle.
|
|
125
|
+
*/
|
|
126
|
+
export type CredentialRefusal = 'unknownLogin' | 'noPassword' | 'wrongPassword';
|
|
127
|
+
/**
|
|
128
|
+
* What an error may carry beside its code.
|
|
129
|
+
*
|
|
130
|
+
* **No field here ever holds a secret.** Not a password, not a hash, not a
|
|
131
|
+
* session token, not a token secret, not a token's hash, and not a connection
|
|
132
|
+
* URI — a connection string holds a password, and the specs assert its absence
|
|
133
|
+
* from every message. A `login` may appear, because the caller just sent it.
|
|
134
|
+
*/
|
|
135
|
+
export interface JanusErrorOptions {
|
|
136
|
+
readonly userId?: string;
|
|
137
|
+
readonly userType?: string;
|
|
138
|
+
/** The login a conflict names: an address, never a secret. */
|
|
139
|
+
readonly login?: string;
|
|
140
|
+
readonly reason?: CredentialRefusal;
|
|
141
|
+
/** The prefix of a hash whose format is unknown. Never the hash. */
|
|
142
|
+
readonly hashPrefix?: string;
|
|
143
|
+
readonly expectedVersion?: number;
|
|
144
|
+
readonly actualVersion?: number;
|
|
145
|
+
readonly issues?: readonly Issue[];
|
|
146
|
+
/** The minimum the policy requires. Never the password that failed it. */
|
|
147
|
+
readonly minLength?: number;
|
|
148
|
+
/** The port method being called: `insertUser`, `consumeToken`. */
|
|
149
|
+
readonly operation?: string;
|
|
150
|
+
/** Which store slot: the sentence should say which store to change. */
|
|
151
|
+
readonly slot?: 'users' | 'sessions' | 'tokens' | 'relations';
|
|
152
|
+
/** The permission being checked, in the notation: `record:r1#view`. */
|
|
153
|
+
readonly permission?: string;
|
|
154
|
+
/** The depth a check may walk. */
|
|
155
|
+
readonly maxDepth?: number;
|
|
156
|
+
readonly cause?: unknown;
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* The base of everything this package throws at call time.
|
|
160
|
+
*
|
|
161
|
+
* It extends `Error` and not `TypeError`, and the rule behind that is
|
|
162
|
+
* `nxgt-data`'s: *extend whichever class the refusals it replaces already
|
|
163
|
+
* threw, so no consumer's `catch` stops working*. These replace nothing — the
|
|
164
|
+
* package is new — and `DataError`, `RedisError` and `S3Error` all extend
|
|
165
|
+
* `Error`, so nobody has to order their `catch` blocks.
|
|
166
|
+
*
|
|
167
|
+
* **There is exactly one definition of this class**, and that matters more here
|
|
168
|
+
* than it looks: an adapter in another package throws `StoreFailure` and this
|
|
169
|
+
* package tests it with `instanceof`. Two copies and the product is wrong about
|
|
170
|
+
* what an outage is. `build.ts` shares the module across entry points with
|
|
171
|
+
* `splitting: true`, and `scripts/verify-artifacts.ts` fails the build if any
|
|
172
|
+
* class name appears in two entry bundles of the packed tarball.
|
|
173
|
+
*/
|
|
174
|
+
export declare class JanusError extends Error {
|
|
175
|
+
name: string;
|
|
176
|
+
readonly code: JanusErrorCode;
|
|
177
|
+
readonly userId: string | undefined;
|
|
178
|
+
readonly userType: string | undefined;
|
|
179
|
+
readonly login: string | undefined;
|
|
180
|
+
readonly reason: CredentialRefusal | undefined;
|
|
181
|
+
readonly hashPrefix: string | undefined;
|
|
182
|
+
readonly expectedVersion: number | undefined;
|
|
183
|
+
readonly actualVersion: number | undefined;
|
|
184
|
+
readonly issues: readonly Issue[] | undefined;
|
|
185
|
+
readonly minLength: number | undefined;
|
|
186
|
+
readonly operation: string | undefined;
|
|
187
|
+
readonly slot: 'users' | 'sessions' | 'tokens' | 'relations' | undefined;
|
|
188
|
+
readonly permission: string | undefined;
|
|
189
|
+
readonly maxDepth: number | undefined;
|
|
190
|
+
constructor(message: string, options?: JanusErrorOptions);
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* The store could not answer.
|
|
194
|
+
*
|
|
195
|
+
* **This is the class an adapter throws**, and it is exported for that reason:
|
|
196
|
+
* an adapter defines no error class of its own, so `instanceof` holds across
|
|
197
|
+
* the two packages. Any other throw from a store is treated as a failure too —
|
|
198
|
+
* throwing this one is how an adapter says so precisely, and sets `cause`.
|
|
199
|
+
*/
|
|
200
|
+
export declare class StoreFailure extends JanusError {
|
|
201
|
+
name: string;
|
|
202
|
+
readonly code: "STORE_FAILED";
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* A uniqueness or a version constraint the store refused.
|
|
206
|
+
*
|
|
207
|
+
* Also thrown by an adapter, and also for the `instanceof` reason. `on` says
|
|
208
|
+
* which constraint, because the two are answered differently: a login
|
|
209
|
+
* collision is the caller's to fix, a version conflict is a retry.
|
|
210
|
+
*/
|
|
211
|
+
export declare class StoreConflict extends JanusError {
|
|
212
|
+
name: string;
|
|
213
|
+
readonly code: JanusErrorCode;
|
|
214
|
+
readonly on: 'login' | 'version';
|
|
215
|
+
constructor(on: 'login' | 'version', message: string, options?: JanusErrorOptions);
|
|
216
|
+
}
|
|
217
|
+
/** There is no such record, and the store said so. */
|
|
218
|
+
export declare class NotFoundError extends JanusError {
|
|
219
|
+
name: string;
|
|
220
|
+
readonly code: "NOT_FOUND";
|
|
221
|
+
}
|
|
222
|
+
/** The fields failed the user type's schema. */
|
|
223
|
+
export declare class UserInvalidError extends JanusError {
|
|
224
|
+
name: string;
|
|
225
|
+
readonly code: "USER_INVALID";
|
|
226
|
+
}
|
|
227
|
+
/** A password too short, credentials that do not match, or a hash format nobody reads. */
|
|
228
|
+
export declare class CredentialError extends JanusError {
|
|
229
|
+
name: string;
|
|
230
|
+
readonly code: JanusErrorCode;
|
|
231
|
+
constructor(code: Extract<JanusErrorCode, 'PASSWORD_TOO_SHORT' | 'CREDENTIALS_INVALID' | 'HASH_UNSUPPORTED'>, message: string, options?: JanusErrorOptions);
|
|
232
|
+
}
|
|
233
|
+
/** The user is inactive, and the password given was the right one. */
|
|
234
|
+
export declare class UserInactiveError extends JanusError {
|
|
235
|
+
name: string;
|
|
236
|
+
readonly code: "USER_INACTIVE";
|
|
237
|
+
}
|
|
238
|
+
/** A one-time token that is unknown, already spent, lapsed, or sent to an e-mail the user no longer has. */
|
|
239
|
+
export declare class TokenError extends JanusError {
|
|
240
|
+
name: string;
|
|
241
|
+
readonly code: JanusErrorCode;
|
|
242
|
+
constructor(code: Extract<JanusErrorCode, 'TOKEN_UNKNOWN' | 'TOKEN_SPENT' | 'TOKEN_EXPIRED' | 'TOKEN_STALE'>, message: string, options?: JanusErrorOptions);
|
|
243
|
+
}
|
|
244
|
+
/** A cursor this store did not mint, or one for another ordering. */
|
|
245
|
+
export declare class InvalidCursorError extends JanusError {
|
|
246
|
+
name: string;
|
|
247
|
+
readonly code: "INVALID_CURSOR";
|
|
248
|
+
}
|
|
249
|
+
/** The wired store does not implement the optional capability asked for. */
|
|
250
|
+
export declare class UnsupportedError extends JanusError {
|
|
251
|
+
name: string;
|
|
252
|
+
readonly code: "UNSUPPORTED";
|
|
253
|
+
}
|
|
254
|
+
/** A permission check walked deeper than `maxDepth` without an answer. */
|
|
255
|
+
export declare class PermissionDepthError extends JanusError {
|
|
256
|
+
name: string;
|
|
257
|
+
readonly code: "PERMISSION_DEPTH";
|
|
258
|
+
}
|
|
259
|
+
//# sourceMappingURL=janus-error.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"janus-error.d.ts","sourceRoot":"","sources":["../../src/errors/janus-error.ts"],"names":[],"mappings":"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"}
|
package/dist/ids/id.d.ts
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* An id — of a user, a session: a UUIDv7, lowercase, hyphenated.
|
|
3
|
+
*
|
|
4
|
+
* **The core mints it, not the store**, and that decision pays for itself three
|
|
5
|
+
* times over:
|
|
6
|
+
*
|
|
7
|
+
* - A UUIDv7 leads with a 48-bit millisecond timestamp, so ids sort in
|
|
8
|
+
* creation order as strings. The pagination cursor is therefore *the last
|
|
9
|
+
* id* — one index on the id, and the ordering is already total. A
|
|
10
|
+
* store-minted id would need a `createdAt` index plus the id as a tiebreak,
|
|
11
|
+
* because a timestamp alone is not a total order, and an opaque cursor per
|
|
12
|
+
* adapter.
|
|
13
|
+
* - `insertUser` becomes **idempotent under retry**: the id is decided
|
|
14
|
+
* before the call, so a retry after a timeout writes the same row rather
|
|
15
|
+
* than a second user.
|
|
16
|
+
* - Every adapter reports the same shape, so moving an application from one
|
|
17
|
+
* adapter to another is a copy rather than a rewrite of every stored
|
|
18
|
+
* reference.
|
|
19
|
+
*
|
|
20
|
+
* The price, stated plainly: an adapter cannot reuse an existing numeric primary
|
|
21
|
+
* key. It gets a `uuid` column, or a 36-character string, and the monotonic
|
|
22
|
+
* prefix gives it the index locality a UUIDv4 destroys.
|
|
23
|
+
*/
|
|
24
|
+
export type Id = string;
|
|
25
|
+
/**
|
|
26
|
+
* A fresh id.
|
|
27
|
+
*
|
|
28
|
+
* Strictly increasing: within one millisecond it uses the sequence, and if that
|
|
29
|
+
* overflows — more than 4096 ids in a millisecond, which no real
|
|
30
|
+
* application reaches — it borrows the next millisecond rather than repeating
|
|
31
|
+
* one. Across processes the 62 random bits of the tail are what keep two machines
|
|
32
|
+
* apart.
|
|
33
|
+
*/
|
|
34
|
+
export declare function mintId(now?: number): Id;
|
|
35
|
+
/**
|
|
36
|
+
* Whether this string is an id this package could have minted.
|
|
37
|
+
*
|
|
38
|
+
* Used by an adapter to answer `null` for a malformed id **without reaching the
|
|
39
|
+
* store**: an id arrives off a URL, and one of the wrong shape is "no such
|
|
40
|
+
* user", not an outage and not a query. Rejecting it here also keeps a
|
|
41
|
+
* hand-written id out of a store that would then hold something the cursor
|
|
42
|
+
* cannot order.
|
|
43
|
+
*/
|
|
44
|
+
export declare function isId(value: string): boolean;
|
|
45
|
+
/**
|
|
46
|
+
* When this id was minted, from the id itself.
|
|
47
|
+
*
|
|
48
|
+
* Offered because the timestamp is *in* the id, so a `createdAt` column is a
|
|
49
|
+
* convenience rather than the truth — and an adapter that loses one can still
|
|
50
|
+
* answer. It is not a substitute for `createdAt`: the sequence may have borrowed
|
|
51
|
+
* a millisecond, and a clock that stepped backwards is held rather than
|
|
52
|
+
* followed, so this is accurate to the millisecond and no further.
|
|
53
|
+
*/
|
|
54
|
+
export declare function mintedAt(id: Id): Date;
|
|
55
|
+
//# sourceMappingURL=id.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"id.d.ts","sourceRoot":"","sources":["../../src/ids/id.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,MAAM,EAAE,GAAG,MAAM,CAAC;AAoBxB;;;;;;;;GAQG;AACH,wBAAgB,MAAM,CAAC,GAAG,GAAE,MAAmB,GAAG,EAAE,CA4CnD;AAKD;;;;;;;;GAQG;AACH,wBAAgB,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAE3C;AAED;;;;;;;;GAQG;AACH,wBAAgB,QAAQ,CAAC,EAAE,EAAE,EAAE,GAAG,IAAI,CAGrC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@nxgt/janus` — embeddable, type-safe authentication and permissions, over a
|
|
3
|
+
* store you provide.
|
|
4
|
+
*
|
|
5
|
+
* This entry point is `janus()` — users, sessions, sign-up, sign-in, e-mail
|
|
6
|
+
* verification and password reset — and what it shares with the permissions
|
|
7
|
+
* module: the subject vocabulary, the error family, pagination, time, and
|
|
8
|
+
* ids. Permissions are `@nxgt/janus/permissions`. Their vocabulary lives here,
|
|
9
|
+
* because users need it too — `subjectOf` is the join between the two, and it
|
|
10
|
+
* is a function rather than a convention on purpose.
|
|
11
|
+
*
|
|
12
|
+
* ## The one rule this package is built around
|
|
13
|
+
*
|
|
14
|
+
* **An outage is never an absence.** A store that cannot answer throws; a store
|
|
15
|
+
* that answered and found nothing returns `null`. A caller that maps a failure
|
|
16
|
+
* to `null` or `false` has turned an outage into a silent lockout — everybody
|
|
17
|
+
* who has an account is told they do not. That sentence is inherited from the
|
|
18
|
+
* Ory layer this package is an alternative to, where it had to be learned twice
|
|
19
|
+
* in two days, and here it is a term of the port rather than a line of prose:
|
|
20
|
+
* `@nxgt/janus/conformance` fails an adapter that breaks it.
|
|
21
|
+
*/
|
|
22
|
+
export * from './auth/index';
|
|
23
|
+
export { CredentialError, type CredentialRefusal, InvalidCursorError, type Issue, JanusError, type JanusErrorCode, type JanusErrorOptions, NotFoundError, PermissionDepthError, StoreConflict, StoreFailure, TokenError, UnsupportedError, UserInactiveError, UserInvalidError, } from './errors/janus-error';
|
|
24
|
+
export { type Id, isId, mintedAt, mintId, } from './ids/id';
|
|
25
|
+
export { type CursorPage, DEFAULT_PAGE_SIZE, invalidCursor, MAX_PAGE_SIZE, pageLimit, } from './pagination/cursor-page';
|
|
26
|
+
export { formatEntity, formatSubject, formatTuple, parseSubject, parseTuple, } from './subjects/notation';
|
|
27
|
+
export { type Entity, isSubjectSet, type RelationTuple, type Subject, type SubjectId, type SubjectSet, subjectOf, } from './subjects/subject';
|
|
28
|
+
export { type Clock, fixedClock, systemClock } from './time/clock';
|
|
29
|
+
export { type Duration, parseDuration } from './time/duration';
|
|
30
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,cAAc,cAAc,CAAC;AAC7B,OAAO,EACN,eAAe,EACf,KAAK,iBAAiB,EACtB,kBAAkB,EAClB,KAAK,KAAK,EACV,UAAU,EACV,KAAK,cAAc,EACnB,KAAK,iBAAiB,EACtB,aAAa,EACb,oBAAoB,EACpB,aAAa,EACb,YAAY,EACZ,UAAU,EACV,gBAAgB,EAChB,iBAAiB,EACjB,gBAAgB,GAChB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EACN,KAAK,EAAE,EACP,IAAI,EACJ,QAAQ,EACR,MAAM,GACN,MAAM,UAAU,CAAC;AAClB,OAAO,EACN,KAAK,UAAU,EACf,iBAAiB,EACjB,aAAa,EACb,aAAa,EACb,SAAS,GACT,MAAM,0BAA0B,CAAC;AAClC,OAAO,EACN,YAAY,EACZ,aAAa,EACb,WAAW,EACX,YAAY,EACZ,UAAU,GACV,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACN,KAAK,MAAM,EACX,YAAY,EACZ,KAAK,aAAa,EAClB,KAAK,OAAO,EACZ,KAAK,SAAS,EACd,KAAK,UAAU,EACf,SAAS,GACT,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,KAAK,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AACnE,OAAO,EAAE,KAAK,QAAQ,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC"}
|