Compare commits

...

114 Commits

Author SHA1 Message Date
Nato Boram b3228f8805
🎨 Prettier 2022-07-25 16:42:08 -04:00
Nato Boram c8d0437e4b
⬆️ ng update 2022-05-25 13:59:15 -04:00
Nato Boram 66b3a74d72
👽️ Update gateways 2022-05-13 11:26:59 -04:00
Nato Boram 14a72ac7af
⬇️ `pnpm i` 2022-05-13 10:40:59 -04:00
Nato Boram 273b416216
🚨 Prettier 2022-05-13 10:32:26 -04:00
Nato Boram e0a31d84a6
⬆️ `pnpm upgrade` 2022-05-13 10:31:49 -04:00
Nato Boram 3a012ae76b
⬆️ pnpm i 2022-05-13 10:25:42 -04:00
Nato Boram 9a5264be85
Merge tag 'v2.2.1' into develop
Update my gateway
2022-03-11 02:58:26 -05:00
Nato Boram 11ec464c07
Merge branch 'release/2.2.1' 2022-03-11 02:58:18 -05:00
Nato Boram 4b9981691e
🔖 2.2.1 2022-03-11 02:58:09 -05:00
Nato Boram c45120f0bf
Merge tag 'v2.2.0' into develop
Upgrade to Angular 13
2022-03-11 02:39:07 -05:00
Nato Boram 4518c8d951
Merge branch 'release/2.2.0' 2022-03-11 02:38:43 -05:00
Nato Boram 0880de93c4
🔖 v2.2.0 2022-03-11 02:38:26 -05:00
Nato Boram 2e06007622
Put good responses first 2022-03-11 02:26:13 -05:00
Nato Boram 4115e3ee4b Merge branch 'feature/more-eslint' into 'develop'
 More ESLint & Prettier

See merge request NatoBoram/public-gateway-cacher!9
2022-03-11 07:17:23 +00:00
Nato Boram 5f8728f78f
Prettier 2022-03-11 02:06:35 -05:00
Nato Boram d8fc7d06a3
🔧 Add recommended ESLint rules 2022-03-11 00:55:23 -05:00
Nato Boram 7980719b9a
🔧 Import Eldarya Enhancement's ESLint 2022-03-11 00:30:44 -05:00
Nato Boram 4497bf7ce7
⬆️ ESNext 2022-03-10 22:51:02 -05:00
Nato Boram 71b337ce7d Merge branch 'feature/pnpm' into 'develop'
🔧 Migrate to pnpm

See merge request NatoBoram/public-gateway-cacher!8
2022-03-11 03:40:16 +00:00
Nato Boram a322b74e3a
⬆️ ng update rxjs 2022-03-10 22:34:56 -05:00
Nato Boram 8e87a1691b
⬆️ ng update 2022-03-10 22:21:41 -05:00
Nato Boram d35ebcf80f
🔧 Migrate to pnpm 2022-03-10 22:20:29 -05:00
Nato Boram 7bd0c946b8 Merge branch 'feature/angular-13' into 'develop'
⬆️ Upgrade to Angular 13

See merge request NatoBoram/public-gateway-cacher!7
2022-03-11 02:54:39 +00:00
Nato Boram 1a7beaec5c
📝 Update changelog 2022-03-10 21:47:14 -05:00
Nato Boram 9c3d5d82ed
🔧 Add ESLint rules 2022-03-10 21:44:37 -05:00
Nato Boram 6f12da98eb
🐛 Add stylePreprocessorOptions 2022-03-10 17:31:47 -05:00
Nato Boram 4b30fc615c
Migrated to ESLint 2022-03-10 16:57:15 -05:00
Nato Boram 295aef9ac1
⬆️ Upgrade to Angular 13
ng update @angular/animations @angular/cdk @angular/common @angular/compiler @angular/core @angular/flex-layout@13.0.0-beta.38 @angular/forms @angular/material @angular/platform-browser @angular/platform-browser-dynamic @angular/router @angular-devkit/build-angular @angular/cli @angular/compiler-cli @angular/language-service
2022-03-10 16:49:14 -05:00
Nato Boram edb998ef7c Merge branch 'feature/upgrade-gateways' into 'develop'
⬆️ Update `gateways.json`

See merge request NatoBoram/public-gateway-cacher!6
2022-03-10 21:32:35 +00:00
Nato Boram e03411ec7f ⬆️ Update `gateways.json` 2022-03-10 21:28:22 +00:00
Nato Boram a704e32a87 Merge branch 'feature/more-package-json' into 'develop'
📝 Add more info in `package.json`

See merge request NatoBoram/public-gateway-cacher!5
2022-03-10 21:27:57 +00:00
Nato Boram 7a41cfb111
📝 Add more info in `package.json` 2022-03-10 16:08:06 -05:00
Nato Boram 36967355d0 Merge branch 'feature/upgrade-tslint' into 'develop'
⬆️ Update some dependencies

See merge request NatoBoram/public-gateway-cacher!4
2022-03-10 20:52:42 +00:00
Nato Boram 8d8f156bb1
📝 Update changelog 2022-03-10 15:45:38 -05:00
Nato Boram 026a663e2b
⬆️ Update Bootstrap, IPFS-CSS, Codelyzer, TOOIR 2022-03-10 15:42:51 -05:00
Nato Boram e87635eeff Merge branch 'feature/angular-12' into 'develop'
⬆️ Upgrade to Angular 12

See merge request NatoBoram/public-gateway-cacher!3
2022-03-10 05:12:32 +00:00
Nato Boram 98548be2a1
💚 image: node:latest 2022-03-10 00:05:10 -05:00
Nato Boram 37060f2a5f
🐛 Fix migration to Angular 12 2022-03-09 23:57:47 -05:00
Nato Boram 28f89c6b09
⬆️ Update to Angular 12
ng update @angular/animations@12 @angular/cdk@12 @angular/common@12 @angular/compiler@12 @angular/core@12 @angular/flex-layout@12.0.0-beta.35 @angular/forms@12 @angular/material@12 @angular/platform-browser@12 @angular/platform-browser-dynamic@12 @angular/router@12 @angular-devkit/build-angular@12 @angular/cli@12 @angular/compiler-cli@12 @angular/language-service@12
2022-03-09 23:13:50 -05:00
Nato Boram 91c9fdca31 Merge tag 'v2.1.1' into develop
Updated gateways and Angular 11
2021-03-20 14:40:28 -04:00
Nato Boram ca758ddd28 Merge branch 'release/2.1.1' 2021-03-20 14:39:44 -04:00
Nato Boram 6361a6381e
Change version to 2.1.1 2021-03-20 14:39:19 -04:00
Nato Boram ae97658bc0
Added some VSCode settings 2021-03-20 14:26:45 -04:00
Nato Boram e24b381d14
Added some accessibility tags 2021-03-20 13:56:29 -04:00
Nato Boram 799e694e68
Add gateway update to changelog 2021-03-20 13:47:48 -04:00
Nato Boram eff14ef287
Update gateways 2021-03-20 13:47:23 -04:00
Nato Boram 6ad85653fd
Add Angular update to changelog 2021-03-20 13:39:16 -04:00
Nato Boram 743f0f5897 Merge branch 'feature/update-angular' into develop 2021-03-19 19:01:03 -04:00
Nato Boram 40ee026a8b
⬆️ ng update
@angular/cdk @angular/cli @angular/core @angular/material @angular/compiler-cli @angular/common @angular/platform-browser @angular-devkit/build-angular @angular/flex-layout
2021-03-19 18:52:53 -04:00
Nato Boram c10977bc1d
Run `yarn` 2021-03-19 18:28:01 -04:00
Nato Boram fb6cba9737
Use workspace TypeScript version 2021-03-19 18:26:02 -04:00
Nato Boram 57ec58ed26
Update recommended extensions 2021-03-19 17:54:50 -04:00
Nato Boram 1f8bf96652
fix title 2020-07-10 02:39:37 -04:00
Nato Boram 1017fe7182 Merge tag 'v2.1.0' into develop
IPFS Theme!
2020-07-10 02:13:11 -04:00
Nato Boram e1343af330 Merge branch 'release/2.1.0' 2020-07-10 02:12:33 -04:00
Nato Boram feee784396
name version 2.1.0 2020-07-10 02:12:17 -04:00
Nato Boram 43b9665252
max_line_length 2020-07-10 02:09:10 -04:00
Nato Boram 46146edf7f
Recommend ms-vscode.vscode-typescript-next 2020-07-10 01:52:36 -04:00
Nato Boram a76a635296
Upgrade ts-node 2020-07-10 01:48:31 -04:00
Nato Boram cea6b51fe3
old base logic 2020-07-10 01:39:09 -04:00
Nato Boram bc40b43479
disable no-implicit-dependencie 2020-07-10 01:24:52 -04:00
Nato Boram 154c28682f
ng lint --fix 2020-07-10 01:00:35 -04:00
Nato Boram 9c79603247
ng update rxjs 2020-07-10 01:00:13 -04:00
Nato Boram 9f49e7ee8c
update with new project data 2020-07-10 00:53:52 -04:00
Nato Boram 723474d5f7
inputColour: ThemePalette 2020-07-10 00:16:58 -04:00
Nato Boram 17b1abe348
Update README.md 2020-07-09 23:14:33 -04:00
Nato Boram 68a2ae9408
Update dependencies 2020-07-09 22:29:51 -04:00
Nato Boram 3cf4f3e4b9
ng update @angular/core 2020-07-09 22:16:46 -04:00
Nato Boram b277fe823a
Change 🤦‍♂️ for 2020-07-09 22:14:46 -04:00
Nato Boram 45dce3a323
node 14 for gitlab-ci 2020-07-08 20:34:43 -04:00
Nato Boram dbeb7b3e22
Add IPFS theme 2020-07-08 20:33:19 -04:00
Nato Boram f55110d6df
Fix mat-column-icon 2020-07-08 16:56:49 -04:00
Nato Boram 3f3314a62a
Add more icons 2020-07-08 16:47:13 -04:00
Nato Boram f688412e73
Strict mode in changelog 2020-07-08 03:46:46 -04:00
Nato Boram fe7308e6b7
Strict mode 2020-07-08 03:42:42 -04:00
Nato Boram 2799e4135b
Added support for subdomain gateways 2020-07-08 02:23:02 -04:00
Nato Boram 6e5438d8a4
Add class="mat-app-background" to body 2020-07-08 01:28:14 -04:00
Nato Boram 4144816f7c
Updated `bootstrap` and `ipfs-css` 2020-07-07 21:11:46 -04:00
Nato Boram 388caa7bdc
--chunker=buzhash 2020-07-07 20:43:12 -04:00
Nato Boram 0e57dc4151 Merge branch 'feature/ng-update' into develop 2020-07-07 20:31:50 -04:00
Nato Boram 03f3975132
ng lint 2020-07-07 20:20:02 -04:00
Nato Boram c050381c49
ng update
ng update @angular/cdk @angular/cli @angular/core @angular/material rxjs @angular/flex-layout
2020-07-07 20:12:55 -04:00
Nato Boram 5c553d78c5
Screenshot in changelog 2019-12-03 01:51:49 -05:00
Nato Boram 3e0796f909
Add a screeshot 2019-12-03 01:50:04 -05:00
Nato Boram 53cad748e2 Merge tag 'v2.0.0' into develop
Migrate to Angular
2019-12-03 01:40:51 -05:00
Nato Boram 03cdf26234 Merge branch 'release/2.0.0' 2019-12-03 01:40:36 -05:00
Nato Boram 86ef05154b
Prepare release v2.0.0 2019-12-03 01:40:09 -05:00
Nato Boram 17075a0922 Merge branch 'feature/angular' into develop 2019-12-03 01:13:23 -05:00
Nato Boram 6211940fb3
typo 2019-12-03 01:12:33 -05:00
Nato Boram 8936301b15 Merge branch 'pages' into 'feature/angular'
Create a successful deployment

