@poly-x/next 0.1.0-alpha.17 → 0.1.0-alpha.19
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 +30 -1
- package/dist/server.d.cts +8 -0
- package/dist/server.d.mts +8 -0
- package/dist/server.mjs +30 -1
- package/package.json +3 -3
package/dist/server.cjs
CHANGED
|
@@ -131,6 +131,20 @@ function geoHeadersFromBody(geo) {
|
|
|
131
131
|
if (g.consent === "granted" || g.consent === "denied" || g.consent === "revoked") headers["x-polyx-geo-consent"] = g.consent;
|
|
132
132
|
return headers;
|
|
133
133
|
}
|
|
134
|
+
/**
|
|
135
|
+
* Build the device-context headers (`x-timezone` / `x-screen-resolution`) from the browser's login
|
|
136
|
+
* body (v6). These are not automatic request headers — the browser captures them client-side and
|
|
137
|
+
* posts them; the platform reads them for session device attribution. Only well-formed values are
|
|
138
|
+
* forwarded (a sane timezone string, a `WxH` resolution) so junk never reaches the platform.
|
|
139
|
+
*/
|
|
140
|
+
function deviceContextHeadersFromBody(deviceContext) {
|
|
141
|
+
const headers = {};
|
|
142
|
+
if (!deviceContext || typeof deviceContext !== "object") return headers;
|
|
143
|
+
const d = deviceContext;
|
|
144
|
+
if (typeof d.timezone === "string" && d.timezone.length > 0 && d.timezone.length <= 64) headers["x-timezone"] = d.timezone;
|
|
145
|
+
if (typeof d.screenResolution === "string" && /^\d{1,5}x\d{1,5}$/.test(d.screenResolution)) headers["x-screen-resolution"] = d.screenResolution;
|
|
146
|
+
return headers;
|
|
147
|
+
}
|
|
134
148
|
/** Read the current session — safe in Server Components (no cookie write). */
|
|
135
149
|
async function auth(overrides) {
|
|
136
150
|
const config = resolveNextConfig(overrides);
|
|
@@ -188,6 +202,7 @@ function createAuthHandlers(handlersConfig = {}) {
|
|
|
188
202
|
return Response.json({ status: "invalid_request" }, { status: 400 });
|
|
189
203
|
}
|
|
190
204
|
const geoHeaders = geoHeadersFromBody(payload.geo);
|
|
205
|
+
const deviceContextHeaders = deviceContextHeadersFromBody(payload.deviceContext);
|
|
191
206
|
const email = typeof payload.email === "string" ? payload.email : "";
|
|
192
207
|
const password = typeof payload.password === "string" ? payload.password : "";
|
|
193
208
|
if (!email || !password) return Response.json({ status: "invalid_request" }, { status: 400 });
|
|
@@ -211,7 +226,8 @@ function createAuthHandlers(handlersConfig = {}) {
|
|
|
211
226
|
case "authorized":
|
|
212
227
|
await newSession(adapt(await (0, next_headers.cookies)()), config, secure).establishFromCode(outcome.code, verifier, redirectUri, {
|
|
213
228
|
...collectForwardedDeviceHeaders(request),
|
|
214
|
-
...geoHeaders
|
|
229
|
+
...geoHeaders,
|
|
230
|
+
...deviceContextHeaders
|
|
215
231
|
});
|
|
216
232
|
return Response.json({
|
|
217
233
|
status: "success",
|
|
@@ -341,6 +357,19 @@ function createAuthHandlers(handlersConfig = {}) {
|
|
|
341
357
|
},
|
|
342
358
|
async session() {
|
|
343
359
|
return Response.json(await auth(handlersConfig));
|
|
360
|
+
},
|
|
361
|
+
async subscriptionCredential() {
|
|
362
|
+
const config = resolveNextConfig(handlersConfig);
|
|
363
|
+
const current = await new require_server_session.ServerSession({
|
|
364
|
+
authClient: buildServerAuthClient(config),
|
|
365
|
+
secret: config.secret,
|
|
366
|
+
cookies: await requestCookies()
|
|
367
|
+
}).read();
|
|
368
|
+
if (!current) return Response.json({ status: "signed_out" }, { status: 401 });
|
|
369
|
+
return Response.json({
|
|
370
|
+
token: current.tokens.accessToken,
|
|
371
|
+
organizationId: current.session.claims.organizationId
|
|
372
|
+
});
|
|
344
373
|
}
|
|
345
374
|
};
|
|
346
375
|
}
|
package/dist/server.d.cts
CHANGED
|
@@ -127,6 +127,14 @@ interface AuthHandlers {
|
|
|
127
127
|
* server truth instead. Never carries a token.
|
|
128
128
|
*/
|
|
129
129
|
session(request: Request): Promise<Response>;
|
|
130
|
+
/**
|
|
131
|
+
* v2 (ADR-0008): a session-derived credential for the real-time `authz:changed` channel. Returns
|
|
132
|
+
* `{ token, organizationId }` read from the sealed session server-side — the token is for the
|
|
133
|
+
* socket handshake only (in-memory; never persisted), per the pragmatic custody decision. A
|
|
134
|
+
* signed-out caller gets `401` with no token. This is the one place a token leaves the BFF, and
|
|
135
|
+
* only to open the live-authz subscription.
|
|
136
|
+
*/
|
|
137
|
+
subscriptionCredential(request: Request): Promise<Response>;
|
|
130
138
|
}
|
|
131
139
|
/** The JSON the `forgotPassword` handler returns — always uniform (no enumeration). */
|
|
132
140
|
type ForgotPasswordResult = {
|
package/dist/server.d.mts
CHANGED
|
@@ -127,6 +127,14 @@ interface AuthHandlers {
|
|
|
127
127
|
* server truth instead. Never carries a token.
|
|
128
128
|
*/
|
|
129
129
|
session(request: Request): Promise<Response>;
|
|
130
|
+
/**
|
|
131
|
+
* v2 (ADR-0008): a session-derived credential for the real-time `authz:changed` channel. Returns
|
|
132
|
+
* `{ token, organizationId }` read from the sealed session server-side — the token is for the
|
|
133
|
+
* socket handshake only (in-memory; never persisted), per the pragmatic custody decision. A
|
|
134
|
+
* signed-out caller gets `401` with no token. This is the one place a token leaves the BFF, and
|
|
135
|
+
* only to open the live-authz subscription.
|
|
136
|
+
*/
|
|
137
|
+
subscriptionCredential(request: Request): Promise<Response>;
|
|
130
138
|
}
|
|
131
139
|
/** The JSON the `forgotPassword` handler returns — always uniform (no enumeration). */
|
|
132
140
|
type ForgotPasswordResult = {
|
package/dist/server.mjs
CHANGED
|
@@ -130,6 +130,20 @@ function geoHeadersFromBody(geo) {
|
|
|
130
130
|
if (g.consent === "granted" || g.consent === "denied" || g.consent === "revoked") headers["x-polyx-geo-consent"] = g.consent;
|
|
131
131
|
return headers;
|
|
132
132
|
}
|
|
133
|
+
/**
|
|
134
|
+
* Build the device-context headers (`x-timezone` / `x-screen-resolution`) from the browser's login
|
|
135
|
+
* body (v6). These are not automatic request headers — the browser captures them client-side and
|
|
136
|
+
* posts them; the platform reads them for session device attribution. Only well-formed values are
|
|
137
|
+
* forwarded (a sane timezone string, a `WxH` resolution) so junk never reaches the platform.
|
|
138
|
+
*/
|
|
139
|
+
function deviceContextHeadersFromBody(deviceContext) {
|
|
140
|
+
const headers = {};
|
|
141
|
+
if (!deviceContext || typeof deviceContext !== "object") return headers;
|
|
142
|
+
const d = deviceContext;
|
|
143
|
+
if (typeof d.timezone === "string" && d.timezone.length > 0 && d.timezone.length <= 64) headers["x-timezone"] = d.timezone;
|
|
144
|
+
if (typeof d.screenResolution === "string" && /^\d{1,5}x\d{1,5}$/.test(d.screenResolution)) headers["x-screen-resolution"] = d.screenResolution;
|
|
145
|
+
return headers;
|
|
146
|
+
}
|
|
133
147
|
/** Read the current session — safe in Server Components (no cookie write). */
|
|
134
148
|
async function auth(overrides) {
|
|
135
149
|
const config = resolveNextConfig(overrides);
|
|
@@ -187,6 +201,7 @@ function createAuthHandlers(handlersConfig = {}) {
|
|
|
187
201
|
return Response.json({ status: "invalid_request" }, { status: 400 });
|
|
188
202
|
}
|
|
189
203
|
const geoHeaders = geoHeadersFromBody(payload.geo);
|
|
204
|
+
const deviceContextHeaders = deviceContextHeadersFromBody(payload.deviceContext);
|
|
190
205
|
const email = typeof payload.email === "string" ? payload.email : "";
|
|
191
206
|
const password = typeof payload.password === "string" ? payload.password : "";
|
|
192
207
|
if (!email || !password) return Response.json({ status: "invalid_request" }, { status: 400 });
|
|
@@ -210,7 +225,8 @@ function createAuthHandlers(handlersConfig = {}) {
|
|
|
210
225
|
case "authorized":
|
|
211
226
|
await newSession(adapt(await cookies()), config, secure).establishFromCode(outcome.code, verifier, redirectUri, {
|
|
212
227
|
...collectForwardedDeviceHeaders(request),
|
|
213
|
-
...geoHeaders
|
|
228
|
+
...geoHeaders,
|
|
229
|
+
...deviceContextHeaders
|
|
214
230
|
});
|
|
215
231
|
return Response.json({
|
|
216
232
|
status: "success",
|
|
@@ -340,6 +356,19 @@ function createAuthHandlers(handlersConfig = {}) {
|
|
|
340
356
|
},
|
|
341
357
|
async session() {
|
|
342
358
|
return Response.json(await auth(handlersConfig));
|
|
359
|
+
},
|
|
360
|
+
async subscriptionCredential() {
|
|
361
|
+
const config = resolveNextConfig(handlersConfig);
|
|
362
|
+
const current = await new ServerSession({
|
|
363
|
+
authClient: buildServerAuthClient(config),
|
|
364
|
+
secret: config.secret,
|
|
365
|
+
cookies: await requestCookies()
|
|
366
|
+
}).read();
|
|
367
|
+
if (!current) return Response.json({ status: "signed_out" }, { status: 401 });
|
|
368
|
+
return Response.json({
|
|
369
|
+
token: current.tokens.accessToken,
|
|
370
|
+
organizationId: current.session.claims.organizationId
|
|
371
|
+
});
|
|
343
372
|
}
|
|
344
373
|
};
|
|
345
374
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@poly-x/next",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
3
|
+
"version": "0.1.0-alpha.19",
|
|
4
4
|
"description": "PolyX SDK for Next.js App Router - components plus server helpers",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -47,8 +47,8 @@
|
|
|
47
47
|
"module": "./dist/index.mjs",
|
|
48
48
|
"types": "./dist/index.d.cts",
|
|
49
49
|
"dependencies": {
|
|
50
|
-
"@poly-x/core": "0.1.0-alpha.
|
|
51
|
-
"@poly-x/react": "0.1.0-alpha.
|
|
50
|
+
"@poly-x/core": "0.1.0-alpha.19",
|
|
51
|
+
"@poly-x/react": "0.1.0-alpha.19"
|
|
52
52
|
},
|
|
53
53
|
"peerDependencies": {
|
|
54
54
|
"next": ">=14",
|