@taruvi/sdk 1.3.3 → 1.3.4-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/.claude/settings.local.json +19 -0
- package/.kiro/settings/lsp.json +198 -0
- package/MODULE_NAMING_CHANGES.md +81 -0
- package/PARAMETER_NAMING_CHANGES.md +106 -0
- package/README.md +4 -4
- package/USAGE_EXAMPLE.md +86 -0
- package/package.json +10 -9
- package/{dist/client.js → src/client.ts} +59 -39
- package/src/index.ts +54 -0
- package/src/lib/analytics/AnalyticsClient.ts +24 -0
- package/src/lib/analytics/types.ts +8 -0
- package/src/lib/app/AppClient.ts +54 -0
- package/src/lib/app/types.ts +50 -0
- package/{dist/lib/auth/AuthClient.js → src/lib/auth/AuthClient.ts} +106 -70
- package/src/lib/auth/types.ts +111 -0
- package/src/lib/database/DatabaseClient.ts +148 -0
- package/src/lib/database/types.ts +46 -0
- package/src/lib/functions/FunctionsClient.ts +27 -0
- package/src/lib/functions/types.ts +25 -0
- package/src/lib/graphs/GraphClient.ts +106 -0
- package/src/lib/graphs/types.ts +33 -0
- package/src/lib/policy/PolicyClient.ts +79 -0
- package/src/lib/policy/types.ts +40 -0
- package/src/lib/secrets/SecretsClient.ts +75 -0
- package/src/lib/secrets/types.ts +59 -0
- package/src/lib/settings/SettingsClient.ts +14 -0
- package/src/lib/settings/types.ts +9 -0
- package/src/lib/storage/StorageClient.ts +123 -0
- package/src/lib/storage/types.ts +86 -0
- package/src/lib/users/UserClient.ts +55 -0
- package/src/lib/users/types.ts +104 -0
- package/src/lib-internal/errors/ErrorClient.ts +102 -0
- package/src/lib-internal/errors/index.ts +3 -0
- package/src/lib-internal/errors/types.ts +28 -0
- package/src/lib-internal/http/HttpClient.ts +129 -0
- package/{dist/lib-internal/http/types.js → src/lib-internal/http/types.ts} +3 -2
- package/src/lib-internal/routes/AnalyticsRoutes.ts +3 -0
- package/src/lib-internal/routes/AppRoutes.ts +9 -0
- package/src/lib-internal/routes/AuthRoutes.ts +0 -0
- package/src/lib-internal/routes/DatabaseRoutes.ts +9 -0
- package/src/lib-internal/routes/FunctionRoutes.ts +3 -0
- package/src/lib-internal/routes/GraphRoutes.ts +14 -0
- package/src/lib-internal/routes/PolicyRoutes.ts +4 -0
- package/src/lib-internal/routes/SecretsRoutes.ts +5 -0
- package/{dist/lib-internal/routes/SettingsRoutes.js → src/lib-internal/routes/SettingsRoutes.ts} +1 -2
- package/src/lib-internal/routes/StorageRoutes.ts +15 -0
- package/src/lib-internal/routes/UserRoutes.ts +11 -0
- package/src/lib-internal/routes/index.ts +0 -0
- package/{dist/lib-internal/token/TokenClient.js → src/lib-internal/token/TokenClient.ts} +144 -99
- package/src/lib-internal/token/types.ts +0 -0
- package/src/types.ts +90 -0
- package/{dist/utils/enums.js → src/utils/enums.ts} +10 -4
- package/src/utils/utils.ts +37 -0
- package/tests/fixtures/mockClient.ts +19 -0
- package/tests/mocks/db.json +1 -0
- package/tests/unit/analytics/AnalyticsClient.test.ts +84 -0
- package/tests/unit/app/AppClient.test.ts +114 -0
- package/tests/unit/auth/AuthClient.test.ts +131 -0
- package/tests/unit/client/Client.test.ts +70 -0
- package/tests/unit/database/DatabaseClient.test.ts +304 -0
- package/tests/unit/edge-cases/robustness.test.ts +259 -0
- package/tests/unit/errors/errors.test.ts +209 -0
- package/tests/unit/functions/FunctionsClient.test.ts +99 -0
- package/tests/unit/graphs/GraphClient.test.ts +329 -0
- package/tests/unit/policy/PolicyClient.test.ts +184 -0
- package/tests/unit/secrets/SecretsClient.test.ts +146 -0
- package/tests/unit/settings/SettingsClient.test.ts +50 -0
- package/tests/unit/storage/StorageClient.test.ts +251 -0
- package/tests/unit/users/UserClient.test.ts +150 -0
- package/tsconfig.json +43 -0
- package/vitest.config.ts +7 -0
- package/dist/client.d.ts +0 -29
- package/dist/client.d.ts.map +0 -1
- package/dist/client.js.map +0 -1
- package/dist/index.d.ts +0 -25
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js +0 -15
- package/dist/index.js.map +0 -1
- package/dist/lib/Analytics/AnalyticsClient.d.ts +0 -9
- package/dist/lib/Analytics/AnalyticsClient.d.ts.map +0 -1
- package/dist/lib/Analytics/AnalyticsClient.js +0 -17
- package/dist/lib/Analytics/AnalyticsClient.js.map +0 -1
- package/dist/lib/Analytics/types.d.ts +0 -7
- package/dist/lib/Analytics/types.d.ts.map +0 -1
- package/dist/lib/Analytics/types.js +0 -2
- package/dist/lib/Analytics/types.js.map +0 -1
- package/dist/lib/App/AppClient.d.ts +0 -15
- package/dist/lib/App/AppClient.d.ts.map +0 -1
- package/dist/lib/App/AppClient.js +0 -41
- package/dist/lib/App/AppClient.js.map +0 -1
- package/dist/lib/App/types.d.ts +0 -36
- package/dist/lib/App/types.d.ts.map +0 -1
- package/dist/lib/App/types.js +0 -2
- package/dist/lib/App/types.js.map +0 -1
- package/dist/lib/Database/DatabaseClient.d.ts +0 -28
- package/dist/lib/Database/DatabaseClient.d.ts.map +0 -1
- package/dist/lib/Database/DatabaseClient.js +0 -116
- package/dist/lib/Database/DatabaseClient.js.map +0 -1
- package/dist/lib/Database/types.d.ts +0 -24
- package/dist/lib/Database/types.d.ts.map +0 -1
- package/dist/lib/Database/types.js +0 -2
- package/dist/lib/Database/types.js.map +0 -1
- package/dist/lib/Function/FunctionsClient.d.ts +0 -9
- package/dist/lib/Function/FunctionsClient.d.ts.map +0 -1
- package/dist/lib/Function/FunctionsClient.js +0 -20
- package/dist/lib/Function/FunctionsClient.js.map +0 -1
- package/dist/lib/Function/types.d.ts +0 -16
- package/dist/lib/Function/types.d.ts.map +0 -1
- package/dist/lib/Function/types.js +0 -2
- package/dist/lib/Function/types.js.map +0 -1
- package/dist/lib/Graphs/GraphClient.d.ts +0 -26
- package/dist/lib/Graphs/GraphClient.d.ts.map +0 -1
- package/dist/lib/Graphs/GraphClient.js +0 -86
- package/dist/lib/Graphs/GraphClient.js.map +0 -1
- package/dist/lib/Graphs/types.d.ts +0 -23
- package/dist/lib/Graphs/types.d.ts.map +0 -1
- package/dist/lib/Graphs/types.js +0 -2
- package/dist/lib/Graphs/types.js.map +0 -1
- package/dist/lib/Policy/PolicyClient.d.ts +0 -9
- package/dist/lib/Policy/PolicyClient.d.ts.map +0 -1
- package/dist/lib/Policy/PolicyClient.js +0 -24
- package/dist/lib/Policy/PolicyClient.js.map +0 -1
- package/dist/lib/Policy/types.d.ts +0 -22
- package/dist/lib/Policy/types.d.ts.map +0 -1
- package/dist/lib/Policy/types.js +0 -2
- package/dist/lib/Policy/types.js.map +0 -1
- package/dist/lib/Secrets/SecretsClient.d.ts +0 -14
- package/dist/lib/Secrets/SecretsClient.d.ts.map +0 -1
- package/dist/lib/Secrets/SecretsClient.js +0 -32
- package/dist/lib/Secrets/SecretsClient.js.map +0 -1
- package/dist/lib/Secrets/types.d.ts +0 -13
- package/dist/lib/Secrets/types.d.ts.map +0 -1
- package/dist/lib/Secrets/types.js +0 -2
- package/dist/lib/Secrets/types.js.map +0 -1
- package/dist/lib/Settings/SettingsClient.d.ts +0 -7
- package/dist/lib/Settings/SettingsClient.d.ts.map +0 -1
- package/dist/lib/Settings/SettingsClient.js +0 -11
- package/dist/lib/Settings/SettingsClient.js.map +0 -1
- package/dist/lib/Settings/types.d.ts +0 -4
- package/dist/lib/Settings/types.d.ts.map +0 -1
- package/dist/lib/Settings/types.js +0 -2
- package/dist/lib/Settings/types.js.map +0 -1
- package/dist/lib/Storage/StorageClient.d.ts +0 -26
- package/dist/lib/Storage/StorageClient.d.ts.map +0 -1
- package/dist/lib/Storage/StorageClient.js +0 -78
- package/dist/lib/Storage/StorageClient.js.map +0 -1
- package/dist/lib/Storage/types.d.ts +0 -35
- package/dist/lib/Storage/types.d.ts.map +0 -1
- package/dist/lib/Storage/types.js +0 -2
- package/dist/lib/Storage/types.js.map +0 -1
- package/dist/lib/auth/AuthClient.d.ts +0 -66
- package/dist/lib/auth/AuthClient.d.ts.map +0 -1
- package/dist/lib/auth/AuthClient.js.map +0 -1
- package/dist/lib/auth/types.d.ts +0 -9
- package/dist/lib/auth/types.d.ts.map +0 -1
- package/dist/lib/auth/types.js +0 -2
- package/dist/lib/auth/types.js.map +0 -1
- package/dist/lib/user/UserClient.d.ts +0 -16
- package/dist/lib/user/UserClient.d.ts.map +0 -1
- package/dist/lib/user/UserClient.js +0 -41
- package/dist/lib/user/UserClient.js.map +0 -1
- package/dist/lib/user/types.d.ts +0 -100
- package/dist/lib/user/types.d.ts.map +0 -1
- package/dist/lib/user/types.js +0 -2
- package/dist/lib/user/types.js.map +0 -1
- package/dist/lib-internal/errors/ErrorClient.d.ts +0 -4
- package/dist/lib-internal/errors/ErrorClient.d.ts.map +0 -1
- package/dist/lib-internal/errors/ErrorClient.js +0 -6
- package/dist/lib-internal/errors/ErrorClient.js.map +0 -1
- package/dist/lib-internal/errors/index.d.ts +0 -8
- package/dist/lib-internal/errors/index.d.ts.map +0 -1
- package/dist/lib-internal/errors/index.js +0 -23
- package/dist/lib-internal/errors/index.js.map +0 -1
- package/dist/lib-internal/errors/types.d.ts +0 -83
- package/dist/lib-internal/errors/types.d.ts.map +0 -1
- package/dist/lib-internal/errors/types.js +0 -65
- package/dist/lib-internal/errors/types.js.map +0 -1
- package/dist/lib-internal/http/HttpClient.d.ts +0 -22
- package/dist/lib-internal/http/HttpClient.d.ts.map +0 -1
- package/dist/lib-internal/http/HttpClient.js +0 -65
- package/dist/lib-internal/http/HttpClient.js.map +0 -1
- package/dist/lib-internal/http/types.d.ts +0 -12
- package/dist/lib-internal/http/types.d.ts.map +0 -1
- package/dist/lib-internal/http/types.js.map +0 -1
- package/dist/lib-internal/routes/AnalyticsRoutes.d.ts +0 -4
- package/dist/lib-internal/routes/AnalyticsRoutes.d.ts.map +0 -1
- package/dist/lib-internal/routes/AnalyticsRoutes.js +0 -4
- package/dist/lib-internal/routes/AnalyticsRoutes.js.map +0 -1
- package/dist/lib-internal/routes/AppRoutes.d.ts +0 -10
- package/dist/lib-internal/routes/AppRoutes.d.ts.map +0 -1
- package/dist/lib-internal/routes/AppRoutes.js +0 -6
- package/dist/lib-internal/routes/AppRoutes.js.map +0 -1
- package/dist/lib-internal/routes/AuthRoutes.d.ts +0 -2
- package/dist/lib-internal/routes/AuthRoutes.d.ts.map +0 -1
- package/dist/lib-internal/routes/AuthRoutes.js +0 -2
- package/dist/lib-internal/routes/AuthRoutes.js.map +0 -1
- package/dist/lib-internal/routes/DatabaseRoutes.d.ts +0 -10
- package/dist/lib-internal/routes/DatabaseRoutes.d.ts.map +0 -1
- package/dist/lib-internal/routes/DatabaseRoutes.js +0 -6
- package/dist/lib-internal/routes/DatabaseRoutes.js.map +0 -1
- package/dist/lib-internal/routes/FunctionRoutes.d.ts +0 -4
- package/dist/lib-internal/routes/FunctionRoutes.d.ts.map +0 -1
- package/dist/lib-internal/routes/FunctionRoutes.js +0 -4
- package/dist/lib-internal/routes/FunctionRoutes.js.map +0 -1
- package/dist/lib-internal/routes/GraphRoutes.d.ts +0 -14
- package/dist/lib-internal/routes/GraphRoutes.d.ts.map +0 -1
- package/dist/lib-internal/routes/GraphRoutes.js +0 -11
- package/dist/lib-internal/routes/GraphRoutes.js.map +0 -1
- package/dist/lib-internal/routes/PolicyRoutes.d.ts +0 -5
- package/dist/lib-internal/routes/PolicyRoutes.d.ts.map +0 -1
- package/dist/lib-internal/routes/PolicyRoutes.js +0 -5
- package/dist/lib-internal/routes/PolicyRoutes.js.map +0 -1
- package/dist/lib-internal/routes/SecretsRoutes.d.ts +0 -6
- package/dist/lib-internal/routes/SecretsRoutes.d.ts.map +0 -1
- package/dist/lib-internal/routes/SecretsRoutes.js +0 -6
- package/dist/lib-internal/routes/SecretsRoutes.js.map +0 -1
- package/dist/lib-internal/routes/SettingsRoutes.d.ts +0 -4
- package/dist/lib-internal/routes/SettingsRoutes.d.ts.map +0 -1
- package/dist/lib-internal/routes/SettingsRoutes.js.map +0 -1
- package/dist/lib-internal/routes/StorageRoutes.d.ts +0 -11
- package/dist/lib-internal/routes/StorageRoutes.d.ts.map +0 -1
- package/dist/lib-internal/routes/StorageRoutes.js +0 -8
- package/dist/lib-internal/routes/StorageRoutes.js.map +0 -1
- package/dist/lib-internal/routes/UserRoutes.d.ts +0 -11
- package/dist/lib-internal/routes/UserRoutes.d.ts.map +0 -1
- package/dist/lib-internal/routes/UserRoutes.js +0 -11
- package/dist/lib-internal/routes/UserRoutes.js.map +0 -1
- package/dist/lib-internal/routes/index.d.ts +0 -2
- package/dist/lib-internal/routes/index.d.ts.map +0 -1
- package/dist/lib-internal/routes/index.js +0 -2
- package/dist/lib-internal/routes/index.js.map +0 -1
- package/dist/lib-internal/token/TokenClient.d.ts +0 -71
- package/dist/lib-internal/token/TokenClient.d.ts.map +0 -1
- package/dist/lib-internal/token/TokenClient.js.map +0 -1
- package/dist/lib-internal/token/types.d.ts +0 -2
- package/dist/lib-internal/token/types.d.ts.map +0 -1
- package/dist/lib-internal/token/types.js +0 -2
- package/dist/lib-internal/token/types.js.map +0 -1
- package/dist/types.d.ts +0 -49
- package/dist/types.d.ts.map +0 -1
- package/dist/types.js +0 -2
- package/dist/types.js.map +0 -1
- package/dist/utils/enums.d.ts +0 -20
- package/dist/utils/enums.d.ts.map +0 -1
- package/dist/utils/enums.js.map +0 -1
- package/dist/utils/utils.d.ts +0 -5
- package/dist/utils/utils.d.ts.map +0 -1
- package/dist/utils/utils.js +0 -32
- package/dist/utils/utils.js.map +0 -1
package/src/types.ts
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { MimeTypeCategory, Visibility } from './utils/enums.js'
|
|
2
|
+
|
|
3
|
+
export interface TaruviConfig {
|
|
4
|
+
apiKey: string // Identifies which site the client belongs to
|
|
5
|
+
appSlug: string // Identifies which app the client belongs to
|
|
6
|
+
apiUrl: string // Base API URL
|
|
7
|
+
deskUrl?: string // URL for the desk/login page
|
|
8
|
+
token?: string // Optional: Pre-existing auth token
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
// Standard response wrapper matching backend AppDataResponse
|
|
12
|
+
export interface TaruviResponse<T = unknown> {
|
|
13
|
+
status: "success" | "error"
|
|
14
|
+
message: string
|
|
15
|
+
data: T
|
|
16
|
+
total?: number
|
|
17
|
+
pagination?: PaginationInfo
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface PaginationInfo {
|
|
21
|
+
offset: number
|
|
22
|
+
limit: number
|
|
23
|
+
count: number
|
|
24
|
+
current_page: number
|
|
25
|
+
total_pages: number
|
|
26
|
+
has_next: boolean
|
|
27
|
+
has_previous: boolean
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export interface StorageFilters {
|
|
31
|
+
// Pagination (DRF style)
|
|
32
|
+
page?: number
|
|
33
|
+
page_size?: number
|
|
34
|
+
|
|
35
|
+
// Range Filters - Size (in bytes)
|
|
36
|
+
size__gte?: number
|
|
37
|
+
size__lte?: number
|
|
38
|
+
size__gt?: number
|
|
39
|
+
size__lt?: number
|
|
40
|
+
min_size?: number
|
|
41
|
+
max_size?: number
|
|
42
|
+
|
|
43
|
+
// Range Filters - Dates (ISO 8601)
|
|
44
|
+
created_at__gte?: string
|
|
45
|
+
created_at__lte?: string
|
|
46
|
+
created_after?: string
|
|
47
|
+
created_before?: string
|
|
48
|
+
updated_at__gte?: string
|
|
49
|
+
updated_at__lte?: string
|
|
50
|
+
|
|
51
|
+
// Search Filters
|
|
52
|
+
search?: string
|
|
53
|
+
filename__icontains?: string
|
|
54
|
+
prefix?: string
|
|
55
|
+
file?: string
|
|
56
|
+
file__icontains?: string
|
|
57
|
+
file__startswith?: string
|
|
58
|
+
file__istartswith?: string
|
|
59
|
+
metadata_search?: string
|
|
60
|
+
|
|
61
|
+
// MIME Type Filters
|
|
62
|
+
mimetype?: string
|
|
63
|
+
mimetype__in?: string
|
|
64
|
+
mimetype_category?: MimeTypeCategory
|
|
65
|
+
|
|
66
|
+
// Visibility & User Filters
|
|
67
|
+
visibility?: Visibility
|
|
68
|
+
created_by_me?: boolean
|
|
69
|
+
modified_by_me?: boolean
|
|
70
|
+
created_by__username?: string
|
|
71
|
+
created_by__username__icontains?: string
|
|
72
|
+
|
|
73
|
+
// Sorting
|
|
74
|
+
ordering?: string
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export interface DatabaseFilters {
|
|
78
|
+
// Pagination (DRF style)
|
|
79
|
+
page?: number
|
|
80
|
+
page_size?: number
|
|
81
|
+
|
|
82
|
+
// Sorting (DRF style: "-field" for desc, "field" for asc)
|
|
83
|
+
ordering?: string
|
|
84
|
+
|
|
85
|
+
// Populate relations
|
|
86
|
+
populate?: string
|
|
87
|
+
|
|
88
|
+
// Dynamic filters - allows any field with operators
|
|
89
|
+
[key: string]: string | number | boolean | undefined
|
|
90
|
+
}
|
|
@@ -4,15 +4,21 @@ export const MimeTypeCategory = {
|
|
|
4
4
|
AUDIO: 'audio',
|
|
5
5
|
APPLICATION: 'application',
|
|
6
6
|
TEXT: 'text'
|
|
7
|
-
}
|
|
7
|
+
} as const
|
|
8
|
+
|
|
9
|
+
export type MimeTypeCategory = typeof MimeTypeCategory[keyof typeof MimeTypeCategory]
|
|
10
|
+
|
|
8
11
|
export const Visibility = {
|
|
9
12
|
PUBLIC: 'public',
|
|
10
13
|
PRIVATE: 'private'
|
|
11
|
-
}
|
|
14
|
+
} as const
|
|
15
|
+
|
|
16
|
+
export type Visibility = typeof Visibility[keyof typeof Visibility]
|
|
17
|
+
|
|
18
|
+
|
|
12
19
|
export const QueryParams = {
|
|
13
20
|
include: "include",
|
|
14
21
|
depth: "depth",
|
|
15
22
|
format: "format",
|
|
16
23
|
graph_type: "graph_type",
|
|
17
|
-
}
|
|
18
|
-
//# sourceMappingURL=enums.js.map
|
|
24
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
const _window = typeof window !== 'undefined' ? window : undefined
|
|
2
|
+
const _navigator = typeof navigator !== 'undefined' ? navigator : undefined
|
|
3
|
+
const _document = typeof document !== 'undefined' ? document : undefined
|
|
4
|
+
|
|
5
|
+
export const isBrowser = (): boolean => {
|
|
6
|
+
return _window !== undefined && _document !== undefined
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export const isReactNative = (): boolean => {
|
|
10
|
+
return _navigator !== undefined &&
|
|
11
|
+
// @ts-ignore - navigator.product is deprecated but still used in RN detection
|
|
12
|
+
_navigator.product === 'ReactNative'
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export const getRuntimeEnvironment = (): string => {
|
|
16
|
+
if (isBrowser()) return 'Browser'
|
|
17
|
+
if (isReactNative()) return 'ReactNative'
|
|
18
|
+
return 'Server'
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function buildQueryString(queryParams: Record<string, unknown> | undefined): string {
|
|
22
|
+
if (!queryParams || Object.keys(queryParams).length === 0) {
|
|
23
|
+
return ''
|
|
24
|
+
}
|
|
25
|
+
const params = new URLSearchParams()
|
|
26
|
+
Object.entries(queryParams).forEach(([key, value]) => {
|
|
27
|
+
if (value !== undefined && value !== null) {
|
|
28
|
+
if (Array.isArray(value)) {
|
|
29
|
+
value.forEach((v) => params.append(key, String(v)))
|
|
30
|
+
} else {
|
|
31
|
+
params.append(key, String(value))
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
})
|
|
35
|
+
const queryString = params.toString()
|
|
36
|
+
return queryString ? `?${queryString}` : ''
|
|
37
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { vi } from 'vitest'
|
|
2
|
+
import { Client } from '../../src/client.js'
|
|
3
|
+
|
|
4
|
+
export const mockHttpClient = {
|
|
5
|
+
get: vi.fn(),
|
|
6
|
+
post: vi.fn(),
|
|
7
|
+
put: vi.fn(),
|
|
8
|
+
patch: vi.fn(),
|
|
9
|
+
delete: vi.fn()
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export const mockClient = {
|
|
13
|
+
getConfig: () => ({ apiKey: 'test-key', appSlug: 'test-app', apiUrl: 'https://api.test.com' }),
|
|
14
|
+
httpClient: mockHttpClient
|
|
15
|
+
} as unknown as Client
|
|
16
|
+
|
|
17
|
+
export function resetMocks() {
|
|
18
|
+
vi.clearAllMocks()
|
|
19
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach } from 'vitest'
|
|
2
|
+
import { Analytics } from '../../../src/lib/analytics/AnalyticsClient.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('Analytics', () => {
|
|
15
|
+
beforeEach(() => {
|
|
16
|
+
vi.clearAllMocks()
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
describe('execute()', () => {
|
|
20
|
+
it('executes analytics query with default options', async () => {
|
|
21
|
+
const response = { data: { total_sales: 1000 } }
|
|
22
|
+
mockHttpClient.post.mockResolvedValue(response)
|
|
23
|
+
|
|
24
|
+
const analytics = new Analytics(mockClient)
|
|
25
|
+
const result = await analytics.execute('sales-report')
|
|
26
|
+
|
|
27
|
+
expect(mockHttpClient.post).toHaveBeenCalledWith(
|
|
28
|
+
'api/apps/test-app/analytics/queries/sales-report/execute/',
|
|
29
|
+
{ params: {} }
|
|
30
|
+
)
|
|
31
|
+
expect(result).toEqual(response)
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
it('executes analytics query with params', async () => {
|
|
35
|
+
const response = { data: { total_sales: 5000 } }
|
|
36
|
+
mockHttpClient.post.mockResolvedValue(response)
|
|
37
|
+
|
|
38
|
+
const analytics = new Analytics(mockClient)
|
|
39
|
+
await analytics.execute('monthly-report', {
|
|
40
|
+
params: {
|
|
41
|
+
start_date: '2024-01-01',
|
|
42
|
+
end_date: '2024-12-31'
|
|
43
|
+
}
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
expect(mockHttpClient.post).toHaveBeenCalledWith(
|
|
47
|
+
'api/apps/test-app/analytics/queries/monthly-report/execute/',
|
|
48
|
+
{
|
|
49
|
+
params: {
|
|
50
|
+
start_date: '2024-01-01',
|
|
51
|
+
end_date: '2024-12-31'
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
)
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
it('supports typed response', async () => {
|
|
58
|
+
interface SalesData {
|
|
59
|
+
total_sales: number
|
|
60
|
+
orders_count: number
|
|
61
|
+
}
|
|
62
|
+
const response = { data: { total_sales: 10000, orders_count: 50 } }
|
|
63
|
+
mockHttpClient.post.mockResolvedValue(response)
|
|
64
|
+
|
|
65
|
+
const analytics = new Analytics(mockClient)
|
|
66
|
+
const result = await analytics.execute<SalesData>('sales-summary')
|
|
67
|
+
|
|
68
|
+
expect(result.data?.total_sales).toBe(10000)
|
|
69
|
+
expect(result.data?.orders_count).toBe(50)
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
it('builds correct URL with app slug and query slug', async () => {
|
|
73
|
+
mockHttpClient.post.mockResolvedValue({})
|
|
74
|
+
|
|
75
|
+
const analytics = new Analytics(mockClient)
|
|
76
|
+
await analytics.execute('dashboard-metrics')
|
|
77
|
+
|
|
78
|
+
expect(mockHttpClient.post).toHaveBeenCalledWith(
|
|
79
|
+
'api/apps/test-app/analytics/queries/dashboard-metrics/execute/',
|
|
80
|
+
expect.any(Object)
|
|
81
|
+
)
|
|
82
|
+
})
|
|
83
|
+
})
|
|
84
|
+
})
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach } from 'vitest'
|
|
2
|
+
import { App } from '../../../src/lib/app/AppClient.js'
|
|
3
|
+
import { Client } from '../../../src/client.js'
|
|
4
|
+
import type { RolesListResponse, AppSettingsResponse } from '../../../src/lib/app/types.js'
|
|
5
|
+
|
|
6
|
+
const mockHttpClient = {
|
|
7
|
+
get: vi.fn()
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const mockClient = {
|
|
11
|
+
getConfig: () => ({ apiKey: 'test-key', appSlug: 'test-app', apiUrl: 'https://api.test.com' }),
|
|
12
|
+
httpClient: mockHttpClient
|
|
13
|
+
} as unknown as Client
|
|
14
|
+
|
|
15
|
+
describe('App', () => {
|
|
16
|
+
beforeEach(() => {
|
|
17
|
+
vi.clearAllMocks()
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
describe('roles()', () => {
|
|
21
|
+
it('returns App instance for chaining', () => {
|
|
22
|
+
const app = new App(mockClient)
|
|
23
|
+
const result = app.roles()
|
|
24
|
+
expect(result).toBeInstanceOf(App)
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
it('fetches app roles on execute', async () => {
|
|
28
|
+
const rolesData = [
|
|
29
|
+
{ id: '1', name: 'Admin', permissions: ['read', 'write', 'delete'] },
|
|
30
|
+
{ id: '2', name: 'Editor', permissions: ['read', 'write'] }
|
|
31
|
+
]
|
|
32
|
+
mockHttpClient.get.mockResolvedValue(rolesData)
|
|
33
|
+
|
|
34
|
+
const app = new App(mockClient)
|
|
35
|
+
const result = await app.roles().execute()
|
|
36
|
+
|
|
37
|
+
expect(mockHttpClient.get).toHaveBeenCalledWith('api/apps/test-app/roles')
|
|
38
|
+
expect(result).toEqual(rolesData)
|
|
39
|
+
})
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
describe('settings()', () => {
|
|
43
|
+
it('returns App instance for chaining', () => {
|
|
44
|
+
const app = new App(mockClient)
|
|
45
|
+
const result = app.settings()
|
|
46
|
+
expect(result).toBeInstanceOf(App)
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
it('fetches app settings on execute', async () => {
|
|
50
|
+
const settingsData = { theme: 'dark', language: 'en' }
|
|
51
|
+
mockHttpClient.get.mockResolvedValue(settingsData)
|
|
52
|
+
|
|
53
|
+
const app = new App(mockClient)
|
|
54
|
+
const result = await app.settings().execute()
|
|
55
|
+
|
|
56
|
+
expect(mockHttpClient.get).toHaveBeenCalledWith('api/apps/test-app/settings/')
|
|
57
|
+
expect(result).toEqual(settingsData)
|
|
58
|
+
})
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
describe('execute()', () => {
|
|
62
|
+
it('calls httpClient.get by default', async () => {
|
|
63
|
+
mockHttpClient.get.mockResolvedValue({})
|
|
64
|
+
|
|
65
|
+
const app = new App(mockClient)
|
|
66
|
+
await app.execute()
|
|
67
|
+
|
|
68
|
+
expect(mockHttpClient.get).toHaveBeenCalled()
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
it('builds correct base URL with app slug', async () => {
|
|
72
|
+
mockHttpClient.get.mockResolvedValue({})
|
|
73
|
+
|
|
74
|
+
const app = new App(mockClient)
|
|
75
|
+
await app.roles().execute()
|
|
76
|
+
|
|
77
|
+
expect(mockHttpClient.get).toHaveBeenCalledWith(
|
|
78
|
+
expect.stringContaining('api/apps/test-app')
|
|
79
|
+
)
|
|
80
|
+
})
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
describe('response handling', () => {
|
|
84
|
+
it('returns roles list matching RolesListResponse type', async () => {
|
|
85
|
+
const mockResponse: RolesListResponse = {
|
|
86
|
+
status: 'success',
|
|
87
|
+
message: 'Data retrieved successfully',
|
|
88
|
+
data: [
|
|
89
|
+
{ id: '1', name: 'Admin', slug: 'admin', description: 'Admin role', is_default: false, created_at: '2024-01-01', updated_at: '2024-01-01' },
|
|
90
|
+
{ id: '2', name: 'Editor', slug: 'editor', description: 'Editor role', is_default: false, created_at: '2024-01-01', updated_at: '2024-01-01' }
|
|
91
|
+
],
|
|
92
|
+
total: 2
|
|
93
|
+
}
|
|
94
|
+
mockHttpClient.get.mockResolvedValue(mockResponse)
|
|
95
|
+
const result = await new App(mockClient).roles().execute() as RolesListResponse
|
|
96
|
+
expect(result.status).toBe('success')
|
|
97
|
+
expect(result.data).toHaveLength(2)
|
|
98
|
+
expect(result.data[0].name).toBe('Admin')
|
|
99
|
+
expect(result.total).toBe(2)
|
|
100
|
+
})
|
|
101
|
+
|
|
102
|
+
it('returns settings matching AppSettingsResponse type', async () => {
|
|
103
|
+
const mockResponse: AppSettingsResponse = {
|
|
104
|
+
status: 'success',
|
|
105
|
+
message: 'Settings retrieved successfully',
|
|
106
|
+
data: { name: 'My App', slug: 'my-app', description: 'Test app', is_active: true, documentation_url: null, support_email: null, default_frontend_worker_url: null, created_at: '2024-01-01', updated_at: '2024-01-01' }
|
|
107
|
+
}
|
|
108
|
+
mockHttpClient.get.mockResolvedValue(mockResponse)
|
|
109
|
+
const result = await new App(mockClient).settings().execute() as AppSettingsResponse
|
|
110
|
+
expect(result.data.name).toBe('My App')
|
|
111
|
+
expect(result.data.is_active).toBe(true)
|
|
112
|
+
})
|
|
113
|
+
})
|
|
114
|
+
})
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach } from 'vitest'
|
|
2
|
+
import { Auth } from '../../../src/lib/auth/AuthClient.js'
|
|
3
|
+
import { Client } from '../../../src/client.js'
|
|
4
|
+
|
|
5
|
+
const mockTokenClient = {
|
|
6
|
+
isAuthenticated: vi.fn(),
|
|
7
|
+
getToken: vi.fn(),
|
|
8
|
+
getRefreshToken: vi.fn(),
|
|
9
|
+
isTokenExpired: vi.fn(),
|
|
10
|
+
clearTokens: vi.fn(),
|
|
11
|
+
updateAccessToken: vi.fn(),
|
|
12
|
+
updateRefreshToken: vi.fn()
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const mockHttpClient = {
|
|
16
|
+
get: vi.fn(),
|
|
17
|
+
post: vi.fn()
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const mockClient = {
|
|
21
|
+
getConfig: () => ({
|
|
22
|
+
apiKey: 'test-key',
|
|
23
|
+
appSlug: 'test-app',
|
|
24
|
+
apiUrl: 'https://api.test.com',
|
|
25
|
+
deskUrl: 'https://desk.test.com'
|
|
26
|
+
}),
|
|
27
|
+
httpClient: mockHttpClient,
|
|
28
|
+
tokenClient: mockTokenClient
|
|
29
|
+
} as unknown as Client
|
|
30
|
+
|
|
31
|
+
describe('Auth', () => {
|
|
32
|
+
beforeEach(() => {
|
|
33
|
+
vi.clearAllMocks()
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
describe('isUserAuthenticated()', () => {
|
|
37
|
+
it('returns true when user is authenticated', () => {
|
|
38
|
+
mockTokenClient.isAuthenticated.mockReturnValue(true)
|
|
39
|
+
const auth = new Auth(mockClient)
|
|
40
|
+
expect(auth.isUserAuthenticated()).toBe(true)
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
it('returns false when user is not authenticated', () => {
|
|
44
|
+
mockTokenClient.isAuthenticated.mockReturnValue(false)
|
|
45
|
+
const auth = new Auth(mockClient)
|
|
46
|
+
expect(auth.isUserAuthenticated()).toBe(false)
|
|
47
|
+
})
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
describe('getAccessToken()', () => {
|
|
51
|
+
it('returns access token from tokenClient', () => {
|
|
52
|
+
mockTokenClient.getToken.mockReturnValue('access-token-123')
|
|
53
|
+
const auth = new Auth(mockClient)
|
|
54
|
+
expect(auth.getAccessToken()).toBe('access-token-123')
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
it('returns null when no token exists', () => {
|
|
58
|
+
mockTokenClient.getToken.mockReturnValue(null)
|
|
59
|
+
const auth = new Auth(mockClient)
|
|
60
|
+
expect(auth.getAccessToken()).toBeNull()
|
|
61
|
+
})
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
describe('getRefreshToken()', () => {
|
|
65
|
+
it('returns refresh token from tokenClient', () => {
|
|
66
|
+
mockTokenClient.getRefreshToken.mockReturnValue('refresh-token-456')
|
|
67
|
+
const auth = new Auth(mockClient)
|
|
68
|
+
expect(auth.getRefreshToken()).toBe('refresh-token-456')
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
it('returns null when no refresh token exists', () => {
|
|
72
|
+
mockTokenClient.getRefreshToken.mockReturnValue(null)
|
|
73
|
+
const auth = new Auth(mockClient)
|
|
74
|
+
expect(auth.getRefreshToken()).toBeNull()
|
|
75
|
+
})
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
describe('isTokenExpired()', () => {
|
|
79
|
+
it('returns true when token is expired', () => {
|
|
80
|
+
mockTokenClient.isTokenExpired.mockReturnValue(true)
|
|
81
|
+
const auth = new Auth(mockClient)
|
|
82
|
+
expect(auth.isTokenExpired()).toBe(true)
|
|
83
|
+
})
|
|
84
|
+
|
|
85
|
+
it('returns false when token is valid', () => {
|
|
86
|
+
mockTokenClient.isTokenExpired.mockReturnValue(false)
|
|
87
|
+
const auth = new Auth(mockClient)
|
|
88
|
+
expect(auth.isTokenExpired()).toBe(false)
|
|
89
|
+
})
|
|
90
|
+
})
|
|
91
|
+
|
|
92
|
+
describe('getCurrentUser()', () => {
|
|
93
|
+
it('returns null when not authenticated', async () => {
|
|
94
|
+
mockTokenClient.isAuthenticated.mockReturnValue(false)
|
|
95
|
+
const auth = new Auth(mockClient)
|
|
96
|
+
const result = await auth.getCurrentUser()
|
|
97
|
+
expect(result).toBeNull()
|
|
98
|
+
})
|
|
99
|
+
|
|
100
|
+
it('fetches user data when authenticated', async () => {
|
|
101
|
+
mockTokenClient.isAuthenticated.mockReturnValue(true)
|
|
102
|
+
const userData = { username: 'testuser', email: 'test@example.com' }
|
|
103
|
+
mockHttpClient.get.mockResolvedValue(userData)
|
|
104
|
+
|
|
105
|
+
const auth = new Auth(mockClient)
|
|
106
|
+
const result = await auth.getCurrentUser()
|
|
107
|
+
|
|
108
|
+
expect(mockHttpClient.get).toHaveBeenCalledWith('api/users/me/')
|
|
109
|
+
expect(result).toEqual(userData)
|
|
110
|
+
})
|
|
111
|
+
|
|
112
|
+
it('returns null on API error', async () => {
|
|
113
|
+
mockTokenClient.isAuthenticated.mockReturnValue(true)
|
|
114
|
+
mockHttpClient.get.mockRejectedValue(new Error('API Error'))
|
|
115
|
+
|
|
116
|
+
const auth = new Auth(mockClient)
|
|
117
|
+
const result = await auth.getCurrentUser()
|
|
118
|
+
|
|
119
|
+
expect(result).toBeNull()
|
|
120
|
+
})
|
|
121
|
+
})
|
|
122
|
+
|
|
123
|
+
describe('refreshAccessToken()', () => {
|
|
124
|
+
it('returns null when no refresh token available', async () => {
|
|
125
|
+
mockTokenClient.getRefreshToken.mockReturnValue(null)
|
|
126
|
+
const auth = new Auth(mockClient)
|
|
127
|
+
const result = await auth.refreshAccessToken()
|
|
128
|
+
expect(result).toBeNull()
|
|
129
|
+
})
|
|
130
|
+
})
|
|
131
|
+
})
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'
|
|
2
|
+
import { Client } from '../../../src/client.js'
|
|
3
|
+
|
|
4
|
+
describe('Client', () => {
|
|
5
|
+
beforeEach(() => {
|
|
6
|
+
vi.clearAllMocks()
|
|
7
|
+
})
|
|
8
|
+
|
|
9
|
+
describe('constructor', () => {
|
|
10
|
+
it('throws error when config is not provided', () => {
|
|
11
|
+
expect(() => new Client(undefined as any)).toThrow('Config is required')
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
it('throws error when apiKey is missing', () => {
|
|
15
|
+
expect(() => new Client({ apiUrl: 'https://api.test.com', appSlug: 'test' } as any))
|
|
16
|
+
.toThrow('API key is required')
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
it('throws error when apiUrl is missing', () => {
|
|
20
|
+
expect(() => new Client({ apiKey: 'key', appSlug: 'test' } as any))
|
|
21
|
+
.toThrow('API URL is required')
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
it('creates client with valid config', () => {
|
|
25
|
+
const client = new Client({
|
|
26
|
+
apiKey: 'test-key',
|
|
27
|
+
appSlug: 'test-app',
|
|
28
|
+
apiUrl: 'https://api.test.com'
|
|
29
|
+
})
|
|
30
|
+
expect(client).toBeInstanceOf(Client)
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
it('initializes httpClient and tokenClient', () => {
|
|
34
|
+
const client = new Client({
|
|
35
|
+
apiKey: 'test-key',
|
|
36
|
+
appSlug: 'test-app',
|
|
37
|
+
apiUrl: 'https://api.test.com'
|
|
38
|
+
})
|
|
39
|
+
expect(client.httpClient).toBeDefined()
|
|
40
|
+
expect(client.tokenClient).toBeDefined()
|
|
41
|
+
})
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
describe('getConfig()', () => {
|
|
45
|
+
it('returns readonly copy of config', () => {
|
|
46
|
+
const config = {
|
|
47
|
+
apiKey: 'test-key',
|
|
48
|
+
appSlug: 'test-app',
|
|
49
|
+
apiUrl: 'https://api.test.com'
|
|
50
|
+
}
|
|
51
|
+
const client = new Client(config)
|
|
52
|
+
const returnedConfig = client.getConfig()
|
|
53
|
+
|
|
54
|
+
expect(returnedConfig.apiKey).toBe(config.apiKey)
|
|
55
|
+
expect(returnedConfig.appSlug).toBe(config.appSlug)
|
|
56
|
+
expect(returnedConfig.apiUrl).toBe(config.apiUrl)
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
it('includes optional deskUrl when provided', () => {
|
|
60
|
+
const config = {
|
|
61
|
+
apiKey: 'test-key',
|
|
62
|
+
appSlug: 'test-app',
|
|
63
|
+
apiUrl: 'https://api.test.com',
|
|
64
|
+
deskUrl: 'https://desk.test.com'
|
|
65
|
+
}
|
|
66
|
+
const client = new Client(config)
|
|
67
|
+
expect(client.getConfig().deskUrl).toBe('https://desk.test.com')
|
|
68
|
+
})
|
|
69
|
+
})
|
|
70
|
+
})
|