index.ts 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. import { invoke } from '@tauri-apps/api/core'
  2. export type Method =
  3. | "GET" // Retrieve resource
  4. | "POST" // Create resource
  5. | "PUT" // Replace resource
  6. | "DELETE" // Remove resource
  7. | "PATCH" // Modify resource
  8. | "HEAD" // GET without body
  9. | "OPTIONS" // Get allowed methods
  10. | "CONNECT" // Create tunnel
  11. | "TRACE" // Loop-back test
  12. export type Version = "HTTP/1.0" | "HTTP/1.1" | "HTTP/2.0" | "HTTP/3.0"
  13. export type StatusCode =
  14. | 100 // Continue
  15. | 101 // Switching Protocols
  16. | 102 // Processing
  17. | 103 // Early Hints
  18. | 200 // OK
  19. | 201 // Created
  20. | 202 // Accepted
  21. | 203 // Non-Authoritative Info
  22. | 204 // No Content
  23. | 205 // Reset Content
  24. | 206 // Partial Content
  25. | 207 // Multi-Status
  26. | 208 // Already Reported
  27. | 226 // IM Used
  28. | 300 // Multiple Choices
  29. | 301 // Moved Permanently
  30. | 302 // Found
  31. | 303 // See Other
  32. | 304 // Not Modified
  33. | 305 // Use Proxy
  34. | 306 // Switch Proxy
  35. | 307 // Temporary Redirect
  36. | 308 // Permanent Redirect
  37. | 400 // Bad Request
  38. | 401 // Unauthorized
  39. | 402 // Payment Required
  40. | 403 // Forbidden
  41. | 404 // Not Found
  42. | 405 // Method Not Allowed
  43. | 406 // Not Acceptable
  44. | 407 // Proxy Auth Required
  45. | 408 // Request Timeout
  46. | 409 // Conflict
  47. | 410 // Gone
  48. | 411 // Length Required
  49. | 412 // Precondition Failed
  50. | 413 // Payload Too Large
  51. | 414 // URI Too Long
  52. | 415 // Unsupported Media
  53. | 416 // Range Not Satisfiable
  54. | 417 // Expectation Failed
  55. | 418 // I'm a teapot
  56. | 421 // Misdirected Request
  57. | 422 // Unprocessable Entity
  58. | 423 // Locked
  59. | 424 // Failed Dependency
  60. | 425 // Too Early
  61. | 426 // Upgrade Required
  62. | 428 // Precondition Required
  63. | 429 // Too Many Requests
  64. | 431 // Headers Too Large
  65. | 451 // Unavailable Legal
  66. | 500 // Server Error
  67. | 501 // Not Implemented
  68. | 502 // Bad Gateway
  69. | 503 // Service Unavailable
  70. | 504 // Gateway Timeout
  71. | 505 // HTTP Ver. Not Supported
  72. | 506 // Variant Negotiates
  73. | 507 // Insufficient Storage
  74. | 508 // Loop Detected
  75. | 510 // Not Extended
  76. | 511 // Network Auth Required
  77. export type FormDataValue =
  78. | { kind: "text"; value: string }
  79. | { kind: "file"; filename: string; contentType: string; data: Uint8Array }
  80. export type FormData = Map<string, FormDataValue[]>
  81. export enum MediaType {
  82. TEXT_PLAIN = "text/plain",
  83. TEXT_HTML = "text/html",
  84. TEXT_CSS = "text/css",
  85. TEXT_CSV = "text/csv",
  86. APPLICATION_JSON = "application/json",
  87. APPLICATION_LD_JSON = "application/ld+json",
  88. APPLICATION_XML = "application/xml",
  89. TEXT_XML = "text/xml",
  90. APPLICATION_FORM = "application/x-www-form-urlencoded",
  91. APPLICATION_OCTET = "application/octet-stream",
  92. MULTIPART_FORM = "multipart/form-data"
  93. }
  94. export type ContentType =
  95. | { kind: "text"; content: string; mediaType: MediaType.TEXT_PLAIN | MediaType.TEXT_HTML | MediaType.TEXT_CSS | MediaType.TEXT_CSV }
  96. | { kind: "json"; content: unknown; mediaType: MediaType.APPLICATION_JSON | MediaType.APPLICATION_LD_JSON }
  97. | { kind: "xml"; content: string; mediaType: MediaType.APPLICATION_XML | MediaType.TEXT_XML }
  98. | { kind: "form"; content: FormData; mediaType: MediaType.APPLICATION_FORM }
  99. | { kind: "binary"; content: Uint8Array; mediaType: MediaType.APPLICATION_OCTET | string; filename?: string }
  100. | { kind: "multipart"; content: FormData; mediaType: MediaType.MULTIPART_FORM }
  101. | { kind: "urlencoded"; content: string; mediaType: MediaType.APPLICATION_FORM }
  102. | { kind: "stream"; content: ReadableStream; mediaType: string }
  103. export interface ResponseBody {
  104. body: Uint8Array
  105. mediaType: MediaType | string
  106. }
  107. export type AuthType =
  108. | { kind: "none" }
  109. | { kind: "basic"; username: string; password: string }
  110. | { kind: "bearer"; token: string }
  111. | {
  112. kind: "digest"
  113. username: string
  114. password: string
  115. realm?: string
  116. nonce?: string
  117. opaque?: string
  118. algorithm?: "MD5" | "SHA-256" | "SHA-512"
  119. qop?: "auth" | "auth-int"
  120. nc?: string
  121. cnonce?: string
  122. }
  123. | {
  124. kind: "oauth2"
  125. grantType:
  126. | {
  127. kind: "authorization_code"
  128. authEndpoint: string
  129. tokenEndpoint: string
  130. clientId: string
  131. clientSecret?: string
  132. }
  133. | {
  134. kind: "client_credentials"
  135. tokenEndpoint: string
  136. clientId: string
  137. clientSecret?: string
  138. }
  139. | {
  140. kind: "password"
  141. tokenEndpoint: string
  142. username: string
  143. password: string
  144. }
  145. | {
  146. kind: "implicit"
  147. authEndpoint: string
  148. clientId: string
  149. }
  150. accessToken?: string
  151. refreshToken?: string
  152. }
  153. export type CertificateType =
  154. | {
  155. kind: "pem"
  156. cert: Uint8Array
  157. key: Uint8Array
  158. }
  159. | {
  160. kind: "pfx"
  161. data: Uint8Array
  162. password: string
  163. }
  164. export interface Request {
  165. id: number
  166. url: string
  167. method: Method
  168. version: Version
  169. headers?: Record<string, string>
  170. params?: Record<string, string>
  171. content?: ContentType
  172. auth?: AuthType
  173. security?: {
  174. certificates?: {
  175. client?: CertificateType
  176. ca?: Array<Uint8Array>
  177. }
  178. validateCertificates?: boolean
  179. verifyHost?: boolean
  180. verifyPeer?: boolean
  181. }
  182. proxy?: {
  183. url: string
  184. auth?: {
  185. username: string
  186. password: string
  187. }
  188. }
  189. }
  190. export interface Response {
  191. id: number
  192. status: StatusCode
  193. statusText: string
  194. version: Version
  195. headers: Record<string, string>
  196. cookies?: Array<{
  197. name: string
  198. value: string
  199. domain?: string
  200. path?: string
  201. expires?: Date
  202. secure?: boolean
  203. httpOnly?: boolean
  204. sameSite?: 'Strict' | 'Lax' | 'None'
  205. }>
  206. body: ResponseBody
  207. meta: {
  208. timing: {
  209. start: number
  210. end: number
  211. }
  212. size: {
  213. headers: number
  214. body: number
  215. total: number
  216. }
  217. }
  218. }
  219. export type UnsupportedFeatureError = {
  220. kind: "unsupported_feature"
  221. feature: string
  222. message: string
  223. relay: string
  224. }
  225. export type RelayError =
  226. | UnsupportedFeatureError
  227. | { kind: "network"; message: string; cause?: unknown }
  228. | { kind: "timeout"; message: string; phase?: "connect" | "tls" | "response" }
  229. | { kind: "certificate"; message: string; cause?: unknown }
  230. | { kind: "parse"; message: string; cause?: unknown }
  231. | { kind: "abort"; message: string }
  232. export type RequestResult =
  233. | { kind: 'success'; response: Response }
  234. | { kind: 'error'; error: RelayError }
  235. export async function execute(request: Request): Promise<RequestResult> {
  236. return await invoke<RequestResult>('plugin:relay|execute', { request })
  237. }
  238. export async function cancel(requestId: number): Promise<void> {
  239. return await invoke<void>('plugin:relay|cancel', { requestId })
  240. }