@donotdev/functions 0.0.12 → 0.0.13

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.
Files changed (50) hide show
  1. package/package.json +4 -4
  2. package/src/firebase/auth/setCustomClaims.ts +19 -5
  3. package/src/firebase/baseFunction.ts +11 -3
  4. package/src/firebase/billing/changePlan.ts +5 -1
  5. package/src/firebase/billing/createCustomerPortal.ts +6 -2
  6. package/src/firebase/billing/webhookHandler.ts +4 -1
  7. package/src/firebase/crud/aggregate.ts +5 -1
  8. package/src/firebase/crud/create.ts +17 -4
  9. package/src/firebase/crud/list.ts +9 -4
  10. package/src/firebase/crud/update.ts +17 -4
  11. package/src/firebase/oauth/exchangeToken.ts +17 -4
  12. package/src/shared/__tests__/validation.test.ts +5 -3
  13. package/src/shared/billing/__tests__/createCheckout.test.ts +123 -22
  14. package/src/shared/billing/__tests__/webhookHandler.test.ts +121 -30
  15. package/src/shared/firebase.ts +1 -1
  16. package/src/shared/logger.ts +7 -1
  17. package/src/shared/oauth/__tests__/exchangeToken.test.ts +6 -8
  18. package/src/shared/oauth/__tests__/grantAccess.test.ts +31 -14
  19. package/src/shared/utils/internal/auth.ts +10 -3
  20. package/src/shared/utils/internal/rateLimiter.ts +8 -2
  21. package/src/shared/utils.ts +5 -1
  22. package/src/supabase/auth/deleteAccount.ts +1 -1
  23. package/src/supabase/auth/getCustomClaims.ts +5 -3
  24. package/src/supabase/auth/getUserAuthStatus.ts +5 -3
  25. package/src/supabase/auth/removeCustomClaims.ts +10 -5
  26. package/src/supabase/auth/setCustomClaims.ts +9 -4
  27. package/src/supabase/baseFunction.ts +77 -22
  28. package/src/supabase/billing/cancelSubscription.ts +9 -3
  29. package/src/supabase/billing/changePlan.ts +20 -5
  30. package/src/supabase/billing/createCheckoutSession.ts +20 -5
  31. package/src/supabase/billing/createCustomerPortal.ts +14 -4
  32. package/src/supabase/billing/refreshSubscriptionStatus.ts +29 -9
  33. package/src/supabase/crud/aggregate.ts +14 -4
  34. package/src/supabase/crud/create.ts +30 -11
  35. package/src/supabase/crud/delete.ts +11 -3
  36. package/src/supabase/crud/get.ts +25 -3
  37. package/src/supabase/crud/list.ts +76 -22
  38. package/src/supabase/crud/update.ts +32 -10
  39. package/src/supabase/helpers/authProvider.ts +5 -2
  40. package/src/supabase/index.ts +1 -4
  41. package/src/supabase/registerCrudFunctions.ts +11 -9
  42. package/src/supabase/utils/idempotency.ts +13 -15
  43. package/src/supabase/utils/monitoring.ts +5 -1
  44. package/src/supabase/utils/rateLimiter.ts +13 -3
  45. package/src/vercel/api/billing/webhook-handler.ts +6 -2
  46. package/src/vercel/api/crud/create.ts +7 -2
  47. package/src/vercel/api/crud/delete.ts +3 -1
  48. package/src/vercel/api/crud/get.ts +3 -1
  49. package/src/vercel/api/crud/list.ts +3 -1
  50. package/src/vercel/api/crud/update.ts +7 -2
