Compare commits

...

67 Commits

Author SHA1 Message Date
8272a02b52 Update changelog v0.3.15 2021-03-28 12:18:37 +00:00
e346b1d9d2 Merge branch 'main' of https://github.com/InseeFrLab/keycloakify into main 2021-03-28 14:14:52 +02:00
2309bd21c6 Remove all reference to --external-assets, broken feature 2021-03-28 14:14:43 +02:00
7d6476c1b5 Update changelog v0.3.14 2021-03-28 11:39:36 +00:00
e892a0e7e6 Merge branch 'main' of https://github.com/InseeFrLab/keycloakify into main 2021-03-28 13:37:07 +02:00
ca5b41e730 Fix standalone mode: imports from js 2021-03-28 13:37:02 +02:00
9b18234112 Update changelog v0.3.13 2021-03-26 16:54:38 +00:00
5274368f47 Merge branch 'main' of https://github.com/InseeFrLab/keycloakify into main 2021-03-26 17:49:36 +01:00
1415c24028 Bump version (changelog ignore) 2021-03-26 17:49:31 +01:00
4a084f5859 Fix previous release (changelog ignore) 2021-03-26 17:49:09 +01:00
a30c9eb0cd Update changelog v0.3.12 2021-03-26 16:35:41 +00:00
85d3b40b8e Merge branch 'main' of https://github.com/InseeFrLab/keycloakify into main 2021-03-26 17:31:06 +01:00
335afec230 Bump version (changelog ignore) 2021-03-26 17:31:01 +01:00
69fa49848a Fix mocksContext 2021-03-26 17:30:04 +01:00
7a09051127 Update changelog v0.3.11 2021-03-26 14:36:48 +00:00
07ee0ecb8b Merge branch 'main' of https://github.com/InseeFrLab/keycloakify into main 2021-03-26 15:29:23 +01:00
6f133428f8 Fix previous build, improve README 2021-03-26 15:29:17 +01:00
4f733736db fmt (changelog ignore) 2021-03-26 14:06:14 +01:00
d96ff13a67 Update changelog v0.3.10 2021-03-26 13:05:25 +00:00
2c1351ce47 fmt (changelog ignore) 2021-03-26 14:04:45 +01:00
96cd56ec77 Merge branch 'main' of https://github.com/InseeFrLab/keycloakify into main 2021-03-26 14:02:46 +01:00
e5b2096d65 Bump version (changelog ignore) 2021-03-26 14:02:40 +01:00
3aa140335f Handle <style> tag, improve documentation 2021-03-26 14:02:14 +01:00
4cafaa2492 Update changelog v0.3.9 2021-03-25 11:54:13 +00:00
9c633a7521 Update readme 2021-03-25 12:48:40 +01:00
e27845ba91 Merge branch 'main' of https://github.com/InseeFrLab/keycloakify into main 2021-03-25 12:01:15 +01:00
2a8708a45b Document --external-assets 2021-03-25 12:01:11 +01:00
6874fa4c24 Update README.md 2021-03-24 09:12:50 +01:00
ba531a4927 Update README.md 2021-03-24 09:12:04 +01:00
20175b57cf Update README.md 2021-03-24 09:10:44 +01:00
ad275e4c34 Update changelog v0.3.8 2021-03-22 22:36:17 +00:00
060b9fe0de Merge branch 'main' of https://github.com/InseeFrLab/keycloakify into main 2021-03-22 23:34:13 +01:00
17b24d14ed Make standalone mode the default 2021-03-22 23:34:07 +01:00
2d278b0680 Update changelog v0.3.7 2021-03-22 19:57:34 +00:00
fb5975e4f1 Merge branch 'main' of https://github.com/InseeFrLab/keycloakify into main 2021-03-22 20:54:35 +01:00
24fccaf513 (test) external asset mode by default 2021-03-22 20:54:28 +01:00
293953aa1b Update changelog v0.3.6 2021-03-22 19:02:53 +00:00
1049e312f9 Fix previous release 2021-03-22 20:00:58 +01:00
a2db250600 Update changelog v0.3.5 2021-03-22 18:43:18 +00:00
cf7fe8c337 Merge branch 'main' of https://github.com/InseeFrLab/keycloakify into main 2021-03-22 19:41:08 +01:00
f5350097bf Bump version (changelog ignore) 2021-03-22 19:40:58 +01:00
1cb5dd461b support homepage with urlPath 2021-03-22 19:40:38 +01:00
845599a5e8 Update changelog v0.3.4 2021-03-22 06:23:40 +00:00
0cc02c292f Merge branch 'main' of https://github.com/InseeFrLab/keycloakify into main 2021-03-22 07:21:36 +01:00
1919702326 Bugfix: Import assets from CSS 2021-03-22 07:21:31 +01:00
0c0052e1cd Update changelog v0.3.3 2021-03-22 04:27:01 +00:00
78622770ec Merge branch 'main' of https://github.com/InseeFrLab/keycloakify into main 2021-03-22 05:21:22 +01:00
7b86727394 Fix submit not receving correct text 2021-03-22 05:21:05 +01:00
0965f8648e Update changelog v0.3.2 2021-03-21 21:31:01 +00:00
98974b4367 Merge branch 'main' of https://github.com/InseeFrLab/keycloakify into main 2021-03-21 22:25:49 +01:00
597bcadd9e Fix broken previous release 2021-03-21 22:25:47 +01:00
4d9aabcb91 Update changelog v0.3.1 2021-03-21 21:13:36 +00:00
1606c2884d kcHeaderClass can be updated after initial mount 2021-03-21 22:10:33 +01:00
12f69b593f Merge branch 'main' of https://github.com/InseeFrLab/keycloakify into main 2021-03-20 05:07:26 +01:00
1ca45f90d0 Update readme (changelog ignore) 2021-03-20 05:07:22 +01:00
a91a5616f9 Update changelog v0.3.0 2021-03-20 04:02:59 +00:00
c525e09368 Bump version 2021-03-20 05:00:14 +01:00
f5bba4a6a0 Feat: Cary over states using URL search params 2021-03-20 04:59:18 +01:00
77a37fb573 Merge branch 'main' of https://github.com/InseeFrLab/keycloakify into main 2021-03-20 02:54:21 +01:00
6b24c5878c Bugfix: with kcHtmlClass 2021-03-20 02:54:15 +01:00
f4414e1249 Update changelog v0.2.10 2021-03-19 23:19:03 +00:00
b72971f4ce Merge branch 'main' of https://github.com/InseeFrLab/keycloakify into main 2021-03-20 00:17:06 +01:00
b9af4e6804 Bump version (changelog ingnore) 2021-03-20 00:16:58 +01:00
2fd1d42d1e Remove dependency to denoify 2021-03-20 00:16:34 +01:00
3cfc7d7fa9 Update changelog v0.2.9 2021-03-19 23:14:27 +00:00
b5d9055fcf Bump version (changelog ignore) 2021-03-20 00:09:37 +01:00
63d644d95f Update deps and CI workflow 2021-03-20 00:09:12 +01:00
18 changed files with 598 additions and 535 deletions

View File

