@corespec/vite-plugin-api-auto-login 0.1.0 → 0.2.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 +88 -69
- package/dist/auth/AuthRequest.d.ts +1 -3
- package/dist/auth/AuthRequest.d.ts.map +1 -1
- package/dist/auth/createFormDataRequest.d.ts +4 -0
- package/dist/auth/createFormDataRequest.d.ts.map +1 -0
- package/dist/auth/createTokenStream.d.ts +14 -0
- package/dist/auth/createTokenStream.d.ts.map +1 -0
- package/dist/config/loadPluginConfig.d.ts +5 -0
- package/dist/config/loadPluginConfig.d.ts.map +1 -0
- package/dist/config/types.d.ts +9 -8
- package/dist/config/types.d.ts.map +1 -1
- package/dist/http/isHtmlDocumentRequest.d.ts +3 -0
- package/dist/http/isHtmlDocumentRequest.d.ts.map +1 -0
- package/dist/index.d.ts +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/middleware/createAutoLoginMiddleware.d.ts +5 -0
- package/dist/middleware/createAutoLoginMiddleware.d.ts.map +1 -0
- package/dist/plugin.d.ts.map +1 -1
- package/dist/vite-plugin-api-auto-login.cjs +1 -1
- package/dist/vite-plugin-api-auto-login.js +144 -124
- package/package.json +3 -1
- package/dist/auth/AuthSession.d.ts +0 -24
- package/dist/auth/AuthSession.d.ts.map +0 -1
- package/dist/auth/FormDataAuthRequest.d.ts +0 -9
- package/dist/auth/FormDataAuthRequest.d.ts.map +0 -1
- package/dist/config/PluginConfig.d.ts +0 -14
- package/dist/config/PluginConfig.d.ts.map +0 -1
- package/dist/http/AuthResponse.d.ts +0 -7
- package/dist/http/AuthResponse.d.ts.map +0 -1
- package/dist/http/HtmlDocumentRequest.d.ts +0 -5
- package/dist/http/HtmlDocumentRequest.d.ts.map +0 -1
- package/dist/middleware/AutoLoginMiddleware.d.ts +0 -12
- package/dist/middleware/AutoLoginMiddleware.d.ts.map +0 -1
package/README.md
CHANGED
|
@@ -46,80 +46,104 @@ Values still come from `API_AUTO_LOGIN_USERNAME` and `API_AUTO_LOGIN_PASSWORD`;
|
|
|
46
46
|
only the outgoing form field names change. Names must be non-empty and distinct.
|
|
47
47
|
The `User-Agent` header is unaffected.
|
|
48
48
|
|
|
49
|
-
Use `formFields` only with the default
|
|
50
|
-
`request
|
|
51
|
-
|
|
52
|
-
The `FormFieldNames` type is exported for reusable mappings.
|
|
49
|
+
Use `formFields` only with the default request; it cannot be combined with a custom
|
|
50
|
+
`request`. The exported `createFormDataRequest(config, fields)` function returns
|
|
51
|
+
a request callback for consumers who want to compose the default behavior.
|
|
53
52
|
|
|
54
53
|
## Customizing the login request
|
|
55
54
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
55
|
+
Pass a function that receives the parsed configuration and returns the URL and
|
|
56
|
+
Undici fetch options. It can return a promise. Create a fresh request body each
|
|
57
|
+
time the callback runs:
|
|
59
58
|
|
|
60
59
|
```ts
|
|
61
60
|
import { defineConfig } from 'vite'
|
|
62
|
-
import {
|
|
63
|
-
viteAPIAutoLogin,
|
|
64
|
-
type PluginEnv,
|
|
65
|
-
type AuthRequest,
|
|
66
|
-
type AuthRequestOptions,
|
|
67
|
-
} from '@corespec/vite-plugin-api-auto-login'
|
|
68
|
-
|
|
69
|
-
class JsonAuthRequest implements AuthRequest {
|
|
70
|
-
create(config: Readonly<PluginEnv>): AuthRequestOptions {
|
|
71
|
-
if (!config.loginUrl || !config.username || !config.password) {
|
|
72
|
-
throw new Error('JSON login requires an endpoint, username, and password')
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
return {
|
|
76
|
-
url: config.loginUrl,
|
|
77
|
-
init: {
|
|
78
|
-
method: 'POST',
|
|
79
|
-
headers: { 'content-type': 'application/json' },
|
|
80
|
-
body: JSON.stringify({
|
|
81
|
-
username: config.username,
|
|
82
|
-
password: config.password,
|
|
83
|
-
}),
|
|
84
|
-
},
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
}
|
|
61
|
+
import { viteAPIAutoLogin } from '@corespec/vite-plugin-api-auto-login'
|
|
88
62
|
|
|
89
63
|
export default defineConfig({
|
|
90
|
-
plugins: [
|
|
64
|
+
plugins: [
|
|
65
|
+
viteAPIAutoLogin({
|
|
66
|
+
request: (config) => {
|
|
67
|
+
if (!config.loginUrl || !config.username || !config.password) {
|
|
68
|
+
throw new Error('JSON login requires an endpoint, username, and password')
|
|
69
|
+
}
|
|
70
|
+
return {
|
|
71
|
+
url: config.loginUrl,
|
|
72
|
+
init: {
|
|
73
|
+
method: 'POST',
|
|
74
|
+
headers: { 'Content-Type': 'application/json' },
|
|
75
|
+
body: JSON.stringify({
|
|
76
|
+
email: config.username,
|
|
77
|
+
password: config.password,
|
|
78
|
+
}),
|
|
79
|
+
},
|
|
80
|
+
}
|
|
81
|
+
},
|
|
82
|
+
}),
|
|
83
|
+
],
|
|
91
84
|
})
|
|
92
85
|
```
|
|
93
86
|
|
|
94
|
-
The
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
87
|
+
The callback runs lazily when a login is needed. Concurrent requests share one
|
|
88
|
+
login through RxJS, and each Vite server has its own token cache. JWTs are reused
|
|
89
|
+
until their `exp` timestamp; opaque tokens and tokens without readable expiry are
|
|
90
|
+
not cached between completed logins. Errors are logged and requests continue;
|
|
91
|
+
the next request can attempt authentication again. There are no automatic retries.
|
|
98
92
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
93
|
+
Custom callbacks validate their own requirements and may omit the default login
|
|
94
|
+
variables. Without a callback, the default sends a multipart POST with the mapped
|
|
95
|
+
username/password fields and a `User-Agent` header.
|
|
102
96
|
|
|
103
|
-
`
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
97
|
+
`init` supports Undici options including `signal` and `redirect`. The plugin
|
|
98
|
+
combines your signal with its lifecycle cancellation and manages `dispatcher`
|
|
99
|
+
through the TLS configuration. The response must be successful JSON containing
|
|
100
|
+
a non-empty `token` string.
|
|
107
101
|
|
|
108
|
-
|
|
109
|
-
with `username` and `password` fields and a `User-Agent` header. This class is also exported
|
|
110
|
-
for consumers that want to extend the default request.
|
|
102
|
+
## Cookie options
|
|
111
103
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
104
|
+
```ts
|
|
105
|
+
viteAPIAutoLogin({
|
|
106
|
+
cookie: {
|
|
107
|
+
path: '/api',
|
|
108
|
+
sameSite: 'strict',
|
|
109
|
+
secure: false,
|
|
110
|
+
httpOnly: true,
|
|
111
|
+
},
|
|
112
|
+
})
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
Defaults preserve the original behavior: `path: '/'`, `sameSite: 'lax'`,
|
|
116
|
+
`secure: false`, and `httpOnly: false`. `sameSite` accepts `lax`, `strict`, or
|
|
117
|
+
`none`; `none` requires `secure: true`. Enable `httpOnly` when your frontend does
|
|
118
|
+
not need JavaScript access to the cookie. `secure` cookies require HTTPS in the
|
|
119
|
+
normal browser cookie model.
|
|
120
|
+
|
|
121
|
+
The name still comes from `API_AUTO_LOGIN_COOKIE_NAME`. Cookie `path` controls
|
|
122
|
+
where the browser sends the cookie, not which page requests trigger login.
|
|
123
|
+
Cookies are serialized with `cookie` and appended without replacing existing
|
|
124
|
+
`Set-Cookie` headers. Disconnected responses unsubscribe without continuing the
|
|
125
|
+
middleware chain. When the last waiting response disconnects, the login is aborted;
|
|
126
|
+
a later request starts a fresh login. Vite shutdown also cancels pending authentication.
|
|
127
|
+
|
|
128
|
+
## Migrating from the class-based API
|
|
129
|
+
|
|
130
|
+
Version `0.2.0` changes the public API under the project's pre-1.0 versioning policy:
|
|
131
|
+
|
|
132
|
+
- Replace `request: instance` with `request: (config) => instance.create(config)`,
|
|
133
|
+
or inline the request construction as shown above.
|
|
134
|
+
- Replace `createAuthRequest` with a `request(config)` callback. The callback runs
|
|
135
|
+
per login, rather than once during server configuration.
|
|
136
|
+
- Replace `PluginConfig.fromEnv(env)` with `loadPluginConfig(env)`.
|
|
137
|
+
- Replace `new FormDataAuthRequest(config, fields)` with
|
|
138
|
+
`createFormDataRequest(config, fields)`. Call the returned function with `config`.
|
|
139
|
+
- `AuthRequest` is now a function type; `AuthRequestFactory` is removed.
|
|
140
|
+
- `AuthCookieOptions` is exported for reusable cookie configuration.
|
|
117
141
|
|
|
118
142
|
## Environment variables
|
|
119
143
|
|
|
120
144
|
Define these variables in your Vite environment files, such as `.env.local`, `.env.development`, or another file in `envDir` that Vite loads for the current mode.
|
|
121
145
|
|
|
122
|
-
Required by the default
|
|
146
|
+
Required by the default form-data request only:
|
|
123
147
|
|
|
124
148
|
| Variable | Description |
|
|
125
149
|
| -------------------------- | -------------------------------------------------------------------------------------------- |
|
|
@@ -137,17 +161,13 @@ Optional variables:
|
|
|
137
161
|
|
|
138
162
|
## Configuration parsing
|
|
139
163
|
|
|
140
|
-
`
|
|
141
|
-
`loadEnv` into
|
|
142
|
-
|
|
143
|
-
`PluginConfig` directly.
|
|
164
|
+
`loadPluginConfig(env)` converts the environment values returned by Vite's
|
|
165
|
+
`loadEnv` into a frozen configuration object. It applies shared defaults and
|
|
166
|
+
parses the TLS flag.
|
|
144
167
|
|
|
145
168
|
Login URL, username, and password are optional in the shared configuration.
|
|
146
|
-
`
|
|
147
|
-
|
|
148
|
-
responsible for validating the fields it uses.
|
|
149
|
-
|
|
150
|
-
The login variables deliberately avoid the `VITE_` prefix so they remain on the server with Vite's default configuration. Do not add `API_AUTO_LOGIN_` to Vite's `envPrefix`, as this would expose credentials to client code.
|
|
169
|
+
`createFormDataRequest` validates them when constructing the default callback.
|
|
170
|
+
Custom request callbacks validate their own requirements.
|
|
151
171
|
|
|
152
172
|
## Vue + MSW example
|
|
153
173
|
|
|
@@ -189,7 +209,7 @@ Local environment overrides (`.env.local` and `.env.*.local`) are ignored by Git
|
|
|
189
209
|
Use `@/` for imports from `src/`, including imports in tests:
|
|
190
210
|
|
|
191
211
|
```ts
|
|
192
|
-
import {
|
|
212
|
+
import { loadPluginConfig } from '@/config/loadPluginConfig'
|
|
193
213
|
```
|
|
194
214
|
|
|
195
215
|
TypeScript and Vite/Vitest resolve this alias locally. The declaration build
|
|
@@ -230,10 +250,9 @@ Release setup:
|
|
|
230
250
|
as the repository Actions secret `NPM_TOKEN`. Use a stage-only token; CI does
|
|
231
251
|
not need to bypass 2FA. Keep local tokens in an ignored `.env` file.
|
|
232
252
|
2. Run `npm ci`, `npm run check`, and `npm run example:build`.
|
|
233
|
-
3.
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
bump command described in CONTRIBUTING.md.
|
|
253
|
+
3. Use `npm run release` or an explicit bump command described in CONTRIBUTING.md.
|
|
254
|
+
Releases use version tags such as `v0.2.0`. Historical release tags were removed
|
|
255
|
+
during the repository history reset; published npm versions remain available.
|
|
237
256
|
4. Push the release commit and tag with `git push --follow-tags`. The Publish
|
|
238
257
|
workflow checks, builds, and stages the package with provenance. The npm
|
|
239
258
|
token is available only to its staging step.
|
|
@@ -242,7 +261,7 @@ Release setup:
|
|
|
242
261
|
A successful staging workflow does not mean the version is publicly available.
|
|
243
262
|
|
|
244
263
|
To retry an existing tag, manually run the Publish workflow and supply that tag
|
|
245
|
-
(for example `v0.
|
|
264
|
+
(for example `v0.2.0`). It checks out the tagged source and verifies the version.
|
|
246
265
|
|
|
247
266
|
Trusted publishing can replace the token after configuring owner `core-spec-tech`,
|
|
248
267
|
repository `vite-plugin-api-auto-login`, and workflow `publish.yml` in npm's package
|
|
@@ -4,7 +4,5 @@ export type AuthRequestOptions = {
|
|
|
4
4
|
url: string | URL;
|
|
5
5
|
init: Omit<RequestInit, 'dispatcher'>;
|
|
6
6
|
};
|
|
7
|
-
export
|
|
8
|
-
create(config: Readonly<PluginEnv>): AuthRequestOptions | Promise<AuthRequestOptions>;
|
|
9
|
-
}
|
|
7
|
+
export type AuthRequest = (config: Readonly<PluginEnv>) => AuthRequestOptions | Promise<AuthRequestOptions>;
|
|
10
8
|
//# sourceMappingURL=AuthRequest.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AuthRequest.d.ts","sourceRoot":"","sources":["../../src/auth/AuthRequest.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,QAAQ,CAAA;
|
|
1
|
+
{"version":3,"file":"AuthRequest.d.ts","sourceRoot":"","sources":["../../src/auth/AuthRequest.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,QAAQ,CAAA;AACzC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAE/C,MAAM,MAAM,kBAAkB,GAAG;IAC/B,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;IACjB,IAAI,EAAE,IAAI,CAAC,WAAW,EAAE,YAAY,CAAC,CAAA;CACtC,CAAA;AAED,MAAM,MAAM,WAAW,GAAG,CACxB,MAAM,EAAE,QAAQ,CAAC,SAAS,CAAC,KACxB,kBAAkB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAAA"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { FormFieldNames, PluginEnv } from '../config/types.js';
|
|
2
|
+
import type { AuthRequest } from './AuthRequest.js';
|
|
3
|
+
export declare function createFormDataRequest(config: Readonly<PluginEnv>, fields?: Readonly<FormFieldNames>): AuthRequest;
|
|
4
|
+
//# sourceMappingURL=createFormDataRequest.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"createFormDataRequest.d.ts","sourceRoot":"","sources":["../../src/auth/createFormDataRequest.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAC/D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AAErD,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,QAAQ,CAAC,SAAS,CAAC,EAC3B,MAAM,GAAE,QAAQ,CAAC,cAAc,CAAM,GACpC,WAAW,CAkBb"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Observable } from 'rxjs';
|
|
2
|
+
import { fetch as undiciFetch } from 'undici';
|
|
3
|
+
import type { Dispatcher } from 'undici';
|
|
4
|
+
import type { PluginEnv } from '../config/types.js';
|
|
5
|
+
import type { AuthRequest } from './AuthRequest.js';
|
|
6
|
+
type TokenStreamDependencies = {
|
|
7
|
+
request?: AuthRequest;
|
|
8
|
+
fetch?: typeof undiciFetch;
|
|
9
|
+
createDispatcher?: () => Dispatcher;
|
|
10
|
+
signal?: AbortSignal;
|
|
11
|
+
};
|
|
12
|
+
export declare function createTokenStream(config: Readonly<PluginEnv>, dependencies?: TokenStreamDependencies): Observable<string>;
|
|
13
|
+
export {};
|
|
14
|
+
//# sourceMappingURL=createTokenStream.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"createTokenStream.d.ts","sourceRoot":"","sources":["../../src/auth/createTokenStream.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,MAAM,CAAA;AACtC,OAAO,EAAS,KAAK,IAAI,WAAW,EAAE,MAAM,QAAQ,CAAA;AACpD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAA;AAExC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAC/C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AAIrD,KAAK,uBAAuB,GAAG;IAC7B,OAAO,CAAC,EAAE,WAAW,CAAA;IACrB,KAAK,CAAC,EAAE,OAAO,WAAW,CAAA;IAC1B,gBAAgB,CAAC,EAAE,MAAM,UAAU,CAAA;IACnC,MAAM,CAAC,EAAE,WAAW,CAAA;CACrB,CAAA;AAED,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,QAAQ,CAAC,SAAS,CAAC,EAC3B,YAAY,GAAE,uBAA4B,GACzC,UAAU,CAAC,MAAM,CAAC,CAoDpB"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { PluginEnv, PluginEnvInput } from './types.js';
|
|
2
|
+
export declare const DEFAULT_COOKIE_NAME = "your_token_name";
|
|
3
|
+
export declare const DEFAULT_USER_AGENT = "vite";
|
|
4
|
+
export declare function loadPluginConfig(env: PluginEnvInput): Readonly<PluginEnv>;
|
|
5
|
+
//# sourceMappingURL=loadPluginConfig.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loadPluginConfig.d.ts","sourceRoot":"","sources":["../../src/config/loadPluginConfig.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAA;AAE/D,eAAO,MAAM,mBAAmB,oBAAoB,CAAA;AACpD,eAAO,MAAM,kBAAkB,SAAS,CAAA;AAExC,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,cAAc,GAAG,QAAQ,CAAC,SAAS,CAAC,CASzE"}
|
package/dist/config/types.d.ts
CHANGED
|
@@ -8,22 +8,23 @@ export type PluginEnv = {
|
|
|
8
8
|
userAgent: string;
|
|
9
9
|
};
|
|
10
10
|
export type PluginEnvInput = Readonly<Record<string, string | undefined>>;
|
|
11
|
-
export type AuthRequestFactory = (config: Readonly<PluginEnv>) => AuthRequest;
|
|
12
11
|
export type FormFieldNames = {
|
|
13
12
|
username?: string;
|
|
14
13
|
password?: string;
|
|
15
14
|
};
|
|
15
|
+
export type AuthCookieOptions = {
|
|
16
|
+
path?: string;
|
|
17
|
+
sameSite?: 'lax' | 'strict' | 'none';
|
|
18
|
+
secure?: boolean;
|
|
19
|
+
httpOnly?: boolean;
|
|
20
|
+
};
|
|
16
21
|
export type AutoLoginOptions = {
|
|
22
|
+
cookie?: AuthCookieOptions;
|
|
23
|
+
} & ({
|
|
17
24
|
formFields?: FormFieldNames;
|
|
18
25
|
request?: never;
|
|
19
|
-
createAuthRequest?: never;
|
|
20
26
|
} | {
|
|
21
27
|
formFields?: never;
|
|
22
28
|
request: AuthRequest;
|
|
23
|
-
|
|
24
|
-
} | {
|
|
25
|
-
formFields?: never;
|
|
26
|
-
request?: never;
|
|
27
|
-
createAuthRequest: AuthRequestFactory;
|
|
28
|
-
};
|
|
29
|
+
});
|
|
29
30
|
//# sourceMappingURL=types.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/config/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AAErD,MAAM,MAAM,SAAS,GAAG;IACtB,gBAAgB,EAAE,OAAO,CAAA;IACzB,UAAU,EAAE,MAAM,CAAA;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,MAAM,CAAA;CAClB,CAAA;AAED,MAAM,MAAM,cAAc,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC,CAAA;AAEzE,MAAM,MAAM,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/config/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AAErD,MAAM,MAAM,SAAS,GAAG;IACtB,gBAAgB,EAAE,OAAO,CAAA;IACzB,UAAU,EAAE,MAAM,CAAA;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,MAAM,CAAA;CAClB,CAAA;AAED,MAAM,MAAM,cAAc,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC,CAAA;AAEzE,MAAM,MAAM,cAAc,GAAG;IAC3B,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB,CAAA;AAED,MAAM,MAAM,iBAAiB,GAAG;IAC9B,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,QAAQ,CAAC,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAA;IACpC,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB,CAAA;AAED,MAAM,MAAM,gBAAgB,GAAG;IAAE,MAAM,CAAC,EAAE,iBAAiB,CAAA;CAAE,GAAG,CAC9D;IAAE,UAAU,CAAC,EAAE,cAAc,CAAC;IAAC,OAAO,CAAC,EAAE,KAAK,CAAA;CAAE,GAAG;IAAE,UAAU,CAAC,EAAE,KAAK,CAAC;IAAC,OAAO,EAAE,WAAW,CAAA;CAAE,CAChG,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"isHtmlDocumentRequest.d.ts","sourceRoot":"","sources":["../../src/http/isHtmlDocumentRequest.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,WAAW,CAAA;AAEhD,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,eAAe,GAAG,OAAO,CAKnE"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export { viteAPIAutoLogin } from './plugin.js';
|
|
2
|
-
export {
|
|
2
|
+
export { createFormDataRequest } from './auth/createFormDataRequest.js';
|
|
3
|
+
export { loadPluginConfig } from './config/loadPluginConfig.js';
|
|
3
4
|
export type { AuthRequest, AuthRequestOptions } from './auth/AuthRequest.js';
|
|
4
|
-
export type { AutoLoginOptions, PluginEnv,
|
|
5
|
-
export { PluginConfig } from './config/PluginConfig.js';
|
|
5
|
+
export type { AutoLoginOptions, PluginEnv, FormFieldNames, AuthCookieOptions } from './config/types.js';
|
|
6
6
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAA;AAC3C,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAA;AAC3C,OAAO,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAA;AACpE,OAAO,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAA;AAC5D,YAAY,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAA;AACzE,YAAY,EAAE,gBAAgB,EAAE,SAAS,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAA"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { Observable } from 'rxjs';
|
|
2
|
+
import type { Connect, Logger } from 'vite';
|
|
3
|
+
import type { AuthCookieOptions, PluginEnv } from '../config/types.js';
|
|
4
|
+
export declare function createAutoLoginMiddleware(config: Readonly<PluginEnv>, cookie: Required<AuthCookieOptions>, token$: Observable<string>, logger: Pick<Logger, 'error'>, signal: AbortSignal): Connect.NextHandleFunction;
|
|
5
|
+
//# sourceMappingURL=createAutoLoginMiddleware.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"createAutoLoginMiddleware.d.ts","sourceRoot":"","sources":["../../src/middleware/createAutoLoginMiddleware.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,MAAM,CAAA;AACtC,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,MAAM,CAAA;AAE3C,OAAO,KAAK,EAAE,iBAAiB,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAIlE,wBAAgB,yBAAyB,CACvC,MAAM,EAAE,QAAQ,CAAC,SAAS,CAAC,EAC3B,MAAM,EAAE,QAAQ,CAAC,iBAAiB,CAAC,EACnC,MAAM,EAAE,UAAU,CAAC,MAAM,CAAC,EAC1B,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,MAAM,EAAE,WAAW,GAClB,OAAO,CAAC,kBAAkB,CA0C5B"}
|
package/dist/plugin.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAA;AAOlC,OAAO,KAAK,EAAqB,gBAAgB,EAAE,MAAM,gBAAgB,CAAA;AAGzE,wBAAgB,gBAAgB,CAAC,OAAO,GAAE,gBAAqB,GAAG,MAAM,CAoDvE"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});let e=require("
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});let e=require("cookie"),t=require("vite"),n=require("undici"),r=require("jose"),i=require("rxjs");function a(e,t={}){let r=t.username??`username`,i=t.password??`password`;if(!r.trim()||!i.trim()||r===i)throw Error(`Form field names must be non-empty and distinct`);return o(e),e=>{let{loginUrl:t,username:a,password:s}=o(e),c=new n.FormData;return c.set(r,a),c.set(i,s),{url:t,init:{method:`POST`,headers:{"User-Agent":e.userAgent},body:c}}}}function o(e){let{loginUrl:t,username:n,password:r}=e;if(!t||!n||!r)throw Error(`Missing required env vars: API_AUTO_LOGIN_LOGIN_URL, API_AUTO_LOGIN_USERNAME, API_AUTO_LOGIN_PASSWORD`);return{loginUrl:t,username:n,password:r}}function s(e,t={}){let r=t.request??a(e),o=t.fetch??n.fetch,s;return(0,i.defer)(()=>{if(t.signal?.aborted)return i.EMPTY;if(s?.expiresAt!==void 0&&s.expiresAt>Date.now())return(0,i.of)(s.value);let a=new AbortController,l;return e.allowInsecureTls&&(l=t.createDispatcher?.()??new n.Agent({connect:{rejectUnauthorized:!1}})),(0,i.defer)(()=>(0,i.from)(Promise.resolve(r(e)))).pipe((0,i.switchMap)(({url:e,init:n})=>{let r=[a.signal];return n.signal&&r.push(n.signal),t.signal&&r.push(t.signal),(0,i.from)(o(e,{...n,dispatcher:l,signal:AbortSignal.any(r)}))}),(0,i.switchMap)(e=>{if(!e.ok)throw Error(`Login request failed with status ${e.status}`);return(0,i.from)(e.json())}),(0,i.map)(c),(0,i.tap)(e=>{s=e}),(0,i.map)(e=>e.value),(0,i.takeUntil)(t.signal?(0,i.fromEvent)(t.signal,`abort`):i.EMPTY),(0,i.finalize)(()=>{a.abort(),l&&l.destroy().catch(()=>{})}))}).pipe((0,i.share)({connector:()=>new i.ReplaySubject(1),resetOnError:!0,resetOnComplete:!0,resetOnRefCountZero:!0}))}function c(e){if(!e||typeof e!=`object`||!(`token`in e)||typeof e.token!=`string`||e.token.length===0)throw Error(`Login response did not include a token`);let t=e.token;try{let{exp:e}=(0,r.decodeJwt)(t);return{value:t,expiresAt:typeof e==`number`?e*1e3:void 0}}catch{return{value:t}}}var l=`vite-plugin-api-auto-login`;function u(e){return Object.freeze({allowInsecureTls:e.API_AUTO_LOGIN_ALLOW_INSECURE_TLS===`true`,cookieName:e.API_AUTO_LOGIN_COOKIE_NAME??`your_token_name`,username:e.API_AUTO_LOGIN_USERNAME,loginUrl:e.API_AUTO_LOGIN_LOGIN_URL,password:e.API_AUTO_LOGIN_PASSWORD,userAgent:e.API_AUTO_LOGIN_USER_AGENT??`vite`})}function d(e){let t=e.method===`GET`||e.method===`HEAD`,n=e.headers.accept?.includes(`text/html`)??!1,r=e.headers.upgrade?.toLowerCase()===`websocket`;return t&&n&&!r}function f(t,n,r,a,o){return(s,c,u)=>{if(o.aborted||c.destroyed||c.writableEnded)return;let f=new i.Subscription,p=()=>f.unsubscribe(),m=()=>{o.aborted||c.destroyed||c.writableEnded||f.closed||u()};c.once(`close`,p),o.addEventListener(`abort`,p,{once:!0}),f.add(()=>{c.off(`close`,p),o.removeEventListener(`abort`,p)}),f.add((0,i.of)(s).pipe((0,i.filter)(d),(0,i.switchMap)(()=>r),(0,i.take)(1),(0,i.map)(r=>(0,e.stringifySetCookie)({...n,name:t.cookieName,value:r})),(0,i.tap)(e=>{c.headersSent||c.destroyed||c.writableEnded||c.appendHeader(`Set-Cookie`,e)})).subscribe({error:e=>{let n=e instanceof Error?e.message:String(e),r=t.loginUrl?` (${t.loginUrl})`:``;a.error(`[${l}] ${n}${r}`),m(),f.unsubscribe()},complete:()=>{m(),f.unsubscribe()}}))}}function p(n={}){if(`createAuthRequest`in n)throw Error(`createAuthRequest was removed; use request(config) instead`);if(n.request!==void 0&&typeof n.request!=`function`)throw Error(`request must be a function: request(config)`);if(n.formFields!==void 0&&n.request!==void 0)throw Error(`Use formFields only with the default request`);let r={path:n.cookie?.path??`/`,sameSite:n.cookie?.sameSite??`lax`,secure:n.cookie?.secure??!1,httpOnly:n.cookie?.httpOnly??!1};if(r.sameSite===`none`&&!r.secure)throw Error(`cookie.sameSite "none" requires cookie.secure to be true`);(0,e.stringifySetCookie)({...r,name:`validation`,value:``});let i=new Set;return{name:l,apply:`serve`,configureServer(o){let{mode:c,envDir:d,logger:p}=o.config;try{let l=u((0,t.loadEnv)(c,d,`API_AUTO_LOGIN_`));(0,e.stringifySetCookie)({...r,name:l.cookieName,value:``});let m=n.request??a(l,n.formFields),h=new AbortController,g=()=>{h.abort(),o.httpServer?.off(`close`,g),i.delete(g)};i.add(g),o.httpServer?.once(`close`,g);let _=s(l,{request:m,signal:h.signal});o.middlewares.use(f(l,r,_,p,h.signal))}catch(e){p.error(`[${l}] ${e instanceof Error?e.message:String(e)}`)}},closeBundle(){for(let e of i)e()}}}exports.createFormDataRequest=a,exports.loadPluginConfig=u,exports.viteAPIAutoLogin=p;
|
|
@@ -1,144 +1,164 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
create(e) {
|
|
15
|
-
let { username: t, password: r, loginUrl: i } = this.validate(e), a = new n();
|
|
16
|
-
return a.set(this.fields.username, t), a.set(this.fields.password, r), {
|
|
17
|
-
url: i,
|
|
1
|
+
import { stringifySetCookie as e } from "cookie";
|
|
2
|
+
import { loadEnv as t } from "vite";
|
|
3
|
+
import { Agent as n, FormData as r, fetch as i } from "undici";
|
|
4
|
+
import { decodeJwt as a } from "jose";
|
|
5
|
+
import { EMPTY as o, ReplaySubject as s, Subscription as c, defer as l, filter as u, finalize as d, from as f, fromEvent as p, map as m, of as h, share as g, switchMap as _, take as v, takeUntil as y, tap as b } from "rxjs";
|
|
6
|
+
// src/auth/createFormDataRequest.ts
|
|
7
|
+
function x(e, t = {}) {
|
|
8
|
+
let n = t.username ?? "username", i = t.password ?? "password";
|
|
9
|
+
if (!n.trim() || !i.trim() || n === i) throw Error("Form field names must be non-empty and distinct");
|
|
10
|
+
return S(e), (e) => {
|
|
11
|
+
let { loginUrl: t, username: a, password: o } = S(e), s = new r();
|
|
12
|
+
return s.set(n, a), s.set(i, o), {
|
|
13
|
+
url: t,
|
|
18
14
|
init: {
|
|
19
15
|
method: "POST",
|
|
20
16
|
headers: { "User-Agent": e.userAgent },
|
|
21
|
-
body:
|
|
17
|
+
body: s
|
|
22
18
|
}
|
|
23
19
|
};
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
function S(e) {
|
|
23
|
+
let { loginUrl: t, username: n, password: r } = e;
|
|
24
|
+
if (!t || !n || !r) throw Error("Missing required env vars: API_AUTO_LOGIN_LOGIN_URL, API_AUTO_LOGIN_USERNAME, API_AUTO_LOGIN_PASSWORD");
|
|
25
|
+
return {
|
|
26
|
+
loginUrl: t,
|
|
27
|
+
username: n,
|
|
28
|
+
password: r
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
// src/auth/createTokenStream.ts
|
|
32
|
+
function C(e, t = {}) {
|
|
33
|
+
let r = t.request ?? x(e), a = t.fetch ?? i, c;
|
|
34
|
+
return l(() => {
|
|
35
|
+
if (t.signal?.aborted) return o;
|
|
36
|
+
if (c?.expiresAt !== void 0 && c.expiresAt > Date.now()) return h(c.value);
|
|
37
|
+
let i = new AbortController(), s;
|
|
38
|
+
return e.allowInsecureTls && (s = t.createDispatcher?.() ?? new n({ connect: { rejectUnauthorized: !1 } })), l(() => f(Promise.resolve(r(e)))).pipe(_(({ url: e, init: n }) => {
|
|
39
|
+
let r = [i.signal];
|
|
40
|
+
return n.signal && r.push(n.signal), t.signal && r.push(t.signal), f(a(e, {
|
|
41
|
+
...n,
|
|
42
|
+
dispatcher: s,
|
|
43
|
+
signal: AbortSignal.any(r)
|
|
44
|
+
}));
|
|
45
|
+
}), _((e) => {
|
|
46
|
+
if (!e.ok) throw Error(`Login request failed with status ${e.status}`);
|
|
47
|
+
return f(e.json());
|
|
48
|
+
}), m(w), b((e) => {
|
|
49
|
+
c = e;
|
|
50
|
+
}), m((e) => e.value), y(t.signal ? p(t.signal, "abort") : o), d(() => {
|
|
51
|
+
i.abort(), s && s.destroy().catch(() => {});
|
|
52
|
+
}));
|
|
53
|
+
}).pipe(g({
|
|
54
|
+
connector: () => new s(1),
|
|
55
|
+
resetOnError: !0,
|
|
56
|
+
resetOnComplete: !0,
|
|
57
|
+
resetOnRefCountZero: !0
|
|
58
|
+
}));
|
|
59
|
+
}
|
|
60
|
+
function w(e) {
|
|
61
|
+
if (!e || typeof e != "object" || !("token" in e) || typeof e.token != "string" || e.token.length === 0) throw Error("Login response did not include a token");
|
|
62
|
+
let t = e.token;
|
|
63
|
+
try {
|
|
64
|
+
let { exp: e } = a(t);
|
|
28
65
|
return {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
password: r
|
|
66
|
+
value: t,
|
|
67
|
+
expiresAt: typeof e == "number" ? e * 1e3 : void 0
|
|
32
68
|
};
|
|
69
|
+
} catch {
|
|
70
|
+
return { value: t };
|
|
33
71
|
}
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
return this.cachedToken?.expiresAt !== void 0 && this.cachedToken.expiresAt > Date.now() ? this.cachedToken.value : (this.pendingLogin ??= this.requestToken().then((e) => (this.cachedToken = e, e.value)).finally(() => {
|
|
59
|
-
this.pendingLogin = void 0;
|
|
60
|
-
}), this.pendingLogin);
|
|
61
|
-
}
|
|
62
|
-
async requestToken() {
|
|
63
|
-
let { url: e, init: t } = await this.request.create(this.env), n = await this.fetchImpl(e, {
|
|
64
|
-
...t,
|
|
65
|
-
dispatcher: this.dispatcher
|
|
66
|
-
});
|
|
67
|
-
if (!n.ok) throw Error(`Login request failed with status ${n.status}`);
|
|
68
|
-
let r = await n.json();
|
|
69
|
-
if (typeof r.token != "string" || r.token.length === 0) throw Error("Login response did not include a token");
|
|
70
|
-
return {
|
|
71
|
-
expiresAt: this.parseJwtExpiry(r.token),
|
|
72
|
-
value: r.token
|
|
72
|
+
}
|
|
73
|
+
// src/constants.ts
|
|
74
|
+
var T = "vite-plugin-api-auto-login";
|
|
75
|
+
function E(e) {
|
|
76
|
+
return Object.freeze({
|
|
77
|
+
allowInsecureTls: e.API_AUTO_LOGIN_ALLOW_INSECURE_TLS === "true",
|
|
78
|
+
cookieName: e.API_AUTO_LOGIN_COOKIE_NAME ?? "your_token_name",
|
|
79
|
+
username: e.API_AUTO_LOGIN_USERNAME,
|
|
80
|
+
loginUrl: e.API_AUTO_LOGIN_LOGIN_URL,
|
|
81
|
+
password: e.API_AUTO_LOGIN_PASSWORD,
|
|
82
|
+
userAgent: e.API_AUTO_LOGIN_USER_AGENT ?? "vite"
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
// src/http/isHtmlDocumentRequest.ts
|
|
86
|
+
function D(e) {
|
|
87
|
+
let t = e.method === "GET" || e.method === "HEAD", n = e.headers.accept?.includes("text/html") ?? !1, r = e.headers.upgrade?.toLowerCase() === "websocket";
|
|
88
|
+
return t && n && !r;
|
|
89
|
+
}
|
|
90
|
+
// src/middleware/createAutoLoginMiddleware.ts
|
|
91
|
+
function O(t, n, r, i, a) {
|
|
92
|
+
return (o, s, l) => {
|
|
93
|
+
if (a.aborted || s.destroyed || s.writableEnded) return;
|
|
94
|
+
let d = new c(), f = () => d.unsubscribe(), p = () => {
|
|
95
|
+
a.aborted || s.destroyed || s.writableEnded || d.closed || l();
|
|
73
96
|
};
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
let n = `${e}=${t}; Path=/; SameSite=Lax`, r = this.response.getHeader("Set-Cookie");
|
|
90
|
-
if (!r) {
|
|
91
|
-
this.response.setHeader("Set-Cookie", n);
|
|
92
|
-
return;
|
|
93
|
-
}
|
|
94
|
-
let i;
|
|
95
|
-
i = Array.isArray(r) ? r : [String(r)], this.response.setHeader("Set-Cookie", [...i, n]);
|
|
96
|
-
}
|
|
97
|
-
}, u = "text/html", d = class {
|
|
98
|
-
static matches(e) {
|
|
99
|
-
return e.headers.upgrade?.toLowerCase() === "websocket" || e.method !== "GET" && e.method !== "HEAD" ? !1 : e.headers.accept?.includes(u) ?? !1;
|
|
100
|
-
}
|
|
101
|
-
}, f = class {
|
|
102
|
-
config;
|
|
103
|
-
logger;
|
|
104
|
-
request;
|
|
105
|
-
session;
|
|
106
|
-
constructor(e, t, n) {
|
|
107
|
-
this.config = e, this.logger = t, this.request = n;
|
|
108
|
-
}
|
|
109
|
-
handle = async (e, t, n) => {
|
|
110
|
-
if (!d.matches(e)) n();
|
|
111
|
-
else {
|
|
112
|
-
try {
|
|
113
|
-
this.session ??= new c(this.config, { request: this.request });
|
|
114
|
-
let e = await this.session.getToken();
|
|
115
|
-
new l(t).setAuthCookie(this.config.cookieName, e);
|
|
116
|
-
} catch (e) {
|
|
117
|
-
let t = e instanceof Error ? e.message : String(e), n = this.config.loginUrl ? ` (${this.config.loginUrl})` : "";
|
|
118
|
-
this.logger.error(`[${o}] ${t}${n}`);
|
|
97
|
+
s.once("close", f), a.addEventListener("abort", f, { once: !0 }), d.add(() => {
|
|
98
|
+
s.off("close", f), a.removeEventListener("abort", f);
|
|
99
|
+
}), d.add(h(o).pipe(u(D), _(() => r), v(1), m((r) => e({
|
|
100
|
+
...n,
|
|
101
|
+
name: t.cookieName,
|
|
102
|
+
value: r
|
|
103
|
+
})), b((e) => {
|
|
104
|
+
s.headersSent || s.destroyed || s.writableEnded || s.appendHeader("Set-Cookie", e);
|
|
105
|
+
})).subscribe({
|
|
106
|
+
error: (e) => {
|
|
107
|
+
let n = e instanceof Error ? e.message : String(e), r = t.loginUrl ? ` (${t.loginUrl})` : "";
|
|
108
|
+
i.error(`[${T}] ${n}${r}`), p(), d.unsubscribe();
|
|
109
|
+
},
|
|
110
|
+
complete: () => {
|
|
111
|
+
p(), d.unsubscribe();
|
|
119
112
|
}
|
|
120
|
-
|
|
121
|
-
}
|
|
113
|
+
}));
|
|
122
114
|
};
|
|
123
|
-
}
|
|
115
|
+
}
|
|
124
116
|
// src/plugin.ts
|
|
125
|
-
function
|
|
126
|
-
if (
|
|
127
|
-
if (
|
|
117
|
+
function k(n = {}) {
|
|
118
|
+
if ("createAuthRequest" in n) throw Error("createAuthRequest was removed; use request(config) instead");
|
|
119
|
+
if (n.request !== void 0 && typeof n.request != "function") throw Error("request must be a function: request(config)");
|
|
120
|
+
if (n.formFields !== void 0 && n.request !== void 0) throw Error("Use formFields only with the default request");
|
|
121
|
+
let r = {
|
|
122
|
+
path: n.cookie?.path ?? "/",
|
|
123
|
+
sameSite: n.cookie?.sameSite ?? "lax",
|
|
124
|
+
secure: n.cookie?.secure ?? !1,
|
|
125
|
+
httpOnly: n.cookie?.httpOnly ?? !1
|
|
126
|
+
};
|
|
127
|
+
if (r.sameSite === "none" && !r.secure) throw Error("cookie.sameSite \"none\" requires cookie.secure to be true");
|
|
128
|
+
e({
|
|
129
|
+
...r,
|
|
130
|
+
name: "validation",
|
|
131
|
+
value: ""
|
|
132
|
+
});
|
|
133
|
+
let i = /* @__PURE__ */ new Set();
|
|
128
134
|
return {
|
|
129
|
-
name:
|
|
135
|
+
name: T,
|
|
130
136
|
apply: "serve",
|
|
131
|
-
configureServer(
|
|
132
|
-
let { mode:
|
|
137
|
+
configureServer(a) {
|
|
138
|
+
let { mode: o, envDir: s, logger: c } = a.config;
|
|
133
139
|
try {
|
|
134
|
-
let
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
140
|
+
let l = E(t(o, s, "API_AUTO_LOGIN_"));
|
|
141
|
+
e({
|
|
142
|
+
...r,
|
|
143
|
+
name: l.cookieName,
|
|
144
|
+
value: ""
|
|
145
|
+
});
|
|
146
|
+
let u = n.request ?? x(l, n.formFields), d = new AbortController(), f = () => {
|
|
147
|
+
d.abort(), a.httpServer?.off("close", f), i.delete(f);
|
|
148
|
+
};
|
|
149
|
+
i.add(f), a.httpServer?.once("close", f);
|
|
150
|
+
let p = C(l, {
|
|
151
|
+
request: u,
|
|
152
|
+
signal: d.signal
|
|
153
|
+
});
|
|
154
|
+
a.middlewares.use(O(l, r, p, c, d.signal));
|
|
138
155
|
} catch (e) {
|
|
139
|
-
c.error(`[${
|
|
156
|
+
c.error(`[${T}] ${e instanceof Error ? e.message : String(e)}`);
|
|
140
157
|
}
|
|
158
|
+
},
|
|
159
|
+
closeBundle() {
|
|
160
|
+
for (let e of i) e();
|
|
141
161
|
}
|
|
142
162
|
};
|
|
143
163
|
}
|
|
144
|
-
export {
|
|
164
|
+
export { x as createFormDataRequest, E as loadPluginConfig, k as viteAPIAutoLogin };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@corespec/vite-plugin-api-auto-login",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Reusable Vite plugin for API auto login during local development",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/vite-plugin-api-auto-login.cjs",
|
|
@@ -68,7 +68,9 @@
|
|
|
68
68
|
"vue-tsc": "^3.3.14"
|
|
69
69
|
},
|
|
70
70
|
"dependencies": {
|
|
71
|
+
"cookie": "^2.0.2",
|
|
71
72
|
"jose": "^6.2.15",
|
|
73
|
+
"rxjs": "^7.8.2",
|
|
72
74
|
"undici": "^8.12.3"
|
|
73
75
|
},
|
|
74
76
|
"peerDependencies": {
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import { fetch as undiciFetch } from 'undici';
|
|
2
|
-
import type { Dispatcher } from 'undici';
|
|
3
|
-
import type { PluginEnv } from '../config/types.js';
|
|
4
|
-
import type { AuthRequest } from './AuthRequest.js';
|
|
5
|
-
type FetchLike = typeof undiciFetch;
|
|
6
|
-
type AuthSessionDependencies = {
|
|
7
|
-
request?: AuthRequest;
|
|
8
|
-
createDispatcher?: () => Dispatcher;
|
|
9
|
-
fetch?: FetchLike;
|
|
10
|
-
};
|
|
11
|
-
export declare class AuthSession {
|
|
12
|
-
private readonly env;
|
|
13
|
-
private readonly request;
|
|
14
|
-
private readonly fetchImpl;
|
|
15
|
-
private readonly dispatcher;
|
|
16
|
-
private cachedToken;
|
|
17
|
-
private pendingLogin;
|
|
18
|
-
constructor(env: PluginEnv, dependencies?: AuthSessionDependencies);
|
|
19
|
-
getToken(): Promise<string>;
|
|
20
|
-
private requestToken;
|
|
21
|
-
private parseJwtExpiry;
|
|
22
|
-
}
|
|
23
|
-
export {};
|
|
24
|
-
//# sourceMappingURL=AuthSession.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"AuthSession.d.ts","sourceRoot":"","sources":["../../src/auth/AuthSession.ts"],"names":[],"mappings":"AACA,OAAO,EAAS,KAAK,IAAI,WAAW,EAAE,MAAM,QAAQ,CAAA;AACpD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAA;AAExC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAE/C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AAOrD,KAAK,SAAS,GAAG,OAAO,WAAW,CAAA;AAEnC,KAAK,uBAAuB,GAAG;IAC7B,OAAO,CAAC,EAAE,WAAW,CAAA;IACrB,gBAAgB,CAAC,EAAE,MAAM,UAAU,CAAA;IACnC,KAAK,CAAC,EAAE,SAAS,CAAA;CAClB,CAAA;AAED,qBAAa,WAAW;IAQpB,OAAO,CAAC,QAAQ,CAAC,GAAG;IAPtB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAa;IACrC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAW;IACrC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAwB;IACnD,OAAO,CAAC,WAAW,CAAwB;IAC3C,OAAO,CAAC,YAAY,CAA6B;gBAG9B,GAAG,EAAE,SAAS,EAC/B,YAAY,GAAE,uBAA4B;IAUtC,QAAQ,IAAI,OAAO,CAAC,MAAM,CAAC;YAiBnB,YAAY;IAuB1B,OAAO,CAAC,cAAc;CASvB"}
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import type { FormFieldNames, PluginEnv } from '../config/types.js';
|
|
2
|
-
import type { AuthRequest, AuthRequestOptions } from './AuthRequest.js';
|
|
3
|
-
export declare class FormDataAuthRequest implements AuthRequest {
|
|
4
|
-
private readonly fields;
|
|
5
|
-
constructor(config?: Readonly<PluginEnv>, fields?: Readonly<FormFieldNames>);
|
|
6
|
-
create(config: Readonly<PluginEnv>): AuthRequestOptions;
|
|
7
|
-
private validate;
|
|
8
|
-
}
|
|
9
|
-
//# sourceMappingURL=FormDataAuthRequest.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"FormDataAuthRequest.d.ts","sourceRoot":"","sources":["../../src/auth/FormDataAuthRequest.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAC/D,OAAO,KAAK,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAA;AAEzE,qBAAa,mBAAoB,YAAW,WAAW;IACrD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA0B;gBAErC,MAAM,CAAC,EAAE,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,GAAE,QAAQ,CAAC,cAAc,CAAM;IAkB/E,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,SAAS,CAAC,GAAG,kBAAkB;IAgBvD,OAAO,CAAC,QAAQ;CASjB"}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import type { PluginEnv, PluginEnvInput } from './types.js';
|
|
2
|
-
export declare const DEFAULT_COOKIE_NAME = "your_token_name";
|
|
3
|
-
export declare const DEFAULT_USER_AGENT = "vite";
|
|
4
|
-
export declare class PluginConfig implements PluginEnv {
|
|
5
|
-
readonly allowInsecureTls: boolean;
|
|
6
|
-
readonly cookieName: string;
|
|
7
|
-
readonly username: string | undefined;
|
|
8
|
-
readonly loginUrl: string | undefined;
|
|
9
|
-
readonly password: string | undefined;
|
|
10
|
-
readonly userAgent: string;
|
|
11
|
-
static fromEnv(env: PluginEnvInput): PluginConfig;
|
|
12
|
-
private constructor();
|
|
13
|
-
}
|
|
14
|
-
//# sourceMappingURL=PluginConfig.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"PluginConfig.d.ts","sourceRoot":"","sources":["../../src/config/PluginConfig.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAA;AAE/D,eAAO,MAAM,mBAAmB,oBAAoB,CAAA;AACpD,eAAO,MAAM,kBAAkB,SAAS,CAAA;AAExC,qBAAa,YAAa,YAAW,SAAS;IAC5C,QAAQ,CAAC,gBAAgB,EAAE,OAAO,CAAA;IAClC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;IAC3B,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAA;IACrC,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAA;IACrC,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAA;IACrC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAE1B,MAAM,CAAC,OAAO,CAAC,GAAG,EAAE,cAAc,GAAG,YAAY;IAIjD,OAAO;CAQR"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"AuthResponse.d.ts","sourceRoot":"","sources":["../../src/http/AuthResponse.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,WAAW,CAAA;AAE/C,qBAAa,YAAY;IACX,OAAO,CAAC,QAAQ,CAAC,QAAQ;gBAAR,QAAQ,EAAE,cAAc;IAErD,aAAa,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;CAkBvD"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"HtmlDocumentRequest.d.ts","sourceRoot":"","sources":["../../src/http/HtmlDocumentRequest.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,WAAW,CAAA;AAIhD,qBAAa,mBAAmB;IAC9B,MAAM,CAAC,OAAO,CAAC,GAAG,EAAE,eAAe,GAAG,OAAO;CAW9C"}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import type { Connect, Logger } from 'vite';
|
|
2
|
-
import type { AuthRequest } from '../auth/AuthRequest.js';
|
|
3
|
-
import type { PluginEnv } from '../config/types.js';
|
|
4
|
-
export declare class AutoLoginMiddleware {
|
|
5
|
-
private readonly config;
|
|
6
|
-
private readonly logger;
|
|
7
|
-
private readonly request;
|
|
8
|
-
private session;
|
|
9
|
-
constructor(config: PluginEnv, logger: Pick<Logger, 'error'>, request: AuthRequest);
|
|
10
|
-
readonly handle: Connect.NextHandleFunction;
|
|
11
|
-
}
|
|
12
|
-
//# sourceMappingURL=AutoLoginMiddleware.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"AutoLoginMiddleware.d.ts","sourceRoot":"","sources":["../../src/middleware/AutoLoginMiddleware.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,MAAM,CAAA;AAG3C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AACrD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAK/C,qBAAa,mBAAmB;IAI5B,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,OAAO;IAL1B,OAAO,CAAC,OAAO,CAAyB;gBAGrB,MAAM,EAAE,SAAS,EACjB,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,OAAO,EAAE,WAAW;IAGvC,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC,kBAAkB,CAiB1C;CACF"}
|