@taruvi/sdk 1.5.0 → 1.5.1

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 (229) hide show
  1. package/README.md +60 -1289
  2. package/dist/client.d.ts +27 -0
  3. package/dist/client.d.ts.map +1 -0
  4. package/{src/client.ts → dist/client.js} +30 -48
  5. package/dist/client.js.map +1 -0
  6. package/dist/index.d.ts +28 -0
  7. package/dist/index.d.ts.map +1 -0
  8. package/dist/index.js +20 -0
  9. package/dist/index.js.map +1 -0
  10. package/dist/lib/analytics/AnalyticsClient.d.ts +9 -0
  11. package/dist/lib/analytics/AnalyticsClient.d.ts.map +1 -0
  12. package/dist/lib/analytics/AnalyticsClient.js +17 -0
  13. package/dist/lib/analytics/AnalyticsClient.js.map +1 -0
  14. package/dist/lib/analytics/types.d.ts +6 -0
  15. package/dist/lib/analytics/types.d.ts.map +1 -0
  16. package/dist/lib/analytics/types.js +2 -0
  17. package/dist/lib/analytics/types.js.map +1 -0
  18. package/dist/lib/app/AppClient.d.ts +15 -0
  19. package/dist/lib/app/AppClient.d.ts.map +1 -0
  20. package/dist/lib/app/AppClient.js +41 -0
  21. package/dist/lib/app/AppClient.js.map +1 -0
  22. package/dist/lib/app/types.d.ts +41 -0
  23. package/dist/lib/app/types.d.ts.map +1 -0
  24. package/dist/lib/app/types.js +2 -0
  25. package/dist/lib/app/types.js.map +1 -0
  26. package/dist/lib/auth/AuthClient.d.ts +47 -0
  27. package/dist/lib/auth/AuthClient.d.ts.map +1 -0
  28. package/{src/lib/auth/AuthClient.ts → dist/lib/auth/AuthClient.js} +58 -79
  29. package/dist/lib/auth/AuthClient.js.map +1 -0
  30. package/dist/lib/database/DatabaseClient.d.ts +76 -0
  31. package/dist/lib/database/DatabaseClient.d.ts.map +1 -0
  32. package/dist/lib/database/DatabaseClient.js +250 -0
  33. package/dist/lib/database/DatabaseClient.js.map +1 -0
  34. package/dist/lib/database/types.d.ts +66 -0
  35. package/dist/lib/database/types.d.ts.map +1 -0
  36. package/dist/lib/database/types.js +20 -0
  37. package/dist/lib/database/types.js.map +1 -0
  38. package/dist/lib/functions/FunctionsClient.d.ts +9 -0
  39. package/dist/lib/functions/FunctionsClient.d.ts.map +1 -0
  40. package/dist/lib/functions/FunctionsClient.js +20 -0
  41. package/dist/lib/functions/FunctionsClient.js.map +1 -0
  42. package/dist/lib/functions/types.d.ts +25 -0
  43. package/dist/lib/functions/types.d.ts.map +1 -0
  44. package/dist/lib/functions/types.js +2 -0
  45. package/dist/lib/functions/types.js.map +1 -0
  46. package/dist/lib/policy/PolicyClient.d.ts +25 -0
  47. package/dist/lib/policy/PolicyClient.d.ts.map +1 -0
  48. package/{src/lib/policy/PolicyClient.ts → dist/lib/policy/PolicyClient.js} +26 -40
  49. package/dist/lib/policy/PolicyClient.js.map +1 -0
  50. package/dist/lib/policy/types.d.ts +32 -0
  51. package/dist/lib/policy/types.d.ts.map +1 -0
  52. package/dist/lib/policy/types.js +2 -0
  53. package/dist/lib/policy/types.js.map +1 -0
  54. package/dist/lib/secrets/SecretsClient.d.ts +29 -0
  55. package/dist/lib/secrets/SecretsClient.d.ts.map +1 -0
  56. package/dist/lib/secrets/SecretsClient.js +66 -0
  57. package/dist/lib/secrets/SecretsClient.js.map +1 -0
  58. package/dist/lib/secrets/types.d.ts +43 -0
  59. package/dist/lib/secrets/types.d.ts.map +1 -0
  60. package/dist/lib/secrets/types.js +2 -0
  61. package/dist/lib/secrets/types.js.map +1 -0
  62. package/dist/lib/settings/SettingsClient.d.ts +9 -0
  63. package/dist/lib/settings/SettingsClient.d.ts.map +1 -0
  64. package/dist/lib/settings/SettingsClient.js +17 -0
  65. package/dist/lib/settings/SettingsClient.js.map +1 -0
  66. package/dist/lib/settings/types.d.ts +6 -0
  67. package/dist/lib/settings/types.d.ts.map +1 -0
  68. package/dist/lib/settings/types.js +2 -0
  69. package/dist/lib/settings/types.js.map +1 -0
  70. package/dist/lib/storage/StorageClient.d.ts +38 -0
  71. package/dist/lib/storage/StorageClient.d.ts.map +1 -0
  72. package/dist/lib/storage/StorageClient.js +102 -0
  73. package/dist/lib/storage/StorageClient.js.map +1 -0
  74. package/dist/lib/storage/types.d.ts +73 -0
  75. package/dist/lib/storage/types.d.ts.map +1 -0
  76. package/dist/lib/storage/types.js +2 -0
  77. package/dist/lib/storage/types.js.map +1 -0
  78. package/dist/lib/users/UserClient.d.ts +17 -0
  79. package/dist/lib/users/UserClient.d.ts.map +1 -0
  80. package/dist/lib/users/UserClient.js +40 -0
  81. package/dist/lib/users/UserClient.js.map +1 -0
  82. package/dist/lib/users/types.d.ts +108 -0
  83. package/dist/lib/users/types.d.ts.map +1 -0
  84. package/dist/lib/users/types.js +2 -0
  85. package/dist/lib/users/types.js.map +1 -0
  86. package/dist/lib-internal/errors/ErrorClient.d.ts +42 -0
  87. package/dist/lib-internal/errors/ErrorClient.d.ts.map +1 -0
  88. package/dist/lib-internal/errors/ErrorClient.js +102 -0
  89. package/dist/lib-internal/errors/ErrorClient.js.map +1 -0
  90. package/dist/lib-internal/errors/index.d.ts +4 -0
  91. package/dist/lib-internal/errors/index.d.ts.map +1 -0
  92. package/dist/lib-internal/errors/index.js +3 -0
  93. package/dist/lib-internal/errors/index.js.map +1 -0
  94. package/dist/lib-internal/errors/types.d.ts +29 -0
  95. package/dist/lib-internal/errors/types.d.ts.map +1 -0
  96. package/dist/lib-internal/errors/types.js +18 -0
  97. package/dist/lib-internal/errors/types.js.map +1 -0
  98. package/dist/lib-internal/http/HttpClient.d.ts +24 -0
  99. package/dist/lib-internal/http/HttpClient.d.ts.map +1 -0
  100. package/dist/lib-internal/http/HttpClient.js +103 -0
  101. package/dist/lib-internal/http/HttpClient.js.map +1 -0
  102. package/dist/lib-internal/http/types.d.ts +12 -0
  103. package/dist/lib-internal/http/types.d.ts.map +1 -0
  104. package/{src/lib-internal/http/types.ts → dist/lib-internal/http/types.js} +2 -3
  105. package/dist/lib-internal/http/types.js.map +1 -0
  106. package/dist/lib-internal/routes/AnalyticsRoutes.d.ts +4 -0
  107. package/dist/lib-internal/routes/AnalyticsRoutes.d.ts.map +1 -0
  108. package/dist/lib-internal/routes/AnalyticsRoutes.js +4 -0
  109. package/dist/lib-internal/routes/AnalyticsRoutes.js.map +1 -0
  110. package/dist/lib-internal/routes/AppRoutes.d.ts +10 -0
  111. package/dist/lib-internal/routes/AppRoutes.d.ts.map +1 -0
  112. package/dist/lib-internal/routes/AppRoutes.js +6 -0
  113. package/dist/lib-internal/routes/AppRoutes.js.map +1 -0
  114. package/dist/lib-internal/routes/AuthRoutes.d.ts +4 -0
  115. package/dist/lib-internal/routes/AuthRoutes.d.ts.map +1 -0
  116. package/{src/lib-internal/routes/AuthRoutes.ts → dist/lib-internal/routes/AuthRoutes.js} +2 -1
  117. package/dist/lib-internal/routes/AuthRoutes.js.map +1 -0
  118. package/dist/lib-internal/routes/DatabaseRoutes.d.ts +11 -0
  119. package/dist/lib-internal/routes/DatabaseRoutes.d.ts.map +1 -0
  120. package/dist/lib-internal/routes/DatabaseRoutes.js +7 -0
  121. package/dist/lib-internal/routes/DatabaseRoutes.js.map +1 -0
  122. package/dist/lib-internal/routes/FunctionRoutes.d.ts +4 -0
  123. package/dist/lib-internal/routes/FunctionRoutes.d.ts.map +1 -0
  124. package/dist/lib-internal/routes/FunctionRoutes.js +4 -0
  125. package/dist/lib-internal/routes/FunctionRoutes.js.map +1 -0
  126. package/dist/lib-internal/routes/PolicyRoutes.d.ts +5 -0
  127. package/dist/lib-internal/routes/PolicyRoutes.d.ts.map +1 -0
  128. package/dist/lib-internal/routes/PolicyRoutes.js +5 -0
  129. package/dist/lib-internal/routes/PolicyRoutes.js.map +1 -0
  130. package/dist/lib-internal/routes/SecretsRoutes.d.ts +6 -0
  131. package/dist/lib-internal/routes/SecretsRoutes.d.ts.map +1 -0
  132. package/dist/lib-internal/routes/SecretsRoutes.js +6 -0
  133. package/dist/lib-internal/routes/SecretsRoutes.js.map +1 -0
  134. package/dist/lib-internal/routes/SettingsRoutes.d.ts +5 -0
  135. package/dist/lib-internal/routes/SettingsRoutes.d.ts.map +1 -0
  136. package/{src/lib-internal/routes/SettingsRoutes.ts → dist/lib-internal/routes/SettingsRoutes.js} +2 -1
  137. package/dist/lib-internal/routes/SettingsRoutes.js.map +1 -0
  138. package/dist/lib-internal/routes/StorageRoutes.d.ts +11 -0
  139. package/dist/lib-internal/routes/StorageRoutes.d.ts.map +1 -0
  140. package/dist/lib-internal/routes/StorageRoutes.js +8 -0
  141. package/dist/lib-internal/routes/StorageRoutes.js.map +1 -0
  142. package/dist/lib-internal/routes/UserRoutes.d.ts +13 -0
  143. package/dist/lib-internal/routes/UserRoutes.d.ts.map +1 -0
  144. package/dist/lib-internal/routes/UserRoutes.js +13 -0
  145. package/dist/lib-internal/routes/UserRoutes.js.map +1 -0
  146. package/dist/lib-internal/routes/index.d.ts +2 -0
  147. package/dist/lib-internal/routes/index.d.ts.map +1 -0
  148. package/dist/lib-internal/routes/index.js +2 -0
  149. package/dist/lib-internal/routes/index.js.map +1 -0
  150. package/dist/lib-internal/token/TokenClient.d.ts +38 -0
  151. package/dist/lib-internal/token/TokenClient.d.ts.map +1 -0
  152. package/{src/lib-internal/token/TokenClient.ts → dist/lib-internal/token/TokenClient.js} +44 -59
  153. package/dist/lib-internal/token/TokenClient.js.map +1 -0
  154. package/dist/lib-internal/token/types.d.ts +2 -0
  155. package/dist/lib-internal/token/types.d.ts.map +1 -0
  156. package/dist/lib-internal/token/types.js +2 -0
  157. package/dist/lib-internal/token/types.js.map +1 -0
  158. package/dist/types.d.ts +74 -0
  159. package/dist/types.d.ts.map +1 -0
  160. package/dist/types.js +2 -0
  161. package/dist/types.js.map +1 -0
  162. package/dist/utils/enums.d.ts +31 -0
  163. package/dist/utils/enums.d.ts.map +1 -0
  164. package/dist/utils/enums.js +26 -0
  165. package/dist/utils/enums.js.map +1 -0
  166. package/dist/utils/utils.d.ts +6 -0
  167. package/dist/utils/utils.d.ts.map +1 -0
  168. package/dist/utils/utils.js +38 -0
  169. package/dist/utils/utils.js.map +1 -0
  170. package/package.json +11 -2
  171. package/.github/worflows/publish.yml +0 -57
  172. package/.github/workflows/publish.yml +0 -58
  173. package/.kiro/settings/lsp.json +0 -198
  174. package/MODULE_NAMING_CHANGES.md +0 -81
  175. package/PARAMETER_NAMING_CHANGES.md +0 -106
  176. package/USAGE_EXAMPLE.md +0 -86
  177. package/src/index.ts +0 -50
  178. package/src/lib/analytics/AnalyticsClient.ts +0 -24
  179. package/src/lib/analytics/types.ts +0 -8
  180. package/src/lib/app/AppClient.ts +0 -54
  181. package/src/lib/app/types.ts +0 -50
  182. package/src/lib/auth/types.ts +0 -123
  183. package/src/lib/database/DatabaseClient.ts +0 -244
  184. package/src/lib/database/types.ts +0 -90
  185. package/src/lib/functions/FunctionsClient.ts +0 -27
  186. package/src/lib/functions/types.ts +0 -27
  187. package/src/lib/policy/types.ts +0 -39
  188. package/src/lib/secrets/SecretsClient.ts +0 -75
  189. package/src/lib/secrets/types.ts +0 -59
  190. package/src/lib/settings/SettingsClient.ts +0 -22
  191. package/src/lib/settings/types.ts +0 -9
  192. package/src/lib/storage/StorageClient.ts +0 -131
  193. package/src/lib/storage/types.ts +0 -86
  194. package/src/lib/users/UserClient.ts +0 -63
  195. package/src/lib/users/types.ts +0 -123
  196. package/src/lib-internal/errors/ErrorClient.ts +0 -114
  197. package/src/lib-internal/errors/index.ts +0 -3
  198. package/src/lib-internal/errors/types.ts +0 -29
  199. package/src/lib-internal/http/HttpClient.ts +0 -117
  200. package/src/lib-internal/routes/AnalyticsRoutes.ts +0 -3
  201. package/src/lib-internal/routes/AppRoutes.ts +0 -9
  202. package/src/lib-internal/routes/DatabaseRoutes.ts +0 -10
  203. package/src/lib-internal/routes/FunctionRoutes.ts +0 -3
  204. package/src/lib-internal/routes/PolicyRoutes.ts +0 -4
  205. package/src/lib-internal/routes/SecretsRoutes.ts +0 -5
  206. package/src/lib-internal/routes/StorageRoutes.ts +0 -15
  207. package/src/lib-internal/routes/UserRoutes.ts +0 -12
  208. package/src/lib-internal/routes/index.ts +0 -0
  209. package/src/lib-internal/token/types.ts +0 -0
  210. package/src/types.ts +0 -98
  211. package/src/utils/enums.ts +0 -24
  212. package/src/utils/utils.ts +0 -37
  213. package/tests/fixtures/mockClient.ts +0 -19
  214. package/tests/mocks/db.json +0 -1
  215. package/tests/unit/analytics/AnalyticsClient.test.ts +0 -84
  216. package/tests/unit/app/AppClient.test.ts +0 -114
  217. package/tests/unit/auth/AuthClient.test.ts +0 -91
  218. package/tests/unit/client/Client.test.ts +0 -87
  219. package/tests/unit/database/DatabaseClient.test.ts +0 -565
  220. package/tests/unit/edge-cases/robustness.test.ts +0 -258
  221. package/tests/unit/errors/errors.test.ts +0 -236
  222. package/tests/unit/functions/FunctionsClient.test.ts +0 -99
  223. package/tests/unit/policy/PolicyClient.test.ts +0 -180
  224. package/tests/unit/secrets/SecretsClient.test.ts +0 -146
  225. package/tests/unit/settings/SettingsClient.test.ts +0 -50
  226. package/tests/unit/storage/StorageClient.test.ts +0 -252
  227. package/tests/unit/users/UserClient.test.ts +0 -150
  228. package/tsconfig.json +0 -44
  229. package/vitest.config.ts +0 -7