@ -2,14 +2,14 @@ name: ci
on:
push:
branches:
- develop
- main
pull_request:
branches:
- develop
- main
jobs:
test_node:
test:
runs-on: macos-10.15
strategy:
matrix:
@ -17,72 +17,120 @@ jobs:
name: Test with Node v${{ matrix.node }}
steps:
- name: Tell if project is using npm or yarn
id: _1
uses: garronej/github_actions_toolkit@v1.11
id: step1
uses: garronej/github_actions_toolkit@v2.2
with:
action_name: tell_if_project_uses_npm_or_yarn
owner: ${{github.repository_owner}}
repo: ${{github.event.repository.name}}
branch: ${{github.ref}}
- uses: actions/checkout@v2
- uses: actions/setup-node@v1
- uses: actions/checkout@v2.3.4
- uses: actions/setup-node@v2.1.3
with:
node-version: ${{ matrix.node }}
- if: steps._1.outputs.npm_or_yarn == 'yarn'
- if: steps.step1.outputs.npm_or_yarn == 'yarn'
run: |
yarn install --frozen-lockfile
yarn run build
yarn run test
- if: steps._1.outputs.npm_or_yarn == 'npm'
yarn build
yarn test
- if: steps.step1.outputs.npm_or_yarn == 'npm'
run: |
npm ci
npm run build
npm run test
trigger_publish:
name: Trigger publish.yaml workflow if package.json version updated ( and secrets.PAT is set ).
npm test
check_if_version_upgraded:
name: Check if version upgrade
if: github.event_name == 'push'
runs-on: ubuntu-latest
env:
PAT: ${{secrets.PAT}}
if: github.event_name == 'push' && github.event.head_commit.author.name != 'ts_ci'
needs: test_node
needs: test
outputs:
from_version: ${{ steps.step1.outputs.from_version }}
to_version: ${{ steps.step1.outputs.to_version }}
is_upgraded_version: ${{steps.step1.outputs.is_upgraded_version }}
steps:
- name: Get version on latest
id: v_latest
uses: garronej/github_actions_toolkit@v1.11
- uses: garronej/github_actions_toolkit@v2.2
id: step1
with:
action_name: get_package_json_version
owner: ${{github.repository_owner}}
repo: ${{github.event.repository.name}}
branch: latest
compare_to_version: '0.0.0'
action_name: is_package_json_version_upgraded
- name: Get version on develop
id: v_develop
uses: garronej/github_actions_toolkit@v1.11
with:
action_name: get_package_json_version
owner: ${{github.repository_owner}}
repo: ${{github.event.repository.name}}
branch: ${{ github.sha }}
compare_to_version: ${{steps.v_latest.outputs.version || '0.0.0'}}
- name: 'Trigger the ''publish'' workflow'
if: ${{ !!env.PAT && steps.v_develop.outputs.compare_result == '1' }}
uses: garronej/github_actions_toolkit@v1.11
env:
GITHUB_TOKEN: ${{ secrets.PAT }}
update_changelog:
runs-on: ubuntu-latest
needs: check_if_version_upgraded
if: needs.check_if_version_upgraded.outputs.is_upgraded_version == 'true'
steps:
- uses: garronej/github_actions_toolkit@v2.2
with:
action_name: dispatch_event
owner: ${{github.repository_owner}}
repo: ${{github.event.repository.name}}
event_type: publish
client_payload_json: |
${{
format(
'{{"from_version":"{0}","to_version":"{1}","repo":"{2}"}}',
steps.v_latest.outputs.version,
steps.v_develop.outputs.version,
github.event.repository.name
)
}}
action_name: update_changelog
branch: ${{ github.ref }}
commit_author_email: ts_ci@github.com
create_github_release:
runs-on: ubuntu-latest
needs:
- update_changelog
- check_if_version_upgraded
steps:
- uses: actions/checkout@v2
with:
ref: ${{ github.ref }}
- name: Build GitHub release body
id: step1
run: |
if [ "$FROM_VERSION" = "0.0.0" ]; then
echo "::set-output name=body::🚀"
else
echo "::set-output name=body::📋 [CHANGELOG](https://github.com/$GITHUB_REPOSITORY/blob/v$TO_VERSION/CHANGELOG.md)"
fi
env:
FROM_VERSION: ${{ needs.check_if_version_upgraded.outputs.from_version }}
TO_VERSION: ${{ needs.check_if_version_upgraded.outputs.to_version }}
- uses: garronej/action-gh-release@v0.2.0
with:
name: Release v${{ needs.check_if_version_upgraded.outputs.to_version }}
tag_name: v${{ needs.check_if_version_upgraded.outputs.to_version }}
target_commitish: ${{ github.ref }}
body: ${{ steps.step1.outputs.body }}
draft: false
prerelease: false
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
publish_on_npm:
runs-on: macos-10.15
needs:
- update_changelog
- check_if_version_upgraded
steps:
- uses: actions/checkout@v2.3.4
with:
ref: ${{ github.ref }}
- uses: actions/setup-node@v2.1.3
with:
node-version: '15'
- run: |
PACKAGE_MANAGER=npm
if [ -f "./yarn.lock" ]; then
PACKAGE_MANAGER=yarn
fi
if [ "$PACKAGE_MANAGER" = "yarn" ]; then
yarn install --frozen-lockfile
else
npm ci
fi
$PACKAGE_MANAGER run build
- run: npx -y -p denoify@0.6.5 denoify_enable_short_npm_import_path
env:
DRY_RUN: "0"
- name: Publishing on NPM
run: |
if [ "$(npm show . version)" = "$VERSION" ]; then
echo "This version is already published"
exit 0
fi
if [ "$NPM_TOKEN" = "" ]; then
echo "Can't publish on NPM, You must first create a secret called NPM_TOKEN that contains your NPM auth token. https://help.github.com/en/actions/automating-your-workflow-with-github-actions/creating-and-using-encrypted-secrets"
false
fi
echo '//registry.npmjs.org/:_authToken=${NPM_TOKEN}' > .npmrc
npm publish
rm .npmrc
env:
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
VERSION: ${{ needs.check_if_version_upgraded.outputs.to_version }}

View File

@ -1,116 +0,0 @@
on:
repository_dispatch:
types: publish
jobs:
update_changelog_and_sync_package_lock_version:
name: Update CHANGELOG.md and make sure package.json and package-lock.json versions matches.
runs-on: ubuntu-latest
steps:
- name: Synchronize package.json and package-lock.json version if needed.
uses: garronej/github_actions_toolkit@v1.11
env:
GITHUB_TOKEN: ${{ secrets.PAT }}
with:
action_name: sync_package_and_package_lock_version
owner: ${{github.repository_owner}}
repo: ${{github.event.client_payload.repo}}
branch: develop
commit_author_email: ts_ci@github.com
- name: Update CHANGELOG.md
if: ${{ !!github.event.client_payload.from_version }}
uses: garronej/github_actions_toolkit@v1.11
env:
GITHUB_TOKEN: ${{ secrets.PAT }}
with:
action_name: update_changelog
owner: ${{github.repository_owner}}
repo: ${{github.event.client_payload.repo}}
branch_behind: latest
branch_ahead: develop
commit_author_email: ts_ci@github.com
exclude_commit_from_author_names_json: '["ts_ci"]'
publish:
runs-on: macos-10.15
needs: update_changelog_and_sync_package_lock_version
steps:
- uses: actions/checkout@v2
with:
fetch-depth: 0
ref: develop
- name: Remove .github directory, useless on 'latest' branch
run: rm -r .github
- name: Remove branch 'latest'
continue-on-error: true
run: |
git branch -d latest || true
git push origin :latest
- name: Create the new 'latest' branch
run: |
git branch latest
git checkout latest
- uses: actions/setup-node@v1
- run: |
if [ -f "./yarn.lock" ]; then
yarn install --frozen-lockfile
else
npm ci
fi
- run: |
PACKAGE_MANAGER=npm
if [ -f "./yarn.lock" ]; then
PACKAGE_MANAGER=yarn
fi
$PACKAGE_MANAGER run enable_short_import_path
env:
DRY_RUN: "0"
- name: (DEBUG) Show how the files have been moved to enable short import
run: ls -lR
- name: Publishing on NPM
run: |
if [ "$(npm show . version)" = "$VERSION" ]; then
echo "This version is already published"
exit 0
fi
if [ "$NPM_TOKEN" = "" ]; then
echo "Can't publish on NPM, You must first create a secret called NPM_TOKEN that contains your NPM auth token. https://help.github.com/en/actions/automating-your-workflow-with-github-actions/creating-and-using-encrypted-secrets"
false
fi
echo '//registry.npmjs.org/:_authToken=${NPM_TOKEN}' > .npmrc
npm publish
rm .npmrc
env:
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
VERSION: ${{ github.event.client_payload.to_version }}
- name: Commit changes
run: |
git config --local user.email "ts_ci@github.com"
git config --local user.name "ts_ci"
git add -A
git commit -am "Enabling shorter import paths [automatic]"
- run: git push origin latest
- name: Release body
id: id_rb
run: |
if [ "$FROM_VERSION" = "" ]; then
echo "::set-output name=body::🚀"
else
echo "::set-output name=body::📋 [CHANGELOG](https://github.com/$OWNER/$REPO/blob/$REF/CHANGELOG.md)"
fi
env:
FROM_VERSION: ${{ github.event.client_payload.from_version }}
OWNER: ${{github.repository_owner}}
REPO: ${{github.event.client_payload.repo}}
REF: v${{github.event.client_payload.to_version}}
- name: Create Release
uses: garronej/create-release@master
env:
GITHUB_TOKEN: ${{ secrets.PAT }}
with:
tag_name: v${{ github.event.client_payload.to_version }}
release_name: Release v${{ github.event.client_payload.to_version }}
branch: latest
draft: false
prerelease: false
body: ${{ steps.id_rb.outputs.body }}

View File

@ -1,3 +1,81 @@
### **0.3.15** (2021-03-28)
- Remove all reference to --external-assets, broken feature
### **0.3.14** (2021-03-28)
- Fix standalone mode: imports from js
### **0.3.13** (2021-03-26)
### **0.3.12** (2021-03-26)
- Fix mocksContext
### **0.3.11** (2021-03-26)
- Fix previous build, improve README
### **0.3.10** (2021-03-26)
- Handle <style> tag, improve documentation
### **0.3.9** (2021-03-25)
- Update readme
- Document --external-assets
- Update README.md
- Update README.md
- Update README.md
### **0.3.8** (2021-03-22)
- Make standalone mode the default
### **0.3.7** (2021-03-22)
- (test) external asset mode by default
### **0.3.6** (2021-03-22)
- Fix previous release
### **0.3.5** (2021-03-22)
- support homepage with urlPath
### **0.3.4** (2021-03-22)
- Bugfix: Import assets from CSS
### **0.3.3** (2021-03-22)
- Fix submit not receving correct text
### **0.3.2** (2021-03-21)
- Fix broken previous release
### **0.3.1** (2021-03-21)
- kcHeaderClass can be updated after initial mount
## **0.3.0** (2021-03-20)
- Bump version
- Feat: Cary over states using URL search params
- Bugfix: with kcHtmlClass
### **0.2.10** (2021-03-19)
- Remove dependency to denoify
### **0.2.9** (2021-03-19)
- Update deps and CI workflow
### **0.2.8** (2021-03-19)
- Bugfix: keycloak_build that grow and grow in size

