opticedge-cloud-utils 1.1.14 → 1.1.16

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/.eslintignore CHANGED
@@ -1,2 +1,2 @@
1
- # Ignore compiled output
2
- dist/
1
+ # Ignore compiled output
2
+ dist/
package/.prettierignore CHANGED
@@ -1,4 +1,4 @@
1
- node_modules
2
- dist
3
- build
4
- coverage
1
+ node_modules
2
+ dist
3
+ build
4
+ coverage
@@ -1 +1 @@
1
- export declare function pregenerateInAppWallet(projectId: string, twClientId: string, twSecretKeyName: string, email: string): Promise<string | null>;
1
+ export declare function pregenerateInAppWallet(twClientId: string, twSecretKey: string, email: string): Promise<string | null>;
package/dist/tw/wallet.js CHANGED
@@ -4,21 +4,20 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.pregenerateInAppWallet = pregenerateInAppWallet;
7
+ // src/tw/wallet.ts
7
8
  const axios_1 = __importDefault(require("axios"));
8
- const secrets_1 = require("../secrets");
9
9
  const retry_1 = require("../retry");
10
- async function pregenerateInAppWallet(projectId, twClientId, twSecretKeyName, email) {
11
- const TW_SECRET_KEY = await (0, secrets_1.getSecret)(projectId, twSecretKeyName);
12
- if (!TW_SECRET_KEY) {
13
- console.error('Missing TW secret key', { projectId, twSecretKeyName });
10
+ async function pregenerateInAppWallet(twClientId, twSecretKey, email) {
11
+ if (!twClientId || !twSecretKey || !email) {
12
+ console.error('Missing client id or secret or email');
14
13
  return null;
15
14
  }
16
15
  const doRequest = async () => {
17
16
  const res = await axios_1.default.post('https://in-app-wallet.thirdweb.com/api/v1/pregenerate', { strategy: 'email', email }, {
18
17
  headers: {
19
- 'x-secret-key': TW_SECRET_KEY,
18
+ 'Content-Type': 'application/json',
20
19
  'x-client-id': twClientId,
21
- 'Content-Type': 'application/json'
20
+ 'x-secret-key': twSecretKey
22
21
  },
23
22
  timeout: 10000
24
23
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opticedge-cloud-utils",
3
- "version": "1.1.14",
3
+ "version": "1.1.16",
4
4
  "description": "Common utilities for cloud functions",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -20,7 +20,7 @@
20
20
  "@google-cloud/tasks": "^6.1.0",
21
21
  "axios": "^1.10.0",
22
22
  "google-auth-library": "^9.15.1",
23
- "mongodb": "^6.16.0"
23
+ "mongodb": "^7.0.0"
24
24
  },
25
25
  "devDependencies": {
26
26
  "@google-cloud/functions-framework": "^4.0.0",
package/src/tw/wallet.ts CHANGED
@@ -1,16 +1,14 @@
1
+ // src/tw/wallet.ts
1
2
  import axios from 'axios'
2
- import { getSecret } from '../secrets'
3
3
  import { isRetryableAxios, retry, RetryOptions } from '../retry'
4
4
 
5
5
  export async function pregenerateInAppWallet(
6
- projectId: string,
7
6
  twClientId: string,
8
- twSecretKeyName: string,
7
+ twSecretKey: string,
9
8
  email: string
10
9
  ): Promise<string | null> {
11
- const TW_SECRET_KEY = await getSecret(projectId, twSecretKeyName)
12
- if (!TW_SECRET_KEY) {
13
- console.error('Missing TW secret key', { projectId, twSecretKeyName })
10
+ if (!twClientId || !twSecretKey || !email) {
11
+ console.error('Missing client id or secret or email')
14
12
  return null
15
13
  }
16
14
 
@@ -20,9 +18,9 @@ export async function pregenerateInAppWallet(
20
18
  { strategy: 'email', email },
21
19
  {
22
20
  headers: {
23
- 'x-secret-key': TW_SECRET_KEY,
21
+ 'Content-Type': 'application/json',
24
22
  'x-client-id': twClientId,
25
- 'Content-Type': 'application/json'
23
+ 'x-secret-key': twSecretKey
26
24
  },
27
25
  timeout: 10000
28
26
  }
@@ -1,42 +1,35 @@
1
+ // tests/tw/wallet.test.ts
1
2
  /* eslint-disable @typescript-eslint/no-explicit-any */
2
- // tests/wallet.test.ts (or append to your existing test file)
3
3
  import axios from 'axios'
4
4
  import { pregenerateInAppWallet } from '../../src/tw/wallet'
5
- import * as secrets from '../../src/secrets'
6
5
 
7
6
  jest.mock('axios')
8
- jest.mock('../../src/secrets')
9
-
10
7
  const mockedAxios = axios as jest.Mocked<typeof axios>
11
- const mockedGetSecret = secrets.getSecret as jest.Mock
12
-
13
- const makeSuccessResponse = (data: any) => ({ data, status: 200 })
14
8
 
15
- // small helper to synthesize axios-like errors
16
9
  function makeAxiosError(message: string, status?: number, noResponse = false) {
17
10
  const err: any = new Error(message)
18
11
  err.isAxiosError = true
19
12
  if (!noResponse) {
20
- if (typeof status === 'number') {
21
- err.response = { status, data: { message: `mocked ${status}` } }
22
- } else {
23
- // no numeric status provided but simulate a response
24
- err.response = { status: 500, data: { message: 'mock' } }
13
+ err.response = {
14
+ status: typeof status === 'number' ? status : 500,
15
+ data: { message: `mocked ${status ?? 500}` }
25
16
  }
26
17
  } else {
27
- // explicitly simulate network error: no response property
18
+ // simulate network error (no response)
28
19
  delete err.response
29
20
  }
30
21
  return err
31
22
  }
32
23
 
33
- describe('pregenerateInAppWallet with retry behavior', () => {
34
- const mockProjectId = 'test-project'
24
+ function makeSuccessResponse(data: any) {
25
+ return { data, status: 200 }
26
+ }
27
+
28
+ describe('pregenerateInAppWallet (current signature)', () => {
35
29
  const mockClientId = 'test-client-id'
36
- const mockSecretKeyName = 'test-key'
30
+ const mockSecretKey = 'test-secret-key'
37
31
  const mockEmail = 'user@example.com'
38
32
  const mockWalletAddress = '0xabc123'
39
- const mockSecretValue = 'mock-secret-key'
40
33
 
41
34
  const realMathRandom = Math.random
42
35
  const realWarn = console.warn
@@ -44,162 +37,93 @@ describe('pregenerateInAppWallet with retry behavior', () => {
44
37
 
45
38
  beforeEach(() => {
46
39
  jest.clearAllMocks()
47
- // make retry jitter deterministic (so delay becomes 0)
40
+ // make retry jitter deterministic (so delays don't interfere)
48
41
  Math.random = jest.fn(() => 0)
49
42
 
43
+ // axios.isAxiosError helper
50
44
  jest
51
45
  .spyOn(axios, 'isAxiosError')
52
46
  .mockImplementation((e: any) => Boolean(e && e.isAxiosError) as any)
53
- // silence console.warn/error in passing tests (but still allow spying)
47
+
48
+ // silence logs during tests but keep spies
54
49
  console.warn = jest.fn()
55
50
  console.error = jest.fn()
56
51
  })
57
52
 
58
53
  afterEach(() => {
59
- // restore
60
54
  Math.random = realMathRandom
61
55
  console.warn = realWarn
62
56
  console.error = realError
63
57
  })
64
58
 
65
- it('returns null and logs if secret is missing', async () => {
66
- // simulate secret manager returning nothing
67
- mockedGetSecret.mockResolvedValueOnce(undefined)
68
-
69
- const result = await pregenerateInAppWallet(
70
- mockProjectId,
71
- mockClientId,
72
- mockSecretKeyName,
73
- mockEmail
74
- )
75
-
76
- // should not call axios at all
59
+ it('returns null and logs if params missing', async () => {
60
+ const res = await pregenerateInAppWallet('', mockSecretKey, mockEmail)
77
61
  expect(mockedAxios.post).not.toHaveBeenCalled()
78
- expect(result).toBeNull()
79
-
80
- // console.error should be called with "Missing TW secret key"
62
+ expect(res).toBeNull()
81
63
  expect((console.error as jest.Mock).mock.calls.length).toBeGreaterThanOrEqual(1)
82
- expect((console.error as jest.Mock).mock.calls[0][0]).toEqual('Missing TW secret key')
83
- // second arg should contain the projectId and secretName
84
- expect((console.error as jest.Mock).mock.calls[0][1]).toEqual(
85
- expect.objectContaining({ projectId: mockProjectId, twSecretKeyName: mockSecretKeyName })
64
+ expect((console.error as jest.Mock).mock.calls[0][0]).toEqual(
65
+ 'Missing client id or secret or email'
86
66
  )
87
67
  })
88
68
 
89
69
  it('retries on 500 then succeeds and returns address', async () => {
90
- mockedGetSecret.mockResolvedValue(mockSecretValue)
91
-
92
- // first call: server 500 -> rejected
70
+ // first: 500, then success
93
71
  mockedAxios.post
94
72
  .mockRejectedValueOnce(makeAxiosError('server error', 500))
95
- // second call: success
96
- .mockResolvedValueOnce({
97
- data: {
98
- wallet: { address: mockWalletAddress }
99
- }
100
- } as any)
101
-
102
- const result = await pregenerateInAppWallet(
103
- mockProjectId,
104
- mockClientId,
105
- mockSecretKeyName,
106
- mockEmail
107
- )
73
+ .mockResolvedValueOnce({ data: { wallet: { address: mockWalletAddress } } } as any)
74
+
75
+ const result = await pregenerateInAppWallet(mockClientId, mockSecretKey, mockEmail)
108
76
 
109
- expect(mockedGetSecret).toHaveBeenCalledWith(mockProjectId, mockSecretKeyName)
110
77
  expect(mockedAxios.post).toHaveBeenCalledTimes(2)
111
78
  expect(result).toBe(mockWalletAddress)
112
- // onRetry should have been called (we log via console.warn in our version)
113
79
  expect((console.warn as jest.Mock).mock.calls.length).toBeGreaterThanOrEqual(1)
114
80
  })
115
81
 
116
82
  it('does NOT retry on 400 and returns null immediately', async () => {
117
- mockedGetSecret.mockResolvedValue(mockSecretValue)
118
83
  mockedAxios.post.mockRejectedValue(makeAxiosError('bad request', 400))
119
84
 
120
- const result = await pregenerateInAppWallet(
121
- mockProjectId,
122
- mockClientId,
123
- mockSecretKeyName,
124
- mockEmail
125
- )
85
+ const result = await pregenerateInAppWallet(mockClientId, mockSecretKey, mockEmail)
126
86
 
127
87
  expect(mockedAxios.post).toHaveBeenCalledTimes(1)
128
88
  expect(result).toBeNull()
129
- // console.warn should not indicate retry
89
+ // no retry log
130
90
  expect((console.warn as jest.Mock).mock.calls.length).toBe(0)
131
91
  })
132
92
 
133
93
  it('retries on network/no-response errors and then succeeds', async () => {
134
- mockedGetSecret.mockResolvedValue(mockSecretValue)
135
-
136
- // First: network error (no response)
137
94
  mockedAxios.post
138
95
  .mockRejectedValueOnce(makeAxiosError('network down', undefined, true))
139
- .mockResolvedValueOnce({
140
- data: { wallet: { address: mockWalletAddress } }
141
- } as any)
142
-
143
- const result = await pregenerateInAppWallet(
144
- mockProjectId,
145
- mockClientId,
146
- mockSecretKeyName,
147
- mockEmail
148
- )
96
+ .mockResolvedValueOnce({ data: { wallet: { address: mockWalletAddress } } } as any)
97
+
98
+ const result = await pregenerateInAppWallet(mockClientId, mockSecretKey, mockEmail)
149
99
 
150
100
  expect(mockedAxios.post).toHaveBeenCalledTimes(2)
151
101
  expect(result).toBe(mockWalletAddress)
152
102
  })
153
103
 
154
104
  it('exhausts retries on repeated 500s and returns null', async () => {
155
- mockedGetSecret.mockResolvedValue(mockSecretValue)
156
-
157
- // Always 500 errors
158
105
  mockedAxios.post.mockRejectedValue(makeAxiosError('server error', 500))
159
106
 
160
- const result = await pregenerateInAppWallet(
161
- mockProjectId,
162
- mockClientId,
163
- mockSecretKeyName,
164
- mockEmail
165
- )
107
+ const result = await pregenerateInAppWallet(mockClientId, mockSecretKey, mockEmail)
166
108
 
167
- // retry attempts are implementation-dependent (your retry opts). We assert >1 calls
109
+ // retry behavior is implementation-dependent; assert at least one call and final null
168
110
  expect(mockedAxios.post.mock.calls.length).toBeGreaterThanOrEqual(1)
169
- // final result should be null when retries exhausted
170
111
  expect(result).toBeNull()
171
- // error should have been logged
172
112
  expect((console.error as jest.Mock).mock.calls.length).toBeGreaterThanOrEqual(1)
173
113
  })
174
114
 
175
- it('logs invalid wallet shape and returns null when wallet.address is missing (2xx response)', async () => {
176
- mockedGetSecret.mockResolvedValueOnce(mockSecretValue)
177
-
178
- // Simulate a 200 response that has wallet but no address
115
+ it('logs invalid wallet shape and returns null when wallet.address missing (2xx response)', async () => {
179
116
  mockedAxios.post.mockResolvedValueOnce(makeSuccessResponse({ wallet: {} }))
180
117
 
181
- const result = await pregenerateInAppWallet(
182
- mockProjectId,
183
- mockClientId,
184
- mockSecretKeyName,
185
- mockEmail
186
- )
118
+ const result = await pregenerateInAppWallet(mockClientId, mockSecretKey, mockEmail)
187
119
 
188
- // axios was called once, but the function returns null (final failure)
189
120
  expect(mockedAxios.post).toHaveBeenCalledTimes(1)
190
121
  expect(result).toBeNull()
191
122
 
192
- // console.error should be called with the shape error message
123
+ // ensure we logged the invalid shape (the implementation logs then throws)
193
124
  expect((console.error as jest.Mock).mock.calls.length).toBeGreaterThanOrEqual(1)
194
-
195
- // the first arg of the logged call should be the string we log in the implementation
196
- // (adjust if your message differs)
197
125
  const firstArg = (console.error as jest.Mock).mock.calls[0][0]
198
- expect(firstArg).toEqual(
199
- 'Invalid wallet response shape' /* or 'Invalid wallet response shape' */
200
- )
201
-
202
- // the second arg should contain status and data info
126
+ expect(firstArg).toEqual('Invalid wallet response shape')
203
127
  const secondArg = (console.error as jest.Mock).mock.calls[0][1]
204
128
  expect(secondArg).toEqual(expect.objectContaining({ status: 200, data: { wallet: {} } }))
205
129
  })