@drawbridge/drawbridge-utils 0.0.50 → 0.0.52

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/env.cjs ADDED
@@ -0,0 +1,41 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
+ var __getOwnPropNames = Object.getOwnPropertyNames;
4
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
5
+ var __export = (target, all) => {
6
+ for (var name in all)
7
+ __defProp(target, name, { get: all[name], enumerable: true });
8
+ };
9
+ var __copyProps = (to, from, except, desc) => {
10
+ if (from && typeof from === "object" || typeof from === "function") {
11
+ for (let key of __getOwnPropNames(from))
12
+ if (!__hasOwnProp.call(to, key) && key !== except)
13
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
14
+ }
15
+ return to;
16
+ };
17
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
18
+
19
+ // lib/env.js
20
+ var env_exports = {};
21
+ __export(env_exports, {
22
+ assertEnv: () => assertEnv
23
+ });
24
+ module.exports = __toCommonJS(env_exports);
25
+ var assertEnv = (required = [], { env = process.env, exit = true } = {}) => {
26
+ const missing = (required || []).filter((key) => {
27
+ const value = env[key];
28
+ return value === void 0 || value === null || String(value).trim() === "";
29
+ });
30
+ if (missing.length === 0) return;
31
+ const message = "Missing required environment variable" + (missing.length > 1 ? "s" : "") + ": " + missing.join(", ");
32
+ console.error("[boot] " + message);
33
+ if (exit) {
34
+ process.exit(1);
35
+ }
36
+ throw new Error(message);
37
+ };
38
+ // Annotate the CommonJS export names for ESM import in node:
39
+ 0 && (module.exports = {
40
+ assertEnv
41
+ });
package/dist/env.d.cts ADDED
@@ -0,0 +1,41 @@
1
+ // Boot-time required-environment-variable validation. A service calls
2
+ // assertEnv(required) as the first thing in index.js so a missing must-have
3
+ // config fails loudly at startup instead of silently degrading at first use
4
+ // (e.g. a missing OAUTH_TOKEN_HMAC_KEY surfacing only as failed socket auth).
5
+ //
6
+ // const { assertEnv } = require( '@drawbridge/drawbridge-utils/env' );
7
+ // assertEnv([ 'MONGODB_URI', 'REDIS_URL', 'OAUTH_TOKEN_HMAC_KEY' ]);
8
+ //
9
+ // Reports EVERY missing var in one message (not just the first) and exits the
10
+ // process with code 1. A var counts as missing when unset, null, or an
11
+ // empty/whitespace-only string. Pass { exit : false } to throw instead of
12
+ // exiting (used in tests); pass { env } to validate against a supplied map.
13
+ const assertEnv = ( required = [], { env = process.env, exit = true } = {} ) => {
14
+
15
+ const missing = ( required || [] ).filter( ( key ) => {
16
+
17
+ const value = env[ key ];
18
+
19
+ return value === undefined || value === null || String( value ).trim() === '';
20
+
21
+ });
22
+
23
+ if( missing.length === 0 ) return;
24
+
25
+ const message = 'Missing required environment variable'
26
+ + ( missing.length > 1 ? 's' : '' )
27
+ + ': ' + missing.join( ', ' );
28
+
29
+ console.error( '[boot] ' + message );
30
+
31
+ if( exit ){
32
+
33
+ process.exit( 1 );
34
+
35
+ }
36
+
37
+ throw new Error( message );
38
+
39
+ };
40
+
41
+ export { assertEnv };
package/dist/env.d.ts ADDED
@@ -0,0 +1,41 @@
1
+ // Boot-time required-environment-variable validation. A service calls
2
+ // assertEnv(required) as the first thing in index.js so a missing must-have
3
+ // config fails loudly at startup instead of silently degrading at first use
4
+ // (e.g. a missing OAUTH_TOKEN_HMAC_KEY surfacing only as failed socket auth).
5
+ //
6
+ // const { assertEnv } = require( '@drawbridge/drawbridge-utils/env' );
7
+ // assertEnv([ 'MONGODB_URI', 'REDIS_URL', 'OAUTH_TOKEN_HMAC_KEY' ]);
8
+ //
9
+ // Reports EVERY missing var in one message (not just the first) and exits the
10
+ // process with code 1. A var counts as missing when unset, null, or an
11
+ // empty/whitespace-only string. Pass { exit : false } to throw instead of
12
+ // exiting (used in tests); pass { env } to validate against a supplied map.
13
+ const assertEnv = ( required = [], { env = process.env, exit = true } = {} ) => {
14
+
15
+ const missing = ( required || [] ).filter( ( key ) => {
16
+
17
+ const value = env[ key ];
18
+
19
+ return value === undefined || value === null || String( value ).trim() === '';
20
+
21
+ });
22
+
23
+ if( missing.length === 0 ) return;
24
+
25
+ const message = 'Missing required environment variable'
26
+ + ( missing.length > 1 ? 's' : '' )
27
+ + ': ' + missing.join( ', ' );
28
+
29
+ console.error( '[boot] ' + message );
30
+
31
+ if( exit ){
32
+
33
+ process.exit( 1 );
34
+
35
+ }
36
+
37
+ throw new Error( message );
38
+
39
+ };
40
+
41
+ export { assertEnv };
package/dist/env.js ADDED
@@ -0,0 +1,17 @@
1
+ // lib/env.js
2
+ var assertEnv = (required = [], { env = process.env, exit = true } = {}) => {
3
+ const missing = (required || []).filter((key) => {
4
+ const value = env[key];
5
+ return value === void 0 || value === null || String(value).trim() === "";
6
+ });
7
+ if (missing.length === 0) return;
8
+ const message = "Missing required environment variable" + (missing.length > 1 ? "s" : "") + ": " + missing.join(", ");
9
+ console.error("[boot] " + message);
10
+ if (exit) {
11
+ process.exit(1);
12
+ }
13
+ throw new Error(message);
14
+ };
15
+ export {
16
+ assertEnv
17
+ };
@@ -47,6 +47,7 @@ __export(oauth_exports, {
47
47
  scopeLabels: () => scopeLabels,
48
48
  scopeOptions: () => scopeOptions,
49
49
  scopes: () => scopes,
50
+ tokenFromHandshake: () => tokenFromHandshake,
50
51
  tokenTypes: () => tokenTypes,
51
52
  validate: () => validate
52
53
  });
