@offlinejs/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/dist/index.d.ts +18 -0
- package/dist/index.js +90 -0
- package/dist/index.js.map +1 -0
- package/package.json +31 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { OfflinePlugin, SyncTransport } from '@offlinejs/types';
|
|
2
|
+
|
|
3
|
+
interface AuthTokenProvider {
|
|
4
|
+
getToken(): Promise<string | null> | string | null;
|
|
5
|
+
refreshToken?(): Promise<string | null> | string | null;
|
|
6
|
+
}
|
|
7
|
+
interface AuthTransportOptions {
|
|
8
|
+
headerName?: string;
|
|
9
|
+
onUnauthorized?: () => Promise<void> | void;
|
|
10
|
+
refreshToken?: () => Promise<string | null> | string | null;
|
|
11
|
+
retryOnUnauthorized?: boolean;
|
|
12
|
+
scheme?: string;
|
|
13
|
+
tokenProvider: AuthTokenProvider | (() => Promise<string | null> | string | null);
|
|
14
|
+
}
|
|
15
|
+
declare const createAuthTransport: (transport: SyncTransport, options: AuthTransportOptions) => SyncTransport;
|
|
16
|
+
declare const authPlugin: (options: AuthTransportOptions) => OfflinePlugin;
|
|
17
|
+
|
|
18
|
+
export { type AuthTokenProvider, type AuthTransportOptions, authPlugin, createAuthTransport };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
// src/index.ts
|
|
2
|
+
var createAuthTransport = (transport, options) => ({
|
|
3
|
+
...transport.contractVersion === void 0 ? {} : { contractVersion: transport.contractVersion },
|
|
4
|
+
async request(request) {
|
|
5
|
+
const send = async () => {
|
|
6
|
+
const token = await resolveToken(options.tokenProvider);
|
|
7
|
+
const headerName = options.headerName ?? "authorization";
|
|
8
|
+
const scheme = options.scheme ?? "Bearer";
|
|
9
|
+
return transport.request({
|
|
10
|
+
...request,
|
|
11
|
+
headers: {
|
|
12
|
+
...request.headers,
|
|
13
|
+
...token ? { [headerName]: `${scheme} ${token}` } : {}
|
|
14
|
+
}
|
|
15
|
+
});
|
|
16
|
+
};
|
|
17
|
+
try {
|
|
18
|
+
return await send();
|
|
19
|
+
} catch (error) {
|
|
20
|
+
if (!shouldRetryUnauthorized(error, options)) {
|
|
21
|
+
throw error;
|
|
22
|
+
}
|
|
23
|
+
const refreshed = await refreshAuthToken(options);
|
|
24
|
+
if (!refreshed) {
|
|
25
|
+
await options.onUnauthorized?.();
|
|
26
|
+
throw error;
|
|
27
|
+
}
|
|
28
|
+
return send();
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
var authPlugin = (options) => ({
|
|
33
|
+
name: "auth",
|
|
34
|
+
setup({ events }) {
|
|
35
|
+
void resolveToken(options.tokenProvider).then((token) => {
|
|
36
|
+
if (!token) {
|
|
37
|
+
events.emit("error", new Error("OfflineJS auth plugin did not receive a token"));
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
if (typeof events.on !== "function") {
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
return events.on("error", (error) => {
|
|
44
|
+
if (!isUnauthorizedError(error)) {
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
void refreshAuthToken(options).then((token) => {
|
|
48
|
+
if (!token) {
|
|
49
|
+
return options.onUnauthorized?.();
|
|
50
|
+
}
|
|
51
|
+
}).catch((refreshError) => {
|
|
52
|
+
events.emit(
|
|
53
|
+
"error",
|
|
54
|
+
refreshError instanceof Error ? refreshError : new Error(String(refreshError))
|
|
55
|
+
);
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
var resolveToken = (provider) => {
|
|
61
|
+
if (typeof provider === "function") {
|
|
62
|
+
return Promise.resolve(provider());
|
|
63
|
+
}
|
|
64
|
+
return Promise.resolve(provider.getToken());
|
|
65
|
+
};
|
|
66
|
+
var refreshAuthToken = async (options) => {
|
|
67
|
+
if (options.refreshToken) {
|
|
68
|
+
return Promise.resolve(options.refreshToken());
|
|
69
|
+
}
|
|
70
|
+
if (typeof options.tokenProvider !== "function" && options.tokenProvider.refreshToken) {
|
|
71
|
+
return Promise.resolve(options.tokenProvider.refreshToken());
|
|
72
|
+
}
|
|
73
|
+
return null;
|
|
74
|
+
};
|
|
75
|
+
var shouldRetryUnauthorized = (error, options) => {
|
|
76
|
+
if (!isUnauthorizedError(error)) {
|
|
77
|
+
return false;
|
|
78
|
+
}
|
|
79
|
+
if (options.retryOnUnauthorized === false) {
|
|
80
|
+
return false;
|
|
81
|
+
}
|
|
82
|
+
return Boolean(
|
|
83
|
+
options.refreshToken || typeof options.tokenProvider !== "function" && options.tokenProvider.refreshToken
|
|
84
|
+
);
|
|
85
|
+
};
|
|
86
|
+
var isUnauthorizedError = (error) => typeof error === "object" && error !== null && "status" in error && error.status === 401;
|
|
87
|
+
|
|
88
|
+
export { authPlugin, createAuthTransport };
|
|
89
|
+
//# sourceMappingURL=index.js.map
|
|
90
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import type {\n OfflinePlugin,\n SyncTransport,\n TransportRequest,\n TransportResponse\n} from \"@offlinejs/types\";\n\nexport interface AuthTokenProvider {\n getToken(): Promise<string | null> | string | null;\n refreshToken?(): Promise<string | null> | string | null;\n}\n\nexport interface AuthTransportOptions {\n headerName?: string;\n onUnauthorized?: () => Promise<void> | void;\n refreshToken?: () => Promise<string | null> | string | null;\n retryOnUnauthorized?: boolean;\n scheme?: string;\n tokenProvider: AuthTokenProvider | (() => Promise<string | null> | string | null);\n}\n\nexport const createAuthTransport = (\n transport: SyncTransport,\n options: AuthTransportOptions\n): SyncTransport => ({\n ...(transport.contractVersion === undefined\n ? {}\n : { contractVersion: transport.contractVersion }),\n async request<TData = unknown, TBody = unknown>(\n request: TransportRequest<TBody>\n ): Promise<TransportResponse<TData>> {\n const send = async (): Promise<TransportResponse<TData>> => {\n const token = await resolveToken(options.tokenProvider);\n const headerName = options.headerName ?? \"authorization\";\n const scheme = options.scheme ?? \"Bearer\";\n\n return transport.request<TData, TBody>({\n ...request,\n headers: {\n ...request.headers,\n ...(token ? { [headerName]: `${scheme} ${token}` } : {})\n }\n });\n };\n\n try {\n return await send();\n } catch (error) {\n if (!shouldRetryUnauthorized(error, options)) {\n throw error;\n }\n\n const refreshed = await refreshAuthToken(options);\n if (!refreshed) {\n await options.onUnauthorized?.();\n throw error;\n }\n\n return send();\n }\n }\n});\n\nexport const authPlugin = (options: AuthTransportOptions): OfflinePlugin => ({\n name: \"auth\",\n setup({ events }) {\n void resolveToken(options.tokenProvider).then((token) => {\n if (!token) {\n events.emit(\"error\", new Error(\"OfflineJS auth plugin did not receive a token\"));\n }\n });\n\n if (typeof events.on !== \"function\") {\n return;\n }\n\n return events.on(\"error\", (error) => {\n if (!isUnauthorizedError(error)) {\n return;\n }\n\n void refreshAuthToken(options)\n .then((token) => {\n if (!token) {\n return options.onUnauthorized?.();\n }\n })\n .catch((refreshError) => {\n events.emit(\n \"error\",\n refreshError instanceof Error ? refreshError : new Error(String(refreshError))\n );\n });\n });\n }\n});\n\nconst resolveToken = (\n provider: AuthTokenProvider | (() => Promise<string | null> | string | null)\n): Promise<string | null> => {\n if (typeof provider === \"function\") {\n return Promise.resolve(provider());\n }\n\n return Promise.resolve(provider.getToken());\n};\n\nconst refreshAuthToken = async (options: AuthTransportOptions): Promise<string | null> => {\n if (options.refreshToken) {\n return Promise.resolve(options.refreshToken());\n }\n\n if (typeof options.tokenProvider !== \"function\" && options.tokenProvider.refreshToken) {\n return Promise.resolve(options.tokenProvider.refreshToken());\n }\n\n return null;\n};\n\nconst shouldRetryUnauthorized = (error: unknown, options: AuthTransportOptions): boolean => {\n if (!isUnauthorizedError(error)) {\n return false;\n }\n\n if (options.retryOnUnauthorized === false) {\n return false;\n }\n\n return Boolean(\n options.refreshToken ||\n (typeof options.tokenProvider !== \"function\" && options.tokenProvider.refreshToken)\n );\n};\n\nconst isUnauthorizedError = (error: unknown): boolean =>\n typeof error === \"object\" &&\n error !== null &&\n \"status\" in error &&\n (error as { status?: number }).status === 401;\n"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@offlinejs/auth",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Authentication transport helpers and plugin patterns for OfflineJS.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"sideEffects": false,
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"import": "./dist/index.js"
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
"files": [
|
|
14
|
+
"dist"
|
|
15
|
+
],
|
|
16
|
+
"dependencies": {
|
|
17
|
+
"@offlinejs/types": "0.1.0"
|
|
18
|
+
},
|
|
19
|
+
"devDependencies": {
|
|
20
|
+
"tsup": "latest",
|
|
21
|
+
"typescript": "latest"
|
|
22
|
+
},
|
|
23
|
+
"publishConfig": {
|
|
24
|
+
"access": "public",
|
|
25
|
+
"registry": "https://registry.npmjs.org/"
|
|
26
|
+
},
|
|
27
|
+
"scripts": {
|
|
28
|
+
"build": "tsup",
|
|
29
|
+
"typecheck": "tsc --noEmit"
|
|
30
|
+
}
|
|
31
|
+
}
|