@taruvi/sdk 1.5.0-beta.1 → 1.5.0-beta.2

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 (69) hide show
  1. package/README.md +58 -1295
  2. package/package.json +10 -2
  3. package/.claude/settings.local.json +0 -19
  4. package/.github/worflows/publish.yml +0 -57
  5. package/.github/workflows/publish.yml +0 -58
  6. package/.kiro/settings/lsp.json +0 -198
  7. package/MODULE_NAMING_CHANGES.md +0 -81
  8. package/PARAMETER_NAMING_CHANGES.md +0 -106
  9. package/USAGE_EXAMPLE.md +0 -86
  10. package/src/client.ts +0 -88
  11. package/src/index.ts +0 -51
  12. package/src/lib/analytics/AnalyticsClient.ts +0 -24
  13. package/src/lib/analytics/types.ts +0 -8
  14. package/src/lib/app/AppClient.ts +0 -54
  15. package/src/lib/app/types.ts +0 -50
  16. package/src/lib/auth/AuthClient.ts +0 -126
  17. package/src/lib/auth/types.ts +0 -123
  18. package/src/lib/database/DatabaseClient.ts +0 -306
  19. package/src/lib/database/types.ts +0 -156
  20. package/src/lib/functions/FunctionsClient.ts +0 -27
  21. package/src/lib/functions/types.ts +0 -27
  22. package/src/lib/policy/PolicyClient.ts +0 -79
  23. package/src/lib/policy/types.ts +0 -39
  24. package/src/lib/secrets/SecretsClient.ts +0 -75
  25. package/src/lib/secrets/types.ts +0 -59
  26. package/src/lib/settings/SettingsClient.ts +0 -22
  27. package/src/lib/settings/types.ts +0 -9
  28. package/src/lib/storage/StorageClient.ts +0 -131
  29. package/src/lib/storage/types.ts +0 -86
  30. package/src/lib/users/UserClient.ts +0 -63
  31. package/src/lib/users/types.ts +0 -123
  32. package/src/lib-internal/errors/ErrorClient.ts +0 -114
  33. package/src/lib-internal/errors/index.ts +0 -3
  34. package/src/lib-internal/errors/types.ts +0 -29
  35. package/src/lib-internal/http/HttpClient.ts +0 -116
  36. package/src/lib-internal/http/types.ts +0 -12
  37. package/src/lib-internal/routes/AnalyticsRoutes.ts +0 -3
  38. package/src/lib-internal/routes/AppRoutes.ts +0 -9
  39. package/src/lib-internal/routes/AuthRoutes.ts +0 -0
  40. package/src/lib-internal/routes/DatabaseRoutes.ts +0 -10
  41. package/src/lib-internal/routes/FunctionRoutes.ts +0 -3
  42. package/src/lib-internal/routes/PolicyRoutes.ts +0 -4
  43. package/src/lib-internal/routes/SecretsRoutes.ts +0 -5
  44. package/src/lib-internal/routes/SettingsRoutes.ts +0 -4
  45. package/src/lib-internal/routes/StorageRoutes.ts +0 -15
  46. package/src/lib-internal/routes/UserRoutes.ts +0 -12
  47. package/src/lib-internal/routes/index.ts +0 -0
  48. package/src/lib-internal/token/TokenClient.ts +0 -108
  49. package/src/lib-internal/token/types.ts +0 -0
  50. package/src/types.ts +0 -104
  51. package/src/utils/enums.ts +0 -24
  52. package/src/utils/utils.ts +0 -38
  53. package/tests/fixtures/mockClient.ts +0 -19
  54. package/tests/mocks/db.json +0 -1
  55. package/tests/unit/analytics/AnalyticsClient.test.ts +0 -84
  56. package/tests/unit/app/AppClient.test.ts +0 -114
  57. package/tests/unit/auth/AuthClient.test.ts +0 -91
  58. package/tests/unit/client/Client.test.ts +0 -87
  59. package/tests/unit/database/DatabaseClient.test.ts +0 -652
  60. package/tests/unit/edge-cases/robustness.test.ts +0 -258
  61. package/tests/unit/errors/errors.test.ts +0 -236
  62. package/tests/unit/functions/FunctionsClient.test.ts +0 -99
  63. package/tests/unit/policy/PolicyClient.test.ts +0 -180
  64. package/tests/unit/secrets/SecretsClient.test.ts +0 -146
  65. package/tests/unit/settings/SettingsClient.test.ts +0 -50
  66. package/tests/unit/storage/StorageClient.test.ts +0 -252
  67. package/tests/unit/users/UserClient.test.ts +0 -150
  68. package/tsconfig.json +0 -44
  69. package/vitest.config.ts +0 -7