@@ -80,7 +80,10 @@ vi.mock('../../logger.js', () => ({
80
80
  // Reset idempotency store between tests so events are never pre-marked
81
81
  import { resetIdempotencyStore } from '../idempotency.js';
82
82
  import { processWebhook } from '../webhookHandler.js';
83
- import type { UpdateSubscriptionFn, WebhookAuthProvider } from '../webhookHandler.js';
83
+ import type {
84
+ UpdateSubscriptionFn,
85
+ WebhookAuthProvider,
86
+ } from '../webhookHandler.js';
84
87
 
85
88
  // ---------------------------------------------------------------------------
86
89
  // Shared test fixtures
@@ -217,15 +220,15 @@ describe('processWebhook — signature verification', () => {
217
220
  const stripe = {
218
221
  webhooks: {
219
222
  constructEvent: vi.fn(() => {
220
- throw new Error('No signatures found matching the expected signature');
223
+ throw new Error(
224
+ 'No signatures found matching the expected signature'
225
+ );
221
226
  }),
222
227
  },
223
228
  subscriptions: { retrieve: vi.fn() },
224
229
  };
225
230
 
226
- await expect(
227
- callProcessWebhook({ stripe })
228
- ).rejects.toThrow();
231
+ await expect(callProcessWebhook({ stripe })).rejects.toThrow();
229
232
  });
230
233
  });
231
234
 
@@ -260,7 +263,10 @@ describe('processWebhook — idempotency', () => {
260
263
  updateSubscription: updateSubscription2,
261
264
  });
262
265
 
263
- expect(result).toEqual({ success: true, message: 'Event already processed' });
266
+ expect(result).toEqual({
267
+ success: true,
268
+ message: 'Event already processed',
269
+ });
264
270
  expect(updateSubscription2).not.toHaveBeenCalled();
265
271
  });
266
272
 
@@ -279,8 +285,16 @@ describe('processWebhook — idempotency', () => {
279
285
  const updateSubscription1 = makeUpdateSubscription();
280
286
  const updateSubscription2 = makeUpdateSubscription();
281
287
 
282
- await callProcessWebhook({ stripe: makeStripe(event1), config, updateSubscription: updateSubscription1 });
283
- await callProcessWebhook({ stripe: makeStripe(event2), config, updateSubscription: updateSubscription2 });
288
+ await callProcessWebhook({
289
+ stripe: makeStripe(event1),
290
+ config,
291
+ updateSubscription: updateSubscription1,
292
+ });
293
+ await callProcessWebhook({
294
+ stripe: makeStripe(event2),
295
+ config,
296
+ updateSubscription: updateSubscription2,
297
+ });
284
298
 
285
299
  expect(updateSubscription1).toHaveBeenCalledTimes(1);
286
300
  expect(updateSubscription2).toHaveBeenCalledTimes(1);
@@ -349,7 +363,11 @@ describe('event routing — checkout.session.completed (StripeSubscription)', ()
349
363
  const config = makeConfig();
350
364
  const updateSubscription = makeUpdateSubscription();
351
365
 
352
- await callProcessWebhook({ stripe: makeStripe(event), config, updateSubscription });
366
+ await callProcessWebhook({
367
+ stripe: makeStripe(event),
368
+ config,
369
+ updateSubscription,
370
+ });
353
371
 
354
372
  expect(updateSubscription).toHaveBeenCalledOnce();
355
373
  const [userId, data] = (updateSubscription as any).mock.calls[0];
@@ -370,9 +388,16 @@ describe('event routing — checkout.session.completed (StripeSubscription)', ()
370
388
  customer: 'cus_hook',
371
389
  });
372
390
 
373
- await callProcessWebhook({ stripe: makeStripe(event), config, updateSubscription: makeUpdateSubscription() });
391
+ await callProcessWebhook({
392
+ stripe: makeStripe(event),
393
+ config,
394
+ updateSubscription: makeUpdateSubscription(),
395
+ });
374
396
 
375
- expect(onSubscriptionCreated).toHaveBeenCalledWith('u_hook', expect.any(Object));
397
+ expect(onSubscriptionCreated).toHaveBeenCalledWith(
398
+ 'u_hook',
399
+ expect.any(Object)
400
+ );
376
401
  });
377
402
 
