@taruvi/sdk 1.3.6 → 1.3.7-beta.0
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/.github/workflows/publish.yml +57 -0
- package/package.json +1 -1
- package/src/lib-internal/token/TokenClient.ts +16 -0
- package/tests/unit/database/DatabaseClient.test.ts +5 -5
- package/tests/unit/edge-cases/robustness.test.ts +1 -1
- package/tests/unit/graphs/GraphClient.test.ts +14 -14
- package/tests/unit/storage/StorageClient.test.ts +1 -1
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
name: Publish to NPM
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main, beta]
|
|
6
|
+
|
|
7
|
+
jobs:
|
|
8
|
+
publish:
|
|
9
|
+
runs-on: ubuntu-latest
|
|
10
|
+
steps:
|
|
11
|
+
- uses: actions/checkout@v4
|
|
12
|
+
with:
|
|
13
|
+
fetch-depth: 0
|
|
14
|
+
|
|
15
|
+
- uses: actions/setup-node@v4
|
|
16
|
+
with:
|
|
17
|
+
node-version: '20'
|
|
18
|
+
registry-url: 'https://registry.npmjs.org'
|
|
19
|
+
|
|
20
|
+
- name: Get secrets from Infisical
|
|
21
|
+
uses: Infisical/secrets-action@v1.0.7
|
|
22
|
+
with:
|
|
23
|
+
client-id: ${{ secrets.INFISICAL_CLIENT_ID }}
|
|
24
|
+
client-secret: ${{ secrets.INFISICAL_CLIENT_SECRET }}
|
|
25
|
+
env-slug: taruvi-test
|
|
26
|
+
project-slug: taruvi-qmc-d
|
|
27
|
+
domain: "https://environment.eoxvantage.com"
|
|
28
|
+
|
|
29
|
+
- run: npm install
|
|
30
|
+
|
|
31
|
+
- run: npm test
|
|
32
|
+
|
|
33
|
+
- name: Check if version changed
|
|
34
|
+
id: version_check
|
|
35
|
+
run: |
|
|
36
|
+
CURRENT_VERSION=$(node -p "require('./package.json').version")
|
|
37
|
+
echo "current_version=$CURRENT_VERSION" >> $GITHUB_OUTPUT
|
|
38
|
+
|
|
39
|
+
if git tag | grep -q "^v${CURRENT_VERSION}$"; then
|
|
40
|
+
echo "changed=false" >> $GITHUB_OUTPUT
|
|
41
|
+
else
|
|
42
|
+
echo "changed=true" >> $GITHUB_OUTPUT
|
|
43
|
+
fi
|
|
44
|
+
|
|
45
|
+
- name: Tag release
|
|
46
|
+
if: steps.version_check.outputs.changed == 'true'
|
|
47
|
+
run: |
|
|
48
|
+
git config user.name "github-actions[bot]"
|
|
49
|
+
git config user.email "github-actions[bot]@users.noreply.github.com"
|
|
50
|
+
git tag "v${{ steps.version_check.outputs.current_version }}"
|
|
51
|
+
git push origin "v${{ steps.version_check.outputs.current_version }}"
|
|
52
|
+
|
|
53
|
+
- name: Publish (beta)
|
|
54
|
+
if: steps.version_check.outputs.changed == 'true'
|
|
55
|
+
run: npm publish --access public --tag beta
|
|
56
|
+
env:
|
|
57
|
+
NODE_AUTH_TOKEN: ${{ env.NPM_TOKEN }}
|
package/package.json
CHANGED
|
@@ -194,6 +194,22 @@ export class TokenClient {
|
|
|
194
194
|
return parseInt(expiresAt) < Date.now()
|
|
195
195
|
}
|
|
196
196
|
|
|
197
|
+
/**
|
|
198
|
+
* Set access token directly (e.g., from external storage)
|
|
199
|
+
*/
|
|
200
|
+
setAccessToken(token: string): void {
|
|
201
|
+
if (this.browserRunTime) {
|
|
202
|
+
if (typeof window === 'undefined' || typeof localStorage === 'undefined') return
|
|
203
|
+
try {
|
|
204
|
+
localStorage.setItem(TokenClient.ACCESS_TOKEN_KEY, token)
|
|
205
|
+
} catch (err) {
|
|
206
|
+
console.error('Failed to set access token:', err)
|
|
207
|
+
}
|
|
208
|
+
} else {
|
|
209
|
+
this.serverToken = token
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
197
213
|
/**
|
|
198
214
|
* Update access token after refresh
|
|
199
215
|
* ⚠️ IMPORTANT: Taruvi uses refresh token rotation
|
|
@@ -182,19 +182,19 @@ describe('Database', () => {
|
|
|
182
182
|
|
|
183
183
|
describe('first()', () => {
|
|
184
184
|
it('returns first item from array', async () => {
|
|
185
|
-
mockHttpClient.get.mockResolvedValue([{ id: '1' }, { id: '2' }])
|
|
185
|
+
mockHttpClient.get.mockResolvedValue({ data: [{ id: '1' }, { id: '2' }] })
|
|
186
186
|
const result = await new Database(mockClient).from('accounts').first()
|
|
187
187
|
expect(result).toEqual({ id: '1' })
|
|
188
188
|
})
|
|
189
189
|
|
|
190
190
|
it('returns null for empty array', async () => {
|
|
191
|
-
mockHttpClient.get.mockResolvedValue([])
|
|
191
|
+
mockHttpClient.get.mockResolvedValue({ data: [] })
|
|
192
192
|
const result = await new Database(mockClient).from('accounts').first()
|
|
193
193
|
expect(result).toBeNull()
|
|
194
194
|
})
|
|
195
195
|
|
|
196
196
|
it('returns single item if not array', async () => {
|
|
197
|
-
mockHttpClient.get.mockResolvedValue({ id: '1' })
|
|
197
|
+
mockHttpClient.get.mockResolvedValue({ data: { id: '1' } })
|
|
198
198
|
const result = await new Database(mockClient).from('accounts').get('1').first()
|
|
199
199
|
expect(result).toEqual({ id: '1' })
|
|
200
200
|
})
|
|
@@ -202,13 +202,13 @@ describe('Database', () => {
|
|
|
202
202
|
|
|
203
203
|
describe('count()', () => {
|
|
204
204
|
it('returns array length', async () => {
|
|
205
|
-
mockHttpClient.get.mockResolvedValue([{ id: '1' }, { id: '2' }, { id: '3' }])
|
|
205
|
+
mockHttpClient.get.mockResolvedValue({ data: [{ id: '1' }, { id: '2' }, { id: '3' }] })
|
|
206
206
|
const result = await new Database(mockClient).from('accounts').count()
|
|
207
207
|
expect(result).toBe(3)
|
|
208
208
|
})
|
|
209
209
|
|
|
210
210
|
it('returns 0 for non-array', async () => {
|
|
211
|
-
mockHttpClient.get.mockResolvedValue({ id: '1' })
|
|
211
|
+
mockHttpClient.get.mockResolvedValue({ data: { id: '1' } })
|
|
212
212
|
const result = await new Database(mockClient).from('accounts').get('1').count()
|
|
213
213
|
expect(result).toBe(0)
|
|
214
214
|
})
|
|
@@ -248,7 +248,7 @@ describe('Builder immutability', () => {
|
|
|
248
248
|
mockHttpClient.post.mockResolvedValue({})
|
|
249
249
|
const base = new Graph(mockClient).from('employees')
|
|
250
250
|
const traversal = base.get('1').include('descendants')
|
|
251
|
-
const edge = base.
|
|
251
|
+
const edge = base.create([{ from: 1, to: 2, type: 'manager' }])
|
|
252
252
|
|
|
253
253
|
await traversal.execute()
|
|
254
254
|
await edge.execute()
|
|
@@ -123,48 +123,48 @@ describe('Graph', () => {
|
|
|
123
123
|
})
|
|
124
124
|
|
|
125
125
|
describe('edge CRUD', () => {
|
|
126
|
-
it('
|
|
126
|
+
it('list() calls GET on edges route', async () => {
|
|
127
127
|
mockHttpClient.get.mockResolvedValue({ edges: [], total: 0 })
|
|
128
|
-
await new Graph(mockClient).from('employees').
|
|
128
|
+
await new Graph(mockClient).from('employees').list().execute()
|
|
129
129
|
expect(mockHttpClient.get).toHaveBeenCalledWith('api/apps/test-app/datatables/employees/edges/')
|
|
130
130
|
})
|
|
131
131
|
|
|
132
|
-
it('
|
|
132
|
+
it('create() calls POST with array of edges', async () => {
|
|
133
133
|
const edges = [
|
|
134
134
|
{ from: 5, to: 2, type: 'manager' },
|
|
135
135
|
{ from: 5, to: 3, type: 'dotted_line', metadata: { project: 'AI' } }
|
|
136
136
|
]
|
|
137
137
|
mockHttpClient.post.mockResolvedValue({ status: 'success', data: edges, total: 2 })
|
|
138
|
-
await new Graph(mockClient).from('employees').
|
|
138
|
+
await new Graph(mockClient).from('employees').create(edges).execute()
|
|
139
139
|
expect(mockHttpClient.post).toHaveBeenCalledWith(
|
|
140
140
|
'api/apps/test-app/datatables/employees/edges/',
|
|
141
141
|
edges
|
|
142
142
|
)
|
|
143
143
|
})
|
|
144
144
|
|
|
145
|
-
it('
|
|
145
|
+
it('create() with metadata', async () => {
|
|
146
146
|
const edges = [{ from: 5, to: 3, type: 'dotted_line', metadata: { percentage: 30 } }]
|
|
147
147
|
mockHttpClient.post.mockResolvedValue({ status: 'success', data: edges, total: 1 })
|
|
148
|
-
await new Graph(mockClient).from('employees').
|
|
148
|
+
await new Graph(mockClient).from('employees').create(edges).execute()
|
|
149
149
|
expect(mockHttpClient.post).toHaveBeenCalledWith(
|
|
150
150
|
'api/apps/test-app/datatables/employees/edges/',
|
|
151
151
|
edges
|
|
152
152
|
)
|
|
153
153
|
})
|
|
154
154
|
|
|
155
|
-
it('
|
|
155
|
+
it('update() calls PATCH with edge ID in URL', async () => {
|
|
156
156
|
const edge = { from: 5, to: 3, type: 'dotted_line' }
|
|
157
157
|
mockHttpClient.patch.mockResolvedValue({ id: 9, ...edge })
|
|
158
|
-
await new Graph(mockClient).from('employees').
|
|
158
|
+
await new Graph(mockClient).from('employees').update('9', edge).execute()
|
|
159
159
|
expect(mockHttpClient.patch).toHaveBeenCalledWith(
|
|
160
160
|
'api/apps/test-app/datatables/employees/edges/9/',
|
|
161
161
|
edge
|
|
162
162
|
)
|
|
163
163
|
})
|
|
164
164
|
|
|
165
|
-
it('
|
|
165
|
+
it('delete() calls DELETE with edge_ids object', async () => {
|
|
166
166
|
mockHttpClient.delete.mockResolvedValue({ deleted: 2 })
|
|
167
|
-
await new Graph(mockClient).from('employees').
|
|
167
|
+
await new Graph(mockClient).from('employees').delete([9, 10]).execute()
|
|
168
168
|
expect(mockHttpClient.delete).toHaveBeenCalledWith(
|
|
169
169
|
'api/apps/test-app/datatables/employees/edges/',
|
|
170
170
|
{ edge_ids: [9, 10] }
|
|
@@ -290,7 +290,7 @@ describe('Graph', () => {
|
|
|
290
290
|
total: 2
|
|
291
291
|
}
|
|
292
292
|
mockHttpClient.get.mockResolvedValue(mockResponse)
|
|
293
|
-
const result = await new Graph(mockClient).from('employees').
|
|
293
|
+
const result = await new Graph(mockClient).from('employees').list().execute()
|
|
294
294
|
expect((result as any).edges).toHaveLength(2)
|
|
295
295
|
expect((result as any).edges[0].type).toBe('manager')
|
|
296
296
|
expect((result as any).total).toBe(2)
|
|
@@ -306,7 +306,7 @@ describe('Graph', () => {
|
|
|
306
306
|
total: 1
|
|
307
307
|
}
|
|
308
308
|
mockHttpClient.post.mockResolvedValue(mockResponse)
|
|
309
|
-
const result = await new Graph(mockClient).from('employees').
|
|
309
|
+
const result = await new Graph(mockClient).from('employees').create([{ from: 5, to: 2, type: 'manager' }]).execute() as TaruviResponse<EdgeResponse[]>
|
|
310
310
|
expect(result.data).toHaveLength(1)
|
|
311
311
|
expect(result.data[0].id).toBe(10)
|
|
312
312
|
})
|
|
@@ -314,7 +314,7 @@ describe('Graph', () => {
|
|
|
314
314
|
it('returns updated edge matching EdgeResponse type', async () => {
|
|
315
315
|
const mockResponse: EdgeResponse = { id: 9, from: 5, to: 3, type: 'dotted_line', metadata: {} }
|
|
316
316
|
mockHttpClient.patch.mockResolvedValue(mockResponse)
|
|
317
|
-
const result = await new Graph(mockClient).from('employees').
|
|
317
|
+
const result = await new Graph(mockClient).from('employees').update('9', { from: 5, to: 3, type: 'dotted_line' }).execute() as EdgeResponse
|
|
318
318
|
expect(result.id).toBe(9)
|
|
319
319
|
expect(result.type).toBe('dotted_line')
|
|
320
320
|
})
|
|
@@ -322,7 +322,7 @@ describe('Graph', () => {
|
|
|
322
322
|
it('returns delete count response', async () => {
|
|
323
323
|
const mockResponse = { deleted: 3 }
|
|
324
324
|
mockHttpClient.delete.mockResolvedValue(mockResponse)
|
|
325
|
-
const result = await new Graph(mockClient).from('employees').
|
|
325
|
+
const result = await new Graph(mockClient).from('employees').delete([1, 2, 3]).execute()
|
|
326
326
|
expect((result as any).deleted).toBe(3)
|
|
327
327
|
})
|
|
328
328
|
})
|
|
@@ -148,7 +148,7 @@ describe('Storage', () => {
|
|
|
148
148
|
mockHttpClient.get.mockResolvedValue(new Blob())
|
|
149
149
|
await new Storage(mockClient).from('documents').download('folder/file name.pdf').execute()
|
|
150
150
|
expect(mockHttpClient.get).toHaveBeenCalledWith(
|
|
151
|
-
'api/apps/test-app/storage/buckets/documents/objects/folder%2Ffile%20name.pdf
|
|
151
|
+
'api/apps/test-app/storage/buckets/documents/objects/folder%2Ffile%20name.pdf/?metadata=true'
|
|
152
152
|
)
|
|
153
153
|
})
|
|
154
154
|
|