@@ -1,75 +0,0 @@
1
- import type { Client } from "../../client.js";
2
- import type { SecretsUrlParams, GetSecretOptions, GetSecretsOptions, SecretsBatchResponse, SecretsBatchMetadataResponse } from "./types.js";
3
- import { HttpMethod } from "../../lib-internal/http/types.js";
4
- import { SecretsRoutes } from "../../lib-internal/routes/SecretsRoutes.js";
5
- import { buildQueryString } from "../../utils/utils.js";
6
-
7
- export class Secrets {
8
- private client: Client
9
- private urlParams: SecretsUrlParams
10
- private body: object | undefined
11
- private method: HttpMethod
12
-
13
- constructor(client: Client, urlParams: SecretsUrlParams = {}, body?: object, method: HttpMethod = HttpMethod.GET) {
14
- this.client = client
15
- this.urlParams = urlParams
16
- this.body = body
17
- this.method = method
18
- }
19
-
20
- /**
21
- * Get a specific secret by key.
22
- *
23
- * @param key - Secret key/name
24
- * @param options - Optional app context for 2-tier inheritance and tag validation
25
- * @returns Secrets instance for chaining with execute()
26
- */
27
- get(key: string, options: GetSecretOptions = {}): Secrets {
28
- if (!key || typeof key !== 'string') {
29
- throw new Error('Secret key is required and must be a string.')
30
- }
31
-
32
- const path = SecretsRoutes.get(key)
33
- const queryParams: Record<string, unknown> = {}
34
-
35
- if (options.app) queryParams.app = options.app
36
- if (options.tags && options.tags.length > 0) queryParams.tags = options.tags.join(',')
37
-
38
- return new Secrets(this.client, { ...this.urlParams, path, queryParams }, undefined, HttpMethod.GET)
39
- }
40
-
41
- /**
42
- * List multiple secrets by keys using backend batch endpoint.
43
- * More efficient than making multiple individual requests - uses a single API call.
44
- *
45
- * @param keys - List of secret keys to retrieve
46
- * @param options - Optional app context and metadata flag
47
- * @returns Promise with dict mapping keys to values (or full objects if includeMetadata=true)
48
- */
49
- async list(keys: string[], options: GetSecretsOptions = {}): Promise<SecretsBatchResponse | SecretsBatchMetadataResponse> {
50
- const queryParams: Record<string, unknown> = {
51
- keys: keys.join(',')
52
- }
53
-
54
- if (options.app) queryParams.app = options.app
55
- if (options.includeMetadata) queryParams.include_metadata = options.includeMetadata
56
-
57
- const queryString = buildQueryString(queryParams)
58
- const url = SecretsRoutes.baseUrl + queryString
59
-
60
- return await this.client.httpClient.get<SecretsBatchResponse | SecretsBatchMetadataResponse>(url)
61
- }
62
-
63
- async execute<T = unknown>(): Promise<T> {
64
- const queryString = buildQueryString(this.urlParams.queryParams)
65
- const url = (this.urlParams.path ?? SecretsRoutes.baseUrl) + queryString
66
-
67
- switch (this.method) {
68
- case HttpMethod.PUT:
69
- return await this.client.httpClient.put<T>(url, this.body)
70
- case HttpMethod.GET:
71
- default:
72
- return await this.client.httpClient.get<T>(url)
73
- }
74
- }
75
- }
@@ -1,59 +0,0 @@
1
- import type { TaruviResponse } from "../../types.js"
2
-
3
- // Internal types
4
- export interface SecretsUrlParams {
5
- path?: string
6
- queryParams?: Record<string, unknown>
7
- }
8
-
9
- // Request types - matches SiteSecretIn from backend
10
- export interface SecretCreateRequest {
11
- key: string
12
- value: string | Record<string, unknown>
13
- secret_type: string
14
- tags?: string[]
15
- app?: string
16
- }
17
-
18
- export interface SecretUpdateRequest {
19
- value?: string | Record<string, unknown>
20
- secret_type?: string
21
- tags?: string[]
22
- app?: string
23
- }
24
-
25
- // Options for getting a single secret
26
- export interface GetSecretOptions {
27
- app?: string
28
- tags?: string[]
29
- }
30
-
31
- // Options for batch getting secrets
32
- export interface GetSecretsOptions {
33
- app?: string
34
- includeMetadata?: boolean
35
- }
36
-
37
- // Secret data
38
- export interface SecretData {
39
- key: string
40
- value: string | Record<string, unknown>
41
- tags?: string[]
42
- secret_type?: string
43
- created_at?: string
44
- updated_at?: string
45
- }
46
-
47
- // Response types - uses standard wrapper
48
- export type SecretResponse = TaruviResponse<SecretData>
49
- export type SecretsListResponse = TaruviResponse<SecretData[]>
50
-
51
- // Batch get response - values only
52
- export type SecretsBatchResponse = TaruviResponse<Record<string, string>>
53
-
54
- // Batch get response - with metadata
55
- export type SecretsBatchMetadataResponse = TaruviResponse<Record<string, {
56
- value: string
57
- tags: string[]
58
- secret_type: string
59
- }>>
@@ -1,22 +0,0 @@
1
- import type { Client } from "../../client.js";
2
- import { SettingsRoutes } from "../../lib-internal/routes/SettingsRoutes.js";
3
-
4
- export class Settings {
5
- private client: Client
6
-
7
- constructor(client: Client) {
8
- this.client = client
9
- }
10
-
11
- async get<T = unknown>(): Promise<T> {
12
- return await this.client.httpClient.get<T>(SettingsRoutes.metadata)
13
- }
14
-
15
- async getUserAttributes<T = unknown>(): Promise<T> {
16
- return await this.client.httpClient.get<T>(SettingsRoutes.userAttributes)
17
- }
18
-
19
- async updateUserAttributes<T = unknown>(schema: Record<string, unknown>): Promise<T> {
20
- return await this.client.httpClient.post<T>(SettingsRoutes.userAttributes, schema)
21
- }
22
- }
@@ -1,9 +0,0 @@
1
- import type { TaruviResponse } from "../../types.js"
2
-
3
- // Site settings data
4
- export interface SiteSettingsData {
5
- [key: string]: unknown
6
- }
7
-
8
- // Response type - uses standard wrapper
9
- export type SettingsResponse = TaruviResponse<SiteSettingsData>
@@ -1,131 +0,0 @@
1
- import type { Client } from "../../client.js";
2
- import type {
3
- BucketUrlParams,
4
- StorageResponse,
5
- StorageListResponse,
6
- StorageUploadBatchResponse,
7
- StorageDeleteBatchResponse
8
- } from "./types.js";
9
- import { StorageRoutes, type StorageRouteKey } from "../../lib-internal/routes/StorageRoutes.js";
10
- import type { TaruviConfig, StorageFilters } from "../../types.js";
11
- import { HttpMethod } from "../../lib-internal/http/types.js";
12
- import { buildQueryString } from "../../utils/utils.js";
13
-
14
- export class Storage {
15
-
16
- private client: Client
17
- private config: TaruviConfig
18
- private urlParams: BucketUrlParams
19
- private operation: HttpMethod | undefined
20
- private body: object | undefined
21
- private filters: StorageFilters | undefined
22
- private queryParams: Record<string, string> | undefined
23
-
24
-
25
- constructor(client: Client, urlParams: BucketUrlParams = {} as BucketUrlParams, operation?: HttpMethod | undefined, body?: object, filters?: StorageFilters, queryParams?: Record<string, string>) {
26
- this.client = client
27
- this.urlParams = urlParams
28
- this.operation = operation
29
- this.config = this.client.getConfig()
30
- this.body = body
31
- this.filters = filters
32
- this.queryParams = queryParams
33
- }
34
-
35
-
36
- from(bucket: string): Storage {
37
- return new Storage(this.client, { ...this.urlParams, bucket }, undefined, undefined)
38
- }
39
-
40
- filter(filters: StorageFilters) {
41
- return new Storage(this.client, { ...this.urlParams }, undefined, undefined, filters)
42
- }
43
-
44
- delete(paths: string[]): Storage {
45
- return new Storage(this.client, {
46
- ...this.urlParams, delete: "delete"
47
- }, HttpMethod.POST, { paths })
48
- }
49
-
50
- update(path: string, body: object): Storage {
51
- return new Storage(this.client, { ...this.urlParams, path }, HttpMethod.PUT, body)
52
- }
53
-
54
- download(path: string): Storage {
55
- return new Storage(this.client, { ...this.urlParams, path }, HttpMethod.GET)
56
- }
57
-
58
- metadata(path: string): Storage {
59
- return new Storage(this.client, { ...this.urlParams, path }, HttpMethod.GET, undefined, undefined, { metadata: 'true' })
60
- }
61
-
62
- upload(filesData: { files: File[], metadatas: object[], paths: string[] }): Storage {
63
- const formData = new FormData()
64
- filesData.files.forEach(f => formData.append('files', f))
65
- formData.append('paths', JSON.stringify(filesData.paths))
66
- formData.append('metadata', JSON.stringify(filesData.metadatas))
67
- return new Storage(this.client, {
68
- ...this.urlParams, upload: "upload"
69
- }, HttpMethod.POST, formData)
70
- }
71
-
72
- private buildRoute(): string {
73
- if (!this.urlParams.bucket) {
74
- throw new Error('Bucket is required. Call .from(bucketName) first.')
75
- }
76
-
77
- return (
78
- StorageRoutes.baseUrl(this.config.appSlug, this.urlParams.bucket) +
79
- (Object.keys(this.urlParams) as StorageRouteKey[]).reduce((acc, key) => {
80
- const value = this.urlParams[key as keyof BucketUrlParams]
81
-
82
- if (!value) return acc
83
-
84
- if (key === 'path' && typeof value === 'string') {
85
- acc += StorageRoutes.path(value)
86
- }
87
-
88
- if ((key === 'upload' || key === 'delete') && typeof StorageRoutes[key] === 'function') {
89
- acc += (StorageRoutes[key] as () => string)()
90
- }
91
-
92
- return acc
93
- }, '') +
94
- '/' +
95
- buildQueryString({ ...this.filters as Record<string, unknown>, ...this.queryParams })
96
- )
97
- }
98
-
99
-
100
-
101
- /**
102
- * Execute the storage operation.
103
- * Returns different types based on the operation:
104
- * - List files: StorageListResponse[]
105
- * - Download: Blob
106
- * - Upload: StorageUploadBatchResponse
107
- * - Delete: StorageDeleteBatchResponse
108
- * - Update: StorageResponse
109
- */
110
- async execute<T = StorageListResponse[] | StorageResponse | StorageUploadBatchResponse | StorageDeleteBatchResponse | Blob>(): Promise<T> {
111
- const url = this.buildRoute()
112
- const operation = this.operation || HttpMethod.GET
113
-
114
- switch (operation) {
115
- case HttpMethod.POST:
116
- return await this.client.httpClient.post<T>(url, this.body)
117
-
118
- case HttpMethod.PUT:
119
- return await this.client.httpClient.put<T>(url, this.body)
120
-
121
- case HttpMethod.DELETE:
122
- return await this.client.httpClient.delete<T>(url)
123
-
124
- case HttpMethod.GET:
125
- default: {
126
- const isDownload = this.urlParams.path && !this.queryParams?.metadata
127
- return await this.client.httpClient.get<T>(url, isDownload ? { responseType: 'blob' } : undefined)
128
- }
129
- }
130
- }
131
- }
@@ -1,86 +0,0 @@
1
- import type { TaruviResponse } from "../../types.js"
2
-
3
- // Internal types - all optional since they're built incrementally via builder pattern
4
- export interface BucketUrlParams {
5
- appSlug?: string
6
- bucket?: string
7
- path?: string
8
- upload?: string
9
- delete?: string
10
- }
11
-
12
- export interface BucketFileUpload {
13
- files: []
14
- path: string
15
- metadata?: Record<string, unknown>
16
- }
17
-
18
- // Request types
19
- export interface StorageRequest {
20
- files: File[]
21
- paths: string[]
22
- metadatas: object[]
23
- }
24
-
25
- export interface StorageUpdateRequest {
26
- metadata?: Record<string, unknown>
27
- visibility?: 'public' | 'private'
28
- }
29
-
30
- // Storage object - matches StorageObjectSerializer from API
31
- export interface StorageObject {
32
- id: number
33
- uuid: string
34
- bucket?: number
35
- bucket_slug?: string
36
- bucket_name?: string
37
- filename: string
38
- file_path: string
39
- file_url: string
40
- size: number
41
- mimetype: string
42
- metadata?: Record<string, unknown>
43
- visibility?: string
44
- created_at: string
45
- updated_at: string
46
- created_by?: string
47
- modified_by?: string
48
- }
49
-
50
- // Response types - uses standard wrapper
51
- export type StorageResponse = TaruviResponse<StorageObject>
52
- export type StorageListResponse = TaruviResponse<StorageObject[]>
53
-
54
- // Batch upload response
55
- export interface StorageUploadBatchResponse {
56
- status: "success" | "error"
57
- message: string
58
- data: {
59
- uploaded_count: number
60
- failed_count: number
61
- total: number
62
- successful: Array<{
63
- index: number
64
- path: string
65
- object: StorageObject
66
- }>
67
- failed: Array<{
68
- index: number
69
- path: string
70
- error: string
71
- }>
72
- }
73
- }
74
-
75
- // Batch delete response
76
- export interface StorageDeleteBatchResponse {
77
- status: "success" | "error"
78
- message: string
79
- data: {
80
- deleted_count: number
81
- failed: Array<{
82
- path: string
83
- error: string
84
- }>
85
- }
86
- }
@@ -1,63 +0,0 @@
1
- import type { Client } from "../../client.js";
2
- import type { UserCreateRequest, UserResponse, UserListResponse, UserListFilters, UserUpdateRequest, UserAppsResponse, AssignRolesRequest, RevokeRolesRequest, RolesResponse, UserPreferencesResponse, UserPreferencesUpdate } from "./types.js";
3
- import { UserRoutes } from "../../lib-internal/routes/UserRoutes.js";
4
- import { buildQueryString } from "../../utils/utils.js";
5
-
6
-
7
- export class User {
8
- private client: Client
9
-
10
- constructor(client: Client) {
11
- this.client = client
12
- }
13
-
14
- async updateUser(username: string, body: UserUpdateRequest): Promise<UserResponse> {
15
- return await this.client.httpClient.put(UserRoutes.updateUser(username), body)
16
- }
17
-
18
- async getUser(username: string): Promise<UserResponse> {
19
- return await this.client.httpClient.get<UserResponse>(UserRoutes.getUser(username))
20
- }
21
-
22
- async list(filters?: UserListFilters): Promise<UserListResponse> {
23
- const queryString = buildQueryString(filters as unknown as Record<string, unknown>)
24
- return await this.client.httpClient.get<UserListResponse>(UserRoutes.listUser(queryString))
25
- }
26
-
27
- async getUserApps(username: string): Promise<UserAppsResponse> {
28
- return await this.client.httpClient.get<UserAppsResponse>(UserRoutes.getUserApps(username))
29
- }
30
-
31
- async createUser(userData: UserCreateRequest): Promise<UserResponse> {
32
- return await this.client.httpClient.post<UserResponse, UserCreateRequest>(
33
- UserRoutes.baseUrl,
34
- userData
35
- )
36
- }
37
-
38
- async deleteUser(username: string): Promise<void> {
39
- return await this.client.httpClient.delete(UserRoutes.deleteUser(username))
40
- }
41
-
42
- async assignRoles(request: AssignRolesRequest): Promise<RolesResponse> {
43
- return await this.client.httpClient.post<RolesResponse, AssignRolesRequest>(
44
- UserRoutes.assignRoles(),
45
- request
46
- )
47
- }
48
-
49
- async revokeRoles(request: RevokeRolesRequest): Promise<RolesResponse> {
50
- return await this.client.httpClient.delete<RolesResponse>(
51
- UserRoutes.revokeRoles(),
52
- request
53
- )
54
- }
55
-
56
- async getPreferences(): Promise<UserPreferencesResponse> {
57
- return await this.client.httpClient.get<UserPreferencesResponse>(UserRoutes.preferences())
58
- }
59
-
60
- async updatePreferences(body: UserPreferencesUpdate): Promise<UserPreferencesResponse> {
61
- return await this.client.httpClient.put<UserPreferencesResponse>(UserRoutes.preferences(), body)
62
- }
63
- }
@@ -1,123 +0,0 @@
1
- import type { TaruviResponse } from "../../types.js"
2
-
3
- export interface UserCreateRequest {
4
- username: string
5
- email: string
6
- password: string
7
- confirm_password: string
8
- first_name: string
9
- last_name: string
10
- is_active?: boolean
11
- is_staff?: boolean
12
- is_cloud_user?: boolean
13
- attributes?: Record<string, unknown>
14
- role_slugs?: string[]
15
- }
16
-
17
- export interface UserData {
18
- id: string
19
- username: string
20
- email: string
21
- first_name: string
22
- last_name: string
23
- full_name?: string
24
- is_active: boolean
25
- is_staff: boolean
26
- is_superuser?: boolean
27
- is_deleted: boolean
28
- date_joined: string
29
- last_login?: string
30
- groups?: UserGroup[]
31
- user_permissions?: UserPermission[]
32
- attributes?: Record<string, unknown>
33
- missing_attributes?: string[]
34
- roles?: UserRole[]
35
- icon_url?: string
36
- }
37
-
38
- export interface UserGroup {
39
- id: number
40
- name: string
41
- }
42
-
43
- export interface UserPermission {
44
- id: number
45
- name: string
46
- codename: string
47
- content_type: string
48
- }
49
-
50
- export interface UserRole {
51
- name: string
52
- slug: string
53
- type: string
54
- app_slug: string
55
- source: "direct" | "site_role" | "inherited"
56
- }
57
-
58
- export interface UserUpdateRequest {
59
- username?: string
60
- email?: string
61
- first_name?: string
62
- last_name?: string
63
- is_active?: boolean
64
- is_staff?: boolean
65
- }
66
-
67
- export interface UserListFilters {
68
- search?: string
69
- is_active?: boolean
70
- is_staff?: boolean
71
- is_superuser?: boolean
72
- is_deleted?: boolean
73
- roles?: string
74
- ordering?: string
75
- page?: number
76
- page_size?: number
77
- }
78
-
79
- export interface UserApp {
80
- name: string
81
- slug: string
82
- icon: string
83
- url: string
84
- display_name: string
85
- }
86
-
87
- // Response types - uses standard wrapper
88
- export type UserResponse = TaruviResponse<UserData>
89
- export type UserListResponse = TaruviResponse<UserData[]>
90
- export type UserAppsResponse = TaruviResponse<UserApp[]>
91
-
92
- export interface UserPreferences {
93
- date_format: string
94
- time_format: string
95
- timezone: string
96
- theme: string
97
- widget_config: Record<string, unknown>
98
- }
99
-
100
- export interface UserPreferencesUpdate {
101
- date_format?: string
102
- time_format?: string
103
- timezone?: string
104
- theme?: string
105
- widget_config?: Record<string, unknown>
106
- }
107
-
108
- export type UserPreferencesResponse = TaruviResponse<UserPreferences>
109
-
110
- export interface AssignRolesRequest {
111
- roles: string[]
112
- usernames: string[]
113
- expires_at?: string
114
- }
115
-
116
- export interface RevokeRolesRequest {
117
- roles: string[]
118
- usernames: string[]
119
- }
120
-
121
- export type RolesResponse = TaruviResponse<{
122
- count: number
123
- }>
@@ -1,114 +0,0 @@
1
- import { ErrorCode, type ErrorResponseBody } from './types.js'
2
-
3
- /**
4
- * Base SDK error. All typed errors extend this.
5
- */
6
- export class TaruviError extends Error {
7
- public readonly code: string
8
- public readonly statusCode: number
9
- public readonly detail: string | undefined
10
- public readonly errors: Record<string, unknown> | undefined
11
- public readonly data: unknown
12
-
13
- constructor(message: string, statusCode: number, code: string = ErrorCode.INTERNAL_ERROR, detail?: string, errors?: Record<string, unknown>, data?: unknown) {
14
- super(message)
15
- this.name = 'TaruviError'
16
- this.statusCode = statusCode
17
- this.code = code
18
- this.detail = detail
19
- this.errors = errors
20
- this.data = data
21
- }
22
- }
23
-
24
- export class ValidationError extends TaruviError {
25
- constructor(message = 'Validation failed', detail?: string, errors?: Record<string, unknown>) {
26
- super(message, 400, ErrorCode.VALIDATION_ERROR, detail, errors)
27
- this.name = 'ValidationError'
28
- }
29
- }
30
-
31
- export class AuthError extends TaruviError {
32
- constructor(message = 'Authentication required') {
33
- super(message, 401, ErrorCode.UNAUTHORIZED)
34
- this.name = 'AuthError'
35
- }
36
- }
37
-
38
- export class ForbiddenError extends TaruviError {
39
- constructor(message = 'Permission denied') {
40
- super(message, 403, ErrorCode.FORBIDDEN)
41
- this.name = 'ForbiddenError'
42
- }
43
- }
44
-
45
- export class NotFoundError extends TaruviError {
46
- constructor(message = 'Resource not found') {
47
- super(message, 404, ErrorCode.NOT_FOUND)
48
- this.name = 'NotFoundError'
49
- }
50
- }
51
-
52
- export class ConflictError extends TaruviError {
53
- constructor(message = 'Resource conflict', detail?: string) {
54
- super(message, 409, ErrorCode.CONFLICT, detail)
55
- this.name = 'ConflictError'
56
- }
57
- }
58
-
59
- export class TimeoutError extends TaruviError {
60
- constructor(message = 'Request timeout') {
61
- super(message, 504, ErrorCode.GATEWAY_TIMEOUT)
62
- this.name = 'TimeoutError'
63
- }
64
- }
65
-
66
- export class RateLimitError extends TaruviError {
67
- public readonly retryAfter: number | undefined
68
-
69
- constructor(message = 'Rate limit exceeded', retryAfter?: number) {
70
- super(message, 429, ErrorCode.RATE_LIMITED)
71
- this.name = 'RateLimitError'
72
- this.retryAfter = retryAfter
73
- }
74
- }
75
-
76
- export class NetworkError extends TaruviError {
77
- constructor(message = 'Network error') {
78
- super(message, 0, ErrorCode.NETWORK_ERROR)
79
- this.name = 'NetworkError'
80
- }
81
- }
82
-
83
- /**
84
- * Maps HTTP status + response body to the appropriate typed error.
85
- */
86
- export function createErrorFromResponse(statusCode: number, body?: ErrorResponseBody): TaruviError {
87
- const message = body?.message || 'Request failed'
88
- const code = body?.code || ErrorCode.INTERNAL_ERROR
89
- const detail = body?.detail
90
- const errors = body?.errors
91
- const data = body?.data
92
-
93
- switch (statusCode) {
94
- case 400:
95
- if (code === ErrorCode.VALIDATION_ERROR) {
96
- return new ValidationError(message, detail, errors)
97
- }
98
- return new TaruviError(message, 400, code, detail, errors, data)
99
- case 401:
100
- return new AuthError(message)
101
- case 403:
102
- return new ForbiddenError(message)
103
- case 404:
104
- return new NotFoundError(message)
105
- case 409:
106
- return new ConflictError(message, detail)
107
- case 429:
108
- return new RateLimitError(message)
109
- case 504:
110
- return new TimeoutError(message)
111
- default:
112
- return new TaruviError(message, statusCode, code, detail, errors, data)
113
- }
114
- }
@@ -1,3 +0,0 @@
1
- export { TaruviError, ValidationError, AuthError, ForbiddenError, NotFoundError, ConflictError, TimeoutError, NetworkError, RateLimitError, createErrorFromResponse } from './ErrorClient.js'
2
- export { ErrorCode } from './types.js'
3
- export type { ErrorResponseBody } from './types.js'