@poly-x/next 0.1.0-alpha.1 → 0.1.0-alpha.3
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/server.cjs +45 -0
- package/dist/server.d.cts +26 -1
- package/dist/server.d.mts +26 -1
- package/dist/server.mjs +45 -0
- package/dist/styles.css +274 -0
- package/package.json +9 -6
package/dist/server.cjs
CHANGED
|
@@ -89,6 +89,51 @@ function createAuthHandlers(handlersConfig = {}) {
|
|
|
89
89
|
});
|
|
90
90
|
return Response.redirect(url, 302);
|
|
91
91
|
},
|
|
92
|
+
async authenticate(request) {
|
|
93
|
+
const config = resolveNextConfig(handlersConfig);
|
|
94
|
+
const redirectUri = `${new URL(request.url).origin}${callbackPath}`;
|
|
95
|
+
let payload;
|
|
96
|
+
try {
|
|
97
|
+
payload = await request.json();
|
|
98
|
+
} catch {
|
|
99
|
+
return Response.json({ status: "invalid_request" }, { status: 400 });
|
|
100
|
+
}
|
|
101
|
+
const email = typeof payload.email === "string" ? payload.email : "";
|
|
102
|
+
const password = typeof payload.password === "string" ? payload.password : "";
|
|
103
|
+
if (!email || !password) return Response.json({ status: "invalid_request" }, { status: 400 });
|
|
104
|
+
const organizationCode = typeof payload.organizationCode === "string" ? payload.organizationCode : void 0;
|
|
105
|
+
const tenantId = typeof payload.tenantId === "string" ? payload.tenantId : void 0;
|
|
106
|
+
const { verifier, challenge } = await (0, _poly_x_core.generatePkce)();
|
|
107
|
+
const state = (0, _poly_x_core.randomState)();
|
|
108
|
+
const outcome = await buildServerAuthClient(config).authorizeWithPassword({
|
|
109
|
+
email,
|
|
110
|
+
password,
|
|
111
|
+
redirectUri,
|
|
112
|
+
state,
|
|
113
|
+
challenge,
|
|
114
|
+
organizationCode,
|
|
115
|
+
tenantId
|
|
116
|
+
});
|
|
117
|
+
switch (outcome.type) {
|
|
118
|
+
case "authorized":
|
|
119
|
+
await newSession(adapt(await (0, next_headers.cookies)()), config).establishFromCode(outcome.code, verifier, redirectUri);
|
|
120
|
+
return Response.json({
|
|
121
|
+
status: "success",
|
|
122
|
+
redirectTo: afterSignInPath
|
|
123
|
+
});
|
|
124
|
+
case "select_tenant": return Response.json({
|
|
125
|
+
status: "select_tenant",
|
|
126
|
+
tenants: outcome.tenants,
|
|
127
|
+
state: outcome.state
|
|
128
|
+
});
|
|
129
|
+
case "password_change_required": return Response.json({
|
|
130
|
+
status: "password_change_required",
|
|
131
|
+
userId: outcome.userId
|
|
132
|
+
}, { status: 403 });
|
|
133
|
+
case "no_access": return Response.json({ status: "no_access" }, { status: 403 });
|
|
134
|
+
default: return Response.json({ status: "invalid_credentials" }, { status: 401 });
|
|
135
|
+
}
|
|
136
|
+
},
|
|
92
137
|
async callback(request) {
|
|
93
138
|
const config = resolveNextConfig(handlersConfig);
|
|
94
139
|
const url = new URL(request.url);
|
package/dist/server.d.cts
CHANGED
|
@@ -73,10 +73,35 @@ interface AuthHandlersConfig extends Partial<NextServerConfig> {
|
|
|
73
73
|
}
|
|
74
74
|
interface AuthHandlers {
|
|
75
75
|
signin(request: Request): Promise<Response>;
|
|
76
|
+
/**
|
|
77
|
+
* The embedded `<SignIn/>` BFF endpoint: reads `{email, password}` (+ optional
|
|
78
|
+
* `organizationCode`/`tenantId`), runs the password authorize entirely
|
|
79
|
+
* server-side, and — on success — seals the httpOnly session before returning.
|
|
80
|
+
* The browser never sees the code, the tokens, or the credentials after POST.
|
|
81
|
+
*/
|
|
82
|
+
authenticate(request: Request): Promise<Response>;
|
|
76
83
|
callback(request: Request): Promise<Response>;
|
|
77
84
|
refresh(request: Request): Promise<Response>;
|
|
78
85
|
signout(request: Request): Promise<Response>;
|
|
79
86
|
}
|
|
87
|
+
/** The JSON the `authenticate` handler returns — the `<SignIn/>` form branches on `status`. */
|
|
88
|
+
type AuthenticateResult = {
|
|
89
|
+
status: "success";
|
|
90
|
+
redirectTo: string;
|
|
91
|
+
} | {
|
|
92
|
+
status: "select_tenant";
|
|
93
|
+
tenants: unknown[];
|
|
94
|
+
state: string;
|
|
95
|
+
} | {
|
|
96
|
+
status: "password_change_required";
|
|
97
|
+
userId: string;
|
|
98
|
+
} | {
|
|
99
|
+
status: "no_access";
|
|
100
|
+
} | {
|
|
101
|
+
status: "invalid_credentials";
|
|
102
|
+
} | {
|
|
103
|
+
status: "invalid_request";
|
|
104
|
+
};
|
|
80
105
|
declare function createAuthHandlers(handlersConfig?: AuthHandlersConfig): AuthHandlers;
|
|
81
106
|
//#endregion
|
|
82
|
-
export { type AuthContext, AuthHandlers, AuthHandlersConfig, type CookieAdapter, type CookieSetOptions, DEFAULT_SESSION_COOKIE, type NextServerConfig, ServerSession, auth, createAuthHandlers, openSession, resolveNextConfig, sealSession };
|
|
107
|
+
export { type AuthContext, AuthHandlers, AuthHandlersConfig, AuthenticateResult, type CookieAdapter, type CookieSetOptions, DEFAULT_SESSION_COOKIE, type NextServerConfig, ServerSession, auth, createAuthHandlers, openSession, resolveNextConfig, sealSession };
|
package/dist/server.d.mts
CHANGED
|
@@ -73,10 +73,35 @@ interface AuthHandlersConfig extends Partial<NextServerConfig> {
|
|
|
73
73
|
}
|
|
74
74
|
interface AuthHandlers {
|
|
75
75
|
signin(request: Request): Promise<Response>;
|
|
76
|
+
/**
|
|
77
|
+
* The embedded `<SignIn/>` BFF endpoint: reads `{email, password}` (+ optional
|
|
78
|
+
* `organizationCode`/`tenantId`), runs the password authorize entirely
|
|
79
|
+
* server-side, and — on success — seals the httpOnly session before returning.
|
|
80
|
+
* The browser never sees the code, the tokens, or the credentials after POST.
|
|
81
|
+
*/
|
|
82
|
+
authenticate(request: Request): Promise<Response>;
|
|
76
83
|
callback(request: Request): Promise<Response>;
|
|
77
84
|
refresh(request: Request): Promise<Response>;
|
|
78
85
|
signout(request: Request): Promise<Response>;
|
|
79
86
|
}
|
|
87
|
+
/** The JSON the `authenticate` handler returns — the `<SignIn/>` form branches on `status`. */
|
|
88
|
+
type AuthenticateResult = {
|
|
89
|
+
status: "success";
|
|
90
|
+
redirectTo: string;
|
|
91
|
+
} | {
|
|
92
|
+
status: "select_tenant";
|
|
93
|
+
tenants: unknown[];
|
|
94
|
+
state: string;
|
|
95
|
+
} | {
|
|
96
|
+
status: "password_change_required";
|
|
97
|
+
userId: string;
|
|
98
|
+
} | {
|
|
99
|
+
status: "no_access";
|
|
100
|
+
} | {
|
|
101
|
+
status: "invalid_credentials";
|
|
102
|
+
} | {
|
|
103
|
+
status: "invalid_request";
|
|
104
|
+
};
|
|
80
105
|
declare function createAuthHandlers(handlersConfig?: AuthHandlersConfig): AuthHandlers;
|
|
81
106
|
//#endregion
|
|
82
|
-
export { type AuthContext, AuthHandlers, AuthHandlersConfig, type CookieAdapter, type CookieSetOptions, DEFAULT_SESSION_COOKIE, type NextServerConfig, ServerSession, auth, createAuthHandlers, openSession, resolveNextConfig, sealSession };
|
|
107
|
+
export { type AuthContext, AuthHandlers, AuthHandlersConfig, AuthenticateResult, type CookieAdapter, type CookieSetOptions, DEFAULT_SESSION_COOKIE, type NextServerConfig, ServerSession, auth, createAuthHandlers, openSession, resolveNextConfig, sealSession };
|
package/dist/server.mjs
CHANGED
|
@@ -88,6 +88,51 @@ function createAuthHandlers(handlersConfig = {}) {
|
|
|
88
88
|
});
|
|
89
89
|
return Response.redirect(url, 302);
|
|
90
90
|
},
|
|
91
|
+
async authenticate(request) {
|
|
92
|
+
const config = resolveNextConfig(handlersConfig);
|
|
93
|
+
const redirectUri = `${new URL(request.url).origin}${callbackPath}`;
|
|
94
|
+
let payload;
|
|
95
|
+
try {
|
|
96
|
+
payload = await request.json();
|
|
97
|
+
} catch {
|
|
98
|
+
return Response.json({ status: "invalid_request" }, { status: 400 });
|
|
99
|
+
}
|
|
100
|
+
const email = typeof payload.email === "string" ? payload.email : "";
|
|
101
|
+
const password = typeof payload.password === "string" ? payload.password : "";
|
|
102
|
+
if (!email || !password) return Response.json({ status: "invalid_request" }, { status: 400 });
|
|
103
|
+
const organizationCode = typeof payload.organizationCode === "string" ? payload.organizationCode : void 0;
|
|
104
|
+
const tenantId = typeof payload.tenantId === "string" ? payload.tenantId : void 0;
|
|
105
|
+
const { verifier, challenge } = await generatePkce();
|
|
106
|
+
const state = randomState();
|
|
107
|
+
const outcome = await buildServerAuthClient(config).authorizeWithPassword({
|
|
108
|
+
email,
|
|
109
|
+
password,
|
|
110
|
+
redirectUri,
|
|
111
|
+
state,
|
|
112
|
+
challenge,
|
|
113
|
+
organizationCode,
|
|
114
|
+
tenantId
|
|
115
|
+
});
|
|
116
|
+
switch (outcome.type) {
|
|
117
|
+
case "authorized":
|
|
118
|
+
await newSession(adapt(await cookies()), config).establishFromCode(outcome.code, verifier, redirectUri);
|
|
119
|
+
return Response.json({
|
|
120
|
+
status: "success",
|
|
121
|
+
redirectTo: afterSignInPath
|
|
122
|
+
});
|
|
123
|
+
case "select_tenant": return Response.json({
|
|
124
|
+
status: "select_tenant",
|
|
125
|
+
tenants: outcome.tenants,
|
|
126
|
+
state: outcome.state
|
|
127
|
+
});
|
|
128
|
+
case "password_change_required": return Response.json({
|
|
129
|
+
status: "password_change_required",
|
|
130
|
+
userId: outcome.userId
|
|
131
|
+
}, { status: 403 });
|
|
132
|
+
case "no_access": return Response.json({ status: "no_access" }, { status: 403 });
|
|
133
|
+
default: return Response.json({ status: "invalid_credentials" }, { status: 401 });
|
|
134
|
+
}
|
|
135
|
+
},
|
|
91
136
|
async callback(request) {
|
|
92
137
|
const config = resolveNextConfig(handlersConfig);
|
|
93
138
|
const url = new URL(request.url);
|
package/dist/styles.css
ADDED
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @poly-x/react — default component styles.
|
|
3
|
+
*
|
|
4
|
+
* Import once, near the root of your app:
|
|
5
|
+
* import "@poly-x/react/styles.css"; // or "@poly-x/next/styles.css"
|
|
6
|
+
*
|
|
7
|
+
* The SDK is a guest in your app: every rule is scoped under a `.polyx-*` class,
|
|
8
|
+
* there are no global element selectors, and nothing here leaks into your own
|
|
9
|
+
* markup. To theme it, override the custom properties below on any ancestor
|
|
10
|
+
* (`:root`, a wrapper div, …) — that is the supported theming surface. Dark mode
|
|
11
|
+
* follows the OS by default and defers to an explicit `.dark` / `[data-theme]`
|
|
12
|
+
* on a host ancestor when one is present.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
.polyx-signin {
|
|
16
|
+
/* Colors */
|
|
17
|
+
--polyx-brand: #4f46e5;
|
|
18
|
+
--polyx-brand-hover: #4338ca;
|
|
19
|
+
--polyx-brand-fg: #ffffff;
|
|
20
|
+
--polyx-bg: #ffffff;
|
|
21
|
+
--polyx-fg: #18181b;
|
|
22
|
+
--polyx-muted-fg: #71717a;
|
|
23
|
+
--polyx-border: #e4e4e7;
|
|
24
|
+
--polyx-input-bg: #ffffff;
|
|
25
|
+
--polyx-ring: #a5b4fc;
|
|
26
|
+
--polyx-danger: #dc2626;
|
|
27
|
+
--polyx-danger-bg: #fef2f2;
|
|
28
|
+
--polyx-page-bg: #fafafa;
|
|
29
|
+
|
|
30
|
+
/* Shape + type */
|
|
31
|
+
--polyx-radius: 0.75rem;
|
|
32
|
+
--polyx-radius-sm: 0.5rem;
|
|
33
|
+
--polyx-font: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
|
|
34
|
+
--polyx-shadow: 0 1px 3px rgb(0 0 0 / 0.06), 0 10px 30px rgb(0 0 0 / 0.07);
|
|
35
|
+
|
|
36
|
+
font-family: var(--polyx-font);
|
|
37
|
+
color: var(--polyx-fg);
|
|
38
|
+
-webkit-font-smoothing: antialiased;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/* Scoped box model — applies only inside our own subtree. */
|
|
42
|
+
.polyx-signin,
|
|
43
|
+
.polyx-signin *,
|
|
44
|
+
.polyx-signin *::before,
|
|
45
|
+
.polyx-signin *::after {
|
|
46
|
+
box-sizing: border-box;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/* Dark: follow the OS… */
|
|
50
|
+
@media (prefers-color-scheme: dark) {
|
|
51
|
+
.polyx-signin {
|
|
52
|
+
--polyx-brand: #6366f1;
|
|
53
|
+
--polyx-brand-hover: #818cf8;
|
|
54
|
+
--polyx-bg: #18181b;
|
|
55
|
+
--polyx-fg: #fafafa;
|
|
56
|
+
--polyx-muted-fg: #a1a1aa;
|
|
57
|
+
--polyx-border: #3f3f46;
|
|
58
|
+
--polyx-input-bg: #27272a;
|
|
59
|
+
--polyx-ring: #4f46e5;
|
|
60
|
+
--polyx-danger: #f87171;
|
|
61
|
+
--polyx-danger-bg: #2a1616;
|
|
62
|
+
--polyx-page-bg: #09090b;
|
|
63
|
+
--polyx-shadow: 0 1px 3px rgb(0 0 0 / 0.4), 0 10px 30px rgb(0 0 0 / 0.35);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/* …but an explicit host theme wins over the OS preference (`:where` keeps
|
|
68
|
+
specificity at 0 so these stay as easy to override as the base rule). */
|
|
69
|
+
:where(.dark, [data-theme="dark"]) .polyx-signin {
|
|
70
|
+
--polyx-brand: #6366f1;
|
|
71
|
+
--polyx-brand-hover: #818cf8;
|
|
72
|
+
--polyx-bg: #18181b;
|
|
73
|
+
--polyx-fg: #fafafa;
|
|
74
|
+
--polyx-muted-fg: #a1a1aa;
|
|
75
|
+
--polyx-border: #3f3f46;
|
|
76
|
+
--polyx-input-bg: #27272a;
|
|
77
|
+
--polyx-ring: #4f46e5;
|
|
78
|
+
--polyx-danger: #f87171;
|
|
79
|
+
--polyx-danger-bg: #2a1616;
|
|
80
|
+
--polyx-page-bg: #09090b;
|
|
81
|
+
--polyx-shadow: 0 1px 3px rgb(0 0 0 / 0.4), 0 10px 30px rgb(0 0 0 / 0.35);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
:where(.light, [data-theme="light"]) .polyx-signin {
|
|
85
|
+
--polyx-brand: #4f46e5;
|
|
86
|
+
--polyx-brand-hover: #4338ca;
|
|
87
|
+
--polyx-bg: #ffffff;
|
|
88
|
+
--polyx-fg: #18181b;
|
|
89
|
+
--polyx-muted-fg: #71717a;
|
|
90
|
+
--polyx-border: #e4e4e7;
|
|
91
|
+
--polyx-input-bg: #ffffff;
|
|
92
|
+
--polyx-ring: #a5b4fc;
|
|
93
|
+
--polyx-danger: #dc2626;
|
|
94
|
+
--polyx-danger-bg: #fef2f2;
|
|
95
|
+
--polyx-page-bg: #fafafa;
|
|
96
|
+
--polyx-shadow: 0 1px 3px rgb(0 0 0 / 0.06), 0 10px 30px rgb(0 0 0 / 0.07);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/* --- Variants ------------------------------------------------------------ */
|
|
100
|
+
|
|
101
|
+
/* `page`: owns the viewport — centered card on a full-bleed background. */
|
|
102
|
+
.polyx-signin--page {
|
|
103
|
+
display: grid;
|
|
104
|
+
place-items: center;
|
|
105
|
+
min-height: 100dvh;
|
|
106
|
+
padding: 1.5rem;
|
|
107
|
+
background: var(--polyx-page-bg);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/* `card`: just the card — drop it anywhere in your own layout. */
|
|
111
|
+
.polyx-signin--card {
|
|
112
|
+
display: block;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
.polyx-signin__card {
|
|
116
|
+
width: 100%;
|
|
117
|
+
max-width: 24rem;
|
|
118
|
+
margin-inline: auto;
|
|
119
|
+
padding: 2rem;
|
|
120
|
+
background: var(--polyx-bg);
|
|
121
|
+
border: 1px solid var(--polyx-border);
|
|
122
|
+
border-radius: var(--polyx-radius);
|
|
123
|
+
box-shadow: var(--polyx-shadow);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/* --- Header -------------------------------------------------------------- */
|
|
127
|
+
|
|
128
|
+
.polyx-signin__header {
|
|
129
|
+
display: flex;
|
|
130
|
+
flex-direction: column;
|
|
131
|
+
gap: 0.375rem;
|
|
132
|
+
margin-bottom: 1.75rem;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
.polyx-signin__logo {
|
|
136
|
+
display: flex;
|
|
137
|
+
margin-bottom: 0.75rem;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
.polyx-signin__heading {
|
|
141
|
+
margin: 0;
|
|
142
|
+
font-size: 1.375rem;
|
|
143
|
+
font-weight: 600;
|
|
144
|
+
letter-spacing: -0.01em;
|
|
145
|
+
color: var(--polyx-fg);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
.polyx-signin__subheading {
|
|
149
|
+
margin: 0;
|
|
150
|
+
font-size: 0.875rem;
|
|
151
|
+
color: var(--polyx-muted-fg);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/* --- Form ---------------------------------------------------------------- */
|
|
155
|
+
|
|
156
|
+
.polyx-signin__form {
|
|
157
|
+
display: flex;
|
|
158
|
+
flex-direction: column;
|
|
159
|
+
gap: 1.125rem;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
.polyx-signin__field {
|
|
163
|
+
display: flex;
|
|
164
|
+
flex-direction: column;
|
|
165
|
+
gap: 0.4375rem;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
.polyx-signin__label {
|
|
169
|
+
font-size: 0.875rem;
|
|
170
|
+
font-weight: 500;
|
|
171
|
+
color: var(--polyx-fg);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
.polyx-signin__input {
|
|
175
|
+
width: 100%;
|
|
176
|
+
height: 2.5rem;
|
|
177
|
+
padding: 0 0.75rem;
|
|
178
|
+
font: inherit;
|
|
179
|
+
font-size: 0.875rem;
|
|
180
|
+
color: var(--polyx-fg);
|
|
181
|
+
background: var(--polyx-input-bg);
|
|
182
|
+
border: 1px solid var(--polyx-border);
|
|
183
|
+
border-radius: var(--polyx-radius-sm);
|
|
184
|
+
outline: none;
|
|
185
|
+
transition: border-color 0.15s ease, box-shadow 0.15s ease;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
.polyx-signin__input::placeholder {
|
|
189
|
+
color: var(--polyx-muted-fg);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
.polyx-signin__input:focus-visible {
|
|
193
|
+
border-color: var(--polyx-brand);
|
|
194
|
+
box-shadow: 0 0 0 3px var(--polyx-ring);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
.polyx-signin__input:disabled {
|
|
198
|
+
opacity: 0.6;
|
|
199
|
+
cursor: not-allowed;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/* --- Buttons ------------------------------------------------------------- */
|
|
203
|
+
|
|
204
|
+
.polyx-signin__submit,
|
|
205
|
+
.polyx-signin__tenant {
|
|
206
|
+
display: inline-flex;
|
|
207
|
+
align-items: center;
|
|
208
|
+
justify-content: center;
|
|
209
|
+
width: 100%;
|
|
210
|
+
min-height: 2.5rem;
|
|
211
|
+
padding: 0 1rem;
|
|
212
|
+
font: inherit;
|
|
213
|
+
font-size: 0.875rem;
|
|
214
|
+
font-weight: 500;
|
|
215
|
+
color: var(--polyx-brand-fg);
|
|
216
|
+
background: var(--polyx-brand);
|
|
217
|
+
border: 1px solid transparent;
|
|
218
|
+
border-radius: var(--polyx-radius-sm);
|
|
219
|
+
cursor: pointer;
|
|
220
|
+
transition: background-color 0.15s ease;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
.polyx-signin__submit:hover:not(:disabled),
|
|
224
|
+
.polyx-signin__tenant:hover:not(:disabled) {
|
|
225
|
+
background: var(--polyx-brand-hover);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
.polyx-signin__submit:focus-visible,
|
|
229
|
+
.polyx-signin__tenant:focus-visible {
|
|
230
|
+
outline: none;
|
|
231
|
+
box-shadow: 0 0 0 3px var(--polyx-ring);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
.polyx-signin__submit:disabled,
|
|
235
|
+
.polyx-signin__tenant:disabled {
|
|
236
|
+
opacity: 0.6;
|
|
237
|
+
cursor: not-allowed;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/* --- Error --------------------------------------------------------------- */
|
|
241
|
+
|
|
242
|
+
.polyx-signin__error {
|
|
243
|
+
margin: 0;
|
|
244
|
+
padding: 0.625rem 0.75rem;
|
|
245
|
+
font-size: 0.8125rem;
|
|
246
|
+
color: var(--polyx-danger);
|
|
247
|
+
background: var(--polyx-danger-bg);
|
|
248
|
+
border: 1px solid color-mix(in srgb, var(--polyx-danger) 30%, transparent);
|
|
249
|
+
border-radius: var(--polyx-radius-sm);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/* --- Workspace picker ---------------------------------------------------- */
|
|
253
|
+
|
|
254
|
+
.polyx-signin__tenants {
|
|
255
|
+
display: flex;
|
|
256
|
+
flex-direction: column;
|
|
257
|
+
gap: 0.625rem;
|
|
258
|
+
margin: 0;
|
|
259
|
+
padding: 0;
|
|
260
|
+
list-style: none;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/* The picker's buttons read as choices, not as the primary CTA. */
|
|
264
|
+
.polyx-signin__tenant {
|
|
265
|
+
justify-content: flex-start;
|
|
266
|
+
color: var(--polyx-fg);
|
|
267
|
+
background: var(--polyx-input-bg);
|
|
268
|
+
border-color: var(--polyx-border);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
.polyx-signin__tenant:hover:not(:disabled) {
|
|
272
|
+
background: var(--polyx-input-bg);
|
|
273
|
+
border-color: var(--polyx-brand);
|
|
274
|
+
}
|
package/package.json
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@poly-x/next",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
3
|
+
"version": "0.1.0-alpha.3",
|
|
4
4
|
"description": "PolyX SDK for Next.js App Router - components plus server helpers",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
7
|
-
"sideEffects":
|
|
7
|
+
"sideEffects": [
|
|
8
|
+
"**/*.css"
|
|
9
|
+
],
|
|
8
10
|
"files": [
|
|
9
11
|
"dist"
|
|
10
12
|
],
|
|
@@ -38,14 +40,15 @@
|
|
|
38
40
|
"types": "./dist/proxy.d.cts",
|
|
39
41
|
"default": "./dist/proxy.cjs"
|
|
40
42
|
}
|
|
41
|
-
}
|
|
43
|
+
},
|
|
44
|
+
"./styles.css": "./dist/styles.css"
|
|
42
45
|
},
|
|
43
46
|
"main": "./dist/index.cjs",
|
|
44
47
|
"module": "./dist/index.mjs",
|
|
45
48
|
"types": "./dist/index.d.cts",
|
|
46
49
|
"dependencies": {
|
|
47
|
-
"@poly-x/core": "0.1.0-alpha.
|
|
48
|
-
"@poly-x/react": "0.1.0-alpha.
|
|
50
|
+
"@poly-x/core": "0.1.0-alpha.3",
|
|
51
|
+
"@poly-x/react": "0.1.0-alpha.3"
|
|
49
52
|
},
|
|
50
53
|
"peerDependencies": {
|
|
51
54
|
"next": ">=14",
|
|
@@ -68,7 +71,7 @@
|
|
|
68
71
|
"react-dom": "^19.2.7"
|
|
69
72
|
},
|
|
70
73
|
"scripts": {
|
|
71
|
-
"build": "tsdown",
|
|
74
|
+
"build": "tsdown && node scripts/copy-styles.mjs",
|
|
72
75
|
"test": "vitest run",
|
|
73
76
|
"lint": "eslint src"
|
|
74
77
|
}
|