@blakearoberts/visage 0.0.1-rc.7 → 0.0.1-rc.9
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 +1 -1
- package/dist/certs.d.ts.map +1 -1
- package/dist/compose.d.ts.map +1 -1
- package/dist/config.d.ts +14 -5
- package/dist/config.d.ts.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +96 -68
- package/dist/render/nginx.d.ts.map +1 -1
- package/dist/types.d.ts +4 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +15 -11
package/README.md
CHANGED
|
@@ -125,7 +125,7 @@ Do not treat the managed Dex and OAuth2 Proxy defaults as production auth infras
|
|
|
125
125
|
- If startup fails immediately, confirm Docker is running and `docker compose` works.
|
|
126
126
|
- If NGINX cannot start, check whether the configured `port` is already in use.
|
|
127
127
|
- If the hostname cannot be resolved, Visage may need permission to update `/etc/hosts`.
|
|
128
|
-
- If the browser rejects the certificate, allow the local certificate authority prompt from `mkcert
|
|
128
|
+
- If the browser rejects the certificate, allow the local certificate authority prompt from `mkcert`; CI test runners should be configured to ignore local HTTPS errors.
|
|
129
129
|
|
|
130
130
|
## TO-DO
|
|
131
131
|
|
package/dist/certs.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"certs.d.ts","sourceRoot":"","sources":["../src/certs.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"certs.d.ts","sourceRoot":"","sources":["../src/certs.ts"],"names":[],"mappings":"AAcA,KAAK,OAAO,GAAG;IACb,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC;AAIF,wBAAsB,WAAW,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CA0C7E"}
|
package/dist/compose.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compose.d.ts","sourceRoot":"","sources":["../src/compose.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"compose.d.ts","sourceRoot":"","sources":["../src/compose.ts"],"names":[],"mappings":"AAIA,KAAK,WAAW,GAAG,MAAM,IAAI,CAAC;AAI9B,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,CAwCtD"}
|
package/dist/config.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ResolvedConfig } from 'vite';
|
|
2
|
-
import type { VisageDexExpiry, VisageDexOptions, VisageDexUser, VisageExternalIdpOptions, VisageOptions, VisageService, VisageUpstream } from './types';
|
|
2
|
+
import type { VisageDexExpiry, VisageDexOptions, VisageDexUser, VisageExternalIdpOptions, VisageOptions, VisageProxyPolicy, VisageService, VisageUpstream } from './types';
|
|
3
3
|
type Volume = readonly [from: string, to: string];
|
|
4
4
|
type ResolvedCookiePolicy = {
|
|
5
5
|
readonly cookie_name: string;
|
|
@@ -24,7 +24,7 @@ type ResolvedVisageOptions = {
|
|
|
24
24
|
readonly idp: ResolvedIdpOption;
|
|
25
25
|
readonly oauth2: ResolvedOAuth2Client;
|
|
26
26
|
readonly services: Readonly<Record<string, VisageService>>;
|
|
27
|
-
readonly upstreams
|
|
27
|
+
readonly upstreams: Record<string, VisageUpstream>;
|
|
28
28
|
};
|
|
29
29
|
type ResolvedBaseIdpConfig = {
|
|
30
30
|
readonly upstream: string;
|
|
@@ -44,10 +44,19 @@ type ResolvedExternalIdpConfig = ResolvedBaseIdpConfig & {
|
|
|
44
44
|
};
|
|
45
45
|
type ResolvedIdpConfig = ResolvedDexIdpConfig | ResolvedExternalIdpConfig;
|
|
46
46
|
type ResolvedService = Omit<VisageService, 'upstream'>;
|
|
47
|
-
type ResolvedUpstream =
|
|
47
|
+
type ResolvedUpstream = {
|
|
48
|
+
readonly scheme: 'http' | 'https';
|
|
48
49
|
readonly host: string;
|
|
49
50
|
readonly port: number;
|
|
50
|
-
readonly
|
|
51
|
+
readonly locations: Readonly<Record<string, VisageProxyPolicy>>;
|
|
52
|
+
};
|
|
53
|
+
type ResolvedProxyPolicy = {
|
|
54
|
+
readonly auth: Required<VisageProxyPolicy['auth']>;
|
|
55
|
+
readonly headers: VisageProxyPolicy['headers'];
|
|
56
|
+
};
|
|
57
|
+
type ResolvedConfigUpstream = Omit<ResolvedUpstream, 'locations'> & {
|
|
58
|
+
readonly locations: Readonly<Record<string, ResolvedProxyPolicy>>;
|
|
59
|
+
readonly external: boolean;
|
|
51
60
|
};
|
|
52
61
|
export type VisageConfig = {
|
|
53
62
|
readonly host: string;
|
|
@@ -65,7 +74,7 @@ export type VisageConfig = {
|
|
|
65
74
|
readonly oauth2ProxyClientSecret: Volume;
|
|
66
75
|
};
|
|
67
76
|
readonly services: Readonly<Record<string, ResolvedService>>;
|
|
68
|
-
readonly upstreams: Readonly<Record<string,
|
|
77
|
+
readonly upstreams: Readonly<Record<string, ResolvedConfigUpstream>>;
|
|
69
78
|
};
|
|
70
79
|
export declare function resolveOptions(options: VisageOptions): ResolvedVisageOptions;
|
|
71
80
|
export declare function resolveConfig(options: ResolvedVisageOptions, config: ResolvedConfig, vitePort: number): VisageConfig;
|
package/dist/config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,MAAM,CAAC;AAE3C,OAAO,KAAK,EACV,eAAe,EACf,gBAAgB,EAChB,aAAa,EACb,wBAAwB,EACxB,aAAa,
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AAOnC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AAOnC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAG7C,YAAY,EACV,kBAAkB,EAClB,eAAe,EACf,gBAAgB,EAChB,aAAa,EACb,wBAAwB,EACxB,kBAAkB,EAClB,aAAa,EACb,iBAAiB,EACjB,aAAa,EACb,cAAc,GACf,MAAM,SAAS,CAAC;AAUjB,wBAAgB,MAAM,CAAC,OAAO,GAAE,aAAkB,GAAG,MAAM,CAgE1D;AAED,eAAe,MAAM,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { spawnSync } from 'node:child_process';
|
|
3
|
-
import {
|
|
1
|
+
import { join, dirname } from 'node:path';
|
|
2
|
+
import { spawn, spawnSync } from 'node:child_process';
|
|
3
|
+
import { mkdirSync, openSync, chmodSync, rmSync, existsSync, createWriteStream, readFileSync, appendFileSync, writeFileSync } from 'node:fs';
|
|
4
4
|
import { homedir } from 'node:os';
|
|
5
5
|
import { Readable } from 'node:stream';
|
|
6
6
|
import { pipeline } from 'node:stream/promises';
|
|
@@ -9,83 +9,78 @@ import { hashSync } from 'bcryptjs';
|
|
|
9
9
|
import { Eta } from 'eta';
|
|
10
10
|
import { createHash } from 'node:crypto';
|
|
11
11
|
|
|
12
|
-
let
|
|
12
|
+
let stopRef;
|
|
13
13
|
function startCompose(file) {
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
stopRef?.();
|
|
15
|
+
stopRef = undefined;
|
|
16
|
+
const logs = join(dirname(file), 'logs');
|
|
17
|
+
mkdirSync(logs, { recursive: true });
|
|
18
|
+
const output = openSync(join(logs, 'compose.log'), 'w');
|
|
19
|
+
const compose = [
|
|
20
|
+
'compose',
|
|
21
|
+
`--project-name=${process.env.COMPOSE_PROJECT_NAME ?? 'visage'}`,
|
|
22
|
+
`--file=${file}`,
|
|
23
|
+
];
|
|
24
|
+
const env = { ...process.env, COMPOSE_MENU: 'false' };
|
|
25
|
+
const opts = {
|
|
26
|
+
cwd: dirname(file),
|
|
27
|
+
stdio: ['ignore', output, output],
|
|
28
|
+
env,
|
|
29
|
+
};
|
|
30
|
+
const up = [
|
|
31
|
+
...compose,
|
|
32
|
+
'up',
|
|
33
|
+
'--abort-on-container-failure',
|
|
34
|
+
'--no-color',
|
|
35
|
+
'--remove-orphans',
|
|
36
|
+
];
|
|
37
|
+
const child = spawn('docker', up, opts);
|
|
16
38
|
const stop = () => {
|
|
17
|
-
if (
|
|
39
|
+
if (stopRef !== stop)
|
|
18
40
|
return;
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
41
|
+
stopRef = undefined;
|
|
42
|
+
child.kill();
|
|
43
|
+
const down = [...compose, 'down', '--remove-orphans'];
|
|
44
|
+
spawnSync('docker', down, opts);
|
|
23
45
|
};
|
|
24
|
-
|
|
25
|
-
stopCompose = stop;
|
|
26
|
-
process.off('SIGINT', onSigInt);
|
|
27
|
-
process.off('SIGTERM', onSigTerm);
|
|
28
|
-
process.once('SIGINT', onSigInt);
|
|
29
|
-
process.once('SIGTERM', onSigTerm);
|
|
46
|
+
stopRef = stop;
|
|
30
47
|
return stop;
|
|
31
48
|
}
|
|
32
|
-
function run(file, args, message) {
|
|
33
|
-
const result = spawnSync('docker', ['compose', '-f', file, ...args], {
|
|
34
|
-
cwd: dirname(file),
|
|
35
|
-
stdio: 'inherit',
|
|
36
|
-
});
|
|
37
|
-
if (result.error)
|
|
38
|
-
throw result.error;
|
|
39
|
-
if (result.status !== 0)
|
|
40
|
-
throw new Error(message);
|
|
41
|
-
}
|
|
42
|
-
function onSigInt() {
|
|
43
|
-
try {
|
|
44
|
-
stopCompose?.();
|
|
45
|
-
}
|
|
46
|
-
finally {
|
|
47
|
-
process.exit(130);
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
function onSigTerm() {
|
|
51
|
-
try {
|
|
52
|
-
stopCompose?.();
|
|
53
|
-
}
|
|
54
|
-
finally {
|
|
55
|
-
process.exit(143);
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
49
|
|
|
50
|
+
const CACHE_HOME = process.env.XDG_CACHE_HOME || join(homedir(), '.cache');
|
|
59
51
|
async function ensureCerts({ certs, hostname }) {
|
|
60
|
-
const
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
return;
|
|
52
|
+
const CAROOT = join(CACHE_HOME, 'visage/ca');
|
|
53
|
+
mkdirSync(CAROOT, { recursive: true, mode: 0o700 });
|
|
54
|
+
chmodSync(CAROOT, 0o700);
|
|
64
55
|
const mkcert = await ensureMkCert();
|
|
65
|
-
const
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
};
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
56
|
+
const logs = join(dirname(certs), 'logs');
|
|
57
|
+
mkdirSync(logs, { recursive: true });
|
|
58
|
+
const log = join(logs, 'mkcert.log');
|
|
59
|
+
const output = openSync(log, 'w');
|
|
60
|
+
const env = { CAROOT, TRUST_STORES: 'system', ...process.env };
|
|
61
|
+
const tty = process.stdin.isTTY;
|
|
62
|
+
const stdio = [
|
|
63
|
+
tty ? 'inherit' : 'ignore',
|
|
64
|
+
output,
|
|
65
|
+
output,
|
|
66
|
+
];
|
|
67
|
+
if (process.env.CI !== 'true') {
|
|
68
|
+
// mkcert -install is idempotent; CA files alone do not prove trust-store state.
|
|
69
|
+
const result = spawnSync(mkcert, ['-install'], { env, stdio });
|
|
78
70
|
if (result.error)
|
|
79
71
|
throw result.error;
|
|
80
72
|
if (result.status !== 0) {
|
|
81
73
|
throw new Error('Failed to install CA');
|
|
82
74
|
}
|
|
83
75
|
}
|
|
84
|
-
|
|
76
|
+
const cert = join(certs, 'tls.crt');
|
|
77
|
+
const key = join(certs, 'tls.key');
|
|
85
78
|
mkdirSync(certs, { recursive: true });
|
|
79
|
+
rmSync(cert, { force: true });
|
|
80
|
+
rmSync(key, { force: true });
|
|
86
81
|
const names = [...new Set([hostname, 'localhost', '127.0.0.1', '::1'])];
|
|
87
82
|
const args = ['-cert-file', cert, '-key-file', key, ...names];
|
|
88
|
-
const result = spawnSync(mkcert, args, { env, stdio
|
|
83
|
+
const result = spawnSync(mkcert, args, { env, stdio });
|
|
89
84
|
if (result.error)
|
|
90
85
|
throw result.error;
|
|
91
86
|
if (result.status !== 0) {
|
|
@@ -93,7 +88,7 @@ async function ensureCerts({ certs, hostname }) {
|
|
|
93
88
|
}
|
|
94
89
|
}
|
|
95
90
|
async function ensureMkCert() {
|
|
96
|
-
const bin = join(
|
|
91
|
+
const bin = join(CACHE_HOME, 'visage/bin');
|
|
97
92
|
const file = join(bin, `mkcert-${process.platform}-${process.arch}`);
|
|
98
93
|
if (existsSync(file))
|
|
99
94
|
return file;
|
|
@@ -235,6 +230,8 @@ const template = `
|
|
|
235
230
|
events {}
|
|
236
231
|
|
|
237
232
|
http {
|
|
233
|
+
resolver 127.0.0.11 ipv6=off;
|
|
234
|
+
|
|
238
235
|
# Allow WebSockets (Vite HMR).
|
|
239
236
|
map $http_upgrade $connection_upgrade {
|
|
240
237
|
default upgrade;
|
|
@@ -243,7 +240,12 @@ http {
|
|
|
243
240
|
|
|
244
241
|
<%_ for (const [name, upstream] of Object.entries(it.upstreams)) { %>
|
|
245
242
|
upstream <%~ name %> {
|
|
243
|
+
<%_ if (upstream.external) { %>
|
|
244
|
+
zone <%~ name %> 64k;
|
|
245
|
+
server <%~ upstream.host %>:<%~ upstream.port %> resolve;
|
|
246
|
+
<%_ } else { %>
|
|
246
247
|
server <%~ upstream.host %>:<%~ upstream.port %>;
|
|
248
|
+
<%_ } %>
|
|
247
249
|
}
|
|
248
250
|
|
|
249
251
|
<%_ } %>
|
|
@@ -254,6 +256,9 @@ http {
|
|
|
254
256
|
ssl_certificate <%~ it.ssl.cert %>;
|
|
255
257
|
ssl_certificate_key <%~ it.ssl.key %>;
|
|
256
258
|
|
|
259
|
+
# Redirect accidental plaintext HTTP requests sent to the HTTPS port.
|
|
260
|
+
error_page 497 =301 https://$http_host$request_uri;
|
|
261
|
+
|
|
257
262
|
<%_ for (const [name, upstream] of Object.entries(it.upstreams)) { %>
|
|
258
263
|
<%_ for (const [path, location] of Object.entries(upstream.locations ?? {})) { %>
|
|
259
264
|
location <%~ path %> {
|
|
@@ -334,6 +339,8 @@ function renderOauth2ProxyConfig(config) {
|
|
|
334
339
|
cookie_httponly: true,
|
|
335
340
|
cookie_secure: true,
|
|
336
341
|
cookie_samesite: 'lax',
|
|
342
|
+
cookie_csrf_per_request: true,
|
|
343
|
+
cookie_csrf_per_request_limit: 16,
|
|
337
344
|
email_domains: ['*'],
|
|
338
345
|
scope: config.oauth2.scopes.join(' '),
|
|
339
346
|
upstreams: ['static://202'],
|
|
@@ -342,6 +349,7 @@ function renderOauth2ProxyConfig(config) {
|
|
|
342
349
|
pass_access_token: true,
|
|
343
350
|
pass_authorization_header: true,
|
|
344
351
|
skip_provider_button: true,
|
|
352
|
+
whitelist_domains: [config.host, `${config.host}:${config.port}`],
|
|
345
353
|
};
|
|
346
354
|
return `${Object.entries(data)
|
|
347
355
|
.map(([key, value]) => {
|
|
@@ -598,6 +606,7 @@ function resolveExternalIdpUpstream(idp) {
|
|
|
598
606
|
const issuer = new URL(idp.issuer);
|
|
599
607
|
return {
|
|
600
608
|
host: issuer.hostname,
|
|
609
|
+
locations: {},
|
|
601
610
|
scheme: issuer.protocol === 'https:' ? 'https' : 'http',
|
|
602
611
|
port: Number(issuer.port) || (issuer.protocol === 'https:' ? 443 : 80),
|
|
603
612
|
};
|
|
@@ -639,12 +648,13 @@ function resolveConfig(options, config, vitePort) {
|
|
|
639
648
|
...Object.fromEntries(Object.entries(options.services).map(([name, { upstream: _upstream, ...service }]) => [name, service])),
|
|
640
649
|
},
|
|
641
650
|
upstreams: Object.fromEntries(Object.entries(upstreams).map(([name, upstream]) => {
|
|
642
|
-
const external = options.upstreams
|
|
651
|
+
const external = options.upstreams[name] !== undefined &&
|
|
643
652
|
options.services[name] === undefined;
|
|
644
653
|
return [
|
|
645
654
|
name,
|
|
646
655
|
{
|
|
647
656
|
...upstream,
|
|
657
|
+
external,
|
|
648
658
|
locations: Object.fromEntries(Object.entries(upstream.locations ?? {}).map(([path, policy]) => [
|
|
649
659
|
path,
|
|
650
660
|
{
|
|
@@ -663,9 +673,20 @@ function resolveConfig(options, config, vitePort) {
|
|
|
663
673
|
};
|
|
664
674
|
}
|
|
665
675
|
|
|
676
|
+
function formatUrl(host, port) {
|
|
677
|
+
const AnsiGreen = '\x1b[32m';
|
|
678
|
+
const AnsiCyan = '\x1b[36m';
|
|
679
|
+
const AnsiBold = '\x1b[1m';
|
|
680
|
+
const AnsiReset = '\x1b[0m';
|
|
681
|
+
return ` ${AnsiGreen}➜${AnsiReset} ${AnsiBold}Visage${AnsiReset}: ${AnsiCyan}https://${host}:${AnsiBold}${port}${AnsiReset}${AnsiCyan}/${AnsiReset}`;
|
|
682
|
+
}
|
|
666
683
|
function visage(options = {}) {
|
|
667
684
|
const resolvedOptions = resolveOptions(options);
|
|
668
685
|
let stop;
|
|
686
|
+
const closeBundle = () => {
|
|
687
|
+
stop?.();
|
|
688
|
+
stop = undefined;
|
|
689
|
+
};
|
|
669
690
|
return {
|
|
670
691
|
name: 'visage',
|
|
671
692
|
apply: 'serve',
|
|
@@ -682,8 +703,17 @@ function visage(options = {}) {
|
|
|
682
703
|
};
|
|
683
704
|
},
|
|
684
705
|
configureServer(server) {
|
|
706
|
+
let url;
|
|
707
|
+
const printUrls = server.printUrls.bind(server);
|
|
708
|
+
server.printUrls = () => {
|
|
709
|
+
printUrls();
|
|
710
|
+
if (url)
|
|
711
|
+
server.config.logger.info(formatUrl(url.host, url.port));
|
|
712
|
+
};
|
|
685
713
|
async function startVisage(port) {
|
|
686
714
|
const config = resolveConfig(resolvedOptions, server.config, port);
|
|
715
|
+
url = { host: config.host, port: config.port };
|
|
716
|
+
rmSync(join(config.cache, 'logs'), { recursive: true, force: true });
|
|
687
717
|
await ensureCerts({
|
|
688
718
|
certs: join(config.cache, config.files.certs[0]),
|
|
689
719
|
hostname: config.host,
|
|
@@ -700,13 +730,11 @@ function visage(options = {}) {
|
|
|
700
730
|
throw new Error('Failed to resolve port for Visage');
|
|
701
731
|
}
|
|
702
732
|
stop = await startVisage(address.port);
|
|
733
|
+
server.httpServer?.once('close', closeBundle);
|
|
703
734
|
return result;
|
|
704
735
|
};
|
|
705
736
|
},
|
|
706
|
-
closeBundle
|
|
707
|
-
stop?.();
|
|
708
|
-
stop = undefined;
|
|
709
|
-
},
|
|
737
|
+
closeBundle,
|
|
710
738
|
};
|
|
711
739
|
}
|
|
712
740
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"nginx.d.ts","sourceRoot":"","sources":["../../src/render/nginx.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"nginx.d.ts","sourceRoot":"","sources":["../../src/render/nginx.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAiE9C,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,YAAY,GAAG,IAAI,CAI3D"}
|
package/dist/types.d.ts
CHANGED
|
@@ -151,11 +151,15 @@ export type VisageDexExpiry = {
|
|
|
151
151
|
export type VisageDexUser = {
|
|
152
152
|
/**
|
|
153
153
|
* Email address used as the Dex login identifier.
|
|
154
|
+
*
|
|
155
|
+
* @defaultValue `'user@example.com'`
|
|
154
156
|
*/
|
|
155
157
|
readonly email: string;
|
|
156
158
|
/**
|
|
157
159
|
* Plain-text development password. Visage hashes this before rendering the
|
|
158
160
|
* Dex config.
|
|
161
|
+
*
|
|
162
|
+
* @defaultValue `'pass'`
|
|
159
163
|
*/
|
|
160
164
|
readonly password: string;
|
|
161
165
|
/**
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,MAAM,aAAa,GAAG;IAC1B;;;;OAIG;IACH,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB;;;;OAIG;IACH,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB;;;OAGG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,kBAAkB,CAAC;IACrC;;;OAGG;IACH,QAAQ,CAAC,GAAG,CAAC,EAAE,gBAAgB,GAAG,wBAAwB,CAAC;IAC3D;;OAEG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,kBAAkB,CAAC;IACrC;;;OAGG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;IAClD;;OAEG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;CACrD,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,MAAM,kBAAkB,GAAG;IAC/B;;;;;;OAMG;IACH,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB;;;;;;;OAOG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB;;;;;;;;OAQG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B;;;OAGG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACrC;;;;;OAKG;IACH,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;CACxB,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,gBAAgB,GAAG;IAC7B;;OAEG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,eAAe,CAAC;IAClC;;;;OAIG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,aAAa,EAAE,CAAC;CAC3C,CAAC;AAEF;;;;GAIG;AACH,MAAM,MAAM,eAAe,GAAG;IAC5B;;OAEG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B;;OAEG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B;;OAEG;IACH,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IACjC;;OAEG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B;;OAEG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE;QACvB;;WAEG;QACH,QAAQ,CAAC,iBAAiB,CAAC,EAAE,MAAM,CAAC;QACpC;;WAEG;QACH,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;QACnC;;WAEG;QACH,QAAQ,CAAC,eAAe,CAAC,EAAE,OAAO,CAAC;QACnC;;WAEG;QACH,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;KACjC,CAAC;CACH,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,aAAa,GAAG;IAC1B
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@blakearoberts/visage",
|
|
3
|
-
"version": "0.0.1-rc.
|
|
3
|
+
"version": "0.0.1-rc.9",
|
|
4
4
|
"description": "Vite plugin for local development with HMR and OIDC session cookie lifecycle semantics.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"author": "Blake Roberts",
|
|
@@ -14,14 +14,15 @@
|
|
|
14
14
|
},
|
|
15
15
|
"homepage": "https://github.com/blakearoberts/visage#readme",
|
|
16
16
|
"keywords": [
|
|
17
|
-
"
|
|
18
|
-
"plugin",
|
|
19
|
-
"oidc",
|
|
17
|
+
"authentication",
|
|
20
18
|
"hmr",
|
|
21
|
-
"
|
|
22
|
-
"
|
|
23
|
-
"
|
|
24
|
-
"
|
|
19
|
+
"local-development",
|
|
20
|
+
"oauth2",
|
|
21
|
+
"oidc",
|
|
22
|
+
"pkce",
|
|
23
|
+
"session-cookie",
|
|
24
|
+
"vite",
|
|
25
|
+
"vite-plugin"
|
|
25
26
|
],
|
|
26
27
|
"main": "dist/index.js",
|
|
27
28
|
"types": "dist/index.d.ts",
|
|
@@ -44,11 +45,14 @@
|
|
|
44
45
|
"scripts": {
|
|
45
46
|
"build": "npm run clean && rollup -c",
|
|
46
47
|
"clean": "node -e \"require('node:fs').rmSync('dist', { recursive: true, force: true })\"",
|
|
47
|
-
"
|
|
48
|
+
"dev:example": "cd examples/managed-service && npm run dev",
|
|
49
|
+
"format": "prettier --write \"{docs,examples,src,test}/**/*.{ts,tsx,js,jsx,json,css,html,md}\" \"*.{json,md}\"",
|
|
50
|
+
"format:check": "prettier --check \"{docs,examples,src,test}/**/*.{ts,tsx,js,jsx,json,css,html,md}\" \"*.{json,md}\"",
|
|
51
|
+
"test": "npm run typecheck && npm run test:unit",
|
|
52
|
+
"test:all": "npm test && npm run test:e2e",
|
|
48
53
|
"test:e2e": "playwright test test/e2e",
|
|
49
54
|
"test:unit": "node --experimental-strip-types --test test/unit/*.test.ts",
|
|
50
|
-
"
|
|
51
|
-
"format:check": "prettier --check \"{docs,examples,src,test}/**/*.{ts,tsx,js,jsx,json,css,html,md}\" \"*.{json,md}\""
|
|
55
|
+
"typecheck": "tsc --noEmit && tsc -p tsconfig.test.json"
|
|
52
56
|
},
|
|
53
57
|
"devDependencies": {
|
|
54
58
|
"@playwright/test": "^1.59.1",
|