diff --git a/contents/docs/1-getting-started/version-control-basics/index.mdx b/contents/docs/1-getting-started/version-control-basics/index.mdx index 676ae987..b5dbca9e 100644 --- a/contents/docs/1-getting-started/version-control-basics/index.mdx +++ b/contents/docs/1-getting-started/version-control-basics/index.mdx @@ -35,8 +35,6 @@ Systems like Git where every user has a complete copy of the repository, includi #### Free Resources -###### Free Resources - Official Docs diff --git a/contents/docs/2-git-basics/commands/adding--updating/index.mdx b/contents/docs/2-git-basics/commands/adding--updating/index.mdx index d33a0122..28761dd5 100644 --- a/contents/docs/2-git-basics/commands/adding--updating/index.mdx +++ b/contents/docs/2-git-basics/commands/adding--updating/index.mdx @@ -9,8 +9,6 @@ To add a submodule to a repository, use `git submodule add https://github.com/us #### Free Resources -###### Free Resources - Articles diff --git a/contents/docs/2-git-basics/commands/between-commits/index.mdx b/contents/docs/2-git-basics/commands/between-commits/index.mdx index fb1d8843..4ea39c33 100644 --- a/contents/docs/2-git-basics/commands/between-commits/index.mdx +++ b/contents/docs/2-git-basics/commands/between-commits/index.mdx @@ -7,8 +7,6 @@ To compare two specific commits in your Git history, use git diff followed by th #### Free Resources -###### Free Resources - Articles diff --git a/contents/docs/2-git-basics/commands/checkout-tags/index.mdx b/contents/docs/2-git-basics/commands/checkout-tags/index.mdx index a3f2924e..9a02d835 100644 --- a/contents/docs/2-git-basics/commands/checkout-tags/index.mdx +++ b/contents/docs/2-git-basics/commands/checkout-tags/index.mdx @@ -8,8 +8,6 @@ Tags in Git are typically used to mark specific points in history, such as a rel #### Free Resources -###### Free Resources - Articles diff --git a/contents/docs/2-git-basics/commands/citation-files/index.mdx b/contents/docs/2-git-basics/commands/citation-files/index.mdx index c83a873f..3830122f 100644 --- a/contents/docs/2-git-basics/commands/citation-files/index.mdx +++ b/contents/docs/2-git-basics/commands/citation-files/index.mdx @@ -7,9 +7,6 @@ You can add a CITATION.cff file to the root of a repository to let others know h #### Free Resources - -###### Free Resources - Official Docs diff --git a/contents/docs/2-git-basics/commands/collaboration/index.mdx b/contents/docs/2-git-basics/commands/collaboration/index.mdx index 970d1028..04ebe5f2 100644 --- a/contents/docs/2-git-basics/commands/collaboration/index.mdx +++ b/contents/docs/2-git-basics/commands/collaboration/index.mdx @@ -8,8 +8,6 @@ When working on projects with others, Git provides tools to facilitate collabora #### Free Resources -###### Free Resources - Official Docs diff --git a/contents/docs/2-git-basics/commands/commit-messages/index.mdx b/contents/docs/2-git-basics/commands/commit-messages/index.mdx index 166a2143..09e171bf 100644 --- a/contents/docs/2-git-basics/commands/commit-messages/index.mdx +++ b/contents/docs/2-git-basics/commands/commit-messages/index.mdx @@ -7,8 +7,6 @@ A Git commit message is a brief explanation of the changes introduced in a parti #### Free Resources -###### Free Resources - Articles diff --git a/contents/docs/2-git-basics/commands/commit-msg/index.mdx b/contents/docs/2-git-basics/commands/commit-msg/index.mdx index ae76250f..b19a0b36 100644 --- a/contents/docs/2-git-basics/commands/commit-msg/index.mdx +++ b/contents/docs/2-git-basics/commands/commit-msg/index.mdx @@ -9,9 +9,6 @@ The commit-msg hook is a client-side hook that runs after you've committed chang #### Free Resources - -###### Free Resources - Articles diff --git a/contents/docs/2-git-basics/commands/git-commit/index.mdx b/contents/docs/2-git-basics/commands/git-commit/index.mdx index 35341831..e913141a 100644 --- a/contents/docs/2-git-basics/commands/git-commit/index.mdx +++ b/contents/docs/2-git-basics/commands/git-commit/index.mdx @@ -30,8 +30,6 @@ git commit --amend #### Free Resources -###### Free Resources - Articles diff --git a/contents/docs/2-git-basics/commands/git-lfs/index.mdx b/contents/docs/2-git-basics/commands/git-lfs/index.mdx index f84b1e36..436db00c 100644 --- a/contents/docs/2-git-basics/commands/git-lfs/index.mdx +++ b/contents/docs/2-git-basics/commands/git-lfs/index.mdx @@ -7,11 +7,6 @@ Git Large File Storage (LFS) is an extension that helps manage large files by tr #### Free Resources -- [@article@Learning About Git Large File System (LFS)](https://medium.com/swlh/learning-about-git-large-file-system-lfs-72e0c86cfbaf) -- [@video@Git LFS (Large File Storage) | Learn Git](https://www.youtube.com/watch?v=jXsvFfksvd0) - -#### Free Resources - Official Docs diff --git a/contents/docs/2-git-basics/commands/git-remotes/index.mdx b/contents/docs/2-git-basics/commands/git-remotes/index.mdx index 8ac730e6..13cc604f 100644 --- a/contents/docs/2-git-basics/commands/git-remotes/index.mdx +++ b/contents/docs/2-git-basics/commands/git-remotes/index.mdx @@ -7,11 +7,6 @@ In Git, a remote is a reference to a repository that exists on another server or #### Free Resources -- [@official@About Remote Repositories](https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories) -- [@video@What is a Remote Repository? [Beginner Git Tutorial]](https://www.youtube.com/watch?v=Lb4yvfrX_7I) - -#### Free Resources - Official Docs diff --git a/contents/docs/2-git-basics/commands/handling-conflicts/index.mdx b/contents/docs/2-git-basics/commands/handling-conflicts/index.mdx index 15a623d8..0eb66109 100644 --- a/contents/docs/2-git-basics/commands/handling-conflicts/index.mdx +++ b/contents/docs/2-git-basics/commands/handling-conflicts/index.mdx @@ -7,12 +7,6 @@ When multiple developers work on the same project simultaneously, conflicts can #### Free Resources -- [@article@Resolving a merge conflict using the command line](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/addressing-merge-conflicts/resolving-a-merge-conflict-using-the-command-line) -- [@article@Resolve merge conflicts in Visual Studio](https://learn.microsoft.com/en-us/visualstudio/version-control/git-resolve-conflicts?view=vs-2022) -- [@video@Resolve Git MERGE CONFLICTS: The Definitive Guide](https://www.youtube.com/watch?v=Sqsz1-o7nXk) - -#### Free Resources - Official Docs diff --git a/contents/docs/2-git-basics/commands/history/index.mdx b/contents/docs/2-git-basics/commands/history/index.mdx index 433d0f48..47f61ad2 100644 --- a/contents/docs/2-git-basics/commands/history/index.mdx +++ b/contents/docs/2-git-basics/commands/history/index.mdx @@ -7,10 +7,6 @@ The history of a Git repository is a record of all commits made over time, inclu #### Free Resources -- [@official@Git Basics - Viewing the Commit History](https://git-scm.com/book/en/v2/Git-Basics-Viewing-the-Commit-History) - -#### Free Resources - Official Docs diff --git a/contents/docs/2-git-basics/commands/managing-remotes/index.mdx b/contents/docs/2-git-basics/commands/managing-remotes/index.mdx index b7679746..38b05efe 100644 --- a/contents/docs/2-git-basics/commands/managing-remotes/index.mdx +++ b/contents/docs/2-git-basics/commands/managing-remotes/index.mdx @@ -14,10 +14,6 @@ Managing remotes is essential for collaborating on projects or tracking changes #### Free Resources -- [@official@Managing remote repositories](https://docs.github.com/en/get-started/getting-started-with-git/managing-remote-repositories) - -#### Free Resources - Official Docs diff --git a/contents/docs/2-git-basics/commands/managing-tags/index.mdx b/contents/docs/2-git-basics/commands/managing-tags/index.mdx index 946c9fea..6a2ab18f 100644 --- a/contents/docs/2-git-basics/commands/managing-tags/index.mdx +++ b/contents/docs/2-git-basics/commands/managing-tags/index.mdx @@ -13,11 +13,6 @@ Tags can be used for marking releases, milestones, or other significant events i #### Free Resources -- [@official@Git Basics - Tagging](https://git-scm.com/book/en/v2/Git-Basics-Tagging) -- [@article@Git — Use Tags for Versioning and Release Management](https://medium.com/@KeyurRamoliya/git-use-tags-for-versioning-and-release-management-09aca9631eee) - -#### Free Resources - Official Docs diff --git a/contents/docs/2-git-basics/commands/pre-push/index.mdx b/contents/docs/2-git-basics/commands/pre-push/index.mdx index 2846e36f..9210f0af 100644 --- a/contents/docs/2-git-basics/commands/pre-push/index.mdx +++ b/contents/docs/2-git-basics/commands/pre-push/index.mdx @@ -9,11 +9,6 @@ Git pre-push hooks are scripts that run automatically before a push operation is #### Free Resources -- [@article@pre-push hooks](https://dev.to/jameson/pre-push-hooks-42g5) -- [@video@Detect secrets with a pre-commit git hook](https://www.youtube.com/watch?v=8bDKn3y7Br4) - -#### Free Resources - Official Docs diff --git a/contents/docs/2-git-basics/commands/pushing-tags/index.mdx b/contents/docs/2-git-basics/commands/pushing-tags/index.mdx index baa91a8a..54818adc 100644 --- a/contents/docs/2-git-basics/commands/pushing-tags/index.mdx +++ b/contents/docs/2-git-basics/commands/pushing-tags/index.mdx @@ -7,12 +7,6 @@ Pushing tags in Git is the process of sharing your local tags with a remote repo #### Free Resources -- [@article@Tagging in git](https://git-scm.com/book/en/Git-Basics-Tagging) -- [@article@How to Push Git Tags to Remote](https://kodekloud.com/blog/how-to-push-git-tags-to-remote/) -- [@article@Git Push Tag to Remote Guide](https://phoenixnap.com/kb/git-push-tag) - -#### Free Resources - Official Docs diff --git a/contents/docs/2-git-basics/commands/staged-changes/index.mdx b/contents/docs/2-git-basics/commands/staged-changes/index.mdx index df4b5910..3c1769ed 100644 --- a/contents/docs/2-git-basics/commands/staged-changes/index.mdx +++ b/contents/docs/2-git-basics/commands/staged-changes/index.mdx @@ -7,11 +7,6 @@ To view the changes you've staged with `git add`, but not yet committed, use `gi #### Free Resources -- [@article@What does Staged Changes mean in Git?](https://dillionmegida.com/p/staged-changes-in-git/) -- [@video@What are Staged Changes in Git?](https://www.youtube.com/watch?v=HyeNfWZBut8) - -#### Free Resources - Official Docs diff --git a/contents/docs/2-git-basics/commands/staging-area/index.mdx b/contents/docs/2-git-basics/commands/staging-area/index.mdx index 0c9284b7..a09c1a69 100644 --- a/contents/docs/2-git-basics/commands/staging-area/index.mdx +++ b/contents/docs/2-git-basics/commands/staging-area/index.mdx @@ -10,11 +10,6 @@ In Git, a staging area serves as an intermediate step between your local reposit #### Free Resources -- [@official@Getting Started - What is Git? - Staging Area](https://git-scm.com/book/en/v2/Getting-Started-What-is-Git%3F#:~:text=The%20staging%20area%20is%20a,area%E2%80%9D%20works%20just%20as%20well.) -- [@video@What are Staged Changes in Git?](https://www.youtube.com/watch?v=HyeNfWZBut8) - -#### Free Resources - Official Docs diff --git a/contents/docs/2-git-basics/commands/submodules/index.mdx b/contents/docs/2-git-basics/commands/submodules/index.mdx index a755e3ac..0efddb61 100644 --- a/contents/docs/2-git-basics/commands/submodules/index.mdx +++ b/contents/docs/2-git-basics/commands/submodules/index.mdx @@ -10,11 +10,6 @@ In Git, submodules allow you to include another repository within a project. Thi #### Free Resources -- [@official@Git Submodules](https://git-scm.com/book/en/v2/Git-Tools-Submodules) -- [@article@Git Submodules Tutorial](https://www.atlassian.com/git/tutorials/git-submodule) - -#### Free Resources - Official Docs diff --git a/contents/docs/2-git-basics/commands/tagging/index.mdx b/contents/docs/2-git-basics/commands/tagging/index.mdx index fb37414a..8218d33a 100644 --- a/contents/docs/2-git-basics/commands/tagging/index.mdx +++ b/contents/docs/2-git-basics/commands/tagging/index.mdx @@ -10,10 +10,6 @@ In Git, tags are used to identify specific points in a repository's history as b #### Free Resources -- [@official@Git Basics - Tagging](https://git-scm.com/book/en/v2/Git-Basics-Tagging) - -#### Free Resources - Official Docs diff --git a/contents/docs/2-git-basics/setup/local-vs-global-config/index.mdx b/contents/docs/2-git-basics/setup/local-vs-global-config/index.mdx index 70893760..c8bd1bd0 100644 --- a/contents/docs/2-git-basics/setup/local-vs-global-config/index.mdx +++ b/contents/docs/2-git-basics/setup/local-vs-global-config/index.mdx @@ -9,8 +9,6 @@ description: To manage local and global configuration settings, you can use the #### Free Resources -###### Free Resources - Official Docs diff --git a/contents/docs/2-git-basics/working-with-files/git-attributes/index.mdx b/contents/docs/2-git-basics/working-with-files/git-attributes/index.mdx index 1a8e1687..527bc2eb 100644 --- a/contents/docs/2-git-basics/working-with-files/git-attributes/index.mdx +++ b/contents/docs/2-git-basics/working-with-files/git-attributes/index.mdx @@ -9,8 +9,6 @@ Git attributes are settings stored in the .gitattributes file, controlling how G #### Free Resources -###### Free Resources - Official Docs diff --git a/contents/docs/2-git-basics/working-with-files/staging-area/index.mdx b/contents/docs/2-git-basics/working-with-files/staging-area/index.mdx index f7310144..48d28043 100644 --- a/contents/docs/2-git-basics/working-with-files/staging-area/index.mdx +++ b/contents/docs/2-git-basics/working-with-files/staging-area/index.mdx @@ -5,8 +5,6 @@ description: Learn about Staging Area in Git #### Free Resources -###### Free Resources - Official Docs diff --git a/contents/docs/3-git-branching/basics/between-branches/index.mdx b/contents/docs/3-git-branching/basics/between-branches/index.mdx index d8e78f0a..e904a332 100644 --- a/contents/docs/3-git-branching/basics/between-branches/index.mdx +++ b/contents/docs/3-git-branching/basics/between-branches/index.mdx @@ -7,11 +7,6 @@ When comparing the differences between two branches, such as a feature branch an #### Free Resources -- [@article@How to compare branches in Git diff](https://scribehow.com/shared/How_to_Compare_Branches_in_GitHub__xsotezV-S1O-GL0PquqJwQ) -- [@article@How can I see the differences between two branches?](https://stackoverflow.com/questions/9834689/how-can-i-see-the-differences-between-two-branches) - -#### Free Resources - Official Docs diff --git a/contents/docs/3-git-branching/basics/branch-naming/index.mdx b/contents/docs/3-git-branching/basics/branch-naming/index.mdx index 64dd7b24..e1d15ac1 100644 --- a/contents/docs/3-git-branching/basics/branch-naming/index.mdx +++ b/contents/docs/3-git-branching/basics/branch-naming/index.mdx @@ -7,11 +7,6 @@ A well-defined branch naming convention is essential for maintaining a clean and #### Free Resources -- [@article@Naming conventions for Git Branches — a Cheatsheet](https://medium.com/@abhay.pixolo/naming-conventions-for-git-branches-a-cheatsheet-8549feca2534) -- [@article@Git Branching Naming Convention: Best Practices to Follow](https://phoenixnap.com/kb/git-branch-name-convention) - -#### Free Resources - Official Docs diff --git a/contents/docs/3-git-branching/basics/branching-basics/index.mdx b/contents/docs/3-git-branching/basics/branching-basics/index.mdx index 958d3e3e..be5fcf25 100644 --- a/contents/docs/3-git-branching/basics/branching-basics/index.mdx +++ b/contents/docs/3-git-branching/basics/branching-basics/index.mdx @@ -5,12 +5,6 @@ description: Branches in Git serve as separate lines of development that allow m #### Free Resources -- [@official@Git Branching - Basic Branching and Merging](https://git-scm.com/book/en/v2/Git-Branching-Basic-Branching-and-Merging) -- [@article@Learn Git Branching](https://learngitbranching.js.org/) -- [@video@Git Branches Tutorial](https://www.youtube.com/watch?v=e2IbNHi4uCI) - -#### Free Resources - Official Docs diff --git a/contents/docs/3-git-branching/basics/checkout-branch/index.mdx b/contents/docs/3-git-branching/basics/checkout-branch/index.mdx index 975ec517..d72b3a30 100644 --- a/contents/docs/3-git-branching/basics/checkout-branch/index.mdx +++ b/contents/docs/3-git-branching/basics/checkout-branch/index.mdx @@ -7,12 +7,6 @@ In Git, to "checkout" from a branch means to switch your working directory to th #### Free Resources -- [@official@git-checkout](https://git-scm.com/docs/git-checkout) -- [@article@git-commands-checkout](https://www.git-tower.com/learn/git/commands/git-checkout) -- [@video@Git Checkout. Different ways of using the checkout command in the Git Project](https://youtu.be/h_PIHOFUYuw?si=tebKCCb5U3ues0Io) - -#### Free Resources - Official Docs diff --git a/contents/docs/3-git-branching/basics/cherry-picking-commits/index.mdx b/contents/docs/3-git-branching/basics/cherry-picking-commits/index.mdx index 6e993d33..e89ee05c 100644 --- a/contents/docs/3-git-branching/basics/cherry-picking-commits/index.mdx +++ b/contents/docs/3-git-branching/basics/cherry-picking-commits/index.mdx @@ -7,12 +7,6 @@ Cherry-picking in Git allows you to apply a specific commit from one branch to a #### Free Resources -- [@official@git-cherry-pick docs](https://git-scm.com/docs/git-cherry-pick) -- [@article@Git Cherry Pick](https://www.atlassian.com/git/tutorials/cherry-pick) -- [@video@Git Cherry Pick - Tutorial](https://youtu.be/i657Bg_HAWI?si=3jjn2X8Hi1na--F4) - -#### Free Resources - Official Docs diff --git a/contents/docs/3-git-branching/basics/clean-git-history/index.mdx b/contents/docs/3-git-branching/basics/clean-git-history/index.mdx index f7f81ab5..b6792727 100644 --- a/contents/docs/3-git-branching/basics/clean-git-history/index.mdx +++ b/contents/docs/3-git-branching/basics/clean-git-history/index.mdx @@ -12,11 +12,6 @@ Cleaning up Git history can make your commit history more readable, concise, and #### Free Resources -- [@article@Clean GIT history — a Step by Step Guide](https://medium.com/@catalinaturlea/clean-git-history-a-step-by-step-guide-eefc0ad8696d) -- [@video@Git Best Practice Tip: Clean Commit History](https://youtu.be/bZpiVijzd2g?si=8lJTlR3LfY9ZUd77) - -#### Free Resources - Official Docs diff --git a/contents/docs/3-git-branching/basics/code-reviews/index.mdx b/contents/docs/3-git-branching/basics/code-reviews/index.mdx index d87cd581..14a7226b 100644 --- a/contents/docs/3-git-branching/basics/code-reviews/index.mdx +++ b/contents/docs/3-git-branching/basics/code-reviews/index.mdx @@ -15,11 +15,6 @@ Some of the benefits of code reviews include: #### Free Resources -- [@article@A practical guide for better, faster code reviews](https://github.com/mawrkus/pull-request-review-guide) -- [@article@How to improve code with code reviews](https://github.com/resources/articles/software-development/how-to-improve-code-with-code-reviews) - -#### Free Resources - Official Docs diff --git a/contents/docs/3-git-branching/basics/collaborators/index.mdx b/contents/docs/3-git-branching/basics/collaborators/index.mdx index b1b07efd..c2569e2b 100644 --- a/contents/docs/3-git-branching/basics/collaborators/index.mdx +++ b/contents/docs/3-git-branching/basics/collaborators/index.mdx @@ -7,13 +7,6 @@ Collaborators in GitHub are users who have been granted direct access to a repos #### Free Resources -- [@official@How to add collaborators to your personal projects](https://docs.github.com/en/account-and-profile/setting-up-and-managing-your-personal-account-on-github/managing-access-to-your-personal-repositories/inviting-collaborators-to-a-personal-repository) -- [@official@Adding outside collaborators to repositories in your organization](https://docs.github.com/en/organizations/managing-user-access-to-your-organizations-repositories/managing-outside-collaborators/adding-outside-collaborators-to-repositories-in-your-organization) -- [@article@How to Add Collaborators to Your GitHub Repository](https://www.blinkops.com/blog/how-to-add-collaborators-to-your-github-repository) -- [@video@Using Github for Team collaboration](https://youtu.be/4nyIS58ORWw?si=yK5LCONNVm9OIUK5) - -#### Free Resources - Official Docs diff --git a/contents/docs/3-git-branching/basics/creating-branch/index.mdx b/contents/docs/3-git-branching/basics/creating-branch/index.mdx index d7b493e2..6a102fa8 100644 --- a/contents/docs/3-git-branching/basics/creating-branch/index.mdx +++ b/contents/docs/3-git-branching/basics/creating-branch/index.mdx @@ -7,11 +7,6 @@ Creating a branch in Git is a fundamental part of working with version control, #### Free Resources -- [@official@Git branch documentation](https://git-scm.com/docs/git-branch) -- [@article@Git branch](https://www.atlassian.com/git/tutorials/using-branches) - -#### Free Resources - Official Docs diff --git a/contents/docs/3-git-branching/basics/deleting-branch/index.mdx b/contents/docs/3-git-branching/basics/deleting-branch/index.mdx index e1909d43..ee7bab54 100644 --- a/contents/docs/3-git-branching/basics/deleting-branch/index.mdx +++ b/contents/docs/3-git-branching/basics/deleting-branch/index.mdx @@ -7,11 +7,6 @@ Deleting a Git branch means removing a line of development from your Git reposit #### Free Resources -- [@official@Creating and deleting branches within your repository](https://docs.github.com/articles/creating-and-deleting-branches-within-your-repository) -- [@article@How to Delete a Git Branch Both Locally and Remotely](https://www.freecodecamp.org/news/how-to-delete-a-git-branch-both-locally-and-remotely/) - -#### Free Resources - Official Docs diff --git a/contents/docs/3-git-branching/basics/detached-head/index.mdx b/contents/docs/3-git-branching/basics/detached-head/index.mdx index b2768c74..10371cba 100644 --- a/contents/docs/3-git-branching/basics/detached-head/index.mdx +++ b/contents/docs/3-git-branching/basics/detached-head/index.mdx @@ -7,11 +7,6 @@ In Git, a detached head occurs when you check out a commit directly using its ha #### Free Resources -- [@article@How to resolve detached HEAD state in Git](https://graphite.dev/guides/how-to-resolve-detached-head-state-in-git) -- [@video@Head & Detached Head](https://www.youtube.com/watch?v=HvDjbAa9ZsY) - -#### Free Resources - Official Docs diff --git a/contents/docs/3-git-branching/basics/fast-forward-vs-non-ff/index.mdx b/contents/docs/3-git-branching/basics/fast-forward-vs-non-ff/index.mdx index fe07d3c7..d2a9b217 100644 --- a/contents/docs/3-git-branching/basics/fast-forward-vs-non-ff/index.mdx +++ b/contents/docs/3-git-branching/basics/fast-forward-vs-non-ff/index.mdx @@ -14,14 +14,6 @@ A Non-Fast-Forward (No-FF) merge happens when the target branch has diverged fro #### Free Resources -- [@article@Git Fast-Forward VS Non-Fast-Forward](https://leimao.github.io/blog/Git-Fast-Forward-VS-Non-Fast-Forward/) -- [@article@Git Merge: To Squash Or Fast-Forward?](https://dev.to/trpricesoftware/git-merge-to-squash-or-fast-forward-3791) -- [@article@Difference between a git fast forward and no fast forward](https://gist.github.com/moraisaugusto/1fa02c49b6d9833fcdf665505595ac2e) -- [@video@GIT Fast Forward Visualized](https://youtu.be/DN1fNYoJgDw?si=_TZKACj4SCOuESGm) -- [@video@git merge no fast forward](https://youtu.be/X_8atqzsO8U?si=e9hMQg_aWLRMWf4O) - -#### Free Resources - Official Docs diff --git a/contents/docs/3-git-branching/basics/git-filter-branch/index.mdx b/contents/docs/3-git-branching/basics/git-filter-branch/index.mdx index f7ec93b1..2e6d5a04 100644 --- a/contents/docs/3-git-branching/basics/git-filter-branch/index.mdx +++ b/contents/docs/3-git-branching/basics/git-filter-branch/index.mdx @@ -15,12 +15,6 @@ Notably, there exists a simpler, safer, and more powerful alternative: `git filt #### Free Resources -- [@official@git filter-branch](https://git-scm.com/docs/git-filter-branch) -- [@official@git filter-repo](https://github.com/newren/git-filter-repo) -- [@article@Removing sensitive data from a repository](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/removing-sensitive-data-from-a-repository) - -#### Free Resources - Official Docs diff --git a/contents/docs/3-git-branching/basics/git-log-options/index.mdx b/contents/docs/3-git-branching/basics/git-log-options/index.mdx index 64d12e63..d518de30 100644 --- a/contents/docs/3-git-branching/basics/git-log-options/index.mdx +++ b/contents/docs/3-git-branching/basics/git-log-options/index.mdx @@ -22,11 +22,6 @@ For example, `git log -2 --graph` will display the last two commits in graph for #### Free Resources -- [@official@Git Log](https://git-scm.com/docs/git-log) -- [@article@Git Log Cheatsheet](https://elijahmanor.com/blog/git-log) - -#### Free Resources - Official Docs diff --git a/contents/docs/3-git-branching/basics/git-patch/index.mdx b/contents/docs/3-git-branching/basics/git-patch/index.mdx index 74f0ac82..ba159b84 100644 --- a/contents/docs/3-git-branching/basics/git-patch/index.mdx +++ b/contents/docs/3-git-branching/basics/git-patch/index.mdx @@ -7,11 +7,6 @@ In Git, a patch is a file that contains a set of changes made to a project's cod #### Free Resources -- [@article@Git Patch](https://www.gitkraken.com/learn/git/git-patch) -- [@article@How to generate and apply patches with git?](https://gist.github.com/nepsilon/22bc62a23f785716705c) - -#### Free Resources - Official Docs diff --git a/contents/docs/3-git-branching/basics/git-rebase/index.mdx b/contents/docs/3-git-branching/basics/git-rebase/index.mdx index a771f4be..36ba7714 100644 --- a/contents/docs/3-git-branching/basics/git-rebase/index.mdx +++ b/contents/docs/3-git-branching/basics/git-rebase/index.mdx @@ -7,13 +7,6 @@ Git rebase is a powerful command in Git that allows you to integrate changes fro #### Free Resources -- [@official@Git - git-rebase Documentation](https://git-scm.com/docs/git-rebase) -- [@article@git rebase](https://www.atlassian.com/git/tutorials/rewriting-history/git-rebase) -- [@video@git rebase - Why, When & How to fix conflicts](https://youtu.be/DkWDHzmMvyg?si=59jauQgkL-sMewzo) -- [@video@Git Rebase --interactive: EXPLAINED](https://youtu.be/H7RFt0Pxxp8?si=gLhfkVW_PmWHBQSs) - -#### Free Resources - Official Docs diff --git a/contents/docs/3-git-branching/basics/git-reflog/index.mdx b/contents/docs/3-git-branching/basics/git-reflog/index.mdx index c91ffc1a..3320ce2f 100644 --- a/contents/docs/3-git-branching/basics/git-reflog/index.mdx +++ b/contents/docs/3-git-branching/basics/git-reflog/index.mdx @@ -7,13 +7,6 @@ Git reflog is a powerful tool in Git that keeps a record of all the changes made #### Free Resources -- [@official@Git - git-reflog Documentation](https://git-scm.com/docs/git-reflog) -- [@article@What is the Git Reflog? | Learn Version Control with Git](https://www.git-tower.com/learn/git/faq/what-is-git-reflog) -- [@video@Learn Git Essentials 12: Git Reflog](https://youtu.be/RVu8lpS7JFY?si=eNGBpsYfHtlyPClj) -- [@video@Git Reflog Command. Get all log details of the reference using git reflog show command](https://youtu.be/I4f4pddD16g?si=0Ny7xOJgiPgdfuh6) - -#### Free Resources - Official Docs diff --git a/contents/docs/3-git-branching/basics/git-reset/index.mdx b/contents/docs/3-git-branching/basics/git-reset/index.mdx index 46d0aa1e..fb8f7767 100644 --- a/contents/docs/3-git-branching/basics/git-reset/index.mdx +++ b/contents/docs/3-git-branching/basics/git-reset/index.mdx @@ -7,11 +7,6 @@ Git reset is a command that allows you to "undo" or reset your current branch to #### Free Resources -- [@article@git reset](https://www.atlassian.com/git/tutorials/undoing-changes/git-reset) -- [@video@Git Reset | How to Use Git Reset | Learn Git](https://www.youtube.com/watch?v=s1idhUiCk38) - -#### Free Resources - Official Docs diff --git a/contents/docs/3-git-branching/basics/git-revert/index.mdx b/contents/docs/3-git-branching/basics/git-revert/index.mdx index 5bf5e8e6..b9df415d 100644 --- a/contents/docs/3-git-branching/basics/git-revert/index.mdx +++ b/contents/docs/3-git-branching/basics/git-revert/index.mdx @@ -13,11 +13,6 @@ Here are some key things to know about `git revert`: #### Free Resources -- [@article@Git Revert](https://medium.com/@meghasharmaa704/git-revert-84727b543c17) -- [@video@Git Revert - Visualised](https://www.youtube.com/watch?v=XJqQPNudPSY) - -#### Free Resources - Official Docs diff --git a/contents/docs/3-git-branching/basics/git-vs-other-vcs/index.mdx b/contents/docs/3-git-branching/basics/git-vs-other-vcs/index.mdx index 483ebcb9..fc2fac80 100644 --- a/contents/docs/3-git-branching/basics/git-vs-other-vcs/index.mdx +++ b/contents/docs/3-git-branching/basics/git-vs-other-vcs/index.mdx @@ -12,10 +12,6 @@ Git has become the de facto standard for source control in software development, #### Free Resources -- [@article@Git vs. Other VCS: A Comparative Analysis](https://medium.com/@pascalchinedu2000/git-vs-other-vcs-a-comparative-analysis-5cb03ad58e0e) - -#### Free Resources - Official Docs diff --git a/contents/docs/3-git-branching/basics/git-worktree/index.mdx b/contents/docs/3-git-branching/basics/git-worktree/index.mdx index f4cb95de..a25a6c24 100644 --- a/contents/docs/3-git-branching/basics/git-worktree/index.mdx +++ b/contents/docs/3-git-branching/basics/git-worktree/index.mdx @@ -7,11 +7,6 @@ A Git worktree allows you to create multiple working directories for a single re #### Free Resources -- [@article@Git Worktree](https://www.gitkraken.com/learn/git/git-worktree) -- [@video@Manage Branches easily using Git Worktree](https://www.youtube.com/watch?v=cRunWRC8ye0) - -#### Free Resources - Official Docs diff --git a/contents/docs/3-git-branching/basics/github-essentials/index.mdx b/contents/docs/3-git-branching/basics/github-essentials/index.mdx index 1bf469ed..1d9547a3 100644 --- a/contents/docs/3-git-branching/basics/github-essentials/index.mdx +++ b/contents/docs/3-git-branching/basics/github-essentials/index.mdx @@ -7,11 +7,6 @@ GitHub Essentials refers to the core features and functionalities that form the #### Free Resources -- [@official@Github Essentials - Microsoft](https://learn.microsoft.com/en-us/contribute/content/git-github-fundamentals) -- [@official@Hello World](https://docs.github.com/en/get-started/start-your-journey/hello-world) - -#### Free Resources - Official Docs diff --git a/contents/docs/3-git-branching/basics/head/index.mdx b/contents/docs/3-git-branching/basics/head/index.mdx index 929dfa63..6b17c39d 100644 --- a/contents/docs/3-git-branching/basics/head/index.mdx +++ b/contents/docs/3-git-branching/basics/head/index.mdx @@ -7,11 +7,6 @@ The `HEAD` file is at the core of how Git knows the SHA-1 of the last commit whe #### Free Resources -- [@official@Git Internals - Git References - The HEAD](https://git-scm.com/book/en/v2/Git-Internals-Git-References#:~:text=want%20to%20create.-,The%20HEAD,-The%20question%20now) -- [@video@Learn Git Essentials: Head & Detached Head](https://www.youtube.com/watch?v=HvDjbAa9ZsY) - -#### Free Resources - Official Docs diff --git a/contents/docs/3-git-branching/basics/linear-vs-non-linear/index.mdx b/contents/docs/3-git-branching/basics/linear-vs-non-linear/index.mdx index 0d867355..bd266e51 100644 --- a/contents/docs/3-git-branching/basics/linear-vs-non-linear/index.mdx +++ b/contents/docs/3-git-branching/basics/linear-vs-non-linear/index.mdx @@ -12,11 +12,6 @@ In Git, linear and non-linear history refer to different ways of managing commit #### Free Resources -- [@article@Linear vs Non-Linear History](https://idiv-biodiversity.github.io/git-knowledge-base/linear-vs-nonlinear.html) -- [@article@Linear git history - Part I](https://jun-sheng.medium.com/linear-git-history-part-i-b97184dde252#:~:text=The%20benefit%20of%20having%20a%20linear%20git%20history&text=It%20is%20easier%20to%20understand,bisect%20to%20track%20a%20bug.) - -#### Free Resources - Official Docs diff --git a/contents/docs/3-git-branching/basics/merging-basics/index.mdx b/contents/docs/3-git-branching/basics/merging-basics/index.mdx index 4057f862..cb2c069b 100644 --- a/contents/docs/3-git-branching/basics/merging-basics/index.mdx +++ b/contents/docs/3-git-branching/basics/merging-basics/index.mdx @@ -7,11 +7,6 @@ A merge in Git is the process of combining changes from one branch into another. #### Free Resources -- [@official@Git Branching - Basic Merging](https://git-scm.com/book/en/v2/Git-Branching-Basic-Branching-and-Merging#:~:text=into%20master%20later.-,Basic%20Merging,-Suppose%20you%E2%80%99ve%20decided) -- [@article@Git merge](https://www.atlassian.com/git/tutorials/using-branches/git-merge) - -#### Free Resources - Official Docs diff --git a/contents/docs/3-git-branching/basics/post-checkout/index.mdx b/contents/docs/3-git-branching/basics/post-checkout/index.mdx index 434c2e34..f8e79f1a 100644 --- a/contents/docs/3-git-branching/basics/post-checkout/index.mdx +++ b/contents/docs/3-git-branching/basics/post-checkout/index.mdx @@ -9,10 +9,6 @@ Git post-checkout hooks are scripts that run automatically after a successful `g #### Free Resources -- [@official@Post-checkout hooks](https://git-scm.com/docs/githooks#_post_checkout) - -#### Free Resources - Official Docs diff --git a/contents/docs/3-git-branching/basics/rebase/index.mdx b/contents/docs/3-git-branching/basics/rebase/index.mdx index 2ee4f26d..aa0289ed 100644 --- a/contents/docs/3-git-branching/basics/rebase/index.mdx +++ b/contents/docs/3-git-branching/basics/rebase/index.mdx @@ -7,10 +7,6 @@ Rebasing in Git is a powerful and potentially complex feature used to reorganize #### Free Resources -- [@official@Rebasing](https://git-scm.com/book/en/v2/Git-Branching-Rebasing) - -#### Free Resources - Official Docs diff --git a/contents/docs/3-git-branching/basics/renaming-branch/index.mdx b/contents/docs/3-git-branching/basics/renaming-branch/index.mdx index a97df328..828528b7 100644 --- a/contents/docs/3-git-branching/basics/renaming-branch/index.mdx +++ b/contents/docs/3-git-branching/basics/renaming-branch/index.mdx @@ -7,11 +7,6 @@ Renaming a branch in Git means changing the name of a branch to something differ #### Free Resources -- [@official@Renaming a Branch - GitHub Docs](https://docs.github.com/github/administering-a-repository/renaming-a-branch) -- [@article@Git Rename Branch – How to Change a Local Branch Name](https://www.freecodecamp.org/news/git-rename-branch-how-to-change-a-local-branch-name/) - -#### Free Resources - Official Docs diff --git a/contents/docs/3-git-branching/basics/rewriting-history/index.mdx b/contents/docs/3-git-branching/basics/rewriting-history/index.mdx index 20acdc3d..0d3c0a07 100644 --- a/contents/docs/3-git-branching/basics/rewriting-history/index.mdx +++ b/contents/docs/3-git-branching/basics/rewriting-history/index.mdx @@ -18,11 +18,6 @@ Rewriting history in Git is typically necessary when: #### Free Resources -- [@official@Git Tools - Rewriting History](https://git-scm.com/book/en/v2/Git-Tools-Rewriting-History) -- [@article@Methods of Rewriting History in Git](https://www.atlassian.com/git/tutorials/rewriting-history) - -#### Free Resources - Official Docs diff --git a/contents/docs/3-git-branching/basics/squash/index.mdx b/contents/docs/3-git-branching/basics/squash/index.mdx index 6f1f1403..f8073e9e 100644 --- a/contents/docs/3-git-branching/basics/squash/index.mdx +++ b/contents/docs/3-git-branching/basics/squash/index.mdx @@ -7,12 +7,6 @@ Squashing in Git, refers to the process of combining multiple commits into a sin #### Free Resources -- [@article@Git Squash Commits](https://www.freecodecamp.org/news/git-squash-commits/) -- [@article@How to Squash Commits in Git](https://medium.com/iosnesia/how-to-squash-commits-in-git-e73a41248211) -- [@video@GIT Tutorial - How to Squash Commits](https://youtu.be/viY1BbKZhSI?si=kORsEzQvCRFGauQa) - -#### Free Resources - Official Docs diff --git a/contents/docs/3-git-branching/basics/undoing-changes/index.mdx b/contents/docs/3-git-branching/basics/undoing-changes/index.mdx index 70c1b5ef..fb51999b 100644 --- a/contents/docs/3-git-branching/basics/undoing-changes/index.mdx +++ b/contents/docs/3-git-branching/basics/undoing-changes/index.mdx @@ -10,12 +10,6 @@ If mistakes or unwanted changes have been committed to your Git repository, ther #### Free Resources -- [@official@Undoing Changes](https://git-scm.com/book/en/v2/Git-Tools-Reset-Demystified) -- [@article@Undo Anything in Git](https://github.blog/open-source/git/how-to-undo-almost-anything-with-git/) -- [@article@Undoing Changes in Git](https://www.atlassian.com/git/tutorials/undoing-changes) - -#### Free Resources - Official Docs diff --git a/contents/docs/3-git-branching/merging/merge-strategies/index.mdx b/contents/docs/3-git-branching/merging/merge-strategies/index.mdx index 06883f79..243e1ffe 100644 --- a/contents/docs/3-git-branching/merging/merge-strategies/index.mdx +++ b/contents/docs/3-git-branching/merging/merge-strategies/index.mdx @@ -13,11 +13,6 @@ When combining changes from one branch into another, Git provides various merge #### Free Resources -- [@official@Git Merge Strategies](https://git-scm.com/docs/merge-strategies) -- [@article@Git Merge Options](https://www.atlassian.com/git/tutorials/using-branches/merge-strategy) - -#### Free Resources - Official Docs diff --git a/contents/docs/3-git-branching/remote/git-push---force/index.mdx b/contents/docs/3-git-branching/remote/git-push---force/index.mdx index c7c2504c..430cf460 100644 --- a/contents/docs/3-git-branching/remote/git-push---force/index.mdx +++ b/contents/docs/3-git-branching/remote/git-push---force/index.mdx @@ -9,11 +9,6 @@ description: Learn about Git Push Force in Git #### Free Resources -- [@article@Git Push Force](https://www.gitkraken.com/learn/git/problems/git-push-force) -- [@video@How to force push to GitHub?](https://www.youtube.com/watch?v=wgXbfLn-zkI) - -#### Free Resources - Official Docs diff --git a/contents/docs/3-git-branching/remote/pull-requests/index.mdx b/contents/docs/3-git-branching/remote/pull-requests/index.mdx index 8b15c987..ebd092f5 100644 --- a/contents/docs/3-git-branching/remote/pull-requests/index.mdx +++ b/contents/docs/3-git-branching/remote/pull-requests/index.mdx @@ -12,11 +12,6 @@ You can use GitHub CLI to manage pull requests with the following commands: #### Free Resources -- [@official@gh pr](https://cli.github.com/manual/gh_pr) -- [@video@Use GitHub CLI For Command Line Pull Request Management](https://www.youtube.com/watch?v=Ku9_0Mftiic) - -#### Free Resources - Official Docs diff --git a/contents/docs/3-git-branching/remote/pushing--pulling-changes/index.mdx b/contents/docs/3-git-branching/remote/pushing--pulling-changes/index.mdx index d17932d6..e947f578 100644 --- a/contents/docs/3-git-branching/remote/pushing--pulling-changes/index.mdx +++ b/contents/docs/3-git-branching/remote/pushing--pulling-changes/index.mdx @@ -9,12 +9,6 @@ When you pull changes in Git, you're fetching and integrating changes from a rem #### Free Resources -- [@official@Pushing commits to a remote repository](https://docs.github.com/en/get-started/using-git/pushing-commits-to-a-remote-repository) -- [@article@A Comprehensive Guide to git pull and git push](https://dev.to/alexmercedcoder/mastering-git-a-comprehensive-guide-to-git-pull-and-git-push-2eo3) -- [@article@Git Push and Pull Tutorial](https://www.datacamp.com/tutorial/git-push-pull) - -#### Free Resources - Official Docs diff --git a/contents/docs/4-git-advanced/tools/--hard/index.mdx b/contents/docs/4-git-advanced/tools/--hard/index.mdx index e512b1c9..3f090dc9 100644 --- a/contents/docs/4-git-advanced/tools/--hard/index.mdx +++ b/contents/docs/4-git-advanced/tools/--hard/index.mdx @@ -9,10 +9,6 @@ With this option, both the HEAD pointer and the working directory's contents are #### Free Resources -- [@official@--hard documentation](https://git-scm.com/docs/git-reset#Documentation/git-reset.txt---hard) - -#### Free Resources - Official Docs diff --git a/contents/docs/4-git-advanced/tools/--mixed/index.mdx b/contents/docs/4-git-advanced/tools/--mixed/index.mdx index f4d50493..75e11b42 100644 --- a/contents/docs/4-git-advanced/tools/--mixed/index.mdx +++ b/contents/docs/4-git-advanced/tools/--mixed/index.mdx @@ -9,10 +9,6 @@ When using mixed mode, the HEAD pointer is moved to the specified commit. Howeve #### Free Resources -- [@official@--mixed documentation](https://git-scm.com/docs/git-reset#Documentation/git-reset.txt---mixed) - -#### Free Resources - Official Docs diff --git a/contents/docs/4-git-advanced/tools/basic-git-usage/index.mdx b/contents/docs/4-git-advanced/tools/basic-git-usage/index.mdx index 30632676..b742c6de 100644 --- a/contents/docs/4-git-advanced/tools/basic-git-usage/index.mdx +++ b/contents/docs/4-git-advanced/tools/basic-git-usage/index.mdx @@ -7,17 +7,6 @@ Starting with a new project, you'll use `git init` to initialize a repository an #### Free Resources -- [@video@Git Tutorial for Beginners: Learn Git in 1 Hour](https://www.youtube.com/watch?v=8JJ101D3knE&t=1135s) -- [@article@Git ignore](https://www.atlassian.com/git/tutorials/saving-changes/gitignore) -- [@article@Git remote](https://www.atlassian.com/git/tutorials/syncing) -- [@article@Git Cheat Sheet](https://education.github.com/git-cheat-sheet-education.pdf) -- [@official@Git Branching - Basic Branching and Merging](https://git-scm.com/book/en/v2/Git-Branching-Basic-Branching-and-Merging) -- [@official@Creating a new repository](https://docs.github.com/en/repositories/creating-and-managing-repositories/creating-a-new-repository) -- [@official@Setting repository visibility](https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/managing-repository-settings/setting-repository-visibility) -- [@official@Pushing commits to a remote repository](https://docs.github.com/en/get-started/using-git/pushing-commits-to-a-remote-repository) - -#### Free Resources - Official Docs diff --git a/contents/docs/4-git-advanced/tools/fetch-without-merge/index.mdx b/contents/docs/4-git-advanced/tools/fetch-without-merge/index.mdx index 4a9b04e2..f30e9080 100644 --- a/contents/docs/4-git-advanced/tools/fetch-without-merge/index.mdx +++ b/contents/docs/4-git-advanced/tools/fetch-without-merge/index.mdx @@ -7,12 +7,6 @@ Running `git fetch` retrieves changes from a remote repository into your local c #### Free Resources -- [@official@Git Fetch](https://git-scm.com/docs/git-fetch) -- [@article@Git fetch](https://www.atlassian.com/git/tutorials/syncing/git-fetch) -- [@video@Git Fetch | What is Git Fetch and How to Use it | Learn Git](https://www.youtube.com/watch?v=uEEcw1s_wWk) - -#### Free Resources - Official Docs diff --git a/contents/docs/4-git-advanced/tools/git-bisect/index.mdx b/contents/docs/4-git-advanced/tools/git-bisect/index.mdx index 4d599bb2..e9ee3889 100644 --- a/contents/docs/4-git-advanced/tools/git-bisect/index.mdx +++ b/contents/docs/4-git-advanced/tools/git-bisect/index.mdx @@ -7,12 +7,6 @@ Git Bisect is an interactive tool used to identify which commit in your project' #### Free Resources -- [@official@Git Bisect](https://git-scm.com/docs/git-bisect) -- [@article@Using `git bisect` to find the faulty commit](https://dev.to/alvesjessica/using-git-bisect-to-find-the-faulty-commit-25gf) -- [@video@Git Bisect | How to use Git Bisect | Learn Git](https://www.youtube.com/watch?v=z-AkSXDqodc) - -#### Free Resources - Official Docs diff --git a/contents/docs/5-github/actions/github-actions/index.mdx b/contents/docs/5-github/actions/github-actions/index.mdx index 31046854..4cc035ff 100644 --- a/contents/docs/5-github/actions/github-actions/index.mdx +++ b/contents/docs/5-github/actions/github-actions/index.mdx @@ -9,13 +9,6 @@ One of the best ways to learn about GitHub Actions is through the course offered #### Free Resources -- [@official@Github Actions](https://docs.github.com/en/actions) -- [@course@Microsoft Learn: Introduction to GitHub Actions](https://learn.microsoft.com/en-us/collections/n5p4a5z7keznp5) -- [@course@YouTube: GitHub Actions Playlist](https://www.youtube.com/watch?v=-hVG9z0fCac&list=PLArH6NjfKsUhvGHrpag7SuPumMzQRhUKY&pp=iAQB) -- [@video@What are Github Actions](https://www.youtube.com/watch?v=URmeTqglS58) - -#### Free Resources - Official Docs diff --git a/contents/docs/5-github/actions/marketplace-actions/index.mdx b/contents/docs/5-github/actions/marketplace-actions/index.mdx index fa9a919b..f1b8d239 100644 --- a/contents/docs/5-github/actions/marketplace-actions/index.mdx +++ b/contents/docs/5-github/actions/marketplace-actions/index.mdx @@ -13,10 +13,6 @@ These actions are created by the GitHub community and can be easily added to you #### Free Resources -- [@official@GitHub MarketPlace - Actions](https://github.com/marketplace?type=actions) - -#### Free Resources - Official Docs diff --git a/contents/docs/5-github/actions/reactions/index.mdx b/contents/docs/5-github/actions/reactions/index.mdx index 2c2c769a..5e7ad175 100644 --- a/contents/docs/5-github/actions/reactions/index.mdx +++ b/contents/docs/5-github/actions/reactions/index.mdx @@ -7,10 +7,6 @@ Reactions in GitHub are a way for users to express their feelings or opinions ab #### Free Resources -- [@official@Add Reactions to Pull Requests, Issues, and Comments](https://github.blog/news-insights/product-news/add-reactions-to-pull-requests-issues-and-comments/) - -#### Free Resources - Official Docs diff --git a/contents/docs/5-github/basics/automations/index.mdx b/contents/docs/5-github/basics/automations/index.mdx index 0640468d..47938c21 100644 --- a/contents/docs/5-github/basics/automations/index.mdx +++ b/contents/docs/5-github/basics/automations/index.mdx @@ -7,11 +7,6 @@ To add automation to your GitHub project, use built-in workflows that can trigge #### Free Resources -- [@official@Automating your project](https://docs.github.com/en/issues/planning-and-tracking-with-projects/automating-your-project) -- [@video@GitHub Project Management - Create GitHub Project Board & Automations](https://www.youtube.com/watch?v=oPQgFxHcjAw&t=600s) - -#### Free Resources - Official Docs diff --git a/contents/docs/5-github/basics/caching-dependencies/index.mdx b/contents/docs/5-github/basics/caching-dependencies/index.mdx index 51a3fbf1..fae1c001 100644 --- a/contents/docs/5-github/basics/caching-dependencies/index.mdx +++ b/contents/docs/5-github/basics/caching-dependencies/index.mdx @@ -13,11 +13,6 @@ It is highly recommended to not store any sensitive information in the cache. Fo #### Free Resources -- [@official@Caching dependencies to speed up workflows](https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/caching-dependencies-to-speed-up-workflows) -- [@video@Cache Management with GitHub actions](https://www.youtube.com/watch?v=7PVUjRXUY0o) - -#### Free Resources - Official Docs diff --git a/contents/docs/5-github/basics/cloning-repositories/index.mdx b/contents/docs/5-github/basics/cloning-repositories/index.mdx index 39459b72..c56f032c 100644 --- a/contents/docs/5-github/basics/cloning-repositories/index.mdx +++ b/contents/docs/5-github/basics/cloning-repositories/index.mdx @@ -7,13 +7,6 @@ Cloning a repository in Git and GitHub involves creating a local copy of a remot #### Free Resources -- [@official@git clone](https://git-scm.com/docs/git-clone) -- [@official@Cloning a Repository](https://docs.github.com/en/repositories/creating-and-managing-repositories/cloning-a-repository) -- [@article@Clone a Git Repository](https://www.atlassian.com/git/tutorials/setting-up-a-repository/git-clone) -- [@video@Cloning Remote Repository into local machine](https://youtu.be/xeQih8LVtZM?si=djlyTDpLNS0oyqQH) - -#### Free Resources - Official Docs diff --git a/contents/docs/5-github/basics/collaboration-on-github/index.mdx b/contents/docs/5-github/basics/collaboration-on-github/index.mdx index 2ed7e539..0246904f 100644 --- a/contents/docs/5-github/basics/collaboration-on-github/index.mdx +++ b/contents/docs/5-github/basics/collaboration-on-github/index.mdx @@ -7,12 +7,6 @@ Collaboration on GitHub is a powerful way for multiple people to work together o #### Free Resources -- [@official@How to collaborate in a GitHub project](https://gist.github.com/neklaf/9002d3acccf6b6e448db5c4c4e8764c0) -- [@article@Best Practices for collaborating in github](https://www.gitkraken.com/blog/collaborate-on-github) -- [@article@Working with GitHub in VS Code](https://code.visualstudio.com/docs/sourcecontrol/github) - -#### Free Resources - Official Docs diff --git a/contents/docs/5-github/basics/collaborators--members/index.mdx b/contents/docs/5-github/basics/collaborators--members/index.mdx index 82cd4e87..3b74ddc4 100644 --- a/contents/docs/5-github/basics/collaborators--members/index.mdx +++ b/contents/docs/5-github/basics/collaborators--members/index.mdx @@ -9,11 +9,6 @@ In GitHub, collaborators and members refer to individuals who contribute to or h #### Free Resources -- [@article@Inviting collaborators to a personal repository](https://docs.github.com/en/account-and-profile/setting-up-and-managing-your-personal-account-on-github/managing-access-to-your-personal-repositories/inviting-collaborators-to-a-personal-repository) -- [@official@REST API endpoints for collaborators](https://docs.github.com/en/rest/collaborators/collaborators?apiVersion=2022-11-28) - -#### Free Resources - Official Docs diff --git a/contents/docs/5-github/basics/contribution-guidelines/index.mdx b/contents/docs/5-github/basics/contribution-guidelines/index.mdx index a23840d5..29768ed6 100644 --- a/contents/docs/5-github/basics/contribution-guidelines/index.mdx +++ b/contents/docs/5-github/basics/contribution-guidelines/index.mdx @@ -7,13 +7,6 @@ Contribution guidelines are essential for collaborative projects on GitHub as th #### Free Resources -- [@official@Setting Guidelines for Repository Contributors](https://docs.github.com/articles/setting-guidelines-for-repository-contributors) -- [@official@Contributing Guidelines](https://github.blog/news-insights/contributing-guidelines/) -- [@official@Contributing Guides: A Template](https://github.com/nayafia/contributing-template) -- [@article@How to Build a CONTRIBUTING.md](https://mozillascience.github.io/working-open-workshop/contributing/) - -#### Free Resources - Official Docs diff --git a/contents/docs/5-github/basics/creating-apps/index.mdx b/contents/docs/5-github/basics/creating-apps/index.mdx index 3dd33093..4e902437 100644 --- a/contents/docs/5-github/basics/creating-apps/index.mdx +++ b/contents/docs/5-github/basics/creating-apps/index.mdx @@ -7,10 +7,6 @@ GitHub Apps are a way to integrate with the GitHub platform programmatically, us #### Free Resources -- [@official@Creating GitHub Apps](https://docs.github.com/en/apps/creating-github-apps) - -#### Free Resources - Official Docs diff --git a/contents/docs/5-github/basics/creating-repositories/index.mdx b/contents/docs/5-github/basics/creating-repositories/index.mdx index 3ef13584..6468bf4b 100644 --- a/contents/docs/5-github/basics/creating-repositories/index.mdx +++ b/contents/docs/5-github/basics/creating-repositories/index.mdx @@ -7,10 +7,6 @@ Creating a Git repository means setting up a system to track changes in your pro #### Free Resources -- [@official@Quickstart for repositories - GitHub Docs](https://docs.github.com/en/repositories/creating-and-managing-repositories/quickstart-for-repositories) - -#### Free Resources - Official Docs diff --git a/contents/docs/5-github/basics/custom-domains/index.mdx b/contents/docs/5-github/basics/custom-domains/index.mdx index 15c68f5b..f0dd202c 100644 --- a/contents/docs/5-github/basics/custom-domains/index.mdx +++ b/contents/docs/5-github/basics/custom-domains/index.mdx @@ -7,11 +7,6 @@ On GitHub Pages, users can customize their site's URL by connecting a custom dom #### Free Resources -- [@official@Configuring a Custom Domain for Your GitHub Pages Site](https://docs.github.com/en/pages/configuring-a-custom-domain-for-your-github-pages-site) -- [@video@How to Host a Website on GitHub Pages Free (Custom Domain Setup Included)](https://www.youtube.com/watch?v=e5AwNU3Y2es&t=156s) - -#### Free Resources - Official Docs diff --git a/contents/docs/5-github/basics/deploying-static-websites/index.mdx b/contents/docs/5-github/basics/deploying-static-websites/index.mdx index 18b1e740..b8293072 100644 --- a/contents/docs/5-github/basics/deploying-static-websites/index.mdx +++ b/contents/docs/5-github/basics/deploying-static-websites/index.mdx @@ -7,11 +7,6 @@ Deploying static websites on GitHub Pages involves uploading and serving website #### Free Resources -- [@article@How to Deploy a Static Website for Free Using Github Pages](https://medium.com/flycode/how-to-deploy-a-static-website-for-free-using-github-pages-8eddc194853b) -- [@video@How to Host a Website on GitHub Pages Free (Custom Domain Setup Included)](https://www.youtube.com/watch?v=e5AwNU3Y2es) - -#### Free Resources - Official Docs diff --git a/contents/docs/5-github/basics/documentation/index.mdx b/contents/docs/5-github/basics/documentation/index.mdx index cbdab244..07b05c21 100644 --- a/contents/docs/5-github/basics/documentation/index.mdx +++ b/contents/docs/5-github/basics/documentation/index.mdx @@ -16,10 +16,6 @@ These documents help ensure a smooth onboarding process for contributors, making #### Free Resources -- [@article@How to Manage Documentation in a GitHub Repository: A Guide for Junior Developers](https://dev.to/mochafreddo/how-to-manage-documentation-in-a-github-repository-a-guide-for-junior-developers-pgo) - -#### Free Resources - Official Docs diff --git a/contents/docs/5-github/basics/forking-vs-cloning/index.mdx b/contents/docs/5-github/basics/forking-vs-cloning/index.mdx index 3a5877d6..2e0f1876 100644 --- a/contents/docs/5-github/basics/forking-vs-cloning/index.mdx +++ b/contents/docs/5-github/basics/forking-vs-cloning/index.mdx @@ -9,13 +9,6 @@ Forking a repository is specific to platforms like GitHub, GitLab, and Bitbucket #### Free Resources -- [@official@The difference between forking and cloning a repository](https://github.com/orgs/community/discussions/35849) -- [@article@Git fork vs. clone: What's the difference?](https://www.theserverside.com/answer/Git-fork-vs-clone-Whats-the-difference) -- [@video@Git Fork vs. Git Clone: What's the Difference?](https://youtu.be/6YQxkxw8nhE?si=mJNvcaB4lQccsU57) -- [@video@GitHub Forking vs Cloning: Key Differences Explained](https://youtu.be/yQSjqYs2UBE?si=3BKYtWmkLIMWvA6G) - -#### Free Resources - Official Docs diff --git a/contents/docs/5-github/basics/github-api/index.mdx b/contents/docs/5-github/basics/github-api/index.mdx index f4bbca43..016e5c76 100644 --- a/contents/docs/5-github/basics/github-api/index.mdx +++ b/contents/docs/5-github/basics/github-api/index.mdx @@ -7,11 +7,6 @@ The GitHub API is a powerful tool that allows developers to interact with the Gi #### Free Resources -- [@official@Github API Docs](https://docs.github.com/en/rest?apiVersion=2022-11-28) -- [@article@Getting Started](https://docs.github.com/en/rest/using-the-rest-api/getting-started-with-the-rest-api?apiVersion=2022-11-28) - -#### Free Resources - Official Docs diff --git a/contents/docs/5-github/basics/github-apps/index.mdx b/contents/docs/5-github/basics/github-apps/index.mdx index d08bf026..234b3d97 100644 --- a/contents/docs/5-github/basics/github-apps/index.mdx +++ b/contents/docs/5-github/basics/github-apps/index.mdx @@ -7,10 +7,6 @@ A GitHub App is a way to integrate with the GitHub platform programmatically, us #### Free Resources -- [@official@GitHub Apps Documentation](https://docs.github.com/en/apps) - -#### Free Resources - Official Docs diff --git a/contents/docs/5-github/basics/github-classroom/index.mdx b/contents/docs/5-github/basics/github-classroom/index.mdx index b5e2737d..3f9ef83e 100644 --- a/contents/docs/5-github/basics/github-classroom/index.mdx +++ b/contents/docs/5-github/basics/github-classroom/index.mdx @@ -7,11 +7,6 @@ GitHub Classroom is an integrated feature within GitHub that allows educators to #### Free Resources -- [@official@About GitHub Classroom](https://docs.github.com/en/education/manage-coursework-with-github-classroom/get-started-with-github-classroom/about-github-classroom) -- [@video@GitHub Classroom - Getting Started Guide](https://www.youtube.com/watch?v=xVVeqIDgCvM&list=PLIRjfNq867bewk3ZGV6Z7a16YDNRCpK3u) - -#### Free Resources - Official Docs diff --git a/contents/docs/5-github/basics/github-cli/index.mdx b/contents/docs/5-github/basics/github-cli/index.mdx index 38e812ba..8316983c 100644 --- a/contents/docs/5-github/basics/github-cli/index.mdx +++ b/contents/docs/5-github/basics/github-cli/index.mdx @@ -7,11 +7,6 @@ GitHub CLI is a command-line interface tool that brings GitHub functionality to #### Free Resources -- [@official@GitHub CLI Docs](https://cli.github.com/) -- [@video@What is the GitHub CLI?](https://www.youtube.com/watch?v=uy_PEGgUF4U) - -#### Free Resources - Official Docs diff --git a/contents/docs/5-github/basics/github-codespaces/index.mdx b/contents/docs/5-github/basics/github-codespaces/index.mdx index 9a964dd0..854c51db 100644 --- a/contents/docs/5-github/basics/github-codespaces/index.mdx +++ b/contents/docs/5-github/basics/github-codespaces/index.mdx @@ -7,11 +7,6 @@ GitHub Codespaces is a cloud-based development environment that allows developer #### Free Resources -- [@official@GitHub Codespaces Overview](https://docs.github.com/en/codespaces/overview) -- [@video@How to Deploy a GitHub Codespace](https://www.youtube.com/watch?v=_01iCF9sO1c) - -#### Free Resources - Official Docs diff --git a/contents/docs/5-github/basics/github-copilot/index.mdx b/contents/docs/5-github/basics/github-copilot/index.mdx index ce1fb21b..a0a1b4dc 100644 --- a/contents/docs/5-github/basics/github-copilot/index.mdx +++ b/contents/docs/5-github/basics/github-copilot/index.mdx @@ -7,12 +7,6 @@ GitHub Copilot is an AI-powered code-completion tool that helps developers write #### Free Resources -- [@official@Quickstart for GitHub Copilot](https://docs.github.com/en/copilot/quickstart) -- [@video@Intro to GitHob Copilot in Visual Studio](https://www.youtube.com/watch?v=z1ycDvspv8U) -- [@video@GitHub Copilot in VSCode: Top 10 Features Explained](https://www.youtube.com/watch?v=2nPoiUJpDaU) - -#### Free Resources - Official Docs diff --git a/contents/docs/5-github/basics/github-discussions/index.mdx b/contents/docs/5-github/basics/github-discussions/index.mdx index 42621bbb..e341e2ee 100644 --- a/contents/docs/5-github/basics/github-discussions/index.mdx +++ b/contents/docs/5-github/basics/github-discussions/index.mdx @@ -7,11 +7,6 @@ GitHub Discussions is a collaborative communication feature within GitHub reposi #### Free Resources -- [@official@GitHub Discussions Docs](https://docs.github.com/en/discussions) -- [@video@What is GitHub Discussions?](https://www.youtube.com/watch?v=bErGYN3Ljz8) - -#### Free Resources - Official Docs diff --git a/contents/docs/5-github/basics/github-education/index.mdx b/contents/docs/5-github/basics/github-education/index.mdx index 4885e8f7..ad1670dd 100644 --- a/contents/docs/5-github/basics/github-education/index.mdx +++ b/contents/docs/5-github/basics/github-education/index.mdx @@ -7,11 +7,6 @@ GitHub Education is a program that provides free and discounted access to GitHub #### Free Resources -- [@official@official GitHub Education Docs](https://education.github.com/) -- [@video@GitHub GitHub Education: free programs, technology, and opportunities available for Students](https://www.youtube.com/watch?v=HIVFdN9VGgw) - -#### Free Resources - Official Docs diff --git a/contents/docs/5-github/basics/github-gists/index.mdx b/contents/docs/5-github/basics/github-gists/index.mdx index 6e780edf..3b9d2069 100644 --- a/contents/docs/5-github/basics/github-gists/index.mdx +++ b/contents/docs/5-github/basics/github-gists/index.mdx @@ -7,11 +7,6 @@ A GitHub Gist is a small code or text snippet that can be shared with others. It #### Free Resources -- [@official@Creating Gists](https://docs.github.com/en/get-started/writing-on-github/editing-and-sharing-content-with-gists/creating-gists) -- [@official@REST API endpoints for Gists](https://docs.github.com/en/rest/gists/gists?apiVersion=2022-11-28) - -#### Free Resources - Official Docs diff --git a/contents/docs/5-github/basics/github-interface/index.mdx b/contents/docs/5-github/basics/github-interface/index.mdx index 3db2fcd3..8ba0c969 100644 --- a/contents/docs/5-github/basics/github-interface/index.mdx +++ b/contents/docs/5-github/basics/github-interface/index.mdx @@ -7,11 +7,6 @@ The GitHub interface is a web-based platform that provides a user-friendly envir #### Free Resources -- [@official@GitHub Desktop App](https://github.com/apps/desktop) -- [@article@Getting Started with GitHub](https://digital.gov/resources/an-introduction-github/) - -#### Free Resources - Official Docs diff --git a/contents/docs/5-github/basics/github-marketplace/index.mdx b/contents/docs/5-github/basics/github-marketplace/index.mdx index 6089d882..4a4e3bd7 100644 --- a/contents/docs/5-github/basics/github-marketplace/index.mdx +++ b/contents/docs/5-github/basics/github-marketplace/index.mdx @@ -7,11 +7,6 @@ GitHub Marketplace is a platform that allows developers to discover, install, an #### Free Resources -- [@official@GitHub Marketplace](https://github.com/marketplace) -- [@official@About GitHub Marketplace for apps](https://docs.github.com/en/apps/github-marketplace/github-marketplace-overview/about-github-marketplace-for-apps) - -#### Free Resources - Official Docs diff --git a/contents/docs/5-github/basics/github-models/index.mdx b/contents/docs/5-github/basics/github-models/index.mdx index 2e1c4094..ade1300b 100644 --- a/contents/docs/5-github/basics/github-models/index.mdx +++ b/contents/docs/5-github/basics/github-models/index.mdx @@ -7,11 +7,6 @@ GitHub Models is a feature that allows developers to search, explore, and use pr #### Free Resources -- [@official@Prototyping with AI models](https://docs.github.com/en/github-models/prototyping-with-ai-models) -- [@video@GitHub Models DEMO | AI models for developers on GitHub](https://www.youtube.com/watch?v=WiBB8Lsgl7I) - -#### Free Resources - Official Docs diff --git a/contents/docs/5-github/basics/github-organizations/index.mdx b/contents/docs/5-github/basics/github-organizations/index.mdx index cdbc8354..50955bc8 100644 --- a/contents/docs/5-github/basics/github-organizations/index.mdx +++ b/contents/docs/5-github/basics/github-organizations/index.mdx @@ -7,11 +7,6 @@ GitHub Organizations are shared accounts that provide centralized management and #### Free Resources -- [@official@About Organizations](https://docs.github.com/en/organizations/collaborating-with-groups-in-organizations/about-organizations) -- [@video@Set up a GitHub Organization](https://www.youtube.com/watch?v=XowSSIhJFuk) - -#### Free Resources - Official Docs diff --git a/contents/docs/5-github/basics/github-packages/index.mdx b/contents/docs/5-github/basics/github-packages/index.mdx index 8a8ef1c6..73424776 100644 --- a/contents/docs/5-github/basics/github-packages/index.mdx +++ b/contents/docs/5-github/basics/github-packages/index.mdx @@ -7,11 +7,6 @@ GitHub Packages is a package repository service that allows developers to store #### Free Resources -- [@official@Introduction to GitHub Packages](https://docs.github.com/en/packages/learn-github-packages/introduction-to-github-packages) -- [@official@GitHub Packages documentation](https://docs.github.com/en/packages) - -#### Free Resources - Official Docs diff --git a/contents/docs/5-github/basics/github-pages/index.mdx b/contents/docs/5-github/basics/github-pages/index.mdx index 3e547e36..7b0e0d7b 100644 --- a/contents/docs/5-github/basics/github-pages/index.mdx +++ b/contents/docs/5-github/basics/github-pages/index.mdx @@ -7,12 +7,6 @@ GitHub Pages is a feature that allows users to host and publish web content dire #### Free Resources -- [@official@About GitHub Pages](https://docs.github.com/en/pages/getting-started-with-github-pages/about-github-pages) -- [@official@Creating a GitHub Pages site](https://docs.github.com/en/pages/getting-started-with-github-pages/creating-a-github-pages-site) -- [@official@GitHub Pages examples](https://github.com/collections/github-pages-examples) - -#### Free Resources - Official Docs diff --git a/contents/docs/5-github/basics/github-projects/index.mdx b/contents/docs/5-github/basics/github-projects/index.mdx index 63056869..0e9a352f 100644 --- a/contents/docs/5-github/basics/github-projects/index.mdx +++ b/contents/docs/5-github/basics/github-projects/index.mdx @@ -7,11 +7,6 @@ GitHub Projects is a flexible project management tool integrated directly into G #### Free Resources -- [@official@About Projects](https://docs.github.com/en/issues/planning-and-tracking-with-projects/learning-about-projects/about-projects) -- [@video@How to use Projects Roadmap](https://www.youtube.com/watch?v=D80u__nYYWw) - -#### Free Resources - Official Docs diff --git a/contents/docs/5-github/basics/github-releases/index.mdx b/contents/docs/5-github/basics/github-releases/index.mdx index fae6a784..b8106f63 100644 --- a/contents/docs/5-github/basics/github-releases/index.mdx +++ b/contents/docs/5-github/basics/github-releases/index.mdx @@ -7,11 +7,6 @@ GitHub Releases is a feature that allows developers to package and distribute so #### Free Resources -- [@official@About Releases](https://docs.github.com/en/repositories/releasing-projects-on-github/about-releases) -- [@article@REST API endpoints for releases](https://docs.github.com/en/rest/releases/releases?apiVersion=2022-11-28) - -#### Free Resources - Official Docs diff --git a/contents/docs/5-github/basics/github-security/index.mdx b/contents/docs/5-github/basics/github-security/index.mdx index e8f32777..2871f29d 100644 --- a/contents/docs/5-github/basics/github-security/index.mdx +++ b/contents/docs/5-github/basics/github-security/index.mdx @@ -7,12 +7,6 @@ GitHub Security is a suite of features and tools that help developers identify, #### Free Resources -- [@official@GitHub security features](https://docs.github.com/en/code-security/getting-started/github-security-features) -- [@official@Dependabot Quick-start Guide](https://docs.github.com/en/code-security/getting-started/dependabot-quickstart-guide) -- [@official@About user alerts](https://docs.github.com/en/code-security/secret-scanning/managing-alerts-from-secret-scanning/about-alerts#about-user-alerts) - -#### Free Resources - Official Docs diff --git a/contents/docs/5-github/basics/github-sponsors/index.mdx b/contents/docs/5-github/basics/github-sponsors/index.mdx index a631f501..a5756a99 100644 --- a/contents/docs/5-github/basics/github-sponsors/index.mdx +++ b/contents/docs/5-github/basics/github-sponsors/index.mdx @@ -7,11 +7,6 @@ A GitHub Sponsor is a way to support and fund open-source projects on GitHub. It #### Free Resources -- [@official@Sponsoring an open source contributor through GitHub](https://docs.github.com/en/sponsors/sponsoring-open-source-contributors/sponsoring-an-open-source-contributor-through-github) -- [@official@Receiving sponsorships through GitHub Sponsors](https://docs.github.com/en/sponsors/receiving-sponsorships-through-github-sponsors) - -#### Free Resources - Official Docs diff --git a/contents/docs/5-github/basics/github-wikis/index.mdx b/contents/docs/5-github/basics/github-wikis/index.mdx index ab2ebd17..60373c22 100644 --- a/contents/docs/5-github/basics/github-wikis/index.mdx +++ b/contents/docs/5-github/basics/github-wikis/index.mdx @@ -7,11 +7,6 @@ GitHub Wikis are collaborative documentation spaces integrated directly into Git #### Free Resources -- [@official@About Wikis](https://docs.github.com/en/communities/documenting-your-project-with-wikis/about-wikis) -- [@official@Documenting your project with Wikis](https://docs.github.com/en/communities/documenting-your-project-with-wikis) - -#### Free Resources - Official Docs diff --git a/contents/docs/5-github/basics/gitignore/index.mdx b/contents/docs/5-github/basics/gitignore/index.mdx index e378fa42..fa322599 100644 --- a/contents/docs/5-github/basics/gitignore/index.mdx +++ b/contents/docs/5-github/basics/gitignore/index.mdx @@ -9,13 +9,6 @@ Ignored files are tracked in a special file named `.gitignore` that is checked i #### Free Resources -- [@official@gitignore Documentation](https://git-scm.com/docs/gitignore) -- [@article@.gitignore file - ignoring files in Git | Atlassian Git Tutorial](https://www.atlassian.com/git/tutorials/saving-changes/gitignore) -- [@article@Ignoring files - GitHub Docs](https://docs.github.com/en/get-started/getting-started-with-git/ignoring-files) -- [@opensource@gitignore - A collection of useful .gitignore templates](https://github.com/github/gitignore) - -#### Free Resources - Official Docs diff --git a/contents/docs/5-github/basics/graphql-api/index.mdx b/contents/docs/5-github/basics/graphql-api/index.mdx index 6de0cb4d..45b6b428 100644 --- a/contents/docs/5-github/basics/graphql-api/index.mdx +++ b/contents/docs/5-github/basics/graphql-api/index.mdx @@ -7,11 +7,6 @@ The GitHub GraphQL API is a set of APIs that provides access to various GitHub f #### Free Resources -- [@official@GitHub GraphQL API documentation](https://docs.github.com/en/graphql) -- [@official@Forming calls with GraphQL](https://docs.github.com/en/graphql/guides/forming-calls-with-graphql) - -#### Free Resources - Official Docs diff --git a/contents/docs/5-github/basics/installation-and-setup/index.mdx b/contents/docs/5-github/basics/installation-and-setup/index.mdx index fe3907e6..f1b70a77 100644 --- a/contents/docs/5-github/basics/installation-and-setup/index.mdx +++ b/contents/docs/5-github/basics/installation-and-setup/index.mdx @@ -9,12 +9,6 @@ Once installed, setting up the GitHub CLI typically involves authenticating with #### Free Resources -- [@official@GitHub CLI - Installation](https://github.com/cli/cli?tab=readme-ov-file#installation) -- [@official@GitHub CLI - Release](https://github.com/cli/cli/releases/) -- [@official@GitHub CLI Quickstart](https://docs.github.com/en/github-cli/github-cli/quickstart) - -#### Free Resources - Official Docs diff --git a/contents/docs/5-github/basics/installing-git-locally/index.mdx b/contents/docs/5-github/basics/installing-git-locally/index.mdx index 395506f7..aa6a4ef4 100644 --- a/contents/docs/5-github/basics/installing-git-locally/index.mdx +++ b/contents/docs/5-github/basics/installing-git-locally/index.mdx @@ -13,11 +13,6 @@ Once installed, you can verify the Git version by running `git --version` in you #### Free Resources -- [@official@Git - Downloads](https://git-scm.com/downloads) -- [@article@Install Git](https://github.com/git-guides/install-git) - -#### Free Resources - Official Docs diff --git a/contents/docs/5-github/basics/kanban-boards/index.mdx b/contents/docs/5-github/basics/kanban-boards/index.mdx index a42fa51f..c5a47521 100644 --- a/contents/docs/5-github/basics/kanban-boards/index.mdx +++ b/contents/docs/5-github/basics/kanban-boards/index.mdx @@ -9,11 +9,6 @@ A Kanban board typically has columns representing different stages or states, su #### Free Resources -- [@official@Projects - Boards - Changing the layout of a view](https://docs.github.com/en/issues/planning-and-tracking-with-projects/customizing-views-in-your-project/changing-the-layout-of-a-view) -- [@video@GitHub Project Management - Create GitHub Project Board & Automations](https://www.youtube.com/watch?v=oPQgFxHcjAw) - -#### Free Resources - Official Docs diff --git a/contents/docs/5-github/basics/learn-the-basics/index.mdx b/contents/docs/5-github/basics/learn-the-basics/index.mdx index 184abcaa..01688869 100644 --- a/contents/docs/5-github/basics/learn-the-basics/index.mdx +++ b/contents/docs/5-github/basics/learn-the-basics/index.mdx @@ -7,16 +7,6 @@ A Version Control System (VCS) is a tool that helps developers manage changes to #### Free Resources -- [@article@What is version control?](https://www.atlassian.com/git/tutorials/what-is-version-control) -- [@article@What is Git? - The Complete Guide to Git](https://www.datacamp.com/blog/all-about-git) -- [@article@Version Control (Git) - The Missing Semester of Your CS Education](https://missing.csail.mit.edu/2020/version-control/) -- [@video@What is Git? Explained in 2 Minutes!](https://www.youtube.com/watch?v=2ReR1YJrNOM) -- [@official@GUI Clients](https://git-scm.com/downloads/guis) -- [@official@Getting Started - Installing Git](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git) -- [@official@Creating an account on GitHub](https://docs.github.com/en/get-started/start-your-journey/creating-an-account-on-github) - -#### Free Resources - Official Docs diff --git a/contents/docs/5-github/basics/markdown/index.mdx b/contents/docs/5-github/basics/markdown/index.mdx index 22fff55f..910f0c42 100644 --- a/contents/docs/5-github/basics/markdown/index.mdx +++ b/contents/docs/5-github/basics/markdown/index.mdx @@ -13,11 +13,6 @@ By using Markdown, you can easily format text within your GitHub repository, mak #### Free Resources -- [@official@Basic writing and formatting syntax](https://docs.github.com/en/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax) -- [@article@Markdown Cheatsheet](https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet) - -#### Free Resources - Official Docs diff --git a/contents/docs/5-github/basics/mentions/index.mdx b/contents/docs/5-github/basics/mentions/index.mdx index 4250e009..2ba23e4e 100644 --- a/contents/docs/5-github/basics/mentions/index.mdx +++ b/contents/docs/5-github/basics/mentions/index.mdx @@ -7,10 +7,6 @@ Mentions on GitHub allow you to notify specific users or teams about comments, i #### Free Resources -- [@official@Mention Somebody](https://github.blog/news-insights/mention-somebody-they-re-notified/) - -#### Free Resources - Official Docs diff --git a/contents/docs/5-github/basics/oauth-apps/index.mdx b/contents/docs/5-github/basics/oauth-apps/index.mdx index 19914e66..f4049ad0 100644 --- a/contents/docs/5-github/basics/oauth-apps/index.mdx +++ b/contents/docs/5-github/basics/oauth-apps/index.mdx @@ -7,11 +7,6 @@ GitHub OAuth Apps allow developers to integrate with GitHub using OAuth 2.0 auth #### Free Resources -- [@official@Creating an OAuth app](https://docs.github.com/en/apps/oauth-apps/building-oauth-apps/creating-an-oauth-app) -- [@video@GitHub Login With React (GitHub APIs, GitHub OAuth 2.0 Authentication)](https://www.youtube.com/watch?v=rRn2EisxPl4) - -#### Free Resources - Official Docs diff --git a/contents/docs/5-github/basics/pr-from-a-fork/index.mdx b/contents/docs/5-github/basics/pr-from-a-fork/index.mdx index b28fb6b4..d99f3c7b 100644 --- a/contents/docs/5-github/basics/pr-from-a-fork/index.mdx +++ b/contents/docs/5-github/basics/pr-from-a-fork/index.mdx @@ -7,11 +7,6 @@ Creating a pull request from a fork on GitHub is a common workflow for contribut #### Free Resources -- [@official@Creating a pull request from a fork](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/creating-a-pull-request-from-a-fork) -- [@video@How to Create a Pull Request from a Fork on GitHub](https://www.youtube.com/watch?v=a_FLqX3vGR4) - -#### Free Resources - Official Docs diff --git a/contents/docs/5-github/basics/private-vs-public/index.mdx b/contents/docs/5-github/basics/private-vs-public/index.mdx index 6c002e9c..0a4a62d1 100644 --- a/contents/docs/5-github/basics/private-vs-public/index.mdx +++ b/contents/docs/5-github/basics/private-vs-public/index.mdx @@ -7,10 +7,6 @@ GitHub offers both private and public repositories, each serving different purpo #### Free Resources -- [@official@About project visibility](https://docs.github.com/en/repositories/creating-and-managing-repositories/about-repositories#about-repository-visibility) - -#### Free Resources - Official Docs diff --git a/contents/docs/5-github/basics/profile-readme/index.mdx b/contents/docs/5-github/basics/profile-readme/index.mdx index edcae650..14a45157 100644 --- a/contents/docs/5-github/basics/profile-readme/index.mdx +++ b/contents/docs/5-github/basics/profile-readme/index.mdx @@ -7,11 +7,6 @@ A GitHub Profile README is a special repository that allows users to showcase th #### Free Resources -- [@official@Managing your Profile README](https://docs.github.com/en/account-and-profile/setting-up-and-managing-your-github-profile/customizing-your-profile/managing-your-profile-readme) -- [@video@GitHub Profile README](https://www.youtube.com/watch?v=KhGWbt1dAKQ) - -#### Free Resources - Official Docs diff --git a/contents/docs/5-github/basics/project-planning/index.mdx b/contents/docs/5-github/basics/project-planning/index.mdx index fd8e9896..f8c01668 100644 --- a/contents/docs/5-github/basics/project-planning/index.mdx +++ b/contents/docs/5-github/basics/project-planning/index.mdx @@ -7,11 +7,6 @@ Project planning on GitHub is a comprehensive process that leverages the platfor #### Free Resources -- [@official@Project planning for developers](https://github.com/features/issues) -- [@video@GitHub Project Management](https://www.youtube.com/watch?v=oPQgFxHcjAw) - -#### Free Resources - Official Docs diff --git a/contents/docs/5-github/basics/project-readme/index.mdx b/contents/docs/5-github/basics/project-readme/index.mdx index 30f98e95..f22a7e9a 100644 --- a/contents/docs/5-github/basics/project-readme/index.mdx +++ b/contents/docs/5-github/basics/project-readme/index.mdx @@ -7,11 +7,6 @@ A GitHub project README is a crucial document that serves as the front page of a #### Free Resources -- [@official@About READMEs](https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-readmes) -- [@article@How to write a good README](https://bulldogjob.com/readme/how-to-write-a-good-readme-for-your-github-project) - -#### Free Resources - Official Docs diff --git a/contents/docs/5-github/basics/repository-management/index.mdx b/contents/docs/5-github/basics/repository-management/index.mdx index b4f4b737..e8c17b44 100644 --- a/contents/docs/5-github/basics/repository-management/index.mdx +++ b/contents/docs/5-github/basics/repository-management/index.mdx @@ -12,12 +12,6 @@ Using GitHub CLI for repository management allows you to streamline tasks and wo #### Free Resources -- [@official@gh repo](https://cli.github.com/manual/gh_repo) -- [@article@Efficient GitHub Operations: Simplifying Repository Management using Github CLI](https://dev.to/yutee_okon/efficient-github-operations-simplifying-repository-management-using-github-cli-190l) -- [@video@GitHub CLI (gh) - How to manage repositories more efficiently](https://www.youtube.com/watch?v=BII6ZY2Rnlc) - -#### Free Resources - Official Docs diff --git a/contents/docs/5-github/basics/rest-api/index.mdx b/contents/docs/5-github/basics/rest-api/index.mdx index 2c23b43f..d2ec70d5 100644 --- a/contents/docs/5-github/basics/rest-api/index.mdx +++ b/contents/docs/5-github/basics/rest-api/index.mdx @@ -7,12 +7,6 @@ The GitHub REST API is a set of APIs that provide access to various GitHub featu #### Free Resources -- [@official@GitHub REST API documentation](https://docs.github.com/en/rest?apiVersion=2022-11-28) -- [@official@Quickstart for GitHub REST API](https://docs.github.com/en/rest/quickstart?apiVersion=2022-11-28) -- [@video@[Tutorial] - How to use GitHub REST API for Beginners](https://www.youtube.com/watch?v=OvfLavRD1Os) - -#### Free Resources - Official Docs diff --git a/contents/docs/5-github/basics/roadmaps/index.mdx b/contents/docs/5-github/basics/roadmaps/index.mdx index a7533690..f2855942 100644 --- a/contents/docs/5-github/basics/roadmaps/index.mdx +++ b/contents/docs/5-github/basics/roadmaps/index.mdx @@ -7,11 +7,6 @@ GitHub Roadmaps are a feature that helps you visualize and organize plans for yo #### Free Resources -- [@official@Customizing the Roadmap Layout](https://docs.github.com/en/issues/planning-and-tracking-with-projects/customizing-views-in-your-project/customizing-the-roadmap-layout) -- [@video@Learn how to use Project Roadmaps - GitHub Checkout](https://www.youtube.com/watch?v=D80u__nYYWw) - -#### Free Resources - Official Docs diff --git a/contents/docs/5-github/basics/saved-replies/index.mdx b/contents/docs/5-github/basics/saved-replies/index.mdx index c94bd1b2..455a88ba 100644 --- a/contents/docs/5-github/basics/saved-replies/index.mdx +++ b/contents/docs/5-github/basics/saved-replies/index.mdx @@ -10,11 +10,6 @@ GitHub allows you to save frequently used comments and reuse them when discussin #### Free Resources -- [@official@Using saved replies](https://docs.github.com/en/get-started/writing-on-github/working-with-saved-replies/using-saved-replies) -- [@article@Walkthrough: Using Github’s “Saved Replies” to make life consistent and easy](https://prowe214.medium.com/walkthrough-using-githubs-saved-replies-to-make-life-consistent-and-easy-80f23efe6a0) - -#### Free Resources - Official Docs diff --git a/contents/docs/5-github/basics/scheduled-worfklows/index.mdx b/contents/docs/5-github/basics/scheduled-worfklows/index.mdx index 77e0af6f..23057364 100644 --- a/contents/docs/5-github/basics/scheduled-worfklows/index.mdx +++ b/contents/docs/5-github/basics/scheduled-worfklows/index.mdx @@ -7,11 +7,6 @@ GitHub Actions allows you to schedule workflows to run at specific times or inte #### Free Resources -- [@official@Events that trigger workflows - Schedule](https://docs.github.com/en/actions/writing-workflows/choosing-when-your-workflow-runs/events-that-trigger-workflows#schedule) -- [@video@GitHub Actions - How to Schedule workflows in GitHub](https://www.youtube.com/watch?v=StipNrK__Gk) - -#### Free Resources - Official Docs diff --git a/contents/docs/5-github/basics/secrets-and-env-vars/index.mdx b/contents/docs/5-github/basics/secrets-and-env-vars/index.mdx index bd17982e..3cc7983a 100644 --- a/contents/docs/5-github/basics/secrets-and-env-vars/index.mdx +++ b/contents/docs/5-github/basics/secrets-and-env-vars/index.mdx @@ -10,12 +10,6 @@ GitHub provides features to securely store and manage sensitive data, such as se #### Free Resources -- [@official@Using secrets in GitHub Actions](https://docs.github.com/en/actions/security-for-github-actions/security-guides/using-secrets-in-github-actions) -- [@official@Store information in variables](https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/store-information-in-variables) -- [@video@Secrets and Environment Variables in your GitHub Action](https://www.youtube.com/watch?v=dPLPSaFqJmY) - -#### Free Resources - Official Docs diff --git a/contents/docs/5-github/basics/setting-up-profile/index.mdx b/contents/docs/5-github/basics/setting-up-profile/index.mdx index f862db1e..b59d3e3d 100644 --- a/contents/docs/5-github/basics/setting-up-profile/index.mdx +++ b/contents/docs/5-github/basics/setting-up-profile/index.mdx @@ -11,11 +11,6 @@ On GitHub, creating a profile is an essential step in showcasing yourself as a d #### Free Resources -- [@official@Setting up your profile](https://docs.github.com/en/get-started/start-your-journey/setting-up-your-profile) -- [@video@GitHub Profile Readme](https://www.youtube.com/watch?v=KhGWbt1dAKQ) - -#### Free Resources - Official Docs diff --git a/contents/docs/5-github/basics/static-site-generators/index.mdx b/contents/docs/5-github/basics/static-site-generators/index.mdx index bbc867bf..936265d2 100644 --- a/contents/docs/5-github/basics/static-site-generators/index.mdx +++ b/contents/docs/5-github/basics/static-site-generators/index.mdx @@ -7,11 +7,6 @@ GitHub offers a set of static site generators (SSGs) that allow users to create #### Free Resources -- [@official@Static Site Generators](https://github.com/collections/static-site-generators) -- [@official@About GitHub Pages and Jekyll](https://docs.github.com/en/pages/setting-up-a-github-pages-site-with-jekyll/about-github-pages-and-jekyll) - -#### Free Resources - Official Docs diff --git a/contents/docs/5-github/basics/storing-artifacts/index.mdx b/contents/docs/5-github/basics/storing-artifacts/index.mdx index 432f5040..57441816 100644 --- a/contents/docs/5-github/basics/storing-artifacts/index.mdx +++ b/contents/docs/5-github/basics/storing-artifacts/index.mdx @@ -10,10 +10,6 @@ GitHub provides a feature for storing artifacts, which allows you to upload buil #### Free Resources -- [@official@Storing and sharing data from a workflow](https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/storing-and-sharing-data-from-a-workflow) - -#### Free Resources - Official Docs diff --git a/contents/docs/5-github/basics/teams-within-organization/index.mdx b/contents/docs/5-github/basics/teams-within-organization/index.mdx index 1807a301..e5d5c953 100644 --- a/contents/docs/5-github/basics/teams-within-organization/index.mdx +++ b/contents/docs/5-github/basics/teams-within-organization/index.mdx @@ -11,11 +11,6 @@ GitHub Organizations allow you to create teams within your organization, which h #### Free Resources -- [@official@Organizing Members into Teams](https://docs.github.com/en/organizations/organizing-members-into-teams) -- [@article@Best Practices for Organizations and Teams using GitHub Enterprise Cloud](https://github.blog/enterprise-software/devops/best-practices-for-organizations-and-teams-using-github-enterprise-cloud/) - -#### Free Resources - Official Docs diff --git a/contents/docs/5-github/basics/webhooks/index.mdx b/contents/docs/5-github/basics/webhooks/index.mdx index 72baa43c..055cbc33 100644 --- a/contents/docs/5-github/basics/webhooks/index.mdx +++ b/contents/docs/5-github/basics/webhooks/index.mdx @@ -7,12 +7,6 @@ GitHub Webhooks allow developers to receive real-time notifications about events #### Free Resources -- [@official@About webhooks](https://docs.github.com/en/webhooks/about-webhooks) -- [@official@Webhooks documentation](https://docs.github.com/en/webhooks) -- [@video@How to use GitHub Webhooks with Discord](https://www.youtube.com/watch?v=-gyEHj0CVx0&) - -#### Free Resources - Official Docs diff --git a/contents/docs/5-github/collaboration/issue-management/index.mdx b/contents/docs/5-github/collaboration/issue-management/index.mdx index 40caab53..bb2eaf6d 100644 --- a/contents/docs/5-github/collaboration/issue-management/index.mdx +++ b/contents/docs/5-github/collaboration/issue-management/index.mdx @@ -13,11 +13,6 @@ The GitHub CLI provides a range of features for managing issues within your repo #### Free Resources -- [@official@gh issue](https://cli.github.com/manual/gh_issue) -- [@video@Manage GitHub Issues From The Command Line Using GitHub CLI](https://www.youtube.com/watch?v=nuCQiP41jU0) - -#### Free Resources - Official Docs diff --git a/contents/docs/5-github/collaboration/issues/index.mdx b/contents/docs/5-github/collaboration/issues/index.mdx index 8eb792b3..3b52eb03 100644 --- a/contents/docs/5-github/collaboration/issues/index.mdx +++ b/contents/docs/5-github/collaboration/issues/index.mdx @@ -17,11 +17,6 @@ Issues are a core feature of GitHub repositories, enabling teams to collaborate #### Free Resources -- [@official@About Issues](https://docs.github.com/en/issues/tracking-your-work-with-issues/about-issues) -- [@video@What is GitHub Issues?](https://www.youtube.com/watch?v=6HWw7rhwvtY) - -#### Free Resources - Official Docs diff --git a/contents/docs/5-github/collaboration/labelling-issues--prs/index.mdx b/contents/docs/5-github/collaboration/labelling-issues--prs/index.mdx index f5076812..1bf930a7 100644 --- a/contents/docs/5-github/collaboration/labelling-issues--prs/index.mdx +++ b/contents/docs/5-github/collaboration/labelling-issues--prs/index.mdx @@ -16,10 +16,6 @@ On GitHub, labels are a way to categorize issues and pull requests (PRs) by topi #### Free Resources -- [@official@Managing labels](https://docs.github.com/en/issues/using-labels-and-milestones-to-track-work/managing-labels) - -#### Free Resources - Official Docs diff --git a/contents/docs/6-workflows/best-practices/git-hooks/index.mdx b/contents/docs/6-workflows/best-practices/git-hooks/index.mdx index b5274e77..a308a1a8 100644 --- a/contents/docs/6-workflows/best-practices/git-hooks/index.mdx +++ b/contents/docs/6-workflows/best-practices/git-hooks/index.mdx @@ -12,12 +12,6 @@ There are two types of Git hooks: #### Free Resources -- [@official@Customizing Git - Git Hooks](https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks) -- [@article@Git hooks](https://www.atlassian.com/git/tutorials/git-hooks) -- [@video@What are GitHooks? Explained in 5 minutes](https://www.youtube.com/watch?v=1OFiiPretCM) - -#### Free Resources - Official Docs diff --git a/contents/docs/6-workflows/best-practices/post-update/index.mdx b/contents/docs/6-workflows/best-practices/post-update/index.mdx index 908e7f5a..452bb008 100644 --- a/contents/docs/6-workflows/best-practices/post-update/index.mdx +++ b/contents/docs/6-workflows/best-practices/post-update/index.mdx @@ -9,10 +9,6 @@ Git post-update hooks are scripts that run automatically after a successful push #### Free Resources -- [@official@Post-update hooks](https://git-scm.com/docs/githooks#post-update) - -#### Free Resources - Official Docs diff --git a/contents/docs/6-workflows/best-practices/pr-guidelines/index.mdx b/contents/docs/6-workflows/best-practices/pr-guidelines/index.mdx index 61bd2a4b..0a275967 100644 --- a/contents/docs/6-workflows/best-practices/pr-guidelines/index.mdx +++ b/contents/docs/6-workflows/best-practices/pr-guidelines/index.mdx @@ -7,11 +7,6 @@ Pull Request (PR) guidelines are essential for maintaining a smooth and efficien #### Free Resources -- [@official@Best Practices for Pull Requests](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/getting-started/best-practices-for-pull-requests) -- [@article@Pull Request Guidelines](https://opensource.creativecommons.org/contributing-code/pr-guidelines/) - -#### Free Resources - Official Docs diff --git a/contents/docs/6-workflows/best-practices/pre-commit/index.mdx b/contents/docs/6-workflows/best-practices/pre-commit/index.mdx index 0b42b732..136843e7 100644 --- a/contents/docs/6-workflows/best-practices/pre-commit/index.mdx +++ b/contents/docs/6-workflows/best-practices/pre-commit/index.mdx @@ -9,11 +9,6 @@ Git pre-commit hooks are scripts that run automatically before a commit is creat #### Free Resources -- [@opensource@pre-commit/pre-commit](https://github.com/pre-commit/pre-commit) -- [@official@Git Hooks](https://www.atlassian.com/git/tutorials/git-hooks) - -#### Free Resources - Official Docs diff --git a/contents/docs/7-automation/git-hooks/client-vs-server-hooks/index.mdx b/contents/docs/7-automation/git-hooks/client-vs-server-hooks/index.mdx index 308827e2..6f8739b3 100644 --- a/contents/docs/7-automation/git-hooks/client-vs-server-hooks/index.mdx +++ b/contents/docs/7-automation/git-hooks/client-vs-server-hooks/index.mdx @@ -7,12 +7,6 @@ Like many other Version Control Systems, Git has a way to fire off custom script #### Free Resources -- [@official@Git Hooks](https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks#:~:text=There%20are%20two%20groups%20of,for%20all%20sorts%20of%20reasons.) -- [@article@Git Hooks: The Powerful Tool You're Probably Not Using](https://dev.to/algodame/git-hooks-the-powerful-tool-youre-probably-not-using-but-should-be-1lec) -- [@video@Client vs Server Hooks](https://youtu.be/egfuwOe8nXc?si=IkbLCr-3eGE9x6cY) - -#### Free Resources - Official Docs diff --git a/public/sw.js b/public/sw.js index 78bbd2a0..971e9a73 100644 --- a/public/sw.js +++ b/public/sw.js @@ -1,92 +1 @@ -/** - * Copyright 2018 Google Inc. All Rights Reserved. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0 - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -// If the loader is already loaded, just stop. -if (!self.define) { - let registry = {}; - - // Used for `eval` and `importScripts` where we can't get script URL by other means. - // In both cases, it's safe to use a global var because those functions are synchronous. - let nextDefineUri; - - const singleRequire = (uri, parentUri) => { - uri = new URL(uri + ".js", parentUri).href; - return registry[uri] || ( - - new Promise(resolve => { - if ("document" in self) { - const script = document.createElement("script"); - script.src = uri; - script.onload = resolve; - document.head.appendChild(script); - } else { - nextDefineUri = uri; - importScripts(uri); - resolve(); - } - }) - - .then(() => { - let promise = registry[uri]; - if (!promise) { - throw new Error(`Module ${uri} didn’t register its module`); - } - return promise; - }) - ); - }; - - self.define = (depsNames, factory) => { - const uri = nextDefineUri || ("document" in self ? document.currentScript.src : "") || location.href; - if (registry[uri]) { - // Module is already loading or loaded. - return; - } - let exports = {}; - const require = depUri => singleRequire(depUri, uri); - const specialDeps = { - module: { uri }, - exports, - require - }; - registry[uri] = Promise.all(depsNames.map( - depName => specialDeps[depName] || require(depName) - )).then(deps => { - factory(...deps); - return exports; - }); - }; -} -define(['./workbox-7144475a'], (function (workbox) { 'use strict'; - - importScripts(); - self.skipWaiting(); - workbox.clientsClaim(); - workbox.registerRoute("/", new workbox.NetworkFirst({ - "cacheName": "start-url", - plugins: [{ - cacheWillUpdate: async ({ - response: e - }) => e && "opaqueredirect" === e.type ? new Response(e.body, { - status: 200, - statusText: "OK", - headers: e.headers - }) : e - }] - }), 'GET'); - workbox.registerRoute(/.*/i, new workbox.NetworkOnly({ - "cacheName": "dev", - plugins: [] - }), 'GET'); - -})); +if(!self.define){let e,s={};const a=(a,c)=>(a=new URL(a+".js",c).href,s[a]||new Promise(s=>{if("document"in self){const e=document.createElement("script");e.src=a,e.onload=s,document.head.appendChild(e)}else e=a,importScripts(a),s()}).then(()=>{let e=s[a];if(!e)throw new Error(`Module ${a} didn’t register its module`);return e}));self.define=(c,n)=>{const i=e||("document"in self?document.currentScript.src:"")||location.href;if(s[i])return;let t={};const r=e=>a(e,i),f={module:{uri:i},exports:t,require:r};s[i]=Promise.all(c.map(e=>f[e]||r(e))).then(e=>(n(...e),t))}}define(["./workbox-f1770938"],function(e){"use strict";importScripts(),self.skipWaiting(),e.clientsClaim(),e.precacheAndRoute([{url:"/_next/static/chunks/0e5ce63c-5c918b05c11fcedb.js",revision:"5c918b05c11fcedb"},{url:"/_next/static/chunks/141-d4ddc02f418ca1d5.js",revision:"d4ddc02f418ca1d5"},{url:"/_next/static/chunks/168-4036d486527fe395.js",revision:"4036d486527fe395"},{url:"/_next/static/chunks/232-c50cb5d393cd0124.js",revision:"c50cb5d393cd0124"},{url:"/_next/static/chunks/313-cbfc4577bcd5505a.js",revision:"cbfc4577bcd5505a"},{url:"/_next/static/chunks/355-e6c2a78ce156937f.js",revision:"e6c2a78ce156937f"},{url:"/_next/static/chunks/361-1415786b96bedc9f.js",revision:"1415786b96bedc9f"},{url:"/_next/static/chunks/38-d7868fff84f51b02.js",revision:"d7868fff84f51b02"},{url:"/_next/static/chunks/4bd1b696-cf72ae8a39fa05aa.js",revision:"cf72ae8a39fa05aa"},{url:"/_next/static/chunks/503-e538ca013f3e15a3.js",revision:"e538ca013f3e15a3"},{url:"/_next/static/chunks/519-fa250016fb8cdf72.js",revision:"fa250016fb8cdf72"},{url:"/_next/static/chunks/660-90548280a614b53c.js",revision:"90548280a614b53c"},{url:"/_next/static/chunks/823-d66bb3af97db83a0.js",revision:"d66bb3af97db83a0"},{url:"/_next/static/chunks/881-8fbe4978c99e3ad6.js",revision:"8fbe4978c99e3ad6"},{url:"/_next/static/chunks/900-644fa5069fbc149c.js",revision:"644fa5069fbc149c"},{url:"/_next/static/chunks/943-e9a1b78299a5dc9d.js",revision:"e9a1b78299a5dc9d"},{url:"/_next/static/chunks/app/_not-found/page-66bb8aec4c2678c5.js",revision:"66bb8aec4c2678c5"},{url:"/_next/static/chunks/app/blog/%5Bslug%5D/page-aa1d983d6039e53f.js",revision:"aa1d983d6039e53f"},{url:"/_next/static/chunks/app/blog/layout-66bb8aec4c2678c5.js",revision:"66bb8aec4c2678c5"},{url:"/_next/static/chunks/app/blog/page-aa1d983d6039e53f.js",revision:"aa1d983d6039e53f"},{url:"/_next/static/chunks/app/docs/%5B%5B...slug%5D%5D/page-4f63776b0729aff2.js",revision:"4f63776b0729aff2"},{url:"/_next/static/chunks/app/docs/layout-f8ff12552508fdf7.js",revision:"f8ff12552508fdf7"},{url:"/_next/static/chunks/app/error-2685b0a155205f18.js",revision:"2685b0a155205f18"},{url:"/_next/static/chunks/app/layout-99165bcdca89ffc7.js",revision:"99165bcdca89ffc7"},{url:"/_next/static/chunks/app/not-found-e2645c205ae492df.js",revision:"e2645c205ae492df"},{url:"/_next/static/chunks/app/page-7fed32e49476429d.js",revision:"7fed32e49476429d"},{url:"/_next/static/chunks/framework-306aa0968ce8efc5.js",revision:"306aa0968ce8efc5"},{url:"/_next/static/chunks/main-2fae19461cbc658a.js",revision:"2fae19461cbc658a"},{url:"/_next/static/chunks/main-app-4dfffc931ba50363.js",revision:"4dfffc931ba50363"},{url:"/_next/static/chunks/pages/_app-0a0020ddd67f79cf.js",revision:"0a0020ddd67f79cf"},{url:"/_next/static/chunks/pages/_error-03529f2c21436739.js",revision:"03529f2c21436739"},{url:"/_next/static/chunks/polyfills-42372ed130431b0a.js",revision:"846118c33b2c0e922d7b3a7676f81f6f"},{url:"/_next/static/chunks/webpack-7bac0c5f0c7c94a3.js",revision:"7bac0c5f0c7c94a3"},{url:"/_next/static/css/cc6ad1d09e457cd4.css",revision:"cc6ad1d09e457cd4"},{url:"/_next/static/media/028c0d39d2e8f589-s.p.woff2",revision:"c47061a6ce9601b5dea8da0c9e847f79"},{url:"/_next/static/rlaeIsLA9oxASi6Zdm2zZ/_buildManifest.js",revision:"f5a1685661b52a70f97334f0ec7189a7"},{url:"/_next/static/rlaeIsLA9oxASi6Zdm2zZ/_ssgManifest.js",revision:"b6652df95db52feb4daf4eca35380933"},{url:"/docs.png",revision:"8f6e212edc2bc734ee6bcfa764b5544c"},{url:"/docsw.png",revision:"f7fbb6e34217d818b513d60290f6da9f"},{url:"/favicon-48x48.png",revision:"855e40ed3754666fbde1f53620ed9b1d"},{url:"/favicon.svg",revision:"04e8c29e9b671c2e5e42267d55fdafd0"},{url:"/git-cheatsheet.pdf",revision:"1fcf70393d2aed298ef2c521126e8cd3"},{url:"/git_explained_in_100_seconds.mp4",revision:"9d2862eaa4cc9a5e4ee124fd1b02f1fd"},{url:"/og.png",revision:"d08df9673a68bd26777d70f03ad68693"},{url:"/site.webmanifest",revision:"9090e674d41e265d5f03c180fe5f6721"},{url:"/web-app-manifest-192x192.png",revision:"06461dc6065d5ddd00eb2e38b858151e"},{url:"/web-app-manifest-512x512.png",revision:"6700fe9fb3805ebead0c5075266431f8"}],{ignoreURLParametersMatching:[/^utm_/,/^fbclid$/]}),e.cleanupOutdatedCaches(),e.registerRoute("/",new e.NetworkFirst({cacheName:"start-url",plugins:[{cacheWillUpdate:async({response:e})=>e&&"opaqueredirect"===e.type?new Response(e.body,{status:200,statusText:"OK",headers:e.headers}):e}]}),"GET"),e.registerRoute(/^https:\/\/fonts\.(?:gstatic)\.com\/.*/i,new e.CacheFirst({cacheName:"google-fonts-webfonts",plugins:[new e.ExpirationPlugin({maxEntries:4,maxAgeSeconds:31536e3})]}),"GET"),e.registerRoute(/^https:\/\/fonts\.(?:googleapis)\.com\/.*/i,new e.StaleWhileRevalidate({cacheName:"google-fonts-stylesheets",plugins:[new e.ExpirationPlugin({maxEntries:4,maxAgeSeconds:604800})]}),"GET"),e.registerRoute(/\.(?:eot|otf|ttc|ttf|woff|woff2|font.css)$/i,new e.StaleWhileRevalidate({cacheName:"static-font-assets",plugins:[new e.ExpirationPlugin({maxEntries:4,maxAgeSeconds:604800})]}),"GET"),e.registerRoute(/\.(?:jpg|jpeg|gif|png|svg|ico|webp)$/i,new e.StaleWhileRevalidate({cacheName:"static-image-assets",plugins:[new e.ExpirationPlugin({maxEntries:64,maxAgeSeconds:2592e3})]}),"GET"),e.registerRoute(/\/_next\/static.+\.js$/i,new e.CacheFirst({cacheName:"next-static-js-assets",plugins:[new e.ExpirationPlugin({maxEntries:64,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(/\/_next\/image\?url=.+$/i,new e.StaleWhileRevalidate({cacheName:"next-image",plugins:[new e.ExpirationPlugin({maxEntries:64,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(/\.(?:mp3|wav|ogg)$/i,new e.CacheFirst({cacheName:"static-audio-assets",plugins:[new e.RangeRequestsPlugin,new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(/\.(?:mp4|webm)$/i,new e.CacheFirst({cacheName:"static-video-assets",plugins:[new e.RangeRequestsPlugin,new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(/\.(?:js)$/i,new e.StaleWhileRevalidate({cacheName:"static-js-assets",plugins:[new e.ExpirationPlugin({maxEntries:48,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(/\.(?:css|less)$/i,new e.StaleWhileRevalidate({cacheName:"static-style-assets",plugins:[new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(/\/_next\/data\/.+\/.+\.json$/i,new e.StaleWhileRevalidate({cacheName:"next-data",plugins:[new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(/\.(?:json|xml|csv)$/i,new e.NetworkFirst({cacheName:"static-data-assets",plugins:[new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(({sameOrigin:e,url:{pathname:s}})=>!(!e||s.startsWith("/api/auth/callback")||!s.startsWith("/api/")),new e.NetworkFirst({cacheName:"apis",networkTimeoutSeconds:10,plugins:[new e.ExpirationPlugin({maxEntries:16,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(({request:e,url:{pathname:s},sameOrigin:a})=>"1"===e.headers.get("RSC")&&"1"===e.headers.get("Next-Router-Prefetch")&&a&&!s.startsWith("/api/"),new e.NetworkFirst({cacheName:"pages-rsc-prefetch",plugins:[new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(({request:e,url:{pathname:s},sameOrigin:a})=>"1"===e.headers.get("RSC")&&a&&!s.startsWith("/api/"),new e.NetworkFirst({cacheName:"pages-rsc",plugins:[new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(({url:{pathname:e},sameOrigin:s})=>s&&!e.startsWith("/api/"),new e.NetworkFirst({cacheName:"pages",plugins:[new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(({sameOrigin:e})=>!e,new e.NetworkFirst({cacheName:"cross-origin",networkTimeoutSeconds:10,plugins:[new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:3600})]}),"GET")}); diff --git a/public/workbox-7144475a.js b/public/workbox-7144475a.js deleted file mode 100644 index 85db1a71..00000000 --- a/public/workbox-7144475a.js +++ /dev/null @@ -1,2455 +0,0 @@ -define(['exports'], (function (exports) { 'use strict'; - - // @ts-ignore - try { - self['workbox:core:7.0.0'] && _(); - } catch (e) {} - - /* - Copyright 2019 Google LLC - Use of this source code is governed by an MIT-style - license that can be found in the LICENSE file or at - https://opensource.org/licenses/MIT. - */ - const logger = (() => { - // Don't overwrite this value if it's already set. - // See https://github.com/GoogleChrome/workbox/pull/2284#issuecomment-560470923 - if (!('__WB_DISABLE_DEV_LOGS' in globalThis)) { - self.__WB_DISABLE_DEV_LOGS = false; - } - let inGroup = false; - const methodToColorMap = { - debug: `#7f8c8d`, - log: `#2ecc71`, - warn: `#f39c12`, - error: `#c0392b`, - groupCollapsed: `#3498db`, - groupEnd: null // No colored prefix on groupEnd - }; - const print = function (method, args) { - if (self.__WB_DISABLE_DEV_LOGS) { - return; - } - if (method === 'groupCollapsed') { - // Safari doesn't print all console.groupCollapsed() arguments: - // https://bugs.webkit.org/show_bug.cgi?id=182754 - if (/^((?!chrome|android).)*safari/i.test(navigator.userAgent)) { - console[method](...args); - return; - } - } - const styles = [`background: ${methodToColorMap[method]}`, `border-radius: 0.5em`, `color: white`, `font-weight: bold`, `padding: 2px 0.5em`]; - // When in a group, the workbox prefix is not displayed. - const logPrefix = inGroup ? [] : ['%cworkbox', styles.join(';')]; - console[method](...logPrefix, ...args); - if (method === 'groupCollapsed') { - inGroup = true; - } - if (method === 'groupEnd') { - inGroup = false; - } - }; - // eslint-disable-next-line @typescript-eslint/ban-types - const api = {}; - const loggerMethods = Object.keys(methodToColorMap); - for (const key of loggerMethods) { - const method = key; - api[method] = (...args) => { - print(method, args); - }; - } - return api; - })(); - - /* - Copyright 2018 Google LLC - - Use of this source code is governed by an MIT-style - license that can be found in the LICENSE file or at - https://opensource.org/licenses/MIT. - */ - const messages$1 = { - 'invalid-value': ({ - paramName, - validValueDescription, - value - }) => { - if (!paramName || !validValueDescription) { - throw new Error(`Unexpected input to 'invalid-value' error.`); - } - return `The '${paramName}' parameter was given a value with an ` + `unexpected value. ${validValueDescription} Received a value of ` + `${JSON.stringify(value)}.`; - }, - 'not-an-array': ({ - moduleName, - className, - funcName, - paramName - }) => { - if (!moduleName || !className || !funcName || !paramName) { - throw new Error(`Unexpected input to 'not-an-array' error.`); - } - return `The parameter '${paramName}' passed into ` + `'${moduleName}.${className}.${funcName}()' must be an array.`; - }, - 'incorrect-type': ({ - expectedType, - paramName, - moduleName, - className, - funcName - }) => { - if (!expectedType || !paramName || !moduleName || !funcName) { - throw new Error(`Unexpected input to 'incorrect-type' error.`); - } - const classNameStr = className ? `${className}.` : ''; - return `The parameter '${paramName}' passed into ` + `'${moduleName}.${classNameStr}` + `${funcName}()' must be of type ${expectedType}.`; - }, - 'incorrect-class': ({ - expectedClassName, - paramName, - moduleName, - className, - funcName, - isReturnValueProblem - }) => { - if (!expectedClassName || !moduleName || !funcName) { - throw new Error(`Unexpected input to 'incorrect-class' error.`); - } - const classNameStr = className ? `${className}.` : ''; - if (isReturnValueProblem) { - return `The return value from ` + `'${moduleName}.${classNameStr}${funcName}()' ` + `must be an instance of class ${expectedClassName}.`; - } - return `The parameter '${paramName}' passed into ` + `'${moduleName}.${classNameStr}${funcName}()' ` + `must be an instance of class ${expectedClassName}.`; - }, - 'missing-a-method': ({ - expectedMethod, - paramName, - moduleName, - className, - funcName - }) => { - if (!expectedMethod || !paramName || !moduleName || !className || !funcName) { - throw new Error(`Unexpected input to 'missing-a-method' error.`); - } - return `${moduleName}.${className}.${funcName}() expected the ` + `'${paramName}' parameter to expose a '${expectedMethod}' method.`; - }, - 'add-to-cache-list-unexpected-type': ({ - entry - }) => { - return `An unexpected entry was passed to ` + `'workbox-precaching.PrecacheController.addToCacheList()' The entry ` + `'${JSON.stringify(entry)}' isn't supported. You must supply an array of ` + `strings with one or more characters, objects with a url property or ` + `Request objects.`; - }, - 'add-to-cache-list-conflicting-entries': ({ - firstEntry, - secondEntry - }) => { - if (!firstEntry || !secondEntry) { - throw new Error(`Unexpected input to ` + `'add-to-cache-list-duplicate-entries' error.`); - } - return `Two of the entries passed to ` + `'workbox-precaching.PrecacheController.addToCacheList()' had the URL ` + `${firstEntry} but different revision details. Workbox is ` + `unable to cache and version the asset correctly. Please remove one ` + `of the entries.`; - }, - 'plugin-error-request-will-fetch': ({ - thrownErrorMessage - }) => { - if (!thrownErrorMessage) { - throw new Error(`Unexpected input to ` + `'plugin-error-request-will-fetch', error.`); - } - return `An error was thrown by a plugins 'requestWillFetch()' method. ` + `The thrown error message was: '${thrownErrorMessage}'.`; - }, - 'invalid-cache-name': ({ - cacheNameId, - value - }) => { - if (!cacheNameId) { - throw new Error(`Expected a 'cacheNameId' for error 'invalid-cache-name'`); - } - return `You must provide a name containing at least one character for ` + `setCacheDetails({${cacheNameId}: '...'}). Received a value of ` + `'${JSON.stringify(value)}'`; - }, - 'unregister-route-but-not-found-with-method': ({ - method - }) => { - if (!method) { - throw new Error(`Unexpected input to ` + `'unregister-route-but-not-found-with-method' error.`); - } - return `The route you're trying to unregister was not previously ` + `registered for the method type '${method}'.`; - }, - 'unregister-route-route-not-registered': () => { - return `The route you're trying to unregister was not previously ` + `registered.`; - }, - 'queue-replay-failed': ({ - name - }) => { - return `Replaying the background sync queue '${name}' failed.`; - }, - 'duplicate-queue-name': ({ - name - }) => { - return `The Queue name '${name}' is already being used. ` + `All instances of backgroundSync.Queue must be given unique names.`; - }, - 'expired-test-without-max-age': ({ - methodName, - paramName - }) => { - return `The '${methodName}()' method can only be used when the ` + `'${paramName}' is used in the constructor.`; - }, - 'unsupported-route-type': ({ - moduleName, - className, - funcName, - paramName - }) => { - return `The supplied '${paramName}' parameter was an unsupported type. ` + `Please check the docs for ${moduleName}.${className}.${funcName} for ` + `valid input types.`; - }, - 'not-array-of-class': ({ - value, - expectedClass, - moduleName, - className, - funcName, - paramName - }) => { - return `The supplied '${paramName}' parameter must be an array of ` + `'${expectedClass}' objects. Received '${JSON.stringify(value)},'. ` + `Please check the call to ${moduleName}.${className}.${funcName}() ` + `to fix the issue.`; - }, - 'max-entries-or-age-required': ({ - moduleName, - className, - funcName - }) => { - return `You must define either config.maxEntries or config.maxAgeSeconds` + `in ${moduleName}.${className}.${funcName}`; - }, - 'statuses-or-headers-required': ({ - moduleName, - className, - funcName - }) => { - return `You must define either config.statuses or config.headers` + `in ${moduleName}.${className}.${funcName}`; - }, - 'invalid-string': ({ - moduleName, - funcName, - paramName - }) => { - if (!paramName || !moduleName || !funcName) { - throw new Error(`Unexpected input to 'invalid-string' error.`); - } - return `When using strings, the '${paramName}' parameter must start with ` + `'http' (for cross-origin matches) or '/' (for same-origin matches). ` + `Please see the docs for ${moduleName}.${funcName}() for ` + `more info.`; - }, - 'channel-name-required': () => { - return `You must provide a channelName to construct a ` + `BroadcastCacheUpdate instance.`; - }, - 'invalid-responses-are-same-args': () => { - return `The arguments passed into responsesAreSame() appear to be ` + `invalid. Please ensure valid Responses are used.`; - }, - 'expire-custom-caches-only': () => { - return `You must provide a 'cacheName' property when using the ` + `expiration plugin with a runtime caching strategy.`; - }, - 'unit-must-be-bytes': ({ - normalizedRangeHeader - }) => { - if (!normalizedRangeHeader) { - throw new Error(`Unexpected input to 'unit-must-be-bytes' error.`); - } - return `The 'unit' portion of the Range header must be set to 'bytes'. ` + `The Range header provided was "${normalizedRangeHeader}"`; - }, - 'single-range-only': ({ - normalizedRangeHeader - }) => { - if (!normalizedRangeHeader) { - throw new Error(`Unexpected input to 'single-range-only' error.`); - } - return `Multiple ranges are not supported. Please use a single start ` + `value, and optional end value. The Range header provided was ` + `"${normalizedRangeHeader}"`; - }, - 'invalid-range-values': ({ - normalizedRangeHeader - }) => { - if (!normalizedRangeHeader) { - throw new Error(`Unexpected input to 'invalid-range-values' error.`); - } - return `The Range header is missing both start and end values. At least ` + `one of those values is needed. The Range header provided was ` + `"${normalizedRangeHeader}"`; - }, - 'no-range-header': () => { - return `No Range header was found in the Request provided.`; - }, - 'range-not-satisfiable': ({ - size, - start, - end - }) => { - return `The start (${start}) and end (${end}) values in the Range are ` + `not satisfiable by the cached response, which is ${size} bytes.`; - }, - 'attempt-to-cache-non-get-request': ({ - url, - method - }) => { - return `Unable to cache '${url}' because it is a '${method}' request and ` + `only 'GET' requests can be cached.`; - }, - 'cache-put-with-no-response': ({ - url - }) => { - return `There was an attempt to cache '${url}' but the response was not ` + `defined.`; - }, - 'no-response': ({ - url, - error - }) => { - let message = `The strategy could not generate a response for '${url}'.`; - if (error) { - message += ` The underlying error is ${error}.`; - } - return message; - }, - 'bad-precaching-response': ({ - url, - status - }) => { - return `The precaching request for '${url}' failed` + (status ? ` with an HTTP status of ${status}.` : `.`); - }, - 'non-precached-url': ({ - url - }) => { - return `createHandlerBoundToURL('${url}') was called, but that URL is ` + `not precached. Please pass in a URL that is precached instead.`; - }, - 'add-to-cache-list-conflicting-integrities': ({ - url - }) => { - return `Two of the entries passed to ` + `'workbox-precaching.PrecacheController.addToCacheList()' had the URL ` + `${url} with different integrity values. Please remove one of them.`; - }, - 'missing-precache-entry': ({ - cacheName, - url - }) => { - return `Unable to find a precached response in ${cacheName} for ${url}.`; - }, - 'cross-origin-copy-response': ({ - origin - }) => { - return `workbox-core.copyResponse() can only be used with same-origin ` + `responses. It was passed a response with origin ${origin}.`; - }, - 'opaque-streams-source': ({ - type - }) => { - const message = `One of the workbox-streams sources resulted in an ` + `'${type}' response.`; - if (type === 'opaqueredirect') { - return `${message} Please do not use a navigation request that results ` + `in a redirect as a source.`; - } - return `${message} Please ensure your sources are CORS-enabled.`; - } - }; - - /* - Copyright 2018 Google LLC - - Use of this source code is governed by an MIT-style - license that can be found in the LICENSE file or at - https://opensource.org/licenses/MIT. - */ - const generatorFunction = (code, details = {}) => { - const message = messages$1[code]; - if (!message) { - throw new Error(`Unable to find message for code '${code}'.`); - } - return message(details); - }; - const messageGenerator = generatorFunction; - - /* - Copyright 2018 Google LLC - - Use of this source code is governed by an MIT-style - license that can be found in the LICENSE file or at - https://opensource.org/licenses/MIT. - */ - /** - * Workbox errors should be thrown with this class. - * This allows use to ensure the type easily in tests, - * helps developers identify errors from workbox - * easily and allows use to optimise error - * messages correctly. - * - * @private - */ - class WorkboxError extends Error { - /** - * - * @param {string} errorCode The error code that - * identifies this particular error. - * @param {Object=} details Any relevant arguments - * that will help developers identify issues should - * be added as a key on the context object. - */ - constructor(errorCode, details) { - const message = messageGenerator(errorCode, details); - super(message); - this.name = errorCode; - this.details = details; - } - } - - /* - Copyright 2018 Google LLC - - Use of this source code is governed by an MIT-style - license that can be found in the LICENSE file or at - https://opensource.org/licenses/MIT. - */ - /* - * This method throws if the supplied value is not an array. - * The destructed values are required to produce a meaningful error for users. - * The destructed and restructured object is so it's clear what is - * needed. - */ - const isArray = (value, details) => { - if (!Array.isArray(value)) { - throw new WorkboxError('not-an-array', details); - } - }; - const hasMethod = (object, expectedMethod, details) => { - const type = typeof object[expectedMethod]; - if (type !== 'function') { - details['expectedMethod'] = expectedMethod; - throw new WorkboxError('missing-a-method', details); - } - }; - const isType = (object, expectedType, details) => { - if (typeof object !== expectedType) { - details['expectedType'] = expectedType; - throw new WorkboxError('incorrect-type', details); - } - }; - const isInstance = (object, - // Need the general type to do the check later. - // eslint-disable-next-line @typescript-eslint/ban-types - expectedClass, details) => { - if (!(object instanceof expectedClass)) { - details['expectedClassName'] = expectedClass.name; - throw new WorkboxError('incorrect-class', details); - } - }; - const isOneOf = (value, validValues, details) => { - if (!validValues.includes(value)) { - details['validValueDescription'] = `Valid values are ${JSON.stringify(validValues)}.`; - throw new WorkboxError('invalid-value', details); - } - }; - const isArrayOfClass = (value, - // Need general type to do check later. - expectedClass, - // eslint-disable-line - details) => { - const error = new WorkboxError('not-array-of-class', details); - if (!Array.isArray(value)) { - throw error; - } - for (const item of value) { - if (!(item instanceof expectedClass)) { - throw error; - } - } - }; - const finalAssertExports = { - hasMethod, - isArray, - isInstance, - isOneOf, - isType, - isArrayOfClass - }; - - // @ts-ignore - try { - self['workbox:routing:7.0.0'] && _(); - } catch (e) {} - - /* - Copyright 2018 Google LLC - - Use of this source code is governed by an MIT-style - license that can be found in the LICENSE file or at - https://opensource.org/licenses/MIT. - */ - /** - * The default HTTP method, 'GET', used when there's no specific method - * configured for a route. - * - * @type {string} - * - * @private - */ - const defaultMethod = 'GET'; - /** - * The list of valid HTTP methods associated with requests that could be routed. - * - * @type {Array} - * - * @private - */ - const validMethods = ['DELETE', 'GET', 'HEAD', 'PATCH', 'POST', 'PUT']; - - /* - Copyright 2018 Google LLC - - Use of this source code is governed by an MIT-style - license that can be found in the LICENSE file or at - https://opensource.org/licenses/MIT. - */ - /** - * @param {function()|Object} handler Either a function, or an object with a - * 'handle' method. - * @return {Object} An object with a handle method. - * - * @private - */ - const normalizeHandler = handler => { - if (handler && typeof handler === 'object') { - { - finalAssertExports.hasMethod(handler, 'handle', { - moduleName: 'workbox-routing', - className: 'Route', - funcName: 'constructor', - paramName: 'handler' - }); - } - return handler; - } else { - { - finalAssertExports.isType(handler, 'function', { - moduleName: 'workbox-routing', - className: 'Route', - funcName: 'constructor', - paramName: 'handler' - }); - } - return { - handle: handler - }; - } - }; - - /* - Copyright 2018 Google LLC - - Use of this source code is governed by an MIT-style - license that can be found in the LICENSE file or at - https://opensource.org/licenses/MIT. - */ - /** - * A `Route` consists of a pair of callback functions, "match" and "handler". - * The "match" callback determine if a route should be used to "handle" a - * request by returning a non-falsy value if it can. The "handler" callback - * is called when there is a match and should return a Promise that resolves - * to a `Response`. - * - * @memberof workbox-routing - */ - class Route { - /** - * Constructor for Route class. - * - * @param {workbox-routing~matchCallback} match - * A callback function that determines whether the route matches a given - * `fetch` event by returning a non-falsy value. - * @param {workbox-routing~handlerCallback} handler A callback - * function that returns a Promise resolving to a Response. - * @param {string} [method='GET'] The HTTP method to match the Route - * against. - */ - constructor(match, handler, method = defaultMethod) { - { - finalAssertExports.isType(match, 'function', { - moduleName: 'workbox-routing', - className: 'Route', - funcName: 'constructor', - paramName: 'match' - }); - if (method) { - finalAssertExports.isOneOf(method, validMethods, { - paramName: 'method' - }); - } - } - // These values are referenced directly by Router so cannot be - // altered by minificaton. - this.handler = normalizeHandler(handler); - this.match = match; - this.method = method; - } - /** - * - * @param {workbox-routing-handlerCallback} handler A callback - * function that returns a Promise resolving to a Response - */ - setCatchHandler(handler) { - this.catchHandler = normalizeHandler(handler); - } - } - - /* - Copyright 2018 Google LLC - - Use of this source code is governed by an MIT-style - license that can be found in the LICENSE file or at - https://opensource.org/licenses/MIT. - */ - /** - * RegExpRoute makes it easy to create a regular expression based - * {@link workbox-routing.Route}. - * - * For same-origin requests the RegExp only needs to match part of the URL. For - * requests against third-party servers, you must define a RegExp that matches - * the start of the URL. - * - * @memberof workbox-routing - * @extends workbox-routing.Route - */ - class RegExpRoute extends Route { - /** - * If the regular expression contains - * [capture groups]{@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp#grouping-back-references}, - * the captured values will be passed to the - * {@link workbox-routing~handlerCallback} `params` - * argument. - * - * @param {RegExp} regExp The regular expression to match against URLs. - * @param {workbox-routing~handlerCallback} handler A callback - * function that returns a Promise resulting in a Response. - * @param {string} [method='GET'] The HTTP method to match the Route - * against. - */ - constructor(regExp, handler, method) { - { - finalAssertExports.isInstance(regExp, RegExp, { - moduleName: 'workbox-routing', - className: 'RegExpRoute', - funcName: 'constructor', - paramName: 'pattern' - }); - } - const match = ({ - url - }) => { - const result = regExp.exec(url.href); - // Return immediately if there's no match. - if (!result) { - return; - } - // Require that the match start at the first character in the URL string - // if it's a cross-origin request. - // See https://github.com/GoogleChrome/workbox/issues/281 for the context - // behind this behavior. - if (url.origin !== location.origin && result.index !== 0) { - { - logger.debug(`The regular expression '${regExp.toString()}' only partially matched ` + `against the cross-origin URL '${url.toString()}'. RegExpRoute's will only ` + `handle cross-origin requests if they match the entire URL.`); - } - return; - } - // If the route matches, but there aren't any capture groups defined, then - // this will return [], which is truthy and therefore sufficient to - // indicate a match. - // If there are capture groups, then it will return their values. - return result.slice(1); - }; - super(match, handler, method); - } - } - - /* - Copyright 2018 Google LLC - - Use of this source code is governed by an MIT-style - license that can be found in the LICENSE file or at - https://opensource.org/licenses/MIT. - */ - const getFriendlyURL = url => { - const urlObj = new URL(String(url), location.href); - // See https://github.com/GoogleChrome/workbox/issues/2323 - // We want to include everything, except for the origin if it's same-origin. - return urlObj.href.replace(new RegExp(`^${location.origin}`), ''); - }; - - /* - Copyright 2018 Google LLC - - Use of this source code is governed by an MIT-style - license that can be found in the LICENSE file or at - https://opensource.org/licenses/MIT. - */ - /** - * The Router can be used to process a `FetchEvent` using one or more - * {@link workbox-routing.Route}, responding with a `Response` if - * a matching route exists. - * - * If no route matches a given a request, the Router will use a "default" - * handler if one is defined. - * - * Should the matching Route throw an error, the Router will use a "catch" - * handler if one is defined to gracefully deal with issues and respond with a - * Request. - * - * If a request matches multiple routes, the **earliest** registered route will - * be used to respond to the request. - * - * @memberof workbox-routing - */ - class Router { - /** - * Initializes a new Router. - */ - constructor() { - this._routes = new Map(); - this._defaultHandlerMap = new Map(); - } - /** - * @return {Map>} routes A `Map` of HTTP - * method name ('GET', etc.) to an array of all the corresponding `Route` - * instances that are registered. - */ - get routes() { - return this._routes; - } - /** - * Adds a fetch event listener to respond to events when a route matches - * the event's request. - */ - addFetchListener() { - // See https://github.com/Microsoft/TypeScript/issues/28357#issuecomment-436484705 - self.addEventListener('fetch', event => { - const { - request - } = event; - const responsePromise = this.handleRequest({ - request, - event - }); - if (responsePromise) { - event.respondWith(responsePromise); - } - }); - } - /** - * Adds a message event listener for URLs to cache from the window. - * This is useful to cache resources loaded on the page prior to when the - * service worker started controlling it. - * - * The format of the message data sent from the window should be as follows. - * Where the `urlsToCache` array may consist of URL strings or an array of - * URL string + `requestInit` object (the same as you'd pass to `fetch()`). - * - * ``` - * { - * type: 'CACHE_URLS', - * payload: { - * urlsToCache: [ - * './script1.js', - * './script2.js', - * ['./script3.js', {mode: 'no-cors'}], - * ], - * }, - * } - * ``` - */ - addCacheListener() { - // See https://github.com/Microsoft/TypeScript/issues/28357#issuecomment-436484705 - self.addEventListener('message', event => { - // event.data is type 'any' - // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access - if (event.data && event.data.type === 'CACHE_URLS') { - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment - const { - payload - } = event.data; - { - logger.debug(`Caching URLs from the window`, payload.urlsToCache); - } - const requestPromises = Promise.all(payload.urlsToCache.map(entry => { - if (typeof entry === 'string') { - entry = [entry]; - } - const request = new Request(...entry); - return this.handleRequest({ - request, - event - }); - // TODO(philipwalton): TypeScript errors without this typecast for - // some reason (probably a bug). The real type here should work but - // doesn't: `Array | undefined>`. - })); // TypeScript - event.waitUntil(requestPromises); - // If a MessageChannel was used, reply to the message on success. - if (event.ports && event.ports[0]) { - void requestPromises.then(() => event.ports[0].postMessage(true)); - } - } - }); - } - /** - * Apply the routing rules to a FetchEvent object to get a Response from an - * appropriate Route's handler. - * - * @param {Object} options - * @param {Request} options.request The request to handle. - * @param {ExtendableEvent} options.event The event that triggered the - * request. - * @return {Promise|undefined} A promise is returned if a - * registered route can handle the request. If there is no matching - * route and there's no `defaultHandler`, `undefined` is returned. - */ - handleRequest({ - request, - event - }) { - { - finalAssertExports.isInstance(request, Request, { - moduleName: 'workbox-routing', - className: 'Router', - funcName: 'handleRequest', - paramName: 'options.request' - }); - } - const url = new URL(request.url, location.href); - if (!url.protocol.startsWith('http')) { - { - logger.debug(`Workbox Router only supports URLs that start with 'http'.`); - } - return; - } - const sameOrigin = url.origin === location.origin; - const { - params, - route - } = this.findMatchingRoute({ - event, - request, - sameOrigin, - url - }); - let handler = route && route.handler; - const debugMessages = []; - { - if (handler) { - debugMessages.push([`Found a route to handle this request:`, route]); - if (params) { - debugMessages.push([`Passing the following params to the route's handler:`, params]); - } - } - } - // If we don't have a handler because there was no matching route, then - // fall back to defaultHandler if that's defined. - const method = request.method; - if (!handler && this._defaultHandlerMap.has(method)) { - { - debugMessages.push(`Failed to find a matching route. Falling ` + `back to the default handler for ${method}.`); - } - handler = this._defaultHandlerMap.get(method); - } - if (!handler) { - { - // No handler so Workbox will do nothing. If logs is set of debug - // i.e. verbose, we should print out this information. - logger.debug(`No route found for: ${getFriendlyURL(url)}`); - } - return; - } - { - // We have a handler, meaning Workbox is going to handle the route. - // print the routing details to the console. - logger.groupCollapsed(`Router is responding to: ${getFriendlyURL(url)}`); - debugMessages.forEach(msg => { - if (Array.isArray(msg)) { - logger.log(...msg); - } else { - logger.log(msg); - } - }); - logger.groupEnd(); - } - // Wrap in try and catch in case the handle method throws a synchronous - // error. It should still callback to the catch handler. - let responsePromise; - try { - responsePromise = handler.handle({ - url, - request, - event, - params - }); - } catch (err) { - responsePromise = Promise.reject(err); - } - // Get route's catch handler, if it exists - const catchHandler = route && route.catchHandler; - if (responsePromise instanceof Promise && (this._catchHandler || catchHandler)) { - responsePromise = responsePromise.catch(async err => { - // If there's a route catch handler, process that first - if (catchHandler) { - { - // Still include URL here as it will be async from the console group - // and may not make sense without the URL - logger.groupCollapsed(`Error thrown when responding to: ` + ` ${getFriendlyURL(url)}. Falling back to route's Catch Handler.`); - logger.error(`Error thrown by:`, route); - logger.error(err); - logger.groupEnd(); - } - try { - return await catchHandler.handle({ - url, - request, - event, - params - }); - } catch (catchErr) { - if (catchErr instanceof Error) { - err = catchErr; - } - } - } - if (this._catchHandler) { - { - // Still include URL here as it will be async from the console group - // and may not make sense without the URL - logger.groupCollapsed(`Error thrown when responding to: ` + ` ${getFriendlyURL(url)}. Falling back to global Catch Handler.`); - logger.error(`Error thrown by:`, route); - logger.error(err); - logger.groupEnd(); - } - return this._catchHandler.handle({ - url, - request, - event - }); - } - throw err; - }); - } - return responsePromise; - } - /** - * Checks a request and URL (and optionally an event) against the list of - * registered routes, and if there's a match, returns the corresponding - * route along with any params generated by the match. - * - * @param {Object} options - * @param {URL} options.url - * @param {boolean} options.sameOrigin The result of comparing `url.origin` - * against the current origin. - * @param {Request} options.request The request to match. - * @param {Event} options.event The corresponding event. - * @return {Object} An object with `route` and `params` properties. - * They are populated if a matching route was found or `undefined` - * otherwise. - */ - findMatchingRoute({ - url, - sameOrigin, - request, - event - }) { - const routes = this._routes.get(request.method) || []; - for (const route of routes) { - let params; - // route.match returns type any, not possible to change right now. - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment - const matchResult = route.match({ - url, - sameOrigin, - request, - event - }); - if (matchResult) { - { - // Warn developers that using an async matchCallback is almost always - // not the right thing to do. - if (matchResult instanceof Promise) { - logger.warn(`While routing ${getFriendlyURL(url)}, an async ` + `matchCallback function was used. Please convert the ` + `following route to use a synchronous matchCallback function:`, route); - } - } - // See https://github.com/GoogleChrome/workbox/issues/2079 - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment - params = matchResult; - if (Array.isArray(params) && params.length === 0) { - // Instead of passing an empty array in as params, use undefined. - params = undefined; - } else if (matchResult.constructor === Object && - // eslint-disable-line - Object.keys(matchResult).length === 0) { - // Instead of passing an empty object in as params, use undefined. - params = undefined; - } else if (typeof matchResult === 'boolean') { - // For the boolean value true (rather than just something truth-y), - // don't set params. - // See https://github.com/GoogleChrome/workbox/pull/2134#issuecomment-513924353 - params = undefined; - } - // Return early if have a match. - return { - route, - params - }; - } - } - // If no match was found above, return and empty object. - return {}; - } - /** - * Define a default `handler` that's called when no routes explicitly - * match the incoming request. - * - * Each HTTP method ('GET', 'POST', etc.) gets its own default handler. - * - * Without a default handler, unmatched requests will go against the - * network as if there were no service worker present. - * - * @param {workbox-routing~handlerCallback} handler A callback - * function that returns a Promise resulting in a Response. - * @param {string} [method='GET'] The HTTP method to associate with this - * default handler. Each method has its own default. - */ - setDefaultHandler(handler, method = defaultMethod) { - this._defaultHandlerMap.set(method, normalizeHandler(handler)); - } - /** - * If a Route throws an error while handling a request, this `handler` - * will be called and given a chance to provide a response. - * - * @param {workbox-routing~handlerCallback} handler A callback - * function that returns a Promise resulting in a Response. - */ - setCatchHandler(handler) { - this._catchHandler = normalizeHandler(handler); - } - /** - * Registers a route with the router. - * - * @param {workbox-routing.Route} route The route to register. - */ - registerRoute(route) { - { - finalAssertExports.isType(route, 'object', { - moduleName: 'workbox-routing', - className: 'Router', - funcName: 'registerRoute', - paramName: 'route' - }); - finalAssertExports.hasMethod(route, 'match', { - moduleName: 'workbox-routing', - className: 'Router', - funcName: 'registerRoute', - paramName: 'route' - }); - finalAssertExports.isType(route.handler, 'object', { - moduleName: 'workbox-routing', - className: 'Router', - funcName: 'registerRoute', - paramName: 'route' - }); - finalAssertExports.hasMethod(route.handler, 'handle', { - moduleName: 'workbox-routing', - className: 'Router', - funcName: 'registerRoute', - paramName: 'route.handler' - }); - finalAssertExports.isType(route.method, 'string', { - moduleName: 'workbox-routing', - className: 'Router', - funcName: 'registerRoute', - paramName: 'route.method' - }); - } - if (!this._routes.has(route.method)) { - this._routes.set(route.method, []); - } - // Give precedence to all of the earlier routes by adding this additional - // route to the end of the array. - this._routes.get(route.method).push(route); - } - /** - * Unregisters a route with the router. - * - * @param {workbox-routing.Route} route The route to unregister. - */ - unregisterRoute(route) { - if (!this._routes.has(route.method)) { - throw new WorkboxError('unregister-route-but-not-found-with-method', { - method: route.method - }); - } - const routeIndex = this._routes.get(route.method).indexOf(route); - if (routeIndex > -1) { - this._routes.get(route.method).splice(routeIndex, 1); - } else { - throw new WorkboxError('unregister-route-route-not-registered'); - } - } - } - - /* - Copyright 2019 Google LLC - - Use of this source code is governed by an MIT-style - license that can be found in the LICENSE file or at - https://opensource.org/licenses/MIT. - */ - let defaultRouter; - /** - * Creates a new, singleton Router instance if one does not exist. If one - * does already exist, that instance is returned. - * - * @private - * @return {Router} - */ - const getOrCreateDefaultRouter = () => { - if (!defaultRouter) { - defaultRouter = new Router(); - // The helpers that use the default Router assume these listeners exist. - defaultRouter.addFetchListener(); - defaultRouter.addCacheListener(); - } - return defaultRouter; - }; - - /* - Copyright 2019 Google LLC - - Use of this source code is governed by an MIT-style - license that can be found in the LICENSE file or at - https://opensource.org/licenses/MIT. - */ - /** - * Easily register a RegExp, string, or function with a caching - * strategy to a singleton Router instance. - * - * This method will generate a Route for you if needed and - * call {@link workbox-routing.Router#registerRoute}. - * - * @param {RegExp|string|workbox-routing.Route~matchCallback|workbox-routing.Route} capture - * If the capture param is a `Route`, all other arguments will be ignored. - * @param {workbox-routing~handlerCallback} [handler] A callback - * function that returns a Promise resulting in a Response. This parameter - * is required if `capture` is not a `Route` object. - * @param {string} [method='GET'] The HTTP method to match the Route - * against. - * @return {workbox-routing.Route} The generated `Route`. - * - * @memberof workbox-routing - */ - function registerRoute(capture, handler, method) { - let route; - if (typeof capture === 'string') { - const captureUrl = new URL(capture, location.href); - { - if (!(capture.startsWith('/') || capture.startsWith('http'))) { - throw new WorkboxError('invalid-string', { - moduleName: 'workbox-routing', - funcName: 'registerRoute', - paramName: 'capture' - }); - } - // We want to check if Express-style wildcards are in the pathname only. - // TODO: Remove this log message in v4. - const valueToCheck = capture.startsWith('http') ? captureUrl.pathname : capture; - // See https://github.com/pillarjs/path-to-regexp#parameters - const wildcards = '[*:?+]'; - if (new RegExp(`${wildcards}`).exec(valueToCheck)) { - logger.debug(`The '$capture' parameter contains an Express-style wildcard ` + `character (${wildcards}). Strings are now always interpreted as ` + `exact matches; use a RegExp for partial or wildcard matches.`); - } - } - const matchCallback = ({ - url - }) => { - { - if (url.pathname === captureUrl.pathname && url.origin !== captureUrl.origin) { - logger.debug(`${capture} only partially matches the cross-origin URL ` + `${url.toString()}. This route will only handle cross-origin requests ` + `if they match the entire URL.`); - } - } - return url.href === captureUrl.href; - }; - // If `capture` is a string then `handler` and `method` must be present. - route = new Route(matchCallback, handler, method); - } else if (capture instanceof RegExp) { - // If `capture` is a `RegExp` then `handler` and `method` must be present. - route = new RegExpRoute(capture, handler, method); - } else if (typeof capture === 'function') { - // If `capture` is a function then `handler` and `method` must be present. - route = new Route(capture, handler, method); - } else if (capture instanceof Route) { - route = capture; - } else { - throw new WorkboxError('unsupported-route-type', { - moduleName: 'workbox-routing', - funcName: 'registerRoute', - paramName: 'capture' - }); - } - const defaultRouter = getOrCreateDefaultRouter(); - defaultRouter.registerRoute(route); - return route; - } - - // @ts-ignore - try { - self['workbox:strategies:7.0.0'] && _(); - } catch (e) {} - - /* - Copyright 2018 Google LLC - - Use of this source code is governed by an MIT-style - license that can be found in the LICENSE file or at - https://opensource.org/licenses/MIT. - */ - const cacheOkAndOpaquePlugin = { - /** - * Returns a valid response (to allow caching) if the status is 200 (OK) or - * 0 (opaque). - * - * @param {Object} options - * @param {Response} options.response - * @return {Response|null} - * - * @private - */ - cacheWillUpdate: async ({ - response - }) => { - if (response.status === 200 || response.status === 0) { - return response; - } - return null; - } - }; - - /* - Copyright 2018 Google LLC - - Use of this source code is governed by an MIT-style - license that can be found in the LICENSE file or at - https://opensource.org/licenses/MIT. - */ - const _cacheNameDetails = { - googleAnalytics: 'googleAnalytics', - precache: 'precache-v2', - prefix: 'workbox', - runtime: 'runtime', - suffix: typeof registration !== 'undefined' ? registration.scope : '' - }; - const _createCacheName = cacheName => { - return [_cacheNameDetails.prefix, cacheName, _cacheNameDetails.suffix].filter(value => value && value.length > 0).join('-'); - }; - const eachCacheNameDetail = fn => { - for (const key of Object.keys(_cacheNameDetails)) { - fn(key); - } - }; - const cacheNames = { - updateDetails: details => { - eachCacheNameDetail(key => { - if (typeof details[key] === 'string') { - _cacheNameDetails[key] = details[key]; - } - }); - }, - getGoogleAnalyticsName: userCacheName => { - return userCacheName || _createCacheName(_cacheNameDetails.googleAnalytics); - }, - getPrecacheName: userCacheName => { - return userCacheName || _createCacheName(_cacheNameDetails.precache); - }, - getPrefix: () => { - return _cacheNameDetails.prefix; - }, - getRuntimeName: userCacheName => { - return userCacheName || _createCacheName(_cacheNameDetails.runtime); - }, - getSuffix: () => { - return _cacheNameDetails.suffix; - } - }; - - /* - Copyright 2020 Google LLC - Use of this source code is governed by an MIT-style - license that can be found in the LICENSE file or at - https://opensource.org/licenses/MIT. - */ - function stripParams(fullURL, ignoreParams) { - const strippedURL = new URL(fullURL); - for (const param of ignoreParams) { - strippedURL.searchParams.delete(param); - } - return strippedURL.href; - } - /** - * Matches an item in the cache, ignoring specific URL params. This is similar - * to the `ignoreSearch` option, but it allows you to ignore just specific - * params (while continuing to match on the others). - * - * @private - * @param {Cache} cache - * @param {Request} request - * @param {Object} matchOptions - * @param {Array} ignoreParams - * @return {Promise} - */ - async function cacheMatchIgnoreParams(cache, request, ignoreParams, matchOptions) { - const strippedRequestURL = stripParams(request.url, ignoreParams); - // If the request doesn't include any ignored params, match as normal. - if (request.url === strippedRequestURL) { - return cache.match(request, matchOptions); - } - // Otherwise, match by comparing keys - const keysOptions = Object.assign(Object.assign({}, matchOptions), { - ignoreSearch: true - }); - const cacheKeys = await cache.keys(request, keysOptions); - for (const cacheKey of cacheKeys) { - const strippedCacheKeyURL = stripParams(cacheKey.url, ignoreParams); - if (strippedRequestURL === strippedCacheKeyURL) { - return cache.match(cacheKey, matchOptions); - } - } - return; - } - - /* - Copyright 2018 Google LLC - - Use of this source code is governed by an MIT-style - license that can be found in the LICENSE file or at - https://opensource.org/licenses/MIT. - */ - /** - * The Deferred class composes Promises in a way that allows for them to be - * resolved or rejected from outside the constructor. In most cases promises - * should be used directly, but Deferreds can be necessary when the logic to - * resolve a promise must be separate. - * - * @private - */ - class Deferred { - /** - * Creates a promise and exposes its resolve and reject functions as methods. - */ - constructor() { - this.promise = new Promise((resolve, reject) => { - this.resolve = resolve; - this.reject = reject; - }); - } - } - - /* - Copyright 2018 Google LLC - - Use of this source code is governed by an MIT-style - license that can be found in the LICENSE file or at - https://opensource.org/licenses/MIT. - */ - // Callbacks to be executed whenever there's a quota error. - // Can't change Function type right now. - // eslint-disable-next-line @typescript-eslint/ban-types - const quotaErrorCallbacks = new Set(); - - /* - Copyright 2018 Google LLC - - Use of this source code is governed by an MIT-style - license that can be found in the LICENSE file or at - https://opensource.org/licenses/MIT. - */ - /** - * Runs all of the callback functions, one at a time sequentially, in the order - * in which they were registered. - * - * @memberof workbox-core - * @private - */ - async function executeQuotaErrorCallbacks() { - { - logger.log(`About to run ${quotaErrorCallbacks.size} ` + `callbacks to clean up caches.`); - } - for (const callback of quotaErrorCallbacks) { - await callback(); - { - logger.log(callback, 'is complete.'); - } - } - { - logger.log('Finished running callbacks.'); - } - } - - /* - Copyright 2019 Google LLC - Use of this source code is governed by an MIT-style - license that can be found in the LICENSE file or at - https://opensource.org/licenses/MIT. - */ - /** - * Returns a promise that resolves and the passed number of milliseconds. - * This utility is an async/await-friendly version of `setTimeout`. - * - * @param {number} ms - * @return {Promise} - * @private - */ - function timeout(ms) { - return new Promise(resolve => setTimeout(resolve, ms)); - } - - /* - Copyright 2020 Google LLC - - Use of this source code is governed by an MIT-style - license that can be found in the LICENSE file or at - https://opensource.org/licenses/MIT. - */ - function toRequest(input) { - return typeof input === 'string' ? new Request(input) : input; - } - /** - * A class created every time a Strategy instance instance calls - * {@link workbox-strategies.Strategy~handle} or - * {@link workbox-strategies.Strategy~handleAll} that wraps all fetch and - * cache actions around plugin callbacks and keeps track of when the strategy - * is "done" (i.e. all added `event.waitUntil()` promises have resolved). - * - * @memberof workbox-strategies - */ - class StrategyHandler { - /** - * Creates a new instance associated with the passed strategy and event - * that's handling the request. - * - * The constructor also initializes the state that will be passed to each of - * the plugins handling this request. - * - * @param {workbox-strategies.Strategy} strategy - * @param {Object} options - * @param {Request|string} options.request A request to run this strategy for. - * @param {ExtendableEvent} options.event The event associated with the - * request. - * @param {URL} [options.url] - * @param {*} [options.params] The return value from the - * {@link workbox-routing~matchCallback} (if applicable). - */ - constructor(strategy, options) { - this._cacheKeys = {}; - /** - * The request the strategy is performing (passed to the strategy's - * `handle()` or `handleAll()` method). - * @name request - * @instance - * @type {Request} - * @memberof workbox-strategies.StrategyHandler - */ - /** - * The event associated with this request. - * @name event - * @instance - * @type {ExtendableEvent} - * @memberof workbox-strategies.StrategyHandler - */ - /** - * A `URL` instance of `request.url` (if passed to the strategy's - * `handle()` or `handleAll()` method). - * Note: the `url` param will be present if the strategy was invoked - * from a workbox `Route` object. - * @name url - * @instance - * @type {URL|undefined} - * @memberof workbox-strategies.StrategyHandler - */ - /** - * A `param` value (if passed to the strategy's - * `handle()` or `handleAll()` method). - * Note: the `param` param will be present if the strategy was invoked - * from a workbox `Route` object and the - * {@link workbox-routing~matchCallback} returned - * a truthy value (it will be that value). - * @name params - * @instance - * @type {*|undefined} - * @memberof workbox-strategies.StrategyHandler - */ - { - finalAssertExports.isInstance(options.event, ExtendableEvent, { - moduleName: 'workbox-strategies', - className: 'StrategyHandler', - funcName: 'constructor', - paramName: 'options.event' - }); - } - Object.assign(this, options); - this.event = options.event; - this._strategy = strategy; - this._handlerDeferred = new Deferred(); - this._extendLifetimePromises = []; - // Copy the plugins list (since it's mutable on the strategy), - // so any mutations don't affect this handler instance. - this._plugins = [...strategy.plugins]; - this._pluginStateMap = new Map(); - for (const plugin of this._plugins) { - this._pluginStateMap.set(plugin, {}); - } - this.event.waitUntil(this._handlerDeferred.promise); - } - /** - * Fetches a given request (and invokes any applicable plugin callback - * methods) using the `fetchOptions` (for non-navigation requests) and - * `plugins` defined on the `Strategy` object. - * - * The following plugin lifecycle methods are invoked when using this method: - * - `requestWillFetch()` - * - `fetchDidSucceed()` - * - `fetchDidFail()` - * - * @param {Request|string} input The URL or request to fetch. - * @return {Promise} - */ - async fetch(input) { - const { - event - } = this; - let request = toRequest(input); - if (request.mode === 'navigate' && event instanceof FetchEvent && event.preloadResponse) { - const possiblePreloadResponse = await event.preloadResponse; - if (possiblePreloadResponse) { - { - logger.log(`Using a preloaded navigation response for ` + `'${getFriendlyURL(request.url)}'`); - } - return possiblePreloadResponse; - } - } - // If there is a fetchDidFail plugin, we need to save a clone of the - // original request before it's either modified by a requestWillFetch - // plugin or before the original request's body is consumed via fetch(). - const originalRequest = this.hasCallback('fetchDidFail') ? request.clone() : null; - try { - for (const cb of this.iterateCallbacks('requestWillFetch')) { - request = await cb({ - request: request.clone(), - event - }); - } - } catch (err) { - if (err instanceof Error) { - throw new WorkboxError('plugin-error-request-will-fetch', { - thrownErrorMessage: err.message - }); - } - } - // The request can be altered by plugins with `requestWillFetch` making - // the original request (most likely from a `fetch` event) different - // from the Request we make. Pass both to `fetchDidFail` to aid debugging. - const pluginFilteredRequest = request.clone(); - try { - let fetchResponse; - // See https://github.com/GoogleChrome/workbox/issues/1796 - fetchResponse = await fetch(request, request.mode === 'navigate' ? undefined : this._strategy.fetchOptions); - if ("development" !== 'production') { - logger.debug(`Network request for ` + `'${getFriendlyURL(request.url)}' returned a response with ` + `status '${fetchResponse.status}'.`); - } - for (const callback of this.iterateCallbacks('fetchDidSucceed')) { - fetchResponse = await callback({ - event, - request: pluginFilteredRequest, - response: fetchResponse - }); - } - return fetchResponse; - } catch (error) { - { - logger.log(`Network request for ` + `'${getFriendlyURL(request.url)}' threw an error.`, error); - } - // `originalRequest` will only exist if a `fetchDidFail` callback - // is being used (see above). - if (originalRequest) { - await this.runCallbacks('fetchDidFail', { - error: error, - event, - originalRequest: originalRequest.clone(), - request: pluginFilteredRequest.clone() - }); - } - throw error; - } - } - /** - * Calls `this.fetch()` and (in the background) runs `this.cachePut()` on - * the response generated by `this.fetch()`. - * - * The call to `this.cachePut()` automatically invokes `this.waitUntil()`, - * so you do not have to manually call `waitUntil()` on the event. - * - * @param {Request|string} input The request or URL to fetch and cache. - * @return {Promise} - */ - async fetchAndCachePut(input) { - const response = await this.fetch(input); - const responseClone = response.clone(); - void this.waitUntil(this.cachePut(input, responseClone)); - return response; - } - /** - * Matches a request from the cache (and invokes any applicable plugin - * callback methods) using the `cacheName`, `matchOptions`, and `plugins` - * defined on the strategy object. - * - * The following plugin lifecycle methods are invoked when using this method: - * - cacheKeyWillByUsed() - * - cachedResponseWillByUsed() - * - * @param {Request|string} key The Request or URL to use as the cache key. - * @return {Promise} A matching response, if found. - */ - async cacheMatch(key) { - const request = toRequest(key); - let cachedResponse; - const { - cacheName, - matchOptions - } = this._strategy; - const effectiveRequest = await this.getCacheKey(request, 'read'); - const multiMatchOptions = Object.assign(Object.assign({}, matchOptions), { - cacheName - }); - cachedResponse = await caches.match(effectiveRequest, multiMatchOptions); - { - if (cachedResponse) { - logger.debug(`Found a cached response in '${cacheName}'.`); - } else { - logger.debug(`No cached response found in '${cacheName}'.`); - } - } - for (const callback of this.iterateCallbacks('cachedResponseWillBeUsed')) { - cachedResponse = (await callback({ - cacheName, - matchOptions, - cachedResponse, - request: effectiveRequest, - event: this.event - })) || undefined; - } - return cachedResponse; - } - /** - * Puts a request/response pair in the cache (and invokes any applicable - * plugin callback methods) using the `cacheName` and `plugins` defined on - * the strategy object. - * - * The following plugin lifecycle methods are invoked when using this method: - * - cacheKeyWillByUsed() - * - cacheWillUpdate() - * - cacheDidUpdate() - * - * @param {Request|string} key The request or URL to use as the cache key. - * @param {Response} response The response to cache. - * @return {Promise} `false` if a cacheWillUpdate caused the response - * not be cached, and `true` otherwise. - */ - async cachePut(key, response) { - const request = toRequest(key); - // Run in the next task to avoid blocking other cache reads. - // https://github.com/w3c/ServiceWorker/issues/1397 - await timeout(0); - const effectiveRequest = await this.getCacheKey(request, 'write'); - { - if (effectiveRequest.method && effectiveRequest.method !== 'GET') { - throw new WorkboxError('attempt-to-cache-non-get-request', { - url: getFriendlyURL(effectiveRequest.url), - method: effectiveRequest.method - }); - } - // See https://github.com/GoogleChrome/workbox/issues/2818 - const vary = response.headers.get('Vary'); - if (vary) { - logger.debug(`The response for ${getFriendlyURL(effectiveRequest.url)} ` + `has a 'Vary: ${vary}' header. ` + `Consider setting the {ignoreVary: true} option on your strategy ` + `to ensure cache matching and deletion works as expected.`); - } - } - if (!response) { - { - logger.error(`Cannot cache non-existent response for ` + `'${getFriendlyURL(effectiveRequest.url)}'.`); - } - throw new WorkboxError('cache-put-with-no-response', { - url: getFriendlyURL(effectiveRequest.url) - }); - } - const responseToCache = await this._ensureResponseSafeToCache(response); - if (!responseToCache) { - { - logger.debug(`Response '${getFriendlyURL(effectiveRequest.url)}' ` + `will not be cached.`, responseToCache); - } - return false; - } - const { - cacheName, - matchOptions - } = this._strategy; - const cache = await self.caches.open(cacheName); - const hasCacheUpdateCallback = this.hasCallback('cacheDidUpdate'); - const oldResponse = hasCacheUpdateCallback ? await cacheMatchIgnoreParams( - // TODO(philipwalton): the `__WB_REVISION__` param is a precaching - // feature. Consider into ways to only add this behavior if using - // precaching. - cache, effectiveRequest.clone(), ['__WB_REVISION__'], matchOptions) : null; - { - logger.debug(`Updating the '${cacheName}' cache with a new Response ` + `for ${getFriendlyURL(effectiveRequest.url)}.`); - } - try { - await cache.put(effectiveRequest, hasCacheUpdateCallback ? responseToCache.clone() : responseToCache); - } catch (error) { - if (error instanceof Error) { - // See https://developer.mozilla.org/en-US/docs/Web/API/DOMException#exception-QuotaExceededError - if (error.name === 'QuotaExceededError') { - await executeQuotaErrorCallbacks(); - } - throw error; - } - } - for (const callback of this.iterateCallbacks('cacheDidUpdate')) { - await callback({ - cacheName, - oldResponse, - newResponse: responseToCache.clone(), - request: effectiveRequest, - event: this.event - }); - } - return true; - } - /** - * Checks the list of plugins for the `cacheKeyWillBeUsed` callback, and - * executes any of those callbacks found in sequence. The final `Request` - * object returned by the last plugin is treated as the cache key for cache - * reads and/or writes. If no `cacheKeyWillBeUsed` plugin callbacks have - * been registered, the passed request is returned unmodified - * - * @param {Request} request - * @param {string} mode - * @return {Promise} - */ - async getCacheKey(request, mode) { - const key = `${request.url} | ${mode}`; - if (!this._cacheKeys[key]) { - let effectiveRequest = request; - for (const callback of this.iterateCallbacks('cacheKeyWillBeUsed')) { - effectiveRequest = toRequest(await callback({ - mode, - request: effectiveRequest, - event: this.event, - // params has a type any can't change right now. - params: this.params // eslint-disable-line - })); - } - this._cacheKeys[key] = effectiveRequest; - } - return this._cacheKeys[key]; - } - /** - * Returns true if the strategy has at least one plugin with the given - * callback. - * - * @param {string} name The name of the callback to check for. - * @return {boolean} - */ - hasCallback(name) { - for (const plugin of this._strategy.plugins) { - if (name in plugin) { - return true; - } - } - return false; - } - /** - * Runs all plugin callbacks matching the given name, in order, passing the - * given param object (merged ith the current plugin state) as the only - * argument. - * - * Note: since this method runs all plugins, it's not suitable for cases - * where the return value of a callback needs to be applied prior to calling - * the next callback. See - * {@link workbox-strategies.StrategyHandler#iterateCallbacks} - * below for how to handle that case. - * - * @param {string} name The name of the callback to run within each plugin. - * @param {Object} param The object to pass as the first (and only) param - * when executing each callback. This object will be merged with the - * current plugin state prior to callback execution. - */ - async runCallbacks(name, param) { - for (const callback of this.iterateCallbacks(name)) { - // TODO(philipwalton): not sure why `any` is needed. It seems like - // this should work with `as WorkboxPluginCallbackParam[C]`. - await callback(param); - } - } - /** - * Accepts a callback and returns an iterable of matching plugin callbacks, - * where each callback is wrapped with the current handler state (i.e. when - * you call each callback, whatever object parameter you pass it will - * be merged with the plugin's current state). - * - * @param {string} name The name fo the callback to run - * @return {Array} - */ - *iterateCallbacks(name) { - for (const plugin of this._strategy.plugins) { - if (typeof plugin[name] === 'function') { - const state = this._pluginStateMap.get(plugin); - const statefulCallback = param => { - const statefulParam = Object.assign(Object.assign({}, param), { - state - }); - // TODO(philipwalton): not sure why `any` is needed. It seems like - // this should work with `as WorkboxPluginCallbackParam[C]`. - return plugin[name](statefulParam); - }; - yield statefulCallback; - } - } - } - /** - * Adds a promise to the - * [extend lifetime promises]{@link https://w3c.github.io/ServiceWorker/#extendableevent-extend-lifetime-promises} - * of the event event associated with the request being handled (usually a - * `FetchEvent`). - * - * Note: you can await - * {@link workbox-strategies.StrategyHandler~doneWaiting} - * to know when all added promises have settled. - * - * @param {Promise} promise A promise to add to the extend lifetime promises - * of the event that triggered the request. - */ - waitUntil(promise) { - this._extendLifetimePromises.push(promise); - return promise; - } - /** - * Returns a promise that resolves once all promises passed to - * {@link workbox-strategies.StrategyHandler~waitUntil} - * have settled. - * - * Note: any work done after `doneWaiting()` settles should be manually - * passed to an event's `waitUntil()` method (not this handler's - * `waitUntil()` method), otherwise the service worker thread my be killed - * prior to your work completing. - */ - async doneWaiting() { - let promise; - while (promise = this._extendLifetimePromises.shift()) { - await promise; - } - } - /** - * Stops running the strategy and immediately resolves any pending - * `waitUntil()` promises. - */ - destroy() { - this._handlerDeferred.resolve(null); - } - /** - * This method will call cacheWillUpdate on the available plugins (or use - * status === 200) to determine if the Response is safe and valid to cache. - * - * @param {Request} options.request - * @param {Response} options.response - * @return {Promise} - * - * @private - */ - async _ensureResponseSafeToCache(response) { - let responseToCache = response; - let pluginsUsed = false; - for (const callback of this.iterateCallbacks('cacheWillUpdate')) { - responseToCache = (await callback({ - request: this.request, - response: responseToCache, - event: this.event - })) || undefined; - pluginsUsed = true; - if (!responseToCache) { - break; - } - } - if (!pluginsUsed) { - if (responseToCache && responseToCache.status !== 200) { - responseToCache = undefined; - } - { - if (responseToCache) { - if (responseToCache.status !== 200) { - if (responseToCache.status === 0) { - logger.warn(`The response for '${this.request.url}' ` + `is an opaque response. The caching strategy that you're ` + `using will not cache opaque responses by default.`); - } else { - logger.debug(`The response for '${this.request.url}' ` + `returned a status code of '${response.status}' and won't ` + `be cached as a result.`); - } - } - } - } - } - return responseToCache; - } - } - - /* - Copyright 2020 Google LLC - - Use of this source code is governed by an MIT-style - license that can be found in the LICENSE file or at - https://opensource.org/licenses/MIT. - */ - /** - * An abstract base class that all other strategy classes must extend from: - * - * @memberof workbox-strategies - */ - class Strategy { - /** - * Creates a new instance of the strategy and sets all documented option - * properties as public instance properties. - * - * Note: if a custom strategy class extends the base Strategy class and does - * not need more than these properties, it does not need to define its own - * constructor. - * - * @param {Object} [options] - * @param {string} [options.cacheName] Cache name to store and retrieve - * requests. Defaults to the cache names provided by - * {@link workbox-core.cacheNames}. - * @param {Array} [options.plugins] [Plugins]{@link https://developers.google.com/web/tools/workbox/guides/using-plugins} - * to use in conjunction with this caching strategy. - * @param {Object} [options.fetchOptions] Values passed along to the - * [`init`](https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch#Parameters) - * of [non-navigation](https://github.com/GoogleChrome/workbox/issues/1796) - * `fetch()` requests made by this strategy. - * @param {Object} [options.matchOptions] The - * [`CacheQueryOptions`]{@link https://w3c.github.io/ServiceWorker/#dictdef-cachequeryoptions} - * for any `cache.match()` or `cache.put()` calls made by this strategy. - */ - constructor(options = {}) { - /** - * Cache name to store and retrieve - * requests. Defaults to the cache names provided by - * {@link workbox-core.cacheNames}. - * - * @type {string} - */ - this.cacheName = cacheNames.getRuntimeName(options.cacheName); - /** - * The list - * [Plugins]{@link https://developers.google.com/web/tools/workbox/guides/using-plugins} - * used by this strategy. - * - * @type {Array} - */ - this.plugins = options.plugins || []; - /** - * Values passed along to the - * [`init`]{@link https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch#Parameters} - * of all fetch() requests made by this strategy. - * - * @type {Object} - */ - this.fetchOptions = options.fetchOptions; - /** - * The - * [`CacheQueryOptions`]{@link https://w3c.github.io/ServiceWorker/#dictdef-cachequeryoptions} - * for any `cache.match()` or `cache.put()` calls made by this strategy. - * - * @type {Object} - */ - this.matchOptions = options.matchOptions; - } - /** - * Perform a request strategy and returns a `Promise` that will resolve with - * a `Response`, invoking all relevant plugin callbacks. - * - * When a strategy instance is registered with a Workbox - * {@link workbox-routing.Route}, this method is automatically - * called when the route matches. - * - * Alternatively, this method can be used in a standalone `FetchEvent` - * listener by passing it to `event.respondWith()`. - * - * @param {FetchEvent|Object} options A `FetchEvent` or an object with the - * properties listed below. - * @param {Request|string} options.request A request to run this strategy for. - * @param {ExtendableEvent} options.event The event associated with the - * request. - * @param {URL} [options.url] - * @param {*} [options.params] - */ - handle(options) { - const [responseDone] = this.handleAll(options); - return responseDone; - } - /** - * Similar to {@link workbox-strategies.Strategy~handle}, but - * instead of just returning a `Promise` that resolves to a `Response` it - * it will return an tuple of `[response, done]` promises, where the former - * (`response`) is equivalent to what `handle()` returns, and the latter is a - * Promise that will resolve once any promises that were added to - * `event.waitUntil()` as part of performing the strategy have completed. - * - * You can await the `done` promise to ensure any extra work performed by - * the strategy (usually caching responses) completes successfully. - * - * @param {FetchEvent|Object} options A `FetchEvent` or an object with the - * properties listed below. - * @param {Request|string} options.request A request to run this strategy for. - * @param {ExtendableEvent} options.event The event associated with the - * request. - * @param {URL} [options.url] - * @param {*} [options.params] - * @return {Array} A tuple of [response, done] - * promises that can be used to determine when the response resolves as - * well as when the handler has completed all its work. - */ - handleAll(options) { - // Allow for flexible options to be passed. - if (options instanceof FetchEvent) { - options = { - event: options, - request: options.request - }; - } - const event = options.event; - const request = typeof options.request === 'string' ? new Request(options.request) : options.request; - const params = 'params' in options ? options.params : undefined; - const handler = new StrategyHandler(this, { - event, - request, - params - }); - const responseDone = this._getResponse(handler, request, event); - const handlerDone = this._awaitComplete(responseDone, handler, request, event); - // Return an array of promises, suitable for use with Promise.all(). - return [responseDone, handlerDone]; - } - async _getResponse(handler, request, event) { - await handler.runCallbacks('handlerWillStart', { - event, - request - }); - let response = undefined; - try { - response = await this._handle(request, handler); - // The "official" Strategy subclasses all throw this error automatically, - // but in case a third-party Strategy doesn't, ensure that we have a - // consistent failure when there's no response or an error response. - if (!response || response.type === 'error') { - throw new WorkboxError('no-response', { - url: request.url - }); - } - } catch (error) { - if (error instanceof Error) { - for (const callback of handler.iterateCallbacks('handlerDidError')) { - response = await callback({ - error, - event, - request - }); - if (response) { - break; - } - } - } - if (!response) { - throw error; - } else { - logger.log(`While responding to '${getFriendlyURL(request.url)}', ` + `an ${error instanceof Error ? error.toString() : ''} error occurred. Using a fallback response provided by ` + `a handlerDidError plugin.`); - } - } - for (const callback of handler.iterateCallbacks('handlerWillRespond')) { - response = await callback({ - event, - request, - response - }); - } - return response; - } - async _awaitComplete(responseDone, handler, request, event) { - let response; - let error; - try { - response = await responseDone; - } catch (error) { - // Ignore errors, as response errors should be caught via the `response` - // promise above. The `done` promise will only throw for errors in - // promises passed to `handler.waitUntil()`. - } - try { - await handler.runCallbacks('handlerDidRespond', { - event, - request, - response - }); - await handler.doneWaiting(); - } catch (waitUntilError) { - if (waitUntilError instanceof Error) { - error = waitUntilError; - } - } - await handler.runCallbacks('handlerDidComplete', { - event, - request, - response, - error: error - }); - handler.destroy(); - if (error) { - throw error; - } - } - } - /** - * Classes extending the `Strategy` based class should implement this method, - * and leverage the {@link workbox-strategies.StrategyHandler} - * arg to perform all fetching and cache logic, which will ensure all relevant - * cache, cache options, fetch options and plugins are used (per the current - * strategy instance). - * - * @name _handle - * @instance - * @abstract - * @function - * @param {Request} request - * @param {workbox-strategies.StrategyHandler} handler - * @return {Promise} - * - * @memberof workbox-strategies.Strategy - */ - - /* - Copyright 2018 Google LLC - - Use of this source code is governed by an MIT-style - license that can be found in the LICENSE file or at - https://opensource.org/licenses/MIT. - */ - const messages = { - strategyStart: (strategyName, request) => `Using ${strategyName} to respond to '${getFriendlyURL(request.url)}'`, - printFinalResponse: response => { - if (response) { - logger.groupCollapsed(`View the final response here.`); - logger.log(response || '[No response returned]'); - logger.groupEnd(); - } - } - }; - - /* - Copyright 2018 Google LLC - - Use of this source code is governed by an MIT-style - license that can be found in the LICENSE file or at - https://opensource.org/licenses/MIT. - */ - /** - * An implementation of a - * [network first](https://developer.chrome.com/docs/workbox/caching-strategies-overview/#network-first-falling-back-to-cache) - * request strategy. - * - * By default, this strategy will cache responses with a 200 status code as - * well as [opaque responses](https://developer.chrome.com/docs/workbox/caching-resources-during-runtime/#opaque-responses). - * Opaque responses are are cross-origin requests where the response doesn't - * support [CORS](https://enable-cors.org/). - * - * If the network request fails, and there is no cache match, this will throw - * a `WorkboxError` exception. - * - * @extends workbox-strategies.Strategy - * @memberof workbox-strategies - */ - class NetworkFirst extends Strategy { - /** - * @param {Object} [options] - * @param {string} [options.cacheName] Cache name to store and retrieve - * requests. Defaults to cache names provided by - * {@link workbox-core.cacheNames}. - * @param {Array} [options.plugins] [Plugins]{@link https://developers.google.com/web/tools/workbox/guides/using-plugins} - * to use in conjunction with this caching strategy. - * @param {Object} [options.fetchOptions] Values passed along to the - * [`init`](https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch#Parameters) - * of [non-navigation](https://github.com/GoogleChrome/workbox/issues/1796) - * `fetch()` requests made by this strategy. - * @param {Object} [options.matchOptions] [`CacheQueryOptions`](https://w3c.github.io/ServiceWorker/#dictdef-cachequeryoptions) - * @param {number} [options.networkTimeoutSeconds] If set, any network requests - * that fail to respond within the timeout will fallback to the cache. - * - * This option can be used to combat - * "[lie-fi]{@link https://developers.google.com/web/fundamentals/performance/poor-connectivity/#lie-fi}" - * scenarios. - */ - constructor(options = {}) { - super(options); - // If this instance contains no plugins with a 'cacheWillUpdate' callback, - // prepend the `cacheOkAndOpaquePlugin` plugin to the plugins list. - if (!this.plugins.some(p => 'cacheWillUpdate' in p)) { - this.plugins.unshift(cacheOkAndOpaquePlugin); - } - this._networkTimeoutSeconds = options.networkTimeoutSeconds || 0; - { - if (this._networkTimeoutSeconds) { - finalAssertExports.isType(this._networkTimeoutSeconds, 'number', { - moduleName: 'workbox-strategies', - className: this.constructor.name, - funcName: 'constructor', - paramName: 'networkTimeoutSeconds' - }); - } - } - } - /** - * @private - * @param {Request|string} request A request to run this strategy for. - * @param {workbox-strategies.StrategyHandler} handler The event that - * triggered the request. - * @return {Promise} - */ - async _handle(request, handler) { - const logs = []; - { - finalAssertExports.isInstance(request, Request, { - moduleName: 'workbox-strategies', - className: this.constructor.name, - funcName: 'handle', - paramName: 'makeRequest' - }); - } - const promises = []; - let timeoutId; - if (this._networkTimeoutSeconds) { - const { - id, - promise - } = this._getTimeoutPromise({ - request, - logs, - handler - }); - timeoutId = id; - promises.push(promise); - } - const networkPromise = this._getNetworkPromise({ - timeoutId, - request, - logs, - handler - }); - promises.push(networkPromise); - const response = await handler.waitUntil((async () => { - // Promise.race() will resolve as soon as the first promise resolves. - return (await handler.waitUntil(Promise.race(promises))) || ( - // If Promise.race() resolved with null, it might be due to a network - // timeout + a cache miss. If that were to happen, we'd rather wait until - // the networkPromise resolves instead of returning null. - // Note that it's fine to await an already-resolved promise, so we don't - // have to check to see if it's still "in flight". - await networkPromise); - })()); - { - logger.groupCollapsed(messages.strategyStart(this.constructor.name, request)); - for (const log of logs) { - logger.log(log); - } - messages.printFinalResponse(response); - logger.groupEnd(); - } - if (!response) { - throw new WorkboxError('no-response', { - url: request.url - }); - } - return response; - } - /** - * @param {Object} options - * @param {Request} options.request - * @param {Array} options.logs A reference to the logs array - * @param {Event} options.event - * @return {Promise} - * - * @private - */ - _getTimeoutPromise({ - request, - logs, - handler - }) { - let timeoutId; - const timeoutPromise = new Promise(resolve => { - const onNetworkTimeout = async () => { - { - logs.push(`Timing out the network response at ` + `${this._networkTimeoutSeconds} seconds.`); - } - resolve(await handler.cacheMatch(request)); - }; - timeoutId = setTimeout(onNetworkTimeout, this._networkTimeoutSeconds * 1000); - }); - return { - promise: timeoutPromise, - id: timeoutId - }; - } - /** - * @param {Object} options - * @param {number|undefined} options.timeoutId - * @param {Request} options.request - * @param {Array} options.logs A reference to the logs Array. - * @param {Event} options.event - * @return {Promise} - * - * @private - */ - async _getNetworkPromise({ - timeoutId, - request, - logs, - handler - }) { - let error; - let response; - try { - response = await handler.fetchAndCachePut(request); - } catch (fetchError) { - if (fetchError instanceof Error) { - error = fetchError; - } - } - if (timeoutId) { - clearTimeout(timeoutId); - } - { - if (response) { - logs.push(`Got response from network.`); - } else { - logs.push(`Unable to get a response from the network. Will respond ` + `with a cached response.`); - } - } - if (error || !response) { - response = await handler.cacheMatch(request); - { - if (response) { - logs.push(`Found a cached response in the '${this.cacheName}'` + ` cache.`); - } else { - logs.push(`No response found in the '${this.cacheName}' cache.`); - } - } - } - return response; - } - } - - /* - Copyright 2018 Google LLC - - Use of this source code is governed by an MIT-style - license that can be found in the LICENSE file or at - https://opensource.org/licenses/MIT. - */ - /** - * An implementation of a - * [network-only](https://developer.chrome.com/docs/workbox/caching-strategies-overview/#network-only) - * request strategy. - * - * This class is useful if you want to take advantage of any - * [Workbox plugins](https://developer.chrome.com/docs/workbox/using-plugins/). - * - * If the network request fails, this will throw a `WorkboxError` exception. - * - * @extends workbox-strategies.Strategy - * @memberof workbox-strategies - */ - class NetworkOnly extends Strategy { - /** - * @param {Object} [options] - * @param {Array} [options.plugins] [Plugins]{@link https://developers.google.com/web/tools/workbox/guides/using-plugins} - * to use in conjunction with this caching strategy. - * @param {Object} [options.fetchOptions] Values passed along to the - * [`init`](https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch#Parameters) - * of [non-navigation](https://github.com/GoogleChrome/workbox/issues/1796) - * `fetch()` requests made by this strategy. - * @param {number} [options.networkTimeoutSeconds] If set, any network requests - * that fail to respond within the timeout will result in a network error. - */ - constructor(options = {}) { - super(options); - this._networkTimeoutSeconds = options.networkTimeoutSeconds || 0; - } - /** - * @private - * @param {Request|string} request A request to run this strategy for. - * @param {workbox-strategies.StrategyHandler} handler The event that - * triggered the request. - * @return {Promise} - */ - async _handle(request, handler) { - { - finalAssertExports.isInstance(request, Request, { - moduleName: 'workbox-strategies', - className: this.constructor.name, - funcName: '_handle', - paramName: 'request' - }); - } - let error = undefined; - let response; - try { - const promises = [handler.fetch(request)]; - if (this._networkTimeoutSeconds) { - const timeoutPromise = timeout(this._networkTimeoutSeconds * 1000); - promises.push(timeoutPromise); - } - response = await Promise.race(promises); - if (!response) { - throw new Error(`Timed out the network response after ` + `${this._networkTimeoutSeconds} seconds.`); - } - } catch (err) { - if (err instanceof Error) { - error = err; - } - } - { - logger.groupCollapsed(messages.strategyStart(this.constructor.name, request)); - if (response) { - logger.log(`Got response from network.`); - } else { - logger.log(`Unable to get a response from the network.`); - } - messages.printFinalResponse(response); - logger.groupEnd(); - } - if (!response) { - throw new WorkboxError('no-response', { - url: request.url, - error - }); - } - return response; - } - } - - /* - Copyright 2019 Google LLC - - Use of this source code is governed by an MIT-style - license that can be found in the LICENSE file or at - https://opensource.org/licenses/MIT. - */ - /** - * Claim any currently available clients once the service worker - * becomes active. This is normally used in conjunction with `skipWaiting()`. - * - * @memberof workbox-core - */ - function clientsClaim() { - self.addEventListener('activate', () => self.clients.claim()); - } - - exports.NetworkFirst = NetworkFirst; - exports.NetworkOnly = NetworkOnly; - exports.clientsClaim = clientsClaim; - exports.registerRoute = registerRoute; - -})); diff --git a/public/workbox-f1770938.js b/public/workbox-f1770938.js new file mode 100644 index 00000000..8d64e054 --- /dev/null +++ b/public/workbox-f1770938.js @@ -0,0 +1 @@ +define(["exports"],function(t){"use strict";try{self["workbox:core:7.0.0"]&&_()}catch(t){}const e=(t,...e)=>{let s=t;return e.length>0&&(s+=` :: ${JSON.stringify(e)}`),s};class s extends Error{constructor(t,s){super(e(t,s)),this.name=t,this.details=s}}try{self["workbox:routing:7.0.0"]&&_()}catch(t){}const n=t=>t&&"object"==typeof t?t:{handle:t};class r{constructor(t,e,s="GET"){this.handler=n(e),this.match=t,this.method=s}setCatchHandler(t){this.catchHandler=n(t)}}class i extends r{constructor(t,e,s){super(({url:e})=>{const s=t.exec(e.href);if(s&&(e.origin===location.origin||0===s.index))return s.slice(1)},e,s)}}class a{constructor(){this.t=new Map,this.i=new Map}get routes(){return this.t}addFetchListener(){self.addEventListener("fetch",t=>{const{request:e}=t,s=this.handleRequest({request:e,event:t});s&&t.respondWith(s)})}addCacheListener(){self.addEventListener("message",t=>{if(t.data&&"CACHE_URLS"===t.data.type){const{payload:e}=t.data,s=Promise.all(e.urlsToCache.map(e=>{"string"==typeof e&&(e=[e]);const s=new Request(...e);return this.handleRequest({request:s,event:t})}));t.waitUntil(s),t.ports&&t.ports[0]&&s.then(()=>t.ports[0].postMessage(!0))}})}handleRequest({request:t,event:e}){const s=new URL(t.url,location.href);if(!s.protocol.startsWith("http"))return;const n=s.origin===location.origin,{params:r,route:i}=this.findMatchingRoute({event:e,request:t,sameOrigin:n,url:s});let a=i&&i.handler;const o=t.method;if(!a&&this.i.has(o)&&(a=this.i.get(o)),!a)return;let c;try{c=a.handle({url:s,request:t,event:e,params:r})}catch(t){c=Promise.reject(t)}const h=i&&i.catchHandler;return c instanceof Promise&&(this.o||h)&&(c=c.catch(async n=>{if(h)try{return await h.handle({url:s,request:t,event:e,params:r})}catch(t){t instanceof Error&&(n=t)}if(this.o)return this.o.handle({url:s,request:t,event:e});throw n})),c}findMatchingRoute({url:t,sameOrigin:e,request:s,event:n}){const r=this.t.get(s.method)||[];for(const i of r){let r;const a=i.match({url:t,sameOrigin:e,request:s,event:n});if(a)return r=a,(Array.isArray(r)&&0===r.length||a.constructor===Object&&0===Object.keys(a).length||"boolean"==typeof a)&&(r=void 0),{route:i,params:r}}return{}}setDefaultHandler(t,e="GET"){this.i.set(e,n(t))}setCatchHandler(t){this.o=n(t)}registerRoute(t){this.t.has(t.method)||this.t.set(t.method,[]),this.t.get(t.method).push(t)}unregisterRoute(t){if(!this.t.has(t.method))throw new s("unregister-route-but-not-found-with-method",{method:t.method});const e=this.t.get(t.method).indexOf(t);if(!(e>-1))throw new s("unregister-route-route-not-registered");this.t.get(t.method).splice(e,1)}}let o;const c=()=>(o||(o=new a,o.addFetchListener(),o.addCacheListener()),o);function h(t,e,n){let a;if("string"==typeof t){const s=new URL(t,location.href);a=new r(({url:t})=>t.href===s.href,e,n)}else if(t instanceof RegExp)a=new i(t,e,n);else if("function"==typeof t)a=new r(t,e,n);else{if(!(t instanceof r))throw new s("unsupported-route-type",{moduleName:"workbox-routing",funcName:"registerRoute",paramName:"capture"});a=t}return c().registerRoute(a),a}try{self["workbox:strategies:7.0.0"]&&_()}catch(t){}const u={cacheWillUpdate:async({response:t})=>200===t.status||0===t.status?t:null},l={googleAnalytics:"googleAnalytics",precache:"precache-v2",prefix:"workbox",runtime:"runtime",suffix:"undefined"!=typeof registration?registration.scope:""},f=t=>[l.prefix,t,l.suffix].filter(t=>t&&t.length>0).join("-"),w=t=>t||f(l.precache),d=t=>t||f(l.runtime);function p(t,e){const s=new URL(t);for(const t of e)s.searchParams.delete(t);return s.href}class y{constructor(){this.promise=new Promise((t,e)=>{this.resolve=t,this.reject=e})}}const g=new Set;function m(t){return"string"==typeof t?new Request(t):t}class v{constructor(t,e){this.h={},Object.assign(this,e),this.event=e.event,this.u=t,this.l=new y,this.p=[],this.m=[...t.plugins],this.v=new Map;for(const t of this.m)this.v.set(t,{});this.event.waitUntil(this.l.promise)}async fetch(t){const{event:e}=this;let n=m(t);if("navigate"===n.mode&&e instanceof FetchEvent&&e.preloadResponse){const t=await e.preloadResponse;if(t)return t}const r=this.hasCallback("fetchDidFail")?n.clone():null;try{for(const t of this.iterateCallbacks("requestWillFetch"))n=await t({request:n.clone(),event:e})}catch(t){if(t instanceof Error)throw new s("plugin-error-request-will-fetch",{thrownErrorMessage:t.message})}const i=n.clone();try{let t;t=await fetch(n,"navigate"===n.mode?void 0:this.u.fetchOptions);for(const s of this.iterateCallbacks("fetchDidSucceed"))t=await s({event:e,request:i,response:t});return t}catch(t){throw r&&await this.runCallbacks("fetchDidFail",{error:t,event:e,originalRequest:r.clone(),request:i.clone()}),t}}async fetchAndCachePut(t){const e=await this.fetch(t),s=e.clone();return this.waitUntil(this.cachePut(t,s)),e}async cacheMatch(t){const e=m(t);let s;const{cacheName:n,matchOptions:r}=this.u,i=await this.getCacheKey(e,"read"),a=Object.assign(Object.assign({},r),{cacheName:n});s=await caches.match(i,a);for(const t of this.iterateCallbacks("cachedResponseWillBeUsed"))s=await t({cacheName:n,matchOptions:r,cachedResponse:s,request:i,event:this.event})||void 0;return s}async cachePut(t,e){const n=m(t);var r;await(r=0,new Promise(t=>setTimeout(t,r)));const i=await this.getCacheKey(n,"write");if(!e)throw new s("cache-put-with-no-response",{url:(a=i.url,new URL(String(a),location.href).href.replace(new RegExp(`^${location.origin}`),""))});var a;const o=await this.R(e);if(!o)return!1;const{cacheName:c,matchOptions:h}=this.u,u=await self.caches.open(c),l=this.hasCallback("cacheDidUpdate"),f=l?await async function(t,e,s,n){const r=p(e.url,s);if(e.url===r)return t.match(e,n);const i=Object.assign(Object.assign({},n),{ignoreSearch:!0}),a=await t.keys(e,i);for(const e of a)if(r===p(e.url,s))return t.match(e,n)}(u,i.clone(),["__WB_REVISION__"],h):null;try{await u.put(i,l?o.clone():o)}catch(t){if(t instanceof Error)throw"QuotaExceededError"===t.name&&await async function(){for(const t of g)await t()}(),t}for(const t of this.iterateCallbacks("cacheDidUpdate"))await t({cacheName:c,oldResponse:f,newResponse:o.clone(),request:i,event:this.event});return!0}async getCacheKey(t,e){const s=`${t.url} | ${e}`;if(!this.h[s]){let n=t;for(const t of this.iterateCallbacks("cacheKeyWillBeUsed"))n=m(await t({mode:e,request:n,event:this.event,params:this.params}));this.h[s]=n}return this.h[s]}hasCallback(t){for(const e of this.u.plugins)if(t in e)return!0;return!1}async runCallbacks(t,e){for(const s of this.iterateCallbacks(t))await s(e)}*iterateCallbacks(t){for(const e of this.u.plugins)if("function"==typeof e[t]){const s=this.v.get(e),n=n=>{const r=Object.assign(Object.assign({},n),{state:s});return e[t](r)};yield n}}waitUntil(t){return this.p.push(t),t}async doneWaiting(){let t;for(;t=this.p.shift();)await t}destroy(){this.l.resolve(null)}async R(t){let e=t,s=!1;for(const t of this.iterateCallbacks("cacheWillUpdate"))if(e=await t({request:this.request,response:e,event:this.event})||void 0,s=!0,!e)break;return s||e&&200!==e.status&&(e=void 0),e}}class R{constructor(t={}){this.cacheName=d(t.cacheName),this.plugins=t.plugins||[],this.fetchOptions=t.fetchOptions,this.matchOptions=t.matchOptions}handle(t){const[e]=this.handleAll(t);return e}handleAll(t){t instanceof FetchEvent&&(t={event:t,request:t.request});const e=t.event,s="string"==typeof t.request?new Request(t.request):t.request,n="params"in t?t.params:void 0,r=new v(this,{event:e,request:s,params:n}),i=this.q(r,s,e);return[i,this.D(i,r,s,e)]}async q(t,e,n){let r;await t.runCallbacks("handlerWillStart",{event:n,request:e});try{if(r=await this.U(e,t),!r||"error"===r.type)throw new s("no-response",{url:e.url})}catch(s){if(s instanceof Error)for(const i of t.iterateCallbacks("handlerDidError"))if(r=await i({error:s,event:n,request:e}),r)break;if(!r)throw s}for(const s of t.iterateCallbacks("handlerWillRespond"))r=await s({event:n,request:e,response:r});return r}async D(t,e,s,n){let r,i;try{r=await t}catch(i){}try{await e.runCallbacks("handlerDidRespond",{event:n,request:s,response:r}),await e.doneWaiting()}catch(t){t instanceof Error&&(i=t)}if(await e.runCallbacks("handlerDidComplete",{event:n,request:s,response:r,error:i}),e.destroy(),i)throw i}}function b(t){t.then(()=>{})}function q(){return q=Object.assign?Object.assign.bind():function(t){for(var e=1;e(t[e]=s,!0),has:(t,e)=>t instanceof IDBTransaction&&("done"===e||"store"===e)||e in t};function O(t){return t!==IDBDatabase.prototype.transaction||"objectStoreNames"in IDBTransaction.prototype?(U||(U=[IDBCursor.prototype.advance,IDBCursor.prototype.continue,IDBCursor.prototype.continuePrimaryKey])).includes(t)?function(...e){return t.apply(B(this),e),k(x.get(this))}:function(...e){return k(t.apply(B(this),e))}:function(e,...s){const n=t.call(B(this),e,...s);return I.set(n,e.sort?e.sort():[e]),k(n)}}function T(t){return"function"==typeof t?O(t):(t instanceof IDBTransaction&&function(t){if(L.has(t))return;const e=new Promise((e,s)=>{const n=()=>{t.removeEventListener("complete",r),t.removeEventListener("error",i),t.removeEventListener("abort",i)},r=()=>{e(),n()},i=()=>{s(t.error||new DOMException("AbortError","AbortError")),n()};t.addEventListener("complete",r),t.addEventListener("error",i),t.addEventListener("abort",i)});L.set(t,e)}(t),e=t,(D||(D=[IDBDatabase,IDBObjectStore,IDBIndex,IDBCursor,IDBTransaction])).some(t=>e instanceof t)?new Proxy(t,N):t);var e}function k(t){if(t instanceof IDBRequest)return function(t){const e=new Promise((e,s)=>{const n=()=>{t.removeEventListener("success",r),t.removeEventListener("error",i)},r=()=>{e(k(t.result)),n()},i=()=>{s(t.error),n()};t.addEventListener("success",r),t.addEventListener("error",i)});return e.then(e=>{e instanceof IDBCursor&&x.set(e,t)}).catch(()=>{}),E.set(e,t),e}(t);if(C.has(t))return C.get(t);const e=T(t);return e!==t&&(C.set(t,e),E.set(e,t)),e}const B=t=>E.get(t);const P=["get","getKey","getAll","getAllKeys","count"],M=["put","add","delete","clear"],W=new Map;function j(t,e){if(!(t instanceof IDBDatabase)||e in t||"string"!=typeof e)return;if(W.get(e))return W.get(e);const s=e.replace(/FromIndex$/,""),n=e!==s,r=M.includes(s);if(!(s in(n?IDBIndex:IDBObjectStore).prototype)||!r&&!P.includes(s))return;const i=async function(t,...e){const i=this.transaction(t,r?"readwrite":"readonly");let a=i.store;return n&&(a=a.index(e.shift())),(await Promise.all([a[s](...e),r&&i.done]))[0]};return W.set(e,i),i}N=(t=>q({},t,{get:(e,s,n)=>j(e,s)||t.get(e,s,n),has:(e,s)=>!!j(e,s)||t.has(e,s)}))(N);try{self["workbox:expiration:7.0.0"]&&_()}catch(t){}const S="cache-entries",K=t=>{const e=new URL(t,location.href);return e.hash="",e.href};class A{constructor(t){this._=null,this.L=t}I(t){const e=t.createObjectStore(S,{keyPath:"id"});e.createIndex("cacheName","cacheName",{unique:!1}),e.createIndex("timestamp","timestamp",{unique:!1})}C(t){this.I(t),this.L&&function(t,{blocked:e}={}){const s=indexedDB.deleteDatabase(t);e&&s.addEventListener("blocked",t=>e(t.oldVersion,t)),k(s).then(()=>{})}(this.L)}async setTimestamp(t,e){const s={url:t=K(t),timestamp:e,cacheName:this.L,id:this.N(t)},n=(await this.getDb()).transaction(S,"readwrite",{durability:"relaxed"});await n.store.put(s),await n.done}async getTimestamp(t){const e=await this.getDb(),s=await e.get(S,this.N(t));return null==s?void 0:s.timestamp}async expireEntries(t,e){const s=await this.getDb();let n=await s.transaction(S).store.index("timestamp").openCursor(null,"prev");const r=[];let i=0;for(;n;){const s=n.value;s.cacheName===this.L&&(t&&s.timestamp=e?r.push(n.value):i++),n=await n.continue()}const a=[];for(const t of r)await s.delete(S,t.id),a.push(t.url);return a}N(t){return this.L+"|"+K(t)}async getDb(){return this._||(this._=await function(t,e,{blocked:s,upgrade:n,blocking:r,terminated:i}={}){const a=indexedDB.open(t,e),o=k(a);return n&&a.addEventListener("upgradeneeded",t=>{n(k(a.result),t.oldVersion,t.newVersion,k(a.transaction),t)}),s&&a.addEventListener("blocked",t=>s(t.oldVersion,t.newVersion,t)),o.then(t=>{i&&t.addEventListener("close",()=>i()),r&&t.addEventListener("versionchange",t=>r(t.oldVersion,t.newVersion,t))}).catch(()=>{}),o}("workbox-expiration",1,{upgrade:this.C.bind(this)})),this._}}class F{constructor(t,e={}){this.O=!1,this.T=!1,this.k=e.maxEntries,this.B=e.maxAgeSeconds,this.P=e.matchOptions,this.L=t,this.M=new A(t)}async expireEntries(){if(this.O)return void(this.T=!0);this.O=!0;const t=this.B?Date.now()-1e3*this.B:0,e=await this.M.expireEntries(t,this.k),s=await self.caches.open(this.L);for(const t of e)await s.delete(t,this.P);this.O=!1,this.T&&(this.T=!1,b(this.expireEntries()))}async updateTimestamp(t){await this.M.setTimestamp(t,Date.now())}async isURLExpired(t){if(this.B){const e=await this.M.getTimestamp(t),s=Date.now()-1e3*this.B;return void 0===e||er||e&&e<0)throw new s("range-not-satisfiable",{size:r,end:n,start:e});let i,a;return void 0!==e&&void 0!==n?(i=e,a=n+1):void 0!==e&&void 0===n?(i=e,a=r):void 0!==n&&void 0===e&&(i=r-n,a=r),{start:i,end:a}}(i,r.start,r.end),o=i.slice(a.start,a.end),c=o.size,h=new Response(o,{status:206,statusText:"Partial Content",headers:e.headers});return h.headers.set("Content-Length",String(c)),h.headers.set("Content-Range",`bytes ${a.start}-${a.end-1}/${i.size}`),h}catch(t){return new Response("",{status:416,statusText:"Range Not Satisfiable"})}}function $(t,e){const s=e();return t.waitUntil(s),s}try{self["workbox:precaching:7.0.0"]&&_()}catch(t){}function z(t){if(!t)throw new s("add-to-cache-list-unexpected-type",{entry:t});if("string"==typeof t){const e=new URL(t,location.href);return{cacheKey:e.href,url:e.href}}const{revision:e,url:n}=t;if(!n)throw new s("add-to-cache-list-unexpected-type",{entry:t});if(!e){const t=new URL(n,location.href);return{cacheKey:t.href,url:t.href}}const r=new URL(n,location.href),i=new URL(n,location.href);return r.searchParams.set("__WB_REVISION__",e),{cacheKey:r.href,url:i.href}}class G{constructor(){this.updatedURLs=[],this.notUpdatedURLs=[],this.handlerWillStart=async({request:t,state:e})=>{e&&(e.originalRequest=t)},this.cachedResponseWillBeUsed=async({event:t,state:e,cachedResponse:s})=>{if("install"===t.type&&e&&e.originalRequest&&e.originalRequest instanceof Request){const t=e.originalRequest.url;s?this.notUpdatedURLs.push(t):this.updatedURLs.push(t)}return s}}}class V{constructor({precacheController:t}){this.cacheKeyWillBeUsed=async({request:t,params:e})=>{const s=(null==e?void 0:e.cacheKey)||this.W.getCacheKeyForURL(t.url);return s?new Request(s,{headers:t.headers}):t},this.W=t}}let J,Q;async function X(t,e){let n=null;if(t.url){n=new URL(t.url).origin}if(n!==self.location.origin)throw new s("cross-origin-copy-response",{origin:n});const r=t.clone(),i={headers:new Headers(r.headers),status:r.status,statusText:r.statusText},a=e?e(i):i,o=function(){if(void 0===J){const t=new Response("");if("body"in t)try{new Response(t.body),J=!0}catch(t){J=!1}J=!1}return J}()?r.body:await r.blob();return new Response(o,a)}class Y extends R{constructor(t={}){t.cacheName=w(t.cacheName),super(t),this.j=!1!==t.fallbackToNetwork,this.plugins.push(Y.copyRedirectedCacheableResponsesPlugin)}async U(t,e){const s=await e.cacheMatch(t);return s||(e.event&&"install"===e.event.type?await this.S(t,e):await this.K(t,e))}async K(t,e){let n;const r=e.params||{};if(!this.j)throw new s("missing-precache-entry",{cacheName:this.cacheName,url:t.url});{const s=r.integrity,i=t.integrity,a=!i||i===s;n=await e.fetch(new Request(t,{integrity:"no-cors"!==t.mode?i||s:void 0})),s&&a&&"no-cors"!==t.mode&&(this.A(),await e.cachePut(t,n.clone()))}return n}async S(t,e){this.A();const n=await e.fetch(t);if(!await e.cachePut(t,n.clone()))throw new s("bad-precaching-response",{url:t.url,status:n.status});return n}A(){let t=null,e=0;for(const[s,n]of this.plugins.entries())n!==Y.copyRedirectedCacheableResponsesPlugin&&(n===Y.defaultPrecacheCacheabilityPlugin&&(t=s),n.cacheWillUpdate&&e++);0===e?this.plugins.push(Y.defaultPrecacheCacheabilityPlugin):e>1&&null!==t&&this.plugins.splice(t,1)}}Y.defaultPrecacheCacheabilityPlugin={cacheWillUpdate:async({response:t})=>!t||t.status>=400?null:t},Y.copyRedirectedCacheableResponsesPlugin={cacheWillUpdate:async({response:t})=>t.redirected?await X(t):t};class Z{constructor({cacheName:t,plugins:e=[],fallbackToNetwork:s=!0}={}){this.F=new Map,this.H=new Map,this.$=new Map,this.u=new Y({cacheName:w(t),plugins:[...e,new V({precacheController:this})],fallbackToNetwork:s}),this.install=this.install.bind(this),this.activate=this.activate.bind(this)}get strategy(){return this.u}precache(t){this.addToCacheList(t),this.G||(self.addEventListener("install",this.install),self.addEventListener("activate",this.activate),this.G=!0)}addToCacheList(t){const e=[];for(const n of t){"string"==typeof n?e.push(n):n&&void 0===n.revision&&e.push(n.url);const{cacheKey:t,url:r}=z(n),i="string"!=typeof n&&n.revision?"reload":"default";if(this.F.has(r)&&this.F.get(r)!==t)throw new s("add-to-cache-list-conflicting-entries",{firstEntry:this.F.get(r),secondEntry:t});if("string"!=typeof n&&n.integrity){if(this.$.has(t)&&this.$.get(t)!==n.integrity)throw new s("add-to-cache-list-conflicting-integrities",{url:r});this.$.set(t,n.integrity)}if(this.F.set(r,t),this.H.set(r,i),e.length>0){const t=`Workbox is precaching URLs without revision info: ${e.join(", ")}\nThis is generally NOT safe. Learn more at https://bit.ly/wb-precache`;console.warn(t)}}}install(t){return $(t,async()=>{const e=new G;this.strategy.plugins.push(e);for(const[e,s]of this.F){const n=this.$.get(s),r=this.H.get(e),i=new Request(e,{integrity:n,cache:r,credentials:"same-origin"});await Promise.all(this.strategy.handleAll({params:{cacheKey:s},request:i,event:t}))}const{updatedURLs:s,notUpdatedURLs:n}=e;return{updatedURLs:s,notUpdatedURLs:n}})}activate(t){return $(t,async()=>{const t=await self.caches.open(this.strategy.cacheName),e=await t.keys(),s=new Set(this.F.values()),n=[];for(const r of e)s.has(r.url)||(await t.delete(r),n.push(r.url));return{deletedURLs:n}})}getURLsToCacheKeys(){return this.F}getCachedURLs(){return[...this.F.keys()]}getCacheKeyForURL(t){const e=new URL(t,location.href);return this.F.get(e.href)}getIntegrityForCacheKey(t){return this.$.get(t)}async matchPrecache(t){const e=t instanceof Request?t.url:t,s=this.getCacheKeyForURL(e);if(s){return(await self.caches.open(this.strategy.cacheName)).match(s)}}createHandlerBoundToURL(t){const e=this.getCacheKeyForURL(t);if(!e)throw new s("non-precached-url",{url:t});return s=>(s.request=new Request(t),s.params=Object.assign({cacheKey:e},s.params),this.strategy.handle(s))}}const tt=()=>(Q||(Q=new Z),Q);class et extends r{constructor(t,e){super(({request:s})=>{const n=t.getURLsToCacheKeys();for(const r of function*(t,{ignoreURLParametersMatching:e=[/^utm_/,/^fbclid$/],directoryIndex:s="index.html",cleanURLs:n=!0,urlManipulation:r}={}){const i=new URL(t,location.href);i.hash="",yield i.href;const a=function(t,e=[]){for(const s of[...t.searchParams.keys()])e.some(t=>t.test(s))&&t.searchParams.delete(s);return t}(i,e);if(yield a.href,s&&a.pathname.endsWith("/")){const t=new URL(a.href);t.pathname+=s,yield t.href}if(n){const t=new URL(a.href);t.pathname+=".html",yield t.href}if(r){const t=r({url:i});for(const e of t)yield e.href}}(s.url,e)){const e=n.get(r);if(e){return{cacheKey:e,integrity:t.getIntegrityForCacheKey(e)}}}},t.strategy)}}t.CacheFirst=class extends R{async U(t,e){let n,r=await e.cacheMatch(t);if(!r)try{r=await e.fetchAndCachePut(t)}catch(t){t instanceof Error&&(n=t)}if(!r)throw new s("no-response",{url:t.url,error:n});return r}},t.ExpirationPlugin=class{constructor(t={}){this.cachedResponseWillBeUsed=async({event:t,request:e,cacheName:s,cachedResponse:n})=>{if(!n)return null;const r=this.V(n),i=this.J(s);b(i.expireEntries());const a=i.updateTimestamp(e.url);if(t)try{t.waitUntil(a)}catch(t){}return r?n:null},this.cacheDidUpdate=async({cacheName:t,request:e})=>{const s=this.J(t);await s.updateTimestamp(e.url),await s.expireEntries()},this.X=t,this.B=t.maxAgeSeconds,this.Y=new Map,t.purgeOnQuotaError&&function(t){g.add(t)}(()=>this.deleteCacheAndMetadata())}J(t){if(t===d())throw new s("expire-custom-caches-only");let e=this.Y.get(t);return e||(e=new F(t,this.X),this.Y.set(t,e)),e}V(t){if(!this.B)return!0;const e=this.Z(t);if(null===e)return!0;return e>=Date.now()-1e3*this.B}Z(t){if(!t.headers.has("date"))return null;const e=t.headers.get("date"),s=new Date(e).getTime();return isNaN(s)?null:s}async deleteCacheAndMetadata(){for(const[t,e]of this.Y)await self.caches.delete(t),await e.delete();this.Y=new Map}},t.NetworkFirst=class extends R{constructor(t={}){super(t),this.plugins.some(t=>"cacheWillUpdate"in t)||this.plugins.unshift(u),this.tt=t.networkTimeoutSeconds||0}async U(t,e){const n=[],r=[];let i;if(this.tt){const{id:s,promise:a}=this.et({request:t,logs:n,handler:e});i=s,r.push(a)}const a=this.st({timeoutId:i,request:t,logs:n,handler:e});r.push(a);const o=await e.waitUntil((async()=>await e.waitUntil(Promise.race(r))||await a)());if(!o)throw new s("no-response",{url:t.url});return o}et({request:t,logs:e,handler:s}){let n;return{promise:new Promise(e=>{n=setTimeout(async()=>{e(await s.cacheMatch(t))},1e3*this.tt)}),id:n}}async st({timeoutId:t,request:e,logs:s,handler:n}){let r,i;try{i=await n.fetchAndCachePut(e)}catch(t){t instanceof Error&&(r=t)}return t&&clearTimeout(t),!r&&i||(i=await n.cacheMatch(e)),i}},t.RangeRequestsPlugin=class{constructor(){this.cachedResponseWillBeUsed=async({request:t,cachedResponse:e})=>e&&t.headers.has("range")?await H(t,e):e}},t.StaleWhileRevalidate=class extends R{constructor(t={}){super(t),this.plugins.some(t=>"cacheWillUpdate"in t)||this.plugins.unshift(u)}async U(t,e){const n=e.fetchAndCachePut(t).catch(()=>{});e.waitUntil(n);let r,i=await e.cacheMatch(t);if(i);else try{i=await n}catch(t){t instanceof Error&&(r=t)}if(!i)throw new s("no-response",{url:t.url,error:r});return i}},t.cleanupOutdatedCaches=function(){self.addEventListener("activate",t=>{const e=w();t.waitUntil((async(t,e="-precache-")=>{const s=(await self.caches.keys()).filter(s=>s.includes(e)&&s.includes(self.registration.scope)&&s!==t);return await Promise.all(s.map(t=>self.caches.delete(t))),s})(e).then(t=>{}))})},t.clientsClaim=function(){self.addEventListener("activate",()=>self.clients.claim())},t.precacheAndRoute=function(t,e){!function(t){tt().precache(t)}(t),function(t){const e=tt();h(new et(e,t))}(e)},t.registerRoute=h});