Once the deployment successfully shows up at https://natoboram.gitlab.io/public-gateway-cacher, I'll be ready to merge this pull request and move forward with the IPFS integration.

Closes #1.

See merge request NatoBoram/public-gateway-cacher!1
2019-12-03 06:02:58 +00:00
Nato Boram cb8425bd39 Create a successful deployment 2019-12-03 06:02:57 +00:00
Nato Boram 820ad61a8d
restore proper yarn.lock 2019-12-02 22:25:49 -05:00
Nato Boram e881c0df23
registry.js.ipfs.io 2019-12-02 22:16:20 -05:00
Nato Boram 0c1265ad09
cancel subscriptions 2019-12-02 20:31:23 -05:00
Nato Boram 819cdbfe60
small alignment 2019-11-29 04:07:17 -05:00
Nato Boram 4c45431ca0
support ipns 2019-11-29 04:00:44 -05:00
Nato Boram ad79caac54
add about 2019-11-29 03:36:08 -05:00
Nato Boram dd384d6d9d
useHash 2019-11-29 03:28:00 -05:00
Nato Boram ee146753d2
drop npm-ipfs 2019-11-29 03:14:21 -05:00
Nato Boram a1c7c1e09b
yarn global add ipfs-npm 2019-11-29 03:06:02 -05:00
Nato Boram c3c2cb36ff
test pipeline with ipfs-yarn 2019-11-29 03:01:48 -05:00
Nato Boram e6f8c9ccf1
remove sort 2019-11-29 02:50:12 -05:00
Nato Boram 311a3b0698
mostly functional 2019-11-29 02:26:41 -05:00
Nato Boram 26cf1d120f
add material 2019-11-28 22:44:39 -05:00
Nato Boram 39e582e4c4
ng update rxjs 2019-11-28 22:37:30 -05:00
Nato Boram 38ef223dd8
re-add lockfile 2019-11-28 22:35:33 -05:00
Nato Boram 462816e27a
created pages 2019-11-28 22:35:03 -05:00
Nato Boram 4844ab14d1
pages 2019-11-28 22:16:33 -05:00
Nato Boram 4ac6b557fa
remove yarn-ipfs 2019-11-28 22:10:55 -05:00
Nato Boram 141fed8a6e
proper yarn lock 2019-11-28 22:09:32 -05:00
Nato Boram 3253d7e017
output angular in dist/angular 2019-11-28 22:07:50 -05:00
Nato Boram ec71ce24bc
removed devDependencies on ipfs-npm because rabin is shit 2019-11-28 21:57:38 -05:00
Nato Boram 3899bf01c7
first angular commit 2019-11-28 21:20:50 -05:00
71 changed files with 11138 additions and 388 deletions

18
.browserslistrc Normal file
View File

@ -0,0 +1,18 @@
# This file is used by the build system to adjust CSS and JS output to support the specified browsers below.
# For additional information regarding the format and rule options, please see:
# https://github.com/browserslist/browserslist#queries
# For the full list of supported browsers by the Angular framework, please see:
# https://angular.io/guide/browser-support
# You can see what browsers were selected by your queries by running:
# npx browserslist
last 1 Chrome version
last 1 Firefox version
last 2 Edge major versions
last 2 Safari major versions
last 2 iOS major versions
Firefox ESR
not IE 9-10 # Angular support for IE 9-10 has been deprecated and will be removed as of Angular v11. To opt-in, remove the 'not' prefix on this line.
not IE 11 # Angular supports IE 11 only as an opt-in. To opt-in, remove the 'not' prefix on this line.

13
.editorconfig Normal file
View File

@ -0,0 +1,13 @@
root = true
[*]
charset = utf-8
indent_size = 2
indent_style = space
insert_final_newline = true
max_line_length = 140
trim_trailing_whitespace = true
[*.md]
max_line_length = false
trim_trailing_whitespace = false

8
.eslintignore Normal file
View File

@ -0,0 +1,8 @@
.angular
.pnpm-store
dist
e2e/protractor.conf.js
node_modules
pnpm-lock.yaml
public
src/test.ts

134
.eslintrc.json Normal file
View File

@ -0,0 +1,134 @@
{
"root": true,
"env": {
"browser": true
},
"ignorePatterns": ["projects/**/*"],
"overrides": [
{
"files": ["*.ts"],
"parserOptions": {
"project": ["tsconfig.json", "e2e/tsconfig.json"],
"createDefaultProgram": true
},
"plugins": ["rxjs-angular"],
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
"plugin:@typescript-eslint/recommended-requiring-type-checking",
"prettier",
"plugin:rxjs/recommended",
"plugin:@angular-eslint/all",
"plugin:@angular-eslint/recommended--extra",
"plugin:@angular-eslint/template/process-inline-templates"
],
"rules": {
"@angular-eslint/directive-selector": [
"error",
{
"type": "attribute",
"prefix": "app",
"style": "camelCase"
}
],
"@angular-eslint/component-selector": [
"error",
{
"type": "element",
"prefix": "app",
"style": "kebab-case"
}
],
// Custom rules
// @typescript-eslint
"@typescript-eslint/array-type": "error",
"@typescript-eslint/class-literal-property-style": "error",
"@typescript-eslint/consistent-indexed-object-style": "error",
"@typescript-eslint/consistent-type-assertions": [
"error",
{
"assertionStyle": "as",
"objectLiteralTypeAssertions": "never"
}
],
"@typescript-eslint/consistent-type-definitions": "error",
"@typescript-eslint/consistent-type-imports": "error",
"@typescript-eslint/dot-notation": "error",
"@typescript-eslint/explicit-function-return-type": "error",
"@typescript-eslint/explicit-member-accessibility": [
"error",
{
"accessibility": "no-public"
}
],
"@typescript-eslint/member-delimiter-style": [
"error",
{
"multiline": {
"delimiter": "none",
"requireLast": true
}
}
],
"@typescript-eslint/method-signature-style": "error",
"@typescript-eslint/no-base-to-string": "error",
"@typescript-eslint/no-confusing-non-null-assertion": "error",
"@typescript-eslint/no-confusing-void-expression": [
"error",
{
"ignoreArrowShorthand": true,
"ignoreVoidOperator": true
}
],
"@typescript-eslint/no-dynamic-delete": "error",
"@typescript-eslint/no-empty-function": [
"error",
{
"allow": ["private-constructors", "protected-constructors"]
}
],
"@typescript-eslint/no-extra-parens": ["error", "functions"],
"@typescript-eslint/no-implicit-any-catch": "error",
"@typescript-eslint/no-invalid-void-type": "error",
"@typescript-eslint/no-non-null-assertion": "error",
"@typescript-eslint/no-unnecessary-boolean-literal-compare": "error",
"@typescript-eslint/no-unnecessary-condition": "error",
"@typescript-eslint/no-unnecessary-qualifier": "error",
"@typescript-eslint/no-unnecessary-type-arguments": "error",
"@typescript-eslint/no-unnecessary-type-constraint": "error",
"@typescript-eslint/no-unsafe-argument": "error",
"@typescript-eslint/no-unsafe-assignment": "error",
"@typescript-eslint/no-var-requires": "error",
"@typescript-eslint/non-nullable-type-assertion-style": "error",
"@typescript-eslint/prefer-for-of": "error",
"@typescript-eslint/prefer-function-type": "error",
"@typescript-eslint/prefer-includes": "error",
"@typescript-eslint/prefer-nullish-coalescing": "error",
"@typescript-eslint/prefer-optional-chain": "error",
"@typescript-eslint/prefer-readonly": "error",
"@typescript-eslint/prefer-reduce-type-parameter": "error",
"@typescript-eslint/prefer-return-this-type": "error",
"@typescript-eslint/prefer-string-starts-ends-with": "error",
"@typescript-eslint/prefer-ts-expect-error": "error",
"@typescript-eslint/promise-function-async": "error",
"@typescript-eslint/require-array-sort-compare": "error",
"@typescript-eslint/semi": ["error", "never"],
"@typescript-eslint/sort-type-union-intersection-members": "error",
"@typescript-eslint/switch-exhaustiveness-check": "error",
"@typescript-eslint/type-annotation-spacing": "error",
"@typescript-eslint/unified-signatures": "error",
// eslint-plugin-rxjs-angular
//"rxjs-angular/prefer-async-pipe": "error",
"rxjs-angular/prefer-takeuntil": "error"
}
},
{
"files": ["*.html"],
"extends": ["plugin:@angular-eslint/template/all"],
"rules": {
// Custom rules
"@angular-eslint/template/i18n": "off"
}
}
]
}

12
.github/FUNDING.yml vendored Normal file
View File

@ -0,0 +1,12 @@
# These are supported funding model platforms
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
patreon: NatoBoram # Replace with a single Patreon username
open_collective: # Replace with a single Open Collective username
ko_fi: # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
otechie: # Replace with a single Otechie username
custom: ["https://paypal.me/NatoBoram/5"] # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']

134
.gitignore vendored
View File

