This commit is contained in:
2025-08-25 20:24:23 +08:00
parent 30106e0129
commit 0ae8d7a709
1044 changed files with 321581 additions and 0 deletions

View File

@@ -0,0 +1,490 @@
# Change Log
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [3.4.1](https://github.com/decaporg/decap-cms/compare/decap-cms-backend-git-gateway@3.4.0...decap-cms-backend-git-gateway@3.4.1) (2025-07-31)
**Note:** Version bump only for package decap-cms-backend-git-gateway
# [3.4.0](https://github.com/decaporg/decap-cms/compare/decap-cms-backend-git-gateway@3.3.1...decap-cms-backend-git-gateway@3.4.0) (2025-07-15)
### Features
- add logo to header ([#7487](https://github.com/decaporg/decap-cms/issues/7487)) ([b540ace](https://github.com/decaporg/decap-cms/commit/b540acec943eb231df6aac7b1d515d9b4b84fa5d))
## [3.3.1](https://github.com/decaporg/decap-cms/compare/decap-cms-backend-git-gateway@3.3.0...decap-cms-backend-git-gateway@3.3.1) (2025-07-10)
**Note:** Version bump only for package decap-cms-backend-git-gateway
# [3.3.0](https://github.com/decaporg/decap-cms/compare/decap-cms-backend-git-gateway@3.2.2...decap-cms-backend-git-gateway@3.3.0) (2025-06-26)
**Note:** Version bump only for package decap-cms-backend-git-gateway
## [3.2.2](https://github.com/decaporg/decap-cms/compare/decap-cms-backend-git-gateway@3.2.1...decap-cms-backend-git-gateway@3.2.2) (2024-08-13)
### Reverts
- Revert "Update dependencies (#7264)" ([22d483a](https://github.com/decaporg/decap-cms/commit/22d483a5b0c654071ae05735ac4f49abdc13d38c)), closes [#7264](https://github.com/decaporg/decap-cms/issues/7264)
## [3.2.1](https://github.com/decaporg/decap-cms/compare/decap-cms-backend-git-gateway@3.2.0...decap-cms-backend-git-gateway@3.2.1) (2024-08-13)
**Note:** Version bump only for package decap-cms-backend-git-gateway
# [3.2.0](https://github.com/decaporg/decap-cms/compare/decap-cms-backend-git-gateway@3.1.1...decap-cms-backend-git-gateway@3.2.0) (2024-08-07)
**Note:** Version bump only for package decap-cms-backend-git-gateway
## [3.1.1](https://github.com/decaporg/decap-cms/compare/decap-cms-backend-git-gateway@3.1.0-beta.1...decap-cms-backend-git-gateway@3.1.1) (2024-03-21)
**Note:** Version bump only for package decap-cms-backend-git-gateway
# [3.1.0](https://github.com/decaporg/decap-cms/compare/decap-cms-backend-git-gateway@3.1.0-beta.1...decap-cms-backend-git-gateway@3.1.0) (2024-02-01)
**Note:** Version bump only for package decap-cms-backend-git-gateway
# [3.1.0-beta.1](https://github.com/decaporg/decap-cms/compare/decap-cms-backend-git-gateway@3.1.0-beta.0...decap-cms-backend-git-gateway@3.1.0-beta.1) (2024-01-31)
**Note:** Version bump only for package decap-cms-backend-git-gateway
# [3.1.0-beta.0](https://github.com/decaporg/decap-cms/compare/decap-cms-backend-git-gateway@3.1.0...decap-cms-backend-git-gateway@3.1.0-beta.0) (2023-10-20)
### Reverts
- Revert "chore(release): publish" ([b89fc89](https://github.com/decaporg/decap-cms/commit/b89fc894dfbb5f4136b2e5427fd25a29378a58c6))
## [3.0.3](https://github.com/decaporg/decap-cms/compare/decap-cms-backend-git-gateway@3.0.2...decap-cms-backend-git-gateway@3.0.3) (2023-10-13)
**Note:** Version bump only for package decap-cms-backend-git-gateway
## [3.0.2](https://github.com/decaporg/decap-cms/compare/decap-cms-backend-git-gateway@3.0.1...decap-cms-backend-git-gateway@3.0.2) (2023-09-06)
### Performance Improvements
- filter by path when loading collection from github backend ([#6898](https://github.com/decaporg/decap-cms/issues/6898)) ([18ef773](https://github.com/decaporg/decap-cms/commit/18ef773f35db1b7ef3ab5a0f25527d87745b9c73))
## [3.0.1](https://github.com/decaporg/decap-cms/compare/decap-cms-backend-git-gateway@3.0.0...decap-cms-backend-git-gateway@3.0.1) (2023-08-25)
### Bug Fixes
- update peer dependencies ([#6886](https://github.com/decaporg/decap-cms/issues/6886)) ([e580ce5](https://github.com/decaporg/decap-cms/commit/e580ce52ce5f80fa040e8fbcab7fed0744f4f695))
# [3.0.0](https://github.com/decaporg/decap-cms/compare/decap-cms-backend-git-gateway@2.14.0...decap-cms-backend-git-gateway@3.0.0) (2023-08-18)
**Note:** Version bump only for package decap-cms-backend-git-gateway
# [2.14.0](https://github.com/decaporg/decap-cms/compare/decap-cms-backend-git-gateway@2.14.0-beta.0...decap-cms-backend-git-gateway@2.14.0) (2023-08-18)
**Note:** Version bump only for package decap-cms-backend-git-gateway
# 2.14.0-beta.0 (2023-08-18)
### Features
- rename packages ([#6863](https://github.com/decaporg/decap-cms/issues/6863)) ([d515e7b](https://github.com/decaporg/decap-cms/commit/d515e7bd33216a775d96887b08c4f7b1962941bb))
## [2.13.2-beta.0](https://github.com/decaporg/decap-cms/compare/decap-cms-backend-git-gateway@2.13.1...decap-cms-backend-git-gateway@2.13.2-beta.0) (2023-07-27)
**Note:** Version bump only for package decap-cms-backend-git-gateway
## [2.13.1](https://github.com/decaporg/decap-cms/compare/decap-cms-backend-git-gateway@2.13.0...decap-cms-backend-git-gateway@2.13.1) (2022-03-08)
**Note:** Version bump only for package decap-cms-backend-git-gateway
# [2.13.0](https://github.com/decaporg/decap-cms/compare/decap-cms-backend-git-gateway@2.12.2...decap-cms-backend-git-gateway@2.13.0) (2021-12-28)
### Bug Fixes
- **decap-cms-ui-default:** use grayDark for button ([#6069](https://github.com/decaporg/decap-cms/issues/6069)) ([ad85514](https://github.com/decaporg/decap-cms/commit/ad85514cba607f066ab7071bee5932b2192466ee)), closes [/github.com/decaporg/decap-cms/issues/1333#issuecomment-998115794](https://github.com//github.com/decaporg/decap-cms/issues/1333/issues/issuecomment-998115794)
### Features
- **backend-gitlab:** initial GraphQL support ([#6059](https://github.com/decaporg/decap-cms/issues/6059)) ([1523a41](https://github.com/decaporg/decap-cms/commit/1523a4140a3d2f4cc01a1548514ae17bc1ad504e))
- disable 'Save' button when there are no changes ([#5595](https://github.com/decaporg/decap-cms/issues/5595)) ([4b566a7](https://github.com/decaporg/decap-cms/commit/4b566a78f4282a6f04caf3deafaaac4d74acfd63))
## [2.12.2](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/compare/decap-cms-backend-git-gateway@2.12.1...decap-cms-backend-git-gateway@2.12.2) (2021-06-01)
**Note:** Version bump only for package decap-cms-backend-git-gateway
## [2.12.1](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/compare/decap-cms-backend-git-gateway@2.12.0...decap-cms-backend-git-gateway@2.12.1) (2021-05-31)
**Note:** Version bump only for package decap-cms-backend-git-gateway
# [2.12.0](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/compare/decap-cms-backend-git-gateway@2.11.11...decap-cms-backend-git-gateway@2.12.0) (2021-05-04)
### Features
- added react 17 as peer dependency in packages ([#5316](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/issues/5316)) ([9e42380](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/commit/9e423805707321396eec137f5b732a5b07a0dd3f))
## [2.11.11](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/compare/decap-cms-backend-git-gateway@2.11.10...decap-cms-backend-git-gateway@2.11.11) (2021-02-25)
**Note:** Version bump only for package decap-cms-backend-git-gateway
## [2.11.10](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/compare/decap-cms-backend-git-gateway@2.11.9...decap-cms-backend-git-gateway@2.11.10) (2021-02-23)
**Note:** Version bump only for package decap-cms-backend-git-gateway
## [2.11.9](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/compare/decap-cms-backend-git-gateway@2.11.8...decap-cms-backend-git-gateway@2.11.9) (2021-02-10)
**Note:** Version bump only for package decap-cms-backend-git-gateway
## [2.11.8](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/compare/decap-cms-backend-git-gateway@2.11.7...decap-cms-backend-git-gateway@2.11.8) (2020-12-15)
### Bug Fixes
- **deps:** update dependency ini to v2 ([#4722](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/issues/4722)) ([e14ace3](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/commit/e14ace373b11510159a9b4d3f977d27ed886b288))
## [2.11.7](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/compare/decap-cms-backend-git-gateway@2.11.6...decap-cms-backend-git-gateway@2.11.7) (2020-12-06)
### Bug Fixes
- **large-media:** mark pointer files as binary ([#4678](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/issues/4678)) ([7697b90](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/commit/7697b907d7bae750f4ec041a184188aa46995320))
## [2.11.6](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/compare/decap-cms-backend-git-gateway@2.11.5...decap-cms-backend-git-gateway@2.11.6) (2020-10-12)
### Bug Fixes
- **deps:** update dependency jwt-decode to v3 ([#4408](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/issues/4408)) ([03492e4](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/commit/03492e4e684ffce3a541ef15edb591d1fd5b5854))
## [2.11.5](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/compare/decap-cms-backend-git-gateway@2.11.4...decap-cms-backend-git-gateway@2.11.5) (2020-09-20)
**Note:** Version bump only for package decap-cms-backend-git-gateway
## [2.11.4](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/compare/decap-cms-backend-git-gateway@2.11.3...decap-cms-backend-git-gateway@2.11.4) (2020-09-15)
**Note:** Version bump only for package decap-cms-backend-git-gateway
## 2.11.3 (2020-09-08)
### Reverts
- Revert "chore(release): publish" ([828bb16](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/commit/828bb16415b8c22a34caa19c50c38b24ffe9ceae))
## 2.11.2 (2020-08-20)
### Reverts
- Revert "chore(release): publish" ([8262487](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/commit/82624879ccbcb16610090041db28f00714d924c8))
## 2.11.1 (2020-07-27)
### Reverts
- Revert "chore(release): publish" ([118d50a](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/commit/118d50a7a70295f25073e564b5161aa2b9883056))
# [2.11.0](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/compare/decap-cms-backend-git-gateway@2.10.5...decap-cms-backend-git-gateway@2.11.0) (2020-06-18)
### Bug Fixes
- handle token expiry ([#3847](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/issues/3847)) ([285c940](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/commit/285c940562548d7bc88de244123ba87ff66fba65))
### Features
- add backend status down indicator ([#3889](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/issues/3889)) ([a50edc7](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/commit/a50edc70553ad6afa1acee6a51996ad226443f8c))
- **backend-gitgateway:** improve deploy preview visibility ([#3882](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/issues/3882)) ([afc9bf4](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/commit/afc9bf4f3fe14ccb60851fc24e68922a6e4a85a9))
## [2.10.5](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/compare/decap-cms-backend-git-gateway@2.10.4...decap-cms-backend-git-gateway@2.10.5) (2020-05-19)
**Note:** Version bump only for package decap-cms-backend-git-gateway
## [2.10.4](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/compare/decap-cms-backend-git-gateway@2.10.3...decap-cms-backend-git-gateway@2.10.4) (2020-05-04)
### Bug Fixes
- **git-gateway:** wait for identity widget to initialize ([#3660](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/issues/3660)) ([6c229c5](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/commit/6c229c5149e3beff05bcfb42ca286d3e9170e54e))
## [2.10.3](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/compare/decap-cms-backend-git-gateway@2.10.2...decap-cms-backend-git-gateway@2.10.3) (2020-04-21)
### Bug Fixes
- **large-media:** match netlify.app as lfs host ([#3642](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/issues/3642)) ([9b79623](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/commit/9b79623bc8b8fe212fb2d15dec8a75328cde9c64))
## [2.10.2](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/compare/decap-cms-backend-git-gateway@2.10.1...decap-cms-backend-git-gateway@2.10.2) (2020-04-01)
**Note:** Version bump only for package decap-cms-backend-git-gateway
## [2.10.1](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/compare/decap-cms-backend-git-gateway@2.10.0...decap-cms-backend-git-gateway@2.10.1) (2020-03-30)
**Note:** Version bump only for package decap-cms-backend-git-gateway
# [2.10.0](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/compare/decap-cms-backend-git-gateway@2.9.1...decap-cms-backend-git-gateway@2.10.0) (2020-03-12)
### Features
- add media lib virtualization ([#3381](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/issues/3381)) ([92e7601](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/commit/92e76011e7a9e8b5370088b0a2c065df66b5f7fb))
- **backend-github:** add pagination ([#3379](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/issues/3379)) ([39f1307](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/commit/39f1307e3a36447da8c9b3ca79b1d7db52ea1a19))
## [2.9.1](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/compare/decap-cms-backend-git-gateway@2.9.0...decap-cms-backend-git-gateway@2.9.1) (2020-03-03)
### Bug Fixes
- **locale:** Remove hard coded string literals ([#3333](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/issues/3333)) ([7c45a3c](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/commit/7c45a3cda983be427864a56e58791565eb9232e2))
# [2.9.0](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/compare/decap-cms-backend-git-gateway@2.8.1...decap-cms-backend-git-gateway@2.9.0) (2020-02-25)
### Features
- **core:** align GitHub metadata handling with other backends ([#3316](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/issues/3316)) ([7e0a8ad](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/commit/7e0a8ad532012576dc5e40bd4e9d54522e307123)), closes [#3292](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/issues/3292)
## [2.8.1](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/compare/decap-cms-backend-git-gateway@2.8.0...decap-cms-backend-git-gateway@2.8.1) (2020-02-22)
### Reverts
- Revert "feat(core): Align GitHub metadata handling with other backends (#3292)" ([5bdd3df](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/commit/5bdd3df9ccbb5149c22d79987ebdcd6cab4b261f)), closes [#3292](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/issues/3292)
# [2.8.0](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/compare/decap-cms-backend-git-gateway@2.7.2...decap-cms-backend-git-gateway@2.8.0) (2020-02-22)
### Features
- **core:** Align GitHub metadata handling with other backends ([#3292](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/issues/3292)) ([8193b5a](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/commit/8193b5ace89d6f14a6c756235a50b186a763b6b1))
## [2.7.2](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/compare/decap-cms-backend-git-gateway@2.7.1...decap-cms-backend-git-gateway@2.7.2) (2020-02-11)
### Bug Fixes
- stringify error message ([#3233](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/issues/3233)) ([249bd7e](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/commit/249bd7ec1ed2197106cbb01f8c05e1b8830aa5bc))
## [2.7.1](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/compare/decap-cms-backend-git-gateway@2.7.0...decap-cms-backend-git-gateway@2.7.1) (2020-01-24)
### Bug Fixes
- **backend-git-gateway:** re-write GitHub pagination links ([#3135](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/issues/3135)) ([834f6b9](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/commit/834f6b9e457f3738ce0f240ddd4cc160aff9e2f5))
# [2.7.0](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/compare/decap-cms-backend-git-gateway@2.6.2...decap-cms-backend-git-gateway@2.7.0) (2020-01-21)
### Bug Fixes
- **git-gateway-gitlab:** fix large media support for editorial workflow ([#3105](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/issues/3105)) ([038803c](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/commit/038803c9f249de386812652372c35c4c53935295))
### Features
- **backend-bitbucket:** Add Git-LFS support ([#3118](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/issues/3118)) ([a48c02d](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/commit/a48c02d852ca5e11055da3a14cefae8d17a68498))
## [2.6.2](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/compare/decap-cms-backend-git-gateway@2.6.1...decap-cms-backend-git-gateway@2.6.2) (2020-01-16)
### Bug Fixes
- don't fail on malformed pointer files ([#3095](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/issues/3095)) ([9210843](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/commit/92108431f0c3df3e99b5aa7f462006ec3fa7777e))
## [2.6.1](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/compare/decap-cms-backend-git-gateway@2.6.0...decap-cms-backend-git-gateway@2.6.1) (2020-01-14)
**Note:** Version bump only for package decap-cms-backend-git-gateway
# [2.6.0](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/compare/decap-cms-backend-git-gateway@2.6.0-beta.0...decap-cms-backend-git-gateway@2.6.0) (2020-01-07)
### Bug Fixes
- rebase open authoring branches ([#2975](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/issues/2975)) ([8c175f6](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/commit/8c175f6132fa18a13763cc563f7d3201c1e3580e))
### Features
- **backend-git-gateway:** handle identity disabled error message ([#3002](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/issues/3002)) ([b5ffccd](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/commit/b5ffccdac506db416c09aaebb38611783487c52a))
# [2.6.0-beta.0](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/compare/decap-cms-backend-git-gateway@2.5.1...decap-cms-backend-git-gateway@2.6.0-beta.0) (2019-12-18)
### Features
- bundle assets with content ([#2958](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/issues/2958)) ([2b41d8a](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/commit/2b41d8a838a9c8a6b21cde2ddd16b9288334e298))
## [2.5.1](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/compare/decap-cms-backend-git-gateway@2.5.0...decap-cms-backend-git-gateway@2.5.1) (2019-11-18)
### Bug Fixes
- **git-gateway:** unpublished entries not loaded for git-gateway(GitHub) ([#2856](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/issues/2856)) ([4a2328b](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/commit/4a2328b2f10ea678184391e4caf235b41323cd3e))
# [2.5.0](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/compare/decap-cms-backend-git-gateway@2.4.6...decap-cms-backend-git-gateway@2.5.0) (2019-11-07)
### Bug Fixes
- **backend-git-gateway:** omit /repos/ when no repo ([#2846](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/issues/2846)) ([da2dab3](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/commit/da2dab305ab7f0655791ef0fb5376e3d5e72897c))
### Features
- add go back to site button ([#2538](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/issues/2538)) ([f206e7e](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/commit/f206e7e5a13fb48ec6b27dce0dbb3a59b61de8f9))
- enable specifying custom open authoring commit message ([#2810](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/issues/2810)) ([2841ff9](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/commit/2841ff9ffe58afcf4dba45514a84a262ad370f1d))
## [2.4.6](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/compare/decap-cms-backend-git-gateway@2.4.5...decap-cms-backend-git-gateway@2.4.6) (2019-09-26)
### Bug Fixes
- **git-gateway:** pass api URL instead of constructing it from repo value ([#2631](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/issues/2631)) ([922c0f3](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/commit/922c0f3))
## [2.4.5](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/compare/decap-cms-backend-git-gateway@2.4.4...decap-cms-backend-git-gateway@2.4.5) (2019-07-24)
**Note:** Version bump only for package decap-cms-backend-git-gateway
## [2.4.4](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/compare/decap-cms-backend-git-gateway@2.4.3...decap-cms-backend-git-gateway@2.4.4) (2019-06-26)
**Note:** Version bump only for package decap-cms-backend-git-gateway
## [2.4.3](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/compare/decap-cms-backend-git-gateway@2.4.2...decap-cms-backend-git-gateway@2.4.3) (2019-06-18)
### Bug Fixes
- **core:** address new entries error for non-github backends ([#2390](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/issues/2390)) ([a5bd6b3](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/commit/a5bd6b3))
## [2.4.2](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/compare/decap-cms-backend-git-gateway@2.4.2-beta.0...decap-cms-backend-git-gateway@2.4.2) (2019-04-10)
**Note:** Version bump only for package decap-cms-backend-git-gateway
## [2.4.2-beta.0](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/compare/decap-cms-backend-git-gateway@2.4.1...decap-cms-backend-git-gateway@2.4.2-beta.0) (2019-04-05)
### Bug Fixes
- **backend-git-gateway:** fix image display w/o large media ([#2271](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/issues/2271)) ([6c3506b](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/commit/6c3506b))
## [2.4.1](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/compare/decap-cms-backend-git-gateway@2.4.1-beta.1...decap-cms-backend-git-gateway@2.4.1) (2019-03-29)
**Note:** Version bump only for package decap-cms-backend-git-gateway
## [2.4.1-beta.1](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/compare/decap-cms-backend-git-gateway@2.4.1-beta.0...decap-cms-backend-git-gateway@2.4.1-beta.1) (2019-03-26)
### Bug Fixes
- export on decap-cms and maps on esm ([#2244](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/issues/2244)) ([6ffd13b](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/commit/6ffd13b))
## [2.4.1-beta.0](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/compare/decap-cms-backend-git-gateway@2.4.0...decap-cms-backend-git-gateway@2.4.1-beta.0) (2019-03-25)
### Bug Fixes
- update peer dep versions ([#2234](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/issues/2234)) ([7987091](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/commit/7987091))
# [2.4.0](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/compare/decap-cms-backend-git-gateway@2.3.1-beta.0...decap-cms-backend-git-gateway@2.4.0) (2019-03-22)
### Features
- add ES module builds ([#2215](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/issues/2215)) ([d142b32](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/commit/d142b32))
## [2.3.1-beta.0](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/compare/decap-cms-backend-git-gateway@2.3.0...decap-cms-backend-git-gateway@2.3.1-beta.0) (2019-03-22)
### Bug Fixes
- **editorial-workflow:** fix LM pointers changing to binary files ([#2228](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/issues/2228)) ([d39a361](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/commit/d39a361))
# [2.3.0](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/compare/decap-cms-backend-git-gateway@2.3.0-beta.0...decap-cms-backend-git-gateway@2.3.0) (2019-03-22)
**Note:** Version bump only for package decap-cms-backend-git-gateway
# [2.3.0-beta.0](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/compare/decap-cms-backend-git-gateway@2.2.5-beta.0...decap-cms-backend-git-gateway@2.3.0-beta.0) (2019-03-21)
### Bug Fixes
- fix umd builds ([#2214](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/issues/2214)) ([e04f6be](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/commit/e04f6be))
### Features
- provide usable UMD builds for all packages ([#2141](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/issues/2141)) ([82cc794](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/commit/82cc794))
## [2.2.5-beta.0](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/compare/decap-cms-backend-git-gateway@2.2.4...decap-cms-backend-git-gateway@2.2.5-beta.0) (2019-03-15)
### Features
- upgrade to Emotion 10 ([#2166](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/issues/2166)) ([ccef446](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/commit/ccef446))
## [2.2.4](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/compare/decap-cms-backend-git-gateway@2.2.3...decap-cms-backend-git-gateway@2.2.4) (2019-03-11)
### Bug Fixes
- **backend-github:** make non-Large Media previews work with Git Gateway+GitHub ([#2151](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/issues/2151)) ([63582dc](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/commit/63582dc))
## [2.2.3](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/compare/decap-cms-backend-git-gateway@2.2.2...decap-cms-backend-git-gateway@2.2.3) (2019-03-08)
**Note:** Version bump only for package decap-cms-backend-git-gateway
## [2.2.2](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/compare/decap-cms-backend-git-gateway@2.2.1...decap-cms-backend-git-gateway@2.2.2) (2019-02-28)
### Bug Fixes
- **git-gateway:** fix previews for GitHub images not in Large Media ([#2125](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/issues/2125)) ([d17f896](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/commit/d17f896))
## [2.2.1](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/compare/decap-cms-backend-git-gateway@2.2.0...decap-cms-backend-git-gateway@2.2.1) (2019-02-26)
**Note:** Version bump only for package decap-cms-backend-git-gateway
# [2.2.0](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/compare/decap-cms-backend-git-gateway@2.1.2...decap-cms-backend-git-gateway@2.2.0) (2019-02-08)
### Features
- **workflow:** add deploy preview links ([#2028](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/issues/2028)) ([15d221d](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/commit/15d221d))
## [2.1.2](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/compare/decap-cms-backend-git-gateway@2.1.1...decap-cms-backend-git-gateway@2.1.2) (2018-12-11)
### Bug Fixes
- **decap-cms-backend-git-gateway:** content-type may have charset ([#1951](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/issues/1951)) ([c74dbae](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/commit/c74dbae))
## [2.1.1](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/compare/decap-cms-backend-git-gateway@2.1.0...decap-cms-backend-git-gateway@2.1.1) (2018-11-29)
### Bug Fixes
- **backend-git-gateway:** double slashes when gateway_url contained a backend ([#1712](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/issues/1712)) ([6de47cd](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/commit/6de47cd))
# [2.1.0](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/compare/decap-cms-backend-git-gateway@2.0.8...decap-cms-backend-git-gateway@2.1.0) (2018-11-12)
### Bug Fixes
- **identity:** switch user name reference to full_name ([#1809](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/issues/1809)) ([55d45a8](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/commit/55d45a8))
### Features
- allow custom logo on auth page ([#1818](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/issues/1818)) ([c6ae1e8](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/commit/c6ae1e8))
<a name="2.0.8"></a>
## [2.0.8](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/compare/decap-cms-backend-git-gateway@2.0.7...decap-cms-backend-git-gateway@2.0.8) (2018-09-06)
**Note:** Version bump only for package decap-cms-backend-git-gateway
<a name="2.0.7"></a>
## [2.0.7](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/compare/decap-cms-backend-git-gateway@2.0.6...decap-cms-backend-git-gateway@2.0.7) (2018-08-27)
**Note:** Version bump only for package decap-cms-backend-git-gateway
<a name="2.0.6"></a>
## [2.0.6](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/compare/decap-cms-backend-git-gateway@2.0.5...decap-cms-backend-git-gateway@2.0.6) (2018-08-24)
**Note:** Version bump only for package decap-cms-backend-git-gateway
<a name="2.0.5"></a>
## [2.0.5](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/compare/decap-cms-backend-git-gateway@2.0.4...decap-cms-backend-git-gateway@2.0.5) (2018-08-07)
### Bug Fixes
- **workflow:** fix workflow entries not appearing ([#1581](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/issues/1581)) ([95c8de0](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/commit/95c8de0))
<a name="2.0.4"></a>
## [2.0.4](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/compare/decap-cms-backend-git-gateway@2.0.3...decap-cms-backend-git-gateway@2.0.4) (2018-08-01)
**Note:** Version bump only for package decap-cms-backend-git-gateway
<a name="2.0.3"></a>
## [2.0.3](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/compare/decap-cms-backend-git-gateway@2.0.2...decap-cms-backend-git-gateway@2.0.3) (2018-07-28)
### Bug Fixes
- **git-gateway:** correct `proxied` value for proxied backends ([#1540](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/issues/1540)) ([f7dba87](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway/commit/f7dba87))
<a name="2.0.2"></a>
## 2.0.2 (2018-07-27)
### Bug Fixes
- **git-gateway:** pass options through git-gateway backend ([#1532](https://github.com/decaporg/decap-cms/issues/1532)) ([4c5436a](https://github.com/decaporg/decap-cms/commit/4c5436a))
<a name="2.0.1"></a>
## 2.0.1 (2018-07-26)
<a name="2.0.0"></a>
# 2.0.0 (2018-07-26)
### Bug Fixes
- **bitbucket:** fix rebasing mistakes in bitbucket backend and deps ([#1522](https://github.com/decaporg/decap-cms/issues/1522)) ([bdfd944](https://github.com/decaporg/decap-cms/commit/bdfd944))

View File

@@ -0,0 +1,53 @@
# Git Gateway
Netlify's [gateway](https://github.com/netlify/git-gateway) to hosted git APIs.
## Code structure
`Implementation` for [File Management System API](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-lib-util/README.md) based on `Api`.
`Api` and `Implementation` from backend-[github](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-github/README.md)/[gitlab](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/README.md)/[bitbacket](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-bitbacket/README.md) extended with Netlify-specific `LargeMedia(LFS)` and `JWT` auth.
`AuthenticationPage` - uses [lib-auth](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-lib-auth/README.md) and implements Netlify Identity authentication flow.
`PKCEAuthenticationPage` = uses [lib-auth](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-lib-auth/README.md) and implements OAuth2 PKCE authentication flow. Enabled if the config.auth_type is set to `pkce`.
Look at tests or types for more info.
## Debugging
When debugging the CMS with Git Gateway you must:
1. Have a Netlify site with [Git Gateway](https://docs.netlify.com/visitor-access/git-gateway/) and [Netlify Identity](https://docs.netlify.com/visitor-access/identity/) enabled. An easy way to create such a site is to use a [template](https://www.decapcms.org/docs/start-with-a-template/), for example the [Gatsby template](https://app.netlify.com/start/deploy?repository=https://github.com/decaporg/gatsby-starter-decap-cms&stack=cms)
2. Tell the CMS the URL of your Netlify site using a local storage item. To do so:
1. Open `http://localhost:8080/` in the browser
2. Write the below command and press enter: `localStorage.setItem('netlifySiteURL', 'https://yourwebsiteurl.netlify.app/')`
3. To be sure, you can run this command as well: `localStorage.getItem('netlifySiteURL')`
4. Refresh the page
5. You should be able to log in via your Netlify Identity email/password
## PKCE with custom Git-Gateway
To use a custom Git-Gateway implementation with PKCE authentication, use a configuration similar to the following:
backend:
name: git-gateway
# Enables PKCE authentication with the git-gateway backend. After auth,
# sends the access_token for all requests to the git-gateway host.
auth_type: pkce
# The base OAuth2 URL. Here is an obfuscated AWS Cognito example.
base_url: https://your-cognito-instance.auth.us-east-1.amazoncognito.com
# If you need to customize the authorize or token endpoints for PKCE, do that here
#auth_endpoint: oauth2/authorize
#auth_token_endpoint: oauth2/token
# The OAuth2 client ID
app_id: your-oauth2-client-id
# The base URL of your custom git-gateway. Note that the last part of the path
# should be "bitbucket", "gitlab", or "github", so the implementation can automatically
# determine which backend API to use when making requests.
gateway_url: https://your.gitgateway.host/git-gateway/bitbucket/
# Override the Netlify git-gateway status check
status_endpoint: https://your.gitgateway.host/api/v2/components.json
# Optional: defaults to "master"
branch: main

View File

@@ -0,0 +1,42 @@
{
"name": "decap-cms-backend-git-gateway",
"description": "Git Gateway backend for Decap CMS",
"version": "3.4.1",
"repository": "https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-git-gateway",
"bugs": "https://github.com/decaporg/decap-cms/issues",
"module": "dist/esm/index.js",
"main": "dist/decap-cms-backend-git-gateway.js",
"license": "MIT",
"keywords": [
"decap-cms",
"backend",
"git-gateway",
"gateway"
],
"sideEffects": false,
"scripts": {
"develop": "npm run build:esm -- --watch",
"build": "cross-env NODE_ENV=production webpack",
"build:esm": "cross-env NODE_ENV=esm babel src --out-dir dist/esm --ignore \"**/__tests__\" --root-mode upward --extensions \".js,.jsx,.ts,.tsx\""
},
"dependencies": {
"gotrue-js": "^0.9.24",
"ini": "^2.0.0",
"jwt-decode": "^3.0.0",
"minimatch": "^7.0.0"
},
"peerDependencies": {
"@emotion/react": "^11.11.1",
"@emotion/styled": "^11.11.0",
"decap-cms-backend-bitbucket": "^3.0.0",
"decap-cms-backend-github": "^3.0.0",
"decap-cms-backend-gitlab": "^3.0.0",
"decap-cms-lib-auth": "^3.0.0",
"decap-cms-lib-util": "^3.0.0",
"decap-cms-ui-auth": "^3.0.0",
"decap-cms-ui-default": "^3.0.0",
"lodash": "^4.17.11",
"prop-types": "^15.7.2",
"react": "^19.1.0"
}
}

View File

@@ -0,0 +1,133 @@
import { API as GithubAPI } from 'decap-cms-backend-github';
import { APIError } from 'decap-cms-lib-util';
import type { Config as GitHubConfig, Diff } from 'decap-cms-backend-github/src/API';
import type { FetchError } from 'decap-cms-lib-util';
import type { Octokit } from '@octokit/rest';
type Config = Omit<GitHubConfig, 'getUser'> & {
apiRoot: string;
tokenPromise: () => Promise<string>;
commitAuthor: { name: string };
isLargeMedia: (filename: string) => Promise<boolean>;
};
export default class API extends GithubAPI {
tokenPromise: () => Promise<string>;
commitAuthor: { name: string };
isLargeMedia: (filename: string) => Promise<boolean>;
constructor(config: Config) {
super({
getUser: () => Promise.reject('Never used'),
...config,
});
this.apiRoot = config.apiRoot;
this.tokenPromise = config.tokenPromise;
this.commitAuthor = config.commitAuthor;
this.isLargeMedia = config.isLargeMedia;
this.repoURL = '';
this.originRepoURL = '';
}
hasWriteAccess() {
return this.getDefaultBranch()
.then(() => true)
.catch((error: FetchError) => {
if (error.status === 401) {
if (error.message === 'Bad credentials') {
throw new APIError(
'Git Gateway Error: Please ask your site administrator to reissue the Git Gateway token.',
error.status,
'Git Gateway',
);
} else {
return false;
}
} else if (
error.status === 404 &&
(error.message === undefined || error.message === 'Unable to locate site configuration')
) {
throw new APIError(
`Git Gateway Error: Please make sure Git Gateway is enabled on your site.`,
error.status,
'Git Gateway',
);
} else {
console.error('Problem fetching repo data from Git Gateway');
throw error;
}
});
}
requestHeaders(headers = {}) {
return this.tokenPromise().then(jwtToken => {
const baseHeader = {
Authorization: `Bearer ${jwtToken}`,
'Content-Type': 'application/json; charset=utf-8',
...headers,
};
return baseHeader;
});
}
handleRequestError(error: FetchError & { msg: string }, responseStatus: number) {
throw new APIError(error.message || error.msg, responseStatus, 'Git Gateway');
}
user() {
return Promise.resolve({ login: '', ...this.commitAuthor });
}
async getHeadReference(head: string) {
if (!this.repoOwner) {
// get the repo owner from the branch url
// this is required for returning the full head reference, e.g. owner:head
// when filtering pull requests based on the head
const branch = await this.getDefaultBranch();
const self = branch._links.self;
const regex = new RegExp('https?://.+?/repos/(.+?)/');
const owner = self.match(regex);
this.repoOwner = owner ? owner[1] : '';
}
return super.getHeadReference(head);
}
commit(message: string, changeTree: { parentSha?: string; sha: string }) {
const commitParams: {
message: string;
tree: string;
parents: string[];
author?: { name: string; date: string };
} = {
message,
tree: changeTree.sha,
parents: changeTree.parentSha ? [changeTree.parentSha] : [],
};
if (this.commitAuthor) {
commitParams.author = {
...this.commitAuthor,
date: new Date().toISOString(),
};
}
return this.request('/git/commits', {
method: 'POST',
body: JSON.stringify(commitParams),
});
}
nextUrlProcessor() {
return (url: string) => url.replace(/^(?:[a-z]+:\/\/.+?\/.+?\/.+?\/)/, `${this.apiRoot}/`);
}
async diffFromFile(file: Octokit.ReposCompareCommitsResponseFilesItem): Promise<Diff> {
const diff = await super.diffFromFile(file);
return {
...diff,
binary: diff.binary || (await this.isLargeMedia(file.filename)),
};
}
}

View File

@@ -0,0 +1,30 @@
import { API as GitlabAPI } from 'decap-cms-backend-gitlab';
import { unsentRequest } from 'decap-cms-lib-util';
import type { Config as GitLabConfig, CommitAuthor } from 'decap-cms-backend-gitlab/src/API';
import type { ApiRequest } from 'decap-cms-lib-util';
type Config = GitLabConfig & { tokenPromise: () => Promise<string>; commitAuthor: CommitAuthor };
export default class API extends GitlabAPI {
tokenPromise: () => Promise<string>;
constructor(config: Config) {
super(config);
this.tokenPromise = config.tokenPromise;
this.commitAuthor = config.commitAuthor;
this.repoURL = '';
}
withAuthorizationHeaders = async (req: ApiRequest) => {
const token = await this.tokenPromise();
return unsentRequest.withHeaders(
{
Authorization: `Bearer ${token}`,
},
req,
);
};
hasWriteAccess = () => Promise.resolve(true);
}

View File

@@ -0,0 +1,97 @@
import API from '../GitHubAPI';
describe('github API', () => {
describe('request', () => {
beforeEach(() => {
const fetch = jest.fn();
global.fetch = fetch;
});
afterEach(() => {
jest.resetAllMocks();
});
it('should fetch url with authorization header', async () => {
const api = new API({
apiRoot: 'https://site.netlify.com/.netlify/git/github',
tokenPromise: () => Promise.resolve('token'),
});
fetch.mockResolvedValue({
text: jest.fn().mockResolvedValue('some response'),
ok: true,
status: 200,
headers: { get: () => '' },
});
const result = await api.request('/some-path');
expect(result).toEqual('some response');
expect(fetch).toHaveBeenCalledTimes(1);
expect(fetch).toHaveBeenCalledWith('https://site.netlify.com/.netlify/git/github/some-path', {
cache: 'no-cache',
headers: {
Authorization: 'Bearer token',
'Content-Type': 'application/json; charset=utf-8',
},
signal: expect.any(AbortSignal),
});
});
it('should throw error on not ok response with message property', async () => {
const api = new API({
apiRoot: 'https://site.netlify.com/.netlify/git/github',
tokenPromise: () => Promise.resolve('token'),
});
fetch.mockResolvedValue({
text: jest.fn().mockResolvedValue({ message: 'some error' }),
ok: false,
status: 404,
headers: { get: () => '' },
});
await expect(api.request('some-path')).rejects.toThrow(
expect.objectContaining({
message: 'some error',
name: 'API_ERROR',
status: 404,
api: 'Git Gateway',
}),
);
});
it('should throw error on not ok response with msg property', async () => {
const api = new API({
apiRoot: 'https://site.netlify.com/.netlify/git/github',
tokenPromise: () => Promise.resolve('token'),
});
fetch.mockResolvedValue({
text: jest.fn().mockResolvedValue({ msg: 'some error' }),
ok: false,
status: 404,
headers: { get: () => '' },
});
await expect(api.request('some-path')).rejects.toThrow(
expect.objectContaining({
message: 'some error',
name: 'API_ERROR',
status: 404,
api: 'Git Gateway',
}),
);
});
});
describe('nextUrlProcessor', () => {
it('should re-write github url', () => {
const api = new API({
apiRoot: 'https://site.netlify.com/.netlify/git/github',
});
expect(api.nextUrlProcessor()('https://api.github.com/repositories/10000/pulls')).toEqual(
'https://site.netlify.com/.netlify/git/github/pulls',
);
});
});
});

View File

@@ -0,0 +1,645 @@
import GoTrue from 'gotrue-js';
import jwtDecode from 'jwt-decode';
import get from 'lodash/get';
import pick from 'lodash/pick';
import intersection from 'lodash/intersection';
import ini from 'ini';
import {
APIError,
unsentRequest,
basename,
entriesByFiles,
parsePointerFile,
getLargeMediaPatternsFromGitAttributesFile,
getPointerFileForMediaFileObj,
getLargeMediaFilteredMediaFiles,
AccessTokenError,
PreviewState,
} from 'decap-cms-lib-util';
import { GitHubBackend } from 'decap-cms-backend-github';
import { GitLabBackend } from 'decap-cms-backend-gitlab';
import { BitbucketBackend, API as BitBucketAPI } from 'decap-cms-backend-bitbucket';
import { NetlifyAuthenticationPage, PKCEAuthenticationPage } from 'decap-cms-ui-auth';
import GitHubAPI from './GitHubAPI';
import GitLabAPI from './GitLabAPI';
import { getClient } from './netlify-lfs-client';
import type { Client } from './netlify-lfs-client';
import type {
ApiRequest,
AssetProxy,
PersistOptions,
Entry,
Cursor,
Implementation,
DisplayURL,
User,
Credentials,
Config,
ImplementationFile,
DisplayURLObject,
} from 'decap-cms-lib-util';
const STATUS_PAGE = 'https://www.netlifystatus.com';
const GIT_GATEWAY_STATUS_ENDPOINT = `${STATUS_PAGE}/api/v2/components.json`;
const GIT_GATEWAY_OPERATIONAL_UNITS = ['Git Gateway'];
type GitGatewayStatus = {
id: string;
name: string;
status: string;
};
type NetlifyIdentity = {
logout: () => void;
currentUser: () => User;
on: (event: string, args: unknown) => void;
init: () => void;
store: { user: unknown; modal: { page: string }; saving: boolean };
};
type AuthClient = {
logout: () => void;
currentUser: () => unknown;
login?(email: string, password: string, remember?: boolean): Promise<unknown>;
clearStore: () => void;
};
declare global {
interface Window {
netlifyIdentity?: NetlifyIdentity;
}
}
const localHosts: Record<string, boolean> = {
localhost: true,
'127.0.0.1': true,
'0.0.0.0': true,
};
const defaults = {
identity: '/.netlify/identity',
gateway: '/.netlify/git',
largeMedia: '/.netlify/large-media',
};
function getEndpoint(endpoint: string, netlifySiteURL: string | null) {
if (
localHosts[document.location.host.split(':').shift() as string] &&
netlifySiteURL &&
endpoint.match(/^\/\.netlify\//)
) {
const parts = [];
if (netlifySiteURL) {
parts.push(netlifySiteURL);
if (!netlifySiteURL.match(/\/$/)) {
parts.push('/');
}
}
parts.push(endpoint.replace(/^\//, ''));
return parts.join('');
}
return endpoint;
}
// wait for identity widget to initialize
// force init on timeout
let initPromise = Promise.resolve() as Promise<unknown>;
if (window.netlifyIdentity) {
let initialized = false;
initPromise = Promise.race([
new Promise<void>(resolve => {
window.netlifyIdentity?.on('init', () => {
initialized = true;
resolve();
});
}),
new Promise(resolve => setTimeout(resolve, 2500)).then(() => {
if (!initialized) {
console.log('Manually initializing identity widget');
window.netlifyIdentity?.init();
}
}),
]);
}
interface GitGatewayUser extends Credentials {
jwt: () => Promise<string>;
email: string;
user_metadata: { full_name: string; avatar_url: string };
}
async function apiGet(path: string) {
const apiRoot = 'https://api.netlify.com/api/v1/sites';
const response = await fetch(`${apiRoot}/${path}`).then(res => res.json());
return response;
}
export default class GitGateway implements Implementation {
config: Config;
api?: GitHubAPI | GitLabAPI | BitBucketAPI;
branch: string;
squashMerges: boolean;
cmsLabelPrefix: string;
mediaFolder: string;
transformImages: boolean;
gatewayUrl: string;
gitGatewayStatusEndpoint: string;
netlifyLargeMediaURL: string;
backendType: string | null;
apiUrl: string;
authType: 'pkce' | 'netlify';
authClient?: AuthClient;
backend: GitHubBackend | GitLabBackend | BitbucketBackend | null;
acceptRoles?: string[];
tokenPromise?: () => Promise<string>;
_largeMediaClientPromise?: Promise<Client>;
options: {
proxied: boolean;
API: GitHubAPI | GitLabAPI | BitBucketAPI | null;
initialWorkflowStatus: string;
};
constructor(config: Config, options = {}) {
this.options = {
proxied: true,
API: null,
initialWorkflowStatus: '',
...options,
};
this.config = config;
this.branch = config.backend.branch?.trim() || 'master';
this.squashMerges = config.backend.squash_merges || false;
this.cmsLabelPrefix = config.backend.cms_label_prefix || '';
this.mediaFolder = config.media_folder;
this.gitGatewayStatusEndpoint = config.backend.status_endpoint || GIT_GATEWAY_STATUS_ENDPOINT;
const { use_large_media_transforms_in_media_library: transformImages = true } = config.backend;
this.transformImages = transformImages;
const netlifySiteURL = localStorage.getItem('netlifySiteURL');
this.apiUrl = getEndpoint(config.backend.identity_url || defaults.identity, netlifySiteURL);
this.gatewayUrl = getEndpoint(config.backend.gateway_url || defaults.gateway, netlifySiteURL);
this.netlifyLargeMediaURL = getEndpoint(
config.backend.large_media_url || defaults.largeMedia,
netlifySiteURL,
);
const backendTypeRegex = /\/(github|gitlab|bitbucket)\/?$/;
const backendTypeMatches = this.gatewayUrl.match(backendTypeRegex);
if (backendTypeMatches) {
this.backendType = backendTypeMatches[1];
this.gatewayUrl = this.gatewayUrl.replace(backendTypeRegex, '');
} else {
this.backendType = null;
}
this.backend = null;
if (config.backend.auth_type === 'pkce') {
this.authType = 'pkce';
} else {
this.authType = 'netlify';
NetlifyAuthenticationPage.authClient = () => this.getAuthClient();
}
}
isGitBackend() {
return true;
}
async status() {
const api = await fetch(this.gitGatewayStatusEndpoint)
.then(res => res.json())
.then(res => {
return res['components']
.filter((statusComponent: GitGatewayStatus) =>
GIT_GATEWAY_OPERATIONAL_UNITS.includes(statusComponent.name),
)
.every((statusComponent: GitGatewayStatus) => statusComponent.status === 'operational');
})
.catch(e => {
console.warn('Failed getting Git Gateway status', e);
return true;
});
let auth = false;
// no need to check auth if api is down
if (api) {
auth =
(await this.tokenPromise?.()
.then(token => !!token)
.catch(e => {
console.warn('Failed getting Identity token', e);
return false;
})) || false;
}
return { auth: { status: auth }, api: { status: api, statusPage: STATUS_PAGE } };
}
async getAuthClient() {
if (this.authClient) {
return this.authClient;
}
await initPromise;
if (window.netlifyIdentity) {
this.authClient = {
logout: () => window.netlifyIdentity?.logout(),
currentUser: () => window.netlifyIdentity?.currentUser(),
clearStore: () => {
const store = window.netlifyIdentity?.store;
if (store) {
store.user = null;
store.modal.page = 'login';
store.saving = false;
}
},
};
} else {
const goTrue = new GoTrue({ APIUrl: this.apiUrl });
this.authClient = {
logout: () => {
const user = goTrue.currentUser();
if (user) {
return user.logout();
}
},
currentUser: () => goTrue.currentUser(),
login: goTrue.login.bind(goTrue),
clearStore: () => undefined,
};
}
return this.authClient;
}
requestFunction = (req: ApiRequest) =>
this.tokenPromise!()
.then(
token => unsentRequest.withHeaders({ Authorization: `Bearer ${token}` }, req) as ApiRequest,
)
.then(unsentRequest.performRequest);
authenticate(credentials: Credentials) {
const user = credentials as GitGatewayUser;
if (user.jwt) {
// Netlify auth
this.tokenPromise = async () => {
try {
const func = user.jwt.bind(user);
return await func();
} catch (error) {
throw new AccessTokenError(`Failed getting access token: ${error.message}`);
}
};
} else {
// OAuth
this.tokenPromise = async () => (typeof user.token === 'string' ? user.token : '');
}
return this.tokenPromise!().then(async token => {
if (!this.backendType) {
const {
github_enabled: githubEnabled,
gitlab_enabled: gitlabEnabled,
bitbucket_enabled: bitbucketEnabled,
roles,
} = await unsentRequest
.fetchWithTimeout(`${this.gatewayUrl}/settings`, {
headers: { Authorization: `Bearer ${token}` },
})
.then(async res => {
const contentType = res.headers.get('Content-Type') || '';
if (!contentType.includes('application/json') && !contentType.includes('text/json')) {
throw new APIError(
`Your Git Gateway backend is not returning valid settings. Please make sure it is enabled.`,
res.status,
'Git Gateway',
);
}
const body = await res.json();
if (!res.ok) {
throw new APIError(
`Git Gateway Error: ${body.message ? body.message : body}`,
res.status,
'Git Gateway',
);
}
return body;
});
this.acceptRoles = roles;
if (githubEnabled) {
this.backendType = 'github';
} else if (gitlabEnabled) {
this.backendType = 'gitlab';
} else if (bitbucketEnabled) {
this.backendType = 'bitbucket';
}
}
if (this.acceptRoles && this.acceptRoles.length > 0) {
const userRoles = get(jwtDecode(token), 'app_metadata.roles', []);
const validRole = intersection(userRoles, this.acceptRoles).length > 0;
if (!validRole) {
throw new Error("You don't have sufficient permissions to access Decap CMS");
}
}
const userData = {
name: user.user_metadata.full_name || user.email.split('@').shift()!,
email: user.email,
avatar_url: user.user_metadata.avatar_url,
metadata: user.user_metadata,
};
const apiConfig = {
apiRoot: `${this.gatewayUrl}/${this.backendType}`,
branch: this.branch,
tokenPromise: this.tokenPromise!,
commitAuthor: pick(userData, ['name', 'email']),
isLargeMedia: (filename: string) => this.isLargeMediaFile(filename),
squashMerges: this.squashMerges,
cmsLabelPrefix: this.cmsLabelPrefix,
initialWorkflowStatus: this.options.initialWorkflowStatus,
};
if (this.backendType === 'github') {
this.api = new GitHubAPI(apiConfig);
this.backend = new GitHubBackend(this.config, { ...this.options, API: this.api });
} else if (this.backendType === 'gitlab') {
this.api = new GitLabAPI(apiConfig);
this.backend = new GitLabBackend(this.config, { ...this.options, API: this.api });
} else if (this.backendType === 'bitbucket') {
this.api = new BitBucketAPI({
...apiConfig,
requestFunction: this.requestFunction,
hasWriteAccess: async () => true,
});
this.backend = new BitbucketBackend(this.config, { ...this.options, API: this.api });
}
if (!(await this.api!.hasWriteAccess())) {
throw new Error("You don't have sufficient permissions to access Decap CMS");
}
return {
name: userData.name,
login: userData.email,
avatar_url: userData.avatar_url,
} as unknown as User;
});
}
async restoreUser() {
const client = await this.getAuthClient();
const user = client.currentUser();
if (!user) return Promise.reject();
return this.authenticate(user as Credentials);
}
authComponent() {
return this.authType === 'pkce' ? PKCEAuthenticationPage : NetlifyAuthenticationPage;
}
async logout() {
const client = await this.getAuthClient();
try {
client.logout();
} catch (e) {
// due to a bug in the identity widget (gotrue-js actually) the store is not reset if logout fails
// TODO: remove after https://github.com/netlify/gotrue-js/pull/83 is merged
client.clearStore();
}
}
getToken() {
return this.tokenPromise!();
}
async entriesByFolder(folder: string, extension: string, depth: number) {
return this.backend!.entriesByFolder(folder, extension, depth);
}
allEntriesByFolder(folder: string, extension: string, depth: number, pathRegex?: RegExp) {
return this.backend!.allEntriesByFolder(folder, extension, depth, pathRegex);
}
entriesByFiles(files: ImplementationFile[]) {
return this.backend!.entriesByFiles(files);
}
getEntry(path: string) {
return this.backend!.getEntry(path);
}
async unpublishedEntryDataFile(collection: string, slug: string, path: string, id: string) {
return this.backend!.unpublishedEntryDataFile(collection, slug, path, id);
}
async isLargeMediaFile(path: string) {
const client = await this.getLargeMediaClient();
return client.enabled && client.matchPath(path);
}
async unpublishedEntryMediaFile(collection: string, slug: string, path: string, id: string) {
const isLargeMedia = await this.isLargeMediaFile(path);
if (isLargeMedia) {
const branch = this.backend!.getBranch(collection, slug);
const { url, blob } = await this.getLargeMediaDisplayURL({ path, id }, branch);
return {
id,
name: basename(path),
path,
url,
displayURL: url,
file: new File([blob], basename(path)),
size: blob.size,
};
} else {
return this.backend!.unpublishedEntryMediaFile(collection, slug, path, id);
}
}
getMedia(mediaFolder = this.mediaFolder) {
return this.backend!.getMedia(mediaFolder);
}
// this method memoizes this._getLargeMediaClient so that there can
// only be one client at a time
getLargeMediaClient() {
if (this._largeMediaClientPromise) {
return this._largeMediaClientPromise;
}
this._largeMediaClientPromise = this._getLargeMediaClient();
return this._largeMediaClientPromise;
}
_getLargeMediaClient() {
const netlifyLargeMediaEnabledPromise = this.api!.readFile('.lfsconfig')
.then(config => ini.decode<{ lfs: { url: string } }>(config as string))
.then(({ lfs: { url } }) => new URL(url))
.then(lfsURL => ({
enabled: lfsURL.hostname.endsWith('netlify.com') || lfsURL.hostname.endsWith('netlify.app'),
}))
.catch((err: Error) => ({ enabled: false, err }));
const lfsPatternsPromise = this.api!.readFile('.gitattributes')
.then(attributes => getLargeMediaPatternsFromGitAttributesFile(attributes as string))
.then((patterns: string[]) => ({ err: null, patterns }))
.catch((err: Error) => {
if (err.message.includes('404')) {
console.log('This 404 was expected and handled appropriately.');
return { err: null, patterns: [] as string[] };
} else {
return { err, patterns: [] as string[] };
}
});
return Promise.all([netlifyLargeMediaEnabledPromise, lfsPatternsPromise]).then(
([{ enabled: maybeEnabled }, { patterns, err: patternsErr }]) => {
const enabled = maybeEnabled && !patternsErr;
// We expect LFS patterns to exist when the .lfsconfig states
// that we're using Netlify Large Media
if (maybeEnabled && patternsErr) {
console.error(patternsErr);
}
return getClient({
enabled,
rootURL: this.netlifyLargeMediaURL,
makeAuthorizedRequest: this.requestFunction,
patterns,
transformImages: this.transformImages ? { nf_resize: 'fit', w: 560, h: 320 } : false,
});
},
);
}
async getLargeMediaDisplayURL(
{ path, id }: { path: string; id: string | null },
branch = this.branch,
) {
const readFile = (
path: string,
id: string | null | undefined,
{ parseText }: { parseText: boolean },
) => this.api!.readFile(path, id, { branch, parseText });
const items = await entriesByFiles(
[{ path, id }],
readFile,
this.api!.readFileMetadata.bind(this.api),
'Git-Gateway',
);
const entry = items[0];
const pointerFile = parsePointerFile(entry.data);
if (!pointerFile.sha) {
console.warn(`Failed parsing pointer file ${path}`);
return { url: path, blob: new Blob() };
}
const client = await this.getLargeMediaClient();
const { url, blob } = await client.getDownloadURL(pointerFile);
return { url, blob };
}
async getMediaDisplayURL(displayURL: DisplayURL) {
const { path, id } = displayURL as DisplayURLObject;
const isLargeMedia = await this.isLargeMediaFile(path);
if (isLargeMedia) {
const { url } = await this.getLargeMediaDisplayURL({ path, id });
return url;
}
if (typeof displayURL === 'string') {
return displayURL;
}
const url = await this.backend!.getMediaDisplayURL(displayURL);
return url;
}
async getMediaFile(path: string) {
const isLargeMedia = await this.isLargeMediaFile(path);
if (isLargeMedia) {
const { url, blob } = await this.getLargeMediaDisplayURL({ path, id: null });
return {
id: url,
name: basename(path),
path,
url,
displayURL: url,
file: new File([blob], basename(path)),
size: blob.size,
};
}
return this.backend!.getMediaFile(path);
}
async persistEntry(entry: Entry, options: PersistOptions) {
const client = await this.getLargeMediaClient();
if (client.enabled) {
const assets = await getLargeMediaFilteredMediaFiles(client, entry.assets);
return this.backend!.persistEntry({ ...entry, assets }, options);
} else {
return this.backend!.persistEntry(entry, options);
}
}
async persistMedia(mediaFile: AssetProxy, options: PersistOptions) {
const { fileObj, path } = mediaFile;
const displayURL = fileObj ? URL.createObjectURL(fileObj) : '';
const client = await this.getLargeMediaClient();
const fixedPath = path.startsWith('/') ? path.slice(1) : path;
const isLargeMedia = await this.isLargeMediaFile(fixedPath);
if (isLargeMedia) {
const persistMediaArgument = await getPointerFileForMediaFileObj(
client,
fileObj as File,
path,
);
return {
...(await this.backend!.persistMedia(persistMediaArgument, options)),
displayURL,
};
}
return await this.backend!.persistMedia(mediaFile, options);
}
deleteFiles(paths: string[], commitMessage: string) {
return this.backend!.deleteFiles(paths, commitMessage);
}
async getDeployPreview(collection: string, slug: string) {
let preview = await this.backend!.getDeployPreview(collection, slug);
if (!preview) {
try {
// if the commit doesn't have a status, try to use Netlify API directly
// this is useful when builds are queue up in Netlify and don't have a commit status yet
// and only works with public logs at the moment
// TODO: get Netlify API Token and use it to access private logs
const siteId = new URL(localStorage.getItem('netlifySiteURL') || '').hostname;
const site = await apiGet(siteId);
const deploys: { state: string; commit_ref: string; deploy_url: string }[] = await apiGet(
`${site.id}/deploys?per_page=100`,
);
if (deploys.length > 0) {
const ref = await this.api!.getUnpublishedEntrySha(collection, slug);
const deploy = deploys.find(d => d.commit_ref === ref);
if (deploy) {
preview = {
status: deploy.state === 'ready' ? PreviewState.Success : PreviewState.Other,
url: deploy.deploy_url,
};
}
}
// eslint-disable-next-line no-empty
} catch (e) {}
}
return preview;
}
unpublishedEntries() {
return this.backend!.unpublishedEntries();
}
unpublishedEntry({ id, collection, slug }: { id?: string; collection?: string; slug?: string }) {
return this.backend!.unpublishedEntry({ id, collection, slug });
}
updateUnpublishedEntryStatus(collection: string, slug: string, newStatus: string) {
return this.backend!.updateUnpublishedEntryStatus(collection, slug, newStatus);
}
deleteUnpublishedEntry(collection: string, slug: string) {
return this.backend!.deleteUnpublishedEntry(collection, slug);
}
publishUnpublishedEntry(collection: string, slug: string) {
return this.backend!.publishUnpublishedEntry(collection, slug);
}
traverseCursor(cursor: Cursor, action: string) {
return this.backend!.traverseCursor!(cursor, action);
}
}

View File

@@ -0,0 +1,6 @@
import GitGatewayBackend from './implementation';
export const DecapCmsBackendGitGateway = {
GitGatewayBackend,
};
export { GitGatewayBackend };

View File

@@ -0,0 +1,181 @@
import { flow, fromPairs, map } from 'lodash/fp';
import isPlainObject from 'lodash/isPlainObject';
import isEmpty from 'lodash/isEmpty';
import minimatch from 'minimatch';
import { unsentRequest } from 'decap-cms-lib-util';
import type { ApiRequest, PointerFile } from 'decap-cms-lib-util';
type MakeAuthorizedRequest = (req: ApiRequest) => Promise<Response>;
type ImageTransformations = { nf_resize: string; w: number; h: number };
type ClientConfig = {
rootURL: string;
makeAuthorizedRequest: MakeAuthorizedRequest;
patterns: string[];
enabled: boolean;
transformImages: ImageTransformations | boolean;
};
export function matchPath({ patterns }: ClientConfig, path: string) {
return patterns.some(pattern => minimatch(path, pattern, { matchBase: true }));
}
//
// API interactions
const defaultContentHeaders = {
Accept: 'application/vnd.git-lfs+json',
['Content-Type']: 'application/vnd.git-lfs+json',
};
async function resourceExists(
{ rootURL, makeAuthorizedRequest }: ClientConfig,
{ sha, size }: PointerFile,
) {
const response = await makeAuthorizedRequest({
url: `${rootURL}/verify`,
method: 'POST',
headers: defaultContentHeaders,
body: JSON.stringify({ oid: sha, size }),
});
if (response.ok) {
return true;
}
if (response.status === 404) {
return false;
}
// TODO: what kind of error to throw here? APIError doesn't seem
// to fit
}
function getTransofrmationsParams(t: boolean | ImageTransformations) {
if (isPlainObject(t) && !isEmpty(t)) {
const { nf_resize: resize, w, h } = t as ImageTransformations;
return `?nf_resize=${resize}&w=${w}&h=${h}`;
}
return '';
}
async function getDownloadURL(
{ rootURL, transformImages: t, makeAuthorizedRequest }: ClientConfig,
{ sha }: PointerFile,
) {
try {
const transformation = getTransofrmationsParams(t);
const transformedPromise = makeAuthorizedRequest(`${rootURL}/origin/${sha}${transformation}`);
const [transformed, original] = await Promise.all([
transformedPromise,
// if transformation is defined, we need to load the original so we have the correct meta data
transformation ? makeAuthorizedRequest(`${rootURL}/origin/${sha}`) : transformedPromise,
]);
if (!transformed.ok) {
const error = await transformed.json();
throw new Error(
`Failed getting large media for sha '${sha}': '${error.code} - ${error.msg}'`,
);
}
const transformedBlob = await transformed.blob();
const url = URL.createObjectURL(transformedBlob);
return { url, blob: transformation ? await original.blob() : transformedBlob };
} catch (error) {
console.error(error);
return { url: '', blob: new Blob() };
}
}
function uploadOperation(objects: PointerFile[]) {
return {
operation: 'upload',
transfers: ['basic'],
objects: objects.map(({ sha, ...rest }) => ({ ...rest, oid: sha })),
};
}
async function getResourceUploadURLs(
{
rootURL,
makeAuthorizedRequest,
}: { rootURL: string; makeAuthorizedRequest: MakeAuthorizedRequest },
pointerFiles: PointerFile[],
) {
const response = await makeAuthorizedRequest({
url: `${rootURL}/objects/batch`,
method: 'POST',
headers: defaultContentHeaders,
body: JSON.stringify(uploadOperation(pointerFiles)),
});
const { objects } = await response.json();
const uploadUrls = objects.map(
(object: { error?: { message: string }; actions: { upload: { href: string } } }) => {
if (object.error) {
throw new Error(object.error.message);
}
return object.actions.upload.href;
},
);
return uploadUrls;
}
function uploadBlob(uploadURL: string, blob: Blob) {
return unsentRequest.fetchWithTimeout(uploadURL, {
method: 'PUT',
body: blob,
});
}
async function uploadResource(
clientConfig: ClientConfig,
{ sha, size }: PointerFile,
resource: Blob,
) {
const existingFile = await resourceExists(clientConfig, { sha, size });
if (existingFile) {
return sha;
}
const [uploadURL] = await getResourceUploadURLs(clientConfig, [{ sha, size }]);
await uploadBlob(uploadURL, resource);
return sha;
}
//
// Create Large Media client
function configureFn(config: ClientConfig, fn: Function) {
return (...args: unknown[]) => fn(config, ...args);
}
const clientFns: Record<string, Function> = {
resourceExists,
getResourceUploadURLs,
getDownloadURL,
uploadResource,
matchPath,
};
export type Client = {
resourceExists: (pointer: PointerFile) => Promise<boolean | undefined>;
getResourceUploadURLs: (objects: PointerFile[]) => Promise<string>;
getDownloadURL: (pointer: PointerFile) => Promise<{ url: string; blob: Blob }>;
uploadResource: (pointer: PointerFile, blob: Blob) => Promise<string>;
matchPath: (path: string) => boolean;
patterns: string[];
enabled: boolean;
};
export function getClient(clientConfig: ClientConfig) {
return flow([
Object.keys,
map((key: string) => [key, configureFn(clientConfig, clientFns[key])]),
fromPairs,
configuredFns => ({
...configuredFns,
patterns: clientConfig.patterns,
enabled: clientConfig.enabled,
}),
])(clientFns);
}

View File

@@ -0,0 +1,4 @@
declare module 'ini' {
const ini: { decode: <T>(ini: string) => T };
export default ini;
}

View File

@@ -0,0 +1,3 @@
const { getConfig } = require('../../scripts/webpack.js');
module.exports = getConfig();