@powerhousedao/contributor-billing 0.1.15 → 0.1.17

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.
@@ -7,7 +7,7 @@ import { getCountryCodeFromName } from "./utils/utils.js";
7
7
  import { LoaderCircle } from "lucide-react";
8
8
  let GRAPHQL_URL = "http://localhost:4001/graphql/invoice";
9
9
  if (!window.document.baseURI.includes("localhost")) {
10
- GRAPHQL_URL = "https://jetstream.powerhouse.io/api/graphql/invoice";
10
+ GRAPHQL_URL = "https://switchboard-staging.powerhouse.xyz/graphql/invoice";
11
11
  }
12
12
  export async function loadPDFFile({ file, dispatch, }) {
13
13
  if (!file)
@@ -1 +1 @@
1
- {"version":3,"file":"invoiceToGnosis.d.ts","sourceRoot":"","sources":["../../../editors/invoice/invoiceToGnosis.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA8B,MAAM,OAAO,CAAC;AAGnD,OAAO,KAAK,EACV,aAAa,EACb,YAAY,EACb,MAAM,wCAAwC,CAAC;AAQhD,UAAU,oBAAoB;IAC5B,QAAQ,EAAE,YAAY,CAAC;IACvB,QAAQ,EAAE,KAAK,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC;CACzC;AAED,QAAA,MAAM,eAAe,EAAE,KAAK,CAAC,EAAE,CAAC,oBAAoB,CAgRnD,CAAC;AAEF,eAAe,eAAe,CAAC"}
1
+ {"version":3,"file":"invoiceToGnosis.d.ts","sourceRoot":"","sources":["../../../editors/invoice/invoiceToGnosis.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA8B,MAAM,OAAO,CAAC;AAGnD,OAAO,KAAK,EACV,aAAa,EACb,YAAY,EACb,MAAM,wCAAwC,CAAC;AAQhD,UAAU,oBAAoB;IAC5B,QAAQ,EAAE,YAAY,CAAC;IACvB,QAAQ,EAAE,KAAK,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC;CACzC;AAED,QAAA,MAAM,eAAe,EAAE,KAAK,CAAC,EAAE,CAAC,oBAAoB,CA2RnD,CAAC;AAEF,eAAe,eAAe,CAAC"}
@@ -1,10 +1,10 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
- import { useState, useEffect } from "react";
2
+ import React, { useState, useEffect } from "react";
3
3
  import { actions } from "../../document-models/invoice/index.js";
4
4
  import { generateId } from "document-model";
5
5
  let GRAPHQL_URL = "http://localhost:4001/graphql/invoice";
6
- if (!window.document.baseURI.includes("localhost")) {
7
- GRAPHQL_URL = "https://jetstream.powerhouse.io/api/graphql/invoice";
6
+ if (!window.document.baseURI.includes('localhost')) {
7
+ GRAPHQL_URL = 'https://switchboard-staging.powerhouse.xyz/graphql/invoice';
8
8
  }
9
9
  const InvoiceToGnosis = ({ docState, dispatch, }) => {
10
10
  const [isLoading, setIsLoading] = useState(false);
@@ -12,6 +12,8 @@ const InvoiceToGnosis = ({ docState, dispatch, }) => {
12
12
  const [invoiceStatusResponse, setInvoiceStatusResponse] = useState(null);
13
13
  const [safeTxHash, setsafeTxHash] = useState(null);
14
14
  const [safeAddress, setSafeAddress] = useState(null);
15
+ // Use ref to prevent race conditions from rapid clicks
16
+ const isProcessingRef = React.useRef(false);
15
17
  const currency = docState.currency;
16
18
  const chainName = docState.issuer?.paymentRouting?.wallet?.chainName || "";
17
19
  const invoiceStatus = docState.status;
@@ -74,6 +76,12 @@ const InvoiceToGnosis = ({ docState, dispatch, }) => {
74
76
  return tokenAddress;
75
77
  }
76
78
  const handleInvoiceToGnosis = async () => {
79
+ // Prevent concurrent calls using ref (faster than state update)
80
+ if (isProcessingRef.current) {
81
+ console.log("Payment request already in progress, ignoring duplicate click");
82
+ return;
83
+ }
84
+ isProcessingRef.current = true;
77
85
  setIsLoading(true);
78
86
  setError(null);
79
87
  try {
@@ -138,9 +146,11 @@ const InvoiceToGnosis = ({ docState, dispatch, }) => {
138
146
  }));
139
147
  }
140
148
  setIsLoading(false);
149
+ isProcessingRef.current = false;
141
150
  }
142
151
  catch (error) {
143
152
  setIsLoading(false);
153
+ isProcessingRef.current = false;
144
154
  console.error("Error during transfer:", error);
145
155
  dispatch(actions.addPayment({
146
156
  id: generateId(),
@@ -3,8 +3,8 @@ import { useState } from "react";
3
3
  import { actions } from "../../document-models/invoice/index.js";
4
4
  import { generateId } from "document-model";
5
5
  let GRAPHQL_URL = "http://localhost:4001/graphql/invoice";
6
- if (!window.document.baseURI.includes("localhost")) {
7
- GRAPHQL_URL = "https://jetstream.powerhouse.io/api/graphql/invoice";
6
+ if (!window.document.baseURI.includes('localhost')) {
7
+ GRAPHQL_URL = 'https://switchboard-staging.powerhouse.xyz/graphql/invoice';
8
8
  }
9
9
  const RequestFinance = ({ docState, dispatch, }) => {
10
10
  const [isLoading, setIsLoading] = useState(false);
@@ -7,7 +7,7 @@
7
7
  */
8
8
  let GRAPHQL_URL = 'http://localhost:4001/graphql/invoice';
9
9
  if (!window.document.baseURI.includes('localhost')) {
10
- GRAPHQL_URL = "https://jetstream.powerhouse.io/api/graphql/invoice";
10
+ GRAPHQL_URL = 'https://switchboard-staging.powerhouse.xyz/graphql/invoice';
11
11
  }
12
12
  export async function uploadPdfChunked(pdfData, endpoint = GRAPHQL_URL, chunkSize = 500 * 1024, // 500KB chunks
13
13
  onProgress) {
@@ -1 +1 @@
1
- {"version":3,"file":"gnosisTransactionBuilder.d.ts","sourceRoot":"","sources":["../../../scripts/invoice/gnosisTransactionBuilder.ts"],"names":[],"mappings":"AASA,MAAM,WAAW,WAAW;IAC1B,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,aAAa;IAC5B,WAAW,EAAE,WAAW,CAAC;IACzB,KAAK,EAAE,SAAS,CAAC;IACjB,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,IAAI,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,aAAa,EAAE,CAAC;CACjC;AA6BD,iBAAe,uBAAuB,CACpC,SAAS,EAAE,MAAM,EACjB,mBAAmB,EAAE,aAAa,GAAG,aAAa,EAAE,GACnD,OAAO,CAAC,cAAc,CAAC,CA6FzB;AAED,OAAO,EAAE,uBAAuB,EAAE,CAAA"}
1
+ {"version":3,"file":"gnosisTransactionBuilder.d.ts","sourceRoot":"","sources":["../../../scripts/invoice/gnosisTransactionBuilder.ts"],"names":[],"mappings":"AASA,MAAM,WAAW,WAAW;IAC1B,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,aAAa;IAC5B,WAAW,EAAE,WAAW,CAAC;IACzB,KAAK,EAAE,SAAS,CAAC;IACjB,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,IAAI,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,aAAa,EAAE,CAAC;CACjC;AA6DD,iBAAe,uBAAuB,CACpC,SAAS,EAAE,MAAM,EACjB,mBAAmB,EAAE,aAAa,GAAG,aAAa,EAAE,GACnD,OAAO,CAAC,cAAc,CAAC,CA2GzB;AAED,OAAO,EAAE,uBAAuB,EAAE,CAAA"}
@@ -28,6 +28,31 @@ const payerWallets = {
28
28
  address: safeAddress, // Safe address
29
29
  },
30
30
  };
31
+ /**
32
+ * Retry helper with exponential backoff for Safe API calls
33
+ * Handles rate limiting (429 errors) and temporary failures
34
+ */
35
+ async function withRetry(fn, maxRetries = 3, initialDelay = 1000, operationName = "API call") {
36
+ for (let attempt = 0; attempt < maxRetries; attempt++) {
37
+ try {
38
+ return await fn();
39
+ }
40
+ catch (error) {
41
+ const isRateLimit = error?.message?.includes('Too Many Requests') ||
42
+ error?.message?.includes('429') ||
43
+ error?.status === 429;
44
+ if (isRateLimit && attempt < maxRetries - 1) {
45
+ const waitTime = initialDelay * Math.pow(2, attempt); // Exponential backoff
46
+ console.log(`[${operationName}] Rate limited, retrying in ${waitTime}ms... (attempt ${attempt + 1}/${maxRetries})`);
47
+ await new Promise(resolve => setTimeout(resolve, waitTime));
48
+ continue;
49
+ }
50
+ // If it's not a rate limit error, or we've exhausted retries, throw
51
+ throw error;
52
+ }
53
+ }
54
+ throw new Error(`${operationName}: Max retries (${maxRetries}) exceeded`);
55
+ }
31
56
  // --- Implementation ---
32
57
  async function executeTransferProposal(chainName, paymentDetailsInput) {
33
58
  const payerWallet = payerWallets[chainName.toUpperCase()];
@@ -47,9 +72,11 @@ async function executeTransferProposal(chainName, paymentDetailsInput) {
47
72
  // Safe API and Protocol Kit instances
48
73
  // @ts-ignore - Ignoring constructor error as per requirements
49
74
  const safeApiKit = new SafeApiKit({
50
- chainId: Number(payerWallet.chainId),
75
+ chainId: BigInt(payerWallet.chainId),
76
+ apiKey: process.env.SAFE_API_KEY
51
77
  });
52
- const nextNonce = await safeApiKit.getNextNonce(safeAddress);
78
+ // Get next nonce with retry logic for rate limiting
79
+ const nextNonce = await withRetry(() => safeApiKit.getNextNonce(safeAddress), 3, 1000, "getNextNonce");
53
80
  console.log("Next Nonce: ", nextNonce);
54
81
  // @ts-ignore - Ignoring constructor error as per requirements
55
82
  const protocolKit = await Safe.init({
@@ -89,13 +116,15 @@ async function executeTransferProposal(chainName, paymentDetailsInput) {
89
116
  console.log('\n=== Signing & proposing ===');
90
117
  const safeTxHash = await protocolKit.getTransactionHash(safeTx);
91
118
  const signature = await protocolKit.signHash(safeTxHash);
92
- await safeApiKit.proposeTransaction({
119
+ const senderAddress = await signer.getAddress();
120
+ // Propose transaction with retry logic for rate limiting
121
+ await withRetry(async () => safeApiKit.proposeTransaction({
93
122
  safeAddress: payerWallet.address,
94
123
  safeTransactionData: safeTx.data,
95
124
  safeTxHash,
96
- senderAddress: await signer.getAddress(),
125
+ senderAddress,
97
126
  senderSignature: signature.data,
98
- });
127
+ }), 3, 1000, "proposeTransaction");
99
128
  return {
100
129
  success: true,
101
130
  txHash: safeTxHash,
package/dist/style.css CHANGED
@@ -6488,7 +6488,7 @@ input[type="number"] {
6488
6488
  }
6489
6489
  }
6490
6490
  }
6491
- /*! tailwindcss v4.1.5 | MIT License | https://tailwindcss.com */
6491
+ /*! tailwindcss v4.1.14 | MIT License | https://tailwindcss.com */
6492
6492
  @import url("https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap");
6493
6493
  @layer properties;
6494
6494
  @layer theme, base, components, utilities;
@@ -6765,6 +6765,9 @@ input[type="number"] {
6765
6765
  ::-webkit-datetime-edit, ::-webkit-datetime-edit-year-field, ::-webkit-datetime-edit-month-field, ::-webkit-datetime-edit-day-field, ::-webkit-datetime-edit-hour-field, ::-webkit-datetime-edit-minute-field, ::-webkit-datetime-edit-second-field, ::-webkit-datetime-edit-millisecond-field, ::-webkit-datetime-edit-meridiem-field {
6766
6766
  padding-block: 0;
6767
6767
  }
6768
+ ::-webkit-calendar-picker-indicator {
6769
+ line-height: 1;
6770
+ }
6768
6771
  :-moz-ui-invalid {
6769
6772
  box-shadow: none;
6770
6773
  }
@@ -7623,7 +7626,7 @@ input[type="number"] {
7623
7626
  border-radius: 100px;
7624
7627
  }
7625
7628
  .rounded-full {
7626
- border-radius: calc(infinity * 1px);
7629
+ border-radius: calc(infinity * 1px) !important;
7627
7630
  }
7628
7631
  .rounded-lg {
7629
7632
  border-radius: var(--radius-lg);
@@ -8451,7 +8454,7 @@ input[type="number"] {
8451
8454
  filter: var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,);
8452
8455
  }
8453
8456
  .transition {
8454
- transition-property: color, background-color, border-color, outline-color, text-decoration-color, fill, stroke, --tw-gradient-from, --tw-gradient-via, --tw-gradient-to, opacity, box-shadow, transform, translate, scale, rotate, filter, -webkit-backdrop-filter, backdrop-filter, display, visibility, content-visibility, overlay, pointer-events;
8457
+ transition-property: color, background-color, border-color, outline-color, text-decoration-color, fill, stroke, --tw-gradient-from, --tw-gradient-via, --tw-gradient-to, opacity, box-shadow, transform, translate, scale, rotate, filter, -webkit-backdrop-filter, backdrop-filter, display, content-visibility, overlay, pointer-events;
8455
8458
  transition-timing-function: var(--tw-ease, var(--default-transition-timing-function));
8456
8459
  transition-duration: var(--tw-duration, var(--default-transition-duration));
8457
8460
  }
@@ -8638,7 +8641,7 @@ input[type="number"] {
8638
8641
  }
8639
8642
  .file\:rounded-full {
8640
8643
  &::file-selector-button {
8641
- border-radius: calc(infinity * 1px);
8644
+ border-radius: calc(infinity * 1px) !important;
8642
8645
  }
8643
8646
  }
8644
8647
  .file\:border-0 {
@@ -8733,7 +8736,7 @@ input[type="number"] {
8733
8736
  .before\:rounded-full {
8734
8737
  &::before {
8735
8738
  content: var(--tw-content);
8736
- border-radius: calc(infinity * 1px);
8739
+ border-radius: calc(infinity * 1px) !important;
8737
8740
  }
8738
8741
  }
8739
8742
  .before\:bg-blue-900 {
@@ -8854,7 +8857,7 @@ input[type="number"] {
8854
8857
  .after\:rounded-full {
8855
8858
  &::after {
8856
8859
  content: var(--tw-content);
8857
- border-radius: calc(infinity * 1px);
8860
+ border-radius: calc(infinity * 1px) !important;
8858
8861
  }
8859
8862
  }
8860
8863
  .after\:bg-gray-300 {
@@ -8877,7 +8880,6 @@ input[type="number"] {
8877
8880
  }
8878
8881
  .after\:content-\[\'\'\] {
8879
8882
  &::after {
8880
- content: var(--tw-content);
8881
8883
  --tw-content: '';
8882
8884
  content: var(--tw-content);
8883
8885
  }
@@ -10749,7 +10751,7 @@ input[type="number"] {
10749
10751
  }
10750
10752
  .\[\&_\.date-picker\\\\_\\\\_button-next\]\:rounded-full {
10751
10753
  & .date-picker\_\_button-next {
10752
- border-radius: calc(infinity * 1px);
10754
+ border-radius: calc(infinity * 1px) !important;
10753
10755
  }
10754
10756
  }
10755
10757
  .\[\&_\.date-picker\\\\_\\\\_button-next\]\:border-2 {
@@ -10865,7 +10867,7 @@ input[type="number"] {
10865
10867
  }
10866
10868
  .\[\&_\.date-picker\\\\_\\\\_button-previous\]\:rounded-full {
10867
10869
  & .date-picker\_\_button-previous {
10868
- border-radius: calc(infinity * 1px);
10870
+ border-radius: calc(infinity * 1px) !important;
10869
10871
  }
10870
10872
  }
10871
10873
  .\[\&_\.date-picker\\\\_\\\\_button-previous\]\:border-2 {
@@ -11037,7 +11039,7 @@ input[type="number"] {
11037
11039
  }
11038
11040
  .\[\&_\.date-picker\\\\_\\\\_day-button\]\:rounded-full {
11039
11041
  & .date-picker\_\_day-button {
11040
- border-radius: calc(infinity * 1px);
11042
+ border-radius: calc(infinity * 1px) !important;
11041
11043
  }
11042
11044
  }
11043
11045
  .\[\&_\.date-picker\\\\_\\\\_day-button\]\:font-medium {
@@ -11387,7 +11389,7 @@ input[type="number"] {
11387
11389
  }
11388
11390
  .\[\&_\.date-picker\\\\_\\\\_today\]\:rounded-full {
11389
11391
  & .date-picker\_\_today {
11390
- border-radius: calc(infinity * 1px);
11392
+ border-radius: calc(infinity * 1px) !important;
11391
11393
  }
11392
11394
  }
11393
11395
  .\[\&_\.date-picker\\\\_\\\\_today\]\:border-2 {
@@ -11653,7 +11655,7 @@ input[type="number"] {
11653
11655
  }
11654
11656
  .\[\&_\.radio-group\\\\_\\\\_item\]\:rounded-full {
11655
11657
  & .radio-group\_\_item {
11656
- border-radius: calc(infinity * 1px);
11658
+ border-radius: calc(infinity * 1px) !important;
11657
11659
  }
11658
11660
  }
11659
11661
  .\[\&_\.radio-group\\\\_\\\\_item\]\:text-cyan-400 {
@@ -12545,7 +12547,7 @@ input[type="number"] {
12545
12547
  .\[\&_\.date-picker\\\\_\\\\_date-footer\]\:\[\&\>button\]\:rounded-full {
12546
12548
  & .date-picker\_\_date-footer {
12547
12549
  &>button {
12548
- border-radius: calc(infinity * 1px);
12550
+ border-radius: calc(infinity * 1px) !important;
12549
12551
  }
12550
12552
  }
12551
12553
  }
@@ -13162,7 +13164,7 @@ input[type="number"] {
13162
13164
  }
13163
13165
  }
13164
13166
  }
13165
- /*! tailwindcss v4.1.5 | MIT License | https://tailwindcss.com */
13167
+ /*! tailwindcss v4.1.14 | MIT License | https://tailwindcss.com */
13166
13168
  @import url("https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap");
13167
13169
  @layer properties;
13168
13170
  @layer theme, base, components, utilities;
@@ -13439,6 +13441,9 @@ input[type="number"] {
13439
13441
  ::-webkit-datetime-edit, ::-webkit-datetime-edit-year-field, ::-webkit-datetime-edit-month-field, ::-webkit-datetime-edit-day-field, ::-webkit-datetime-edit-hour-field, ::-webkit-datetime-edit-minute-field, ::-webkit-datetime-edit-second-field, ::-webkit-datetime-edit-millisecond-field, ::-webkit-datetime-edit-meridiem-field {
13440
13442
  padding-block: 0;
13441
13443
  }
13444
+ ::-webkit-calendar-picker-indicator {
13445
+ line-height: 1;
13446
+ }
13442
13447
  :-moz-ui-invalid {
13443
13448
  box-shadow: none;
13444
13449
  }
@@ -14297,7 +14302,7 @@ input[type="number"] {
14297
14302
  border-radius: 100px;
14298
14303
  }
14299
14304
  .rounded-full {
14300
- border-radius: calc(infinity * 1px);
14305
+ border-radius: calc(infinity * 1px) !important;
14301
14306
  }
14302
14307
  .rounded-lg {
14303
14308
  border-radius: var(--radius-lg);
@@ -15125,7 +15130,7 @@ input[type="number"] {
15125
15130
  filter: var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,);
15126
15131
  }
15127
15132
  .transition {
15128
- transition-property: color, background-color, border-color, outline-color, text-decoration-color, fill, stroke, --tw-gradient-from, --tw-gradient-via, --tw-gradient-to, opacity, box-shadow, transform, translate, scale, rotate, filter, -webkit-backdrop-filter, backdrop-filter, display, visibility, content-visibility, overlay, pointer-events;
15133
+ transition-property: color, background-color, border-color, outline-color, text-decoration-color, fill, stroke, --tw-gradient-from, --tw-gradient-via, --tw-gradient-to, opacity, box-shadow, transform, translate, scale, rotate, filter, -webkit-backdrop-filter, backdrop-filter, display, content-visibility, overlay, pointer-events;
15129
15134
  transition-timing-function: var(--tw-ease, var(--default-transition-timing-function));
15130
15135
  transition-duration: var(--tw-duration, var(--default-transition-duration));
15131
15136
  }
@@ -15312,7 +15317,7 @@ input[type="number"] {
15312
15317
  }
15313
15318
  .file\:rounded-full {
15314
15319
  &::file-selector-button {
15315
- border-radius: calc(infinity * 1px);
15320
+ border-radius: calc(infinity * 1px) !important;
15316
15321
  }
15317
15322
  }
15318
15323
  .file\:border-0 {
@@ -15407,7 +15412,7 @@ input[type="number"] {
15407
15412
  .before\:rounded-full {
15408
15413
  &::before {
15409
15414
  content: var(--tw-content);
15410
- border-radius: calc(infinity * 1px);
15415
+ border-radius: calc(infinity * 1px) !important;
15411
15416
  }
15412
15417
  }
15413
15418
  .before\:bg-blue-900 {
@@ -15528,7 +15533,7 @@ input[type="number"] {
15528
15533
  .after\:rounded-full {
15529
15534
  &::after {
15530
15535
  content: var(--tw-content);
15531
- border-radius: calc(infinity * 1px);
15536
+ border-radius: calc(infinity * 1px) !important;
15532
15537
  }
15533
15538
  }
15534
15539
  .after\:bg-gray-300 {
@@ -15551,7 +15556,6 @@ input[type="number"] {
15551
15556
  }
15552
15557
  .after\:content-\[\'\'\] {
15553
15558
  &::after {
15554
- content: var(--tw-content);
15555
15559
  --tw-content: '';
15556
15560
  content: var(--tw-content);
15557
15561
  }
@@ -17423,7 +17427,7 @@ input[type="number"] {
17423
17427
  }
17424
17428
  .\[\&_\.date-picker\\\\_\\\\_button-next\]\:rounded-full {
17425
17429
  & .date-picker\_\_button-next {
17426
- border-radius: calc(infinity * 1px);
17430
+ border-radius: calc(infinity * 1px) !important;
17427
17431
  }
17428
17432
  }
17429
17433
  .\[\&_\.date-picker\\\\_\\\\_button-next\]\:border-2 {
@@ -17539,7 +17543,7 @@ input[type="number"] {
17539
17543
  }
17540
17544
  .\[\&_\.date-picker\\\\_\\\\_button-previous\]\:rounded-full {
17541
17545
  & .date-picker\_\_button-previous {
17542
- border-radius: calc(infinity * 1px);
17546
+ border-radius: calc(infinity * 1px) !important;
17543
17547
  }
17544
17548
  }
17545
17549
  .\[\&_\.date-picker\\\\_\\\\_button-previous\]\:border-2 {
@@ -17711,7 +17715,7 @@ input[type="number"] {
17711
17715
  }
17712
17716
  .\[\&_\.date-picker\\\\_\\\\_day-button\]\:rounded-full {
17713
17717
  & .date-picker\_\_day-button {
17714
- border-radius: calc(infinity * 1px);
17718
+ border-radius: calc(infinity * 1px) !important;
17715
17719
  }
17716
17720
  }
17717
17721
  .\[\&_\.date-picker\\\\_\\\\_day-button\]\:font-medium {
@@ -18061,7 +18065,7 @@ input[type="number"] {
18061
18065
  }
18062
18066
  .\[\&_\.date-picker\\\\_\\\\_today\]\:rounded-full {
18063
18067
  & .date-picker\_\_today {
18064
- border-radius: calc(infinity * 1px);
18068
+ border-radius: calc(infinity * 1px) !important;
18065
18069
  }
18066
18070
  }
18067
18071
  .\[\&_\.date-picker\\\\_\\\\_today\]\:border-2 {
@@ -18327,7 +18331,7 @@ input[type="number"] {
18327
18331
  }
18328
18332
  .\[\&_\.radio-group\\\\_\\\\_item\]\:rounded-full {
18329
18333
  & .radio-group\_\_item {
18330
- border-radius: calc(infinity * 1px);
18334
+ border-radius: calc(infinity * 1px) !important;
18331
18335
  }
18332
18336
  }
18333
18337
  .\[\&_\.radio-group\\\\_\\\\_item\]\:text-cyan-400 {
@@ -19219,7 +19223,7 @@ input[type="number"] {
19219
19223
  .\[\&_\.date-picker\\\\_\\\\_date-footer\]\:\[\&\>button\]\:rounded-full {
19220
19224
  & .date-picker\_\_date-footer {
19221
19225
  &>button {
19222
- border-radius: calc(infinity * 1px);
19226
+ border-radius: calc(infinity * 1px) !important;
19223
19227
  }
19224
19228
  }
19225
19229
  }
@@ -11,15 +11,7 @@ interface UploadInvoicePdfChunkArgs {
11
11
  fileName: string;
12
12
  sessionId: string;
13
13
  }
14
- export declare const Invoice_processGnosisPayment: (_: any, args: any) => Promise<{
15
- success: boolean;
16
- data: import("../../scripts/invoice/gnosisTransactionBuilder.js").TransferResult;
17
- error?: undefined;
18
- } | {
19
- success: boolean;
20
- error: string;
21
- data?: undefined;
22
- }>;
14
+ export declare const Invoice_processGnosisPayment: (_: any, args: any) => Promise<any>;
23
15
  export declare const Invoice_createRequestFinancePayment: (_: any, args: any) => Promise<{
24
16
  success: boolean;
25
17
  error: any;
@@ -1 +1 @@
1
- {"version":3,"file":"customResolvers.d.ts","sourceRoot":"","sources":["../../../subgraphs/invoice/customResolvers.ts"],"names":[],"mappings":"AAOA,QAAA,IAAI,mBAAmB,EAAE,MAAM,CAAC,MAAM,EAAE;IACpC,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,GAAG,CAAC;IACpB,SAAS,EAAE,MAAM,CAAA;CACpB,CAAM,CAAC;AAKR,UAAU,yBAAyB;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;CACrB;AAaD,eAAO,MAAM,4BAA4B,GAAU,GAAG,GAAG,EAAE,MAAM,GAAG;;;;;;;;EA8CnE,CAAC;AAEF,eAAO,MAAM,mCAAmC,GAAU,GAAG,GAAG,EAAE,MAAM,GAAG;;;;;;;;;;;EAkC1E,CAAA;AAED,eAAO,MAAM,6BAA6B,GAAU,GAAG,GAAG,EAAE,MAAM,yBAAyB;;;;;;;;;;;;;;;;;;;;;;EA8E1F,CAAA;AAGD,eAAO,MAAM,UAAU,GAAI,iBAAiB,GAAG,SAE9C,CAAC;AAGF,OAAO,EAAE,mBAAmB,EAAE,CAAC;AAG/B,eAAO,MAAM,6BAA6B,YAyBzC,CAAA;AAwCD,eAAO,MAAM,aAAa,GAAU,KAAK,GAAG,EAAE,KAAK,GAAG,iBAkJrD,CAAA"}
1
+ {"version":3,"file":"customResolvers.d.ts","sourceRoot":"","sources":["../../../subgraphs/invoice/customResolvers.ts"],"names":[],"mappings":"AAOA,QAAA,IAAI,mBAAmB,EAAE,MAAM,CAAC,MAAM,EAAE;IACpC,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,GAAG,CAAC;IACpB,SAAS,EAAE,MAAM,CAAA;CACpB,CAAM,CAAC;AAQR,UAAU,yBAAyB;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;CACrB;AAaD,eAAO,MAAM,4BAA4B,GAAU,GAAG,GAAG,EAAE,MAAM,GAAG,iBAwEnE,CAAC;AAEF,eAAO,MAAM,mCAAmC,GAAU,GAAG,GAAG,EAAE,MAAM,GAAG;;;;;;;;;;;EAkC1E,CAAA;AAED,eAAO,MAAM,6BAA6B,GAAU,GAAG,GAAG,EAAE,MAAM,yBAAyB;;;;;;;;;;;;;;;;;;;;;;EA8E1F,CAAA;AAGD,eAAO,MAAM,UAAU,GAAI,iBAAiB,GAAG,SAE9C,CAAC;AAGF,OAAO,EAAE,mBAAmB,EAAE,CAAC;AAG/B,eAAO,MAAM,6BAA6B,YAyBzC,CAAA;AAwCD,eAAO,MAAM,aAAa,GAAU,KAAK,GAAG,EAAE,KAAK,GAAG,iBAkJrD,CAAA"}
@@ -7,43 +7,71 @@ import * as crypto from "crypto";
7
7
  let pendingTransactions = {};
8
8
  // Add a set to track processed transaction hashes to avoid duplicate processing
9
9
  let processedTransactions = new Set();
10
+ // Track in-flight payment requests to prevent concurrent processing of the same invoice
11
+ const inFlightPayments = new Map();
10
12
  // Create a Map to store file chunks data
11
13
  const fileChunksMap = new Map();
12
14
  let reactor;
13
15
  export const Invoice_processGnosisPayment = async (_, args) => {
14
16
  try {
15
17
  const { chainName, paymentDetails, invoiceNo } = args;
16
- // Cast payerWallet to any to access its properties
17
18
  console.log("Processing gnosis payment:", {
18
19
  chainName,
19
20
  invoiceNo,
20
21
  paymentDetails
21
22
  });
22
- // Import and call the executeTransferProposal function
23
- const result = await executeTransferProposal(chainName, paymentDetails);
24
- console.log("Token transfer result:", result);
25
- // Store the transaction information for later matching with webhook
26
- if (result.success && result.txHash) {
27
- // Generate a unique ID for this transaction
28
- const transactionId = `gnosis-${invoiceNo}-${Date.now()}`;
29
- // Store the transaction with all the details needed for matching
30
- pendingTransactions[transactionId] = {
31
- invoiceNo,
32
- chainName,
33
- paymentDetails,
34
- timestamp: Date.now()
35
- };
36
- console.log(`Stored pending transaction ${transactionId} for invoice ${invoiceNo}`);
23
+ // Check if there's already a payment request in progress for this invoice
24
+ const paymentKey = `payment-${invoiceNo}`;
25
+ if (inFlightPayments.has(paymentKey)) {
26
+ console.log(`Payment request already in progress for invoice ${invoiceNo}, returning existing promise`);
27
+ return await inFlightPayments.get(paymentKey);
37
28
  }
38
- // Return the result without updating the document status yet
39
- // The status will be updated when the webhook confirms the transaction
40
- return {
41
- success: true,
42
- data: result,
43
- };
29
+ // Create a promise for this payment request
30
+ const paymentPromise = (async () => {
31
+ try {
32
+ // Import and call the executeTransferProposal function
33
+ const result = await executeTransferProposal(chainName, paymentDetails);
34
+ console.log("Token transfer result:", result);
35
+ // Store the transaction information for later matching with webhook
36
+ if (result.success && result.txHash) {
37
+ // Generate a unique ID for this transaction
38
+ const transactionId = `gnosis-${invoiceNo}-${Date.now()}`;
39
+ // Store the transaction with all the details needed for matching
40
+ pendingTransactions[transactionId] = {
41
+ invoiceNo,
42
+ chainName,
43
+ paymentDetails,
44
+ timestamp: Date.now()
45
+ };
46
+ console.log(`Stored pending transaction ${transactionId} for invoice ${invoiceNo}`);
47
+ }
48
+ // Return the result without updating the document status yet
49
+ // The status will be updated when the webhook confirms the transaction
50
+ return {
51
+ success: true,
52
+ data: result,
53
+ };
54
+ }
55
+ catch (error) {
56
+ console.error("Error processing gnosis payment:", error);
57
+ return {
58
+ success: false,
59
+ error: error instanceof Error ? error.message : "Unknown error",
60
+ };
61
+ }
62
+ finally {
63
+ // Remove from in-flight payments when done (success or error)
64
+ inFlightPayments.delete(paymentKey);
65
+ console.log(`Removed payment request for invoice ${invoiceNo} from in-flight tracking`);
66
+ }
67
+ })();
68
+ // Store the promise to prevent concurrent requests
69
+ inFlightPayments.set(paymentKey, paymentPromise);
70
+ // Wait for the payment to complete
71
+ return await paymentPromise;
44
72
  }
45
73
  catch (error) {
46
- console.error("Error processing gnosis payment:", error);
74
+ console.error("Error in Invoice_processGnosisPayment wrapper:", error);
47
75
  return {
48
76
  success: false,
49
77
  error: error instanceof Error ? error.message : "Unknown error",
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@powerhousedao/contributor-billing",
3
3
  "description": "Document models that help contributors of open organisations get paid anonymously for their work on a monthly basis.",
4
- "version": "0.1.15",
4
+ "version": "0.1.17",
5
5
  "license": "AGPL-3.0-only",
6
6
  "type": "module",
7
7
  "files": [
@@ -61,7 +61,7 @@
61
61
  "@powerhousedao/design-system": "^5.0.0-staging.30",
62
62
  "@powerhousedao/document-engineering": "1.39.0",
63
63
  "@react-pdf/renderer": "^4.3.0",
64
- "@safe-global/api-kit": "^3.0.1",
64
+ "@safe-global/api-kit": "^4.0.0",
65
65
  "@safe-global/protocol-kit": "^6.0.3",
66
66
  "@safe-global/sdk-starter-kit": "^2.0.2",
67
67
  "@safe-global/types-kit": "^2.0.1",
@@ -97,6 +97,7 @@
97
97
  "@testing-library/react": "^16.3.0",
98
98
  "@types/node": "^22.14.1",
99
99
  "@types/react": "^18.3.20",
100
+ "@types/react-dom": "^19.2.2",
100
101
  "@vitejs/plugin-react": "^4.4.1",
101
102
  "document-drive": "^5.0.0-staging.30",
102
103
  "eslint": "^9.25.0",
@@ -118,4 +119,4 @@
118
119
  "react": "^18.3.1",
119
120
  "react-dom": "^18.3.1"
120
121
  }
121
- }
122
+ }