@ -1,6 +1,37 @@
# Created by https://www.toptal.com/developers/gitignore/api/angular,linux,windows,macos,visualstudiocode
# Edit at https://www.toptal.com/developers/gitignore?templates=angular,linux,windows,macos,visualstudiocode
# Created by https://www.gitignore.io/api/node,linux,macos,windows,visualstudiocode
# Edit at https://www.gitignore.io/?templates=node,linux,macos,windows,visualstudiocode
### Angular ###
## Angular ##
# compiled output
dist/
tmp/
app/**/*.js
app/**/*.js.map
# dependencies
node_modules/
bower_components/
# IDEs and editors
.idea/
# misc
.sass-cache/
connect.lock/
coverage/
libpeerconnection.log/
npm-debug.log
testem.log
typings/
.angular/
# e2e
e2e/*.js
e2e/*.map
# System Files
.DS_Store/
### Linux ###
*~
@ -45,106 +76,31 @@ Network Trash Folder
Temporary Items
.apdisk
### Node ###
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*
# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
# nyc test coverage
.nyc_output
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# TypeScript v1 declaration files
typings/
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variables file
.env
.env.test
# parcel-bundler cache (https://parceljs.org/)
.cache
# next.js build output
.next
# nuxt.js build output
.nuxt
# vuepress build output
.vuepress/dist
# Serverless directories
.serverless/
# FuseBox cache
.fusebox/
# DynamoDB Local files
.dynamodb/
### VisualStudioCode ###
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
!.vscode/*.code-snippets
# Local History for Visual Studio Code
.history/
# Built Visual Studio Code Extensions
*.vsix
### VisualStudioCode Patch ###
# Ignore all local history of files
.history
.ionide
# Support for Project snippet scope
### Windows ###
# Windows thumbnail cache files
Thumbs.db
Thumbs.db:encryptable
ehthumbs.db
ehthumbs_vista.db
@ -167,4 +123,4 @@ $RECYCLE.BIN/
# Windows shortcuts
*.lnk
# End of https://www.gitignore.io/api/node,linux,macos,windows,visualstudiocode
# End of https://www.toptal.com/developers/gitignore/api/angular,linux,windows,macos,visualstudiocode

44
.gitlab-ci.yml Normal file
View File

@ -0,0 +1,44 @@
image: node:latest
before_script:
- curl -f https://get.pnpm.io/v6.16.js | node - add --global pnpm@6
- pnpm config set store-dir .pnpm-store
- pnpm i
variables:
# https://stackoverflow.com/a/69746937/5083247
NODE_OPTIONS: --openssl-legacy-provider
cache:
key:
files:
- pnpm-lock.yaml
paths:
- .pnpm-store
build:
stage: build
script:
- pnpm run build:prod
artifacts:
paths:
- dist/angular
test:
stage: test
script:
- pnpx ng lint
- pnpx prettier --check .
pages:
stage: deploy
script:
- pnpm run build:gitlab
- mv dist/angular public
- cp public/index.html public/404.html
artifacts:
paths:
- public
only:
- master
- pages

3
.ipfs-npmrc Normal file
View File

@ -0,0 +1,3 @@
{
"packageManager": "pnpm"
}

View File

@ -1,3 +0,0 @@
{
"esversion": 6
}

4
.markdownlint.json Normal file
View File

@ -0,0 +1,4 @@
{
"line_length": false,
"no-duplicate-heading": false
}

6
.prettierignore Normal file
View File

@ -0,0 +1,6 @@
.angular
.pnpm-store
dist
node_modules
pnpm-lock.yaml
public

3
.prettierrc.yaml Normal file
View File

@ -0,0 +1,3 @@
arrowParens: avoid
printWidth: 140
semi: false

View File

@ -1,13 +1,23 @@
{
// See http://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations.
// Extension identifier format: ${publisher}.${name}. Example: vscode.csharp
// List of extensions which should be recommended for users of this workspace.
"recommendations": [
"dbaeumer.jshint"
],
// List of extensions recommended by VS Code that should not be recommended for users of this workspace.
"unwantedRecommendations": [
"dbaeumer.vscode-eslint",
"eg2.tslint"
]
}
// See https://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations.
// Extension identifier format: ${publisher}.${name}. Example: vscode.csharp
// List of extensions which should be recommended for users of this workspace.
"recommendations": [
"angular.ng-template",
"davidanson.vscode-markdownlint",
"dbaeumer.vscode-eslint",
"editorconfig.editorconfig",
"esbenp.prettier-vscode",
"gitlab.gitlab-workflow",
"johnpapa.angular2",
"ms-vscode.vscode-typescript-next",
"visualstudioexptteam.vscodeintellicode"
],
// List of extensions recommended by VS Code that should not be recommended for users of this workspace.
"unwantedRecommendations": [
"eg2.tslint",
"ms-azuretools.vscode-docker",
"ms-edgedevtools.vscode-edge-devtools",
"ms-vscode-remote.remote-wsl"
]
}

43
.vscode/launch.json vendored Normal file
View File

@ -0,0 +1,43 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "ng serve",
"type": "chrome",
"request": "launch",
"preLaunchTask": "npm: start",
"url": "http://localhost:4200/#",
"webRoot": "${workspaceFolder}",
"sourceMapPathOverrides": {
"webpack:/*": "${webRoot}/*",
"/./*": "${webRoot}/*",
"/src/*": "${webRoot}/*",
"/*": "*",
"/./~/*": "${webRoot}/node_modules/*"
}
},
{
"name": "ng test",
"type": "chrome",
"request": "launch",
"url": "http://localhost:9876/debug.html",
"webRoot": "${workspaceFolder}",
"sourceMaps": true,
"sourceMapPathOverrides": {
"webpack:/*": "${webRoot}/*",
"/./*": "${webRoot}/*",
"/src/*": "${webRoot}/*",
"/*": "*",
"/./~/*": "${webRoot}/node_modules/*"
}
},
{
"name": "ng e2e",
"type": "node",
"request": "launch",
"program": "${workspaceFolder}/node_modules/protractor/bin/protractor",
"protocol": "inspector",
"args": ["${workspaceFolder}/e2e/protractor.conf.js"]
}
]
}

38
.vscode/settings.json vendored
View File

@ -1,10 +1,30 @@
{
"editor.detectIndentation": false,
"editor.formatOnSave": true,
"editor.insertSpaces": false,
"editor.wordWrap": "on",
"html.format.indentHandlebars": true,
"html.format.maxPreserveNewLines": 1,
"html.format.wrapLineLength": 0,
"jshint.lintHTML": true,
}
"[css][scss][html][javascript][typescript][json][jsonc][markdown][yaml]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"editor.codeActionsOnSave": {
"source.fixAll": true,
"source.fixAll.eslint": true,
"source.organizeImports": true
},
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.formatOnSave": true,
"editor.rulers": [140],
"eslint.options": {
"extensions": [".ts", ".html"]
},
"eslint.packageManager": "pnpm",
"eslint.validate": ["javascript", "javascriptreact", "typescript", "typescriptreact", "html"],
"files.associations": {
".ipfs-npmrc": "json"
},
"html.format.indentHandlebars": true,
"html.format.maxPreserveNewLines": 1,
"html.format.wrapAttributes": "auto",
"html.format.wrapLineLength": 140,
"npm.packageManager": "pnpm",
"tslint.packageManager": "pnpm",
"typescript.preferences.importModuleSpecifier": "relative",
"typescript.tsdk": "node_modules\\typescript\\lib",
"typescript.updateImportsOnFileMove.enabled": "always"
}

34
.vscode/tasks.json vendored Normal file
View File

@ -0,0 +1,34 @@
{
"version": "2.0.0",
"tasks": [
{
"type": "npm",
"script": "start",
"isBackground": true,
"presentation": {
"focus": true,
"panel": "dedicated"
},
"group": {
"kind": "build",
"isDefault": true
},
"problemMatcher": {
"owner": "typescript",
"source": "ts",
"applyTo": "closedDocuments",
"fileLocation": ["relative", "${cwd}"],
"pattern": "$tsc",
"background": {
"activeOnStart": true,
"beginsPattern": {
"regexp": "(.*?)"
},
"endsPattern": {
"regexp": "Compiled |Failed to compile."
}
}
}
}
]
}

99
CHANGELOG.md Normal file
View File

@ -0,0 +1,99 @@
# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/), and this project adheres to [Semantic Versioning](https://semver.org/).
## [Unreleased]
### Added
### Changed
### Deprecated
### Removed
### Fixed
### Security
## [2.2.1]
### Changed
- Updated my own gateway to its HTTPS link
## [2.2.0] - 2022-03-11
### Added
- More information in the `package.json`.
- Added ESLint
- Added Prettier
- Put success reponses at the top of the list
### Changed
- Updated `gateways.json`
- Upgraded to Angular 13
- Targets ESNext
### Removed
- Removed TSLint
## [2.1.1] - 2021-03-20
### Added
- Added some accessibility tags
- Added some VSCode settings
### Changed
- Updated to Angular 11
- Updated gateways
### Fixed
- Corrected the title from "Public IPFS Cacher" to "Public Gateway Cacher".
## [2.1.0] - 2020-07-10
### Added
- Support for subdomain gateways
- Strict mode
- More icons
- IPFS colours
### Changed
- Better screenshot
- Upgraded to Angular 10
- Now uses `--chunker=buzhash`
- Updated `bootstrap` and `ipfs-css`
## [2.0.0] - 2019-12-03
Now based on Angular!
Tests were done with `ipfs-npm` : They weren't successful. `ipfs-css` is only minimally used.
### Added
- GitLab Pages - <https://natoboram.gitlab.io/public-gateway-cacher/>
## [1.0.0] - 2019-11-28
This version is a fork of [github.com/ipfs/public-gateway-checker](https://github.com/ipfs/public-gateway-checker).
## Types of changes
- `Added` for new features.
- `Changed` for changes in existing functionality.
- `Deprecated` for soon-to-be removed features.
- `Removed` for now removed features.
- `Fixed` for any bug fixes.
- `Security` in case of vulnerabilities.

View File

@ -217,23 +217,23 @@ produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these
conditions:
- a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
- b) The work must carry prominent notices stating that it is
released under this License and any conditions added under
section 7. This requirement modifies the requirement in section 4
to "keep intact all notices".
- c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
- d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
- a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
- b) The work must carry prominent notices stating that it is
released under this License and any conditions added under
section 7. This requirement modifies the requirement in section 4
to "keep intact all notices".
- c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
- d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
@ -252,42 +252,42 @@ sections 4 and 5, provided that you also convey the machine-readable
Corresponding Source under the terms of this License, in one of these
ways:
- a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
- b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the Corresponding
Source from a network server at no charge.
- c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
- d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
- e) Convey the object code using peer-to-peer transmission,
provided you inform other peers where the object code and
Corresponding Source of the work are being offered to the general
public at no charge under subsection 6d.
- a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
- b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the Corresponding
Source from a network server at no charge.
- c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
- d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
- e) Convey the object code using peer-to-peer transmission,
provided you inform other peers where the object code and
Corresponding Source of the work are being offered to the general
public at no charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
@ -363,23 +363,23 @@ Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders
of that material) supplement the terms of this License with terms:
- a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
- b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
- c) Prohibiting misrepresentation of the origin of that material,
or requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
- d) Limiting the use for publicity purposes of names of licensors
or authors of the material; or
- e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
- f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions
of it) with contractual assumptions of liability to the recipient,
for any liability that these contractual assumptions directly
impose on those licensors and authors.
- a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
- b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
- c) Prohibiting misrepresentation of the origin of that material,
or requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
- d) Limiting the use for publicity purposes of names of licensors
or authors of the material; or
- e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
- f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions
of it) with contractual assumptions of liability to the recipient,
for any liability that these contractual assumptions directly
impose on those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you

View File

@ -1,13 +1,14 @@
# Public Gateway Cacher
[![pipeline status](https://gitlab.com/NatoBoram/public-gateway-cacher/badges/master/pipeline.svg)](https://gitlab.com/NatoBoram/public-gateway-cacher/-/commits/master)
[![StackShare](https://img.shields.io/badge/tech-stack-0690fa.svg?style=flat)](https://stackshare.io/NatoBoram/public-gateway-cacher)
Cache a specific hash on a bunch of public gateways.
**Note :** All of these (except gateway.ipfs.io and ipfs.io) are hosted by third-parties and should be treated as such.
You can view this website on [GitLab Pages](https://natoboram.gitlab.io/public-gateway-cacher) and [IPFS](https://bafybeievsdzxuvuah5t6vzhig525jecp7wmupnm7olxdkonqmte57zoqf4.ipfs.dweb.link).
You can view this website on [IPFS](https://bafybeifqneiiwgcejnisxd6vjic2xrmfieffldiqembuagflb2xaup772a.cf-ipfs.com).
![Screenshot](https://bafybeie7txrbzw6ipb62lplnpzsjpz7s4o5q7uufb5rjfelol2cuxeyzye.ipfs.dweb.link/Screenshot_2020-07-09%20Public%20Gateway%20Cacher.png)
Here's a screenshot :
**NOTE :** All of these (except `ipfs.io` and `dweb.link`) are hosted by third-parties and should be treated as such.
![screenshot](https://ipfs.io/ipfs/QmUeCSd4gHio7MxZuRXCcLFXED9GpfntKcL87gmXvZV3ed)
If you'd like to add a new public gateway, please go to [github.com/ipfs/public-gateway-checker](https://github.com/ipfs/public-gateway-checker), submit a pull request then open an issue here.
If you'd like to add a new public gateway, please go to [github.com/ipfs/public-gateway-checker](https://github.com/ipfs/public-gateway-checker), submit a pull request then open an issue [here](https://gitlab.com/NatoBoram/public-gateway-cacher/issues/new).

176
angular.json Normal file
View File

@ -0,0 +1,176 @@
{
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"version": 1,
"cli": {
"packageManager": "pnpm",
"analytics": "10b848ad-8b81-4346-852f-5eff89573a85",
"defaultCollection": "@angular-eslint/schematics"
},
"newProjectRoot": "projects",
"projects": {
"public-gateway-cacher": {
"projectType": "application",
"schematics": {
"@schematics/angular:component": {
"style": "scss"
},
"@schematics/angular:application": {
"strict": true
}
},
"root": "",
"sourceRoot": "src",
"prefix": "app",
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:browser",
"options": {
"outputPath": "dist/angular",
"index": "src/index.html",
"main": "src/main.ts",
"polyfills": "src/polyfills.ts",
"tsConfig": "tsconfig.app.json",
"assets": ["src/favicon.png", "src/assets"],
"styles": ["src/styles.scss"],
"stylePreprocessorOptions": {
"includePaths": ["node_modules"]
},
"scripts": [],
"vendorChunk": true,
"extractLicenses": false,
"buildOptimizer": false,
"sourceMap": true,
"optimization": false,
"namedChunks": true
},
"configurations": {
"production": {
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.prod.ts"
}
],
"optimization": true,
"outputHashing": "all",
"extractLicenses": true,
"buildOptimizer": true,
"budgets": [
{
"type": "initial",
"maximumWarning": "2mb",
"maximumError": "5mb"
},
{
"type": "anyComponentStyle",
"maximumWarning": "6kb",
"maximumError": "10kb"
}
]
},
"gitlab": {
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.gitlab.ts"
}
],
"optimization": true,
"outputHashing": "all",
"extractLicenses": true,
"buildOptimizer": true,
"budgets": [
{
"type": "initial",
"maximumWarning": "2mb",
"maximumError": "5mb"
},
{
"type": "anyComponentStyle",
"maximumWarning": "6kb",
"maximumError": "10kb"
}
]
},
"ipfs": {
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.ipfs.ts"
}
],
"optimization": true,
"outputHashing": "all",
"extractLicenses": true,
"buildOptimizer": true,
"budgets": [
{
"type": "initial",
"maximumWarning": "2mb",
"maximumError": "5mb"
},
{
"type": "anyComponentStyle",
"maximumWarning": "6kb",
"maximumError": "10kb"
}
]
}
},
"defaultConfiguration": ""
},
"serve": {
"builder": "@angular-devkit/build-angular:dev-server",
"options": {
"browserTarget": "public-gateway-cacher:build"
},
"configurations": {
"production": {
"browserTarget": "public-gateway-cacher:build:production"
}
}
},
"extract-i18n": {
"builder": "@angular-devkit/build-angular:extract-i18n",
"options": {
"browserTarget": "public-gateway-cacher:build"
}
},
"test": {
"builder": "@angular-devkit/build-angular:karma",
"options": {
"main": "src/test.ts",
"polyfills": "src/polyfills.ts",
"tsConfig": "tsconfig.spec.json",
"karmaConfig": "karma.conf.js",
"assets": ["src/favicon.png", "src/assets"],
"styles": ["src/styles.scss"],
"stylePreprocessorOptions": {
"includePaths": ["node_modules"]
},
"scripts": []
}
},
"e2e": {
"builder": "@angular-devkit/build-angular:protractor",
"options": {
"protractorConfig": "e2e/protractor.conf.js",
"devServerTarget": "public-gateway-cacher:serve"
},
"configurations": {
"production": {
"devServerTarget": "public-gateway-cacher:serve:production"
}
}
},
"lint": {
"builder": "@angular-eslint/builder:lint",
"options": {
"lintFilePatterns": ["src/**/*.ts", "src/**/*.html"]
}
}
}
}
},
"defaultProject": "public-gateway-cacher"
}