378
403
  it('does NOT throw when onSubscriptionCreated hook throws (non-critical)', async () => {
@@ -387,7 +412,11 @@ describe('event routing — checkout.session.completed (StripeSubscription)', ()
387
412
  });
388
413
 
389
414
  await expect(
390
- callProcessWebhook({ stripe: makeStripe(event), config, updateSubscription: makeUpdateSubscription() })
415
+ callProcessWebhook({
416
+ stripe: makeStripe(event),
417
+ config,
418
+ updateSubscription: makeUpdateSubscription(),
419
+ })
391
420
  ).resolves.toEqual({ success: true, message: 'Webhook processed' });
392
421
  });
393
422
 
@@ -459,7 +488,11 @@ describe('event routing — checkout.session.completed (StripePayment)', () => {
459
488
  const config = makeConfig();
460
489
  const updateSubscription = makeUpdateSubscription();
461
490
 
462
- await callProcessWebhook({ stripe: makeStripe(event), config, updateSubscription });
491
+ await callProcessWebhook({
492
+ stripe: makeStripe(event),
493
+ config,
494
+ updateSubscription,
495
+ });
463
496
 
464
497
  expect(updateSubscription).toHaveBeenCalledOnce();
465
498
  const [userId, data] = (updateSubscription as any).mock.calls[0];
@@ -486,9 +519,16 @@ describe('event routing — checkout.session.completed (StripePayment)', () => {
486
519
  customer: 'cus_pay_hook',
487
520
  });
488
521
 
489
- await callProcessWebhook({ stripe: makeStripe(event), config, updateSubscription: makeUpdateSubscription() });
522
+ await callProcessWebhook({
523
+ stripe: makeStripe(event),
524
+ config,
525
+ updateSubscription: makeUpdateSubscription(),
526
+ });
490
527
 
491
- expect(onPurchaseSuccess).toHaveBeenCalledWith('u_pay_hook', expect.any(Object));
528
+ expect(onPurchaseSuccess).toHaveBeenCalledWith(
529
+ 'u_pay_hook',
530
+ expect.any(Object)
531
+ );
492
532
  });
493
533
 
494
534
  it('does NOT throw when onPurchaseSuccess hook throws (non-critical)', async () => {
@@ -509,7 +549,11 @@ describe('event routing — checkout.session.completed (StripePayment)', () => {
509
549
  });
510
550
 
511
551
  await expect(
512
- callProcessWebhook({ stripe: makeStripe(event), config, updateSubscription: makeUpdateSubscription() })
552
+ callProcessWebhook({
553
+ stripe: makeStripe(event),
554
+ config,
555
+ updateSubscription: makeUpdateSubscription(),
556
+ })
513
557
  ).resolves.toEqual({ success: true, message: 'Webhook processed' });
514
558
  });
515
559
  });
@@ -568,9 +612,16 @@ describe('event routing — invoice.payment_succeeded', () => {
568
612
  metadata: { userId: 'u_hook_renewal', billingConfigKey: 'pro_monthly' },
569
613
  }));
570
614
 
571
- await callProcessWebhook({ stripe, config, updateSubscription: makeUpdateSubscription() });
615
+ await callProcessWebhook({
616
+ stripe,
617
+ config,
618
+ updateSubscription: makeUpdateSubscription(),
619
+ });
572
620
 
573
- expect(onSubscriptionRenewed).toHaveBeenCalledWith('u_hook_renewal', expect.any(Object));
621
+ expect(onSubscriptionRenewed).toHaveBeenCalledWith(
622
+ 'u_hook_renewal',
623
+ expect.any(Object)
624
+ );
574
625
  });
575
626
 
576
627
  it('does NOT throw when onSubscriptionRenewed hook throws (non-critical)', async () => {
@@ -593,7 +644,11 @@ describe('event routing — invoice.payment_succeeded', () => {
593
644
  }));
594
645
 
595
646
  await expect(
596
- callProcessWebhook({ stripe, config, updateSubscription: makeUpdateSubscription() })
647
+ callProcessWebhook({
648
+ stripe,
649
+ config,
650
+ updateSubscription: makeUpdateSubscription(),
651
+ })
597
652
  ).resolves.toEqual({ success: true, message: 'Webhook processed' });
598
653
  });
