@cauthyhq/node 1.2.1 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +21 -0
- package/README.md +13 -27
- package/dist/{cauthy-CCSSj3Lg.d.mts → cauthy-CsWUgyv_.d.mts} +42 -145
- package/dist/{cauthy-C7gZ-pbv.d.ts → cauthy-DHLBEuqP.d.ts} +42 -145
- package/dist/express.d.mts +2 -5
- package/dist/express.d.ts +2 -5
- package/dist/express.js +1 -2
- package/dist/express.js.map +1 -1
- package/dist/express.mjs +1 -2
- package/dist/express.mjs.map +1 -1
- package/dist/fastify.d.mts +1 -3
- package/dist/fastify.d.ts +1 -3
- package/dist/fastify.js +0 -2
- package/dist/fastify.js.map +1 -1
- package/dist/fastify.mjs +0 -2
- package/dist/fastify.mjs.map +1 -1
- package/dist/hono.d.mts +2 -5
- package/dist/hono.d.ts +2 -5
- package/dist/hono.js +1 -2
- package/dist/hono.js.map +1 -1
- package/dist/hono.mjs +1 -2
- package/dist/hono.mjs.map +1 -1
- package/dist/index.d.mts +1 -3
- package/dist/index.d.ts +1 -3
- package/dist/index.js +169 -524
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +162 -514
- package/dist/index.mjs.map +1 -1
- package/dist/mcp.js.map +1 -1
- package/dist/mcp.mjs.map +1 -1
- package/dist/next.d.mts +1 -3
- package/dist/next.d.ts +1 -3
- package/dist/testing.d.mts +11 -5
- package/dist/testing.d.ts +11 -5
- package/dist/testing.js +52 -50
- package/dist/testing.js.map +1 -1
- package/dist/testing.mjs +52 -50
- package/dist/testing.mjs.map +1 -1
- package/package.json +4 -15
- package/dist/identity-BTJ8NB_w.d.mts +0 -27
- package/dist/identity-BTJ8NB_w.d.ts +0 -27
- package/dist/keys-D5k0omTb.d.mts +0 -64
- package/dist/keys-D5k0omTb.d.ts +0 -64
- package/dist/keys.d.mts +0 -8
- package/dist/keys.d.ts +0 -8
- package/dist/keys.js +0 -157
- package/dist/keys.js.map +0 -1
- package/dist/keys.mjs +0 -129
- package/dist/keys.mjs.map +0 -1
|
@@ -1,95 +1,5 @@
|
|
|
1
|
-
import { K as KeyStore, P as PactKeys } from './keys-D5k0omTb.js';
|
|
2
1
|
import { JWTVerifyGetKey, JWK } from 'jose';
|
|
3
2
|
import { CauthyTheme } from './theme.js';
|
|
4
|
-
import { I as Identity } from './identity-BTJ8NB_w.js';
|
|
5
|
-
|
|
6
|
-
/** What createCauthy is given to run by contract. */
|
|
7
|
-
interface ContractOptions {
|
|
8
|
-
/** The context graph, as `cauthy contracts pull` writes it (contracts/graph.json). */
|
|
9
|
-
graph: unknown;
|
|
10
|
-
/** This application's system in the graph: `"acme-crm"`. */
|
|
11
|
-
system: string;
|
|
12
|
-
/** The link to read, when the system has more than one with Cauthy. */
|
|
13
|
-
link?: string;
|
|
14
|
-
/** Cauthy's system in the graph. Default: `"cauthy"`. */
|
|
15
|
-
provider?: string;
|
|
16
|
-
}
|
|
17
|
-
/** What an application reads of its contract. */
|
|
18
|
-
interface ResolvedContract {
|
|
19
|
-
system: string;
|
|
20
|
-
link: string;
|
|
21
|
-
/** Cauthy's public address. */
|
|
22
|
-
issuer: string;
|
|
23
|
-
/** The workspace's id, and its slug (what the application's own screens send). */
|
|
24
|
-
tenantId: string;
|
|
25
|
-
tenant: string;
|
|
26
|
-
/** The public client people sign in with: `pact.<link>`. */
|
|
27
|
-
clientId: string;
|
|
28
|
-
/** Where people may return after signing in. */
|
|
29
|
-
redirectUris: string[];
|
|
30
|
-
/** Whether Cauthy asks the system's proof on the code exchange now (`systemProof` is `required`). */
|
|
31
|
-
requireSystemProof: boolean;
|
|
32
|
-
/** How the link asks for the proof: never, from the first proved sign-in on (`auto`), or always. */
|
|
33
|
-
systemProof: 'off' | 'auto' | 'required';
|
|
34
|
-
/** Whether Cauthy issues no token through this link before the address is confirmed. */
|
|
35
|
-
requireVerifiedEmail: boolean;
|
|
36
|
-
/** Whether the link lets its people ask to stay signed in. */
|
|
37
|
-
persistentSessions: boolean;
|
|
38
|
-
/** The system's own client, when the link gives it one: `pact.<link>.service`. */
|
|
39
|
-
serviceClientId?: string;
|
|
40
|
-
/** Where the system publishes its keys, and the path of that address. */
|
|
41
|
-
jwksUrl?: string;
|
|
42
|
-
jwksPath?: string;
|
|
43
|
-
/** Where the system receives Cauthy's events, when it says. */
|
|
44
|
-
eventsUrl?: string;
|
|
45
|
-
}
|
|
46
|
-
/**
|
|
47
|
-
* The variables of the standard mode. With a contract none may be set: two
|
|
48
|
-
* sources of the same thing, one silently winning, is how a system ends up
|
|
49
|
-
* signing people in through a client nobody meant.
|
|
50
|
-
*/
|
|
51
|
-
declare const STANDARD_VARIABLES: readonly ["CAUTHY_ISSUER", "CAUTHY_CLIENT_ID", "CAUTHY_CLIENT_SECRET", "CAUTHY_SECRET", "CAUTHY_SYSTEM", "CAUTHY_TENANT", "CAUTHY_SYSTEM_KEY", "CAUTHY_SYSTEM_KEY_ID"];
|
|
52
|
-
/** Refuses to run by contract with a variable of the standard mode set: names it. */
|
|
53
|
-
declare function failClosed(environment: Record<string, string | undefined> | undefined): void;
|
|
54
|
-
/** Reads what the graph says of the system's link with Cauthy. */
|
|
55
|
-
declare function readContract(options: ContractOptions): ResolvedContract;
|
|
56
|
-
/** One difference between a contract and what Cauthy holds. */
|
|
57
|
-
interface PactItem {
|
|
58
|
-
kind: 'client' | 'redirect_uri' | 'grant_type' | 'role' | 'organization' | 'require_system_proof' | 'persistent_sessions' | 'jwks_url';
|
|
59
|
-
client_id?: string;
|
|
60
|
-
value: string;
|
|
61
|
-
detail?: string;
|
|
62
|
-
}
|
|
63
|
-
/** How the system stands against its contract, as Cauthy checks it (GET /v1/pact/status). Moments are UTC. */
|
|
64
|
-
interface PactStatus {
|
|
65
|
-
system: string;
|
|
66
|
-
tenant_id: string;
|
|
67
|
-
checked_at: string;
|
|
68
|
-
/** When Cauthy's daily reconciliation last checked it; null before the first. */
|
|
69
|
-
reconciled_at: string | null;
|
|
70
|
-
in_step: boolean;
|
|
71
|
-
/** In Cauthy, and the contract does not name it. Nothing is ever deleted for it. */
|
|
72
|
-
outside: PactItem[];
|
|
73
|
-
/** Named by the contract, and Cauthy does not hold it as it says. */
|
|
74
|
-
missing: PactItem[];
|
|
75
|
-
contract: {
|
|
76
|
-
clients: {
|
|
77
|
-
client_id: string;
|
|
78
|
-
link: string;
|
|
79
|
-
purpose: 'sign_in' | 'service';
|
|
80
|
-
redirect_uris?: string[];
|
|
81
|
-
grant_types: string[];
|
|
82
|
-
require_system_proof?: boolean;
|
|
83
|
-
jwks_url?: string;
|
|
84
|
-
}[];
|
|
85
|
-
roles?: Record<string, string[]>;
|
|
86
|
-
};
|
|
87
|
-
held: {
|
|
88
|
-
clients: Record<string, unknown>[];
|
|
89
|
-
roles: string[];
|
|
90
|
-
organizations: Record<string, number>;
|
|
91
|
-
};
|
|
92
|
-
}
|
|
93
3
|
|
|
94
4
|
/** Something that happened in Cauthy, as a subscriber is told. Moments are UTC. */
|
|
95
5
|
interface CauthyEvent {
|
|
@@ -157,7 +67,7 @@ interface CauthyOptions {
|
|
|
157
67
|
* `CAUTHY_KEY`. With it nothing else is read: the workspace, the system and
|
|
158
68
|
* the application's addresses come from Cauthy (`GET /v1/connect/self`),
|
|
159
69
|
* and passing `issuer`, `clientId`, `clientSecret`, `secret`, `system`,
|
|
160
|
-
* `tenant`, `audience`, `tenantId
|
|
70
|
+
* `tenant`, `audience`, `tenantId` or `systemKey` is refused.
|
|
161
71
|
*/
|
|
162
72
|
key?: string;
|
|
163
73
|
/** The key being replaced, during a rotation: read, never written with. Default: `CAUTHY_KEY_PREVIOUS`. */
|
|
@@ -203,8 +113,8 @@ interface CauthyOptions {
|
|
|
203
113
|
*/
|
|
204
114
|
audience?: string;
|
|
205
115
|
/**
|
|
206
|
-
* The workspace's id (a lowercase UUID) for `auth.verifyToken`.
|
|
207
|
-
* it
|
|
116
|
+
* The workspace's id (a lowercase UUID) for `auth.verifyToken`. On
|
|
117
|
+
* CAUTHY_KEY it is Cauthy's answer; otherwise: this, or `CAUTHY_TENANT_ID`.
|
|
208
118
|
*/
|
|
209
119
|
tenantId?: string;
|
|
210
120
|
/**
|
|
@@ -268,23 +178,18 @@ interface CauthyOptions {
|
|
|
268
178
|
request?: number;
|
|
269
179
|
};
|
|
270
180
|
/**
|
|
271
|
-
*
|
|
272
|
-
*
|
|
273
|
-
*
|
|
274
|
-
*
|
|
275
|
-
*
|
|
276
|
-
* createCauthy({ contract: { graph, system: 'acme-crm' }, keys: postgresKeyStore(query) })
|
|
277
|
-
*/
|
|
278
|
-
contract?: ContractOptions;
|
|
279
|
-
/** Where the application keeps its own key, with a contract (@cauthyhq/node/keys). */
|
|
280
|
-
keys?: KeyStore;
|
|
281
|
-
/**
|
|
282
|
-
* The one secret of a contracted application: every key it needs is
|
|
283
|
-
* derived from it. 32 random bytes or more. Default: `PACT_ROOT_KEY`.
|
|
181
|
+
* Removed in 1.3: contracts are retired. Given, `createCauthy` refuses to
|
|
182
|
+
* start (as it does with `PACT_ROOT_KEY` or `PACT_ROOT_KEY_PREVIOUS` set):
|
|
183
|
+
* run on CAUTHY_KEY alone, and protect sign-in with the "Protect sign-in"
|
|
184
|
+
* switches on the application's card in Cauthy's dashboard.
|
|
284
185
|
*/
|
|
285
|
-
|
|
286
|
-
/**
|
|
287
|
-
|
|
186
|
+
contract?: never;
|
|
187
|
+
/** Removed in 1.3 with contracts: given, `createCauthy` refuses to start. */
|
|
188
|
+
keys?: never;
|
|
189
|
+
/** Removed in 1.3 with contracts (it was `PACT_ROOT_KEY`): given, `createCauthy` refuses to start. */
|
|
190
|
+
rootKey?: never;
|
|
191
|
+
/** Removed in 1.3 with contracts (it was `PACT_ROOT_KEY_PREVIOUS`): given, `createCauthy` refuses to start. */
|
|
192
|
+
rootKeyPrevious?: never;
|
|
288
193
|
/**
|
|
289
194
|
* Where `auth.webhook` remembers the deliveries it took, so one sent twice
|
|
290
195
|
* is refused. Default: this process's memory. Give a shared one (a table)
|
|
@@ -411,7 +316,7 @@ declare class CauthyConfigError extends Error {
|
|
|
411
316
|
constructor(message: string);
|
|
412
317
|
}
|
|
413
318
|
/** Why a CAUTHY_KEY was refused (key/cauthy-key.md §3, §8, §9). */
|
|
414
|
-
type CauthyKeyReason = 'key_format' | 'key_version' | 'key_checksum' | 'key_issuer' | 'key_client' | 'key_secret' | '
|
|
319
|
+
type CauthyKeyReason = 'key_format' | 'key_version' | 'key_checksum' | 'key_issuer' | 'key_client' | 'key_secret' | 'key_previous_mismatch';
|
|
415
320
|
/** A refused CAUTHY_KEY. The message names the reason, never the key. */
|
|
416
321
|
declare class CauthyKeyError extends CauthyConfigError {
|
|
417
322
|
readonly reason: CauthyKeyReason;
|
|
@@ -703,17 +608,10 @@ interface SystemOptions {
|
|
|
703
608
|
* client registered to be sent back to. Default: `CAUTHY_ACCEPT_INVITE_URL`.
|
|
704
609
|
*/
|
|
705
610
|
acceptInviteUrl?: string;
|
|
706
|
-
/**
|
|
707
|
-
* The application's own keys, kept in its database (contract mode): it
|
|
708
|
-
* signs with the newest and publishes them. Takes the place of `key`.
|
|
709
|
-
*/
|
|
710
|
-
keys?: PactKeys;
|
|
711
|
-
/** The client the keys prove: the system's own, beside the sign-in client. */
|
|
712
|
-
keysClientId?: string;
|
|
713
611
|
/**
|
|
714
612
|
* CAUTHY_KEY's Ed25519 key (key/cauthy-key.md §6) and the client it proves:
|
|
715
|
-
* every token is asked with an EdDSA assertion. Takes the place of `key
|
|
716
|
-
*
|
|
613
|
+
* every token is asked with an EdDSA assertion. Takes the place of `key`
|
|
614
|
+
* and the secret.
|
|
717
615
|
*/
|
|
718
616
|
signer?: {
|
|
719
617
|
clientId: string;
|
|
@@ -939,8 +837,8 @@ interface VerifyTokenOptions {
|
|
|
939
837
|
/**
|
|
940
838
|
* The client this backend signs people in through. When set, a person's
|
|
941
839
|
* token issued through another client (an `azp` naming another) is refused
|
|
942
|
-
* with `wrong_client` (rule R15); a token with no `azp` passes.
|
|
943
|
-
*
|
|
840
|
+
* with `wrong_client` (rule R15); a token with no `azp` passes. Default:
|
|
841
|
+
* none, and `azp` is not checked.
|
|
944
842
|
*/
|
|
945
843
|
clientId?: string;
|
|
946
844
|
}
|
|
@@ -988,6 +886,25 @@ declare function createVerifierFromEnv(options?: Omit<VerifyTokenOptions, 'issue
|
|
|
988
886
|
*/
|
|
989
887
|
type MountTarget = string | ((request: Request) => Response | Promise<Response>);
|
|
990
888
|
|
|
889
|
+
/** What `GET /v1/connect/self` answers. */
|
|
890
|
+
interface Identity {
|
|
891
|
+
issuer: string;
|
|
892
|
+
audience: string;
|
|
893
|
+
tenant: {
|
|
894
|
+
id: string;
|
|
895
|
+
slug: string;
|
|
896
|
+
};
|
|
897
|
+
system: string;
|
|
898
|
+
client_id: string;
|
|
899
|
+
sign_in_client_id: string;
|
|
900
|
+
app_urls: string[];
|
|
901
|
+
callback_path: string;
|
|
902
|
+
key: {
|
|
903
|
+
kid: string;
|
|
904
|
+
retires_at: string | null;
|
|
905
|
+
} | null;
|
|
906
|
+
}
|
|
907
|
+
|
|
991
908
|
/** What `resolve` answers: who is there, and the cookies that must go back. */
|
|
992
909
|
interface Resolved {
|
|
993
910
|
session: Session | null;
|
|
@@ -1071,10 +988,9 @@ interface Cauthy {
|
|
|
1071
988
|
/**
|
|
1072
989
|
* Verifies a Cauthy access token (or a request's `Authorization: Bearer`) for
|
|
1073
990
|
* an API of this application: `verifyToken` with this instance's issuer, its
|
|
1074
|
-
* workspace (
|
|
1075
|
-
* `CAUTHY_TENANT_ID`) and its audience (
|
|
1076
|
-
*
|
|
1077
|
-
* client than the link's (`wrong_client`).
|
|
991
|
+
* workspace (on CAUTHY_KEY, Cauthy's answer; otherwise `tenantId` or
|
|
992
|
+
* `CAUTHY_TENANT_ID`) and its audience (on CAUTHY_KEY, Cauthy's answer;
|
|
993
|
+
* otherwise `audience` or `CAUTHY_AUDIENCE`).
|
|
1078
994
|
*/
|
|
1079
995
|
verifyToken(from: string | Request | Headers, options?: Partial<VerifyTokenOptions>): Promise<TokenIdentity>;
|
|
1080
996
|
/** The same, built once: throws `CauthyConfigError` now if the audience or the workspace is missing. */
|
|
@@ -1085,11 +1001,6 @@ interface Cauthy {
|
|
|
1085
1001
|
* `systemKey`.
|
|
1086
1002
|
*/
|
|
1087
1003
|
system: CauthySystem;
|
|
1088
|
-
/**
|
|
1089
|
-
* The application's contract, when it runs by one: what its link says,
|
|
1090
|
-
* its own keys, and how it stands against its contract in Cauthy.
|
|
1091
|
-
*/
|
|
1092
|
-
pact?: CauthyPact;
|
|
1093
1004
|
/** What the browser may be told of a session. */
|
|
1094
1005
|
toPublic(session: Session): Promise<PublicSession>;
|
|
1095
1006
|
/** Paths of this application that start a sign-in, a sign-out, or open the account page. */
|
|
@@ -1101,20 +1012,6 @@ interface Cauthy {
|
|
|
1101
1012
|
};
|
|
1102
1013
|
options: Readonly<Required<Pick<CauthyOptions, 'issuer' | 'clientId' | 'basePath' | 'afterSignIn' | 'afterSignOut' | 'cookieName'>>>;
|
|
1103
1014
|
}
|
|
1104
|
-
/** A contracted application's view of its contract (`auth.pact`). */
|
|
1105
|
-
interface CauthyPact {
|
|
1106
|
-
/** What its link in the graph says. */
|
|
1107
|
-
contract: ResolvedContract;
|
|
1108
|
-
/** Its own keys: the one that signs, the ones published, rotating them. */
|
|
1109
|
-
keys: PactKeys;
|
|
1110
|
-
/**
|
|
1111
|
-
* The response for its jwks_url: the published keys. `handler` serves it
|
|
1112
|
-
* at that path too, when the route reaches it.
|
|
1113
|
-
*/
|
|
1114
|
-
jwks(): Promise<Response>;
|
|
1115
|
-
/** How it stands against its contract, as Cauthy checks it now. For a health endpoint. */
|
|
1116
|
-
status(): Promise<PactStatus>;
|
|
1117
|
-
}
|
|
1118
1015
|
declare function createCauthy(given?: CauthyOptions): Cauthy;
|
|
1119
1016
|
|
|
1120
|
-
export {
|
|
1017
|
+
export { memoryReplayStore as $, type AttributeType as A, type RoleOf as B, type Cauthy as C, type SessionOrganization as D, type SessionStatus as E, type SessionUser as F, type SystemKey as G, type SystemOptions as H, type Identity as I, type JsonValue as J, type SystemPolicy as K, type TokenRefusal as L, type MountTarget as M, type NewMember as N, type Organization as O, type PermissionOf as P, type VerifyWebhookOptions as Q, type ReplayStore as R, type Session as S, type TokenIdentity as T, can as U, type VerifyTokenOptions as V, createCauthy as W, createSystem as X, createTokenVerifier as Y, createVerifierFromEnv as Z, definePolicy as _, type CatalogResource as a, policySource as a0, pullCatalog as a1, pullPolicy as a2, pushCatalog as a3, pushPolicy as a4, remoteKeys as a5, verifyToken as a6, verifyWebhook as a7, CauthyApiError as b, CauthyConfigError as c, type CauthyEvent as d, CauthyKeyError as e, type CauthyKeyReason as f, type CauthyOptions as g, type CauthySystem as h, CauthyTokenError as i, CauthyUnavailableError as j, CauthyWebhookError as k, type CheckOf as l, type CheckQuestion as m, type CheckResult as n, type CheckRule as o, type ConditionalPermission as p, type OrganizationMember as q, type OrganizationRef as r, type Permitted as s, type Policy as t, type PolicyDefinition as u, type PolicyPermission as v, type PolicyRole as w, type PublicSession as x, type PushPolicyOptions as y, type Resolved as z };
|
package/dist/express.d.mts
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import { IncomingMessage, ServerResponse } from 'node:http';
|
|
2
|
-
import { S as Session, C as Cauthy } from './cauthy-
|
|
3
|
-
import './keys-D5k0omTb.mjs';
|
|
2
|
+
import { S as Session, C as Cauthy } from './cauthy-CsWUgyv_.mjs';
|
|
4
3
|
import 'jose';
|
|
5
4
|
import './theme.mjs';
|
|
6
|
-
import './identity-BTJ8NB_w.mjs';
|
|
7
5
|
|
|
8
6
|
declare global {
|
|
9
7
|
namespace Express {
|
|
@@ -15,8 +13,7 @@ declare global {
|
|
|
15
13
|
}
|
|
16
14
|
type Next = (error?: unknown) => void;
|
|
17
15
|
/**
|
|
18
|
-
* Serves the routes under the handler's `basePath
|
|
19
|
-
* application's published key), and gives every other
|
|
16
|
+
* Serves the routes under the handler's `basePath`, and gives every other
|
|
20
17
|
* request `req.cauthy()`. Mount it once, before the routes that use it.
|
|
21
18
|
*/
|
|
22
19
|
declare function cauthyExpress(auth: Cauthy): (req: IncomingMessage, res: ServerResponse, next: Next) => void;
|
package/dist/express.d.ts
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import { IncomingMessage, ServerResponse } from 'node:http';
|
|
2
|
-
import { S as Session, C as Cauthy } from './cauthy-
|
|
3
|
-
import './keys-D5k0omTb.js';
|
|
2
|
+
import { S as Session, C as Cauthy } from './cauthy-DHLBEuqP.js';
|
|
4
3
|
import 'jose';
|
|
5
4
|
import './theme.js';
|
|
6
|
-
import './identity-BTJ8NB_w.js';
|
|
7
5
|
|
|
8
6
|
declare global {
|
|
9
7
|
namespace Express {
|
|
@@ -15,8 +13,7 @@ declare global {
|
|
|
15
13
|
}
|
|
16
14
|
type Next = (error?: unknown) => void;
|
|
17
15
|
/**
|
|
18
|
-
* Serves the routes under the handler's `basePath
|
|
19
|
-
* application's published key), and gives every other
|
|
16
|
+
* Serves the routes under the handler's `basePath`, and gives every other
|
|
20
17
|
* request `req.cauthy()`. Mount it once, before the routes that use it.
|
|
21
18
|
*/
|
|
22
19
|
declare function cauthyExpress(auth: Cauthy): (req: IncomingMessage, res: ServerResponse, next: Next) => void;
|
package/dist/express.js
CHANGED
|
@@ -59,11 +59,10 @@ function addCookies(res, cookies) {
|
|
|
59
59
|
}
|
|
60
60
|
function cauthyExpress(auth) {
|
|
61
61
|
const base = auth.options.basePath;
|
|
62
|
-
const key = auth.pact?.contract.jwksPath;
|
|
63
62
|
return function cauthy(req, res, next) {
|
|
64
63
|
const request = req;
|
|
65
64
|
const path = (request.originalUrl ?? request.url ?? "/").split("?")[0];
|
|
66
|
-
if (path === base || path.startsWith(`${base}/`)
|
|
65
|
+
if (path === base || path.startsWith(`${base}/`)) {
|
|
67
66
|
void (async () => {
|
|
68
67
|
const answer = await auth.handler(await toWebRequest(request, true));
|
|
69
68
|
res.statusCode = answer.status;
|
package/dist/express.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/express.ts"],"sourcesContent":["// Express (and anything else that speaks Node's http): the routes, and who is\n// signed in on every request.\n//\n// app.use(cauthyExpress(auth))\n//\n// app.get('/api/me', async (req, res) => {\n// const session = await req.cauthy()\n// if (!session) return res.status(401).json({ error: 'unauthenticated' })\n// res.json(session.user)\n// })\n//\n// app.get('/api/books', requireSession, (req, res) => { … })\n//\n// A session that needs renewing is renewed on the spot, and its new cookie\n// leaves with whatever the route answers.\n\nimport type { IncomingMessage, ServerResponse } from 'node:http'\nimport type { Cauthy } from './cauthy'\nimport type { Session } from './types'\n\ndeclare global {\n // eslint-disable-next-line @typescript-eslint/no-namespace\n namespace Express {\n interface Request {\n /** Who is signed in, or null. Asked once per request. */\n cauthy(): Promise<Session | null>\n }\n }\n}\n\n/** A request as Node gives it, with what Express adds when it is Express. */\ntype NodeRequest = IncomingMessage & { originalUrl?: string; protocol?: string; ip?: string; body?: unknown; cauthy?: () => Promise<Session | null> }\ntype Next = (error?: unknown) => void\n\nfunction originOf(req: NodeRequest): string {\n const secure = (req.socket as { encrypted?: boolean } | undefined)?.encrypted === true\n return `${req.protocol ?? (secure ? 'https' : 'http')}://${req.headers.host ?? 'localhost'}`\n}\n\nasync function bodyOf(req: NodeRequest): Promise<BodyInit | undefined> {\n if (req.method === 'GET' || req.method === 'HEAD') return undefined\n // A body parser was here first (express.json()): what it read is the body.\n if (req.body !== undefined && req.body !== null) {\n if (typeof req.body === 'string') return req.body\n if (req.body instanceof Uint8Array) return new Uint8Array(req.body)\n return JSON.stringify(req.body)\n }\n const chunks: Uint8Array[] = []\n for await (const chunk of req) chunks.push(typeof chunk === 'string' ? new TextEncoder().encode(chunk) : (chunk as Uint8Array))\n return chunks.length === 0 ? undefined : new Blob(chunks as BlobPart[])\n}\n\nasync function toWebRequest(req: NodeRequest, withBody: boolean): Promise<Request> {\n const headers = new Headers()\n for (const [k, v] of Object.entries(req.headers)) {\n if (Array.isArray(v)) for (const one of v) headers.append(k, one)\n else if (v !== undefined) headers.set(k, v)\n }\n // Express knows who is calling (it applies `trust proxy`): that address is\n // the one passed on to Cauthy, whatever the header claimed.\n if (typeof req.ip === 'string' && req.ip !== '') headers.set('x-forwarded-for', req.ip)\n return new Request(new URL(req.originalUrl ?? req.url ?? '/', originOf(req)), {\n method: req.method,\n headers,\n body: withBody ? await bodyOf(req) : undefined,\n })\n}\n\nfunction addCookies(res: ServerResponse, cookies: string[]): void {\n if (cookies.length === 0 || res.headersSent) return\n const had = res.getHeader('set-cookie')\n res.setHeader('set-cookie', [...(Array.isArray(had) ? had : typeof had === 'string' ? [had] : []), ...cookies])\n}\n\n/**\n * Serves the routes under the handler's `basePath
|
|
1
|
+
{"version":3,"sources":["../src/express.ts"],"sourcesContent":["// Express (and anything else that speaks Node's http): the routes, and who is\n// signed in on every request.\n//\n// app.use(cauthyExpress(auth))\n//\n// app.get('/api/me', async (req, res) => {\n// const session = await req.cauthy()\n// if (!session) return res.status(401).json({ error: 'unauthenticated' })\n// res.json(session.user)\n// })\n//\n// app.get('/api/books', requireSession, (req, res) => { … })\n//\n// A session that needs renewing is renewed on the spot, and its new cookie\n// leaves with whatever the route answers.\n\nimport type { IncomingMessage, ServerResponse } from 'node:http'\nimport type { Cauthy } from './cauthy'\nimport type { Session } from './types'\n\ndeclare global {\n // eslint-disable-next-line @typescript-eslint/no-namespace\n namespace Express {\n interface Request {\n /** Who is signed in, or null. Asked once per request. */\n cauthy(): Promise<Session | null>\n }\n }\n}\n\n/** A request as Node gives it, with what Express adds when it is Express. */\ntype NodeRequest = IncomingMessage & { originalUrl?: string; protocol?: string; ip?: string; body?: unknown; cauthy?: () => Promise<Session | null> }\ntype Next = (error?: unknown) => void\n\nfunction originOf(req: NodeRequest): string {\n const secure = (req.socket as { encrypted?: boolean } | undefined)?.encrypted === true\n return `${req.protocol ?? (secure ? 'https' : 'http')}://${req.headers.host ?? 'localhost'}`\n}\n\nasync function bodyOf(req: NodeRequest): Promise<BodyInit | undefined> {\n if (req.method === 'GET' || req.method === 'HEAD') return undefined\n // A body parser was here first (express.json()): what it read is the body.\n if (req.body !== undefined && req.body !== null) {\n if (typeof req.body === 'string') return req.body\n if (req.body instanceof Uint8Array) return new Uint8Array(req.body)\n return JSON.stringify(req.body)\n }\n const chunks: Uint8Array[] = []\n for await (const chunk of req) chunks.push(typeof chunk === 'string' ? new TextEncoder().encode(chunk) : (chunk as Uint8Array))\n return chunks.length === 0 ? undefined : new Blob(chunks as BlobPart[])\n}\n\nasync function toWebRequest(req: NodeRequest, withBody: boolean): Promise<Request> {\n const headers = new Headers()\n for (const [k, v] of Object.entries(req.headers)) {\n if (Array.isArray(v)) for (const one of v) headers.append(k, one)\n else if (v !== undefined) headers.set(k, v)\n }\n // Express knows who is calling (it applies `trust proxy`): that address is\n // the one passed on to Cauthy, whatever the header claimed.\n if (typeof req.ip === 'string' && req.ip !== '') headers.set('x-forwarded-for', req.ip)\n return new Request(new URL(req.originalUrl ?? req.url ?? '/', originOf(req)), {\n method: req.method,\n headers,\n body: withBody ? await bodyOf(req) : undefined,\n })\n}\n\nfunction addCookies(res: ServerResponse, cookies: string[]): void {\n if (cookies.length === 0 || res.headersSent) return\n const had = res.getHeader('set-cookie')\n res.setHeader('set-cookie', [...(Array.isArray(had) ? had : typeof had === 'string' ? [had] : []), ...cookies])\n}\n\n/**\n * Serves the routes under the handler's `basePath`, and gives every other\n * request `req.cauthy()`. Mount it once, before the routes that use it.\n */\nexport function cauthyExpress(auth: Cauthy) {\n const base = auth.options.basePath\n return function cauthy(req: IncomingMessage, res: ServerResponse, next: Next): void {\n const request = req as NodeRequest\n const path = (request.originalUrl ?? request.url ?? '/').split('?')[0]\n\n if (path === base || path.startsWith(`${base}/`)) {\n void (async () => {\n const answer = await auth.handler(await toWebRequest(request, true))\n res.statusCode = answer.status\n answer.headers.forEach((value, name) => {\n if (name !== 'set-cookie') res.setHeader(name, value)\n })\n addCookies(res, answer.headers.getSetCookie())\n res.end(answer.body === null ? undefined : Buffer.from(await answer.arrayBuffer()))\n })().catch(next)\n return\n }\n\n let asked: Promise<Session | null> | undefined\n request.cauthy = () =>\n (asked ??= (async () => {\n const resolved = await auth.resolve(await toWebRequest(request, false))\n addCookies(res, resolved.cookies)\n return resolved.session\n })())\n next()\n }\n}\n\n/** For a route only a signed-in person may call: answers 401 otherwise. Needs `cauthyExpress` mounted before it. */\nexport function requireSession(req: IncomingMessage, res: ServerResponse, next: Next): void {\n const ask = (req as NodeRequest).cauthy\n if (!ask) return next(new Error('@cauthyhq/node: mount cauthyExpress(auth) before requireSession'))\n ask().then((session) => {\n if (session !== null) return next()\n res.statusCode = 401\n res.setHeader('content-type', 'application/json; charset=utf-8')\n res.setHeader('x-cauthy-session', 'none')\n res.end(JSON.stringify({ error: 'unauthenticated' }))\n }, next)\n}\n"],"mappings":"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","names":[]}
|
package/dist/express.mjs
CHANGED
|
@@ -34,11 +34,10 @@ function addCookies(res, cookies) {
|
|
|
34
34
|
}
|
|
35
35
|
function cauthyExpress(auth) {
|
|
36
36
|
const base = auth.options.basePath;
|
|
37
|
-
const key = auth.pact?.contract.jwksPath;
|
|
38
37
|
return function cauthy(req, res, next) {
|
|
39
38
|
const request = req;
|
|
40
39
|
const path = (request.originalUrl ?? request.url ?? "/").split("?")[0];
|
|
41
|
-
if (path === base || path.startsWith(`${base}/`)
|
|
40
|
+
if (path === base || path.startsWith(`${base}/`)) {
|
|
42
41
|
void (async () => {
|
|
43
42
|
const answer = await auth.handler(await toWebRequest(request, true));
|
|
44
43
|
res.statusCode = answer.status;
|
package/dist/express.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/express.ts"],"sourcesContent":["// Express (and anything else that speaks Node's http): the routes, and who is\n// signed in on every request.\n//\n// app.use(cauthyExpress(auth))\n//\n// app.get('/api/me', async (req, res) => {\n// const session = await req.cauthy()\n// if (!session) return res.status(401).json({ error: 'unauthenticated' })\n// res.json(session.user)\n// })\n//\n// app.get('/api/books', requireSession, (req, res) => { … })\n//\n// A session that needs renewing is renewed on the spot, and its new cookie\n// leaves with whatever the route answers.\n\nimport type { IncomingMessage, ServerResponse } from 'node:http'\nimport type { Cauthy } from './cauthy'\nimport type { Session } from './types'\n\ndeclare global {\n // eslint-disable-next-line @typescript-eslint/no-namespace\n namespace Express {\n interface Request {\n /** Who is signed in, or null. Asked once per request. */\n cauthy(): Promise<Session | null>\n }\n }\n}\n\n/** A request as Node gives it, with what Express adds when it is Express. */\ntype NodeRequest = IncomingMessage & { originalUrl?: string; protocol?: string; ip?: string; body?: unknown; cauthy?: () => Promise<Session | null> }\ntype Next = (error?: unknown) => void\n\nfunction originOf(req: NodeRequest): string {\n const secure = (req.socket as { encrypted?: boolean } | undefined)?.encrypted === true\n return `${req.protocol ?? (secure ? 'https' : 'http')}://${req.headers.host ?? 'localhost'}`\n}\n\nasync function bodyOf(req: NodeRequest): Promise<BodyInit | undefined> {\n if (req.method === 'GET' || req.method === 'HEAD') return undefined\n // A body parser was here first (express.json()): what it read is the body.\n if (req.body !== undefined && req.body !== null) {\n if (typeof req.body === 'string') return req.body\n if (req.body instanceof Uint8Array) return new Uint8Array(req.body)\n return JSON.stringify(req.body)\n }\n const chunks: Uint8Array[] = []\n for await (const chunk of req) chunks.push(typeof chunk === 'string' ? new TextEncoder().encode(chunk) : (chunk as Uint8Array))\n return chunks.length === 0 ? undefined : new Blob(chunks as BlobPart[])\n}\n\nasync function toWebRequest(req: NodeRequest, withBody: boolean): Promise<Request> {\n const headers = new Headers()\n for (const [k, v] of Object.entries(req.headers)) {\n if (Array.isArray(v)) for (const one of v) headers.append(k, one)\n else if (v !== undefined) headers.set(k, v)\n }\n // Express knows who is calling (it applies `trust proxy`): that address is\n // the one passed on to Cauthy, whatever the header claimed.\n if (typeof req.ip === 'string' && req.ip !== '') headers.set('x-forwarded-for', req.ip)\n return new Request(new URL(req.originalUrl ?? req.url ?? '/', originOf(req)), {\n method: req.method,\n headers,\n body: withBody ? await bodyOf(req) : undefined,\n })\n}\n\nfunction addCookies(res: ServerResponse, cookies: string[]): void {\n if (cookies.length === 0 || res.headersSent) return\n const had = res.getHeader('set-cookie')\n res.setHeader('set-cookie', [...(Array.isArray(had) ? had : typeof had === 'string' ? [had] : []), ...cookies])\n}\n\n/**\n * Serves the routes under the handler's `basePath
|
|
1
|
+
{"version":3,"sources":["../src/express.ts"],"sourcesContent":["// Express (and anything else that speaks Node's http): the routes, and who is\n// signed in on every request.\n//\n// app.use(cauthyExpress(auth))\n//\n// app.get('/api/me', async (req, res) => {\n// const session = await req.cauthy()\n// if (!session) return res.status(401).json({ error: 'unauthenticated' })\n// res.json(session.user)\n// })\n//\n// app.get('/api/books', requireSession, (req, res) => { … })\n//\n// A session that needs renewing is renewed on the spot, and its new cookie\n// leaves with whatever the route answers.\n\nimport type { IncomingMessage, ServerResponse } from 'node:http'\nimport type { Cauthy } from './cauthy'\nimport type { Session } from './types'\n\ndeclare global {\n // eslint-disable-next-line @typescript-eslint/no-namespace\n namespace Express {\n interface Request {\n /** Who is signed in, or null. Asked once per request. */\n cauthy(): Promise<Session | null>\n }\n }\n}\n\n/** A request as Node gives it, with what Express adds when it is Express. */\ntype NodeRequest = IncomingMessage & { originalUrl?: string; protocol?: string; ip?: string; body?: unknown; cauthy?: () => Promise<Session | null> }\ntype Next = (error?: unknown) => void\n\nfunction originOf(req: NodeRequest): string {\n const secure = (req.socket as { encrypted?: boolean } | undefined)?.encrypted === true\n return `${req.protocol ?? (secure ? 'https' : 'http')}://${req.headers.host ?? 'localhost'}`\n}\n\nasync function bodyOf(req: NodeRequest): Promise<BodyInit | undefined> {\n if (req.method === 'GET' || req.method === 'HEAD') return undefined\n // A body parser was here first (express.json()): what it read is the body.\n if (req.body !== undefined && req.body !== null) {\n if (typeof req.body === 'string') return req.body\n if (req.body instanceof Uint8Array) return new Uint8Array(req.body)\n return JSON.stringify(req.body)\n }\n const chunks: Uint8Array[] = []\n for await (const chunk of req) chunks.push(typeof chunk === 'string' ? new TextEncoder().encode(chunk) : (chunk as Uint8Array))\n return chunks.length === 0 ? undefined : new Blob(chunks as BlobPart[])\n}\n\nasync function toWebRequest(req: NodeRequest, withBody: boolean): Promise<Request> {\n const headers = new Headers()\n for (const [k, v] of Object.entries(req.headers)) {\n if (Array.isArray(v)) for (const one of v) headers.append(k, one)\n else if (v !== undefined) headers.set(k, v)\n }\n // Express knows who is calling (it applies `trust proxy`): that address is\n // the one passed on to Cauthy, whatever the header claimed.\n if (typeof req.ip === 'string' && req.ip !== '') headers.set('x-forwarded-for', req.ip)\n return new Request(new URL(req.originalUrl ?? req.url ?? '/', originOf(req)), {\n method: req.method,\n headers,\n body: withBody ? await bodyOf(req) : undefined,\n })\n}\n\nfunction addCookies(res: ServerResponse, cookies: string[]): void {\n if (cookies.length === 0 || res.headersSent) return\n const had = res.getHeader('set-cookie')\n res.setHeader('set-cookie', [...(Array.isArray(had) ? had : typeof had === 'string' ? [had] : []), ...cookies])\n}\n\n/**\n * Serves the routes under the handler's `basePath`, and gives every other\n * request `req.cauthy()`. Mount it once, before the routes that use it.\n */\nexport function cauthyExpress(auth: Cauthy) {\n const base = auth.options.basePath\n return function cauthy(req: IncomingMessage, res: ServerResponse, next: Next): void {\n const request = req as NodeRequest\n const path = (request.originalUrl ?? request.url ?? '/').split('?')[0]\n\n if (path === base || path.startsWith(`${base}/`)) {\n void (async () => {\n const answer = await auth.handler(await toWebRequest(request, true))\n res.statusCode = answer.status\n answer.headers.forEach((value, name) => {\n if (name !== 'set-cookie') res.setHeader(name, value)\n })\n addCookies(res, answer.headers.getSetCookie())\n res.end(answer.body === null ? undefined : Buffer.from(await answer.arrayBuffer()))\n })().catch(next)\n return\n }\n\n let asked: Promise<Session | null> | undefined\n request.cauthy = () =>\n (asked ??= (async () => {\n const resolved = await auth.resolve(await toWebRequest(request, false))\n addCookies(res, resolved.cookies)\n return resolved.session\n })())\n next()\n }\n}\n\n/** For a route only a signed-in person may call: answers 401 otherwise. Needs `cauthyExpress` mounted before it. */\nexport function requireSession(req: IncomingMessage, res: ServerResponse, next: Next): void {\n const ask = (req as NodeRequest).cauthy\n if (!ask) return next(new Error('@cauthyhq/node: mount cauthyExpress(auth) before requireSession'))\n ask().then((session) => {\n if (session !== null) return next()\n res.statusCode = 401\n res.setHeader('content-type', 'application/json; charset=utf-8')\n res.setHeader('x-cauthy-session', 'none')\n res.end(JSON.stringify({ error: 'unauthenticated' }))\n }, next)\n}\n"],"mappings":"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","names":[]}
|
package/dist/fastify.d.mts
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import { FastifyReply, FastifyPluginAsync, FastifyInstance } from 'fastify';
|
|
2
|
-
import { S as Session, C as Cauthy } from './cauthy-
|
|
3
|
-
import './keys-D5k0omTb.mjs';
|
|
2
|
+
import { S as Session, C as Cauthy } from './cauthy-CsWUgyv_.mjs';
|
|
4
3
|
import 'jose';
|
|
5
4
|
import './theme.mjs';
|
|
6
|
-
import './identity-BTJ8NB_w.mjs';
|
|
7
5
|
|
|
8
6
|
declare module 'fastify' {
|
|
9
7
|
interface FastifyRequest {
|
package/dist/fastify.d.ts
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import { FastifyReply, FastifyPluginAsync, FastifyInstance } from 'fastify';
|
|
2
|
-
import { S as Session, C as Cauthy } from './cauthy-
|
|
3
|
-
import './keys-D5k0omTb.js';
|
|
2
|
+
import { S as Session, C as Cauthy } from './cauthy-DHLBEuqP.js';
|
|
4
3
|
import 'jose';
|
|
5
4
|
import './theme.js';
|
|
6
|
-
import './identity-BTJ8NB_w.js';
|
|
7
5
|
|
|
8
6
|
declare module 'fastify' {
|
|
9
7
|
interface FastifyRequest {
|
package/dist/fastify.js
CHANGED
|
@@ -73,8 +73,6 @@ var plugin = async (app, { auth, checkMount = true }) => {
|
|
|
73
73
|
return reply.send(res.body === null ? null : Buffer.from(await res.arrayBuffer()));
|
|
74
74
|
};
|
|
75
75
|
app.route({ method: ["GET", "POST"], url: `${base}/*`, handler: serve });
|
|
76
|
-
const key = auth.pact?.contract.jwksPath;
|
|
77
|
-
if (key) app.route({ method: ["GET", "HEAD", "POST"], url: key, handler: serve });
|
|
78
76
|
if (checkMount && process.env.NODE_ENV !== "test") app.addHook("onReady", () => probe(app, auth));
|
|
79
77
|
};
|
|
80
78
|
async function probe(app, auth) {
|
package/dist/fastify.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/fastify.ts"],"sourcesContent":["// Fastify: the routes, and who is signed in on every request.\n//\n// await app.register(cauthyFastify, { auth })\n//\n// app.get('/api/me', async (req, reply) => {\n// const session = await req.cauthy()\n// if (!session) return reply.code(401).send({ error: 'unauthenticated' })\n// return session.user\n// })\n//\n// app.get('/api/books', { preHandler: app.requireSession }, async (req) => { … })\n//\n// Here a session that needs renewing is renewed on the spot: Fastify has the\n// reply in hand, so the new cookie always goes back.\n\nimport { createServer } from 'node:http'\nimport type { AddressInfo } from 'node:net'\nimport type { FastifyInstance, FastifyPluginAsync, FastifyReply, FastifyRequest } from 'fastify'\nimport type { Cauthy } from './cauthy'\nimport type { Session } from './types'\n\ndeclare module 'fastify' {\n interface FastifyRequest {\n /** Who is signed in, or null. Asked once per request. */\n cauthy(): Promise<Session | null>\n }\n interface FastifyInstance {\n /** A preHandler that answers 401 unless somebody is signed in. */\n requireSession(request: FastifyRequest, reply: FastifyReply): Promise<void>\n }\n}\n\nexport interface CauthyFastifyOptions {\n auth: Cauthy\n /**\n * Check, when Fastify is ready, that this plugin is what answers under\n * basePath (`checkFastifyMount`), and fail startup when another route\n * does. Default: true.\n */\n checkMount?: boolean\n}\n\nfunction originOf(req: FastifyRequest): string {\n return `${req.protocol}://${req.headers.host ?? 'localhost'}`\n}\n\nfunction toWebRequest(req: FastifyRequest): Request {\n const headers = new Headers()\n for (const [k, v] of Object.entries(req.headers)) {\n if (Array.isArray(v)) for (const one of v) headers.append(k, one)\n else if (v !== undefined) headers.set(k, v)\n }\n // Fastify knows who is calling (it applies `trustProxy`): that address is\n // the one passed on to Cauthy, whatever the header claimed.\n headers.set('x-forwarded-for', req.ip)\n // What Fastify parsed is the body: the application's own sign-in screens post JSON.\n const body = req.method === 'GET' || req.method === 'HEAD' || req.body === undefined || req.body === null\n ? undefined\n : typeof req.body === 'string' ? req.body : JSON.stringify(req.body)\n return new Request(new URL(req.url, originOf(req)), { method: req.method, headers, body })\n}\n\nconst kSession = Symbol('cauthy.session')\nconst kReply = Symbol('cauthy.reply')\n\nconst plugin: FastifyPluginAsync<CauthyFastifyOptions> = async (app: FastifyInstance, { auth, checkMount = true }) => {\n const base = auth.options.basePath\n\n app.decorateRequest('cauthy', async function (this: FastifyRequest): Promise<Session | null> {\n const self = this as FastifyRequest & { [kSession]?: Promise<Session | null> }\n self[kSession] ??= (async () => {\n const resolved = await auth.resolve(toWebRequest(this))\n // Set through the raw response so the cookie leaves whatever the route\n // answers with, even an error.\n const reply = (this as FastifyRequest & { [kReply]?: FastifyReply })[kReply]\n if (resolved.cookies.length > 0 && reply) reply.header('set-cookie', resolved.cookies)\n return resolved.session\n })()\n return self[kSession]\n })\n\n app.addHook('onRequest', async (req, reply) => {\n ;(req as FastifyRequest & { [kReply]?: FastifyReply })[kReply] = reply\n })\n\n app.decorate('requireSession', async function (request: FastifyRequest, reply: FastifyReply): Promise<void> {\n if ((await request.cauthy()) === null) {\n await reply.code(401).header('x-cauthy-session', 'none').send({ error: 'unauthenticated' })\n }\n })\n\n const serve = async (req: FastifyRequest, reply: FastifyReply) => {\n const res = await auth.handler(toWebRequest(req))\n reply.code(res.status)\n res.headers.forEach((value, name) => {\n if (name !== 'set-cookie') reply.header(name, value)\n })\n const cookies = res.headers.getSetCookie()\n if (cookies.length > 0) reply.header('set-cookie', cookies)\n return reply.send(res.body === null ? null : Buffer.from(await res.arrayBuffer()))\n }\n app.route({ method: ['GET', 'POST'], url: `${base}/*`, handler: serve })\n //
|
|
1
|
+
{"version":3,"sources":["../src/fastify.ts"],"sourcesContent":["// Fastify: the routes, and who is signed in on every request.\n//\n// await app.register(cauthyFastify, { auth })\n//\n// app.get('/api/me', async (req, reply) => {\n// const session = await req.cauthy()\n// if (!session) return reply.code(401).send({ error: 'unauthenticated' })\n// return session.user\n// })\n//\n// app.get('/api/books', { preHandler: app.requireSession }, async (req) => { … })\n//\n// Here a session that needs renewing is renewed on the spot: Fastify has the\n// reply in hand, so the new cookie always goes back.\n\nimport { createServer } from 'node:http'\nimport type { AddressInfo } from 'node:net'\nimport type { FastifyInstance, FastifyPluginAsync, FastifyReply, FastifyRequest } from 'fastify'\nimport type { Cauthy } from './cauthy'\nimport type { Session } from './types'\n\ndeclare module 'fastify' {\n interface FastifyRequest {\n /** Who is signed in, or null. Asked once per request. */\n cauthy(): Promise<Session | null>\n }\n interface FastifyInstance {\n /** A preHandler that answers 401 unless somebody is signed in. */\n requireSession(request: FastifyRequest, reply: FastifyReply): Promise<void>\n }\n}\n\nexport interface CauthyFastifyOptions {\n auth: Cauthy\n /**\n * Check, when Fastify is ready, that this plugin is what answers under\n * basePath (`checkFastifyMount`), and fail startup when another route\n * does. Default: true.\n */\n checkMount?: boolean\n}\n\nfunction originOf(req: FastifyRequest): string {\n return `${req.protocol}://${req.headers.host ?? 'localhost'}`\n}\n\nfunction toWebRequest(req: FastifyRequest): Request {\n const headers = new Headers()\n for (const [k, v] of Object.entries(req.headers)) {\n if (Array.isArray(v)) for (const one of v) headers.append(k, one)\n else if (v !== undefined) headers.set(k, v)\n }\n // Fastify knows who is calling (it applies `trustProxy`): that address is\n // the one passed on to Cauthy, whatever the header claimed.\n headers.set('x-forwarded-for', req.ip)\n // What Fastify parsed is the body: the application's own sign-in screens post JSON.\n const body = req.method === 'GET' || req.method === 'HEAD' || req.body === undefined || req.body === null\n ? undefined\n : typeof req.body === 'string' ? req.body : JSON.stringify(req.body)\n return new Request(new URL(req.url, originOf(req)), { method: req.method, headers, body })\n}\n\nconst kSession = Symbol('cauthy.session')\nconst kReply = Symbol('cauthy.reply')\n\nconst plugin: FastifyPluginAsync<CauthyFastifyOptions> = async (app: FastifyInstance, { auth, checkMount = true }) => {\n const base = auth.options.basePath\n\n app.decorateRequest('cauthy', async function (this: FastifyRequest): Promise<Session | null> {\n const self = this as FastifyRequest & { [kSession]?: Promise<Session | null> }\n self[kSession] ??= (async () => {\n const resolved = await auth.resolve(toWebRequest(this))\n // Set through the raw response so the cookie leaves whatever the route\n // answers with, even an error.\n const reply = (this as FastifyRequest & { [kReply]?: FastifyReply })[kReply]\n if (resolved.cookies.length > 0 && reply) reply.header('set-cookie', resolved.cookies)\n return resolved.session\n })()\n return self[kSession]\n })\n\n app.addHook('onRequest', async (req, reply) => {\n ;(req as FastifyRequest & { [kReply]?: FastifyReply })[kReply] = reply\n })\n\n app.decorate('requireSession', async function (request: FastifyRequest, reply: FastifyReply): Promise<void> {\n if ((await request.cauthy()) === null) {\n await reply.code(401).header('x-cauthy-session', 'none').send({ error: 'unauthenticated' })\n }\n })\n\n const serve = async (req: FastifyRequest, reply: FastifyReply) => {\n const res = await auth.handler(toWebRequest(req))\n reply.code(res.status)\n res.headers.forEach((value, name) => {\n if (name !== 'set-cookie') reply.header(name, value)\n })\n const cookies = res.headers.getSetCookie()\n if (cookies.length > 0) reply.header('set-cookie', cookies)\n return reply.send(res.body === null ? null : Buffer.from(await res.arrayBuffer()))\n }\n app.route({ method: ['GET', 'POST'], url: `${base}/*`, handler: serve })\n // Tests build many apps with routes of their own, and mount nothing for real.\n if (checkMount && process.env.NODE_ENV !== 'test') app.addHook('onReady', () => probe(app, auth))\n}\n\n/**\n * Sends the probes of checkMount through Fastify's own router, over a private\n * loopback socket that only lives for the check. Not `app.inject`: inside\n * `onReady` it would wait for the very ready it runs in.\n */\nasync function probe(app: FastifyInstance, auth: Cauthy): Promise<void> {\n const server = createServer((req, res) => app.routing(req, res))\n await new Promise<void>((resolve, reject) => {\n server.once('error', reject)\n server.listen(0, '127.0.0.1', resolve)\n })\n try {\n await auth.checkMount(`http://127.0.0.1:${(server.address() as AddressInfo).port}`)\n } finally {\n server.closeAllConnections()\n await new Promise<void>((resolve) => server.close(() => resolve()))\n }\n}\n\n/**\n * Checks that the plugin is what answers under basePath, in process, once\n * Fastify is ready (the plugin already does it by itself at `onReady`; this\n * is for tests and for `checkMount: false`):\n *\n * await app.ready()\n * await checkFastifyMount(app, auth)\n */\nexport function checkFastifyMount(app: FastifyInstance, auth: Cauthy): Promise<void> {\n return probe(app, auth)\n}\n\n\n// Outside encapsulation: `req.cauthy()` and `requireSession` are for the whole\n// application, not only for routes registered beside this plugin.\n;(plugin as unknown as Record<symbol, boolean>)[Symbol.for('skip-override')] = true\n;(plugin as unknown as Record<symbol, unknown>)[Symbol.for('fastify.display-name')] = '@cauthyhq/node'\n\nexport const cauthyFastify = plugin\nexport default plugin\n"],"mappings":"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","names":[]}
|
package/dist/fastify.mjs
CHANGED
|
@@ -47,8 +47,6 @@ var plugin = async (app, { auth, checkMount = true }) => {
|
|
|
47
47
|
return reply.send(res.body === null ? null : Buffer.from(await res.arrayBuffer()));
|
|
48
48
|
};
|
|
49
49
|
app.route({ method: ["GET", "POST"], url: `${base}/*`, handler: serve });
|
|
50
|
-
const key = auth.pact?.contract.jwksPath;
|
|
51
|
-
if (key) app.route({ method: ["GET", "HEAD", "POST"], url: key, handler: serve });
|
|
52
50
|
if (checkMount && process.env.NODE_ENV !== "test") app.addHook("onReady", () => probe(app, auth));
|
|
53
51
|
};
|
|
54
52
|
async function probe(app, auth) {
|
package/dist/fastify.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/fastify.ts"],"sourcesContent":["// Fastify: the routes, and who is signed in on every request.\n//\n// await app.register(cauthyFastify, { auth })\n//\n// app.get('/api/me', async (req, reply) => {\n// const session = await req.cauthy()\n// if (!session) return reply.code(401).send({ error: 'unauthenticated' })\n// return session.user\n// })\n//\n// app.get('/api/books', { preHandler: app.requireSession }, async (req) => { … })\n//\n// Here a session that needs renewing is renewed on the spot: Fastify has the\n// reply in hand, so the new cookie always goes back.\n\nimport { createServer } from 'node:http'\nimport type { AddressInfo } from 'node:net'\nimport type { FastifyInstance, FastifyPluginAsync, FastifyReply, FastifyRequest } from 'fastify'\nimport type { Cauthy } from './cauthy'\nimport type { Session } from './types'\n\ndeclare module 'fastify' {\n interface FastifyRequest {\n /** Who is signed in, or null. Asked once per request. */\n cauthy(): Promise<Session | null>\n }\n interface FastifyInstance {\n /** A preHandler that answers 401 unless somebody is signed in. */\n requireSession(request: FastifyRequest, reply: FastifyReply): Promise<void>\n }\n}\n\nexport interface CauthyFastifyOptions {\n auth: Cauthy\n /**\n * Check, when Fastify is ready, that this plugin is what answers under\n * basePath (`checkFastifyMount`), and fail startup when another route\n * does. Default: true.\n */\n checkMount?: boolean\n}\n\nfunction originOf(req: FastifyRequest): string {\n return `${req.protocol}://${req.headers.host ?? 'localhost'}`\n}\n\nfunction toWebRequest(req: FastifyRequest): Request {\n const headers = new Headers()\n for (const [k, v] of Object.entries(req.headers)) {\n if (Array.isArray(v)) for (const one of v) headers.append(k, one)\n else if (v !== undefined) headers.set(k, v)\n }\n // Fastify knows who is calling (it applies `trustProxy`): that address is\n // the one passed on to Cauthy, whatever the header claimed.\n headers.set('x-forwarded-for', req.ip)\n // What Fastify parsed is the body: the application's own sign-in screens post JSON.\n const body = req.method === 'GET' || req.method === 'HEAD' || req.body === undefined || req.body === null\n ? undefined\n : typeof req.body === 'string' ? req.body : JSON.stringify(req.body)\n return new Request(new URL(req.url, originOf(req)), { method: req.method, headers, body })\n}\n\nconst kSession = Symbol('cauthy.session')\nconst kReply = Symbol('cauthy.reply')\n\nconst plugin: FastifyPluginAsync<CauthyFastifyOptions> = async (app: FastifyInstance, { auth, checkMount = true }) => {\n const base = auth.options.basePath\n\n app.decorateRequest('cauthy', async function (this: FastifyRequest): Promise<Session | null> {\n const self = this as FastifyRequest & { [kSession]?: Promise<Session | null> }\n self[kSession] ??= (async () => {\n const resolved = await auth.resolve(toWebRequest(this))\n // Set through the raw response so the cookie leaves whatever the route\n // answers with, even an error.\n const reply = (this as FastifyRequest & { [kReply]?: FastifyReply })[kReply]\n if (resolved.cookies.length > 0 && reply) reply.header('set-cookie', resolved.cookies)\n return resolved.session\n })()\n return self[kSession]\n })\n\n app.addHook('onRequest', async (req, reply) => {\n ;(req as FastifyRequest & { [kReply]?: FastifyReply })[kReply] = reply\n })\n\n app.decorate('requireSession', async function (request: FastifyRequest, reply: FastifyReply): Promise<void> {\n if ((await request.cauthy()) === null) {\n await reply.code(401).header('x-cauthy-session', 'none').send({ error: 'unauthenticated' })\n }\n })\n\n const serve = async (req: FastifyRequest, reply: FastifyReply) => {\n const res = await auth.handler(toWebRequest(req))\n reply.code(res.status)\n res.headers.forEach((value, name) => {\n if (name !== 'set-cookie') reply.header(name, value)\n })\n const cookies = res.headers.getSetCookie()\n if (cookies.length > 0) reply.header('set-cookie', cookies)\n return reply.send(res.body === null ? null : Buffer.from(await res.arrayBuffer()))\n }\n app.route({ method: ['GET', 'POST'], url: `${base}/*`, handler: serve })\n //
|
|
1
|
+
{"version":3,"sources":["../src/fastify.ts"],"sourcesContent":["// Fastify: the routes, and who is signed in on every request.\n//\n// await app.register(cauthyFastify, { auth })\n//\n// app.get('/api/me', async (req, reply) => {\n// const session = await req.cauthy()\n// if (!session) return reply.code(401).send({ error: 'unauthenticated' })\n// return session.user\n// })\n//\n// app.get('/api/books', { preHandler: app.requireSession }, async (req) => { … })\n//\n// Here a session that needs renewing is renewed on the spot: Fastify has the\n// reply in hand, so the new cookie always goes back.\n\nimport { createServer } from 'node:http'\nimport type { AddressInfo } from 'node:net'\nimport type { FastifyInstance, FastifyPluginAsync, FastifyReply, FastifyRequest } from 'fastify'\nimport type { Cauthy } from './cauthy'\nimport type { Session } from './types'\n\ndeclare module 'fastify' {\n interface FastifyRequest {\n /** Who is signed in, or null. Asked once per request. */\n cauthy(): Promise<Session | null>\n }\n interface FastifyInstance {\n /** A preHandler that answers 401 unless somebody is signed in. */\n requireSession(request: FastifyRequest, reply: FastifyReply): Promise<void>\n }\n}\n\nexport interface CauthyFastifyOptions {\n auth: Cauthy\n /**\n * Check, when Fastify is ready, that this plugin is what answers under\n * basePath (`checkFastifyMount`), and fail startup when another route\n * does. Default: true.\n */\n checkMount?: boolean\n}\n\nfunction originOf(req: FastifyRequest): string {\n return `${req.protocol}://${req.headers.host ?? 'localhost'}`\n}\n\nfunction toWebRequest(req: FastifyRequest): Request {\n const headers = new Headers()\n for (const [k, v] of Object.entries(req.headers)) {\n if (Array.isArray(v)) for (const one of v) headers.append(k, one)\n else if (v !== undefined) headers.set(k, v)\n }\n // Fastify knows who is calling (it applies `trustProxy`): that address is\n // the one passed on to Cauthy, whatever the header claimed.\n headers.set('x-forwarded-for', req.ip)\n // What Fastify parsed is the body: the application's own sign-in screens post JSON.\n const body = req.method === 'GET' || req.method === 'HEAD' || req.body === undefined || req.body === null\n ? undefined\n : typeof req.body === 'string' ? req.body : JSON.stringify(req.body)\n return new Request(new URL(req.url, originOf(req)), { method: req.method, headers, body })\n}\n\nconst kSession = Symbol('cauthy.session')\nconst kReply = Symbol('cauthy.reply')\n\nconst plugin: FastifyPluginAsync<CauthyFastifyOptions> = async (app: FastifyInstance, { auth, checkMount = true }) => {\n const base = auth.options.basePath\n\n app.decorateRequest('cauthy', async function (this: FastifyRequest): Promise<Session | null> {\n const self = this as FastifyRequest & { [kSession]?: Promise<Session | null> }\n self[kSession] ??= (async () => {\n const resolved = await auth.resolve(toWebRequest(this))\n // Set through the raw response so the cookie leaves whatever the route\n // answers with, even an error.\n const reply = (this as FastifyRequest & { [kReply]?: FastifyReply })[kReply]\n if (resolved.cookies.length > 0 && reply) reply.header('set-cookie', resolved.cookies)\n return resolved.session\n })()\n return self[kSession]\n })\n\n app.addHook('onRequest', async (req, reply) => {\n ;(req as FastifyRequest & { [kReply]?: FastifyReply })[kReply] = reply\n })\n\n app.decorate('requireSession', async function (request: FastifyRequest, reply: FastifyReply): Promise<void> {\n if ((await request.cauthy()) === null) {\n await reply.code(401).header('x-cauthy-session', 'none').send({ error: 'unauthenticated' })\n }\n })\n\n const serve = async (req: FastifyRequest, reply: FastifyReply) => {\n const res = await auth.handler(toWebRequest(req))\n reply.code(res.status)\n res.headers.forEach((value, name) => {\n if (name !== 'set-cookie') reply.header(name, value)\n })\n const cookies = res.headers.getSetCookie()\n if (cookies.length > 0) reply.header('set-cookie', cookies)\n return reply.send(res.body === null ? null : Buffer.from(await res.arrayBuffer()))\n }\n app.route({ method: ['GET', 'POST'], url: `${base}/*`, handler: serve })\n // Tests build many apps with routes of their own, and mount nothing for real.\n if (checkMount && process.env.NODE_ENV !== 'test') app.addHook('onReady', () => probe(app, auth))\n}\n\n/**\n * Sends the probes of checkMount through Fastify's own router, over a private\n * loopback socket that only lives for the check. Not `app.inject`: inside\n * `onReady` it would wait for the very ready it runs in.\n */\nasync function probe(app: FastifyInstance, auth: Cauthy): Promise<void> {\n const server = createServer((req, res) => app.routing(req, res))\n await new Promise<void>((resolve, reject) => {\n server.once('error', reject)\n server.listen(0, '127.0.0.1', resolve)\n })\n try {\n await auth.checkMount(`http://127.0.0.1:${(server.address() as AddressInfo).port}`)\n } finally {\n server.closeAllConnections()\n await new Promise<void>((resolve) => server.close(() => resolve()))\n }\n}\n\n/**\n * Checks that the plugin is what answers under basePath, in process, once\n * Fastify is ready (the plugin already does it by itself at `onReady`; this\n * is for tests and for `checkMount: false`):\n *\n * await app.ready()\n * await checkFastifyMount(app, auth)\n */\nexport function checkFastifyMount(app: FastifyInstance, auth: Cauthy): Promise<void> {\n return probe(app, auth)\n}\n\n\n// Outside encapsulation: `req.cauthy()` and `requireSession` are for the whole\n// application, not only for routes registered beside this plugin.\n;(plugin as unknown as Record<symbol, boolean>)[Symbol.for('skip-override')] = true\n;(plugin as unknown as Record<symbol, unknown>)[Symbol.for('fastify.display-name')] = '@cauthyhq/node'\n\nexport const cauthyFastify = plugin\nexport default plugin\n"],"mappings":"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","names":[]}
|
package/dist/hono.d.mts
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import { MiddlewareHandler } from 'hono';
|
|
2
|
-
import { S as Session, C as Cauthy } from './cauthy-
|
|
3
|
-
import './keys-D5k0omTb.mjs';
|
|
2
|
+
import { S as Session, C as Cauthy } from './cauthy-CsWUgyv_.mjs';
|
|
4
3
|
import 'jose';
|
|
5
4
|
import './theme.mjs';
|
|
6
|
-
import './identity-BTJ8NB_w.mjs';
|
|
7
5
|
|
|
8
6
|
/** What the middleware keeps on the context: `new Hono<{ Variables: CauthyVariables }>()`. */
|
|
9
7
|
interface CauthyVariables {
|
|
@@ -14,8 +12,7 @@ type Env = {
|
|
|
14
12
|
Variables: CauthyVariables;
|
|
15
13
|
};
|
|
16
14
|
/**
|
|
17
|
-
* Serves the routes under the handler's `basePath
|
|
18
|
-
* application's published key), and sets `session` for
|
|
15
|
+
* Serves the routes under the handler's `basePath`, and sets `session` for
|
|
19
16
|
* every other request. Mount it once, before the routes that use it.
|
|
20
17
|
*/
|
|
21
18
|
declare function cauthyHono(auth: Cauthy): MiddlewareHandler<Env>;
|
package/dist/hono.d.ts
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import { MiddlewareHandler } from 'hono';
|
|
2
|
-
import { S as Session, C as Cauthy } from './cauthy-
|
|
3
|
-
import './keys-D5k0omTb.js';
|
|
2
|
+
import { S as Session, C as Cauthy } from './cauthy-DHLBEuqP.js';
|
|
4
3
|
import 'jose';
|
|
5
4
|
import './theme.js';
|
|
6
|
-
import './identity-BTJ8NB_w.js';
|
|
7
5
|
|
|
8
6
|
/** What the middleware keeps on the context: `new Hono<{ Variables: CauthyVariables }>()`. */
|
|
9
7
|
interface CauthyVariables {
|
|
@@ -14,8 +12,7 @@ type Env = {
|
|
|
14
12
|
Variables: CauthyVariables;
|
|
15
13
|
};
|
|
16
14
|
/**
|
|
17
|
-
* Serves the routes under the handler's `basePath
|
|
18
|
-
* application's published key), and sets `session` for
|
|
15
|
+
* Serves the routes under the handler's `basePath`, and sets `session` for
|
|
19
16
|
* every other request. Mount it once, before the routes that use it.
|
|
20
17
|
*/
|
|
21
18
|
declare function cauthyHono(auth: Cauthy): MiddlewareHandler<Env>;
|
package/dist/hono.js
CHANGED
|
@@ -26,10 +26,9 @@ __export(hono_exports, {
|
|
|
26
26
|
module.exports = __toCommonJS(hono_exports);
|
|
27
27
|
function cauthyHono(auth) {
|
|
28
28
|
const base = auth.options.basePath;
|
|
29
|
-
const key = auth.pact?.contract.jwksPath;
|
|
30
29
|
return async (c, next) => {
|
|
31
30
|
const path = new URL(c.req.url).pathname;
|
|
32
|
-
if (path === base || path.startsWith(`${base}/`)
|
|
31
|
+
if (path === base || path.startsWith(`${base}/`)) return auth.handler(c.req.raw);
|
|
33
32
|
const resolved = await auth.resolve(c.req.raw);
|
|
34
33
|
c.set("session", resolved.session);
|
|
35
34
|
await next();
|