36
e2e/protractor.conf.js Normal file
View File

@ -0,0 +1,36 @@
// @ts-check
// Protractor configuration file, see link for more information
// https://github.com/angular/protractor/blob/master/lib/config.ts
const { SpecReporter, StacktraceOption } = require("jasmine-spec-reporter")
/**
* @type { import("protractor").Config }
*/
exports.config = {
allScriptsTimeout: 11000,
specs: ["./src/**/*.e2e-spec.ts"],
capabilities: {
browserName: "chrome",
},
directConnect: true,
baseUrl: "http://localhost:4200/",
framework: "jasmine",
jasmineNodeOpts: {
showColors: true,
defaultTimeoutInterval: 30000,
print: function () {},
},
onPrepare() {
require("ts-node").register({
project: require("path").join(__dirname, "./tsconfig.json"),
})
jasmine.getEnv().addReporter(
new SpecReporter({
spec: {
displayStacktrace: StacktraceOption.PRETTY,
},
})
)
},
}

25
e2e/src/app.e2e-spec.ts Normal file
View File

@ -0,0 +1,25 @@
import { browser, logging } from "protractor"
import { AppPage } from "./app.po"
describe("workspace-project App", (): void => {
let page: AppPage
beforeEach((): void => {
page = new AppPage()
})
it("should display welcome message", (): void => {
void page.navigateTo()
void expect(page.getTitleText()).toEqual("public-gateway-cacher app is running!")
})
afterEach(async (): Promise<void> => {
// Assert that there are no errors emitted from the browser
const logs = await browser.manage().logs().get(logging.Type.BROWSER)
const expected: Partial<logging.Entry> = {
level: logging.Level.SEVERE,
}
void expect(logs).not.toContain(jasmine.objectContaining(expected))
})
})

11
e2e/src/app.po.ts Normal file
View File

@ -0,0 +1,11 @@
import { browser, by, element } from "protractor"
export class AppPage {
async navigateTo(): Promise<unknown> {
return browser.get(browser.baseUrl) as Promise<unknown>
}
async getTitleText(): Promise<string> {
return element(by.css("pgc-root .content span")).getText() as Promise<string>
}
}

10
e2e/tsconfig.json Normal file
View File

@ -0,0 +1,10 @@
/* To learn more about this file see: https://angular.io/config/tsconfig. */
{
"extends": "../tsconfig.json",
"compilerOptions": {
"outDir": "../out-tsc/e2e",
"module": "commonjs",
"target": "ESNext",
"types": ["jasmine", "jasminewd2", "node"]
}
}

View File

@ -1,76 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<title>Public IPFS Gateways</title>
<link rel="shortcut icon" type="image/png" href="images/favicon.png" />
<!-- Bootstrap 4 -->
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
<!-- CSS -->
<link rel="stylesheet" href="css/styles.css">
<!-- JavaScript -->
<script async src="javascript/app.js"></script>
</head>
<body>
<!-- Title -->
<header class="container">
<h1>Public IPFS Gateways</h1>
</header>
<main class="container">
<!-- IPFS Hash -->
<div class="form-group input-group">
<div class="input-group-prepend">
<label class="input-group-text" for="input_ipfs">IPFS Hash</label>
</div>
<input type="text" class="form-control" id="input_ipfs">
<div class="input-group-append">
<button class="btn btn-secondary" type="button" onclick="start_ipfs();">Cache</button>
</div>
</div>
<!-- IPNS Hash -->
<div class="form-group input-group">
<div class="input-group-prepend">
<label class="input-group-text" for="input_ipns">IPNS Hash</label>
</div>
<input type="text" class="form-control" id="input_ipns">
<div class="input-group-append">
<button class="btn btn-secondary" onclick="start_ipns();">Cache</button>
</div>
</div>
<!-- Results -->
<h3 id="stats"></h3>
<div id="results"></div>
</main>
<!-- About -->
<footer class="container">
<h3>About</h3>
<p>
This is a fork of <a href="https://github.com/ipfs/public-gateway-checker">github.com/ipfs/public-gateway-checker</a> that allows you to cache a specific IPFS and IPNS hash to a bunch of public gateways. The code source is available at <a href="https://gitlab.com/NatoBoram/public-gateway-checker">gitlab.com/NatoBoram/public-gateway-checker</a>.
</p>
<p>
If you'd like to add a new public gateway, please go to <a href="https://github.com/ipfs/public-gateway-checker">github.com/ipfs/public-gateway-checker</a>, submit a pull request then open an issue <a href="https://gitlab.com/NatoBoram/public-gateway-checker/issues/new">here</a>.
</p>
</footer>
</body>
</html>