177
README.md
View File

@ -20,8 +20,10 @@
The problem:
![keycloak_before](https://user-images.githubusercontent.com/6702424/108838381-dbbbcf80-75d3-11eb-8ae8-db41563ef9db.gif)
<p align="center">
<i>Without keycloakify:</i><br>
<img src="https://user-images.githubusercontent.com/6702424/108838381-dbbbcf80-75d3-11eb-8ae8-db41563ef9db.gif">
</p>
When we redirected to Keycloak the user suffers from a harsh context switch.
Keycloak does offer a way to customize theses pages but it requires a lot of raw HTML/CSS hacking
to reproduce the look and feel of a specific app. Not mentioning the maintenance cost of such an endeavour.
@ -29,14 +31,12 @@ to reproduce the look and feel of a specific app. Not mentioning the maintenance
Wouldn't it be great if we could just design the login and register pages as if they where part of our app?
Here is `yarn add keycloakify` for you 🍸
TODO: Insert video after.
<p align="center">
<i>With keycloakify:</i><br>
<img src="https://github.com/InseeFrLab/keycloakify/releases/download/v0.3.8/keycloakify_after.gif">
</p>
Tested with the following Keycloak versions:
- [11.0.3](https://hub.docker.com/layers/jboss/keycloak/11.0.3/images/sha256-4438f1e51c1369371cb807dffa526e1208086b3ebb9cab009830a178de949782?context=explore)
- [12.0.4](https://hub.docker.com/layers/jboss/keycloak/12.0.4/images/sha256-67e0c88e69bd0c7aef972c40bdeb558a974013a28b3668ca790ed63a04d70584?context=explore)
**Disclaimer**: This tool will be maintained to stay compatible with Keycloak v11 and up, however, the default pages you will get
(before you customize it) will always be the ones of the Keycloak v11.
**TL;DR**: [Here](https://github.com/garronej/keycloakify-demo-app) is a Hello World React project with Keycloakify set up.
- [Motivations](#motivations)
- [How to use](#how-to-use)
@ -45,41 +45,48 @@ Tested with the following Keycloak versions:
- [Just changing the look](#just-changing-the-look)
- [Changing the look **and** feel](#changing-the-look-and-feel)
- [Hot reload](#hot-reload)
- [How to implement context persistance](#how-to-implement-context-persistance)
- [If your keycloak is a subdomain of your app.](#if-your-keycloak-is-a-subdomain-of-your-app)
- [Else](#else)
- [GitHub Actions](#github-actions)
- [REQUIREMENTS](#requirements)
- [Requirements](#requirements)
- [Limitations](#limitations)
- [`process.env.PUBLIC_URL` not supported.](#processenvpublic_url-not-supported)
- [`@font-face` importing fonts from the `src/` dir](#font-face-importing-fonts-from-thesrc-dir)
- [Example of setup that **won't** work](#example-of-setup-that-wont-work)
- [Workarounds](#workarounds)
- [Implement context persistence (optional)](#implement-context-persistence-optional)
- [API Reference](#api-reference)
- [The build tool](#the-build-tool)
- [The fronted lib ( imported into your react app )](#the-fronted-lib--imported-into-your-react-app-)
# How to use
## Setting up the build tool
Add `keycloakify` to the dev dependencies of your project `npm install --save-dev keycloakify` or `yarn add --dev keycloakify`
then configure your `package.json` build's script to build the keycloak's theme by adding `&& build-keycloak-theme`.
Typically you will get:
`package.json`
[`package.json`](https://github.com/garronej/keycloakify-demo-app/blob/main/package.json)
```json
"devDependencies": {
"homepage": "https://URL.OF/YOUR-APP"
"dependencies": {
"keycloakify": "^0.0.10"
},
"scripts": {
"keycloak": "yarn build && build-keycloak-theme",
},
```
`"homepage"` must be specified only if the url path is not `/`
(Onl `/YOUR-APP` matters `URL.OF` don't have to be the actual domain)
Then run `yarn keycloak` or `npm run keycloak`, you will be provided with instructions
about how to load the theme into Keycloak.
It is mandatory that you specify the url where your app will be available
using the `homepage` field.
Once you've edited your `package.json` you can install your new
dependency with `yarn install` and build the keycloak theme with
`yarn keycloak`.
Once the build is complete instructions about how to load
the theme into Keycloak are printed in the console.
## Developing your login and register pages in your React app
### Just changing the look
The fist approach is to only arr/replace the default class names by your
The first approach is to only arr/replace the default class names by your
own.
```tsx
@ -154,25 +161,6 @@ Checkout [this concrete example](https://github.com/garronej/keycloakify-demo-ap
*NOTE: keycloak-react-theming was renamed keycloakify since this video was recorded*
[![kickstart_video](https://user-images.githubusercontent.com/6702424/108877866-f146ee80-75ff-11eb-8120-003b3c5f6dd8.png)](https://youtu.be/xTz0Rj7i2v8)
# How to implement context persistance
If you want dark mode preference, language and others users preferences
to persist within the page served by keycloak here are the methods you can
adopt.
## If your keycloak is a subdomain of your app.
E.g: Your app url is `my-app.com` and your keycloak url is `auth.my-app.com`.
In this case there is a very straightforward approach and it is to use [`powerhooks/useGlobalState`](https://github.com/garronej/powerhooks).
Instead of `{ "persistance": "localStorage" }` use `{ "persistance": "cookie" }`.
## Else
You will have to use URL parameters to passes states when you redirect to
the login page.
TOTO: Provide a clean way, as abstracted as possible, way to do that.
# GitHub Actions
@ -181,20 +169,108 @@ TOTO: Provide a clean way, as abstracted as possible, way to do that.
[Here is a demo repo](https://github.com/garronej/keycloakify-demo-app) to show how to automate
the building and publishing of the theme (the .jar file).
# REQUIREMENTS
# Requirements
Tested with the following Keycloak versions:
- [11.0.3](https://hub.docker.com/layers/jboss/keycloak/11.0.3/images/sha256-4438f1e51c1369371cb807dffa526e1208086b3ebb9cab009830a178de949782?context=explore)
- [12.0.4](https://hub.docker.com/layers/jboss/keycloak/12.0.4/images/sha256-67e0c88e69bd0c7aef972c40bdeb558a974013a28b3668ca790ed63a04d70584?context=explore)
This tool will be maintained to stay compatible with Keycloak v11 and up, however, the default pages you will get
(before you customize it) will always be the ones of the Keycloak v11.
This tools assumes you are bundling your app with Webpack (tested with 4.44.2) .
It assumes there is a `build/` directory at the root of your react project directory containing a `index.html` file
and a `static/` directory generated by webpack.
and a `build/static/` directory generated by webpack.
**All this is defaults with [`create-react-app`](https://create-react-app.dev)** (tested with 4.0.3=)
- For building the theme: `mvn` (Maven) must be installed
- For development, (testing the theme in a local container ): `rm`, `mkdir`, `wget`, `unzip` are assumed to be available
- For development (testing the theme in a local container ): `rm`, `mkdir`, `wget`, `unzip` are assumed to be available
and `docker` up and running.
NOTE: This build tool has only be tested on MacOS.
# Limitations
## `process.env.PUBLIC_URL` not supported.
You won't be able to [import things from your public directory in your JavaScript code](https://create-react-app.dev/docs/using-the-public-folder/#adding-assets-outside-of-the-module-system). (This isn't recommended anyway).
## `@font-face` importing fonts from the `src/` dir
### Example of setup that **won't** work
- We have a `fonts/` directory in `src/`
- We import the font like this [`src: url("/fonts/my-font.woff2") format("woff2");`(https://github.com/garronej/keycloakify-demo-app/blob/07d54a3012ef354ee12b1374c6f7ad1cb125d56b/src/fonts.scss#L4) in a `.scss` a file.
### Workarounds
If it is possible, use Google Fonts or any other font provider.
If you want to host your font recommended approach is to move your fonts into the `public`
directory and to place your `@font-face` statements in the `public/index.html`.
Example [here]().
You can also [use your explicit url](https://github.com/garronej/keycloakify-demo-app/blob/2de8a9eb6f5de9c94f9cd3991faad0377e63268c/src/fonts.scss#L16) but don't forget [`Access-Control-Allow-Origin`](https://github.com/garronej/keycloakify-demo-app/blob/2de8a9eb6f5de9c94f9cd3991faad0377e63268c/nginx.conf#L17-L19).
# Implement context persistence (optional)
If, before logging in, a user has selected a specific language
you don't want it to be reset to default when the user gets redirected to
the login or register pages.
Same goes for the dark mode, you don't want, if the user had it enabled
to show the login page with light themes.
The problem is that you are probably using `localStorage` to persist theses values across
reload but, as the Keycloak pages are not served on the same domain that the rest of your
app you won't be able to carry over states using `localStorage`.
The only reliable solution is to inject parameters into the URL before
redirecting to Keycloak. We integrate with
[`keycloak-js`](https://github.com/keycloak/keycloak-documentation/blob/master/securing_apps/topics/oidc/javascript-adapter.adoc),
by providing you a way to tell `keycloak-js` that you would like to inject
some search parameters before redirecting.
The method also works with [`@react-keycloak/web`](https://www.npmjs.com/package/@react-keycloak/web) (use the `initOptions`).
You can implement your own mechanism to pass the states in the URL and
restore it on the other side but we recommend using `powerhooks/useGlobalState`
from the library [`powerhooks`](https://www.powerhooks.dev) that provide an elegant
way to handle states such as `isDarkModeEnabled` or `selectedLanguage`.
Let's modify [the example](https://github.com/keycloak/keycloak-documentation/blob/master/securing_apps/topics/oidc/javascript-adapter.adoc) from the official `keycloak-js` documentation to
enables the states of `useGlobalStates` to be injected in the URL before redirecting.
Note that the states are automatically restored on the other side by `powerhooks`
```typescript
import keycloak_js from "keycloak-js";
import { injectGlobalStatesInSearchParams } from "powerhooks/useGlobalState";
import { createKeycloakAdapter } from "keycloakify";
//...
const keycloakInstance = keycloak_js({
"url": "http://keycloak-server/auth",
"realm": "myrealm",
"clientId": "myapp"
});
keycloakInstance.init({
"onLoad": 'check-sso',
"silentCheckSsoRedirectUri": window.location.origin + "/silent-check-sso.html",
"adapter": createKeycloakAdapter({
"transformUrlBeforeRedirect": injectGlobalStatesInSearchParams,
keycloakInstance
})
});
//...
```
If you really want to go the extra miles and avoid having the white
flash of the blank html before the js bundle have been evaluated
[here is a snippet](https://github.com/InseeFrLab/onyxia-ui/blob/a77eb502870cfe6878edd0d956c646d28746d053/public/index.html#L5-L54) that you can place in your `public/index.html` if you are using `powerhooks/useGlobalState`.
# API Reference
## The build tool
@ -202,11 +278,4 @@ NOTE: This build tool has only be tested on MacOS.
Part of the lib that runs with node, at build time.
- `npx build-keycloak-theme`: Builds the theme, the CWD is assumed to be the root of your react project.
- `npx download-sample-keycloak-themes`: Downloads the keycloak default themes (for development purposes)
## The fronted lib ( imported into your react app )
Part of the lib that you import in your react project and runs on the browser.
**TODO**
- `npx download-sample-keycloak-themes`: Downloads the keycloak default themes (for development purposes)

View File

@ -1,6 +1,6 @@
{
"name": "keycloakify",
"version": "0.2.8",
"version": "0.3.15",
"description": "Keycloak theme generator for Reacts app",
"repository": {
"type": "git",
@ -13,7 +13,6 @@
"build": "yarn clean && tsc && yarn grant-exec-perms && yarn copy-files",
"grant-exec-perms": "node dist/bin/tools/grant-exec-perms.js",
"test": "node dist/test",
"enable_short_import_path": "yarn build && denoify_enable_short_npm_import_path",
"copy-files": "copyfiles -u 1 src/**/*.ftl src/**/*.xml src/**/*.js dist/",
"generate-messages": "node dist/bin/generate-i18n-messages.js",
"watch": "tsc -w"
@ -45,18 +44,17 @@
"@types/node": "^10.0.0",
"@types/react": "^17.0.0",
"copyfiles": "^2.4.1",
"denoify": "^0.6.5",
"properties-parser": "^0.3.1",
"react": "^17.0.1",
"rimraf": "^3.0.2",
"typescript": "^4.1.5"
"typescript": "^4.2.3"
},
"dependencies": {
"cheerio": "^1.0.0-rc.5",
"evt": "2.0.0-beta.15",
"minimal-polyfills": "^2.1.6",
"path": "^0.12.7",
"powerhooks": "^0.0.21",
"powerhooks": "^0.0.27",
"scripting-tools": "^0.19.13",
"tss-react": "^0.0.11"
}

View File

@ -2,7 +2,8 @@
import cheerio from "cheerio";
import {
replaceImportFromStaticInJsCode,
replaceImportsFromStaticInJsCode,
replaceImportsInInlineCssCode,
generateCssCodeToDefineGlobals
} from "../replaceImportFromStatic";
import fs from "fs";
@ -11,9 +12,9 @@ import { objectKeys } from "evt/tools/typeSafety/objectKeys";
export const pageIds = ["login.ftl", "register.ftl", "info.ftl", "error.ftl", "login-reset-password.ftl", "login-verify-email.ftl"] as const;
export type PageId = typeof pageIds[number];
export type PageId = typeof pageIds[number];
function loadAdjacentFile(fileBasename: string){
function loadAdjacentFile(fileBasename: string) {
return fs.readFileSync(pathJoin(__dirname, fileBasename))
.toString("utf8");
};
@ -29,21 +30,23 @@ function loadFtlFile(ftlFileBasename: PageId | "template.ftl") {
}
}
export function generateFtlFilesCodeFactory(
params: {
ftlValuesGlobalName: string;
cssGlobalsToDefine: Record<string, string>;
indexHtmlCode: string;
urlPathname: string;
}
) {
const { ftlValuesGlobalName, cssGlobalsToDefine, indexHtmlCode } = params;
const { ftlValuesGlobalName, cssGlobalsToDefine, indexHtmlCode, urlPathname } = params;
const $ = cheerio.load(indexHtmlCode);
$("script:not([src])").each((...[, element]) => {
const { fixedJsCode } = replaceImportFromStaticInJsCode({
const { fixedJsCode } = replaceImportsFromStaticInJsCode({
ftlValuesGlobalName,
"jsCode": $(element).html()!
});
@ -52,6 +55,17 @@ export function generateFtlFilesCodeFactory(
});
$("style").each((...[, element]) => {
const { fixedCssCode } = replaceImportsInInlineCssCode({
"cssCode": $(element).html()!,
"urlPathname": params.urlPathname
});
$(element).text(fixedCssCode);
});
([
["link", "href"],
["script", "src"],
@ -60,11 +74,17 @@ export function generateFtlFilesCodeFactory(
const href = $(element).attr(attrName);
if (!href?.startsWith("/")) {
if (href === undefined) {
return;
}
$(element).attr(attrName, "${url.resourcesPath}/build" + href);
$(element).attr(
attrName,
href.replace(
new RegExp(`^${urlPathname.replace(/\//g, "\\/")}`),
"${url.resourcesPath}/build/"
)
);
})
);
@ -89,9 +109,10 @@ export function generateFtlFilesCodeFactory(
...(Object.keys(cssGlobalsToDefine).length === 0 ? [] : [
'',
'<style>',
generateCssCodeToDefineGlobals(
{ cssGlobalsToDefine }
).cssCodeToPrependInHead,
generateCssCodeToDefineGlobals({
cssGlobalsToDefine,
urlPathname
}).cssCodeToPrependInHead,
'</style>',
''
]),

View File

@ -3,26 +3,28 @@ import { transformCodebase } from "../tools/transformCodebase";
import * as fs from "fs";
import { join as pathJoin } from "path";
import {
replaceImportFromStaticInCssCode,
replaceImportFromStaticInJsCode
replaceImportsInCssCode,
replaceImportsFromStaticInJsCode
} from "./replaceImportFromStatic";
import { generateFtlFilesCodeFactory, pageIds } from "./generateFtl";
import { builtinThemesUrl } from "../install-builtin-keycloak-themes";
import { downloadAndUnzip } from "../tools/downloadAndUnzip";
import { builtinThemesUrl } from "../install-builtin-keycloak-themes";
import { downloadAndUnzip } from "../tools/downloadAndUnzip";
import * as child_process from "child_process";
import { ftlValuesGlobalName } from "./ftlValuesGlobalName";
import { resourcesCommonPath, resourcesPath, subDirOfPublicDirBasename } from "../../lib/kcContextMocks/urlResourcesPath";
import { isInside } from "../tools/isInside";
import { ftlValuesGlobalName } from "./ftlValuesGlobalName";
import { resourcesCommonPath, resourcesPath, subDirOfPublicDirBasename } from "../../lib/kcContextMocks/urlResourcesPath";
import { isInside } from "../tools/isInside";
export function generateKeycloakThemeResources(
params: {
themeName: string;
reactAppBuildDirPath: string;
keycloakThemeBuildingDirPath: string;
urlPathname: string;
}
) {
const { themeName, reactAppBuildDirPath, keycloakThemeBuildingDirPath } = params;
const { themeName, reactAppBuildDirPath, keycloakThemeBuildingDirPath, urlPathname } = params;
const themeDirPath = pathJoin(keycloakThemeBuildingDirPath, "src", "main", "resources", "theme", themeName, "login");
@ -46,7 +48,7 @@ export function generateKeycloakThemeResources(
if (/\.css?$/i.test(filePath)) {
const { cssGlobalsToDefine, fixedCssCode } = replaceImportFromStaticInCssCode(
const { cssGlobalsToDefine, fixedCssCode } = replaceImportsInCssCode(
{ "cssCode": sourceCode.toString("utf8") }
);
@ -59,9 +61,10 @@ export function generateKeycloakThemeResources(
}
if (/\.js?$/i.test(filePath)) {
const { fixedJsCode } = replaceImportFromStaticInJsCode({
const { fixedJsCode } = replaceImportsFromStaticInJsCode({
"jsCode": sourceCode.toString("utf8"),
ftlValuesGlobalName
});
@ -80,7 +83,8 @@ export function generateKeycloakThemeResources(
ftlValuesGlobalName,
"indexHtmlCode": fs.readFileSync(
pathJoin(reactAppBuildDirPath, "index.html")
).toString("utf8")
).toString("utf8"),
urlPathname
});
pageIds.forEach(pageId => {

View File

@ -6,6 +6,7 @@ import type { ParsedPackageJson } from "./generateJavaStackFiles";
import { join as pathJoin, relative as pathRelative, basename as pathBasename } from "path";
import * as child_process from "child_process";
import { generateDebugFiles, containerLaunchScriptBasename } from "./generateDebugFiles";
import { URL } from "url";
const reactProjectDirPath = process.cwd();
@ -22,7 +23,25 @@ if (require.main === module) {
generateKeycloakThemeResources({
keycloakThemeBuildingDirPath,
"reactAppBuildDirPath": pathJoin(reactProjectDirPath, "build"),
"themeName": parsedPackageJson.name
"themeName": parsedPackageJson.name,
"urlPathname": (() => {
const url = (() => {
const { homepage } = parsedPackageJson;
return homepage === undefined ?
undefined :
new URL(homepage);
})();
return url === undefined ?
"/" :
url.pathname.replace(/([^/])$/, "$1/");
})()
});
const { jarFilePath } = generateJavaStackFiles({

View File

@ -1,7 +1,7 @@
import * as crypto from "crypto";
export function replaceImportFromStaticInJsCode(
export function replaceImportsFromStaticInJsCode(
params: {
ftlValuesGlobalName: string;
jsCode: string;
@ -10,16 +10,36 @@ export function replaceImportFromStaticInJsCode(
const { jsCode, ftlValuesGlobalName } = params;
const fixedJsCode = jsCode!.replace(
/"static\//g,
`window.${ftlValuesGlobalName}.url.resourcesPath.replace(/^\\//,"") + "/build/static/`
const fixedJsCode = jsCode.replace(
/[a-z]+\.[a-z]+\+"static\//g,
`window.${ftlValuesGlobalName}.url.resourcesPath + "/build/static/`
);
return { fixedJsCode };
}
export function replaceImportFromStaticInCssCode(
export function replaceImportsInInlineCssCode(
params: {
cssCode: string;
urlPathname: string;
}
): { fixedCssCode: string; } {
const { cssCode, urlPathname } = params;
const fixedCssCode = cssCode.replace(
urlPathname === "/" ?
/url\(\/([^/][^)]+)\)/g :
new RegExp(`url\\(${urlPathname}([^)]+)\\)`, "g"),
(...[, group]) => `url(${"${url.resourcesPath}/build/" + group})`
);
return { fixedCssCode };
}
export function replaceImportsInCssCode(
params: {
cssCode: string;
}
@ -32,7 +52,7 @@ export function replaceImportFromStaticInCssCode(
const cssGlobalsToDefine: Record<string, string> = {};
new Set(cssCode.match(/(url\(\/[^)]+\))/g) ?? [])
new Set(cssCode.match(/url\(\/[^/][^)]+\)[^;}]*/g) ?? [])
.forEach(match =>
cssGlobalsToDefine[
"url" + crypto
@ -60,12 +80,13 @@ export function replaceImportFromStaticInCssCode(
export function generateCssCodeToDefineGlobals(
params: {
cssGlobalsToDefine: Record<string, string>;
urlPathname: string;
}
): {
cssCodeToPrependInHead: string;
} {
const { cssGlobalsToDefine } = params;
const { cssGlobalsToDefine, urlPathname } = params;
return {
"cssCodeToPrependInHead": [
@ -73,12 +94,8 @@ export function generateCssCodeToDefineGlobals(
...Object.keys(cssGlobalsToDefine)
.map(cssVariableName => [
`--${cssVariableName}:`,
[
"url(",
"${url.resourcesPath}/build" +
cssGlobalsToDefine[cssVariableName].match(/^url\(([^)]+)\)$/)![1],
")"
].join("")
cssGlobalsToDefine[cssVariableName]
.replace(new RegExp(`url\\(${urlPathname.replace(/\//g, "\\/")}`, "g"), "url(${url.resourcesPath}/build/")
].join(" "))
.map(line => ` ${line};`),
"}"

View File

@ -66,7 +66,7 @@ export const LoginResetPassword = memo(({ kcContext, ...props }: { kcContext: Kc
props.kcButtonBlockClass, props.kcButtonLargeClass
)}
type="submit"
defaultValue={msgStr("doSubmit")}
value={msgStr("doSubmit")}
/>
</div>
</div>

View File

@ -113,7 +113,7 @@ export const Register = memo(({ kcContext, ...props }: { kcContext: KcContext.Re
<div id="kc-form-buttons" className={cx(props.kcFormButtonsClass)}>
<input className={cx(props.kcButtonClass, props.kcButtonPrimaryClass, props.kcButtonBlockClass, props.kcButtonLargeClass)} type="submit"
defaultValue={msgStr("doRegister")} />
value={msgStr("doRegister")} />
</div>
</div>
</form >

View File

@ -25,8 +25,7 @@ export type TemplateProps = {
showUsernameNode?: ReactNode;
formNode: ReactNode;
infoNode?: ReactNode;
} & { kcContext: KcContext.Template; } & KcTemplateProps;
} & { kcContext: KcContext.Template; } & KcTemplateProps;
export const Template = memo((props: TemplateProps) => {
@ -60,34 +59,35 @@ export const Template = memo((props: TemplateProps) => {
);
const {
realm, locale, auth,
realm, locale, auth,
url, message, isAppInitiatedAction
}= kcContext;
} = kcContext;
useEffect(()=>{
useEffect(() => {
if( !realm.internationalizationEnabled ){
if (!realm.internationalizationEnabled) {
return;
}
assert( locale !== undefined );
assert(locale !== undefined);
if( kcLanguageTag === getBestMatchAmongKcLanguageTag(locale.current) ){
if (kcLanguageTag === getBestMatchAmongKcLanguageTag(locale.current)) {
return;
}
window.location.href =
window.location.href =
locale.supported.find(({ languageTag }) => languageTag === kcLanguageTag)!.url;
},[kcLanguageTag]);
}, [kcLanguageTag]);
const [isExtraCssLoaded, setExtraCssLoaded] = useReducer(() => true, false);
useEffect(() => {
let isUnmounted = false;
const cleanups: (() => void)[] = [];
const toArr = (x: string | readonly string[] | undefined) =>
const toArr = (x: string | readonly string[] | undefined) =>
typeof x === "string" ? x.split(" ") : x ?? [];
Promise.all(
@ -114,13 +114,29 @@ export const Template = memo((props: TemplateProps) => {
})
);
document.getElementsByTagName("html")[0]
.classList
.add(cx(props.kcHtmlClass));
if (props.kcHtmlClass !== undefined) {
return () => { isUnmounted = true; };
const htmlClassList =
document.getElementsByTagName("html")[0]
.classList;
}, []);
const tokens = cx(props.kcHtmlClass).split(" ")
htmlClassList.add(...tokens);
cleanups.push(() => htmlClassList.remove(...tokens));
}
return () => {
isUnmounted = true;
cleanups.forEach(f => f());
};
}, [props.kcHtmlClass]);
if (!isExtraCssLoaded) {
return null;
@ -152,7 +168,7 @@ export const Template = memo((props: TemplateProps) => {
<ul>
{
locale.supported.map(
({ languageTag }) =>
({ languageTag }) =>
<li key={languageTag} className="kc-dropdown-item">
<a href="#" onClick={onChangeLanguageClickFactory(languageTag)}>
{getKcLanguageTagLabel(languageTag)}
@ -218,21 +234,21 @@ export const Template = memo((props: TemplateProps) => {
</div>
</div>
) : (
<>
{showUsernameNode}
<div className={cx(props.kcFormGroupClass)}>
<div id="kc-username">
<label id="kc-attempted-username">{auth?.attemptedUsername}</label>
<a id="reset-login" href={url.loginRestartFlowUrl}>
<div className="kc-login-tooltip">
<i className={cx(props.kcResetFlowIcon)}></i>
<span className="kc-tooltip-text">{msg("restartLoginTooltip")}</span>
</div>
</a>
</div>
<>
{showUsernameNode}
<div className={cx(props.kcFormGroupClass)}>
<div id="kc-username">
<label id="kc-attempted-username">{auth?.attemptedUsername}</label>
<a id="reset-login" href={url.loginRestartFlowUrl}>
<div className="kc-login-tooltip">
<i className={cx(props.kcResetFlowIcon)}></i>
<span className="kc-tooltip-text">{msg("restartLoginTooltip")}</span>
</div>
</a>
</div>
</>
)
</div>
</>
)
)
}
</header>

View File

@ -12,6 +12,7 @@ export * from "./components/Info";
export * from "./components/Error";
export * from "./components/LoginResetPassword";
export * from "./components/LoginVerifyEmail";
export * from "./keycloakJsAdapter";
export * from "./tools/assert";

View File

@ -9,8 +9,8 @@ import { resourcesCommonPath, resourcesPath } from "./urlResourcesPath";
export const kcTemplateContext: KcContext.Template = {
"url": {
"loginAction": "#",
"resourcesPath": "/" + resourcesPath,
"resourcesCommonPath": "/" + resourcesCommonPath,
"resourcesPath": `${process.env["PUBLIC_URL"]}/${resourcesPath}`,
"resourcesCommonPath": `${process.env["PUBLIC_URL"]}/${resourcesCommonPath}`,
"loginRestartFlowUrl": "/auth/realms/myrealm/login-actions/restart?client_id=account&tab_id=HoAx28ja4xg",
"loginUrl": "/auth/realms/myrealm/login-actions/authenticate?client_id=account&tab_id=HoAx28ja4xg",
},

View File

@ -0,0 +1,119 @@
export declare namespace keycloak_js {
export type KeycloakPromiseCallback<T> = (result: T) => void;
export class KeycloakPromise<TSuccess, TError> extends Promise<TSuccess> {
success(callback: KeycloakPromiseCallback<TSuccess>): KeycloakPromise<TSuccess, TError>;
error(callback: KeycloakPromiseCallback<TError>): KeycloakPromise<TSuccess, TError>;
}
export interface KeycloakAdapter {
login(options?: KeycloakLoginOptions): KeycloakPromise<void, void>;
logout(options?: KeycloakLogoutOptions): KeycloakPromise<void, void>;
register(options?: KeycloakLoginOptions): KeycloakPromise<void, void>;
accountManagement(): KeycloakPromise<void, void>;
redirectUri(options: { redirectUri: string; }, encodeHash: boolean): string;
}
export interface KeycloakLogoutOptions {
redirectUri?: string;
}
export interface KeycloakLoginOptions {
scope?: string;
redirectUri?: string;
prompt?: 'none' | 'login';
action?: string;
maxAge?: number;
loginHint?: string;
idpHint?: string;
locale?: string;
cordovaOptions?: { [optionName: string]: string };
}
export type KeycloakInstance = Record<
"createLoginUrl" |
"createLogoutUrl" |
"createRegisterUrl",
(options: KeycloakLoginOptions | undefined) => string
> & {
createAccountUrl(): string;
redirectUri?: string;
}
}
/**
* NOTE: This is just a slightly modified version of the default adapter in keycloak-js
* The goal here is just to be able to inject search param in url before keycloak redirect.
* Our use case for it is to pass over the login screen the states of useGlobalState
* namely isDarkModeEnabled, lgn...
*/
export function createKeycloakAdapter(
params: {
keycloakInstance: keycloak_js.KeycloakInstance;
transformUrlBeforeRedirect(url: string): string;
}
): keycloak_js.KeycloakAdapter {
const { keycloakInstance, transformUrlBeforeRedirect } = params;
const neverResolvingPromise: keycloak_js.KeycloakPromise<void, void> = Object.defineProperties(
new Promise(() => { }),
{
"success": { "value": () => { } },
"error": { "value": () => { } }
}
);
return {
"login": options => {
window.location.replace(
transformUrlBeforeRedirect(
keycloakInstance.createLoginUrl(
options
)
)
);
return neverResolvingPromise;
},
"logout": options => {
window.location.replace(
transformUrlBeforeRedirect(
keycloakInstance.createLogoutUrl(
options
)
)
);
return neverResolvingPromise;
},
"register": options => {
window.location.replace(
transformUrlBeforeRedirect(
keycloakInstance.createRegisterUrl(
options
)
)
);
return neverResolvingPromise;
},
"accountManagement": () => {
var accountUrl = transformUrlBeforeRedirect(keycloakInstance.createAccountUrl());
if (typeof accountUrl !== 'undefined') {
window.location.href = accountUrl;
} else {
throw new Error("Not supported by the OIDC server");
}
return neverResolvingPromise;
},
"redirectUri": options => {
if (options && options.redirectUri) {
return options.redirectUri;
} else if (keycloakInstance.redirectUri) {
return keycloakInstance.redirectUri;
} else {
return window.location.href;
}
}
};
}

View File

@ -1,7 +1,7 @@
import { join as pathJoin } from "path";
import { generateKeycloakThemeResources } from "../bin/build-keycloak-theme/generateKeycloakThemeResources";
import {
import {
setupSampleReactProject,
sampleReactProjectDirPath
} from "./setupSampleReactProject";
@ -9,8 +9,9 @@ import {
setupSampleReactProject();
generateKeycloakThemeResources({
"themeName": "onyxia-ui",
"themeName": "keycloakify-demo-app",
"reactAppBuildDirPath": pathJoin(sampleReactProjectDirPath, "build"),
"keycloakThemeBuildingDirPath": pathJoin(sampleReactProjectDirPath, "build_keycloak_theme")
"keycloakThemeBuildingDirPath": pathJoin(sampleReactProjectDirPath, "build_keycloak_theme"),
"urlPathname": "/keycloakify-demo-app/"
});

View File

@ -1,11 +1,11 @@
import { 
replaceImportFromStaticInJsCode,
replaceImportFromStaticInCssCode,
replaceImportsFromStaticInJsCode,
replaceImportsInCssCode,
generateCssCodeToDefineGlobals
} from "../bin/build-keycloak-theme/replaceImportFromStatic";
const { fixedJsCode } = replaceImportFromStaticInJsCode({
const { fixedJsCode } = replaceImportsFromStaticInJsCode({
"ftlValuesGlobalName": "keycloakFtlValues",
"jsCode": `
function f() {
@ -24,7 +24,7 @@ const { fixedJsCode } = replaceImportFromStaticInJsCode({
console.log({ fixedJsCode });
const { fixedCssCode, cssGlobalsToDefine } = replaceImportFromStaticInCssCode({
const { fixedCssCode, cssGlobalsToDefine } = replaceImportsInCssCode({
"cssCode": `
.my-div {
@ -45,6 +45,6 @@ const { fixedCssCode, cssGlobalsToDefine } = replaceImportFromStaticInCssCode({
console.log({ fixedCssCode, cssGlobalsToDefine });
const { cssCodeToPrependInHead } = generateCssCodeToDefineGlobals({ cssGlobalsToDefine });
const { cssCodeToPrependInHead } = generateCssCodeToDefineGlobals({ cssGlobalsToDefine, "urlPathname": "/" });
console.log({ cssCodeToPrependInHead });

236
yarn.lock
View File

@ -139,114 +139,6 @@
resolved "https://registry.yarnpkg.com/@emotion/weak-memoize/-/weak-memoize-0.2.5.tgz#8eed982e2ee6f7f4e44c253e12962980791efd46"
integrity sha512-6U71C2Wp7r5XtFtQzYrW5iKFT67OixrSxjI4MptCHzdSVlgabczzqLe0ZSgnub/5Kp4hSbpDB1tMytZY9pwxxA==
"@octokit/auth-token@^2.4.4":
version "2.4.5"
resolved "https://registry.yarnpkg.com/@octokit/auth-token/-/auth-token-2.4.5.tgz#568ccfb8cb46f36441fac094ce34f7a875b197f3"
integrity sha512-BpGYsPgJt05M7/L/5FoE1PiAbdxXFZkX/3kDYcsvd1v6UhlnE5e96dTDr0ezX/EFwciQxf3cNV0loipsURU+WA==
dependencies:
"@octokit/types" "^6.0.3"
"@octokit/core@^3.2.3":
version "3.3.0"
resolved "https://registry.yarnpkg.com/@octokit/core/-/core-3.3.0.tgz#58afc26c302e22cf97491bad9a30b2f33e2bcaed"
integrity sha512-GGMpjaodCBY7JrtOwfolMocwZw9Pj5NxuQqfaJhGau4tkyonm0JRV9D6juQYLMb1Kl261++4Q980o0FlAtg8jg==
dependencies:
"@octokit/auth-token" "^2.4.4"
"@octokit/graphql" "^4.5.8"
"@octokit/request" "^5.4.12"
"@octokit/request-error" "^2.0.5"
"@octokit/types" "^6.0.3"
before-after-hook "^2.2.0"
universal-user-agent "^6.0.0"
"@octokit/endpoint@^6.0.1":
version "6.0.11"
resolved "https://registry.yarnpkg.com/@octokit/endpoint/-/endpoint-6.0.11.tgz#082adc2aebca6dcefa1fb383f5efb3ed081949d1"
integrity sha512-fUIPpx+pZyoLW4GCs3yMnlj2LfoXTWDUVPTC4V3MUEKZm48W+XYpeWSZCv+vYF1ZABUm2CqnDVf1sFtIYrj7KQ==
dependencies:
"@octokit/types" "^6.0.3"
is-plain-object "^5.0.0"
universal-user-agent "^6.0.0"
"@octokit/graphql@^4.5.8":
version "4.6.1"
resolved "https://registry.yarnpkg.com/@octokit/graphql/-/graphql-4.6.1.tgz#f975486a46c94b7dbe58a0ca751935edc7e32cc9"
integrity sha512-2lYlvf4YTDgZCTXTW4+OX+9WTLFtEUc6hGm4qM1nlZjzxj+arizM4aHWzBVBCxY9glh7GIs0WEuiSgbVzv8cmA==
dependencies:
"@octokit/request" "^5.3.0"
"@octokit/types" "^6.0.3"
universal-user-agent "^6.0.0"
"@octokit/openapi-types@^5.3.2":
version "5.3.2"
resolved "https://registry.yarnpkg.com/@octokit/openapi-types/-/openapi-types-5.3.2.tgz#b8ac43c5c3d00aef61a34cf744e315110c78deb4"
integrity sha512-NxF1yfYOUO92rCx3dwvA2onF30Vdlg7YUkMVXkeptqpzA3tRLplThhFleV/UKWFgh7rpKu1yYRbvNDUtzSopKA==
"@octokit/plugin-paginate-rest@^2.6.2":
version "2.13.2"
resolved "https://registry.yarnpkg.com/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.13.2.tgz#7b8244a0dd7a31135ba2adc58a533213837bfe87"
integrity sha512-mjfBcla00UNS4EI/NN7toEbUM45ow3kk4go+LxsXAFLQodsrXcIZbftUhXTqi6ZKd+r6bcqMI+Lv4dshLtFjww==
dependencies:
"@octokit/types" "^6.11.0"
"@octokit/plugin-request-log@^1.0.2":
version "1.0.3"
resolved "https://registry.yarnpkg.com/@octokit/plugin-request-log/-/plugin-request-log-1.0.3.tgz#70a62be213e1edc04bb8897ee48c311482f9700d"
integrity sha512-4RFU4li238jMJAzLgAwkBAw+4Loile5haQMQr+uhFq27BmyJXcXSKvoQKqh0agsZEiUlW6iSv3FAgvmGkur7OQ==
"@octokit/plugin-rest-endpoint-methods@4.13.5":
version "4.13.5"
resolved "https://registry.yarnpkg.com/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-4.13.5.tgz#ad76285b82fe05fbb4adf2774a9c887f3534a880"
integrity sha512-kYKcWkFm4Ldk8bZai2RVEP1z97k1C/Ay2FN9FNTBg7JIyKoiiJjks4OtT6cuKeZX39tqa+C3J9xeYc6G+6g8uQ==
dependencies:
"@octokit/types" "^6.12.2"
deprecation "^2.3.1"
"@octokit/request-error@^2.0.0", "@octokit/request-error@^2.0.5":
version "2.0.5"
resolved "https://registry.yarnpkg.com/@octokit/request-error/-/request-error-2.0.5.tgz#72cc91edc870281ad583a42619256b380c600143"
integrity sha512-T/2wcCFyM7SkXzNoyVNWjyVlUwBvW3igM3Btr/eKYiPmucXTtkxt2RBsf6gn3LTzaLSLTQtNmvg+dGsOxQrjZg==
dependencies:
"@octokit/types" "^6.0.3"
deprecation "^2.0.0"
once "^1.4.0"
"@octokit/request@^5.3.0", "@octokit/request@^5.4.12":
version "5.4.14"
resolved "https://registry.yarnpkg.com/@octokit/request/-/request-5.4.14.tgz#ec5f96f78333bb2af390afa5ff66f114b063bc96"
integrity sha512-VkmtacOIQp9daSnBmDI92xNIeLuSRDOIuplp/CJomkvzt7M18NXgG044Cx/LFKLgjKt9T2tZR6AtJayba9GTSA==
dependencies:
"@octokit/endpoint" "^6.0.1"
"@octokit/request-error" "^2.0.0"
"@octokit/types" "^6.7.1"
deprecation "^2.0.0"
is-plain-object "^5.0.0"
node-fetch "^2.6.1"
once "^1.4.0"
universal-user-agent "^6.0.0"
"@octokit/rest@^18.0.0":
version "18.3.5"
resolved "https://registry.yarnpkg.com/@octokit/rest/-/rest-18.3.5.tgz#a89903d46e0b4273bd3234674ec2777a651d68ab"
integrity sha512-ZPeRms3WhWxQBEvoIh0zzf8xdU2FX0Capa7+lTca8YHmRsO3QNJzf1H3PcuKKsfgp91/xVDRtX91sTe1kexlbw==
dependencies:
"@octokit/core" "^3.2.3"
"@octokit/plugin-paginate-rest" "^2.6.2"
"@octokit/plugin-request-log" "^1.0.2"
"@octokit/plugin-rest-endpoint-methods" "4.13.5"
"@octokit/types@^6.0.3", "@octokit/types@^6.11.0", "@octokit/types@^6.12.2", "@octokit/types@^6.7.1":
version "6.12.2"
resolved "https://registry.yarnpkg.com/@octokit/types/-/types-6.12.2.tgz#5b44add079a478b8eb27d78cf384cc47e4411362"
integrity sha512-kCkiN8scbCmSq+gwdJV0iLgHc0O/GTPY1/cffo9kECu1MvatLPh9E+qFhfRIktKfHEA6ZYvv6S1B4Wnv3bi3pA==
dependencies:
"@octokit/openapi-types" "^5.3.2"
"@types/comment-json@^1.1.1":
version "1.1.1"
resolved "https://registry.yarnpkg.com/@types/comment-json/-/comment-json-1.1.1.tgz#b4ae889912a93e64619f97989aecaff8ce889dca"
integrity sha512-U70oEqvnkeSSp8BIJwJclERtT13rd9ejK7XkIzMCQQePZe3VW1b7iQggXyW4ZvfGtGeXD0pZw24q5iWNe++HqQ==
"@types/node@^10.0.0":
version "10.17.55"
resolved "https://registry.yarnpkg.com/@types/node/-/node-10.17.55.tgz#a147f282edec679b894d4694edb5abeb595fecbd"
@ -309,11 +201,6 @@ balanced-match@^1.0.0:
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c=
before-after-hook@^2.2.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/before-after-hook/-/before-after-hook-2.2.0.tgz#09c40d92e936c64777aa385c4e9b904f8147eaf0"
integrity sha512-jH6rKQIfroBbhEXVmI7XmXe3ix5S/PgJqpzdDPnR8JGLHWNYLsYZ6tK5iWOF/Ra3oqEX0NobXGlzbiylIzVphQ==
boolbase@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e"
@ -398,21 +285,6 @@ color-name@~1.1.4:
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
commander@^4.1.1:
version "4.1.1"
resolved "https://registry.yarnpkg.com/commander/-/commander-4.1.1.tgz#9fd602bd936294e9e9ef46a3f4d6964044b18068"
integrity sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==
comment-json@^3.0.2:
version "3.0.3"
resolved "https://registry.yarnpkg.com/comment-json/-/comment-json-3.0.3.tgz#0cadacd6278602b57b8c51b1814dc5d311d228c4"
integrity sha512-P7XwYkC3qjIK45EAa9c5Y3lR7SMXhJqwFdWg3niAIAcbk3zlpKDdajV8Hyz/Y3sGNn3l+YNMl8A2N/OubSArHg==
dependencies:
core-util-is "^1.0.2"
esprima "^4.0.1"
has-own-prop "^2.0.0"
repeat-string "^1.6.1"
concat-map@0.0.1:
version "0.0.1"
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
@ -438,7 +310,7 @@ copyfiles@^2.4.1:
untildify "^4.0.0"
yargs "^16.1.0"
core-util-is@^1.0.2, core-util-is@~1.0.0:
core-util-is@~1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=
@ -483,29 +355,6 @@ d@1, d@^1.0.1:
es5-ext "^0.10.50"
type "^1.0.1"
denoify@^0.6.5:
version "0.6.5"
resolved "https://registry.yarnpkg.com/denoify/-/denoify-0.6.5.tgz#06512be38026ec0f2033db9566d07428e63d56bf"
integrity sha512-AhKBlvO91QdP5T/fRcxiMj3b6cDe5ucr+7YVlePXCuV/kImbiR0V1qjGTCfmVuC3wvRn5Xf6r34qJJRbo86AqA==
dependencies:
"@octokit/rest" "^18.0.0"
"@types/comment-json" "^1.1.1"
commander "^4.1.1"
comment-json "^3.0.2"
evt "^1.9.2"
get-github-default-branch-name "^0.0.4"
gitignore-parser "0.0.2"
glob "^7.1.6"
node-fetch "^2.6.0"
path-depth "^1.0.0"
scripting-tools "^0.19.13"
url-join "^4.0.1"
deprecation@^2.0.0, deprecation@^2.3.1:
version "2.3.1"
resolved "https://registry.yarnpkg.com/deprecation/-/deprecation-2.3.1.tgz#6368cbdb40abf3373b525ac87e4a260c3a700919"
integrity sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==
dom-serializer@^1.0.1, dom-serializer@~1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-1.2.0.tgz#3433d9136aeb3c627981daa385fc7f32d27c48f1"
@ -609,11 +458,6 @@ escape-string-regexp@^4.0.0:
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34"
integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==
esprima@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71"
integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==
event-emitter@^0.3.5:
version "0.3.5"
resolved "https://registry.yarnpkg.com/event-emitter/-/event-emitter-0.3.5.tgz#df8c69eef1647923c7157b9ce83840610b02cc39"
@ -630,14 +474,6 @@ evt@2.0.0-beta.15:
minimal-polyfills "^2.1.5"
run-exclusive "^2.2.14"
evt@^1.9.2:
version "1.9.12"
resolved "https://registry.yarnpkg.com/evt/-/evt-1.9.12.tgz#8d06177259cbcb09ef936e18945bf7ddd087170c"
integrity sha512-u8wC4Xif2pcDJ9cEm0wzWCIQb+Y214m1eUgsgm2hVIuXuvC6LToryA0Ecl1O8Slii2E9l6USLsyxXWntjlnIbw==
dependencies:
minimal-polyfills "^2.1.5"
run-exclusive "^2.2.14"
ext@^1.1.2:
version "1.4.0"
resolved "https://registry.yarnpkg.com/ext/-/ext-1.4.0.tgz#89ae7a07158f79d35517882904324077e4379244"
@ -665,20 +501,7 @@ get-caller-file@^2.0.5:
resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e"
integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==
get-github-default-branch-name@^0.0.4:
version "0.0.4"
resolved "https://registry.yarnpkg.com/get-github-default-branch-name/-/get-github-default-branch-name-0.0.4.tgz#9c0c6606ba606edb136d2fd26e4d515b69f2de90"
integrity sha512-ltOGC9Jk0k8boe48Gk7SkJErwxt7MhwXtbNrBUyNCZcwcXSmGRdkKb2u0YO250PGvPsUtdqRjg7lVuIk1VtpCg==
dependencies:
"@octokit/rest" "^18.0.0"
scripting-tools "^0.19.12"
gitignore-parser@0.0.2:
version "0.0.2"
resolved "https://registry.yarnpkg.com/gitignore-parser/-/gitignore-parser-0.0.2.tgz#f61259b985dd91414b9a7168faef9171c2eec5df"
integrity sha1-9hJZuYXdkUFLmnFo+u+RccLuxd8=
glob@^7.0.5, glob@^7.1.3, glob@^7.1.6:
glob@^7.0.5, glob@^7.1.3:
version "7.1.6"
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6"
integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==
@ -695,11 +518,6 @@ has-flag@^3.0.0:
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0=
has-own-prop@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/has-own-prop/-/has-own-prop-2.0.0.tgz#f0f95d58f65804f5d218db32563bb85b8e0417af"
integrity sha512-Pq0h+hvsVm6dDEa8x82GnLSYHOzNDt7f0ddFa3FqcQlgzEiptPqL+XrOJNavjOzSYiYWIrgeVYYgGlLmnxwilQ==
has@^1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796"
@ -760,11 +578,6 @@ is-fullwidth-code-point@^3.0.0:
resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d"
integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==
is-plain-object@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-5.0.0.tgz#4427f50ab3429e9025ea7d52e9043a9ef4159344"
integrity sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==
is-promise@^2.2.2:
version "2.2.2"
resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.2.2.tgz#39ab959ccbf9a774cf079f7b40c7a26f763135f1"
@ -855,11 +668,6 @@ next-tick@~1.0.0:
resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-1.0.0.tgz#ca86d1fe8828169b0120208e3dc8424b9db8342c"
integrity sha1-yobR/ogoFpsBICCOPchCS524NCw=
node-fetch@^2.6.0, node-fetch@^2.6.1:
version "2.6.1"
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052"
integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==
noms@0.0.0:
version "0.0.0"
resolved "https://registry.yarnpkg.com/noms/-/noms-0.0.0.tgz#da8ebd9f3af9d6760919b27d9cdc8092a7332859"
@ -880,7 +688,7 @@ object-assign@^4.1.1:
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=
once@^1.3.0, once@^1.4.0:
once@^1.3.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E=
@ -916,11 +724,6 @@ parse5@^6.0.0, parse5@^6.0.1:
resolved "https://registry.yarnpkg.com/parse5/-/parse5-6.0.1.tgz#e1a1c085c569b3dc08321184f19a39cc27f7c30b"
integrity sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==
path-depth@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/path-depth/-/path-depth-1.0.0.tgz#88cf881097e171b8b54d450d2167ea76063d3086"
integrity sha512-dEiwdXAQyLvOi6ktLqhFhjVelJiVsdp2xBX3BaUtYCCkMRZTwUiq7cha+A0myvAVXRHbXfjhfTf4mNoAWzm2iA==
path-is-absolute@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
@ -944,10 +747,10 @@ path@^0.12.7:
process "^0.11.1"
util "^0.10.3"
powerhooks@^0.0.21:
version "0.0.21"
resolved "https://registry.yarnpkg.com/powerhooks/-/powerhooks-0.0.21.tgz#0eebaffa3193157981f8cdadd38e76c59e98bb82"
integrity sha512-CmysMra4VNK0eU70PtvxVBzGIi5SXS+oFI2Hd1R5VPzCbQh0ud56EBvfZT5jmnrKAzoLOW6W01FGRwgFskEJfg==
powerhooks@^0.0.27:
version "0.0.27"
resolved "https://registry.yarnpkg.com/powerhooks/-/powerhooks-0.0.27.tgz#e9dc29258860d2f6bf32b249d9cba07c6f53f393"
integrity sha512-ohayWhtIEdLqiC2th/GEhaRfOhqekFg2uFo0JZ8Dn7oTnAZybs618QJeq5ag9oy3lFVzl+kbROpVa8Ch5zrkaA==
dependencies:
evt "2.0.0-beta.15"
memoizee "^0.4.15"
@ -1006,11 +809,6 @@ regenerator-runtime@^0.13.4:
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz#cac2dacc8a1ea675feaabaeb8ae833898ae46f55"
integrity sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==
repeat-string@^1.6.1:
version "1.6.1"
resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637"
integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc=
require-directory@^2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42"
@ -1053,7 +851,7 @@ safe-buffer@~5.1.0, safe-buffer@~5.1.1:
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
scripting-tools@^0.19.12, scripting-tools@^0.19.13:
scripting-tools@^0.19.13:
version "0.19.13"
resolved "https://registry.yarnpkg.com/scripting-tools/-/scripting-tools-0.19.13.tgz#836df7d9c2ec99aea91984d1d5b2bd110670afec"
integrity sha512-d09H8vzSVa8p4XUTJqHZDbjKDyl5TG3SyPfNPUUkfyOwjwykStmfK8AXyWq7VRWjcgzTpkTiJ9uMk1NytMQY7w==
@ -1146,26 +944,16 @@ type@^2.0.0:
resolved "https://registry.yarnpkg.com/type/-/type-2.5.0.tgz#0a2e78c2e77907b252abe5f298c1b01c63f0db3d"
integrity sha512-180WMDQaIMm3+7hGXWf12GtdniDEy7nYcyFMKJn/eZz/6tSLXrUN9V0wKSbMjej0I1WHWbpREDEKHtqPQa9NNw==
typescript@^4.1.5:
typescript@^4.2.3:
version "4.2.3"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.2.3.tgz#39062d8019912d43726298f09493d598048c1ce3"
integrity sha512-qOcYwxaByStAWrBf4x0fibwZvMRG+r4cQoTjbPtUlrWjBHbmCAww1i448U0GJ+3cNNEtebDteo/cHOR3xJ4wEw==
universal-user-agent@^6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/universal-user-agent/-/universal-user-agent-6.0.0.tgz#3381f8503b251c0d9cd21bc1de939ec9df5480ee"
integrity sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w==
untildify@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/untildify/-/untildify-4.0.0.tgz#2bc947b953652487e4600949fb091e3ae8cd919b"
integrity sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==
url-join@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/url-join/-/url-join-4.0.1.tgz#b642e21a2646808ffa178c4c5fda39844e12cde7"
integrity sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==
util-deprecate@~1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
@ -1203,9 +991,9 @@ y18n@^5.0.5:
integrity sha512-hsRUr4FFrvhhRH12wOdfs38Gy7k2FFzB9qgN9v3aLykRq0dRcdcpz5C9FxdS2NuhOrI/628b/KSTJ3rwHysYSg==
yaml@^1.7.2:
version "1.10.1"
resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.1.tgz#bb13d805ed104fba38f533570f3441027eeeca22"
integrity sha512-z/asvd+V08l1ywhaemZVirCwjdzLo6O1/0j2JbYCsGjiezupNQqjs5IIPyNtctbHjPEckqzVGd4jvpU5Lr25vQ==
version "1.10.2"
resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b"
integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==
yargs-parser@^20.2.2:
version "20.2.7"