@@ -84,9 +85,30 @@ var clients = {
84
85
  dashboard: "drawbridge-dashboard",
85
86
  share: "drawbridge-share"
86
87
  };
88
+ var tokenFromHandshake = (socket) => {
89
+ var _a, _b, _c;
90
+ if ((_b = (_a = socket == null ? void 0 : socket.handshake) == null ? void 0 : _a.auth) == null ? void 0 : _b.token) {
91
+ return socket.handshake.auth.token;
92
+ }
93
+ const headers = ((_c = socket == null ? void 0 : socket.handshake) == null ? void 0 : _c.headers) || {};
94
+ const subprotocols = (headers["sec-websocket-protocol"] || "").split(",").map((value) => value.trim());
95
+ for (const subprotocol of subprotocols) {
96
+ if (subprotocol.startsWith("bearer.")) {
97
+ return subprotocol.slice("bearer.".length) || null;
98
+ }
99
+ }
100
+ if (!headers.cookie) return null;
101
+ const parsed = headers.cookie.split(";").reduce((accumulator, pair) => {
102
+ const index = pair.indexOf("=");
103
+ if (index < 0) return accumulator;
104
+ accumulator[pair.slice(0, index).trim()] = decodeURIComponent(pair.slice(index + 1).trim());
105
+ return accumulator;
106
+ }, {});
107
+ return parsed[cookies.session] || null;
108
+ };
87
109
  var lifetimes = {
88
- access: 60 * 60,
89
- // 1 hour
110
+ access: 60 * 60 * 8,
111
+ // 8 hours
90
112
  authorizationCode: 10 * 60,
91
113
  // 10 minutes
92
114
  code: 15 * 60,
@@ -239,7 +261,7 @@ var createOAuthClient = ({
239
261
  const body = await response.json();
240
262
  cached = {
241
263
  accessToken: body.access_token,
242
- expiresAt: Math.floor(Date.now() / 1e3) + Number(body.expires_in || 3600),
264
+ expiresAt: Math.floor(Date.now() / 1e3) + Number(body.expires_in || lifetimes.access),
243
265
  scope: body.scope
244
266
  };
245
267
  return cached.accessToken;
@@ -283,6 +305,7 @@ var createOAuthClient = ({
283
305
  scopeLabels,
284
306
  scopeOptions,
285
307
  scopes,
308
+ tokenFromHandshake,
286
309
  tokenTypes,
287
310
  validate
288
311
  });
@@ -32,10 +32,59 @@ const clients = {
32
32
  share : 'drawbridge-share'
33
33
  };
34
34
 
35
+ // Resolve the raw OAuth access token from a socket.io handshake. Precedence:
36
+ // 1. handshake.auth.token — the browser client connects with
37
+ // io( uri, { auth : { token } } ); socket.io exposes it here.
38
+ // 2. Sec-WebSocket-Protocol: bearer.<token> subprotocol.
39
+ // 3. the drawbridge.session cookie on the upgrade request.
40
+ // This is the OAuth handshake token-source contract; drawbridge-sync's WS auth
41
+ // reads it so any future socket-authenticating service resolves it identically.
42
+ const tokenFromHandshake = ( socket ) => {
43
+
44
+ if( socket?.handshake?.auth?.token ){
45
+
46
+ return socket.handshake.auth.token;
47
+
48
+ }
49
+
50
+ const headers = socket?.handshake?.headers || {};
51
+
52
+ const subprotocols = ( headers[ 'sec-websocket-protocol' ] || '' )
53
+ .split( ',' )
54
+ .map( ( value ) => value.trim() );
55
+
56
+ for( const subprotocol of subprotocols ){
57
+
58
+ if( subprotocol.startsWith( 'bearer.' ) ){
59
+
60
+ return subprotocol.slice( 'bearer.'.length ) || null;
61
+
62
+ }
63
+
64
+ }
65
+
66
+ if( ! headers.cookie ) return null;
67
+
68
+ const parsed = headers.cookie.split( ';' ).reduce( ( accumulator, pair ) => {
69
+
70
+ const index = pair.indexOf( '=' );
71
+
72
+ if( index < 0 ) return accumulator;
73
+
74
+ accumulator[ pair.slice( 0, index ).trim() ] = decodeURIComponent( pair.slice( index + 1 ).trim() );
75
+
76
+ return accumulator;
77
+
78
+ }, {} );
79
+
80
+ return parsed[ cookies.session ] || null;
81
+
82
+ };
83
+
35
84
  // Token / authorization-code / OTC lifetimes in seconds (the OAuth spec's
36
85
  // unit for `expires_in`). Multiply by 1000 when feeding to JS Date math.
37
86
  const lifetimes = {
38
- access : 60 * 60, // 1 hour
87
+ access : 60 * 60 * 8, // 8 hours
39
88
  authorizationCode : 10 * 60, // 10 minutes
40
89
  code : 15 * 60, // 15 minutes (email OTC)
41
90
  refresh : 30 * 24 * 60 * 60 // 30 days
@@ -304,7 +353,7 @@ const createOAuthClient = ({
304
353
 
305
354
  cached = {
306
355
  accessToken : body.access_token,
307
- expiresAt : Math.floor( Date.now() / 1000 ) + Number( body.expires_in || 3600 ),
356
+ expiresAt : Math.floor( Date.now() / 1000 ) + Number( body.expires_in || lifetimes.access ),
308
357
  scope : body.scope
309
358
  };
310
359
 
@@ -346,4 +395,4 @@ const createOAuthClient = ({
346
395
 
347
396
  };
348
397
 
349
- export { clients, cookieOptions, cookies, createOAuthClient, developer, developerOptions, generateToken, hashToken, intersect, isDeveloperAllowed, lifetimes, menuEndpoint, otcContexts, parse, scopeLabels, scopeOptions, scopes, tokenTypes, validate };
398
+ export { clients, cookieOptions, cookies, createOAuthClient, developer, developerOptions, generateToken, hashToken, intersect, isDeveloperAllowed, lifetimes, menuEndpoint, otcContexts, parse, scopeLabels, scopeOptions, scopes, tokenFromHandshake, tokenTypes, validate };
@@ -32,10 +32,59 @@ const clients = {
32
32
  share : 'drawbridge-share'
33
33
  };
34
34
 
35
+ // Resolve the raw OAuth access token from a socket.io handshake. Precedence:
36
+ // 1. handshake.auth.token — the browser client connects with
37
+ // io( uri, { auth : { token } } ); socket.io exposes it here.
38
+ // 2. Sec-WebSocket-Protocol: bearer.<token> subprotocol.
39
+ // 3. the drawbridge.session cookie on the upgrade request.
40
+ // This is the OAuth handshake token-source contract; drawbridge-sync's WS auth
41
+ // reads it so any future socket-authenticating service resolves it identically.
42
+ const tokenFromHandshake = ( socket ) => {
43
+
44
+ if( socket?.handshake?.auth?.token ){
45
+
46
+ return socket.handshake.auth.token;
47
+
48
+ }
49
+
50
+ const headers = socket?.handshake?.headers || {};
51
+
52
+ const subprotocols = ( headers[ 'sec-websocket-protocol' ] || '' )
53
+ .split( ',' )
54
+ .map( ( value ) => value.trim() );
55
+
56
+ for( const subprotocol of subprotocols ){
57
+
58
+ if( subprotocol.startsWith( 'bearer.' ) ){
59
+
60
+ return subprotocol.slice( 'bearer.'.length ) || null;
61
+
62
+ }
63
+
64
+ }
65
+
66
+ if( ! headers.cookie ) return null;
67
+
68
+ const parsed = headers.cookie.split( ';' ).reduce( ( accumulator, pair ) => {
69
+
70
+ const index = pair.indexOf( '=' );
71
+
72
+ if( index < 0 ) return accumulator;
73
+
74
+ accumulator[ pair.slice( 0, index ).trim() ] = decodeURIComponent( pair.slice( index + 1 ).trim() );
75
+
76
+ return accumulator;
77
+
78
+ }, {} );
79
+
80
+ return parsed[ cookies.session ] || null;
81
+
82
+ };
83
+
35
84
  // Token / authorization-code / OTC lifetimes in seconds (the OAuth spec's
36
85
  // unit for `expires_in`). Multiply by 1000 when feeding to JS Date math.
37
86
  const lifetimes = {
38
- access : 60 * 60, // 1 hour
87
+ access : 60 * 60 * 8, // 8 hours
39
88
  authorizationCode : 10 * 60, // 10 minutes
40
89
  code : 15 * 60, // 15 minutes (email OTC)
41
90
  refresh : 30 * 24 * 60 * 60 // 30 days
@@ -304,7 +353,7 @@ const createOAuthClient = ({
304
353
 
305
354
  cached = {
306
355
  accessToken : body.access_token,
307
- expiresAt : Math.floor( Date.now() / 1000 ) + Number( body.expires_in || 3600 ),
356
+ expiresAt : Math.floor( Date.now() / 1000 ) + Number( body.expires_in || lifetimes.access ),
308
357
  scope : body.scope
309
358
  };
310
359
 
@@ -346,4 +395,4 @@ const createOAuthClient = ({
346
395
 
347
396
  };
348
397
 
349
- export { clients, cookieOptions, cookies, createOAuthClient, developer, developerOptions, generateToken, hashToken, intersect, isDeveloperAllowed, lifetimes, menuEndpoint, otcContexts, parse, scopeLabels, scopeOptions, scopes, tokenTypes, validate };
398
+ export { clients, cookieOptions, cookies, createOAuthClient, developer, developerOptions, generateToken, hashToken, intersect, isDeveloperAllowed, lifetimes, menuEndpoint, otcContexts, parse, scopeLabels, scopeOptions, scopes, tokenFromHandshake, tokenTypes, validate };
@@ -30,9 +30,30 @@ var clients = {
30
30
  dashboard: "drawbridge-dashboard",
31
31
  share: "drawbridge-share"
32
32
  };
33
+ var tokenFromHandshake = (socket) => {
34
+ var _a, _b, _c;
35
+ if ((_b = (_a = socket == null ? void 0 : socket.handshake) == null ? void 0 : _a.auth) == null ? void 0 : _b.token) {
36
+ return socket.handshake.auth.token;
37
+ }
38
+ const headers = ((_c = socket == null ? void 0 : socket.handshake) == null ? void 0 : _c.headers) || {};
39
+ const subprotocols = (headers["sec-websocket-protocol"] || "").split(",").map((value) => value.trim());
40
+ for (const subprotocol of subprotocols) {
41
+ if (subprotocol.startsWith("bearer.")) {
42
+ return subprotocol.slice("bearer.".length) || null;
43
+ }
44
+ }
45
+ if (!headers.cookie) return null;
46
+ const parsed = headers.cookie.split(";").reduce((accumulator, pair) => {
47
+ const index = pair.indexOf("=");
48
+ if (index < 0) return accumulator;
49
+ accumulator[pair.slice(0, index).trim()] = decodeURIComponent(pair.slice(index + 1).trim());
50
+ return accumulator;
51
+ }, {});
52
+ return parsed[cookies.session] || null;
53
+ };
33
54
  var lifetimes = {
34
- access: 60 * 60,
35
- // 1 hour
55
+ access: 60 * 60 * 8,
56
+ // 8 hours
36
57
  authorizationCode: 10 * 60,
37
58
  // 10 minutes
38
59
  code: 15 * 60,
@@ -185,7 +206,7 @@ var createOAuthClient = ({
185
206
  const body = await response.json();
186
207
  cached = {
187
208
  accessToken: body.access_token,
188
- expiresAt: Math.floor(Date.now() / 1e3) + Number(body.expires_in || 3600),
209
+ expiresAt: Math.floor(Date.now() / 1e3) + Number(body.expires_in || lifetimes.access),
189
210
  scope: body.scope
190
211
  };
191
212
  return cached.accessToken;
@@ -228,6 +249,7 @@ export {
228
249
  scopeLabels,
229
250
  scopeOptions,
230
251
  scopes,
252
+ tokenFromHandshake,
231
253
  tokenTypes,
232
254
  validate
233
255
  };
@@ -60,8 +60,8 @@ var compare = (a, b) => {
60
60
 
61
61
  // lib/oauth/index.js
62
62
  var lifetimes = {
63
- access: 60 * 60,
64
- // 1 hour
63
+ access: 60 * 60 * 8,
64
+ // 8 hours
65
65
  authorizationCode: 10 * 60,
66
66
  // 10 minutes
67
67
  code: 15 * 60,
@@ -25,8 +25,8 @@ var compare = (a, b) => {
25
25
 
26
26
  // lib/oauth/index.js
27
27
  var lifetimes = {
28
- access: 60 * 60,
29
- // 1 hour
28
+ access: 60 * 60 * 8,
29
+ // 8 hours
30
30
  authorizationCode: 10 * 60,
31
31
  // 10 minutes
32
32
  code: 15 * 60,
package/package.json CHANGED
@@ -39,6 +39,11 @@
39
39
  "import": "./dist/encrypt.js",
40
40
  "require": "./dist/encrypt.cjs"
41
41
  },
42
+ "./env": {
43
+ "types": "./dist/env.d.ts",
44
+ "import": "./dist/env.js",
45
+ "require": "./dist/env.cjs"
46
+ },
42
47
  "./axios": {
43
48
  "types": "./dist/axios.d.ts",
44
49
  "import": "./dist/axios.js",
@@ -130,5 +135,5 @@
130
135
  "build": "tsup && npm publish"
131
136
  },
132
137
  "types": "dist/index.d.ts",
133
- "version": "0.0.50"
138
+ "version": "0.0.52"
134
139
  }