View File

@ -1,79 +0,0 @@
var hashToTest = "";
var protocol = "";
const $results = document.querySelector('#results');
function returnHtmlLink(gateway) {
let gatewayTitle = gateway.split(hashToTest)[0];
return '<a title="' + gatewayTitle + '" href="' + gateway + '">' + gateway + '</a>';
}
function addNode(gateway, online, title) {
const para = document.createElement('div');
let node;
if (online) {
node = document.createElement('strong');
node.innerHTML = '✅ - Online - ' + returnHtmlLink(gateway);
} else {
node = document.createElement('div');
node.innerText = '❌ - Offline - ' + gateway;
}
node.setAttribute('title', title);
para.appendChild(node);
$results.appendChild(para);
}
function updateStats(total, checked) {
document.getElementById('stats').innerText = checked + '/' + total + ' gateways checked';
}
function checkGateways(gateways) {
const total = gateways.length;
let checked = 0;
gateways.forEach((gateway) => {
gateway = gateway.replace('/ipfs/', protocol);
const gatewayAndHash = gateway.replace(':hash', hashToTest);
// opt-out from gateway redirects done by browser extension
const testUrl = gatewayAndHash + '#x-ipfs-companion-no-redirect';
fetch(testUrl)
.then(res => res.text())
.then((text) => {
const matched = true; // TODO : Check if the response is good.
addNode(gatewayAndHash, matched, matched ? 'All good' : 'Output did not match expected output');
checked++;
updateStats(total, checked);
}).catch((err) => {
window.err = err;
addNode(gatewayAndHash, false, err);
checked++;
updateStats(total, checked);
});
});
}
function start_ipfs() {
while ($results.lastChild) {
$results.removeChild($results.lastChild);
}
hashToTest = document.querySelector("#input_ipfs").value;
protocol = "/ipfs/";
fetch('./json/gateways.json')
.then(res => res.json())
.then(gateways => checkGateways(gateways));
}
function start_ipns() {
while ($results.lastChild) {
$results.removeChild($results.lastChild);
}
hashToTest = document.querySelector("#input_ipns").value;
protocol = "/ipns/";
fetch('./json/gateways.json')
.then(res => res.json())
.then(gateways => checkGateways(gateways));
}

View File

@ -1,38 +0,0 @@
[
"https://ipfs.io/ipfs/:hash",
"https://gateway.ipfs.io/ipfs/:hash",
"https://ipfs.infura.io/ipfs/:hash",
"https://rx14.co.uk/ipfs/:hash",
"https://xmine128.tk/ipfs/:hash",
"https://upload.global/ipfs/:hash",
"https://ipfs.jes.xxx/ipfs/:hash",
"https://catalunya.network/ipfs/:hash",
"https://siderus.io/ipfs/:hash",
"https://ipfs.eternum.io/ipfs/:hash",
"https://hardbin.com/ipfs/:hash",
"https://ipfs.macholibre.org/ipfs/:hash",
"https://ipfs.works/ipfs/:hash",
"https://ipfs.wa.hle.rs/ipfs/:hash",
"https://api.wisdom.sh/ipfs/:hash",
"https://gateway.blocksec.com/ipfs/:hash",
"https://ipfs.renehsz.com/ipfs/:hash",
"https://cloudflare-ipfs.com/ipfs/:hash",
"https://ipns.co/:hash",
"https://ipfs.netw0rk.io/ipfs/:hash",
"https://gateway.swedneck.xyz/ipfs/:hash",
"https://ipfs.mrh.io/ipfs/:hash",
"https://gateway.originprotocol.com/ipfs/:hash",
"https://ipfs.dapps.earth/ipfs/:hash",
"https://gateway.pinata.cloud/ipfs/:hash",
"https://ipfs.doolta.com/ipfs/:hash",
"https://ipfs.sloppyta.co/ipfs/:hash",
"https://ipfs.busy.org/ipfs/:hash",
"https://ipfs.greyh.at/ipfs/:hash",
"https://gateway.serph.network/ipfs/:hash",
"https://jorropo.ovh/ipfs/:hash",
"https://ipfs.deo.moe/ipfs/:hash",
"https://gateway.temporal.cloud/ipfs/:hash",
"https://ipfs.fooock.com/ipfs/:hash",
"https://lineageos-on-ipfs.com/ipfs/:hash",
"https://permaweb.io/ipfs/:hash"
]

32
karma.conf.js Normal file
View File

@ -0,0 +1,32 @@
// Karma configuration file, see link for more information
// https://karma-runner.github.io/1.0/config/configuration-file.html
module.exports = function (config) {
config.set({
basePath: "",
frameworks: ["jasmine", "@angular-devkit/build-angular"],
plugins: [
require("karma-jasmine"),
require("karma-chrome-launcher"),
require("karma-jasmine-html-reporter"),
require("karma-coverage-istanbul-reporter"),
require("@angular-devkit/build-angular/plugins/karma"),
],
client: {
clearContext: false, // leave Jasmine Spec Runner output visible in browser
},
coverageIstanbulReporter: {
dir: require("path").join(__dirname, "./coverage/public-gateway-cacher"),
reports: ["html", "lcovonly", "text-summary"],
fixWebpackSourcePaths: true,
},
reporters: ["progress", "kjhtml"],
port: 9876,
colors: true,
logLevel: config.LOG_INFO,
autoWatch: true,
browsers: ["Chrome"],
singleRun: false,
restartOnFileChange: true,
})
}

91
package.json Normal file
View File

@ -0,0 +1,91 @@
{
"name": "public-gateway-cacher",
"version": "2.2.1",
"description": "Cache a specific hash on a bunch of public gateways.",
"keywords": [
"IPFS"
],
"homepage": "https://natoboram.gitlab.io/public-gateway-cacher",
"bugs": {
"url": "https://gitlab.com/NatoBoram/public-gateway-cacher/-/issues",
"email": "contact-project+natoboram-public-gateway-cacher-11685619-issue-@incoming.gitlab.com"
},
"license": "GPL-3.0-or-later",
"author": {
"name": "Nato Boram",
"url": "https://gitlab.com/NatoBoram"
},
"funding": [
{
"type": "patreon",
"url": "https://www.patreon.com/NatoBoram"
},
"https://paypal.me/NatoBoram/5"
],
"repository": "gitlab:NatoBoram/public-gateway-cacher",
"scripts": {
"ng": "ng",
"start": "ng serve --ssl",
"build": "ng build --base-href /",
"build:prod": "ng build --configuration=production --base-href /",
"build:gitlab": "ng build --configuration=gitlab --base-href /public-gateway-cacher/",
"build:ipfs": "ng build --configuration=ipfs",
"test": "ng test",
"lint": "ng lint --fix",
"eslint": "eslint --fix .",
"prettier": "prettier --write .",
"e2e": "ng e2e",
"publish:ipfs": "pnpm run build:ipfs && ipfs add --recursive --chunker=buzhash --cid-version=1 dist/angular",
"postinstall": "ngcc"
},
"dependencies": {
"@angular/animations": "~13.3.9",
"@angular/cdk": "~13.3.7",
"@angular/common": "~13.3.9",
"@angular/compiler": "~13.3.9",
"@angular/core": "~13.3.9",
"@angular/flex-layout": "^13.0.0-beta.38",
"@angular/forms": "~13.3.9",
"@angular/material": "^13.3.7",
"@angular/platform-browser": "~13.3.9",
"@angular/platform-browser-dynamic": "~13.3.9",
"@angular/router": "~13.3.9",
"bootstrap": "^5.1.3",
"ipfs-css": "^1.3.0",
"rxjs": "~7.5.5",
"tslib": "^2.0.0",
"zone.js": "~0.11.4"
},
"devDependencies": {
"@angular-devkit/build-angular": "~13.3.6",
"@angular-eslint/builder": "13.2.1",
"@angular-eslint/eslint-plugin": "13.2.1",
"@angular-eslint/eslint-plugin-template": "13.2.1",
"@angular-eslint/schematics": "13.2.1",
"@angular-eslint/template-parser": "13.2.1",
"@angular/cli": "~13.3.6",
"@angular/compiler-cli": "~13.3.9",
"@angular/language-service": "~13.3.9",
"@types/jasmine": "~3.10.3",
"@types/jasminewd2": "~2.0.3",
"@types/node": "^17.0.21",
"@typescript-eslint/eslint-plugin": "5.14.0",
"@typescript-eslint/parser": "5.14.0",
"eslint": "^8.2.0",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-rxjs": "^5.0.2",
"eslint-plugin-rxjs-angular": "^2.0.0",
"jasmine-core": "~4.0.1",
"jasmine-spec-reporter": "~7.0.0",
"karma": "~6.3.17",
"karma-chrome-launcher": "~3.1.0",
"karma-coverage-istanbul-reporter": "~3.0.2",
"karma-jasmine": "~4.0.0",
"karma-jasmine-html-reporter": "^1.5.0",
"prettier": "^2.5.1",
"protractor": "~7.0.0",
"ts-node": "~10.7.0",
"typescript": "~4.5.5"
},
"private": true
}

9188
pnpm-lock.yaml Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1 +0,0 @@
bafybeicnwv6up3wtr7qwhlsrjthhedr4dkcdqqgatow4nsiog2uxl2ue2e

View File

@ -1,3 +0,0 @@
@echo off
ipfs add --recursive --quieter --wrap-with-directory --chunker=rabin --cid-version=1 index.html css images javascript json > public-gateway-cacher.ipfs
echo on

View File

@ -1,2 +0,0 @@
#!/bin/sh
ipfs add --recursive --quieter --wrap-with-directory --chunker=rabin --cid-version=1 index.html css images javascript json > public-gateway-cacher.ipfs

View File

@ -0,0 +1,17 @@
import { NgModule } from "@angular/core"
import type { Routes } from "@angular/router"
import { RouterModule } from "@angular/router"
import { environment } from "../environments/environment"
const routes: Routes = [
{
path: "",
loadChildren: async () => import("./pages/pages.module").then(m => m.PagesModule),
},
]
@NgModule({
imports: [RouterModule.forRoot(routes, { useHash: environment.useHash, relativeLinkResolution: "legacy" })],
exports: [RouterModule],
})
export class AppRoutingModule {}

View File

@ -0,0 +1,9 @@
<mat-toolbar color="primary" fxLayout="row" fxLayoutAlign="space-between center" fxLayoutGap="1em">
<h1>Public Gateway Cacher</h1>
<!-- Theme Switcher -->
<button mat-icon-button="">
<mat-icon (click)="themeService.switchTheme()">{{ themeService.icon }}</mat-icon>
</button>
</mat-toolbar>
<router-outlet></router-outlet>

