@drawbridge/drawbridge-utils 0.0.58 → 0.0.60

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/ai.cjs CHANGED
@@ -302,18 +302,20 @@ var google = {
302
302
  },
303
303
  text: async ({
304
304
  config = {},
305
+ images = [],
305
306
  prompt = []
306
307
  }, {
307
308
  db,
308
309
  user
309
310
  }) => {
310
311
  const model = models.text;
312
+ const contents = images.length ? { parts: [...images.map((image) => ({ inlineData: { data: image.data, mimeType: image.mimeType } })), { text: prompt.join("\n") }] } : prompt.join("\n");
311
313
  const response = await googleCircuit(() => google_client.models.generateContent({
312
314
  config: {
313
315
  ...config,
314
316
  responseModalities: ["Text"]
315
317
  },
316
- contents: prompt.join("\n"),
318
+ contents,
317
319
  model
318
320
  }));
319
321
  const content = response == null ? void 0 : response.text;
package/dist/ai.d.cts CHANGED
@@ -265,6 +265,7 @@ const google = {
265
265
  text : async (
266
266
  {
267
267
  config = {},
268
+ images = [],
268
269
  prompt = []
269
270
  },
270
271
  {
@@ -275,12 +276,19 @@ const google = {
275
276
 
276
277
  const model = models.text;
277
278
 
279
+ // When images are supplied (e.g. a page screenshot), send a multimodal
280
+ // parts payload so the model can SEE them alongside the text prompt;
281
+ // otherwise keep the plain-string contents for text-only calls.
282
+ const contents = images.length
283
+ ? { parts : [ ...images.map( ( image ) => ({ inlineData : { data : image.data, mimeType : image.mimeType } }) ), { text : prompt.join( '\n' ) } ] }
284
+ : prompt.join( '\n' );
285
+
278
286
  const response = await googleCircuit( () => google_client.models.generateContent({
279
287
  config : {
280
288
  ...config,
281
289
  responseModalities : [ 'Text' ]
282
290
  },
283
- contents : prompt.join( '\n' ),
291
+ contents,
284
292
  model
285
293
  }) );
286
294
 
package/dist/ai.d.ts CHANGED
@@ -265,6 +265,7 @@ const google = {
265
265
  text : async (
266
266
  {
267
267
  config = {},
268
+ images = [],
268
269
  prompt = []
269
270
  },
270
271
  {
@@ -275,12 +276,19 @@ const google = {
275
276
 
276
277
  const model = models.text;
277
278
 
279
+ // When images are supplied (e.g. a page screenshot), send a multimodal
280
+ // parts payload so the model can SEE them alongside the text prompt;
281
+ // otherwise keep the plain-string contents for text-only calls.
282
+ const contents = images.length
283
+ ? { parts : [ ...images.map( ( image ) => ({ inlineData : { data : image.data, mimeType : image.mimeType } }) ), { text : prompt.join( '\n' ) } ] }
284
+ : prompt.join( '\n' );
285
+
278
286
  const response = await googleCircuit( () => google_client.models.generateContent({
279
287
  config : {
280
288
  ...config,
281
289
  responseModalities : [ 'Text' ]
282
290
  },
283
- contents : prompt.join( '\n' ),
291
+ contents,
284
292
  model
285
293
  }) );
286
294
 
package/dist/ai.js CHANGED
@@ -272,18 +272,20 @@ var google = {
272
272
  },
273
273
  text: async ({
274
274
  config = {},
275
+ images = [],
275
276
  prompt = []
276
277
  }, {
277
278
  db,
278
279
  user
279
280
  }) => {
280
281
  const model = models.text;
282
+ const contents = images.length ? { parts: [...images.map((image) => ({ inlineData: { data: image.data, mimeType: image.mimeType } })), { text: prompt.join("\n") }] } : prompt.join("\n");
281
283
  const response = await googleCircuit(() => google_client.models.generateContent({
282
284
  config: {
283
285
  ...config,
284
286
  responseModalities: ["Text"]
285
287
  },
286
- contents: prompt.join("\n"),
288
+ contents,
287
289
  model
288
290
  }));
289
291
  const content = response == null ? void 0 : response.text;
@@ -0,0 +1,133 @@
1
+ var __create = Object.create;
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __getProtoOf = Object.getPrototypeOf;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+ var __copyProps = (to, from, except, desc) => {
12
+ if (from && typeof from === "object" || typeof from === "function") {
13
+ for (let key of __getOwnPropNames(from))
14
+ if (!__hasOwnProp.call(to, key) && key !== except)
15
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
+ }
17
+ return to;
18
+ };
19
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
20
+ // If the importer is in node compatibility mode or this is not an ESM
21
+ // file that has been converted to a CommonJS file using a Babel-
22
+ // compatible transform (i.e. "__esModule" has not been set), then set
23
+ // "default" to the CommonJS "module.exports" for node compatibility.
24
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
25
+ mod
26
+ ));
27
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
28
+
29
+ // lib/sanitize.js
30
+ var sanitize_exports = {};
31
+ __export(sanitize_exports, {
32
+ sanitizeDomain: () => sanitizeDomain,
33
+ sanitizeEmail: () => sanitizeEmail,
34
+ sanitizeQueries: () => sanitizeQueries,
35
+ sanitizeString: () => sanitizeString,
36
+ sanitizeUrl: () => sanitizeUrl
37
+ });
38
+ module.exports = __toCommonJS(sanitize_exports);
39
+ var import_disposable_email_domains = __toESM(require("disposable-email-domains"), 1);
40
+ var SCOPE_KEYS = ["organization", "account", "user", "owner"];
41
+ var DANGEROUS_OPERATORS = ["$where", "$function", "$accumulator"];
42
+ var disposableBlacklist = new Set(import_disposable_email_domains.default.map((d) => d.toLowerCase()));
43
+ var stripDangerousOperators = (value) => {
44
+ if (Array.isArray(value)) {
45
+ return value.map(stripDangerousOperators);
46
+ }
47
+ ;
48
+ if (value && typeof value === "object") {
49
+ const result = {};
50
+ for (const [key, child] of Object.entries(value)) {
51
+ if (DANGEROUS_OPERATORS.includes(key)) continue;
52
+ result[key] = stripDangerousOperators(child);
53
+ }
54
+ ;
55
+ return result;
56
+ }
57
+ ;
58
+ return value;
59
+ };
60
+ var cleanQueryPart = (value) => {
61
+ if (!value || typeof value !== "object" || Array.isArray(value)) return value;
62
+ const cleaned = stripDangerousOperators(value);
63
+ for (const key of SCOPE_KEYS) {
64
+ delete cleaned[key];
65
+ }
66
+ ;
67
+ return cleaned;
68
+ };
69
+ var sanitizeString = (value) => {
70
+ if (value && value !== null) {
71
+ return value.trim();
72
+ } else {
73
+ return null;
74
+ }
75
+ };
76
+ var sanitizeDomain = (value, pattern) => {
77
+ if (!value) return value;
78
+ const cleaned = value.trim().toLowerCase().replace(/^https?:\/\//i, "").replace(/\/+$/, "");
79
+ if (pattern) {
80
+ const match = cleaned.match(pattern);
81
+ return match ? match[0] : cleaned;
82
+ }
83
+ return cleaned;
84
+ };
85
+ var sanitizeUrl = (url) => {
86
+ var _a, _b;
87
+ return (_b = (_a = url == null ? void 0 : url.replace(/^http:\/\//, "https://")) == null ? void 0 : _a.replace(/^https:\/\/www\./, "https://")) == null ? void 0 : _b.replace(/\/$/, "");
88
+ };
89
+ var sanitizeEmail = (raw) => {
90
+ if (typeof raw !== "string") return {
91
+ valid: false,
92
+ reason: "format"
93
+ };
94
+ const email = raw.trim().toLowerCase();
95
+ const match = email.match(/^[^\s@]+@([^\s@]+\.[^\s@]+)$/);
96
+ if (!match) return {
97
+ valid: false,
98
+ reason: "format"
99
+ };
100
+ if (disposableBlacklist.has(match[1])) return {
101
+ valid: false,
102
+ reason: "disposable"
103
+ };
104
+ return {
105
+ email,
106
+ valid: true
107
+ };
108
+ };
109
+ var sanitizeQueries = (req, res, next) => {
110
+ var _a, _b;
111
+ if (req.path.startsWith("/admin/")) {
112
+ next();
113
+ return;
114
+ }
115
+ ;
116
+ if ((_a = req.query) == null ? void 0 : _a.filters) {
117
+ req.query.filters = cleanQueryPart(req.query.filters);
118
+ }
119
+ ;
120
+ if ((_b = req.query) == null ? void 0 : _b.refine) {
121
+ req.query.refine = cleanQueryPart(req.query.refine);
122
+ }
123
+ ;
124
+ next();
125
+ };
126
+ // Annotate the CommonJS export names for ESM import in node:
127
+ 0 && (module.exports = {
128
+ sanitizeDomain,
129
+ sanitizeEmail,
130
+ sanitizeQueries,
131
+ sanitizeString,
132
+ sanitizeUrl
133
+ });
@@ -0,0 +1,174 @@
1
+ import disposableDomains from 'disposable-email-domains';
2
+
3
+ const SCOPE_KEYS = [ 'organization', 'account', 'user', 'owner' ];
4
+ const DANGEROUS_OPERATORS = [ '$where', '$function', '$accumulator' ];
5
+
6
+ // Disposable-domain set, built once at module load (~120K domains, ~6MB RSS).
7
+ // O(1) lookup keeps sanitizeEmail cheap. The npm package auto-updates the list —
8
+ // `npm update` periodically refreshes it. (NOTE: importing this module pulls the
9
+ // 6MB set even for consumers that only use sanitizeUrl/sanitizeString; split
10
+ // sanitizeUrl into its own module later if that footprint matters.)
11
+ const disposableBlacklist = new Set( disposableDomains.map( ( d ) => d.toLowerCase() ) );
12
+
13
+ const stripDangerousOperators = ( value ) => {
14
+
15
+ if( Array.isArray( value ) ){
16
+
17
+ return value.map( stripDangerousOperators );
18
+
19
+ }
20
+ if( value && typeof value === 'object' ){
21
+
22
+ const result = {};
23
+
24
+ for( const [ key, child ] of Object.entries( value ) ){
25
+
26
+ if( DANGEROUS_OPERATORS.includes( key ) ) continue;
27
+
28
+ result[ key ] = stripDangerousOperators( child );
29
+
30
+ }
31
+ return result;
32
+
33
+ }
34
+ return value;
35
+
36
+ };
37
+
38
+ const cleanQueryPart = ( value ) => {
39
+
40
+ if( ! value || typeof value !== 'object' || Array.isArray( value ) ) return value;
41
+
42
+ const cleaned = stripDangerousOperators( value );
43
+
44
+ for( const key of SCOPE_KEYS ){
45
+
46
+ delete cleaned[ key ];
47
+
48
+ }
49
+ return cleaned;
50
+
51
+ };
52
+
53
+ const sanitizeString = (
54
+ value
55
+ ) => {
56
+
57
+ if( value && value !== null ) {
58
+
59
+ //for now will just trim value. Making this a helper in case we end up expanding what gets filtered
60
+ return value.trim();
61
+
62
+ } else {
63
+
64
+ return null;
65
+
66
+ }
67
+
68
+ };
69
+
70
+ const sanitizeDomain = ( value, pattern ) => {
71
+
72
+ if( ! value ) return value;
73
+
74
+ const cleaned = value
75
+ .trim()
76
+ .toLowerCase()
77
+ .replace( /^https?:\/\//i, '' )
78
+ .replace( /\/+$/, '' );
79
+
80
+ if( pattern ){
81
+
82
+ const match = cleaned.match( pattern );
83
+
84
+ return match ? match[ 0 ] : cleaned;
85
+
86
+ }
87
+
88
+ return cleaned;
89
+
90
+ };
91
+
92
+ const sanitizeUrl = ( url ) => url
93
+ ?.replace( /^http:\/\//, 'https://' )
94
+ ?.replace( /^https:\/\/www\./, 'https://' )
95
+ ?.replace( /\/$/, '' );
96
+
97
+ // Normalize + validate an email address. Trim, lowercase, basic shape
98
+ // check, and reject disposable-domain providers. Returns the normalized
99
+ // email on success; never throws.
100
+ //
101
+ // { valid: true, email: 'darren@cursor.io' }
102
+ // { valid: false, reason: 'format' }
103
+ // { valid: false, reason: 'disposable' }
104
+ const sanitizeEmail = ( raw ) => {
105
+
106
+ if( typeof raw !== 'string' ) return {
107
+ valid : false,
108
+ reason : 'format'
109
+ };
110
+
111
+ const email = raw.trim().toLowerCase();
112
+
113
+ // Minimal RFC-ish shape — defers full validation to the email provider
114
+ // on delivery. We just need to reject obvious garbage and extract a
115
+ // domain for the disposable-list check.
116
+ const match = email.match( /^[^\s@]+@([^\s@]+\.[^\s@]+)$/ );
117
+
118
+ if( ! match ) return {
119
+ valid : false,
120
+ reason : 'format'
121
+ };
122
+
123
+ if( disposableBlacklist.has( match[ 1 ] ) ) return {
124
+ valid : false,
125
+ reason : 'disposable'
126
+ };
127
+
128
+ return {
129
+ email,
130
+ valid : true
131
+ };
132
+
133
+ };
134
+
135
+ // Express middleware. Strips two specific attack surfaces from `req.query.filters`
136
+ // and `req.query.refine` before they flow into Mongo queries via the
137
+ // `...filters` / `...refine` spread pattern:
138
+ //
139
+ // 1. Scope-key override at the top level — keys that name a tenant scope
140
+ // (organization, account, user, owner). Without this guard, an attacker can
141
+ // pass `?filters[organization]=OTHER_ORG_ID` or
142
+ // `?filters[organization][$ne]=null` and override the route's scope.
143
+ //
144
+ // 2. JS-execution operators ($where, $function, $accumulator) anywhere in the
145
+ // tree — these run arbitrary server-side JS in Mongo. No client UI builds them.
146
+ //
147
+ // $or / $and / $in / $ne / $regex / etc. on non-scope fields are intentionally
148
+ // allowed — the dashboard's filter builder (components/form-filters.js) produces
149
+ // them and they cannot bypass an outer-scope AND clause.
150
+ //
151
+ // Admin paths (`/admin/...`) bypass entirely.
152
+ const sanitizeQueries = ( req, res, next ) => {
153
+
154
+ if( req.path.startsWith( '/admin/' ) ){
155
+
156
+ next();
157
+ return;
158
+
159
+ }
160
+ if( req.query?.filters ){
161
+
162
+ req.query.filters = cleanQueryPart( req.query.filters );
163
+
164
+ }
165
+ if( req.query?.refine ){
166
+
167
+ req.query.refine = cleanQueryPart( req.query.refine );
168
+
169
+ }
170
+ next();
171
+
172
+ };
173
+
174
+ export { sanitizeDomain, sanitizeEmail, sanitizeQueries, sanitizeString, sanitizeUrl };
@@ -0,0 +1,174 @@
1
+ import disposableDomains from 'disposable-email-domains';
2
+
3
+ const SCOPE_KEYS = [ 'organization', 'account', 'user', 'owner' ];
4
+ const DANGEROUS_OPERATORS = [ '$where', '$function', '$accumulator' ];
5
+
6
+ // Disposable-domain set, built once at module load (~120K domains, ~6MB RSS).
7
+ // O(1) lookup keeps sanitizeEmail cheap. The npm package auto-updates the list —
8
+ // `npm update` periodically refreshes it. (NOTE: importing this module pulls the
9
+ // 6MB set even for consumers that only use sanitizeUrl/sanitizeString; split
10
+ // sanitizeUrl into its own module later if that footprint matters.)
11
+ const disposableBlacklist = new Set( disposableDomains.map( ( d ) => d.toLowerCase() ) );
12
+
13
+ const stripDangerousOperators = ( value ) => {
14
+
15
+ if( Array.isArray( value ) ){
16
+
17
+ return value.map( stripDangerousOperators );
18
+
19
+ }
20
+ if( value && typeof value === 'object' ){
21
+
22
+ const result = {};
23
+
24
+ for( const [ key, child ] of Object.entries( value ) ){
25
+
26
+ if( DANGEROUS_OPERATORS.includes( key ) ) continue;
27
+
28
+ result[ key ] = stripDangerousOperators( child );
29
+
30
+ }
31
+ return result;
32
+
33
+ }
34
+ return value;
35
+
36
+ };
37
+
38
+ const cleanQueryPart = ( value ) => {
39
+
40
+ if( ! value || typeof value !== 'object' || Array.isArray( value ) ) return value;
41
+
42
+ const cleaned = stripDangerousOperators( value );
43
+
44
+ for( const key of SCOPE_KEYS ){
45
+
46
+ delete cleaned[ key ];
47
+
48
+ }
49
+ return cleaned;
50
+
51
+ };
52
+
53
+ const sanitizeString = (
54
+ value
55
+ ) => {
56
+
57
+ if( value && value !== null ) {
58
+
59
+ //for now will just trim value. Making this a helper in case we end up expanding what gets filtered
60
+ return value.trim();
61
+
62
+ } else {
63
+
64
+ return null;
65
+
66
+ }
67
+
68
+ };
69
+
70
+ const sanitizeDomain = ( value, pattern ) => {
71
+
72
+ if( ! value ) return value;
73
+
74
+ const cleaned = value
75
+ .trim()
76
+ .toLowerCase()
77
+ .replace( /^https?:\/\//i, '' )
78
+ .replace( /\/+$/, '' );
79
+
80
+ if( pattern ){
81
+
82
+ const match = cleaned.match( pattern );
83
+
84
+ return match ? match[ 0 ] : cleaned;
85
+
86
+ }
87
+
88
+ return cleaned;
89
+
90
+ };
91
+
92
+ const sanitizeUrl = ( url ) => url
93
+ ?.replace( /^http:\/\//, 'https://' )
94
+ ?.replace( /^https:\/\/www\./, 'https://' )
95
+ ?.replace( /\/$/, '' );
96
+
97
+ // Normalize + validate an email address. Trim, lowercase, basic shape
98
+ // check, and reject disposable-domain providers. Returns the normalized
99
+ // email on success; never throws.
100
+ //
101
+ // { valid: true, email: 'darren@cursor.io' }
102
+ // { valid: false, reason: 'format' }
103
+ // { valid: false, reason: 'disposable' }
104
+ const sanitizeEmail = ( raw ) => {
105
+
106
+ if( typeof raw !== 'string' ) return {
107
+ valid : false,
108
+ reason : 'format'
109
+ };
110
+
111
+ const email = raw.trim().toLowerCase();
112
+
113
+ // Minimal RFC-ish shape — defers full validation to the email provider
114
+ // on delivery. We just need to reject obvious garbage and extract a
115
+ // domain for the disposable-list check.
116
+ const match = email.match( /^[^\s@]+@([^\s@]+\.[^\s@]+)$/ );
117
+
118
+ if( ! match ) return {
119
+ valid : false,
120
+ reason : 'format'
121
+ };
122
+
123
+ if( disposableBlacklist.has( match[ 1 ] ) ) return {
124
+ valid : false,
125
+ reason : 'disposable'
126
+ };
127
+
128
+ return {
129
+ email,
130
+ valid : true
131
+ };
132
+
133
+ };
134
+
135
+ // Express middleware. Strips two specific attack surfaces from `req.query.filters`
136
+ // and `req.query.refine` before they flow into Mongo queries via the
137
+ // `...filters` / `...refine` spread pattern:
138
+ //
139
+ // 1. Scope-key override at the top level — keys that name a tenant scope
140
+ // (organization, account, user, owner). Without this guard, an attacker can
141
+ // pass `?filters[organization]=OTHER_ORG_ID` or
142
+ // `?filters[organization][$ne]=null` and override the route's scope.
143
+ //
144
+ // 2. JS-execution operators ($where, $function, $accumulator) anywhere in the
145
+ // tree — these run arbitrary server-side JS in Mongo. No client UI builds them.
146
+ //
147
+ // $or / $and / $in / $ne / $regex / etc. on non-scope fields are intentionally
148
+ // allowed — the dashboard's filter builder (components/form-filters.js) produces
149
+ // them and they cannot bypass an outer-scope AND clause.
150
+ //
151
+ // Admin paths (`/admin/...`) bypass entirely.
152
+ const sanitizeQueries = ( req, res, next ) => {
153
+
154
+ if( req.path.startsWith( '/admin/' ) ){
155
+
156
+ next();
157
+ return;
158
+
159
+ }
160
+ if( req.query?.filters ){
161
+
162
+ req.query.filters = cleanQueryPart( req.query.filters );
163
+
164
+ }
165
+ if( req.query?.refine ){
166
+
167
+ req.query.refine = cleanQueryPart( req.query.refine );
168
+
169
+ }
170
+ next();
171
+
172
+ };
173
+
174
+ export { sanitizeDomain, sanitizeEmail, sanitizeQueries, sanitizeString, sanitizeUrl };
@@ -0,0 +1,95 @@
1
+ // lib/sanitize.js
2
+ import disposableDomains from "disposable-email-domains";
3
+ var SCOPE_KEYS = ["organization", "account", "user", "owner"];
4
+ var DANGEROUS_OPERATORS = ["$where", "$function", "$accumulator"];
5
+ var disposableBlacklist = new Set(disposableDomains.map((d) => d.toLowerCase()));
6
+ var stripDangerousOperators = (value) => {
7
+ if (Array.isArray(value)) {
8
+ return value.map(stripDangerousOperators);
9
+ }
10
+ ;
11
+ if (value && typeof value === "object") {
12
+ const result = {};
13
+ for (const [key, child] of Object.entries(value)) {
14
+ if (DANGEROUS_OPERATORS.includes(key)) continue;
15
+ result[key] = stripDangerousOperators(child);
16
+ }
17
+ ;
18
+ return result;
19
+ }
20
+ ;
21
+ return value;
22
+ };
23
+ var cleanQueryPart = (value) => {
24
+ if (!value || typeof value !== "object" || Array.isArray(value)) return value;
25
+ const cleaned = stripDangerousOperators(value);
26
+ for (const key of SCOPE_KEYS) {
27
+ delete cleaned[key];
28
+ }
29
+ ;
30
+ return cleaned;
31
+ };
32
+ var sanitizeString = (value) => {
33
+ if (value && value !== null) {
34
+ return value.trim();
35
+ } else {
36
+ return null;
37
+ }
38
+ };
39
+ var sanitizeDomain = (value, pattern) => {
40
+ if (!value) return value;
41
+ const cleaned = value.trim().toLowerCase().replace(/^https?:\/\//i, "").replace(/\/+$/, "");
42
+ if (pattern) {
43
+ const match = cleaned.match(pattern);
44
+ return match ? match[0] : cleaned;
45
+ }
46
+ return cleaned;
47
+ };
48
+ var sanitizeUrl = (url) => {
49
+ var _a, _b;
50
+ return (_b = (_a = url == null ? void 0 : url.replace(/^http:\/\//, "https://")) == null ? void 0 : _a.replace(/^https:\/\/www\./, "https://")) == null ? void 0 : _b.replace(/\/$/, "");
51
+ };
52
+ var sanitizeEmail = (raw) => {
53
+ if (typeof raw !== "string") return {
54
+ valid: false,
55
+ reason: "format"
56
+ };
57
+ const email = raw.trim().toLowerCase();
58
+ const match = email.match(/^[^\s@]+@([^\s@]+\.[^\s@]+)$/);
59
+ if (!match) return {
60
+ valid: false,
61
+ reason: "format"
62
+ };
63
+ if (disposableBlacklist.has(match[1])) return {
64
+ valid: false,
65
+ reason: "disposable"
66
+ };
67
+ return {
68
+ email,
69
+ valid: true
70
+ };
71
+ };
72
+ var sanitizeQueries = (req, res, next) => {
73
+ var _a, _b;
74
+ if (req.path.startsWith("/admin/")) {
75
+ next();
76
+ return;
77
+ }
78
+ ;
79
+ if ((_a = req.query) == null ? void 0 : _a.filters) {
80
+ req.query.filters = cleanQueryPart(req.query.filters);
81
+ }
82
+ ;
83
+ if ((_b = req.query) == null ? void 0 : _b.refine) {
84
+ req.query.refine = cleanQueryPart(req.query.refine);
85
+ }
86
+ ;
87
+ next();
88
+ };
89
+ export {
90
+ sanitizeDomain,
91
+ sanitizeEmail,
92
+ sanitizeQueries,
93
+ sanitizeString,
94
+ sanitizeUrl
95
+ };
package/package.json CHANGED
@@ -2,10 +2,11 @@
2
2
  "type": "module",
3
3
  "dependencies": {
4
4
  "@drawbridge/drawbridge-agents": "0.0.10",
5
- "@drawbridge/drawbridge-telemetry": "0.0.13",
5
+ "@drawbridge/drawbridge-telemetry": "0.0.14",
6
6
  "@google/genai": "1.30.0",
7
7
  "axios": "1.16.0",
8
8
  "currency-codes": "2.2.0",
9
+ "disposable-email-domains": "1.0.62",
9
10
  "nanoid": "3.3.8",
10
11
  "qs": "6.15.2",
11
12
  "slugify": "1.6.6",
@@ -93,6 +94,11 @@
93
94
  "import": "./dist/redirect.js",
94
95
  "require": "./dist/redirect.cjs"
95
96
  },
97
+ "./sanitize": {
98
+ "types": "./dist/sanitize.d.ts",
99
+ "import": "./dist/sanitize.js",
100
+ "require": "./dist/sanitize.cjs"
101
+ },
96
102
  "./cdn": {
97
103
  "types": "./dist/cdn.d.ts",
98
104
  "import": "./dist/cdn.js",
@@ -154,5 +160,5 @@
154
160
  "build": "tsup && npm publish"
155
161
  },
156
162
  "types": "dist/index.d.ts",
157
- "version": "0.0.58"
163
+ "version": "0.0.60"
158
164
  }