credentials.ts 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. import { api } from './client'
  2. export type CredentialType = 'basic' | 'bearer' | 'api_key' | 'oauth2' | 'imap' | 'smtp' | 'mysql' | 'postgresql'
  3. export interface CredentialInfo {
  4. id: string
  5. name: string
  6. description?: string
  7. type: CredentialType
  8. createdBy: string
  9. createdAt: number
  10. // The named type this was created as, when a node registered one. The type
  11. // above is still what decides how it is stored and used.
  12. declaredType?: string
  13. updatedAt: number
  14. allowedWorkflows: string[]
  15. /** How many workflows name this credential - the way to tell two of the same name apart. */
  16. usedByWorkflows?: number
  17. projectId?: string
  18. publicData?: Record<string, unknown> // Non-secret fields for editing
  19. }
  20. export interface BasicAuthData {
  21. username: string
  22. password: string
  23. }
  24. export interface BearerTokenData {
  25. token: string
  26. }
  27. export interface ApiKeyData {
  28. header_name: string
  29. key_value: string
  30. }
  31. export interface OAuth2Data {
  32. grant_type: 'client_credentials' | 'authorization_code'
  33. client_id: string
  34. client_secret: string
  35. token_url: string
  36. auth_url?: string
  37. scope?: string
  38. access_token?: string
  39. refresh_token?: string
  40. expires_at?: number
  41. }
  42. export interface ImapData {
  43. host: string
  44. port: number
  45. username: string
  46. password: string
  47. use_ssl: boolean
  48. }
  49. export interface MysqlData {
  50. host: string
  51. port: number
  52. username: string
  53. password: string
  54. database: string
  55. use_ssl: boolean
  56. }
  57. export interface PostgresqlData {
  58. host: string
  59. port: number
  60. username: string
  61. password: string
  62. database: string
  63. use_ssl: boolean
  64. }
  65. export interface CreateCredentialRequest {
  66. // A node-registered type such as "sdcpp". Optional: the built-in type below
  67. // is still what the store uses.
  68. declaredType?: string
  69. name: string
  70. description?: string
  71. type: CredentialType
  72. data: BasicAuthData | BearerTokenData | ApiKeyData | OAuth2Data | ImapData | MysqlData | PostgresqlData
  73. allowedWorkflows?: string[]
  74. /** Which project it belongs to, and so who can see and use it. */
  75. projectId?: string
  76. }
  77. export interface UpdateCredentialRequest {
  78. name?: string
  79. description?: string
  80. data?: BasicAuthData | BearerTokenData | ApiKeyData | OAuth2Data | ImapData | MysqlData | PostgresqlData
  81. allowedWorkflows?: string[]
  82. }
  83. // Transform backend credential data to frontend format
  84. function transformCredential(data: any): CredentialInfo {
  85. // Everything the server sent, then the handful of fields that need a
  86. // different name or a default.
  87. //
  88. // Listing the fields one by one is how "usedByWorkflows" arrived from the
  89. // server and never reached the screen - the same way the workflow mapper
  90. // dropped the record version. A mapper that names every field silently
  91. // discards every field added after it was written, and nothing fails.
  92. return {
  93. ...data,
  94. id: data.id || data._id,
  95. createdBy: data.createdBy || data.ownerId,
  96. // Sent by the server in milliseconds; it reads the document metadata itself.
  97. createdAt: data.createdAt,
  98. updatedAt: data.updatedAt,
  99. declaredType: data.declaredType || undefined,
  100. allowedWorkflows: data.allowedWorkflows || [],
  101. }
  102. }
  103. export const credentialsApi = {
  104. list: async (): Promise<{ credentials: CredentialInfo[] }> => {
  105. const response = await api.get('/credentials')
  106. return {
  107. ...response.data,
  108. credentials: (response.data.credentials || []).map(transformCredential),
  109. }
  110. },
  111. get: async (id: string): Promise<CredentialInfo> => {
  112. const response = await api.get(`/credentials/${id}`)
  113. return transformCredential(response.data)
  114. },
  115. create: async (data: CreateCredentialRequest): Promise<CredentialInfo> => {
  116. const response = await api.post('/credentials', data)
  117. return transformCredential(response.data)
  118. },
  119. update: async (id: string, data: UpdateCredentialRequest): Promise<CredentialInfo> => {
  120. const response = await api.put(`/credentials/${id}`, data)
  121. return transformCredential(response.data)
  122. },
  123. delete: async (id: string): Promise<void> => {
  124. await api.delete(`/credentials/${id}`)
  125. },
  126. refreshOAuth2: async (id: string): Promise<{ success: boolean; expiresAt?: number }> => {
  127. const response = await api.post(`/credentials/${id}/refresh`)
  128. return response.data
  129. },
  130. }