View File

@ -0,0 +1,41 @@
import { TestBed, waitForAsync } from "@angular/core/testing"
import { RouterTestingModule } from "@angular/router/testing"
import { AppComponent } from "./app.component"
describe("AppComponent", (): void => {
beforeEach(waitForAsync((): void => {
void TestBed.configureTestingModule({
imports: [RouterTestingModule],
declarations: [AppComponent],
}).compileComponents()
}))
it("should create the app", (): void => {
const fixture = TestBed.createComponent(AppComponent)
if (!(fixture.debugElement.componentInstance instanceof AppComponent)) throw new Error("Expected AppComponent")
const app: AppComponent = fixture.debugElement.componentInstance
void expect(app).toBeTruthy()
})
it(`should have a themeService`, (): void => {
const fixture = TestBed.createComponent(AppComponent)
if (!(fixture.debugElement.componentInstance instanceof AppComponent)) throw new Error("Expected AppComponent")
const app: AppComponent = fixture.debugElement.componentInstance
void expect(app.themeService).toBeTruthy()
})
it("should render title", (): void => {
const fixture = TestBed.createComponent(AppComponent)
fixture.detectChanges()
if (!isHTMLElement(fixture.debugElement.nativeElement)) throw new Error("Expected HTMLElement")
const compiled: HTMLElement = fixture.debugElement.nativeElement
void expect(compiled.querySelector("h1")?.textContent).toContain("Public Gateway Cacher")
})
})
function isHTMLElement(element: unknown): element is HTMLElement {
return Object.getPrototypeOf(element) instanceof HTMLElement
}

12
src/app/app.component.ts Normal file
View File

@ -0,0 +1,12 @@
import { ChangeDetectionStrategy, Component, Inject } from "@angular/core"
import { ThemeService } from "./services/theme.service"
@Component({
selector: "app-root",
templateUrl: "./app.component.html",
styleUrls: ["./app.component.scss"],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class AppComponent {
constructor(@Inject(ThemeService) readonly themeService: ThemeService) {}
}

29
src/app/app.module.ts Normal file
View File

@ -0,0 +1,29 @@
import { CommonModule } from "@angular/common"
import { HttpClientModule } from "@angular/common/http"
import { NgModule } from "@angular/core"
import { FlexLayoutModule } from "@angular/flex-layout"
import { MatButtonModule } from "@angular/material/button"
import { MatIconModule } from "@angular/material/icon"
import { MatToolbarModule } from "@angular/material/toolbar"
import { BrowserModule } from "@angular/platform-browser"
import { BrowserAnimationsModule } from "@angular/platform-browser/animations"
import { AppRoutingModule } from "./app-routing.module"
import { AppComponent } from "./app.component"
@NgModule({
declarations: [AppComponent],
imports: [
AppRoutingModule,
BrowserAnimationsModule,
BrowserModule,
CommonModule,
FlexLayoutModule,
HttpClientModule,
MatButtonModule,
MatIconModule,
MatToolbarModule,
],
providers: [],
bootstrap: [AppComponent],
})
export class AppModule {}

View File

@ -0,0 +1,4 @@
export enum Protocol {
IPFS = "ipfs",
IPNS = "ipns",
}

View File

@ -0,0 +1,4 @@
export enum Theme {
Light = "theme-light",
Dark = "theme-dark",
}

View File

@ -0,0 +1,5 @@
export interface Environment {
production: boolean
base_href?: string
useHash: boolean
}

9
src/app/package.json Normal file
View File

@ -0,0 +1,9 @@
{
"name": "public-gateway-cacher",
"private": true,
"description_1": "This is a special package.json file that is not used by package managers.",
"description_2": "It is used to tell the tools and bundlers whether the code under this directory is free of code with non-local side-effect. Any code that does have non-local side-effects can't be well optimized (tree-shaken) and will result in unnecessary increased payload size.",
"description_3": "It should be safe to set this option to 'false' for new applications, but existing code bases could be broken when built with the production config if the application code does contain non-local side-effects that the application depends on.",
"description_4": "To learn more about this file see: https://angular.io/config/app-package-json.",
"sideEffects": false
}

View File

@ -0,0 +1,17 @@
import { NgModule } from "@angular/core"
import type { Routes } from "@angular/router"
import { RouterModule } from "@angular/router"
import { PagesComponent } from "./pages.component"
const routes: Routes = [
{
path: "",
component: PagesComponent,
},
]
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule],
})
export class PagesRoutingModule {}

View File

@ -0,0 +1,82 @@
<div class="container" fxLayout="column" fxLayoutAlign="space-evenly center" fxLayoutGap="1em">
<!-- IPFS -->
<form fxLayout="row" fxLayoutAlign="space-evenly center" fxLayoutGap="1em">
<!-- Hash -->
<mat-form-field [color]="inputColour">
<mat-label>IPFS</mat-label>
<input name="ipfs" [(ngModel)]="ipfs" matInput />
</mat-form-field>
<!-- Cache -->
<button (click)="cacheIPFS()" type="button" mat-flat-button color="primary">Cache</button>
</form>
<!-- IPNS -->
<form fxLayout="row" fxLayoutAlign="space-evenly center" fxLayoutGap="1em">
<!-- Hash -->
<mat-form-field [color]="inputColour">
<mat-label>IPNS</mat-label>
<input name="ipns" [(ngModel)]="ipns" matInput />
</mat-form-field>
<!-- Cache -->
<button (click)="cacheIPNS()" type="button" mat-flat-button color="primary">Cache</button>
</form>
<mat-progress-bar
[value]="(dataSource.data.length / gateways.length) * 100"
*ngIf="subscriptions.length"
mode="determinate"
color="primary"
>
</mat-progress-bar>
<table class="mat-elevation-z8" [dataSource]="dataSource" mat-table aria-label="List of IPFS gateways and their statuses.">
<!-- Result Column -->
<ng-container matColumnDef="icon">
<th mat-header-cell *matHeaderCellDef scope="col">Status</th>
<td mat-cell *matCellDef="let element">
<span [matTooltip]="element.message"> {{ element.icon }} </span>
</td>
</ng-container>
<!-- Gateway Column -->
<ng-container matColumnDef="gateway">
<th mat-header-cell *matHeaderCellDef scope="col">Gateway</th>
<td mat-cell *matCellDef="let element">
<div [ngSwitch]="element.ok">
<div *ngSwitchCase="true">
<strong>
<a class="aqua" href="{{ element.gateway }}#x-ipfs-companion-no-redirect" target="_blank">
{{ element.gateway }}
</a>
</strong>
</div>
<div *ngSwitchCase="false">
<a class="aqua-muted" href="{{ element.gateway }}#x-ipfs-companion-no-redirect" target="_blank">
{{ element.gateway }}
</a>
</div>
</div>
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns"></tr>
</table>
<!-- About -->
<div fxLayout="column" fxLayoutAlign="space-evenly start" fxLayoutGap="1em">
<h3>About</h3>
<p>
This allows you to cache a specific IPFS hash to a bunch of public gateways. It's inspired from
<a class="link" href="https://github.com/ipfs/public-gateway-checker">github.com/ipfs/public-gateway-checker</a>. The source code is
available at <a class="link" href="https://gitlab.com/NatoBoram/public-gateway-cacher">gitlab.com/NatoBoram/public-gateway-cacher</a>.
</p>
<p>
If you'd like to add a new public gateway, please go to
<a class="link" href="https://github.com/ipfs/public-gateway-checker">github.com/ipfs/public-gateway-checker</a>, submit a pull
request then open an issue <a class="link" href="https://gitlab.com/NatoBoram/public-gateway-cacher/issues/new">here</a>.
</p>
</div>
</div>

View File

@ -0,0 +1,27 @@
.mat-form-field {
width: 30em;
max-width: 100%;
}
.mat-table {
width: 100%;
}
.mat-progress-bar {
width: 100%;
}
.mat-header-cell {
padding: 1em;
}
.mat-column-icon {
text-align: center;
width: 5em;
max-width: 100%;
}
.mat-column-gateway {
width: 50em;
max-width: 100%;
}

View File

@ -0,0 +1,26 @@
import { HttpClientTestingModule } from "@angular/common/http/testing"
import type { ComponentFixture } from "@angular/core/testing"
import { TestBed, waitForAsync } from "@angular/core/testing"
import { PagesComponent } from "./pages.component"
describe("PagesComponent", (): void => {
let component: PagesComponent
let fixture: ComponentFixture<PagesComponent>
beforeEach(waitForAsync((): void => {
void TestBed.configureTestingModule({
imports: [HttpClientTestingModule],
declarations: [PagesComponent],
}).compileComponents()
}))
beforeEach((): void => {
fixture = TestBed.createComponent(PagesComponent)
component = fixture.componentInstance
fixture.detectChanges()
})
it("should create", (): void => {
void expect(component).toBeTruthy()
})
})

View File