599
654
 
@@ -647,7 +702,10 @@ describe('event routing — invoice.payment_succeeded', () => {
647
702
  const stripe = makeStripe(event);
648
703
  stripe.subscriptions.retrieve = vi.fn(async () => ({
649
704
  id: 'sub_payment_type',
650
- metadata: { userId: 'u_payment_type', billingConfigKey: 'lifetime_purchase' },
705
+ metadata: {
706
+ userId: 'u_payment_type',
707
+ billingConfigKey: 'lifetime_purchase',
708
+ },
651
709
  }));
652
710
  const updateSubscription = makeUpdateSubscription();
653
711
 
@@ -723,9 +781,16 @@ describe('event routing — customer.subscription.deleted', () => {
723
781
  };
724
782
  const event = makeEvent('customer.subscription.deleted', subscription);
725
783
 
726
- await callProcessWebhook({ stripe: makeStripe(event), config, updateSubscription: makeUpdateSubscription() });
784
+ await callProcessWebhook({
785
+ stripe: makeStripe(event),
786
+ config,
787
+ updateSubscription: makeUpdateSubscription(),
788
+ });
727
789
 
728
- expect(onSubscriptionCancelled).toHaveBeenCalledWith('u_cancel_hook', expect.any(Object));
790
+ expect(onSubscriptionCancelled).toHaveBeenCalledWith(
791
+ 'u_cancel_hook',
792
+ expect.any(Object)
793
+ );
729
794
  });
730
795
 
731
796
  it('does NOT throw when onSubscriptionCancelled hook throws (non-critical)', async () => {
@@ -744,7 +809,11 @@ describe('event routing — customer.subscription.deleted', () => {
744
809
  const event = makeEvent('customer.subscription.deleted', subscription);
745
810
 
746
811
  await expect(
747
- callProcessWebhook({ stripe: makeStripe(event), config, updateSubscription: makeUpdateSubscription() })
812
+ callProcessWebhook({
813
+ stripe: makeStripe(event),
814
+ config,
815
+ updateSubscription: makeUpdateSubscription(),
816
+ })
748
817
  ).resolves.toEqual({ success: true, message: 'Webhook processed' });
749
818
  });
750
819
 
@@ -776,7 +845,11 @@ describe('event routing — customer.subscription.deleted', () => {
776
845
  const event = makeEvent('customer.subscription.deleted', subscription);
777
846
  const updateSubscription = makeUpdateSubscription();
778
847
 
779
- await callProcessWebhook({ stripe: makeStripe(event), config, updateSubscription });
848
+ await callProcessWebhook({
849
+ stripe: makeStripe(event),
850
+ config,
851
+ updateSubscription,
852
+ });
780
853
 
781
854
  expect(updateSubscription).not.toHaveBeenCalled();
782
855
  });
@@ -824,7 +897,10 @@ describe('event routing — invoice.payment_failed', () => {
824
897
 
825
898
  await callProcessWebhook({ stripe: makeStripe(event), config });
826
899
 
827
- expect(onPurchaseFailure).toHaveBeenCalledWith('u_fail_pay', expect.any(Object));
900
+ expect(onPurchaseFailure).toHaveBeenCalledWith(
901
+ 'u_fail_pay',
902
+ expect.any(Object)
903
+ );
828
904
  });
829
905
 
830
906
  it('calls onPaymentFailed for StripeSubscription billing items', async () => {
@@ -839,7 +915,10 @@ describe('event routing — invoice.payment_failed', () => {
839
915
 
840
916
  await callProcessWebhook({ stripe: makeStripe(event), config });
841
917
 
842
- expect(onPaymentFailed).toHaveBeenCalledWith('u_fail_sub', expect.any(Object));
918
+ expect(onPaymentFailed).toHaveBeenCalledWith(
919
+ 'u_fail_sub',
920
+ expect.any(Object)
921
+ );
843
922
  });
844
923
 
845
924
  it('does NOT throw when onPurchaseFailure hook throws (non-critical)', async () => {
@@ -922,7 +1001,11 @@ describe('event routing — invoice.payment_failed', () => {
922
1001
  const event = makeEvent('invoice.payment_failed', invoice);
923
1002
  const updateSubscription = makeUpdateSubscription();
924
1003
 
925
- await callProcessWebhook({ stripe: makeStripe(event), config, updateSubscription });
1004
+ await callProcessWebhook({
1005
+ stripe: makeStripe(event),
1006
+ config,
1007
+ updateSubscription,
1008
+ });
926
1009
 
927
1010
  expect(updateSubscription).not.toHaveBeenCalled();
928
1011
  });
@@ -952,7 +1035,9 @@ describe('event routing — unknown event types', () => {
952
1035
  });
953
1036
 
954
1037
  it('handles payment_intent.succeeded gracefully (not in router)', async () => {
955
- const event = makeEvent('payment_intent.succeeded', { id: 'pi_not_routed' });
1038
+ const event = makeEvent('payment_intent.succeeded', {
1039
+ id: 'pi_not_routed',
1040
+ });
956
1041
 
957
1042
  const result = await callProcessWebhook({ stripe: makeStripe(event) });
958
1043
 
@@ -997,7 +1082,10 @@ describe('state machine transitions', () => {
997
1082
 
998
1083
  it('checkout.session.completed → status=active (StripePayment)', async () => {
999
1084
  const event = makeEvent('checkout.session.completed', {
1000
- metadata: { userId: 'u_sm_pay_active', billingConfigKey: 'lifetime_purchase' },
1085
+ metadata: {
1086
+ userId: 'u_sm_pay_active',
1087
+ billingConfigKey: 'lifetime_purchase',
1088
+ },
1001
1089
  subscription: null,
1002
1090
  customer: 'cus_sm_pay_active',
1003
1091
  });
@@ -1086,6 +1174,9 @@ describe('processWebhook — return value', () => {
1086
1174
  await callProcessWebhook({ stripe: makeStripe(event) });
1087
1175
  const result = await callProcessWebhook({ stripe: makeStripe(event) });
1088
1176
 
1089
- expect(result).toEqual({ success: true, message: 'Event already processed' });
1177
+ expect(result).toEqual({
1178
+ success: true,
1179
+ message: 'Event already processed',
1180
+ });
1090
1181
  });
1091
1182
  });
@@ -212,4 +212,4 @@ export function prepareForFirestore<T = any>(
212
212
 
213
213
  // Return primitive values unchanged
214
214
  return data;
215
- }
215
+ }
@@ -245,7 +245,13 @@ export const logger = {
245
245
  context,
246
246
  error: context?.error,
247
247
  metadata: {
248
- ...(_isNodeEnv ? { pid: process.pid, nodeVersion: process.version, platform: process.platform } : {}),
248
+ ...(_isNodeEnv
249
+ ? {
250
+ pid: process.pid,
251
+ nodeVersion: process.version,
252
+ platform: process.platform,
253
+ }
254
+ : {}),
249
255
  ...context?.metadata,
250
256
  },
251
257
  };
@@ -11,11 +11,11 @@
11
11
 
12
12
  import { describe, it, expect, vi } from 'vitest';
13
13
 
14
- import {
15
- exchangeTokenAlgorithm,
16
- type OAuthProvider,
17
- } from '../exchangeToken';
18
- import type { ExchangeTokenRequest, TokenResponse } from '@donotdev/core/server';
14
+ import { exchangeTokenAlgorithm, type OAuthProvider } from '../exchangeToken';
15
+ import type {
16
+ ExchangeTokenRequest,
17
+ TokenResponse,
18
+ } from '@donotdev/core/server';
19
19
 
20
20
  // ---------------------------------------------------------------------------
21
21
  // Helpers
@@ -94,9 +94,7 @@ describe('exchangeTokenAlgorithm', () => {
94
94
 
95
95
  describe('error scenarios', () => {
96
96
  it('re-throws errors from provider', async () => {
97
- const oauthProvider = makeRejectingProvider(
98
- new Error('invalid_grant')
99
- );
97
+ const oauthProvider = makeRejectingProvider(new Error('invalid_grant'));
100
98
 
101
99
  await expect(
102
100
  exchangeTokenAlgorithm(BASE_REQUEST, oauthProvider)
@@ -1,17 +1,15 @@
1
1
  import { describe, it, expect, vi, beforeEach } from 'vitest';
2
2
 
3
- import {
4
- grantAccessAlgorithm,
5
- type OAuthGrantProvider,
6
- } from '../grantAccess';
3
+ import { grantAccessAlgorithm, type OAuthGrantProvider } from '../grantAccess';
7
4
 
8
5
  // ---------------------------------------------------------------------------
9
6
  // Helpers
10
7
  // ---------------------------------------------------------------------------
11
8
 
12
- function makeProvider(
13
- result: { success: boolean; message: string }
14
- ): OAuthGrantProvider {
9
+ function makeProvider(result: {
10
+ success: boolean;
11
+ message: string;
12
+ }): OAuthGrantProvider {
15
13
  return { grantAccess: vi.fn().mockResolvedValue(result) };
16
14
  }
17
15
 
@@ -187,7 +185,10 @@ describe('grantAccessAlgorithm', () => {
187
185
  );
188
186
 
189
187
  expect(oauthProvider.grantAccess).toHaveBeenCalledWith(
190
- expect.objectContaining({ provider: providerName, accessToken: token })
188
+ expect.objectContaining({
189
+ provider: providerName,
190
+ accessToken: token,
191
+ })
191
192
  );
192
193
  }
193
194
  );
@@ -199,12 +200,16 @@ describe('grantAccessAlgorithm', () => {
199
200
 
200
201
  describe('error scenarios', () => {
201
202
  it('re-throws synchronous errors from provider', async () => {
202
- const oauthProvider = makeRejectingProvider(
203
- new Error('network failure')
204
- );
203
+ const oauthProvider = makeRejectingProvider(new Error('network failure'));
205
204
 
206
205
  await expect(
207
- grantAccessAlgorithm(userId, provider, accessToken, refreshToken, oauthProvider)
206
+ grantAccessAlgorithm(
207
+ userId,
208
+ provider,
209
+ accessToken,
210
+ refreshToken,
211
+ oauthProvider
212
+ )
208
213
  ).rejects.toThrow('network failure');
209
214
  });
210
215
 
@@ -220,7 +225,13 @@ describe('grantAccessAlgorithm', () => {
220
225
  const oauthProvider = makeRejectingProvider(originalError);
221
226
 
222
227
  await expect(
223
- grantAccessAlgorithm(userId, provider, accessToken, refreshToken, oauthProvider)
228
+ grantAccessAlgorithm(
229
+ userId,
230
+ provider,
231
+ accessToken,
232
+ refreshToken,
233
+ oauthProvider
234
+ )
224
235
  ).rejects.toThrow('token expired');
225
236
  });
226
237
 
@@ -228,7 +239,13 @@ describe('grantAccessAlgorithm', () => {
228
239
  const oauthProvider = makeRejectingProvider(new Error('boom'));
229
240
 
230
241
  await expect(
231
- grantAccessAlgorithm(userId, provider, accessToken, refreshToken, oauthProvider)
242
+ grantAccessAlgorithm(
243
+ userId,
244
+ provider,
245
+ accessToken,
246
+ refreshToken,
247
+ oauthProvider
248
+ )
232
249
  ).rejects.toThrow('boom');
233
250
 
234
251
  expect(oauthProvider.grantAccess).toHaveBeenCalledOnce();
@@ -74,7 +74,10 @@ export async function assertAdmin(uid: string): Promise<string> {
74
74
  } catch (error) {
75
75
  // C4: Re-throw permission-denied as-is so callers can distinguish it from
76
76
  // infrastructure failures. Only wrap genuine unexpected errors.
77
- if (error instanceof Error && error.message === 'Admin privileges required') {
77
+ if (
78
+ error instanceof Error &&
79
+ error.message === 'Admin privileges required'
80
+ ) {
78
81
  throw error;
79
82
  }
80
83
  throw new Error('Failed to verify admin status');
@@ -161,7 +164,8 @@ async function verifySupabaseToken(token: string): Promise<{ uid: string }> {
161
164
  const { createClient } = await import('@supabase/supabase-js');
162
165
 
163
166
  const supabaseUrl = process.env.SUPABASE_URL;
164
- const secretKey = process.env.SUPABASE_SECRET_KEY || process.env.SUPABASE_SERVICE_ROLE_KEY;
167
+ const secretKey =
168
+ process.env.SUPABASE_SECRET_KEY || process.env.SUPABASE_SERVICE_ROLE_KEY;
165
169
 
166
170
  if (!supabaseUrl || !secretKey) {
167
171
  throw new Error(
@@ -173,7 +177,10 @@ async function verifySupabaseToken(token: string): Promise<{ uid: string }> {
173
177
  auth: { autoRefreshToken: false, persistSession: false },
174
178
  });
175
179
 
176
- const { data: { user }, error } = await supabaseAdmin.auth.getUser(token);
180
+ const {
181
+ data: { user },
182
+ error,
183
+ } = await supabaseAdmin.auth.getUser(token);
177
184
 
178
185
  if (error || !user) {
179
186
  throw new Error('Invalid or expired token');
@@ -12,7 +12,10 @@
12
12
  import { logger } from 'firebase-functions/v2';
13
13
 
14
14
  import { getFirebaseAdminFirestore } from '@donotdev/firebase/server';
15
- import type { ServerRateLimitConfig as RateLimitConfig, ServerRateLimitResult as RateLimitResult } from '@donotdev/core';
15
+ import type {
16
+ ServerRateLimitConfig as RateLimitConfig,
17
+ ServerRateLimitResult as RateLimitResult,
18
+ } from '@donotdev/core';
16
19
 
17
20
  export type { RateLimitConfig, RateLimitResult };
18
21
 
@@ -204,7 +207,10 @@ export async function checkRateLimitWithFirestore(
204
207
  }
205
208
 
206
209
  // Increment attempts
207
- tx.update(rateLimitRef, { attempts: data.attempts + 1, lastUpdated: now });
210
+ tx.update(rateLimitRef, {
211
+ attempts: data.attempts + 1,
212
+ lastUpdated: now,
213
+ });
208
214
  result = {
209
215
  allowed: true,
210
216
  remaining: config.maxAttempts - (data.attempts + 1),
@@ -439,7 +439,11 @@ export async function findReferences(
439
439
  }>;
440
440
  }
441
441
  ): Promise<Array<{ collection: string; field: string; count: number }>> {
442
- const references: Array<{ collection: string; field: string; count: number }> = [];
442
+ const references: Array<{
443
+ collection: string;
444
+ field: string;
445
+ count: number;
446
+ }> = [];
443
447
 
444
448
  if (!referenceMetadata?.incoming?.length) {
445
449
  return references;
@@ -47,6 +47,6 @@ export function createDeleteAccount() {
47
47
  if (error) throw error;
48
48
 
49
49
  return { success: true };
50
- },
50
+ }
51
51
  );
52
52
  }
@@ -43,14 +43,16 @@ export function createGetCustomClaims() {
43
43
  'get-custom-claims',
44
44
  getCustomClaimsSchema,
45
45
  async (_data, ctx) => {
46
- const { data: { user }, error } =
47
- await ctx.supabaseAdmin.auth.admin.getUserById(ctx.uid);
46
+ const {
47
+ data: { user },
48
+ error,
49
+ } = await ctx.supabaseAdmin.auth.admin.getUserById(ctx.uid);
48
50
  if (error || !user) {
49
51
  throw new Error('User not found');
50
52
  }
51
53
 
52
54
  return { customClaims: user.app_metadata ?? {} };
53
55
  },
54
- 'user',
56
+ 'user'
55
57
  );
56
58
  }
@@ -45,8 +45,10 @@ export function createGetUserAuthStatus() {
45
45
  'get-user-auth-status',
46
46
  getUserAuthStatusSchema,
47
47
  async (_data, ctx) => {
48
- const { data: { user }, error } =
49
- await ctx.supabaseAdmin.auth.admin.getUserById(ctx.uid);
48
+ const {
49
+ data: { user },
50
+ error,
51
+ } = await ctx.supabaseAdmin.auth.admin.getUserById(ctx.uid);
50
52
  if (error || !user) {
51
53
  throw new Error('User not found');
52
54
  }
@@ -59,6 +61,6 @@ export function createGetUserAuthStatus() {
59
61
  disabled: user.banned_until != null,
60
62
  };
61
63
  },
62
- 'user',
64
+ 'user'
63
65
  );
64
66
  }
@@ -20,7 +20,7 @@ import { createSupabaseHandler } from '../baseFunction.js';
20
20
  const removeCustomClaimsSchema = v.object({
21
21
  claimsToRemove: v.pipe(
22
22
  v.array(v.string()),
23
- v.minLength(1, 'At least one claim key is required'),
23
+ v.minLength(1, 'At least one claim key is required')
24
24
  ),
25
25
  });
26
26
 
@@ -49,14 +49,19 @@ export function createRemoveCustomClaims() {
49
49
  removeCustomClaimsSchema,
50
50
  async (data, ctx) => {
51
51
  // Get current app_metadata
52
- const { data: { user }, error: getUserError } =
53
- await ctx.supabaseAdmin.auth.admin.getUserById(ctx.uid);
52
+ const {
53
+ data: { user },
54
+ error: getUserError,
55
+ } = await ctx.supabaseAdmin.auth.admin.getUserById(ctx.uid);
54
56
  if (getUserError || !user) {
55
57
  throw new Error('User not found');
56
58
  }
57
59
 
58
60
  // Remove specified keys
59
- const existingClaims = { ...(user.app_metadata ?? {}) } as Record<string, unknown>;
61
+ const existingClaims = { ...(user.app_metadata ?? {}) } as Record<
62
+ string,
63
+ unknown
64
+ >;
60
65
  for (const key of data.claimsToRemove) {
61
66
  delete existingClaims[key];
62
67
  }
@@ -70,6 +75,6 @@ export function createRemoveCustomClaims() {
70
75
 
71
76
  return { success: true, customClaims: existingClaims };
72
77
  },
73
- 'user',
78
+ 'user'
74
79
  );
75
80
  }
@@ -49,14 +49,19 @@ export function createSetCustomClaims() {
49
49
  setCustomClaimsSchema,
50
50
  async (data, ctx) => {
51
51
  // Get current app_metadata
52
- const { data: { user }, error: getUserError } =
53
- await ctx.supabaseAdmin.auth.admin.getUserById(ctx.uid);
52
+ const {
53
+ data: { user },
54
+ error: getUserError,
55
+ } = await ctx.supabaseAdmin.auth.admin.getUserById(ctx.uid);
54
56
  if (getUserError || !user) {
55
57
  throw new Error('User not found');
56
58
  }
57
59
 
58
60
  // Merge new claims with existing app_metadata
59
- const existingClaims = (user.app_metadata ?? {}) as Record<string, unknown>;
61
+ const existingClaims = (user.app_metadata ?? {}) as Record<
62
+ string,
63
+ unknown
64
+ >;
60
65
  const updatedClaims = { ...existingClaims, ...data.customClaims };
61
66
 
62
67
  // Update app_metadata
@@ -68,6 +73,6 @@ export function createSetCustomClaims() {
68
73
 
69
74
  return { success: true, customClaims: updatedClaims };
70
75
  },
71
- 'user',
76
+ 'user'
72
77
  );
73
78
  }