@drawbridge/drawbridge-utils 0.0.78 → 0.0.80

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
@@ -1,6 +1,8 @@
1
+ var __create = Object.create;
1
2
  var __defProp = Object.defineProperty;
2
3
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
4
  var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __getProtoOf = Object.getPrototypeOf;
4
6
  var __hasOwnProp = Object.prototype.hasOwnProperty;
5
7
  var __export = (target, all) => {
6
8
  for (var name in all)
@@ -14,6 +16,14 @@ var __copyProps = (to, from, except, desc) => {
14
16
  }
15
17
  return to;
16
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
+ ));
17
27
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
18
28
 
19
29
  // lib/ai.js
@@ -251,6 +261,13 @@ var ai = {
251
261
  bill: ({ db, user, model, usage, tools }) => (user == null ? void 0 : user.id) ? () => billRequest({ db, user, model, usage, tools }) : () => Promise.resolve()
252
262
  };
253
263
 
264
+ // lib/fetch.js
265
+ var import_qs = __toESM(require("qs"), 1);
266
+ var isTransientError = (error) => {
267
+ const status = error == null ? void 0 : error.status;
268
+ return !status || status === 429 || status >= 500;
269
+ };
270
+
254
271
  // lib/ai.js
255
272
  var google_client = new import_genai.GoogleGenAI({
256
273
  apiKey: process.env.GOOGLE_GEMINI_API_KEY
@@ -260,6 +277,16 @@ var googleCircuit = circuit({
260
277
  threshold: 3,
261
278
  timeout: 6e4
262
279
  });
280
+ var withRetries = async (fn, { attempts = 3, delay = 500 } = {}) => {
281
+ for (let attempt = 1; ; attempt++) {
282
+ try {
283
+ return await fn();
284
+ } catch (error) {
285
+ if (attempt >= attempts || !isTransientError(error)) throw error;
286
+ await new Promise((resolve) => setTimeout(resolve, delay * attempt));
287
+ }
288
+ }
289
+ };
263
290
  var models = {
264
291
  image: "gemini-2.5-flash-image",
265
292
  text: "gemini-3.5-flash"
@@ -293,14 +320,14 @@ var google = {
293
320
  ...refs.map((ref) => ({ inlineData: { data: ref.data, mimeType: ref.mimeType } })),
294
321
  { text: prompt.join("\n") }
295
322
  ];
296
- const response = await googleCircuit(() => google_client.models.generateContent({
323
+ const response = await googleCircuit(() => withRetries(() => google_client.models.generateContent({
297
324
  model,
298
325
  contents: { parts },
299
326
  config: {
300
327
  ...config,
301
328
  responseModalities: ["Image"]
302
329
  }
303
- }));
330
+ })));
304
331
  const content = (_f = (_e = (_d = (_c = (_b = (_a = response == null ? void 0 : response.candidates) == null ? void 0 : _a[0]) == null ? void 0 : _b.content) == null ? void 0 : _c.parts) == null ? void 0 : _d[0]) == null ? void 0 : _e.inlineData) == null ? void 0 : _f.data;
305
332
  if (!content) {
306
333
  throw new Error("Could not generate from prompt. Please try again with a different prompt.");
@@ -321,14 +348,14 @@ var google = {
321
348
  }) => {
322
349
  const model = models.text;
323
350
  const contents = parts ? { parts } : images.length ? { parts: [...images.map((image) => ({ inlineData: { data: image.data, mimeType: image.mimeType } })), { text: prompt.join("\n") }] } : prompt.join("\n");
324
- const response = await googleCircuit(() => google_client.models.generateContent({
351
+ const response = await googleCircuit(() => withRetries(() => google_client.models.generateContent({
325
352
  config: {
326
353
  ...config,
327
354
  responseModalities: ["Text"]
328
355
  },
329
356
  contents,
330
357
  model
331
- }));
358
+ })));
332
359
  const content = response == null ? void 0 : response.text;
333
360
  if (!content) {
334
361
  throw new Error("Could not generate from prompt. Please try again with a different prompt.");
package/dist/ai.d.cts CHANGED
@@ -2,9 +2,11 @@ import { GoogleGenAI } from '@google/genai';
2
2
  import { circuit } from './circuit.cjs';
3
3
  import { ai } from './billing.cjs';
4
4
  export { MARKUP } from './billing.cjs';
5
+ import { isTransientError } from './fetch.cjs';
5
6
  import './transactions.cjs';
6
7
  import '@drawbridge/drawbridge-telemetry';
7
8
  import './usage.cjs';
9
+ import 'qs';
8
10
 
9
11
  // AI request entry point. Wraps the Google GenAI client with a per-process
10
12
  // circuit breaker, owns the per-model pricing table, and atomically debits
@@ -35,6 +37,35 @@ const googleCircuit = circuit({
35
37
  timeout : 60000
36
38
  });
37
39
 
40
+ // Bounded retry for the raw model call. A single transient failure — undici
41
+ // "fetch failed" on a resource-starved pod, a 429, a 5xx — must not lose the
42
+ // generation step OR count toward the breaker: three of those trip it and
43
+ // hard-fail every AI call for the next 60s. Runs INSIDE the googleCircuit
44
+ // callback so the breaker only counts calls that failed after retries were
45
+ // exhausted, and an OPEN circuit still fails fast without retrying.
46
+ // isTransientError treats status-less errors as transient, which is correct
47
+ // here: the wrapped fn is exactly one SDK call, and the GenAI SDK reports
48
+ // network-level failures as plain Errors with no `.status`.
49
+ const withRetries = async ( fn, { attempts = 3, delay = 500 } = {} ) => {
50
+
51
+ for( let attempt = 1; ; attempt++ ){
52
+
53
+ try {
54
+
55
+ return await fn();
56
+
57
+ } catch ( error ) {
58
+
59
+ if( attempt >= attempts || ! isTransientError( error ) ) throw error;
60
+
61
+ await new Promise( ( resolve ) => setTimeout( resolve, delay * attempt ) );
62
+
63
+ }
64
+
65
+ }
66
+
67
+ };
68
+
38
69
  // gemini-2.5-flash was retired by Google (generateContent → 404 "no longer
39
70
  // available"), taking down every generation. gemini-3.5-flash is the current
40
71
  // stable flash successor. The image model is a distinct model and still live,
@@ -89,14 +120,14 @@ const google = {
89
120
  { text : prompt.join( '\n' ) }
90
121
  ];
91
122
 
92
- const response = await googleCircuit( () => google_client.models.generateContent({
123
+ const response = await googleCircuit( () => withRetries( () => google_client.models.generateContent({
93
124
  model,
94
125
  contents : { parts },
95
126
  config : {
96
127
  ...config,
97
128
  responseModalities : [ 'Image' ]
98
129
  }
99
- }) );
130
+ }) ) );
100
131
 
101
132
  const content = response?.candidates?.[ 0 ]?.content?.parts?.[ 0 ]?.inlineData?.data;
102
133
 
@@ -143,14 +174,14 @@ const google = {
143
174
  ? { parts : [ ...images.map( ( image ) => ({ inlineData : { data : image.data, mimeType : image.mimeType } }) ), { text : prompt.join( '\n' ) } ] }
144
175
  : prompt.join( '\n' );
145
176
 
146
- const response = await googleCircuit( () => google_client.models.generateContent({
177
+ const response = await googleCircuit( () => withRetries( () => google_client.models.generateContent({
147
178
  config : {
148
179
  ...config,
149
180
  responseModalities : [ 'Text' ]
150
181
  },
151
182
  contents,
152
183
  model
153
- }) );
184
+ }) ) );
154
185
 
155
186
  const content = response?.text;
156
187
 
package/dist/ai.d.ts CHANGED
@@ -2,9 +2,11 @@ import { GoogleGenAI } from '@google/genai';
2
2
  import { circuit } from './circuit.js';
3
3
  import { ai } from './billing.js';
4
4
  export { MARKUP } from './billing.js';
5
+ import { isTransientError } from './fetch.js';
5
6
  import './transactions.js';
6
7
  import '@drawbridge/drawbridge-telemetry';
7
8
  import './usage.js';
9
+ import 'qs';
8
10
 
9
11
  // AI request entry point. Wraps the Google GenAI client with a per-process
10
12
  // circuit breaker, owns the per-model pricing table, and atomically debits
@@ -35,6 +37,35 @@ const googleCircuit = circuit({
35
37
  timeout : 60000
36
38
  });
37
39
 
40
+ // Bounded retry for the raw model call. A single transient failure — undici
41
+ // "fetch failed" on a resource-starved pod, a 429, a 5xx — must not lose the
42
+ // generation step OR count toward the breaker: three of those trip it and
43
+ // hard-fail every AI call for the next 60s. Runs INSIDE the googleCircuit
44
+ // callback so the breaker only counts calls that failed after retries were
45
+ // exhausted, and an OPEN circuit still fails fast without retrying.
46
+ // isTransientError treats status-less errors as transient, which is correct
47
+ // here: the wrapped fn is exactly one SDK call, and the GenAI SDK reports
48
+ // network-level failures as plain Errors with no `.status`.
49
+ const withRetries = async ( fn, { attempts = 3, delay = 500 } = {} ) => {
50
+
51
+ for( let attempt = 1; ; attempt++ ){
52
+
53
+ try {
54
+
55
+ return await fn();
56
+
57
+ } catch ( error ) {
58
+
59
+ if( attempt >= attempts || ! isTransientError( error ) ) throw error;
60
+
61
+ await new Promise( ( resolve ) => setTimeout( resolve, delay * attempt ) );
62
+
63
+ }
64
+
65
+ }
66
+
67
+ };
68
+
38
69
  // gemini-2.5-flash was retired by Google (generateContent → 404 "no longer
39
70
  // available"), taking down every generation. gemini-3.5-flash is the current
40
71
  // stable flash successor. The image model is a distinct model and still live,
@@ -89,14 +120,14 @@ const google = {
89
120
  { text : prompt.join( '\n' ) }
90
121
  ];
91
122
 
92
- const response = await googleCircuit( () => google_client.models.generateContent({
123
+ const response = await googleCircuit( () => withRetries( () => google_client.models.generateContent({
93
124
  model,
94
125
  contents : { parts },
95
126
  config : {
96
127
  ...config,
97
128
  responseModalities : [ 'Image' ]
98
129
  }
99
- }) );
130
+ }) ) );
100
131
 
101
132
  const content = response?.candidates?.[ 0 ]?.content?.parts?.[ 0 ]?.inlineData?.data;
102
133
 
@@ -143,14 +174,14 @@ const google = {
143
174
  ? { parts : [ ...images.map( ( image ) => ({ inlineData : { data : image.data, mimeType : image.mimeType } }) ), { text : prompt.join( '\n' ) } ] }
144
175
  : prompt.join( '\n' );
145
176
 
146
- const response = await googleCircuit( () => google_client.models.generateContent({
177
+ const response = await googleCircuit( () => withRetries( () => google_client.models.generateContent({
147
178
  config : {
148
179
  ...config,
149
180
  responseModalities : [ 'Text' ]
150
181
  },
151
182
  contents,
152
183
  model
153
- }) );
184
+ }) ) );
154
185
 
155
186
  const content = response?.text;
156
187
 
package/dist/ai.js CHANGED
@@ -227,6 +227,13 @@ var ai = {
227
227
  bill: ({ db, user, model, usage, tools }) => (user == null ? void 0 : user.id) ? () => billRequest({ db, user, model, usage, tools }) : () => Promise.resolve()
228
228
  };
229
229
 
230
+ // lib/fetch.js
231
+ import qs from "qs";
232
+ var isTransientError = (error) => {
233
+ const status = error == null ? void 0 : error.status;
234
+ return !status || status === 429 || status >= 500;
235
+ };
236
+
230
237
  // lib/ai.js
231
238
  var google_client = new GoogleGenAI({
232
239
  apiKey: process.env.GOOGLE_GEMINI_API_KEY
@@ -236,6 +243,16 @@ var googleCircuit = circuit({
236
243
  threshold: 3,
237
244
  timeout: 6e4
238
245
  });
246
+ var withRetries = async (fn, { attempts = 3, delay = 500 } = {}) => {
247
+ for (let attempt = 1; ; attempt++) {
248
+ try {
249
+ return await fn();
250
+ } catch (error) {
251
+ if (attempt >= attempts || !isTransientError(error)) throw error;
252
+ await new Promise((resolve) => setTimeout(resolve, delay * attempt));
253
+ }
254
+ }
255
+ };
239
256
  var models = {
240
257
  image: "gemini-2.5-flash-image",
241
258
  text: "gemini-3.5-flash"
@@ -269,14 +286,14 @@ var google = {
269
286
  ...refs.map((ref) => ({ inlineData: { data: ref.data, mimeType: ref.mimeType } })),
270
287
  { text: prompt.join("\n") }
271
288
  ];
272
- const response = await googleCircuit(() => google_client.models.generateContent({
289
+ const response = await googleCircuit(() => withRetries(() => google_client.models.generateContent({
273
290
  model,
274
291
  contents: { parts },
275
292
  config: {
276
293
  ...config,
277
294
  responseModalities: ["Image"]
278
295
  }
279
- }));
296
+ })));
280
297
  const content = (_f = (_e = (_d = (_c = (_b = (_a = response == null ? void 0 : response.candidates) == null ? void 0 : _a[0]) == null ? void 0 : _b.content) == null ? void 0 : _c.parts) == null ? void 0 : _d[0]) == null ? void 0 : _e.inlineData) == null ? void 0 : _f.data;
281
298
  if (!content) {
282
299
  throw new Error("Could not generate from prompt. Please try again with a different prompt.");
@@ -297,14 +314,14 @@ var google = {
297
314
  }) => {
298
315
  const model = models.text;
299
316
  const contents = parts ? { parts } : images.length ? { parts: [...images.map((image) => ({ inlineData: { data: image.data, mimeType: image.mimeType } })), { text: prompt.join("\n") }] } : prompt.join("\n");
300
- const response = await googleCircuit(() => google_client.models.generateContent({
317
+ const response = await googleCircuit(() => withRetries(() => google_client.models.generateContent({
301
318
  config: {
302
319
  ...config,
303
320
  responseModalities: ["Text"]
304
321
  },
305
322
  contents,
306
323
  model
307
- }));
324
+ })));
308
325
  const content = response == null ? void 0 : response.text;
309
326
  if (!content) {
310
327
  throw new Error("Could not generate from prompt. Please try again with a different prompt.");
package/dist/email.cjs ADDED
@@ -0,0 +1,42 @@
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/email.js
20
+ var email_exports = {};
21
+ __export(email_exports, {
22
+ toCanonicalEmail: () => toCanonicalEmail
23
+ });
24
+ module.exports = __toCommonJS(email_exports);
25
+ var GMAIL_DOMAINS = /* @__PURE__ */ new Set(["gmail.com", "googlemail.com"]);
26
+ var toCanonicalEmail = (value) => {
27
+ if (!value || typeof value !== "string") return null;
28
+ const email = value.trim().toLowerCase();
29
+ const at = email.lastIndexOf("@");
30
+ if (at < 1 || at === email.length - 1) return null;
31
+ let local = email.slice(0, at);
32
+ const domain = email.slice(at + 1);
33
+ const plus = local.indexOf("+");
34
+ if (plus > 0) local = local.slice(0, plus);
35
+ if (GMAIL_DOMAINS.has(domain)) local = local.replaceAll(".", "");
36
+ if (!local) return null;
37
+ return local + "@" + domain;
38
+ };
39
+ // Annotate the CommonJS export names for ESM import in node:
40
+ 0 && (module.exports = {
41
+ toCanonicalEmail
42
+ });
@@ -0,0 +1,36 @@
1
+ // Gmail treats dots in the local part as insignificant; these are the only
2
+ // domains where dot-stripping is safe.
3
+ const GMAIL_DOMAINS = new Set( [ 'gmail.com', 'googlemail.com' ] );
4
+
5
+ // Canonicalize an email for identity matching (NOT for delivery — always send
6
+ // to the raw address the user typed): trim, lowercase, strip the +tag
7
+ // subaddress, and strip local-part dots on Gmail-family domains. Heuristic by
8
+ // design — a canonical collision only ever merges identities, never loses a
9
+ // deliverable address, so lenient is the right bias. Unparseable input → null.
10
+ const toCanonicalEmail = ( value ) => {
11
+
12
+ if( ! value || typeof value !== 'string' ) return null;
13
+
14
+ const email = value.trim().toLowerCase();
15
+
16
+ const at = email.lastIndexOf( '@' );
17
+
18
+ if( at < 1 || at === email.length - 1 ) return null;
19
+
20
+ let local = email.slice( 0, at );
21
+ const domain = email.slice( at + 1 );
22
+
23
+ // index 0 would empty the local part — leave a leading plus alone
24
+ const plus = local.indexOf( '+' );
25
+
26
+ if( plus > 0 ) local = local.slice( 0, plus );
27
+
28
+ if( GMAIL_DOMAINS.has( domain ) ) local = local.replaceAll( '.', '' );
29
+
30
+ if( ! local ) return null;
31
+
32
+ return local + '@' + domain;
33
+
34
+ };
35
+
36
+ export { toCanonicalEmail };
@@ -0,0 +1,36 @@
1
+ // Gmail treats dots in the local part as insignificant; these are the only
2
+ // domains where dot-stripping is safe.
3
+ const GMAIL_DOMAINS = new Set( [ 'gmail.com', 'googlemail.com' ] );
4
+
5
+ // Canonicalize an email for identity matching (NOT for delivery — always send
6
+ // to the raw address the user typed): trim, lowercase, strip the +tag
7
+ // subaddress, and strip local-part dots on Gmail-family domains. Heuristic by
8
+ // design — a canonical collision only ever merges identities, never loses a
9
+ // deliverable address, so lenient is the right bias. Unparseable input → null.
10
+ const toCanonicalEmail = ( value ) => {
11
+
12
+ if( ! value || typeof value !== 'string' ) return null;
13
+
14
+ const email = value.trim().toLowerCase();
15
+
16
+ const at = email.lastIndexOf( '@' );
17
+
18
+ if( at < 1 || at === email.length - 1 ) return null;
19
+
20
+ let local = email.slice( 0, at );
21
+ const domain = email.slice( at + 1 );
22
+
23
+ // index 0 would empty the local part — leave a leading plus alone
24
+ const plus = local.indexOf( '+' );
25
+
26
+ if( plus > 0 ) local = local.slice( 0, plus );
27
+
28
+ if( GMAIL_DOMAINS.has( domain ) ) local = local.replaceAll( '.', '' );
29
+
30
+ if( ! local ) return null;
31
+
32
+ return local + '@' + domain;
33
+
34
+ };
35
+
36
+ export { toCanonicalEmail };
package/dist/email.js ADDED
@@ -0,0 +1,18 @@
1
+ // lib/email.js
2
+ var GMAIL_DOMAINS = /* @__PURE__ */ new Set(["gmail.com", "googlemail.com"]);
3
+ var toCanonicalEmail = (value) => {
4
+ if (!value || typeof value !== "string") return null;
5
+ const email = value.trim().toLowerCase();
6
+ const at = email.lastIndexOf("@");
7
+ if (at < 1 || at === email.length - 1) return null;
8
+ let local = email.slice(0, at);
9
+ const domain = email.slice(at + 1);
10
+ const plus = local.indexOf("+");
11
+ if (plus > 0) local = local.slice(0, plus);
12
+ if (GMAIL_DOMAINS.has(domain)) local = local.replaceAll(".", "");
13
+ if (!local) return null;
14
+ return local + "@" + domain;
15
+ };
16
+ export {
17
+ toCanonicalEmail
18
+ };
package/dist/fetch.cjs CHANGED
@@ -29,6 +29,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
29
29
  // lib/fetch.js
30
30
  var fetch_exports = {};
31
31
  __export(fetch_exports, {
32
+ isTransientError: () => isTransientError,
32
33
  queryString: () => queryString,
33
34
  request: () => request,
34
35
  setMemoryToken: () => setMemoryToken
@@ -109,8 +110,13 @@ var request = async ({
109
110
  }
110
111
  return res;
111
112
  };
113
+ var isTransientError = (error) => {
114
+ const status = error == null ? void 0 : error.status;
115
+ return !status || status === 429 || status >= 500;
116
+ };
112
117
  // Annotate the CommonJS export names for ESM import in node:
113
118
  0 && (module.exports = {
119
+ isTransientError,
114
120
  queryString,
115
121
  request,
116
122
  setMemoryToken
package/dist/fetch.d.cts CHANGED
@@ -112,4 +112,19 @@ const request = async ({
112
112
 
113
113
  };
114
114
 
115
- export { queryString, request, setMemoryToken };
115
+ // Classifies an error thrown by request() which carries `.status` from the
116
+ // HTTP response, or no status for a network / parse failure. Transient errors
117
+ // ( rate limits, server errors, connection blips ) may succeed on retry, so
118
+ // callers should offer a reload rather than treating them as an auth failure
119
+ // ( → sign-in / 401 ) or a missing resource ( → 404 ). Reserving those hard
120
+ // outcomes for genuine 4xx keeps a rate-limited request from bouncing between
121
+ // error screens in a redirect loop.
122
+ const isTransientError = ( error ) => {
123
+
124
+ const status = error?.status;
125
+
126
+ return ! status || status === 429 || status >= 500;
127
+
128
+ };
129
+
130
+ export { isTransientError, queryString, request, setMemoryToken };
package/dist/fetch.d.ts CHANGED
@@ -112,4 +112,19 @@ const request = async ({
112
112
 
113
113
  };
114
114
 
115
- export { queryString, request, setMemoryToken };
115
+ // Classifies an error thrown by request() which carries `.status` from the
116
+ // HTTP response, or no status for a network / parse failure. Transient errors
117
+ // ( rate limits, server errors, connection blips ) may succeed on retry, so
118
+ // callers should offer a reload rather than treating them as an auth failure
119
+ // ( → sign-in / 401 ) or a missing resource ( → 404 ). Reserving those hard
120
+ // outcomes for genuine 4xx keeps a rate-limited request from bouncing between
121
+ // error screens in a redirect loop.
122
+ const isTransientError = ( error ) => {
123
+
124
+ const status = error?.status;
125
+
126
+ return ! status || status === 429 || status >= 500;
127
+
128
+ };
129
+
130
+ export { isTransientError, queryString, request, setMemoryToken };
package/dist/fetch.js CHANGED
@@ -74,7 +74,12 @@ var request = async ({
74
74
  }
75
75
  return res;
76
76
  };
77
+ var isTransientError = (error) => {
78
+ const status = error == null ? void 0 : error.status;
79
+ return !status || status === 429 || status >= 500;
80
+ };
77
81
  export {
82
+ isTransientError,
78
83
  queryString,
79
84
  request,
80
85
  setMemoryToken
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "type": "module",
3
3
  "dependencies": {
4
4
  "@drawbridge/drawbridge-agents": "0.0.10",
5
- "@drawbridge/drawbridge-telemetry": "0.0.14",
5
+ "@drawbridge/drawbridge-telemetry": "0.0.15",
6
6
  "@google/genai": "1.30.0",
7
7
  "axios": "1.16.0",
8
8
  "currency-codes": "2.2.0",
@@ -47,6 +47,11 @@
47
47
  "import": "./dist/color.js",
48
48
  "require": "./dist/color.cjs"
49
49
  },
50
+ "./email": {
51
+ "types": "./dist/email.d.ts",
52
+ "import": "./dist/email.js",
53
+ "require": "./dist/email.cjs"
54
+ },
50
55
  "./encrypt": {
51
56
  "types": "./dist/encrypt.d.ts",
52
57
  "import": "./dist/encrypt.js",
@@ -159,5 +164,5 @@
159
164
  "test": "node --test test/"
160
165
  },
161
166
  "types": "dist/index.d.ts",
162
- "version": "0.0.78"
167
+ "version": "0.0.80"
163
168
  }