@ -0,0 +1,151 @@
import { HttpErrorResponse } from "@angular/common/http"
import type { OnDestroy, OnInit } from "@angular/core"
import { ChangeDetectionStrategy, Component, EventEmitter, Inject, ViewChild } from "@angular/core"
import type { ThemePalette } from "@angular/material/core"
import { MatTable, MatTableDataSource } from "@angular/material/table"
import type { Subscription } from "rxjs"
import { takeUntil } from "rxjs/operators"
import { environment } from "../../environments/environment"
import { Protocol } from "../enums/protocol.enum"
import { Theme } from "../enums/theme.enum"
import { GatewayService } from "../services/gateway.service"
import { ThemeService } from "../services/theme.service"
@Component({
selector: "app-pages",
templateUrl: "./pages.component.html",
styleUrls: ["./pages.component.scss"],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class PagesComponent implements OnInit, OnDestroy {
@ViewChild(MatTable) matTable!: MatTable<Result>
gateways!: string[]
inputColour: ThemePalette = "primary"
ipfs = ""
ipns = ""
readonly dataSource = new MatTableDataSource<Result>([])
readonly displayedColumns = ["icon", "gateway"]
readonly subscriptions: Subscription[] = []
private readonly destroy$ = new EventEmitter<void>()
constructor(
@Inject(GatewayService) private readonly gatewayService: GatewayService,
@Inject(ThemeService) private readonly themeService: ThemeService
) {}
ngOnInit(): void {
this.gatewayService
.list()
.pipe(takeUntil(this.destroy$))
.subscribe((gateways): void => {
this.gateways = gateways
})
// Theme
this.setColours(this.themeService.current)
this.themeService.valueChanges.pipe(takeUntil(this.destroy$)).subscribe((theme): void => {
this.setColours(theme)
})
}
ngOnDestroy(): void {
this.destroy$.next()
this.destroy$.complete()
}
cacheIPFS(): void {
this.ipfs = this.ipfs.trim()
this.cache(Protocol.IPFS, this.ipfs)
}
cacheIPNS(): void {
this.ipns = this.ipns.trim()
this.cache(Protocol.IPNS, this.ipns)
}
cache(protocol: Protocol, hashpath: string): void {
// Clear subscriptions
while (this.subscriptions.length) {
const sub = this.subscriptions.pop()
if (sub && !sub.closed) {
sub.unsubscribe()
}
}
// Clear table
this.dataSource.data = []
this.matTable.renderRows()
console.clear()
this.gateways.forEach((gateway): void => {
this.subscriptions.push(
this.gatewayService
.get(gateway, protocol, hashpath)
.pipe(takeUntil(this.destroy$))
.subscribe(
(resp): void => {
this.dataSource.data.unshift({
gateway: this.gatewayService.url(gateway, protocol, hashpath),
message: resp.statusText,
icon: this.getIcon(resp.status),
ok: resp.ok,
})
this.matTable.renderRows()
},
(error: unknown): void => {
if (!(error instanceof HttpErrorResponse)) return
this.dataSource.data.push({
gateway: this.gatewayService.url(gateway, protocol, hashpath),
message: error.statusText,
icon: this.getIcon(error.status),
ok: error.ok,
})
this.matTable.renderRows()
}
)
)
})
}
private setColours(theme: Theme): void {
switch (theme) {
case Theme.Light:
this.inputColour = "primary"
break
case Theme.Dark:
this.inputColour = "accent"
break
default:
break
}
}
private getIcon(status: number): string {
if (status >= 200 && status < 300) {
return "✅"
}
switch (status) {
case 0:
return "❌"
case 403:
return "⛔"
case 404:
return "❓"
case 500:
return "❗"
default:
return environment.production ? "❌" : "❔"
}
}
}
interface Result {
gateway: string
message: string
icon: string
ok: boolean
}

View File

@ -0,0 +1,29 @@
import { CommonModule } from "@angular/common"
import { NgModule } from "@angular/core"
import { FlexLayoutModule } from "@angular/flex-layout"
import { FormsModule } from "@angular/forms"
import { MatButtonModule } from "@angular/material/button"
import { MatInputModule } from "@angular/material/input"
import { MatProgressBarModule } from "@angular/material/progress-bar"
import { MatSortModule } from "@angular/material/sort"
import { MatTableModule } from "@angular/material/table"
import { MatTooltipModule } from "@angular/material/tooltip"
import { PagesRoutingModule } from "./pages-routing.module"
import { PagesComponent } from "./pages.component"
@NgModule({
declarations: [PagesComponent],
imports: [
CommonModule,
FlexLayoutModule,
FormsModule,
MatButtonModule,
MatInputModule,
MatProgressBarModule,
MatSortModule,
MatTableModule,
MatTooltipModule,
PagesRoutingModule,
],
})
export class PagesModule {}

View File

@ -0,0 +1,18 @@
import { HttpClientTestingModule } from "@angular/common/http/testing"
import type { TestBedStatic } from "@angular/core/testing"
import { TestBed } from "@angular/core/testing"
import { GatewayService } from "./gateway.service"
describe("GatewayService", (): void => {
beforeEach(
(): TestBedStatic =>
TestBed.configureTestingModule({
imports: [HttpClientTestingModule],
})
)
it("should be created", (): void => {
const service: GatewayService = TestBed.inject(GatewayService)
void expect(service).toBeTruthy()
})
})

View File

@ -0,0 +1,34 @@
import type { HttpResponse } from "@angular/common/http"
import { HttpClient } from "@angular/common/http"
import { Inject, Injectable } from "@angular/core"
import type { Observable } from "rxjs"
import { environment } from "../../environments/environment"
import type { Protocol } from "../enums/protocol.enum"
@Injectable({
providedIn: "root",
})
export class GatewayService {
constructor(@Inject(HttpClient) private readonly http: HttpClient) {}
list(): Observable<string[]> {
return this.http.get<string[]>(
environment.base_href && environment.base_href !== "/"
? `${environment.base_href}/assets/json/gateways.json`
: `${document.querySelector("base")?.href ?? ""}assets/json/gateways.json`
)
}
get(gateway: string, protocol: Protocol, hashpath: string): Observable<HttpResponse<string>> {
return this.http.get(`${this.url(gateway, protocol, hashpath)}#x-ipfs-companion-no-redirect`, {
observe: "response",
responseType: "text",
})
}
url(gateway: string, protocol: Protocol, hashpath: string): string {
const splits: string[] = hashpath.split("/")
const url: string = gateway.replaceAll(":type", protocol).replaceAll(":hash", splits.shift() ?? "")
return splits.length ? [url, splits.join("/")].join("/") : url
}
}

View File

@ -0,0 +1,15 @@
import { TestBed } from "@angular/core/testing"
import { ThemeService } from "./theme.service"
describe("ThemeService", (): void => {
let service: ThemeService
beforeEach((): void => {
TestBed.configureTestingModule({})
service = TestBed.inject(ThemeService)
})
it("should be created", (): void => {
void expect(service).toBeTruthy()
})
})

View File

@ -0,0 +1,51 @@
import { Injectable } from "@angular/core"
import type { Observable } from "rxjs"
import { Subject } from "rxjs"
import { Theme } from "../enums/theme.enum"
function enumGuard<T>(enumeration: T): (token: unknown) => token is T[keyof T] {
return (token: unknown): token is T[keyof T] => Object.values(enumeration).includes(token)
}
@Injectable({
providedIn: "root",
})
export class ThemeService {
current = Theme.Light
icon = "brightness_low"
readonly valueChanges: Observable<Theme>
private readonly subject$ = new Subject<Theme>()
constructor() {
const stored = localStorage.getItem("theme")
if (enumGuard(Theme)(stored)) {
this.setTheme(stored)
}
this.valueChanges = this.subject$.asObservable()
}
switchTheme(): void {
this.setTheme(this.current === Theme.Light ? Theme.Dark : Theme.Light)
}
setTheme(theme: Theme): void {
document.querySelector("body")?.classList.remove(this.current)
document.querySelector("body")?.classList.add(theme)
this.current = theme
this.icon = this.getIcon(theme)
this.subject$.next(theme)
localStorage.setItem("theme", theme)
}
getIcon(theme: Theme): string {
switch (theme) {
case Theme.Dark:
return "brightness_high"
case Theme.Light:
default:
return "brightness_low"
}
}
}

0
src/assets/.gitkeep Normal file
View File

View File

@ -0,0 +1,96 @@
[
"https://ipfs.io/:type/:hash",
"https://dweb.link/:type/:hash",
"https://gateway.ipfs.io/:type/:hash",
"https://ipfs.infura.io/:type/:hash",
"https://infura-ipfs.io/:type/:hash",
"https://ninetailed.ninja/:type/:hash",
"https://via0.com/:type/:hash",
"https://ipfs.eternum.io/:type/:hash",
"https://hardbin.com/:type/:hash",
"https://gateway.blocksec.com/:type/:hash",
"https://cloudflare-ipfs.com/:type/:hash",
"https://astyanax.io/:type/:hash",
"https://cf-ipfs.com/:type/:hash",
"https://ipns.co/:type/:hash",
"https://ipfs.mrh.io/:type/:hash",
"https://gateway.originprotocol.com/:type/:hash",
"https://gateway.pinata.cloud/:type/:hash",
"https://ipfs.doolta.com/:type/:hash",
"https://ipfs.sloppyta.co/:type/:hash",
"https://ipfs.busy.org/:type/:hash",
"https://ipfs.greyh.at/:type/:hash",
"https://gateway.serph.network/:type/:hash",
"https://jorropo.net/:type/:hash",
"https://ipfs.fooock.com/:type/:hash",
"https://cdn.cwinfo.net/:type/:hash",
"https://aragon.ventures/:type/:hash",
"https://ipfs-cdn.aragon.ventures/:type/:hash",
"https://permaweb.io/:type/:hash",
"https://ipfs.best-practice.se/:type/:hash",
"https://storjipfs-gateway.com/:type/:hash",
"https://ipfs.runfission.com/:type/:hash",
"https://ipfs.trusti.id/:type/:hash",
"https://ipfs.overpi.com/:type/:hash",
"https://gateway.ipfs.lc/:type/:hash",
"https://ipfs.ink/:type/:hash",
"https://ipfsgateway.makersplace.com/:type/:hash",
"https://gateway.ravenland.org/:type/:hash",
"https://ipfs.funnychain.co/:type/:hash",
"https://ipfs.telos.miami/:type/:hash",
"https://ipfs.mttk.net/:type/:hash",
"https://ipfs.fleek.co/:type/:hash",
"https://ipfs.jbb.one/:type/:hash",
"https://ipfs.yt/:type/:hash",
"https://hashnews.k1ic.com/:type/:hash",
"https://ipfs.vip/:type/:hash",
"https://ipfs.drink.cafe/:type/:hash",
"https://ipfs.azurewebsites.net/:type/:hash",
"https://gw.ipfspin.com/:type/:hash",
"https://ipfs.kavin.rocks/:type/:hash",
"https://ipfs.denarius.io/:type/:hash",
"https://ipfs.mihir.ch/:type/:hash",
"https://crustwebsites.net/:type/:hash",
"https://ipfs0.sjc.cloudsigma.com/:type/:hash",
"http://ipfs.genenetwork.org/:type/:hash",
"https://ipfs.eth.aragon.network/:type/:hash",
"https://ipfs.smartholdem.io/:type/:hash",
"https://ipfs.xoqq.ch/:type/:hash",
"https://natoboram.mynetgear.com/:type/:hash",
"https://video.oneloveipfs.com/:type/:hash",
"http://ipfs.anonymize.com/:type/:hash",
"https://ipfs.taxi/:type/:hash",
"https://ipfs.scalaproject.io/:type/:hash",
"https://search.ipfsgate.com/:type/:hash",
"https://ipfs.decoo.io/:type/:hash",
"https://ivoputzer.xyz/:type/:hash",
"https://alexdav.id/:type/:hash",
"https://ipfs.uploads.nu/:type/:hash",
"https://hub.textile.io/:type/:hash",
"https://ipfs1.pixura.io/:type/:hash",
"https://ravencoinipfs-gateway.com/:type/:hash",
"https://konubinix.eu/:type/:hash",
"https://3cloud.ee/:type/:hash",
"https://ipfs.tubby.cloud/:type/:hash",
"https://ipfs.lain.la/:type/:hash",
"https://ipfs.adatools.io/:type/:hash",
"https://ipfs.kaleido.art/:type/:hash",
"https://ipfs.slang.cx/:type/:hash",
"https://ipfs.arching-kaos.com/:type/:hash",
"https://storry.tv/:type/:hash",
"https://ipfs.kxv.io/:type/:hash",
"https://ipfs.1-2.dev/:type/:hash",
"https://ipfs-nosub.stibarc.com/:type/:hash",
"https://dweb.eu.org/:type/:hash",
"https://permaweb.eu.org/:type/:hash",
"https://ipfs.namebase.io/:type/:hash",
"https://ipfs.tribecap.co/:type/:hash",
"https://ipfs.kinematiks.com/:type/:hash",
"https://c4rex.co/:type/:hash",
"https://ipfs.zod.tv/:type/:hash",
"https://nftstorage.link/:type/:hash",
"https://gravity.jup.io/:type/:hash",
"http://fzdqwfb5ml56oadins5jpuhe6ki6bk33umri35p5kt2tue4fpws5efid.onion/:type/:hash",
"https://tth-ipfs.com/:type/:hash",
"https://:type.natoboram.com/:type/:hash"
]

View File

@ -0,0 +1,7 @@
import type { Environment } from "../app/interfaces/environment"
export const environment: Environment = {
production: true,
base_href: "/public-gateway-cacher",
useHash: false,
}

View File

@ -0,0 +1,6 @@
import type { Environment } from "../app/interfaces/environment"
export const environment: Environment = {
production: true,
useHash: true,
}

View File

@ -0,0 +1,7 @@
import type { Environment } from "../app/interfaces/environment"
export const environment: Environment = {
production: true,
base_href: "/",
useHash: false,
}

View File

@ -0,0 +1,20 @@
import type { Environment } from "../app/interfaces/environment"
// This file can be replaced during build by using the `fileReplacements` array.
// `ng build --prod` replaces `environment.ts` with `environment.prod.ts`.
// The list of file replacements can be found in `angular.json`.
export const environment: Environment = {
production: false,
base_href: "/",
useHash: false,
}
/*
* For easier debugging in development mode, you can import the following file
* to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`.
*
* This import should be commented out in production mode because it will have a negative impact
* on performance if an error is thrown.
*/
// import 'zone.js/plugins/zone-error'; // Included with Angular CLI.

View File

Before

Width:  |  Height:  |  Size: 99 KiB

After

Width:  |  Height:  |  Size: 99 KiB

23
src/index.html Normal file
View File

@ -0,0 +1,23 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Public Gateway Cacher</title>
<!-- IPFS -->
<script>
if (document.getElementsByTagName("base").length === 0) document.write('<base href="' + window.location.pathname + '"/>')
</script>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="icon" type="image/x-icon" href="favicon.png" />
<!-- Material -->
<link href="https://fonts.googleapis.com/css?family=Roboto:300,400,500&display=swap" rel="stylesheet" />
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet" />
</head>
<body class="mat-app-background theme-light">
<app-root></app-root>
</body>
</html>

12
src/main.ts Normal file
View File

@ -0,0 +1,12 @@
import { enableProdMode } from "@angular/core"
import { platformBrowserDynamic } from "@angular/platform-browser-dynamic"
import { AppModule } from "./app/app.module"
import { environment } from "./environments/environment"
if (environment.production) {
enableProdMode()
}
platformBrowserDynamic()
.bootstrapModule(AppModule)
.catch((err): void => console.error(err))

52
src/polyfills.ts Normal file
View File

@ -0,0 +1,52 @@
/**
* This file includes polyfills needed by Angular and is loaded before the app.
* You can add your own extra polyfills to this file.
*
* This file is divided into 2 sections:
* 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers.
* 2. Application imports. Files imported after ZoneJS that should be loaded before your main
* file.
*
* The current setup is for so-called "evergreen" browsers; the last versions of browsers that
* automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera),
* Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile.
*
* Learn more in https://angular.io/guide/browser-support
*/
/***************************************************************************************************
* BROWSER POLYFILLS
*/
/**
* By default, zone.js will patch all possible macroTask and DomEvents
* user can disable parts of macroTask/DomEvents patch by setting following flags
* because those flags need to be set before `zone.js` being loaded, and webpack
* will put import in the top of bundle, so user need to create a separate file
* in this directory (for example: zone-flags.ts), and put the following flags
* into that file, and then add the following code before importing zone.js.
* import './zone-flags.ts';
*
* The flags allowed in zone-flags.ts are listed here.
*
* The following flags will work for all browsers.
*
* (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame
* (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick
* (window as any).__zone_symbol__UNPATCHED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames
*
* in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js
* with the following flag, it will bypass `zone.js` patch for IE/Edge
*
* (window as any).__Zone_enable_cross_context_check = true;
*
*/
/***************************************************************************************************
* Zone JS is required by default for Angular itself.
*/
import "zone.js" // Included with Angular CLI.
/***************************************************************************************************
* APPLICATION IMPORTS
*/

51
src/styles.scss Normal file
View File

@ -0,0 +1,51 @@
// Custom Theming for Angular Material
@use "@angular/material" as mat;
// For more information: https://material.angular.io/guide/theming
// Plus imports for other components in your app.
// Include the common styles for Angular Material. We include this here so that you only
// have to load a single css file for Angular Material in your app.
// Be sure that you only ever include this mixin once!
@include mat.core();
// // Define the palettes for your theme using the Material Design palettes available in palette.scss
// // (imported above). For each palette, you can optionally specify a default, lighter, and darker
// // hue. Available color palettes: https://material.io/design/color/
// $public-gateway-cacher-primary: mat-palette($mat-indigo);
// $public-gateway-cacher-accent: mat-palette($mat-pink, A200, A100, A400);
// // The warn palette is optional (defaults to red).
// $public-gateway-cacher-warn: mat-palette($mat-red);
// // Create the theme object (a Sass map containing all of the palettes).
// $public-gateway-cacher-theme: mat-light-theme($public-gateway-cacher-primary, $public-gateway-cacher-accent, $public-gateway-cacher-warn);
// // Include theme styles for core and each component used in your app.
// // Alternatively, you can import and @include the theme mixins for each component
// // that you are using.
// @include angular-material-theme($public-gateway-cacher-theme);
@import "styles/ipfs-themes.scss";
.theme-light {
@include mat.all-component-themes($ipfs-light-theme);
}
.theme-dark {
@include mat.all-component-themes($ipfs-dark-theme);
}
/* You can add global styles to this file, and also import other style files */
html,
body {
height: 100%;
}
body {
margin: 0;
font-family: Roboto, "Helvetica Neue", sans-serif;
}
@import "~bootstrap/scss/bootstrap-grid.scss";
@import "~ipfs-css/theme.scss";

View File

@ -0,0 +1,34 @@
@import "@angular/material/core/theming/palette";
$ipfs-colour-navy: (
default: #0b3a53,
lighter: #3e6480,
darker: #00142a,
contrast: (
default: $light-primary-text,
lighter: $light-primary-text,
darker: $light-primary-text,
),
);
$ipfs-colour-aqua: (
default: #69c5cd,
lighter: #9df8ff,
darker: #32949c,
contrast: (
default: $dark-primary-text,
lighter: $dark-primary-text,
darker: $dark-primary-text,
),
);
$ipfs-colour-yellow: (
default: #f39021,
lighter: #ffc155,
darker: #bb6200,
contrast: (
default: $dark-primary-text,
lighter: $dark-primary-text,
darker: $dark-primary-text,
),
);

View File

@ -0,0 +1,6 @@
@use "@angular/material" as mat;
@import "ipfs-colours.scss";
$ipfs-primary: mat.define-palette($ipfs-colour-navy, "default", "lighter", "darker");
$ipfs-accent: mat.define-palette($ipfs-colour-aqua, "default", "lighter", "darker");
$ipfs-warn: mat.define-palette($ipfs-colour-yellow, "default", "lighter", "darker");

View File

@ -0,0 +1,5 @@
@use "@angular/material" as mat;
@import "ipfs-palettes.scss";
$ipfs-light-theme: mat.define-light-theme($ipfs-primary, $ipfs-accent, $ipfs-warn);
$ipfs-dark-theme: mat.define-dark-theme($ipfs-primary, $ipfs-accent, $ipfs-warn);

16
src/test.ts Normal file
View File

@ -0,0 +1,16 @@
// This file is required by karma.conf.js and loads recursively all the .spec and framework files
import "zone.js/testing"
import { getTestBed } from "@angular/core/testing"
import { BrowserDynamicTestingModule, platformBrowserDynamicTesting } from "@angular/platform-browser-dynamic/testing"
declare const require: any
// First, initialize the Angular testing environment.
getTestBed().initTestEnvironment(BrowserDynamicTestingModule, platformBrowserDynamicTesting(), { teardown: { destroyAfterEach: false } })
// Then we find all the tests.
const context = require.context("./", true, /\.spec\.ts$/)
// And load the modules.
context.keys().map(context)

10
tsconfig.app.json Normal file
View File

@ -0,0 +1,10 @@
/* To learn more about this file see: https://angular.io/config/tsconfig. */
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "./out-tsc/app",
"types": []
},
"files": ["src/main.ts", "src/polyfills.ts"],
"include": ["src/**/*.d.ts"]
}

