1- import { checkpoint , cli , command , description , name , option } from "../mod.ts" ;
2- import { schema } from "../lib/param.ts" ;
1+ import {
2+ checkpoint ,
3+ cli ,
4+ command ,
5+ description ,
6+ name ,
7+ option ,
8+ schema ,
9+ transform ,
10+ version ,
11+ } from "../mod.ts" ;
312import type { ModelOf } from "../lib/types.ts" ;
413import { z } from "zod" ;
514
615export const app = command (
716 name ( "auth0" ) ,
17+ description ( "Provision and inspect Auth0 tenants." ) ,
18+ version ( "1.0.0" ) ,
819 option (
9- name ( "port" ) ,
10- description ( "server port" ) ,
11- cli ( [ "--port" , "-p" ] ) ,
12- schema ( z . number ( ) ) ,
13- ) ,
14- option (
15- name ( "domain" ) ,
16- description ( "server domain" ) ,
17- cli ( [ "--domain" ] ) ,
20+ name ( "config" ) ,
21+ description ( "JSON config path" ) ,
22+ cli ( [ "--config" , "-c" ] ) ,
1823 schema ( z . string ( ) ) ,
1924 ) ,
25+ checkpoint ( ) ,
26+ transform (
27+ ( context ) => {
28+ let { domain, port, protocol } = context . options ;
29+ let parsed = domain === undefined ? undefined : parseDomain ( domain ) ;
30+
31+ if ( domain !== undefined && parsed === undefined ) {
32+ context . addIssue ( {
33+ message : `domain must be an HTTP or HTTPS host, received ${ domain } ` ,
34+ } ) ;
35+ }
36+
37+ if (
38+ parsed ?. protocol !== undefined && protocol !== undefined &&
39+ parsed . protocol !== protocol
40+ ) {
41+ context . addIssue ( {
42+ message :
43+ `domain protocol ${ parsed . protocol } conflicts with protocol ${ protocol } ` ,
44+ } ) ;
45+ }
46+
47+ if (
48+ parsed ?. port !== undefined && port !== undefined && parsed . port !== port
49+ ) {
50+ context . addIssue ( {
51+ message : `domain port ${ parsed . port } conflicts with port ${ port } ` ,
52+ } ) ;
53+ }
54+
55+ let resolvedProtocol = protocol ?? parsed ?. protocol ??
56+ ( port === 80 || parsed ?. port === 80 ? "http" : "https" ) ;
57+ let resolvedPort = port ?? parsed ?. port ??
58+ ( resolvedProtocol === "https" ? 443 : 80 ) ;
59+ let host = parsed ?. host ?? "localhost" ;
60+
61+ return {
62+ port : resolvedPort ,
63+ domain : `${ resolvedProtocol } ://${ host } :${ resolvedPort } ` ,
64+ protocol : resolvedProtocol ,
65+ } ;
66+ } ,
67+ option (
68+ name ( "port" ) ,
69+ description ( "server port" ) ,
70+ cli ( [ "--port" , "-p" ] ) ,
71+ schema ( z . optional ( z . number ( ) . int ( ) . min ( 1 ) . max ( 65535 ) ) ) ,
72+ ) ,
73+ option (
74+ name ( "domain" ) ,
75+ description ( "server domain" ) ,
76+ cli ( [ "--domain" ] ) ,
77+ schema ( z . optional ( z . string ( ) ) ) ,
78+ ) ,
79+ option (
80+ name ( "protocol" ) ,
81+ description ( "server protocol" ) ,
82+ cli ( [ "--protocol" ] ) ,
83+ schema ( z . optional ( z . enum ( [ "http" , "https" ] ) ) ) ,
84+ ) ,
85+ ) ,
2086 option (
2187 name ( "audience" ) ,
2288 description ( "Auth0 audience" ) ,
2389 cli ( [ "--audience" ] ) ,
2490 schema ( z . string ( ) ) ,
2591 ) ,
26- option (
27- name ( "clientID" ) ,
28- description ( "Auth0 client ID" ) ,
29- cli ( [ "--client-id" ] ) ,
30- schema ( z . string ( ) ) ,
31- ) ,
32- option (
33- name ( "protocol" ) ,
34- description ( "server protocol" ) ,
35- cli ( [ "--protocol" ] ) ,
36- schema ( z . enum ( [ "http" , "https" ] ) ) ,
37- ) ,
38- checkpoint ( ) ,
39- option (
40- name ( "clientSecret" ) ,
41- description ( "client secret" ) ,
42- cli ( [ "--client-secret" ] ) ,
43- schema ( z . string ( ) ) ,
44- ) ,
45- option (
46- name ( "scope" ) ,
47- description ( "OAuth scope" ) ,
48- cli ( [ "--scope" ] ) ,
49- schema ( z . string ( ) ) ,
50- ) ,
51- option (
52- name ( "rulesDirectory" ) ,
53- description ( "rules directory" ) ,
54- cli ( [ "--rules-directory" ] ) ,
55- schema ( z . string ( ) ) ,
56- ) ,
57- option (
58- name ( "connection" ) ,
59- description ( "Auth0 connection" ) ,
60- cli ( [ "--connection" ] ) ,
61- schema ( z . string ( ) ) ,
62- ) ,
63- option (
64- name ( "config" ) ,
65- description ( "JSON config path" ) ,
66- cli ( [ "--config" , "-c" ] ) ,
67- schema ( z . string ( ) ) ,
68- ) ,
6992) ;
7093
94+ type Protocol = "http" | "https" ;
95+
96+ type ParsedDomain = {
97+ host : string ;
98+ port ?: number ;
99+ protocol ?: Protocol ;
100+ } ;
101+
102+ function parseDomain ( value : string ) : ParsedDomain | undefined {
103+ let hasProtocol = / ^ [ a - z ] [ a - z \d + . - ] * : \/ \/ / i. test ( value ) ;
104+ let url : URL ;
105+
106+ try {
107+ url = new URL ( hasProtocol ? value : `http://${ value } ` ) ;
108+ } catch {
109+ return undefined ;
110+ }
111+
112+ if (
113+ ! [ "http:" , "https:" ] . includes ( url . protocol ) || url . pathname !== "/" ||
114+ url . search !== "" || url . hash !== "" || url . username !== "" ||
115+ url . password !== ""
116+ ) {
117+ return undefined ;
118+ }
119+
120+ return {
121+ host : url . hostname ,
122+ port : url . port === "" ? undefined : Number ( url . port ) ,
123+ protocol : hasProtocol ? url . protocol . slice ( 0 , - 1 ) as Protocol : undefined ,
124+ } ;
125+ }
126+
127+ // Production-use type: application code can use this inferred configuration shape.
71128export type Configuration = ModelOf < typeof app > ;
72129
130+ // Diagnostic-only assertions: these force TypeScript to materialize representative keys.
73131type Equal < A , B > = ( < T > ( ) => T extends A ? 1 : 2 ) extends
74132 ( < T > ( ) => T extends B ? 1 : 2 )
75133 ? ( < T > ( ) => T extends B ? 1 : 2 ) extends ( < T > ( ) => T extends A ? 1 : 2 ) ? true
@@ -79,8 +137,11 @@ type Assert<T extends true> = T;
79137type ConfigIsPresent = Assert <
80138 Equal < "config" extends keyof Configuration ? true : false , true >
81139> ;
82- type ConnectionIsPresent = Assert <
83- Equal < "connection " extends keyof Configuration ? true : false , true >
140+ type PortIsPresent = Assert <
141+ Equal < "port " extends keyof Configuration ? true : false , true >
84142> ;
85143type PortIsNumber = Assert < Equal < Configuration [ "port" ] , number > > ;
86144type ConfigIsString = Assert < Equal < Configuration [ "config" ] , string > > ;
145+ type ProtocolIsEnum = Assert <
146+ Equal < Configuration [ "protocol" ] , "http" | "https" >
147+ > ;
0 commit comments