Monorepo containing core modules of Zeichen.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

71 line
2.4 KiB

  1. import { Deserializer, Serializer } from '../core/storage'
  2. const CREATED = 201
  3. const NO_CONTENT = 204
  4. const NOT_FOUND = 404
  5. const GONE = 410
  6. export default class RemoteStorage<U, T> {
  7. constructor(
  8. private readonly baseUrl: string,
  9. private readonly getItemId = item => item['id'],
  10. private readonly serializers: Map<string, Serializer> = new Map([
  11. ['*/*', JSON.stringify],
  12. ['application/json', JSON.stringify],
  13. ['text/json', JSON.stringify],
  14. ]),
  15. private readonly deserializers: Map<string, Deserializer> = new Map([
  16. ['*/*', JSON.parse],
  17. ['application/json', JSON.parse],
  18. ['text/json', JSON.parse],
  19. ]),
  20. ) {}
  21. async getCollection(collectionId: string) {
  22. const response = await window.fetch([this.baseUrl, collectionId].join('/'))
  23. const contentType = response.headers.get('content-type')
  24. const { [contentType]: deserializer = this.deserializers.get('*/*'), } = Object.fromEntries(this.deserializers.entries())
  25. const payload = await response.text()
  26. return deserializer(payload)
  27. }
  28. async setItem(collectionId: string, item: U, contentType = 'application/json') {
  29. const { [contentType]: serializer = this.serializers.get('application/json'), } = Object.fromEntries(this.serializers.entries())
  30. const response = await window.fetch([this.baseUrl, collectionId, this.getItemId(item)].join('/'), {
  31. method: 'put',
  32. body: serializer(item),
  33. })
  34. // resource is created
  35. if (response.status === CREATED) {
  36. return
  37. }
  38. if (100 <= response.status && response.status <= 399) {
  39. console.warn(`Expected response is ${CREATED}, got ${response.status}.`)
  40. return
  41. }
  42. throw new Error(response.statusText)
  43. }
  44. async removeItem(collectionId: string, item: U) {
  45. const response = await window.fetch([this.baseUrl, collectionId, this.getItemId(item)].join('/'), {
  46. method: 'delete',
  47. })
  48. // resource is deleted
  49. if (response.status === NO_CONTENT) {
  50. return true
  51. }
  52. // resource is already deleted
  53. if (response.status === NOT_FOUND || response.status === GONE) {
  54. return false
  55. }
  56. if (100 <= response.status && response.status <= 399) {
  57. console.warn(`Expected response is ${NO_CONTENT}, got ${response.status}.`)
  58. // assume there's a change in the collection
  59. return true
  60. }
  61. throw new Error(response.statusText)
  62. }
  63. // TODO do removeCollection for account closing?
  64. }