40
tsconfig.json Normal file
View File

@ -0,0 +1,40 @@
/* To learn more about this file see: https://angular.io/config/tsconfig. */
{
"compileOnSave": false,
"compilerOptions": {
"baseUrl": "./",
"outDir": "./dist/out-tsc",
"forceConsistentCasingInFileNames": true,
"strict": true,
"noImplicitAny": true,
"strictNullChecks": true,
"strictFunctionTypes": true,
"strictBindCallApply": true,
"strictPropertyInitialization": true,
"noImplicitThis": true,
"useUnknownInCatchVariables": true,
"alwaysStrict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"exactOptionalPropertyTypes": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"noUncheckedIndexedAccess": true,
"noImplicitOverride": true,
"noPropertyAccessFromIndexSignature": true,
"sourceMap": true,
"declaration": false,
"downlevelIteration": true,
"experimentalDecorators": true,
"moduleResolution": "node",
"importHelpers": true,
"target": "ESNext",
"module": "ESNext",
"lib": ["ESNext", "DOM"]
},
"angularCompilerOptions": {
"fullTemplateTypeCheck": true,
"strictInjectionParameters": true,
"strictTemplates": true
}
}

10
tsconfig.spec.json Normal file
View File

@ -0,0 +1,10 @@
/* To learn more about this file see: https://angular.io/config/tsconfig. */
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "./out-tsc/spec",
"types": ["jasmine"]
},
"files": ["src/test.ts", "src/polyfills.ts"],
"include": ["src/**/*.spec.ts", "src/**/*.d.ts"]
}