unshared-clientjs-sdk 2.0.0-rc.5 → 2.0.0-rc.6

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.
@@ -1,2 +1,4 @@
1
1
  export { UnsharedLabsClient } from './client';
2
+ export { createUnsharedMiddleware, assertTrustProxy } from './middleware';
3
+ export type { MiddlewareOptions } from './middleware';
2
4
  export type { UnsharedLabsClientConfig, ApiResult, UnsharedLabsError, SubmitFingerprintOptions, SubmitFingerprintResult, ProcessUserEventParams, ProcessUserEventResult, CheckUserResult, TriggerEmailVerificationResult, VerifyResult, } from './client';
@@ -1 +1 @@
1
- export{UnsharedLabsClient}from"./client";
1
+ export{UnsharedLabsClient}from"./client";export{createUnsharedMiddleware,assertTrustProxy}from"./middleware";
@@ -1,4 +1,4 @@
1
- import type { Request, Response, NextFunction } from 'express';
1
+ import type { Request, Response, NextFunction, Application } from 'express';
2
2
  import type { UnsharedLabsClient } from './client';
3
3
  export interface MiddlewareOptions {
4
4
  /** Override userId extractor. Falls back to req.body.user_id. */
@@ -25,6 +25,21 @@ export interface MiddlewareOptions {
25
25
  */
26
26
  corsOrigins?: string | string[];
27
27
  }
28
+ /**
29
+ * Asserts that Express `trust proxy` is configured on the app.
30
+ * Call this once during application startup, before mounting any middleware.
31
+ *
32
+ * Throws synchronously if the setting is missing, killing the process before
33
+ * any requests are served.
34
+ *
35
+ * @example
36
+ * ```typescript
37
+ * assertTrustProxy(app); // throws at startup if not set
38
+ * app.use(express.json());
39
+ * app.use(createUnsharedMiddleware(client, options));
40
+ * ```
41
+ */
42
+ export declare function assertTrustProxy(app: Application): void;
28
43
  /**
29
44
  * Creates an Express middleware that proxies browser fingerprint events to
30
45
  * Unshared Labs. Mount this to handle the browser fingerprint route contract (§4 of spec).
@@ -1 +1 @@
1
- export function createUnsharedMiddleware(e,r){const{userIdExtractor:s,eventTypeExtractor:t,sessionIdExtractor:o,ipAddressExtractor:i,defaultEventType:n="browser_event",routePrefix:c="/unshared",corsOrigins:d}=r??{},a=`${c}/submit-fingerprint-event`,l=d?Array.isArray(d)?d:[d]:null;let u=!1;return async(r,c,d)=>{if(!u&&(u=!0,r.app&&!r.app.get("trust proxy")))throw new Error('[unshared-labs] Express "trust proxy" is not set. Add `app.set("trust proxy", 1)` before mounting this middleware, otherwise req.ip will reflect the proxy\'s IP instead of the real client IP.');if(l&&r.path===a){const e=r.headers.origin??"",s=l.includes("*");if((s||l.includes(e))&&(c.setHeader("Access-Control-Allow-Origin",s?"*":e),c.setHeader("Access-Control-Allow-Methods","POST, OPTIONS"),c.setHeader("Access-Control-Allow-Headers","Content-Type, X-Idempotency-Key, X-Session-Id")),"OPTIONS"===r.method)return void c.status(204).end()}if("POST"===r.method&&r.path===a)try{const d=r.body??{};if(!d.hash||!d.stable_hash||!d.collected_at)return void c.status(400).json({success:!1,error:{code:"VALIDATION_ERROR",message:"Missing required fingerprint fields: hash, stable_hash, collected_at"}});const a={full_hash:d.hash,fingerprint_id:d.stable_hash,timestamp:d.collected_at,isIncognito:d.is_incognito??!1,components:d.components??{},version:d.version??"unknown"};let l,u,p,h;try{l=(s?s(r):void 0)??d.user_id}catch{l=d.user_id}r.body&&"object"==typeof r.body&&"user_id"in r.body&&delete r.body.user_id;try{u=(t?t(r):void 0)??d.event_type??n}catch{u=d.event_type??n}try{p=(o?o(r):void 0)??r.headers["x-session-id"]?.toString()??d.session_id}catch{p=r.headers["x-session-id"]?.toString()??d.session_id}try{h=(i?i(r):void 0)??r.ip}catch{h=r.ip}const f=await e.submitFingerprintEvent(a,{userId:l,sessionHash:p,eventType:u,ipAddress:h});if(!f.success)return void c.status(200).json({success:!1,error:{code:"UPSTREAM_ERROR",message:f.error?.message??"Upstream request failed"}});c.status(202).json({success:!0,data:f.data})}catch(e){c.status(200).json({success:!1,error:{code:"MIDDLEWARE_ERROR",message:e instanceof Error?e.message:"Middleware error"}})}else d()}}
1
+ export function assertTrustProxy(e){if(!e.get("trust proxy"))throw new Error('[unshared-labs] Express "trust proxy" is not set. Add `app.set("trust proxy", 1)` before calling assertTrustProxy, otherwise req.ip will reflect the proxy\'s IP instead of the real client IP.')}export function createUnsharedMiddleware(e,r){const{userIdExtractor:t,eventTypeExtractor:s,sessionIdExtractor:o,ipAddressExtractor:i,defaultEventType:n="browser_event",routePrefix:c="/unshared",corsOrigins:a}=r??{},d=`${c}/submit-fingerprint-event`,l=a?Array.isArray(a)?a:[a]:null;let u=!1;return async(r,c,a)=>{if(!u&&(u=!0,r.app&&!r.app.get("trust proxy")))throw new Error('[unshared-labs] Express "trust proxy" is not set. Add `app.set("trust proxy", 1)` before mounting this middleware, otherwise req.ip will reflect the proxy\'s IP instead of the real client IP.');if(l&&r.path===d){const e=r.headers.origin??"",t=l.includes("*");if((t||l.includes(e))&&(c.setHeader("Access-Control-Allow-Origin",t?"*":e),c.setHeader("Access-Control-Allow-Methods","POST, OPTIONS"),c.setHeader("Access-Control-Allow-Headers","Content-Type, X-Idempotency-Key, X-Session-Id")),"OPTIONS"===r.method)return void c.status(204).end()}if("POST"===r.method&&r.path===d)try{const a=r.body??{};if(!a.hash||!a.stable_hash||!a.collected_at)return void c.status(400).json({success:!1,error:{code:"VALIDATION_ERROR",message:"Missing required fingerprint fields: hash, stable_hash, collected_at"}});const d={full_hash:a.hash,fingerprint_id:a.stable_hash,timestamp:a.collected_at,isIncognito:a.is_incognito??!1,components:a.components??{},version:a.version??"unknown"};let l,u,p,h;try{l=(t?t(r):void 0)??a.user_id}catch{l=a.user_id}r.body&&"object"==typeof r.body&&"user_id"in r.body&&delete r.body.user_id;try{u=(s?s(r):void 0)??a.event_type??n}catch{u=a.event_type??n}try{p=(o?o(r):void 0)??r.headers["x-session-id"]?.toString()??a.session_id}catch{p=r.headers["x-session-id"]?.toString()??a.session_id}try{h=(i?i(r):void 0)??r.ip}catch{h=r.ip}const f=await e.submitFingerprintEvent(d,{userId:l,sessionHash:p,eventType:u,ipAddress:h});if(!f.success)return void c.status(200).json({success:!1,error:{code:"UPSTREAM_ERROR",message:f.error?.message??"Upstream request failed"}});c.status(202).json({success:!0,data:f.data})}catch(e){c.status(200).json({success:!1,error:{code:"MIDDLEWARE_ERROR",message:e instanceof Error?e.message:"Middleware error"}})}else a()}}
package/dist/index.d.ts CHANGED
@@ -1,2 +1,4 @@
1
1
  export { UnsharedLabsClient } from './client';
2
+ export { createUnsharedMiddleware, assertTrustProxy } from './middleware';
3
+ export type { MiddlewareOptions } from './middleware';
2
4
  export type { UnsharedLabsClientConfig, ApiResult, UnsharedLabsError, SubmitFingerprintOptions, SubmitFingerprintResult, ProcessUserEventParams, ProcessUserEventResult, CheckUserResult, TriggerEmailVerificationResult, VerifyResult, } from './client';
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,"t",{value:!0}),exports.UnsharedLabsClient=void 0;var client_1=require("./client");Object.defineProperty(exports,"UnsharedLabsClient",{enumerable:!0,get:function(){return client_1.UnsharedLabsClient}});
1
+ "use strict";Object.defineProperty(exports,"t",{value:!0}),exports.assertTrustProxy=exports.createUnsharedMiddleware=exports.UnsharedLabsClient=void 0;var client_1=require("./client");Object.defineProperty(exports,"UnsharedLabsClient",{enumerable:!0,get:function(){return client_1.UnsharedLabsClient}});var middleware_1=require("./middleware");Object.defineProperty(exports,"createUnsharedMiddleware",{enumerable:!0,get:function(){return middleware_1.createUnsharedMiddleware}}),Object.defineProperty(exports,"assertTrustProxy",{enumerable:!0,get:function(){return middleware_1.assertTrustProxy}});
@@ -1,4 +1,4 @@
1
- import type { Request, Response, NextFunction } from 'express';
1
+ import type { Request, Response, NextFunction, Application } from 'express';
2
2
  import type { UnsharedLabsClient } from './client';
3
3
  export interface MiddlewareOptions {
4
4
  /** Override userId extractor. Falls back to req.body.user_id. */
@@ -25,6 +25,21 @@ export interface MiddlewareOptions {
25
25
  */
26
26
  corsOrigins?: string | string[];
27
27
  }
28
+ /**
29
+ * Asserts that Express `trust proxy` is configured on the app.
30
+ * Call this once during application startup, before mounting any middleware.
31
+ *
32
+ * Throws synchronously if the setting is missing, killing the process before
33
+ * any requests are served.
34
+ *
35
+ * @example
36
+ * ```typescript
37
+ * assertTrustProxy(app); // throws at startup if not set
38
+ * app.use(express.json());
39
+ * app.use(createUnsharedMiddleware(client, options));
40
+ * ```
41
+ */
42
+ export declare function assertTrustProxy(app: Application): void;
28
43
  /**
29
44
  * Creates an Express middleware that proxies browser fingerprint events to
30
45
  * Unshared Labs. Mount this to handle the browser fingerprint route contract (§4 of spec).
@@ -1 +1 @@
1
- "use strict";function createUnsharedMiddleware(e,r){const{userIdExtractor:s,eventTypeExtractor:t,sessionIdExtractor:o,ipAddressExtractor:i,defaultEventType:n="browser_event",routePrefix:c="/unshared",corsOrigins:d}=r??{},a=`${c}/submit-fingerprint-event`,l=d?Array.isArray(d)?d:[d]:null;let u=!1;return async(r,c,d)=>{if(!u&&(u=!0,r.app&&!r.app.get("trust proxy")))throw new Error('[unshared-labs] Express "trust proxy" is not set. Add `app.set("trust proxy", 1)` before mounting this middleware, otherwise req.ip will reflect the proxy\'s IP instead of the real client IP.');if(l&&r.path===a){const e=r.headers.origin??"",s=l.includes("*");if((s||l.includes(e))&&(c.setHeader("Access-Control-Allow-Origin",s?"*":e),c.setHeader("Access-Control-Allow-Methods","POST, OPTIONS"),c.setHeader("Access-Control-Allow-Headers","Content-Type, X-Idempotency-Key, X-Session-Id")),"OPTIONS"===r.method)return void c.status(204).end()}if("POST"===r.method&&r.path===a)try{const d=r.body??{};if(!d.hash||!d.stable_hash||!d.collected_at)return void c.status(400).json({success:!1,error:{code:"VALIDATION_ERROR",message:"Missing required fingerprint fields: hash, stable_hash, collected_at"}});const a={full_hash:d.hash,fingerprint_id:d.stable_hash,timestamp:d.collected_at,isIncognito:d.is_incognito??!1,components:d.components??{},version:d.version??"unknown"};let l,u,p,h;try{l=(s?s(r):void 0)??d.user_id}catch{l=d.user_id}r.body&&"object"==typeof r.body&&"user_id"in r.body&&delete r.body.user_id;try{u=(t?t(r):void 0)??d.event_type??n}catch{u=d.event_type??n}try{p=(o?o(r):void 0)??r.headers["x-session-id"]?.toString()??d.session_id}catch{p=r.headers["x-session-id"]?.toString()??d.session_id}try{h=(i?i(r):void 0)??r.ip}catch{h=r.ip}const f=await e.submitFingerprintEvent(a,{userId:l,sessionHash:p,eventType:u,ipAddress:h});if(!f.success)return void c.status(200).json({success:!1,error:{code:"UPSTREAM_ERROR",message:f.error?.message??"Upstream request failed"}});c.status(202).json({success:!0,data:f.data})}catch(e){c.status(200).json({success:!1,error:{code:"MIDDLEWARE_ERROR",message:e instanceof Error?e.message:"Middleware error"}})}else d()}}Object.defineProperty(exports,"t",{value:!0}),exports.createUnsharedMiddleware=createUnsharedMiddleware;
1
+ "use strict";function assertTrustProxy(e){if(!e.get("trust proxy"))throw new Error('[unshared-labs] Express "trust proxy" is not set. Add `app.set("trust proxy", 1)` before calling assertTrustProxy, otherwise req.ip will reflect the proxy\'s IP instead of the real client IP.')}function createUnsharedMiddleware(e,r){const{userIdExtractor:s,eventTypeExtractor:t,sessionIdExtractor:o,ipAddressExtractor:i,defaultEventType:n="browser_event",routePrefix:c="/unshared",corsOrigins:a}=r??{},d=`${c}/submit-fingerprint-event`,l=a?Array.isArray(a)?a:[a]:null;let u=!1;return async(r,c,a)=>{if(!u&&(u=!0,r.app&&!r.app.get("trust proxy")))throw new Error('[unshared-labs] Express "trust proxy" is not set. Add `app.set("trust proxy", 1)` before mounting this middleware, otherwise req.ip will reflect the proxy\'s IP instead of the real client IP.');if(l&&r.path===d){const e=r.headers.origin??"",s=l.includes("*");if((s||l.includes(e))&&(c.setHeader("Access-Control-Allow-Origin",s?"*":e),c.setHeader("Access-Control-Allow-Methods","POST, OPTIONS"),c.setHeader("Access-Control-Allow-Headers","Content-Type, X-Idempotency-Key, X-Session-Id")),"OPTIONS"===r.method)return void c.status(204).end()}if("POST"===r.method&&r.path===d)try{const a=r.body??{};if(!a.hash||!a.stable_hash||!a.collected_at)return void c.status(400).json({success:!1,error:{code:"VALIDATION_ERROR",message:"Missing required fingerprint fields: hash, stable_hash, collected_at"}});const d={full_hash:a.hash,fingerprint_id:a.stable_hash,timestamp:a.collected_at,isIncognito:a.is_incognito??!1,components:a.components??{},version:a.version??"unknown"};let l,u,p,h;try{l=(s?s(r):void 0)??a.user_id}catch{l=a.user_id}r.body&&"object"==typeof r.body&&"user_id"in r.body&&delete r.body.user_id;try{u=(t?t(r):void 0)??a.event_type??n}catch{u=a.event_type??n}try{p=(o?o(r):void 0)??r.headers["x-session-id"]?.toString()??a.session_id}catch{p=r.headers["x-session-id"]?.toString()??a.session_id}try{h=(i?i(r):void 0)??r.ip}catch{h=r.ip}const f=await e.submitFingerprintEvent(d,{userId:l,sessionHash:p,eventType:u,ipAddress:h});if(!f.success)return void c.status(200).json({success:!1,error:{code:"UPSTREAM_ERROR",message:f.error?.message??"Upstream request failed"}});c.status(202).json({success:!0,data:f.data})}catch(e){c.status(200).json({success:!1,error:{code:"MIDDLEWARE_ERROR",message:e instanceof Error?e.message:"Middleware error"}})}else a()}}Object.defineProperty(exports,"t",{value:!0}),exports.assertTrustProxy=assertTrustProxy,exports.createUnsharedMiddleware=createUnsharedMiddleware;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "unshared-clientjs-sdk",
3
- "version": "2.0.0-rc.5",
3
+ "version": "2.0.0-rc.6",
4
4
  "description": "Server-side Node.js SDK for the Unshared Labs V2 API",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/esm/index.mjs",