@go-mondo/nextjs-auth 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/README.md +462 -0
- package/dist/access-token-UIlXwi3X.d.cts +27 -0
- package/dist/access-token-UIlXwi3X.d.ts +27 -0
- package/dist/client.cjs +1324 -0
- package/dist/client.cjs.map +1 -0
- package/dist/client.d.cts +201 -0
- package/dist/client.d.ts +201 -0
- package/dist/client.js +1301 -0
- package/dist/client.js.map +1 -0
- package/dist/config.cjs +4 -0
- package/dist/config.cjs.map +1 -0
- package/dist/config.d.cts +90 -0
- package/dist/config.d.ts +90 -0
- package/dist/config.js +3 -0
- package/dist/config.js.map +1 -0
- package/dist/errors.cjs +189 -0
- package/dist/errors.cjs.map +1 -0
- package/dist/errors.d.cts +178 -0
- package/dist/errors.d.ts +178 -0
- package/dist/errors.js +178 -0
- package/dist/errors.js.map +1 -0
- package/dist/hooks.cjs +236 -0
- package/dist/hooks.cjs.map +1 -0
- package/dist/hooks.d.cts +146 -0
- package/dist/hooks.d.ts +146 -0
- package/dist/hooks.js +230 -0
- package/dist/hooks.js.map +1 -0
- package/dist/oauth.cjs +10 -0
- package/dist/oauth.cjs.map +1 -0
- package/dist/oauth.d.cts +55 -0
- package/dist/oauth.d.ts +55 -0
- package/dist/oauth.js +8 -0
- package/dist/oauth.js.map +1 -0
- package/dist/session.cjs +45 -0
- package/dist/session.cjs.map +1 -0
- package/dist/session.d.cts +71 -0
- package/dist/session.d.ts +71 -0
- package/dist/session.js +43 -0
- package/dist/session.js.map +1 -0
- package/dist/types-CbrOw4QQ.d.cts +108 -0
- package/dist/types-CbrOw4QQ.d.ts +108 -0
- package/package.json +146 -0
package/dist/errors.js
ADDED
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
// src/errors/auth.ts
|
|
2
|
+
function appendCause(errorMessage, cause) {
|
|
3
|
+
if (!cause) return errorMessage;
|
|
4
|
+
const separator = errorMessage.endsWith(".") ? "" : ".";
|
|
5
|
+
return `${errorMessage}${separator} CAUSE: ${cause.message}`;
|
|
6
|
+
}
|
|
7
|
+
var AuthError = class extends Error {
|
|
8
|
+
/**
|
|
9
|
+
* A machine-readable error code that remains stable within a major version of the SDK. You
|
|
10
|
+
* should rely on this error code to handle errors. In contrast, the error message is not part of
|
|
11
|
+
* the API and can change anytime. Do **not** parse or otherwise rely on the error message to
|
|
12
|
+
* handle errors.
|
|
13
|
+
*/
|
|
14
|
+
code;
|
|
15
|
+
/**
|
|
16
|
+
* The error class name.
|
|
17
|
+
*/
|
|
18
|
+
name;
|
|
19
|
+
/**
|
|
20
|
+
* The underlying error, if any.
|
|
21
|
+
*
|
|
22
|
+
* **IMPORTANT** When this error is from the Identity Provider ({@link IdentityProviderError}) it can contain user
|
|
23
|
+
* input and is only escaped using basic escaping for putting untrusted data directly into the HTML body.
|
|
24
|
+
*
|
|
25
|
+
* You should **not** render this error without using a templating engine that will properly escape it for other
|
|
26
|
+
* HTML contexts first.
|
|
27
|
+
*/
|
|
28
|
+
cause;
|
|
29
|
+
/**
|
|
30
|
+
* The HTTP status code, if any.
|
|
31
|
+
*/
|
|
32
|
+
status;
|
|
33
|
+
/**
|
|
34
|
+
* @param options - Error metadata used by SDK-specific subclasses.
|
|
35
|
+
*/
|
|
36
|
+
constructor(options) {
|
|
37
|
+
super(appendCause(options.message, options.cause));
|
|
38
|
+
this.code = options.code;
|
|
39
|
+
this.name = options.name;
|
|
40
|
+
this.cause = options.cause;
|
|
41
|
+
this.status = options.status;
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
// src/errors/access-token.ts
|
|
46
|
+
var AccessTokenErrorCode = /* @__PURE__ */ ((AccessTokenErrorCode2) => {
|
|
47
|
+
AccessTokenErrorCode2["MISSING_SESSION"] = "ERR_MISSING_SESSION";
|
|
48
|
+
AccessTokenErrorCode2["MISSING_ACCESS_TOKEN"] = "ERR_MISSING_ACCESS_TOKEN";
|
|
49
|
+
AccessTokenErrorCode2["MISSING_REFRESH_TOKEN"] = "ERR_MISSING_REFRESH_TOKEN";
|
|
50
|
+
AccessTokenErrorCode2["EXPIRED_ACCESS_TOKEN"] = "ERR_EXPIRED_ACCESS_TOKEN";
|
|
51
|
+
AccessTokenErrorCode2["INSUFFICIENT_SCOPE"] = "ERR_INSUFFICIENT_SCOPE";
|
|
52
|
+
AccessTokenErrorCode2["FAILED_REFRESH_GRANT"] = "ERR_FAILED_REFRESH_GRANT";
|
|
53
|
+
return AccessTokenErrorCode2;
|
|
54
|
+
})(AccessTokenErrorCode || {});
|
|
55
|
+
var AccessTokenError = class _AccessTokenError extends AuthError {
|
|
56
|
+
/**
|
|
57
|
+
* @param code - Stable machine-readable error code.
|
|
58
|
+
* @param message - Human-readable diagnostic message.
|
|
59
|
+
* @param cause - Optional lower-level error.
|
|
60
|
+
*/
|
|
61
|
+
constructor(code, message, cause) {
|
|
62
|
+
super({ code, message, name: "AccessTokenError", cause });
|
|
63
|
+
Error.captureStackTrace(this, this.constructor);
|
|
64
|
+
Object.setPrototypeOf(this, _AccessTokenError.prototype);
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
// src/errors/config.ts
|
|
69
|
+
var ConfigError = class _ConfigError extends AuthError {
|
|
70
|
+
static code = "ERR_CONFIG_VALIDATION";
|
|
71
|
+
/**
|
|
72
|
+
* Standard Schema validation issues for the invalid configuration.
|
|
73
|
+
*/
|
|
74
|
+
issues;
|
|
75
|
+
/**
|
|
76
|
+
* @param issues - Standard Schema validation issues.
|
|
77
|
+
*/
|
|
78
|
+
constructor(issues) {
|
|
79
|
+
super({
|
|
80
|
+
code: _ConfigError.code,
|
|
81
|
+
message: `Invalid @go-mondo/nextjs-auth configuration:
|
|
82
|
+
${formatIssues(
|
|
83
|
+
issues
|
|
84
|
+
)}`,
|
|
85
|
+
name: "ConfigError"
|
|
86
|
+
});
|
|
87
|
+
this.issues = issues;
|
|
88
|
+
Error.captureStackTrace(this, this.constructor);
|
|
89
|
+
Object.setPrototypeOf(this, _ConfigError.prototype);
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
function formatIssues(issues) {
|
|
93
|
+
return issues.map((issue) => {
|
|
94
|
+
const path = issue.path?.length ? issue.path.map(formatPathSegment).join(".") : "config";
|
|
95
|
+
return `- ${path}: ${issue.message}`;
|
|
96
|
+
}).join("\n");
|
|
97
|
+
}
|
|
98
|
+
function formatPathSegment(segment) {
|
|
99
|
+
return typeof segment === "object" && segment !== null && "key" in segment ? String(segment.key) : String(segment);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// src/errors/handlers.ts
|
|
103
|
+
var HandlerError = class extends AuthError {
|
|
104
|
+
constructor(options) {
|
|
105
|
+
let status;
|
|
106
|
+
if ("status" in options.cause) status = options.cause.status;
|
|
107
|
+
super({ ...options, status });
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
var CallbackHandlerError = class _CallbackHandlerError extends HandlerError {
|
|
111
|
+
static code = "ERR_CALLBACK_HANDLER_FAILURE";
|
|
112
|
+
constructor(cause) {
|
|
113
|
+
super({
|
|
114
|
+
code: _CallbackHandlerError.code,
|
|
115
|
+
message: "Callback handler failed.",
|
|
116
|
+
name: "CallbackHandlerError",
|
|
117
|
+
cause
|
|
118
|
+
});
|
|
119
|
+
Object.setPrototypeOf(this, _CallbackHandlerError.prototype);
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
var LoginHandlerError = class _LoginHandlerError extends HandlerError {
|
|
123
|
+
static code = "ERR_LOGIN_HANDLER_FAILURE";
|
|
124
|
+
constructor(cause) {
|
|
125
|
+
super({
|
|
126
|
+
code: _LoginHandlerError.code,
|
|
127
|
+
message: "Login handler failed.",
|
|
128
|
+
name: "LoginHandlerError",
|
|
129
|
+
cause
|
|
130
|
+
});
|
|
131
|
+
Object.setPrototypeOf(this, _LoginHandlerError.prototype);
|
|
132
|
+
}
|
|
133
|
+
};
|
|
134
|
+
var LogoutHandlerError = class _LogoutHandlerError extends HandlerError {
|
|
135
|
+
static code = "ERR_LOGOUT_HANDLER_FAILURE";
|
|
136
|
+
constructor(cause) {
|
|
137
|
+
super({
|
|
138
|
+
code: _LogoutHandlerError.code,
|
|
139
|
+
message: "Logout handler failed.",
|
|
140
|
+
name: "LogoutHandlerError",
|
|
141
|
+
cause
|
|
142
|
+
});
|
|
143
|
+
Object.setPrototypeOf(this, _LogoutHandlerError.prototype);
|
|
144
|
+
}
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
// src/errors/state.ts
|
|
148
|
+
var MissingStateParamError = class _MissingStateParamError extends Error {
|
|
149
|
+
static message = "Missing state parameter in Authorization Response.";
|
|
150
|
+
status = 400;
|
|
151
|
+
statusCode = 400;
|
|
152
|
+
constructor() {
|
|
153
|
+
super(_MissingStateParamError.message);
|
|
154
|
+
Object.setPrototypeOf(this, _MissingStateParamError.prototype);
|
|
155
|
+
}
|
|
156
|
+
};
|
|
157
|
+
var MalformedStateCookieError = class _MalformedStateCookieError extends Error {
|
|
158
|
+
static message = "Your state cookie is not valid JSON.";
|
|
159
|
+
status = 400;
|
|
160
|
+
statusCode = 400;
|
|
161
|
+
constructor() {
|
|
162
|
+
super(_MalformedStateCookieError.message);
|
|
163
|
+
Object.setPrototypeOf(this, _MalformedStateCookieError.prototype);
|
|
164
|
+
}
|
|
165
|
+
};
|
|
166
|
+
var MissingStateCookieError = class _MissingStateCookieError extends Error {
|
|
167
|
+
static message = "Missing state cookie from login request (check login URL, callback URL and cookie config).";
|
|
168
|
+
status = 400;
|
|
169
|
+
statusCode = 400;
|
|
170
|
+
constructor() {
|
|
171
|
+
super(_MissingStateCookieError.message);
|
|
172
|
+
Object.setPrototypeOf(this, _MissingStateCookieError.prototype);
|
|
173
|
+
}
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
export { AccessTokenError, AccessTokenErrorCode, AuthError, CallbackHandlerError, ConfigError, LoginHandlerError, LogoutHandlerError, MalformedStateCookieError, MissingStateCookieError, MissingStateParamError };
|
|
177
|
+
//# sourceMappingURL=errors.js.map
|
|
178
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/errors/auth.ts","../src/errors/access-token.ts","../src/errors/config.ts","../src/errors/handlers.ts","../src/errors/state.ts"],"names":["AccessTokenErrorCode"],"mappings":"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","file":"errors.js","sourcesContent":["function appendCause(errorMessage: string, cause?: Error): string {\n if (!cause) return errorMessage;\n const separator = errorMessage.endsWith('.') ? '' : '.';\n return `${errorMessage}${separator} CAUSE: ${cause.message}`;\n}\n\ntype AuthErrorOptions = {\n code: string;\n message: string;\n name: string;\n cause?: Error;\n status?: number;\n};\n\n/**\n * The base class for all SDK errors.\n *\n * Subclasses expose stable machine-readable codes for application-level error\n * handling.\n */\nexport abstract class AuthError extends Error {\n /**\n * A machine-readable error code that remains stable within a major version of the SDK. You\n * should rely on this error code to handle errors. In contrast, the error message is not part of\n * the API and can change anytime. Do **not** parse or otherwise rely on the error message to\n * handle errors.\n */\n public readonly code: string;\n\n /**\n * The error class name.\n */\n public readonly name: string;\n\n /**\n * The underlying error, if any.\n *\n * **IMPORTANT** When this error is from the Identity Provider ({@link IdentityProviderError}) it can contain user\n * input and is only escaped using basic escaping for putting untrusted data directly into the HTML body.\n *\n * You should **not** render this error without using a templating engine that will properly escape it for other\n * HTML contexts first.\n */\n public readonly cause?: Error;\n\n /**\n * The HTTP status code, if any.\n */\n public readonly status?: number;\n\n /**\n * @param options - Error metadata used by SDK-specific subclasses.\n */\n constructor(options: AuthErrorOptions) {\n /* c8 ignore next */\n super(appendCause(options.message, options.cause));\n this.code = options.code;\n this.name = options.name;\n this.cause = options.cause;\n this.status = options.status;\n }\n}\n","import { AuthError } from './auth';\n\n/**\n * Error codes for {@link AccessTokenError}.\n */\nexport enum AccessTokenErrorCode {\n /** No valid session was available. */\n MISSING_SESSION = 'ERR_MISSING_SESSION',\n\n /** Session exists but does not contain an access token. */\n MISSING_ACCESS_TOKEN = 'ERR_MISSING_ACCESS_TOKEN',\n\n /** Refresh was required but no refresh token was stored. */\n MISSING_REFRESH_TOKEN = 'ERR_MISSING_REFRESH_TOKEN',\n\n /** Access token is expired and cannot be returned as-is. */\n EXPIRED_ACCESS_TOKEN = 'ERR_EXPIRED_ACCESS_TOKEN',\n\n /** Access token does not include the requested scopes. */\n INSUFFICIENT_SCOPE = 'ERR_INSUFFICIENT_SCOPE',\n\n /** Refresh token grant failed or returned an invalid response. */\n FAILED_REFRESH_GRANT = 'ERR_FAILED_REFRESH_GRANT',\n}\n\n/**\n * Error thrown when an access token cannot be returned or refreshed.\n *\n * Use {@link AccessTokenError.code} for stable error handling.\n */\nexport class AccessTokenError extends AuthError {\n /**\n * @param code - Stable machine-readable error code.\n * @param message - Human-readable diagnostic message.\n * @param cause - Optional lower-level error.\n */\n constructor(code: AccessTokenErrorCode, message: string, cause?: Error) {\n /* c8 ignore next */\n super({ code: code, message: message, name: 'AccessTokenError', cause });\n\n Error.captureStackTrace(this, this.constructor);\n Object.setPrototypeOf(this, AccessTokenError.prototype);\n }\n}\n","import { AuthError } from './auth';\n\n/**\n * Standard Schema V1 path segment shape.\n */\nexport interface ConfigIssuePathSegment {\n readonly key: PropertyKey;\n}\n\n/**\n * Standard Schema V1 issue shape returned by configuration validation.\n */\nexport interface ConfigIssue {\n readonly message: string;\n readonly path?: readonly (PropertyKey | ConfigIssuePathSegment)[] | undefined;\n}\n\n/**\n * Error thrown when auth configuration validation fails.\n */\nexport class ConfigError extends AuthError {\n public static readonly code = 'ERR_CONFIG_VALIDATION';\n\n /**\n * Standard Schema validation issues for the invalid configuration.\n */\n public readonly issues: readonly ConfigIssue[];\n\n /**\n * @param issues - Standard Schema validation issues.\n */\n constructor(issues: readonly ConfigIssue[]) {\n super({\n code: ConfigError.code,\n message: `Invalid @go-mondo/nextjs-auth configuration:\\n${formatIssues(\n issues,\n )}`,\n name: 'ConfigError',\n });\n\n this.issues = issues;\n\n Error.captureStackTrace(this, this.constructor);\n Object.setPrototypeOf(this, ConfigError.prototype);\n }\n}\n\nfunction formatIssues(issues: readonly ConfigIssue[]): string {\n return issues\n .map((issue) => {\n const path = issue.path?.length\n ? issue.path.map(formatPathSegment).join('.')\n : 'config';\n return `- ${path}: ${issue.message}`;\n })\n .join('\\n');\n}\n\nfunction formatPathSegment(\n segment: NonNullable<ConfigIssue['path']>[number],\n): string {\n return typeof segment === 'object' && segment !== null && 'key' in segment\n ? String(segment.key)\n : String(segment);\n}\n","import { AuthError } from './auth';\n\n/**\n * Error shape used by lower-level HTTP libraries.\n */\ninterface HttpError extends Error {\n status: number;\n statusCode: number;\n}\n\n/**\n * Supported causes for route-handler errors.\n */\nexport type HandlerErrorCause = Error | AuthError | HttpError;\n\ntype HandlerErrorOptions = {\n code: string;\n message: string;\n name: string;\n cause: HandlerErrorCause;\n};\n\n/**\n * Base class for errors thrown by route handlers.\n */\nclass HandlerError extends AuthError {\n constructor(options: HandlerErrorOptions) {\n let status: number | undefined;\n if ('status' in options.cause) status = options.cause.status;\n /* c8 ignore next */\n super({ ...options, status });\n }\n}\n\n/**\n * Error thrown when callback handling fails.\n */\nexport class CallbackHandlerError extends HandlerError {\n public static readonly code: string = 'ERR_CALLBACK_HANDLER_FAILURE';\n\n constructor(cause: HandlerErrorCause) {\n super({\n code: CallbackHandlerError.code,\n message: 'Callback handler failed.',\n name: 'CallbackHandlerError',\n cause,\n }); /* c8 ignore next */\n Object.setPrototypeOf(this, CallbackHandlerError.prototype);\n }\n}\n\n/**\n * Error thrown when login handling fails.\n */\nexport class LoginHandlerError extends HandlerError {\n public static readonly code: string = 'ERR_LOGIN_HANDLER_FAILURE';\n\n constructor(cause: HandlerErrorCause) {\n super({\n code: LoginHandlerError.code,\n message: 'Login handler failed.',\n name: 'LoginHandlerError',\n cause,\n }); /* c8 ignore next */\n Object.setPrototypeOf(this, LoginHandlerError.prototype);\n }\n}\n\n/**\n * Error thrown when logout handling fails.\n */\nexport class LogoutHandlerError extends HandlerError {\n public static readonly code: string = 'ERR_LOGOUT_HANDLER_FAILURE';\n\n constructor(cause: HandlerErrorCause) {\n super({\n code: LogoutHandlerError.code,\n message: 'Logout handler failed.',\n name: 'LogoutHandlerError',\n cause,\n }); /* c8 ignore next */\n Object.setPrototypeOf(this, LogoutHandlerError.prototype);\n }\n}\n","/**\n * Error used when the callback response is missing a `state` parameter.\n */\nexport class MissingStateParamError extends Error {\n static message = 'Missing state parameter in Authorization Response.';\n status = 400;\n statusCode = 400;\n\n constructor() {\n /* c8 ignore next */\n super(MissingStateParamError.message);\n Object.setPrototypeOf(this, MissingStateParamError.prototype);\n }\n}\n\n/**\n * Error used when transaction state exists but cannot be parsed.\n */\nexport class MalformedStateCookieError extends Error {\n static message = 'Your state cookie is not valid JSON.';\n status = 400;\n statusCode = 400;\n\n constructor() {\n /* c8 ignore next */\n super(MalformedStateCookieError.message);\n Object.setPrototypeOf(this, MalformedStateCookieError.prototype);\n }\n}\n\n/**\n * Error used when the callback cannot find the login transaction cookie.\n */\nexport class MissingStateCookieError extends Error {\n static message =\n 'Missing state cookie from login request (check login URL, callback URL and cookie config).';\n status = 400;\n statusCode = 400;\n\n constructor() {\n /* c8 ignore next */\n super(MissingStateCookieError.message);\n Object.setPrototypeOf(this, MissingStateCookieError.prototype);\n }\n}\n"]}
|
package/dist/hooks.cjs
ADDED
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
var reactQuery = require('@tanstack/react-query');
|
|
5
|
+
|
|
6
|
+
// src/hooks/access-token.ts
|
|
7
|
+
|
|
8
|
+
// src/config/routes.ts
|
|
9
|
+
var DEFAULT_ROUTES = {
|
|
10
|
+
session: "/auth/session",
|
|
11
|
+
accessToken: "/auth/access-token"};
|
|
12
|
+
function getPublicSessionRoute() {
|
|
13
|
+
return typeof process === "undefined" ? DEFAULT_ROUTES.session : process.env.NEXT_PUBLIC_SESSION_ROUTE || DEFAULT_ROUTES.session;
|
|
14
|
+
}
|
|
15
|
+
function getPublicAccessTokenRoute() {
|
|
16
|
+
return typeof process === "undefined" ? DEFAULT_ROUTES.accessToken : process.env.NEXT_PUBLIC_ACCESS_TOKEN_ROUTE || DEFAULT_ROUTES.accessToken;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// src/hooks/access-token.ts
|
|
20
|
+
async function fetchAccessToken(options = {}) {
|
|
21
|
+
const {
|
|
22
|
+
refresh,
|
|
23
|
+
refreshBeforeExpiresIn,
|
|
24
|
+
request,
|
|
25
|
+
route = getPublicAccessTokenRoute(),
|
|
26
|
+
scopes
|
|
27
|
+
} = options;
|
|
28
|
+
const body = getRequestBody({ refresh, refreshBeforeExpiresIn, scopes });
|
|
29
|
+
const headers = new Headers(request?.headers);
|
|
30
|
+
if (body && !headers.has("content-type")) {
|
|
31
|
+
headers.set("content-type", "application/json");
|
|
32
|
+
}
|
|
33
|
+
const response = await fetch(route, {
|
|
34
|
+
...request,
|
|
35
|
+
body: body ? JSON.stringify(body) : request?.body,
|
|
36
|
+
credentials: "same-origin",
|
|
37
|
+
headers,
|
|
38
|
+
method: body ? "POST" : request?.method
|
|
39
|
+
});
|
|
40
|
+
if (!response.ok) {
|
|
41
|
+
const message = await getErrorMessage(response);
|
|
42
|
+
throw new Error(message);
|
|
43
|
+
}
|
|
44
|
+
return await response.json();
|
|
45
|
+
}
|
|
46
|
+
function createAccessTokenProvider(defaultOptions = {}) {
|
|
47
|
+
const entries = /* @__PURE__ */ new Map();
|
|
48
|
+
const loadAccessToken = async (options) => {
|
|
49
|
+
const key = getAccessTokenCacheKey(options);
|
|
50
|
+
let promise;
|
|
51
|
+
promise = fetchAccessToken(options).then(
|
|
52
|
+
(token) => {
|
|
53
|
+
entries.set(key, { token });
|
|
54
|
+
return token;
|
|
55
|
+
},
|
|
56
|
+
(error) => {
|
|
57
|
+
if (entries.get(key)?.promise === promise) {
|
|
58
|
+
entries.delete(key);
|
|
59
|
+
}
|
|
60
|
+
throw error;
|
|
61
|
+
}
|
|
62
|
+
);
|
|
63
|
+
entries.set(key, { promise });
|
|
64
|
+
return promise;
|
|
65
|
+
};
|
|
66
|
+
return {
|
|
67
|
+
getAccessToken(options = {}) {
|
|
68
|
+
const mergedOptions = mergeFetchAccessTokenOptions(
|
|
69
|
+
defaultOptions,
|
|
70
|
+
options
|
|
71
|
+
);
|
|
72
|
+
const key = getAccessTokenCacheKey(mergedOptions);
|
|
73
|
+
const entry = entries.get(key);
|
|
74
|
+
if (mergedOptions.refresh !== true && entry?.token && canUseCachedAccessToken(entry.token, mergedOptions)) {
|
|
75
|
+
return Promise.resolve(entry.token);
|
|
76
|
+
}
|
|
77
|
+
if (mergedOptions.refresh !== true && entry?.promise) {
|
|
78
|
+
return entry.promise;
|
|
79
|
+
}
|
|
80
|
+
return loadAccessToken(mergedOptions);
|
|
81
|
+
},
|
|
82
|
+
clear(options) {
|
|
83
|
+
if (!options) {
|
|
84
|
+
entries.clear();
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
entries.delete(
|
|
88
|
+
getAccessTokenCacheKey(
|
|
89
|
+
mergeFetchAccessTokenOptions(defaultOptions, options)
|
|
90
|
+
)
|
|
91
|
+
);
|
|
92
|
+
},
|
|
93
|
+
clearAll() {
|
|
94
|
+
entries.clear();
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
function useAccessToken(options = {}) {
|
|
99
|
+
const {
|
|
100
|
+
queryKey,
|
|
101
|
+
refresh,
|
|
102
|
+
refreshBeforeExpiresIn,
|
|
103
|
+
request,
|
|
104
|
+
route = getPublicAccessTokenRoute(),
|
|
105
|
+
scopes,
|
|
106
|
+
...queryOptions
|
|
107
|
+
} = options;
|
|
108
|
+
return reactQuery.useQuery({
|
|
109
|
+
queryKey: queryKey ?? [
|
|
110
|
+
"mondo-auth",
|
|
111
|
+
"access-token",
|
|
112
|
+
route,
|
|
113
|
+
normalizeScopes(scopes),
|
|
114
|
+
refresh,
|
|
115
|
+
refreshBeforeExpiresIn
|
|
116
|
+
],
|
|
117
|
+
queryFn: () => fetchAccessToken({
|
|
118
|
+
refresh,
|
|
119
|
+
refreshBeforeExpiresIn,
|
|
120
|
+
request,
|
|
121
|
+
route,
|
|
122
|
+
scopes
|
|
123
|
+
}),
|
|
124
|
+
...queryOptions
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
function getRequestBody(options) {
|
|
128
|
+
if (options.refresh === void 0 && options.refreshBeforeExpiresIn === void 0 && options.scopes === void 0) {
|
|
129
|
+
return void 0;
|
|
130
|
+
}
|
|
131
|
+
return options;
|
|
132
|
+
}
|
|
133
|
+
function mergeFetchAccessTokenOptions(defaultOptions, options) {
|
|
134
|
+
const request = mergeRequestInit(defaultOptions.request, options.request);
|
|
135
|
+
return {
|
|
136
|
+
...defaultOptions,
|
|
137
|
+
...options,
|
|
138
|
+
request
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
function mergeRequestInit(defaultRequest, request) {
|
|
142
|
+
if (!defaultRequest && !request) {
|
|
143
|
+
return void 0;
|
|
144
|
+
}
|
|
145
|
+
return {
|
|
146
|
+
...defaultRequest,
|
|
147
|
+
...request,
|
|
148
|
+
headers: mergeHeaders(defaultRequest?.headers, request?.headers)
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
function mergeHeaders(defaultHeaders, headers) {
|
|
152
|
+
if (!defaultHeaders && !headers) {
|
|
153
|
+
return void 0;
|
|
154
|
+
}
|
|
155
|
+
const mergedHeaders = new Headers(defaultHeaders);
|
|
156
|
+
new Headers(headers).forEach((value, key) => {
|
|
157
|
+
mergedHeaders.set(key, value);
|
|
158
|
+
});
|
|
159
|
+
return mergedHeaders;
|
|
160
|
+
}
|
|
161
|
+
function canUseCachedAccessToken(token, options) {
|
|
162
|
+
const skew = options.refreshBeforeExpiresIn ?? 60;
|
|
163
|
+
return token.expiresAt > Math.floor(Date.now() / 1e3) + skew;
|
|
164
|
+
}
|
|
165
|
+
function getAccessTokenCacheKey(options) {
|
|
166
|
+
return JSON.stringify([
|
|
167
|
+
options.route ?? getPublicAccessTokenRoute(),
|
|
168
|
+
normalizeScopes(options.scopes)
|
|
169
|
+
]);
|
|
170
|
+
}
|
|
171
|
+
async function getErrorMessage(response) {
|
|
172
|
+
const payload = await readJson(response);
|
|
173
|
+
if (typeof payload?.error_description === "string") {
|
|
174
|
+
return payload.error_description;
|
|
175
|
+
}
|
|
176
|
+
return `Unable to load an access token (${response.status}).`;
|
|
177
|
+
}
|
|
178
|
+
async function readJson(response) {
|
|
179
|
+
try {
|
|
180
|
+
return await response.json();
|
|
181
|
+
} catch {
|
|
182
|
+
return void 0;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
function normalizeScopes(scopes) {
|
|
186
|
+
return Array.isArray(scopes) ? scopes.join(" ") : scopes;
|
|
187
|
+
}
|
|
188
|
+
async function fetchUserProfile(options = {}) {
|
|
189
|
+
const { request, route = getPublicSessionRoute() } = options;
|
|
190
|
+
const response = await fetch(route, {
|
|
191
|
+
credentials: "same-origin",
|
|
192
|
+
...request
|
|
193
|
+
});
|
|
194
|
+
if (response.status === 401 || response.status === 403) {
|
|
195
|
+
return void 0;
|
|
196
|
+
}
|
|
197
|
+
if (!response.ok) {
|
|
198
|
+
throw new Error(`Unable to load the current user (${response.status}).`);
|
|
199
|
+
}
|
|
200
|
+
return userProfileFromResponse(
|
|
201
|
+
await response.json()
|
|
202
|
+
);
|
|
203
|
+
}
|
|
204
|
+
function useUserProfile(options = {}) {
|
|
205
|
+
const {
|
|
206
|
+
queryKey,
|
|
207
|
+
route = getPublicSessionRoute(),
|
|
208
|
+
request,
|
|
209
|
+
...queryOptions
|
|
210
|
+
} = options;
|
|
211
|
+
return reactQuery.useQuery({
|
|
212
|
+
queryKey: queryKey ?? ["mondo-auth", "user-profile", route],
|
|
213
|
+
queryFn: () => fetchUserProfile({ request, route }),
|
|
214
|
+
...queryOptions
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
function userProfileFromResponse(payload) {
|
|
218
|
+
if (!payload || typeof payload !== "object") {
|
|
219
|
+
return void 0;
|
|
220
|
+
}
|
|
221
|
+
if ("user" in payload) {
|
|
222
|
+
return isRecord(payload.user) ? payload.user : void 0;
|
|
223
|
+
}
|
|
224
|
+
return payload;
|
|
225
|
+
}
|
|
226
|
+
function isRecord(value) {
|
|
227
|
+
return Boolean(value && typeof value === "object");
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
exports.createAccessTokenProvider = createAccessTokenProvider;
|
|
231
|
+
exports.fetchAccessToken = fetchAccessToken;
|
|
232
|
+
exports.fetchUserProfile = fetchUserProfile;
|
|
233
|
+
exports.useAccessToken = useAccessToken;
|
|
234
|
+
exports.useUserProfile = useUserProfile;
|
|
235
|
+
//# sourceMappingURL=hooks.cjs.map
|
|
236
|
+
//# sourceMappingURL=hooks.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/config/routes.ts","../src/hooks/access-token.ts","../src/hooks/user.ts"],"names":["useQuery"],"mappings":"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","file":"hooks.cjs","sourcesContent":["/**\n * Built-in auth route defaults used by both server configuration and\n * browser-safe client helpers.\n */\nexport const DEFAULT_ROUTES = {\n login: '/auth/login',\n callback: '/auth/callback',\n logout: '/auth/logout',\n session: '/auth/session',\n accessToken: '/auth/access-token',\n postLogoutRedirect: '/',\n} as const;\n\n/**\n * Returns the session route that browser code can safely call.\n *\n * The full server configuration reads secret-bearing environment variables, so\n * client hooks use the public session route override instead.\n */\nexport function getPublicSessionRoute(): string {\n return typeof process === 'undefined'\n ? DEFAULT_ROUTES.session\n : process.env.NEXT_PUBLIC_SESSION_ROUTE || DEFAULT_ROUTES.session;\n}\n\n/**\n * Returns the access-token route that browser code can safely call.\n *\n * The full server configuration may read secret-bearing environment variables,\n * so client hooks use the public access-token route override instead.\n */\nexport function getPublicAccessTokenRoute(): string {\n return typeof process === 'undefined'\n ? DEFAULT_ROUTES.accessToken\n : process.env.NEXT_PUBLIC_ACCESS_TOKEN_ROUTE || DEFAULT_ROUTES.accessToken;\n}\n","import {\n useQuery,\n type QueryKey,\n type UseQueryOptions,\n type UseQueryResult,\n} from '@tanstack/react-query';\nimport { getPublicAccessTokenRoute } from '../config/routes';\nimport type {\n AccessTokenResult,\n GetAccessTokenOptions,\n} from '../oauth/access-token';\n\n/**\n * Options for fetching an access token from browser code.\n */\nexport type FetchAccessTokenOptions = GetAccessTokenOptions & {\n /**\n * Mounted access-token route. Defaults to `/auth/access-token`.\n */\n route?: string;\n\n /**\n * Additional fetch options merged with `credentials: \"same-origin\"`.\n */\n request?: RequestInit;\n};\n\n/**\n * Access-token provider for imperative browser API clients.\n */\nexport type AccessTokenProvider = {\n /**\n * Returns a cached access token when it is still fresh, otherwise calls the\n * mounted access-token route and stores the result.\n */\n getAccessToken: (\n options?: FetchAccessTokenOptions,\n ) => Promise<AccessTokenResult>;\n\n /**\n * Clears the cached entry for the provided route and scopes. Clears every\n * cached entry when no options are provided.\n */\n clear: (options?: Pick<FetchAccessTokenOptions, 'route' | 'scopes'>) => void;\n\n /**\n * Clears every cached entry.\n */\n clearAll: () => void;\n};\n\n/**\n * Default TanStack Query key used by {@link useAccessToken}.\n */\nexport type UseAccessTokenQueryKey = readonly [\n 'mondo-auth',\n 'access-token',\n string,\n string | undefined,\n boolean | undefined,\n number | undefined,\n];\n\n/**\n * Options accepted by {@link useAccessToken}.\n *\n * All normal TanStack Query options are supported except `queryFn` and\n * `queryKey`, which are owned by the hook. Pass `queryKey` here to override the\n * default key.\n */\nexport type UseAccessTokenOptions<\n TData = AccessTokenResult,\n TQueryKey extends QueryKey = UseAccessTokenQueryKey,\n> = FetchAccessTokenOptions &\n Omit<\n UseQueryOptions<AccessTokenResult, Error, TData, TQueryKey>,\n 'queryFn' | 'queryKey'\n > & {\n /**\n * TanStack Query key. Defaults to route, scopes, refresh, and refresh skew.\n */\n queryKey?: TQueryKey;\n };\n\n/**\n * Fetches a current access token from the mounted access-token route.\n *\n * The server reads the local sealed session and refreshes the token when\n * needed, when `refresh` is true, or when requested scopes are missing.\n */\nexport async function fetchAccessToken(\n options: FetchAccessTokenOptions = {},\n): Promise<AccessTokenResult> {\n const {\n refresh,\n refreshBeforeExpiresIn,\n request,\n route = getPublicAccessTokenRoute(),\n scopes,\n } = options;\n const body = getRequestBody({ refresh, refreshBeforeExpiresIn, scopes });\n const headers = new Headers(request?.headers);\n\n if (body && !headers.has('content-type')) {\n headers.set('content-type', 'application/json');\n }\n\n const response = await fetch(route, {\n ...request,\n body: body ? JSON.stringify(body) : request?.body,\n credentials: 'same-origin',\n headers,\n method: body ? 'POST' : request?.method,\n });\n\n if (!response.ok) {\n const message = await getErrorMessage(response);\n throw new Error(message);\n }\n\n return (await response.json()) as AccessTokenResult;\n}\n\n/**\n * Creates an in-memory access-token cache for imperative browser API clients.\n *\n * This is useful when an app needs to make multiple browser-side API calls with\n * a bearer token. Cached tokens are kept only in memory, are refreshed before\n * expiry, and concurrent misses share one `/auth/access-token` request.\n */\nexport function createAccessTokenProvider(\n defaultOptions: FetchAccessTokenOptions = {},\n): AccessTokenProvider {\n const entries = new Map<string, AccessTokenCacheEntry>();\n\n const loadAccessToken = async (options: FetchAccessTokenOptions) => {\n const key = getAccessTokenCacheKey(options);\n let promise: Promise<AccessTokenResult>;\n\n promise = fetchAccessToken(options).then(\n (token) => {\n entries.set(key, { token });\n return token;\n },\n (error) => {\n if (entries.get(key)?.promise === promise) {\n entries.delete(key);\n }\n\n throw error;\n },\n );\n\n entries.set(key, { promise });\n return promise;\n };\n\n return {\n getAccessToken(options = {}) {\n const mergedOptions = mergeFetchAccessTokenOptions(\n defaultOptions,\n options,\n );\n const key = getAccessTokenCacheKey(mergedOptions);\n const entry = entries.get(key);\n\n if (\n mergedOptions.refresh !== true &&\n entry?.token &&\n canUseCachedAccessToken(entry.token, mergedOptions)\n ) {\n return Promise.resolve(entry.token);\n }\n\n if (mergedOptions.refresh !== true && entry?.promise) {\n return entry.promise;\n }\n\n return loadAccessToken(mergedOptions);\n },\n\n clear(options) {\n if (!options) {\n entries.clear();\n return;\n }\n\n entries.delete(\n getAccessTokenCacheKey(\n mergeFetchAccessTokenOptions(defaultOptions, options),\n ),\n );\n },\n\n clearAll() {\n entries.clear();\n },\n };\n}\n\n/**\n * TanStack Query hook for a current access token.\n *\n * Apps must provide a `QueryClientProvider` above this hook. The hook calls the\n * app's local access-token endpoint; refresh tokens never leave the server.\n */\nexport function useAccessToken<\n TData = AccessTokenResult,\n TQueryKey extends QueryKey = UseAccessTokenQueryKey,\n>(\n options: UseAccessTokenOptions<TData, TQueryKey> = {},\n): UseQueryResult<TData, Error> {\n const {\n queryKey,\n refresh,\n refreshBeforeExpiresIn,\n request,\n route = getPublicAccessTokenRoute(),\n scopes,\n ...queryOptions\n } = options;\n\n return useQuery({\n queryKey:\n queryKey ??\n ([\n 'mondo-auth',\n 'access-token',\n route,\n normalizeScopes(scopes),\n refresh,\n refreshBeforeExpiresIn,\n ] satisfies UseAccessTokenQueryKey),\n queryFn: () =>\n fetchAccessToken({\n refresh,\n refreshBeforeExpiresIn,\n request,\n route,\n scopes,\n }),\n ...queryOptions,\n } as UseQueryOptions<AccessTokenResult, Error, TData, TQueryKey>);\n}\n\nfunction getRequestBody(options: GetAccessTokenOptions) {\n if (\n options.refresh === undefined &&\n options.refreshBeforeExpiresIn === undefined &&\n options.scopes === undefined\n ) {\n return undefined;\n }\n\n return options;\n}\n\ntype AccessTokenCacheEntry = {\n token?: AccessTokenResult;\n promise?: Promise<AccessTokenResult>;\n};\n\nfunction mergeFetchAccessTokenOptions(\n defaultOptions: FetchAccessTokenOptions,\n options: FetchAccessTokenOptions,\n): FetchAccessTokenOptions {\n const request = mergeRequestInit(defaultOptions.request, options.request);\n\n return {\n ...defaultOptions,\n ...options,\n request,\n };\n}\n\nfunction mergeRequestInit(\n defaultRequest: RequestInit | undefined,\n request: RequestInit | undefined,\n): RequestInit | undefined {\n if (!defaultRequest && !request) {\n return undefined;\n }\n\n return {\n ...defaultRequest,\n ...request,\n headers: mergeHeaders(defaultRequest?.headers, request?.headers),\n };\n}\n\nfunction mergeHeaders(\n defaultHeaders: HeadersInit | undefined,\n headers: HeadersInit | undefined,\n): Headers | undefined {\n if (!defaultHeaders && !headers) {\n return undefined;\n }\n\n const mergedHeaders = new Headers(defaultHeaders);\n new Headers(headers).forEach((value, key) => {\n mergedHeaders.set(key, value);\n });\n\n return mergedHeaders;\n}\n\nfunction canUseCachedAccessToken(\n token: AccessTokenResult,\n options: GetAccessTokenOptions,\n): boolean {\n const skew = options.refreshBeforeExpiresIn ?? 60;\n return token.expiresAt > Math.floor(Date.now() / 1000) + skew;\n}\n\nfunction getAccessTokenCacheKey(\n options: Pick<FetchAccessTokenOptions, 'route' | 'scopes'>,\n) {\n return JSON.stringify([\n options.route ?? getPublicAccessTokenRoute(),\n normalizeScopes(options.scopes),\n ]);\n}\n\nasync function getErrorMessage(response: Response): Promise<string> {\n const payload = (await readJson(response)) as\n | { error_description?: unknown }\n | undefined;\n\n if (typeof payload?.error_description === 'string') {\n return payload.error_description;\n }\n\n return `Unable to load an access token (${response.status}).`;\n}\n\nasync function readJson(response: Response): Promise<unknown> {\n try {\n return await response.json();\n } catch {\n return undefined;\n }\n}\n\nfunction normalizeScopes(scopes: string | Array<string> | undefined) {\n return Array.isArray(scopes) ? scopes.join(' ') : scopes;\n}\n","import {\n useQuery,\n type QueryKey,\n type UseQueryOptions,\n type UseQueryResult,\n} from '@tanstack/react-query';\nimport { getPublicSessionRoute } from '../config/routes';\nimport type { Claims, UserProfile } from '../session/types';\n\n/**\n * JSON shapes accepted from the mounted session route.\n *\n * The default session route returns `{ user }` as part of the full session, but\n * apps may transform that route to return the user profile directly.\n */\nexport type UserProfileEndpointResponse<UserClaims extends Claims = Claims> =\n | { user?: UserProfile<UserClaims> | null | undefined }\n | UserProfile<UserClaims>\n | null\n | undefined;\n\n/**\n * Options for fetching the current user profile from browser code.\n */\nexport type FetchUserProfileOptions = {\n /**\n * Mounted session route. Defaults to `/auth/session`.\n */\n route?: string;\n\n /**\n * Additional fetch options merged with `credentials: \"same-origin\"`.\n */\n request?: RequestInit;\n};\n\n/**\n * Default TanStack Query key used by {@link useUserProfile}.\n */\nexport type UseUserProfileQueryKey = readonly [\n 'mondo-auth',\n 'user-profile',\n string,\n];\n\n/**\n * Options accepted by {@link useUserProfile}.\n *\n * All normal TanStack Query options are supported except `queryFn` and\n * `queryKey`, which are owned by the hook. Pass `queryKey` here to override the\n * default key.\n */\nexport type UseUserProfileOptions<\n UserClaims extends Claims = Claims,\n TData = UserProfile<UserClaims> | undefined,\n TQueryKey extends QueryKey = UseUserProfileQueryKey,\n> = FetchUserProfileOptions &\n Omit<\n UseQueryOptions<\n UserProfile<UserClaims> | undefined,\n Error,\n TData,\n TQueryKey\n >,\n 'queryFn' | 'queryKey'\n > & {\n /**\n * TanStack Query key. Defaults to `[\"mondo-auth\", \"user-profile\", route]`.\n */\n queryKey?: TQueryKey;\n };\n\n/**\n * Fetches the currently authenticated user profile from the mounted session\n * route.\n *\n * This reads the app's local server-managed session. It does not call the\n * authorization server directly.\n *\n * @returns The current user profile, or `undefined` when no session exists.\n */\nexport async function fetchUserProfile<UserClaims extends Claims = Claims>(\n options: FetchUserProfileOptions = {},\n): Promise<UserProfile<UserClaims> | undefined> {\n const { request, route = getPublicSessionRoute() } = options;\n const response = await fetch(route, {\n credentials: 'same-origin',\n ...request,\n });\n\n if (response.status === 401 || response.status === 403) {\n return undefined;\n }\n\n if (!response.ok) {\n throw new Error(`Unable to load the current user (${response.status}).`);\n }\n\n return userProfileFromResponse<UserClaims>(\n (await response.json()) as UserProfileEndpointResponse<UserClaims>,\n );\n}\n\n/**\n * TanStack Query hook for the currently authenticated user profile.\n *\n * Apps must provide a `QueryClientProvider` above this hook. The hook reads the\n * app's local session endpoint and caches the resulting user profile in\n * TanStack Query.\n */\nexport function useUserProfile<\n UserClaims extends Claims = Claims,\n TData = UserProfile<UserClaims> | undefined,\n TQueryKey extends QueryKey = UseUserProfileQueryKey,\n>(\n options: UseUserProfileOptions<UserClaims, TData, TQueryKey> = {},\n): UseQueryResult<TData, Error> {\n const {\n queryKey,\n route = getPublicSessionRoute(),\n request,\n ...queryOptions\n } = options;\n\n return useQuery({\n queryKey:\n queryKey ??\n (['mondo-auth', 'user-profile', route] satisfies UseUserProfileQueryKey),\n queryFn: () => fetchUserProfile<UserClaims>({ request, route }),\n ...queryOptions,\n } as UseQueryOptions<\n UserProfile<UserClaims> | undefined,\n Error,\n TData,\n TQueryKey\n >);\n}\n\nfunction userProfileFromResponse<UserClaims extends Claims>(\n payload: UserProfileEndpointResponse<UserClaims>,\n): UserProfile<UserClaims> | undefined {\n if (!payload || typeof payload !== 'object') {\n return undefined;\n }\n\n if ('user' in payload) {\n return isRecord(payload.user)\n ? (payload.user as UserProfile<UserClaims>)\n : undefined;\n }\n\n return payload as UserProfile<UserClaims>;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return Boolean(value && typeof value === 'object');\n}\n"]}
|
package/dist/hooks.d.cts
ADDED
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import { QueryKey, UseQueryOptions, UseQueryResult } from '@tanstack/react-query';
|
|
2
|
+
import { G as GetAccessTokenOptions, A as AccessTokenResult } from './access-token-UIlXwi3X.cjs';
|
|
3
|
+
import { C as Claims, U as UserProfile } from './types-CbrOw4QQ.cjs';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Options for fetching an access token from browser code.
|
|
7
|
+
*/
|
|
8
|
+
type FetchAccessTokenOptions = GetAccessTokenOptions & {
|
|
9
|
+
/**
|
|
10
|
+
* Mounted access-token route. Defaults to `/auth/access-token`.
|
|
11
|
+
*/
|
|
12
|
+
route?: string;
|
|
13
|
+
/**
|
|
14
|
+
* Additional fetch options merged with `credentials: "same-origin"`.
|
|
15
|
+
*/
|
|
16
|
+
request?: RequestInit;
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* Access-token provider for imperative browser API clients.
|
|
20
|
+
*/
|
|
21
|
+
type AccessTokenProvider = {
|
|
22
|
+
/**
|
|
23
|
+
* Returns a cached access token when it is still fresh, otherwise calls the
|
|
24
|
+
* mounted access-token route and stores the result.
|
|
25
|
+
*/
|
|
26
|
+
getAccessToken: (options?: FetchAccessTokenOptions) => Promise<AccessTokenResult>;
|
|
27
|
+
/**
|
|
28
|
+
* Clears the cached entry for the provided route and scopes. Clears every
|
|
29
|
+
* cached entry when no options are provided.
|
|
30
|
+
*/
|
|
31
|
+
clear: (options?: Pick<FetchAccessTokenOptions, 'route' | 'scopes'>) => void;
|
|
32
|
+
/**
|
|
33
|
+
* Clears every cached entry.
|
|
34
|
+
*/
|
|
35
|
+
clearAll: () => void;
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
38
|
+
* Default TanStack Query key used by {@link useAccessToken}.
|
|
39
|
+
*/
|
|
40
|
+
type UseAccessTokenQueryKey = readonly [
|
|
41
|
+
'mondo-auth',
|
|
42
|
+
'access-token',
|
|
43
|
+
string,
|
|
44
|
+
string | undefined,
|
|
45
|
+
boolean | undefined,
|
|
46
|
+
number | undefined
|
|
47
|
+
];
|
|
48
|
+
/**
|
|
49
|
+
* Options accepted by {@link useAccessToken}.
|
|
50
|
+
*
|
|
51
|
+
* All normal TanStack Query options are supported except `queryFn` and
|
|
52
|
+
* `queryKey`, which are owned by the hook. Pass `queryKey` here to override the
|
|
53
|
+
* default key.
|
|
54
|
+
*/
|
|
55
|
+
type UseAccessTokenOptions<TData = AccessTokenResult, TQueryKey extends QueryKey = UseAccessTokenQueryKey> = FetchAccessTokenOptions & Omit<UseQueryOptions<AccessTokenResult, Error, TData, TQueryKey>, 'queryFn' | 'queryKey'> & {
|
|
56
|
+
/**
|
|
57
|
+
* TanStack Query key. Defaults to route, scopes, refresh, and refresh skew.
|
|
58
|
+
*/
|
|
59
|
+
queryKey?: TQueryKey;
|
|
60
|
+
};
|
|
61
|
+
/**
|
|
62
|
+
* Fetches a current access token from the mounted access-token route.
|
|
63
|
+
*
|
|
64
|
+
* The server reads the local sealed session and refreshes the token when
|
|
65
|
+
* needed, when `refresh` is true, or when requested scopes are missing.
|
|
66
|
+
*/
|
|
67
|
+
declare function fetchAccessToken(options?: FetchAccessTokenOptions): Promise<AccessTokenResult>;
|
|
68
|
+
/**
|
|
69
|
+
* Creates an in-memory access-token cache for imperative browser API clients.
|
|
70
|
+
*
|
|
71
|
+
* This is useful when an app needs to make multiple browser-side API calls with
|
|
72
|
+
* a bearer token. Cached tokens are kept only in memory, are refreshed before
|
|
73
|
+
* expiry, and concurrent misses share one `/auth/access-token` request.
|
|
74
|
+
*/
|
|
75
|
+
declare function createAccessTokenProvider(defaultOptions?: FetchAccessTokenOptions): AccessTokenProvider;
|
|
76
|
+
/**
|
|
77
|
+
* TanStack Query hook for a current access token.
|
|
78
|
+
*
|
|
79
|
+
* Apps must provide a `QueryClientProvider` above this hook. The hook calls the
|
|
80
|
+
* app's local access-token endpoint; refresh tokens never leave the server.
|
|
81
|
+
*/
|
|
82
|
+
declare function useAccessToken<TData = AccessTokenResult, TQueryKey extends QueryKey = UseAccessTokenQueryKey>(options?: UseAccessTokenOptions<TData, TQueryKey>): UseQueryResult<TData, Error>;
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* JSON shapes accepted from the mounted session route.
|
|
86
|
+
*
|
|
87
|
+
* The default session route returns `{ user }` as part of the full session, but
|
|
88
|
+
* apps may transform that route to return the user profile directly.
|
|
89
|
+
*/
|
|
90
|
+
type UserProfileEndpointResponse<UserClaims extends Claims = Claims> = {
|
|
91
|
+
user?: UserProfile<UserClaims> | null | undefined;
|
|
92
|
+
} | UserProfile<UserClaims> | null | undefined;
|
|
93
|
+
/**
|
|
94
|
+
* Options for fetching the current user profile from browser code.
|
|
95
|
+
*/
|
|
96
|
+
type FetchUserProfileOptions = {
|
|
97
|
+
/**
|
|
98
|
+
* Mounted session route. Defaults to `/auth/session`.
|
|
99
|
+
*/
|
|
100
|
+
route?: string;
|
|
101
|
+
/**
|
|
102
|
+
* Additional fetch options merged with `credentials: "same-origin"`.
|
|
103
|
+
*/
|
|
104
|
+
request?: RequestInit;
|
|
105
|
+
};
|
|
106
|
+
/**
|
|
107
|
+
* Default TanStack Query key used by {@link useUserProfile}.
|
|
108
|
+
*/
|
|
109
|
+
type UseUserProfileQueryKey = readonly [
|
|
110
|
+
'mondo-auth',
|
|
111
|
+
'user-profile',
|
|
112
|
+
string
|
|
113
|
+
];
|
|
114
|
+
/**
|
|
115
|
+
* Options accepted by {@link useUserProfile}.
|
|
116
|
+
*
|
|
117
|
+
* All normal TanStack Query options are supported except `queryFn` and
|
|
118
|
+
* `queryKey`, which are owned by the hook. Pass `queryKey` here to override the
|
|
119
|
+
* default key.
|
|
120
|
+
*/
|
|
121
|
+
type UseUserProfileOptions<UserClaims extends Claims = Claims, TData = UserProfile<UserClaims> | undefined, TQueryKey extends QueryKey = UseUserProfileQueryKey> = FetchUserProfileOptions & Omit<UseQueryOptions<UserProfile<UserClaims> | undefined, Error, TData, TQueryKey>, 'queryFn' | 'queryKey'> & {
|
|
122
|
+
/**
|
|
123
|
+
* TanStack Query key. Defaults to `["mondo-auth", "user-profile", route]`.
|
|
124
|
+
*/
|
|
125
|
+
queryKey?: TQueryKey;
|
|
126
|
+
};
|
|
127
|
+
/**
|
|
128
|
+
* Fetches the currently authenticated user profile from the mounted session
|
|
129
|
+
* route.
|
|
130
|
+
*
|
|
131
|
+
* This reads the app's local server-managed session. It does not call the
|
|
132
|
+
* authorization server directly.
|
|
133
|
+
*
|
|
134
|
+
* @returns The current user profile, or `undefined` when no session exists.
|
|
135
|
+
*/
|
|
136
|
+
declare function fetchUserProfile<UserClaims extends Claims = Claims>(options?: FetchUserProfileOptions): Promise<UserProfile<UserClaims> | undefined>;
|
|
137
|
+
/**
|
|
138
|
+
* TanStack Query hook for the currently authenticated user profile.
|
|
139
|
+
*
|
|
140
|
+
* Apps must provide a `QueryClientProvider` above this hook. The hook reads the
|
|
141
|
+
* app's local session endpoint and caches the resulting user profile in
|
|
142
|
+
* TanStack Query.
|
|
143
|
+
*/
|
|
144
|
+
declare function useUserProfile<UserClaims extends Claims = Claims, TData = UserProfile<UserClaims> | undefined, TQueryKey extends QueryKey = UseUserProfileQueryKey>(options?: UseUserProfileOptions<UserClaims, TData, TQueryKey>): UseQueryResult<TData, Error>;
|
|
145
|
+
|
|
146
|
+
export { type AccessTokenProvider, type FetchAccessTokenOptions, type FetchUserProfileOptions, type UseAccessTokenOptions, type UseAccessTokenQueryKey, type UseUserProfileOptions, type UseUserProfileQueryKey, type UserProfileEndpointResponse, createAccessTokenProvider, fetchAccessToken, fetchUserProfile, useAccessToken, useUserProfile };
|