@@ -1,258 +0,0 @@
1
- import { describe, it, expect, vi, beforeEach } from 'vitest'
2
- import { Database } from '../../../src/lib/database/DatabaseClient.js'
3
- import { Storage } from '../../../src/lib/storage/StorageClient.js'
4
- import { Client } from '../../../src/client.js'
5
-
6
- const mockHttpClient = {
7
- get: vi.fn(),
8
- post: vi.fn(),
9
- put: vi.fn(),
10
- patch: vi.fn(),
11
- delete: vi.fn()
12
- }
13
-
14
- const mockClient = {
15
- getConfig: () => ({ apiKey: 'test-key', appSlug: 'test-app', apiUrl: 'https://api.test.com' }),
16
- httpClient: mockHttpClient
17
- } as unknown as Client
18
-
19
- describe('Non-JSON / empty / malformed responses', () => {
20
- beforeEach(() => vi.clearAllMocks())
21
-
22
- it('handles empty response (204 no content)', async () => {
23
- mockHttpClient.get.mockResolvedValue(undefined)
24
- const result = await new Database(mockClient).from('accounts').execute()
25
- expect(result).toBeUndefined()
26
- })
27
-
28
- it('handles null response body', async () => {
29
- mockHttpClient.get.mockResolvedValue(null)
30
- const result = await new Database(mockClient).from('accounts').execute()
31
- expect(result).toBeNull()
32
- })
33
-
34
- it('handles empty string response', async () => {
35
- mockHttpClient.get.mockResolvedValue('')
36
- const result = await new Database(mockClient).from('accounts').execute()
37
- expect(result).toBe('')
38
- })
39
-
40
- it('handles plain text response', async () => {
41
- mockHttpClient.get.mockResolvedValue('Internal Server Error')
42
- const result = await new Database(mockClient).from('accounts').execute()
43
- expect(result).toBe('Internal Server Error')
44
- })
45
-
46
- it('handles empty array response', async () => {
47
- mockHttpClient.get.mockResolvedValue([])
48
- const result = await new Database(mockClient).from('accounts').execute()
49
- expect(result).toEqual([])
50
- })
51
-
52
- it('handles empty object response', async () => {
53
- mockHttpClient.get.mockResolvedValue({})
54
- const result = await new Database(mockClient).from('accounts').execute()
55
- expect(result).toEqual({})
56
- })
57
-
58
- it('propagates network error from httpClient', async () => {
59
- mockHttpClient.get.mockRejectedValue(new Error('Network Error'))
60
- await expect(new Database(mockClient).from('accounts').execute()).rejects.toThrow('Network Error')
61
- })
62
-
63
- it('propagates network error for Database graph', async () => {
64
- mockHttpClient.get.mockRejectedValue(new Error('ECONNREFUSED'))
65
- await expect(new Database(mockClient).from('employees').execute()).rejects.toThrow('ECONNREFUSED')
66
- })
67
-
68
- it('propagates network error for Storage', async () => {
69
- mockHttpClient.get.mockRejectedValue(new Error('timeout'))
70
- await expect(new Storage(mockClient).from('documents').execute()).rejects.toThrow('timeout')
71
- })
72
-
73
- it('handles response with unexpected shape', async () => {
74
- mockHttpClient.get.mockResolvedValue(42)
75
- const result = await new Database(mockClient).from('accounts').execute()
76
- expect(result).toBe(42)
77
- })
78
-
79
- it('handles response with extra unknown fields', async () => {
80
- mockHttpClient.get.mockResolvedValue({ status: 'success', data: [], unknown_field: true, nested: { deep: 1 } })
81
- const result = await new Database(mockClient).from('accounts').execute()
82
- expect((result as any).unknown_field).toBe(true)
83
- })
84
- })
85
-
86
- describe('Encoding edge cases', () => {
87
- beforeEach(() => vi.clearAllMocks())
88
-
89
- it('encodes special characters in table name', async () => {
90
- mockHttpClient.get.mockResolvedValue([])
91
- await new Database(mockClient).from('my-table_v2').execute()
92
- expect(mockHttpClient.get).toHaveBeenCalledWith(expect.stringContaining('/datatables/my-table_v2/'))
93
- })
94
-
95
- it('encodes special characters in record ID', async () => {
96
- mockHttpClient.get.mockResolvedValue({})
97
- await new Database(mockClient).from('accounts').get('abc-123-def').execute()
98
- expect(mockHttpClient.get).toHaveBeenCalledWith(expect.stringContaining('/abc-123-def/'))
99
- })
100
-
101
- it('encodes filter value with spaces', async () => {
102
- mockHttpClient.get.mockResolvedValue([])
103
- await new Database(mockClient).from('accounts').filter('name', 'eq', 'John Doe').execute()
104
- expect(mockHttpClient.get).toHaveBeenCalledWith(expect.stringContaining('name=John+Doe'))
105
- })
106
-
107
- it('encodes filter value with special characters', async () => {
108
- mockHttpClient.get.mockResolvedValue([])
109
- await new Database(mockClient).from('accounts').filter('email', 'eq', 'user@example.com').execute()
110
- expect(mockHttpClient.get).toHaveBeenCalledWith(expect.stringContaining('email=user%40example.com'))
111
- })
112
-
113
- it('encodes filter value with ampersand', async () => {
114
- mockHttpClient.get.mockResolvedValue([])
115
- await new Database(mockClient).from('accounts').filter('company', 'eq', 'A&B Corp').execute()
116
- const url = mockHttpClient.get.mock.calls[0][0]
117
- expect(url).toContain('company=A%26B')
118
- })
119
-
120
- it('handles unicode in filter values', async () => {
121
- mockHttpClient.get.mockResolvedValue([])
122
- await new Database(mockClient).from('accounts').filter('name', 'icontains', '日本語').execute()
123
- expect(mockHttpClient.get).toHaveBeenCalledWith(expect.stringContaining('name__icontains='))
124
- })
125
-
126
- it('encodes graph relationship types with special chars', async () => {
127
- mockHttpClient.get.mockResolvedValue([])
128
- await new Database(mockClient).from('employees').types(['reports_to']).execute()
129
- expect(mockHttpClient.get).toHaveBeenCalledWith(expect.stringContaining('relationship_type=reports_to'))
130
- })
131
-
132
- it('handles storage bucket with hyphens', async () => {
133
- mockHttpClient.get.mockResolvedValue([])
134
- await new Storage(mockClient).from('my-bucket-name').execute()
135
- expect(mockHttpClient.get).toHaveBeenCalledWith(expect.stringContaining('/buckets/my-bucket-name/'), undefined)
136
- })
137
-
138
- it('handles empty string filter value', async () => {
139
- mockHttpClient.get.mockResolvedValue([])
140
- await new Database(mockClient).from('accounts').filter('status', 'eq', '').execute()
141
- const url = mockHttpClient.get.mock.calls[0][0]
142
- expect(url).toContain('status=')
143
- })
144
- })
145
-
146
- describe('Builder immutability', () => {
147
- beforeEach(() => vi.clearAllMocks())
148
-
149
- it('Database: chaining does not mutate original instance', async () => {
150
- mockHttpClient.get.mockResolvedValue([])
151
- const base = new Database(mockClient).from('accounts')
152
- const filtered = base.filter('status', 'eq', 'active')
153
- const sorted = base.sort('name', 'asc')
154
-
155
- await filtered.execute()
156
- const filteredUrl = mockHttpClient.get.mock.calls[0][0]
157
-
158
- await sorted.execute()
159
- const sortedUrl = mockHttpClient.get.mock.calls[1][0]
160
-
161
- expect(filteredUrl).toContain('status=active')
162
- expect(filteredUrl).not.toContain('ordering=name')
163
-
164
- expect(sortedUrl).toContain('ordering=name')
165
- expect(sortedUrl).not.toContain('status=active')
166
- })
167
-
168
- it('Database: page does not affect sibling chain', async () => {
169
- mockHttpClient.get.mockResolvedValue([])
170
- const base = new Database(mockClient).from('accounts')
171
- const page1 = base.page(1)
172
- const page2 = base.page(2)
173
-
174
- await page1.execute()
175
- await page2.execute()
176
-
177
- expect(mockHttpClient.get.mock.calls[0][0]).toContain('page=1')
178
- expect(mockHttpClient.get.mock.calls[1][0]).toContain('page=2')
179
- expect(mockHttpClient.get.mock.calls[0][0]).not.toContain('page=2')
180
- })
181
-
182
- it('Database graph: chaining does not mutate original instance', async () => {
183
- mockHttpClient.get.mockResolvedValue([])
184
- const base = new Database(mockClient).from('employees')
185
- const descendants = base.get('1').include('descendants').depth(3)
186
- const ancestors = base.get('4').include('ancestors')
187
-
188
- await descendants.execute()
189
- const descUrl = mockHttpClient.get.mock.calls[0][0]
190
-
191
- await ancestors.execute()
192
- const ancUrl = mockHttpClient.get.mock.calls[1][0]
193
-
194
- expect(descUrl).toContain('/1/')
195
- expect(descUrl).toContain('include=descendants')
196
- expect(descUrl).toContain('depth=3')
197
-
198
- expect(ancUrl).toContain('/4/')
199
- expect(ancUrl).toContain('include=ancestors')
200
- expect(ancUrl).not.toContain('depth=3')
201
- })
202
-
203
- it('Database graph: format does not leak between chains', async () => {
204
- mockHttpClient.get.mockResolvedValue([])
205
- const base = new Database(mockClient).from('employees')
206
- const tree = base.format('tree')
207
- const graph = base.format('graph')
208
-
209
- await tree.execute()
210
- await graph.execute()
211
-
212
- expect(mockHttpClient.get.mock.calls[0][0]).toContain('format=tree')
213
- expect(mockHttpClient.get.mock.calls[0][0]).not.toContain('format=graph')
214
- expect(mockHttpClient.get.mock.calls[1][0]).toContain('format=graph')
215
- expect(mockHttpClient.get.mock.calls[1][0]).not.toContain('format=tree')
216
- })
217
-
218
- it('Storage: filter does not mutate original instance', async () => {
219
- mockHttpClient.get.mockResolvedValue([])
220
- const base = new Storage(mockClient).from('documents')
221
- const pdfs = base.filter({ mimetype: 'application/pdf' })
222
- const images = base.filter({ mimetype_category: 'image' })
223
-
224
- await pdfs.execute()
225
- await images.execute()
226
-
227
- expect(mockHttpClient.get.mock.calls[0][0]).toContain('mimetype=application')
228
- expect(mockHttpClient.get.mock.calls[0][0]).not.toContain('mimetype_category')
229
- expect(mockHttpClient.get.mock.calls[1][0]).toContain('mimetype_category=image')
230
- })
231
-
232
- it('Database: get does not affect list chain', async () => {
233
- mockHttpClient.get.mockResolvedValue([])
234
- const base = new Database(mockClient).from('accounts')
235
- const single = base.get('123')
236
- const list = base.page(1)
237
-
238
- await single.execute()
239
- await list.execute()
240
-
241
- expect(mockHttpClient.get.mock.calls[0][0]).toContain('/123/')
242
- expect(mockHttpClient.get.mock.calls[1][0]).not.toContain('/123/')
243
- })
244
-
245
- it('Database: edge operations do not affect traversal chain', async () => {
246
- mockHttpClient.get.mockResolvedValue([])
247
- mockHttpClient.post.mockResolvedValue({})
248
- const base = new Database(mockClient).from('employees')
249
- const traversal = base.get('1').include('descendants')
250
- const edge = base.edges().create([{ from_id: 1, to_id: 2, type: 'manager' }])
251
-
252
- await traversal.execute()
253
- await edge.execute()
254
-
255
- expect(mockHttpClient.get.mock.calls[0][0]).toContain('/data/1/')
256
- expect(mockHttpClient.post.mock.calls[0][0]).toContain('_edges/data/')
257
- })
258
- })
@@ -1,236 +0,0 @@
1
- import { describe, it, expect } from 'vitest'
2
- import {
3
- TaruviError,
4
- ValidationError,
5
- AuthError,
6
- ForbiddenError,
7
- NotFoundError,
8
- ConflictError,
9
- TimeoutError,
10
- NetworkError,
11
- RateLimitError,
12
- createErrorFromResponse,
13
- ErrorCode
14
- } from '../../../src/lib-internal/errors/index.js'
15
-
16
- describe('Error classes', () => {
17
- it('TaruviError has correct properties', () => {
18
- const err = new TaruviError('Something broke', 500, ErrorCode.INTERNAL_ERROR, 'db down', { field: 'bad' }, { extra: 1 })
19
- expect(err).toBeInstanceOf(Error)
20
- expect(err.name).toBe('TaruviError')
21
- expect(err.message).toBe('Something broke')
22
- expect(err.statusCode).toBe(500)
23
- expect(err.code).toBe('INTERNAL_ERROR')
24
- expect(err.detail).toBe('db down')
25
- expect(err.errors).toEqual({ field: 'bad' })
26
- expect(err.data).toEqual({ extra: 1 })
27
- })
28
-
29
- it('ValidationError defaults', () => {
30
- const err = new ValidationError()
31
- expect(err.name).toBe('ValidationError')
32
- expect(err.statusCode).toBe(400)
33
- expect(err.code).toBe('VALIDATION_ERROR')
34
- expect(err.message).toBe('Validation failed')
35
- })
36
-
37
- it('ValidationError with field errors', () => {
38
- const err = new ValidationError('Bad input', 'check fields', { email: 'required' })
39
- expect(err.errors).toEqual({ email: 'required' })
40
- expect(err.detail).toBe('check fields')
41
- })
42
-
43
- it('AuthError defaults', () => {
44
- const err = new AuthError()
45
- expect(err.name).toBe('AuthError')
46
- expect(err.statusCode).toBe(401)
47
- expect(err.code).toBe('UNAUTHORIZED')
48
- })
49
-
50
- it('ForbiddenError defaults', () => {
51
- const err = new ForbiddenError()
52
- expect(err.name).toBe('ForbiddenError')
53
- expect(err.statusCode).toBe(403)
54
- expect(err.code).toBe('FORBIDDEN')
55
- })
56
-
57
- it('NotFoundError defaults', () => {
58
- const err = new NotFoundError()
59
- expect(err.name).toBe('NotFoundError')
60
- expect(err.statusCode).toBe(404)
61
- expect(err.code).toBe('NOT_FOUND')
62
- })
63
-
64
- it('ConflictError defaults', () => {
65
- const err = new ConflictError()
66
- expect(err.name).toBe('ConflictError')
67
- expect(err.statusCode).toBe(409)
68
- expect(err.code).toBe('CONFLICT')
69
- })
70
-
71
- it('TimeoutError defaults', () => {
72
- const err = new TimeoutError()
73
- expect(err.name).toBe('TimeoutError')
74
- expect(err.statusCode).toBe(504)
75
- expect(err.code).toBe('GATEWAY_TIMEOUT')
76
- })
77
-
78
- it('NetworkError defaults', () => {
79
- const err = new NetworkError()
80
- expect(err.name).toBe('NetworkError')
81
- expect(err.statusCode).toBe(0)
82
- expect(err.code).toBe('NETWORK_ERROR')
83
- })
84
-
85
- it('RateLimitError defaults', () => {
86
- const err = new RateLimitError()
87
- expect(err.name).toBe('RateLimitError')
88
- expect(err.statusCode).toBe(429)
89
- expect(err.code).toBe('RATE_LIMITED')
90
- expect(err.retryAfter).toBeUndefined()
91
- })
92
-
93
- it('RateLimitError with retryAfter', () => {
94
- const err = new RateLimitError('Too many requests', 60)
95
- expect(err.message).toBe('Too many requests')
96
- expect(err.retryAfter).toBe(60)
97
- expect(err).toBeInstanceOf(TaruviError)
98
- })
99
-
100
- it('all errors are instanceof TaruviError', () => {
101
- expect(new ValidationError()).toBeInstanceOf(TaruviError)
102
- expect(new AuthError()).toBeInstanceOf(TaruviError)
103
- expect(new ForbiddenError()).toBeInstanceOf(TaruviError)
104
- expect(new NotFoundError()).toBeInstanceOf(TaruviError)
105
- expect(new ConflictError()).toBeInstanceOf(TaruviError)
106
- expect(new TimeoutError()).toBeInstanceOf(TaruviError)
107
- expect(new NetworkError()).toBeInstanceOf(TaruviError)
108
- expect(new RateLimitError()).toBeInstanceOf(TaruviError)
109
- })
110
-
111
- it('all errors are instanceof Error', () => {
112
- expect(new TaruviError('x', 500)).toBeInstanceOf(Error)
113
- expect(new ValidationError()).toBeInstanceOf(Error)
114
- expect(new NetworkError()).toBeInstanceOf(Error)
115
- })
116
- })
117
-
118
- describe('createErrorFromResponse', () => {
119
- it('400 with VALIDATION_ERROR code returns ValidationError', () => {
120
- const err = createErrorFromResponse(400, {
121
- status: 'error',
122
- code: 'VALIDATION_ERROR',
123
- message: 'Email is required',
124
- errors: { email: 'This field is required' }
125
- })
126
- expect(err).toBeInstanceOf(ValidationError)
127
- expect(err.message).toBe('Email is required')
128
- expect(err.errors).toEqual({ email: 'This field is required' })
129
- })
130
-
131
- it('400 with BAD_REQUEST code returns TaruviError', () => {
132
- const err = createErrorFromResponse(400, {
133
- status: 'error',
134
- code: 'BAD_REQUEST',
135
- message: 'Invalid input'
136
- })
137
- expect(err).toBeInstanceOf(TaruviError)
138
- expect(err).not.toBeInstanceOf(ValidationError)
139
- expect(err.code).toBe('BAD_REQUEST')
140
- })
141
-
142
- it('401 returns AuthError', () => {
143
- const err = createErrorFromResponse(401, {
144
- status: 'error',
145
- code: 'UNAUTHORIZED',
146
- message: 'Token expired'
147
- })
148
- expect(err).toBeInstanceOf(AuthError)
149
- expect(err.message).toBe('Token expired')
150
- })
151
-
152
- it('403 returns ForbiddenError', () => {
153
- const err = createErrorFromResponse(403, {
154
- status: 'error',
155
- code: 'FORBIDDEN',
156
- message: 'Not allowed'
157
- })
158
- expect(err).toBeInstanceOf(ForbiddenError)
159
- })
160
-
161
- it('404 returns NotFoundError', () => {
162
- const err = createErrorFromResponse(404, {
163
- status: 'error',
164
- code: 'NOT_FOUND',
165
- message: 'User not found'
166
- })
167
- expect(err).toBeInstanceOf(NotFoundError)
168
- expect(err.message).toBe('User not found')
169
- })
170
-
171
- it('409 returns ConflictError', () => {
172
- const err = createErrorFromResponse(409, {
173
- status: 'error',
174
- code: 'CONFLICT',
175
- message: 'Duplicate entry',
176
- detail: 'Email already exists'
177
- })
178
- expect(err).toBeInstanceOf(ConflictError)
179
- expect(err.detail).toBe('Email already exists')
180
- })
181
-
182
- it('504 returns TimeoutError', () => {
183
- const err = createErrorFromResponse(504, {
184
- status: 'error',
185
- code: 'GATEWAY_TIMEOUT',
186
- message: 'Query timeout'
187
- })
188
- expect(err).toBeInstanceOf(TimeoutError)
189
- })
190
-
191
- it('429 returns RateLimitError', () => {
192
- const err = createErrorFromResponse(429, {
193
- status: 'error',
194
- code: 'RATE_LIMITED',
195
- message: 'Too many requests'
196
- })
197
- expect(err).toBeInstanceOf(RateLimitError)
198
- expect(err.message).toBe('Too many requests')
199
- })
200
-
201
- it('500 returns TaruviError', () => {
202
- const err = createErrorFromResponse(500, {
203
- status: 'error',
204
- code: 'INTERNAL_ERROR',
205
- message: 'Server error'
206
- })
207
- expect(err).toBeInstanceOf(TaruviError)
208
- expect(err.statusCode).toBe(500)
209
- })
210
-
211
- it('handles missing body', () => {
212
- const err = createErrorFromResponse(500, undefined)
213
- expect(err).toBeInstanceOf(TaruviError)
214
- expect(err.message).toBe('Request failed')
215
- })
216
-
217
- it('handles body with extra data field', () => {
218
- const err = createErrorFromResponse(400, {
219
- status: 'error',
220
- code: 'BAD_REQUEST',
221
- message: 'Bad',
222
- data: { hint: 'check params' }
223
- })
224
- expect(err.data).toEqual({ hint: 'check params' })
225
- })
226
-
227
- it('handles unknown status code', () => {
228
- const err = createErrorFromResponse(422, {
229
- status: 'error',
230
- code: 'VALIDATION_ERROR',
231
- message: 'Unprocessable'
232
- })
233
- expect(err).toBeInstanceOf(TaruviError)
234
- expect(err.statusCode).toBe(422)
235
- })
236
- })
@@ -1,99 +0,0 @@
1
- import { describe, it, expect, vi, beforeEach } from 'vitest'
2
- import { Functions } from '../../../src/lib/functions/FunctionsClient.js'
3
- import { Client } from '../../../src/client.js'
4
-
5
- const mockHttpClient = {
6
- post: vi.fn()
7
- }
8
-
9
- const mockClient = {
10
- getConfig: () => ({ apiKey: 'test-key', appSlug: 'test-app', apiUrl: 'https://api.test.com' }),
11
- httpClient: mockHttpClient
12
- } as unknown as Client
13
-
14
- describe('Functions', () => {
15
- beforeEach(() => {
16
- vi.clearAllMocks()
17
- })
18
-
19
- describe('execute()', () => {
20
- it('executes function with default options', async () => {
21
- const response = { data: { result: 'success' } }
22
- mockHttpClient.post.mockResolvedValue(response)
23
-
24
- const functions = new Functions(mockClient)
25
- const result = await functions.execute('my-function')
26
-
27
- expect(mockHttpClient.post).toHaveBeenCalledWith(
28
- 'api/apps/test-app/functions/my-function/execute/',
29
- { async: false, params: {} }
30
- )
31
- expect(result).toEqual(response)
32
- })
33
-
34
- it('executes function with params', async () => {
35
- const response = { data: { result: 'success' } }
36
- mockHttpClient.post.mockResolvedValue(response)
37
-
38
- const functions = new Functions(mockClient)
39
- await functions.execute('my-function', {
40
- params: { key1: 'value1', key2: 123 }
41
- })
42
-
43
- expect(mockHttpClient.post).toHaveBeenCalledWith(
44
- 'api/apps/test-app/functions/my-function/execute/',
45
- { async: false, params: { key1: 'value1', key2: 123 } }
46
- )
47
- })
48
-
49
- it('executes function asynchronously', async () => {
50
- const response = {
51
- invocation: {
52
- invocation_id: 'inv-123',
53
- celery_task_id: 'task-456',
54
- status: 'pending'
55
- }
56
- }
57
- mockHttpClient.post.mockResolvedValue(response)
58
-
59
- const functions = new Functions(mockClient)
60
- const result = await functions.execute('long-task', { async: true })
61
-
62
- expect(mockHttpClient.post).toHaveBeenCalledWith(
63
- 'api/apps/test-app/functions/long-task/execute/',
64
- { async: true, params: {} }
65
- )
66
- expect(result).toEqual(response)
67
- })
68
-
69
- it('executes function with async and params', async () => {
70
- mockHttpClient.post.mockResolvedValue({})
71
-
72
- const functions = new Functions(mockClient)
73
- await functions.execute('process-data', {
74
- async: true,
75
- params: { data: 'test-data' }
76
- })
77
-
78
- expect(mockHttpClient.post).toHaveBeenCalledWith(
79
- 'api/apps/test-app/functions/process-data/execute/',
80
- { async: true, params: { data: 'test-data' } }
81
- )
82
- })
83
-
84
- it('supports typed response', async () => {
85
- interface MyResponse {
86
- total: number
87
- items: string[]
88
- }
89
- const response = { data: { total: 5, items: ['a', 'b', 'c'] } }
90
- mockHttpClient.post.mockResolvedValue(response)
91
-
92
- const functions = new Functions(mockClient)
93
- const result = await functions.execute<MyResponse>('get-items')
94
-
95
- expect(result.data?.total).toBe(5)
96
- expect(result.data?.items).toEqual(['a', 'b', 'c'])
97
- })
98
- })
99
- })