From 744b5172a1271baa02bbe789b9bdbcb752905878 Mon Sep 17 00:00:00 2001 From: Norbert Nagy Date: Tue, 27 Aug 2024 13:33:08 +0300 Subject: [PATCH] Feature/v1.19.0 (#113) * refactor(console): check mermaid by integration test env (#6183) * feat(core): implement new experience API routes (#5992) * feat(core): implement new interaction-session management flow implement a new interaction-session management flow for experience api use * feat(core): implement password sign-in flow implement password sign-in flow * test(core,schemas): add sign-in password tests add sign-in password tests * chore(core): update comments update comments * refactor(core): rename the password input value key rename the password input value key * refactor(core,schemas): refactor the experience API refactor the exerpience API structure * chore(test): add devFeature test add devFeature test * refactor(core): rename the path rename the path * refactor(core,schemas): refactor using the latest API design refactor using the latest API design * chore(test): replace using devFeature test statement replace using devFeature test statement * fix(core): fix lint error fix lint error * refactor(core): refactor experience API implementations refactor experience API implementations * refactor(core): replace with switch replace object map with switch * refactor: apply suggestions from code review * refactor(core): refactor the interaction class refactor the interaction class * refactor(core): update the user identification logic update the user identification logic --------- Co-authored-by: Gao Sun * feat(core): implement verification code verification API (#6001) * feat(core,schemas): implement the verification code flow implement the verification code flow * chore(core): fix rebase issue fix rebase issue * refactor(console): add chrome extension guide (#6178) * feat(core,schemas): implement social verification experience API endpoints (#6150) feat(core,schemas): implement the social verification flow implement the social verificaiton flow * release: version packages (#5987) * fix(deps): update dependency p-limit to v6 (#6182) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> * refactor: correct phrases and translate some untranslate phrases for zh-cn (#6190) * refactor: correct zh-cn translations * refactor: translate some untranslate phrases for zh-cn * feat: organization logo * refactor(experience): cache user input identifier for a better sign-in experience (#6164) * refactor(core, experience): remove `no_cache` param * refactor(experience): add hidden identifier input for browser password manager (#6165) * refactor(core): refactor identifyUser method (#6154) refactor(core): refactor the user identification flow refactor the user identification flow * refactor(experience,phrases): update phrases for link identities page (#6104) * refactor: remove unused patches (#6179) * chore(deps): update dependency superstruct to v2 (#6173) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> * feat(core): actor token (#6171) * feat(console,schemas): add grant context to custom jwt (#6184) * feat(core): add subject token context to jwt customizer (#6185) * feat: support app-level branding * fix(deps): update dependency lru-cache to v11 (#6203) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> * refactor(core): refactor the sso interaction handlers (#6186) refactor(core): revert the sso utils input refactor revert the sso utils input refactor * feat(core): implement enterprise sso verification flow (#6198) implement the enterprise sso verification flow * refactor(console): reorg logo uploads * refactor(experience): add label for input field (#6200) * feat(core): add quota guard for subject tokens (#6205) * style(experience): update floating label position (#6211) * refactor(core): update cache key * refactor(console): rename file * refactor(console): update all logo uploaders (#6209) * refactor(experience): show dark favicon (#6210) * feat(core): implement TOTP verification routes (#6201) * feat(core): implmenent totp verification routes implement totp verification routes * fix(core): update comments update comments * feat(core,schemas): implement backup codes verification (#6207) implement the backup code verification flow * refactor: fix experience branding fallback * fix(experience): use forgot password identifier in related flow (#6221) * refactor(console): improve branding experience * feat(core): handle dpop and client certificate for token exchange (#6199) * refactor: fix third-party app experience branding (#6223) * refactor(core): refactor organizations in grants (#6208) * test: add resource test cases for token exchange (#6216) * feat(core): handle dpop and client certificate for token exchange * refactor(core): refactor organizations in grants * test: add resource test cases for token exchange * feat(core,schemas): introduce new PUT experience API (#6212) * feat(core,schemas): introduce new PUT experience API introduce new PUT experience API * fix(core): fix some comments fix some comments * refactor: experience ssr (#6229) * refactor: experience ssr * refactor: fix parameter issue * chore(deps): upgrade packages * chore(deps): upgrade zod * feat(experience): support loading state for buttons (#6232) * refactor: patch type issues * chore: add changesets (#6239) * chore(deps): update vitest monorepo to v2 (major) (#6202) * chore(deps): update vitest monorepo to v2 * refactor: remove unused lint ignorings --------- Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Gao Sun * feat(core,schemas): implement the sie settings guard (#6215) * feat(core,schemas): implement the sie settings guard implement the sie settings guard * fix(test): fix integration test fix integration test * test(core): add sie guard ut add sie guard ut * chore(core): add some comment add some comment * refactor(core): rename the sign-in-experience-settings class rename the sign-in-experience-settings class * feat: init elements * refactor(core): remove subject token api prefix (#6235) * feat(core): add get available sso connectors endpoint (#6224) feat(core): implement get sso connectors implement get sso connectors endpoint * feat(elements): init i18n * feat(core,schemas): implement the register flow (#6237) * feat(core,schemas): implement the register flow implement the register flow * refactor(core,schemas): relocate the profile type defs relocate the profile type defs * fix(core): fix the validation guard logic fix the validation guard logic * fix(core): fix social and sso identity not created bug fix social and sso identity not created bug * fix(core): fix social identities profile key fix social identities profile key * fix(core): fix sso query method fix sso query method * feat(core,schemas): add post custom ui assets api (#6118) * feat(core,schemas): add post custom ui assets api * test(core): add register integration tests (#6248) * test(core): add register integration tests add register integration tests * test: add enterprise sso integration tests add enterprise sso integration tests * feat(elements): add components * feat(core,schemas): implement the username password registration flow (#6249) * feat(core,schemas): implement the username password registration flow implement the username password registration flow * chore(core): update some comments update some comments * fix(test): fix integration tests fix integration tests * fix(test): fix lint fix lint * fix(experience): correct active state for input field (#6255) * refactor(console): use button loading in experience flow if possible (#6234) * refactor(experience): support and apply modal loading state (#6236) * refactor(experience): support and apply modal loading state * feat(experience): support cancel loading for modal * chore(elements): update readme * feat(core): add the new user provision (#6253) add the new user provision * feat(connector): enable custom headers for SMTP connector (#6256) * fix(console): fix Google connector `scope` field can not be unset bug (#6254) * style(experience): improve input filed style (#6260) * feat(core): set up proxy to host custom ui assets if available (#6214) * feat(core): set up proxy to host custom ui assets if available * refactor: use object param for koa spa proxy middleware * refactor: make queries param mandatory * style(experience): remove autofill style from input component (#6261) * fix(console): fix image upload in onboarding process (#6266) * fix(console): fix grant data card height (#6264) * fix(console): fix passwordless connector tester send failed bug (#6268) * feat(console): implement custom ui assets upload component (#6217) * ci: always set conclusion for alteration tests (#6276) * style(experience): add transition for notched border (#6265) * refactor(experience): avoid disabled button for continue button (#6271) * feat(core): add api quota guard for bring your ui feature (#6273) * fix(console): should not toast invitation sent message when creating tenant w/o invitee (#6270) fix(console): should not toast invitation sent message when creating tenant without invitee * feat(console): add impersonation price item (#6269) * fix(experience): shrink input field when autofilled by the browser (#6280) * feat(console): add impersonation tag to audit log (#6267) * feat(core,schemas): implement social/sso link and sync logic (#6257) * feat(core,schemas): implement social/sso link and sync logic implement social/sso link and sync logic * test(core): add intergration tests add integration tests * feat(core): add mfa verification guard (#6262) add mfa verification guard * chore: remove feature guard for token exchange (#6246) * chore: add changeset for impersonation (#6251) * chore(elements): move check to build * chore(deps): upgrade typescript * chore(elements): add locale changes * chore(deps): upgrade react * chore(elements): check git existence * feat(schemas): init app_secrets table * feat(core): multiple app secrets * refactor(core,schemas): refactor `CodeVerification` (#6277) * refactor(core,schemas): refactor the CodeVerification class split the CodeVerification class into EmailCodeVerification and PhoneCodeVerification * refactor(core,schemas): split CodeVerification type split CodeVerification type * fix(core): code review updates code review updates * feat: add content schema to HTTP 201 CREATED messages (#6244) feat: add content schema to 201 messages * feat(console,phrases): add bring your ui quota item to pricing table (#6274) * refactor(console,phrases,schemas): increase file upload size limit to 10mb (#6258) refactor(console,phrases,schemas): increase file upload size limit to 10 mb * feat(elements): init modal and input * refactor: fix phrases * feat(elements): init user provider * feat(elements): update name * feat(console,phrases): add bring your UI feature paywall (#6275) feat(console,phrases): add bring your ui feature paywall * chore: update README.md (#6297) * chore: update README.md * chore: add awesome list * style(experience): improve notched border animation (#6296) * fix(console): sidebar width should not be shrunk (#6299) * refactor(core): extract password-validator (#6282) * refactor(core): extract password-validator extract password validator * fix(core): update comments and rename method name update comment and rename method name * refactor(console): update file uploader component to 80px fixed height * fix(core): should not sync registered identifier from social (#6283) should not sync registered identifier from social * style(experience): use brand loading color for buttons (#6302) * chore(console): remove dev feature guard (#6303) * refactor(core): extract helpers and provision methods (#6285) extract helpers and provision methods * feat(console): support multiple app secrets * refactor(phrases): improve bring your ui field description * fix(console): add cloud guard to bring your ui form field * refactor(schemas): increase max upload file size limit to 20MB * fix(core): disable bring your ui feature for admin tenant (#6300) * fix(console): should be able to remove the zip on upload error (#6306) * refactor: generate application secret on creation * fix(console): fix loading and error handling for org details page (#6313) * refactor(console): keep button loading before redirecting to sign-in success page (#6305) * refactor: use vite for demo app * refactor(core): log app secret name * chore(phrases): sync keys and translate (#6315) * refactor(core): implement verification records map (#6289) * refactor(core): implement verificaiton records map implement verification records map * fix(core): fix invalid verification type error fix invalid verificaiton type error * fix(core): update the verification record map update the verification record map * fix(core): update some comments update some comments * refactor(core): polish promise dependency polish promise dependency * fix(core): fix the social/sso syncing profile logic fix the social/sso syncing profile logic * refactor(core): optimize the verification records map optimize the verification records map * fix(core): fix set method of VerificationRecord map fix set method of VerificationRecord map * refactor(experience): use button loading for social sign-in (#6316) * chore: add comment * chore: add comment * refactor(console): use vite * refactor(experience): use vite * refactor(console): use local mermaid import * fix(console): use correct public url (#6325) * refactor(console, experience): optimize bundling (#6326) * refactor(console, experience): optimize bundling * fix: use correct favicon paths * chore: use dynamic react dependency checking in bundling * refactor(core): rename some file names and methods (#6321) * refactor(core): rename some files name and methods rename some files name and methods, fix some comments * chore: update comments update comments * chore: update comments update comments * chore: polish the words polish the words * fix(console): check scope only when data is ready (#6329) * feat(core,schemas): implement profile fulfillment flow (#6293) * feat(core,schemas): implement profile fulfillment flow implement profile fulfillment flow * fix(test): fix integration tests fix integration tests * fix(core): fix rebase issue fix rebase issue * refactor(core): refactor the interaction set profile flow refactor the interaction set profile flow * test(core): add profile fulfillment integration tests (#6294) * test(core): add profile fufillment integration tests add profile fufillment integration tests * fix: fix integration tests fix integration tests * refactor(test): rebase and update the latest profile api rebase and update the latest profile api * fix(console): css loaded svg should be rendered properly (#6333) * fix(core): fix some webhook api body status 404 bug (#6311) * fix(core): fix some webhook api body status 404 bug fix some webhook api body status 404 bug * fix(core): improve the webhook trigger logic improve the webhook trigger logic * chore: add changeset add changeset * chore: update the changeset update the changeset * feat(core): implement the WebAuthn verification (#6308) feat(core): implement the webauthn verification implement the webauthn verification * feat(schemas): add custom data to application (#6309) * feat(core,schemas): add application custom data add application custom data * test(core): add update application with new custom data test add update application with new custom data test * refactor(console): increase custom ui assets upload timeout to 5 mins (#6319) refactor(console): increase custom ui assets upload timeout to 5mins * refactor: update logto/core cloud API usage * refactor: update code according to CR * refactor(console): update admin console using new pricing model (#6295) * refactor(console): update cloud API calls * refactor: update code according to CR * refactor: correct component usage * refactor(console): safely lazy load pages (#6332) * refactor(console): safely lazy load pages * chore(console): use react-safe-lazy * feat(core): implement the missing mfa bind and guard flow (#6320) * feat(core): implement the mfa binding flow implment the mfa binding flow * fix(test): fix integration tests fix integration tests * fix(core): fix the wrong status code fix the wrong status code * refactor(core): refactor bind backup codes refactor bind backup codes * refactor(core): extract isNewMfaVerification property (#6338) extract isNewMfaVerifrication property * refactor(core): refactor backup code generates flow (#6339) refactor(core): refactor backup code generate flow refactor backup code generate flow * fix(console): dragging anchor in the color picker on application branding page (#6340) * test(core): add the mfa binding integration tests (#6330) * refactor(core): refactor backup code generate flow refactor backup code generate flow * fix(core): fix api payload fix api payload * test(core): implement the mfa binding integration tests implement the mfa binding integration tests * test(core): rebase backup code refactor rebase backup code refactor * style(console): fix custom jwt guide card style (#6343) * refactor(console): block page navigation when uploading custom ui assets (#6342) * chore(console): update bring your ui documentation link (#6317) chore(console): add bring your ui documentation link * fix(elements): fix user context tag name (#6346) * chore: launch multiple app secrets * chore: launch multiple app secrets * refactor(core): use tsup for building * refactor: use tsup for building * refactor(console): improve ux * chore: fix failed tests * refactor(connector): use tsup for building * ci: add check job * feat(console): remove beta tag for protected app (#6341) * feat(console): add passport.js guide (#6344) * chore: update plausible urls (#6349) * refactor(console, experience): solve sass deprecations (#6356) * fix(console): fix the plan title for subscription plan selector (#6348) * refactor(core): refactor openapi docs for protected app (#6331) * refactor: update per review * feat: allow app secret edit (#6352) * fix(console): add dev guard on new pricing model subscription hooks (#6363) * feat(core): migrate register flow affiliate report logic (#6334) Migrate the new user affiliate flow from interaction API. - `postAffiliateLogs` is forked from `routes/interaction/actions/helpers.ts` * refactor(core): extract verified interaction guard middleware (#6336) * refactor(core): refactor backup code generate flow refactor backup code generate flow * fix(core): fix api payload fix api payload * fix(core): fix rebase issue fix rebase issue * refactor(core): extract verified interaction guard middleware extract verified interaction guard middleware * refactor(console): fix text overflow issue (#6366) * refactor(core): make the interaction event mandatory (#6337) * refactor(core): refactor backup code generate flow refactor backup code generate flow * fix(core): fix api payload fix api payload * fix(core): fix rebase issue fix rebase issue * refactor(core): make the interaction event mandatory make the interaction event mandatory * test: update integration tests update integration tests * fix(core): fix the middleware apply bug fix the koaExperienceInteraction middleware apply bug * feat(core): add webhooks middleware to experience api (#6357) * refactor(core): refactor backup code generate flow refactor backup code generate flow * fix(core): fix api payload fix api payload * fix(core): fix rebase issue fix rebase issue * feat(core): add hooks middleware to experience APIs add interaction hooks to experience APIs * refactor(core): refactor experience API context type refactor experience API context type * feat(connector): added postmark connector * chore: remove unused deps (#6372) * chore: remove unused deps * chore: fix version * refactor(core): improve swagger auth description (#6367) * feat(core,schemas): add auditLogs to experience API (#6361) * refactor(core): refactor backup code generate flow refactor backup code generate flow * fix(core): fix api payload fix api payload * fix(core): fix rebase issue fix rebase issue * feat(core,schemas): add auditLogs to experience API add auditLogs to experience API * refactor(core): allow cloudflare insights origin in csp (#6375) refactor(core): allow cloudflare csp * feat(core,schemas): add mandatory password guard on register (#6368) * refactor(core): refactor backup code generate flow refactor backup code generate flow * fix(core): fix api payload fix api payload * fix(core): fix rebase issue fix rebase issue * feat(core,schemas): add mandatory password guard on register add mandatory password guard on register * feat: add advanced search params to all supported endpoints (#6358) * feat: add search params to list users endpoint * feat: implement advanced search for all supported endpoints * chore(deps): update dependency nock to v14.0.0-beta.9 (#6243) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> * feat(cli): add cli command to setup custom ui local debugging proxy (#6365) * feat(cli): add proxy * refactor(cli): polish code per comments * refactor(cli): polish code * refactor(cli): support serving static files * chore: add changeset * refactor: polish code * refactor(cli): polish code * refactor(cli): make json parse safer * feat(core,console,phrases): add custom data editor to application details page (#6370) * feat(core,console,phrases): add custom data editor to application details page add custom data editor to application details page * chore: add changeset add changeset * fix(core): fix input params bug fix input params bug * fix(test): fix the integration tests fix the integration tests * fix(console): use the form controller element use the form controller element * fix(core,console): remove deepPartial statement remove deepPartial statement from the patch application API payload guard * fix(test): fix backchannel integration test fix backchannel integration test * fix(core): allow non-json body type when parsing (#6379) * refactor(core): make password optional in NewPasswordIdentity (#6377) refactor(core): make password optional in NewPasswordIdentity verification make password optioanl in NewPasswordIdentity verification * refactor(console): get and check `skuId` from checkout session (#6369) * refactor(console): get and check skuId from checkout session * chore: update @logto/cloud dependency * refactor: add tests for content-type in oidc apis (#6380) * refactor(console): delay module loading suspense component display by 500ms (#6345) * chore(console): remove redunant login hint usage for invitation (#6385) * fix(core): error data bug fixing (#6382) fix(core): error code bug fixing error code bug fixing * refactor(console): update billing info showed in subscription details page (#6384) * fix(console): add in-line error message (#6386) * fix(console): add in-line error message add in-line error message * refactor(console): remove old validation logic remove old validation logic * fix(console): create tenant button should stretch to full width (#6381) * fix(console): manual update subscription data when add/delete resources (#6360) * fix(console): add post response hook to update subscription info for useApi hook * refactor: wrap sync subscription data method * chore(phrases): update content (#6392) chore: update content * fix(console): fix the subscription plan display in tenant dropdown (#6393) * refactor(core): should not guard sso authentication flow (#6394) should not guard mfa and profile fulfillment for the sso authentication flow * fix(core): should not throw when not adding any new roles to a user (#6387) * fix(console): should not call cloud API when tenant ID is not valid (#6399) * refactor(console): improve guide logo and contact us logo display (#6391) * feat(core,schemas): add support for argon2d and argon2id (#6404) * feat(console): support next auth v5 (#6397) * feat: add add-on feature notice/tag * chore: define add on unit price temporarily * refactor: produce br outputs (#6376) * refactor: produce br outputs * refactor: fix favicon url * refactor: add `report:subscription:updates` Cloud scope (#6403) * Revert "refactor: add `report:subscription:updates` Cloud scope" (#6412) Revert "refactor: add `report:subscription:updates` Cloud scope (#6403)" This reverts commit e1922e9afbb8f9a0ce4b9fea4b154e9266bcedcf. * fix(console): fix unexpected 401 error toast (#6416) * feat(core): add Sentinel guard (#6374) feat(core): add sentinel protection add sentinel protection * feat(core): support google one tap (#6395) * feat(core): support google one tap support google one tap verification * fix(core): fix google one tap verification error fix google one tap verification error * fix(test): optimize social verification test optimize social verificaiton tests * fix(test): update social verification ut update social verification util unit test * refactor(core,schemas): refactor the register flow (#6401) * refactor(core,schemas): refactor the registration flow refactor the registraction flow * fix(core): remove unused method remove unused method * fix(test): remove legacy test remove legacy test * fix(core): fix webauthn verificaiton api fix webauthn verification api * feat(console): add new usage display for pro subscription plan (#6413) * release: version packages (#6197) * Fixing missing variables. --------- Co-authored-by: Gao Sun Co-authored-by: simeng-li Co-authored-by: silverhand-bot <107667382+silverhand-bot@users.noreply.github.com> Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Misaka_L Co-authored-by: Xiao Yijun Co-authored-by: wangsijie Co-authored-by: Charles Zhao Co-authored-by: Darcy Ye Co-authored-by: Mostafa Moradian Co-authored-by: Sten Roger Sandvik --- .dockerignore | 1 - ...eration-compatibility-integration-test.yml | 8 + .github/workflows/main.yml | 21 +- .npmrc | 6 - .scripts/compare-database.js | 4 +- .scripts/package.sh | 2 +- .vscode/settings.json | 3 +- .vscode/tsx.code-snippets | 2 +- AWESOME.md | 11 + Dockerfile | 3 +- README.md | 7 +- commitlint.config.ts | 2 +- .../src/routes/static/mock-login.html | 7 + package.json | 8 +- packages/app-insights/package.json | 6 +- packages/cli/CHANGELOG.md | 48 + packages/cli/package.json | 22 +- packages/cli/src/commands/proxy/index.ts | 106 + packages/cli/src/commands/proxy/types.ts | 18 + packages/cli/src/commands/proxy/utils.ts | 157 + packages/cli/src/index.ts | 2 + packages/connectors/.gitignore | 3 +- .../connector-alipay-native/CHANGELOG.md | 10 + .../connector-alipay-native/package.json | 25 +- .../connector-alipay-web/CHANGELOG.md | 10 + .../connector-alipay-web/package.json | 25 +- .../connector-aliyun-dm/CHANGELOG.md | 10 + .../connector-aliyun-dm/package.json | 25 +- .../src/single-send-mail.test.ts | 7 +- .../connector-aliyun-dm/src/utils.test.ts | 14 +- .../connector-aliyun-sms/CHANGELOG.md | 10 + .../connector-aliyun-sms/package.json | 25 +- .../src/single-send-text.test.ts | 7 +- .../connector-aliyun-sms/src/utils.test.ts | 13 +- .../connectors/connector-apple/CHANGELOG.md | 10 + .../connectors/connector-apple/package.json | 27 +- .../connectors/connector-aws-ses/CHANGELOG.md | 10 + .../connectors/connector-aws-ses/package.json | 25 +- .../connectors/connector-azuread/CHANGELOG.md | 10 + .../connectors/connector-azuread/README.md | 23 - .../connectors/connector-azuread/package.json | 25 +- .../connector-dingtalk-web/CHANGELOG.md | 10 + .../connector-dingtalk-web/package.json | 25 +- .../connectors/connector-discord/CHANGELOG.md | 10 + .../connectors/connector-discord/package.json | 25 +- .../connector-facebook/CHANGELOG.md | 10 + .../connector-facebook/package.json | 25 +- .../connector-feishu-web/CHANGELOG.md | 10 + .../connector-feishu-web/package.json | 25 +- .../connectors/connector-github/CHANGELOG.md | 10 + .../connectors/connector-github/package.json | 27 +- .../connectors/connector-google/CHANGELOG.md | 10 + .../connectors/connector-google/package.json | 27 +- .../connector-huggingface/CHANGELOG.md | 15 + .../connector-huggingface/package.json | 27 +- .../connectors/connector-kakao/CHANGELOG.md | 10 + .../connectors/connector-kakao/package.json | 25 +- .../connector-logto-email/CHANGELOG.md | 10 + .../connector-logto-email/package.json | 27 +- .../connector-logto-email/src/constant.ts | 2 +- .../connector-logto-sms/CHANGELOG.md | 10 + .../connector-logto-sms/package.json | 25 +- .../connector-logto-social-demo/CHANGELOG.md | 10 + .../connector-logto-social-demo/package.json | 25 +- .../connectors/connector-mailgun/CHANGELOG.md | 10 + .../connectors/connector-mailgun/package.json | 25 +- .../CHANGELOG.md | 10 + .../package.json | 25 +- .../connector-mock-email/CHANGELOG.md | 10 + .../connector-mock-email/package.json | 25 +- .../connector-mock-sms/CHANGELOG.md | 10 + .../connector-mock-sms/package.json | 25 +- .../connector-mock-social/CHANGELOG.md | 10 + .../connector-mock-social/package.json | 25 +- .../connector-mock-social/src/index.ts | 4 +- .../connectors/connector-mygovid/package.json | 6 +- .../connectors/connector-naver/CHANGELOG.md | 10 + .../connectors/connector-naver/package.json | 25 +- .../connectors/connector-oauth2/CHANGELOG.md | 10 + .../connectors/connector-oauth2/package.json | 32 +- .../connector-ogcio-entraid/package.json | 6 +- .../connectors/connector-oidc/CHANGELOG.md | 15 + .../connectors/connector-oidc/package.json | 31 +- .../connector-postmark/CHANGELOG.md | 7 + .../connectors/connector-postmark/README.md | 61 + .../connectors/connector-postmark/logo.svg | 17 + .../connector-postmark/package.json | 68 + .../connector-postmark/src/constant.ts | 57 + .../connector-postmark/src/index.test.ts | 42 + .../connector-postmark/src/index.ts | 65 + .../connectors/connector-postmark/src/mock.ts | 26 + .../connector-postmark/src/types.ts | 32 + .../connectors/connector-saml/CHANGELOG.md | 10 + .../connectors/connector-saml/package.json | 25 +- .../connector-sendgrid-email/CHANGELOG.md | 10 + .../connector-sendgrid-email/package.json | 25 +- .../connectors/connector-smsaero/CHANGELOG.md | 10 + .../connectors/connector-smsaero/package.json | 25 +- .../connectors/connector-smtp/CHANGELOG.md | 11 + .../connectors/connector-smtp/package.json | 25 +- .../connectors/connector-smtp/src/constant.ts | 9 + .../connector-smtp/src/index.test.ts | 22 + .../connectors/connector-smtp/src/index.ts | 11 +- .../connectors/connector-smtp/src/mock.ts | 1 + .../connectors/connector-smtp/src/types.ts | 1 + .../connector-tencent-sms/CHANGELOG.md | 10 + .../connector-tencent-sms/package.json | 25 +- .../connector-twilio-sms/CHANGELOG.md | 10 + .../connector-twilio-sms/package.json | 25 +- .../connector-wechat-native/CHANGELOG.md | 10 + .../connector-wechat-native/package.json | 25 +- .../connector-wechat-web/CHANGELOG.md | 10 + .../connector-wechat-web/package.json | 25 +- .../connectors/connector-wecom/CHANGELOG.md | 10 + .../connectors/connector-wecom/package.json | 25 +- packages/connectors/templates/package.json | 6 +- .../templates/preset/tsconfig.base.json | 9 - .../templates/preset/tsconfig.build.json | 5 - .../connectors/templates/preset/tsconfig.json | 15 +- .../templates/preset/tsconfig.test.json | 7 - .../templates/preset/tsup.config.ts | 5 + packages/connectors/templates/sync-preset.js | 2 +- packages/console/.eslintrc.cjs | 9 + packages/console/CHANGELOG.md | 62 + packages/console/{src => }/index.html | 6 +- packages/console/package.json | 70 +- ...generate-jwt-customizer-type-definition.ts | 9 + packages/console/src/App.tsx | 2 + .../console/src/assets/docs/guides/README.md | 3 + .../docs/guides/api-express/logo-dark.svg | 10 + .../assets/docs/guides/api-express/logo.svg | 11 +- .../assets/docs/guides/api-python/logo.svg | 15 +- .../docs/guides/api-spring-boot/logo.svg | 10 +- .../assets/docs/guides/generate-metadata.js | 28 +- .../console/src/assets/docs/guides/index.tsx | 116 +- .../docs/guides/m2m-general/logo-dark.svg | 35 + .../assets/docs/guides/m2m-general/logo.svg | 52 +- .../docs/guides/native-android/logo.svg | 13 +- .../docs/guides/native-capacitor/logo.svg | 21 +- .../docs/guides/native-expo/logo-dark.svg | 3 + .../assets/docs/guides/native-expo/logo.svg | 4 +- .../docs/guides/native-flutter/logo.svg | 28 +- .../docs/guides/native-ios-swift/logo.svg | 13 +- .../assets/docs/guides/spa-angular/logo.svg | 28 +- .../docs/guides/spa-chrome-extension/logo.svg | 23 +- .../src/assets/docs/guides/spa-react/logo.svg | 11 +- .../assets/docs/guides/spa-vanilla/logo.svg | 14 +- .../src/assets/docs/guides/spa-vue/logo.svg | 6 +- .../assets/docs/guides/spa-webflow/logo.svg | 11 +- .../docs/guides/third-party-oidc/logo.svg | 21 +- .../console/src/assets/docs/guides/types.ts | 3 + .../web-dotnet-core-blazor-server/logo.svg | 8 +- .../web-dotnet-core-blazor-wasm/logo.svg | 8 +- .../fragments/_add-authentication.mdx | 2 +- .../docs/guides/web-dotnet-core-mvc/logo.svg | 14 +- .../docs/guides/web-dotnet-core/logo.svg | 14 +- .../assets/docs/guides/web-express/README.mdx | 2 +- .../docs/guides/web-express/logo-dark.svg | 10 + .../assets/docs/guides/web-express/logo.svg | 11 +- .../src/assets/docs/guides/web-go/README.mdx | 2 +- .../src/assets/docs/guides/web-go/logo.svg | 10 +- .../components/AlwaysIssueRefreshToken.tsx | 1 + .../components/ClientBasics/index.tsx | 2 +- .../docs/guides/web-gpt-plugin/logo.svg | 12 +- .../guides/web-java-spring-boot/README.mdx | 2 +- .../docs/guides/web-java-spring-boot/index.ts | 3 +- .../docs/guides/web-java-spring-boot/logo.svg | 11 +- .../guides/web-next-app-router/README.mdx | 2 +- .../guides/web-next-app-router/logo-dark.svg | 10 + .../docs/guides/web-next-app-router/logo.svg | 11 +- .../docs/guides/web-next-auth/README.mdx | 43 +- .../assets/docs/guides/web-next-auth/index.ts | 4 +- .../assets/docs/guides/web-next-auth/logo.svg | 40 +- .../assets/docs/guides/web-next/README.mdx | 2 +- .../assets/docs/guides/web-next/logo-dark.svg | 10 + .../src/assets/docs/guides/web-next/logo.svg | 11 +- .../assets/docs/guides/web-nuxt/README.mdx | 4 +- .../src/assets/docs/guides/web-nuxt/logo.svg | 4 +- .../docs/guides/web-outline/logo-dark.svg | 10 + .../assets/docs/guides/web-outline/logo.svg | 13 +- .../docs/guides/web-passport/README.mdx | 163 + .../docs/guides/web-passport/config.json | 3 + .../assets/docs/guides/web-passport/index.ts | 11 + .../docs/guides/web-passport/logo-dark.svg | 6 + .../assets/docs/guides/web-passport/logo.svg | 6 + .../src/assets/docs/guides/web-php/README.mdx | 2 +- .../src/assets/docs/guides/web-php/logo.svg | 15 +- .../assets/docs/guides/web-python/README.mdx | 2 +- .../assets/docs/guides/web-python/logo.svg | 15 +- .../assets/docs/guides/web-ruby/README.mdx | 4 +- .../src/assets/docs/guides/web-ruby/logo.svg | 199 + .../docs/guides/web-sveltekit/README.mdx | 2 +- .../assets/docs/guides/web-sveltekit/logo.svg | 5 +- .../assets/docs/guides/web-wordpress/logo.svg | 8 +- .../src/assets/icons/calendar-dark.svg | 9 + .../console/src/assets/icons/calendar.svg | 2 +- packages/console/src/assets/icons/email.svg | 2 +- packages/console/src/assets/icons/github.svg | 2 +- .../src/assets/images/blur-preview.svg | 102 + packages/console/src/cloud/AppRoutes.tsx | 2 +- .../cloud/pages/Main/InvitationList/index.tsx | 4 +- .../TenantLandingPageContent/index.tsx | 8 +- .../pages/Main/TenantLandingPage/index.tsx | 2 +- .../cloud/pages/SocialDemoCallback/index.tsx | 6 +- packages/console/src/cloud/types/router.ts | 20 + .../src/components/ActionBar/index.tsx | 2 +- .../src/components/ActionsButton/index.tsx | 8 +- .../AddOnNoticeFooter/index.module.scss | 17 + .../components/AddOnNoticeFooter/index.tsx | 30 + .../console/src/components/AppError/index.tsx | 10 +- .../src/components/AppLoading/index.tsx | 4 +- .../CreateForm/Footer/index.module.scss | 3 + .../CreateForm/Footer/index.tsx | 45 +- .../ApplicationCreation/CreateForm/index.tsx | 17 +- .../src/components/ApplicationName/index.tsx | 2 +- .../components/EventName/index.module.scss | 1 + .../components/EventName/index.tsx | 8 +- .../src/components/AuditLogTable/index.tsx | 2 +- .../src/components/BasicWebhookForm/index.tsx | 2 +- .../console/src/components/BillInfo/index.tsx | 4 +- .../src/components/Breakable/index.tsx | 2 +- .../components/ChargeNotification/index.tsx | 5 +- .../ConnectorForm/BasicForm/index.tsx | 78 +- .../ConfigForm/ConfigFormFields/index.tsx | 2 +- .../ConnectorForm/ConfigForm/index.tsx | 2 +- .../ConnectorForm/GoogleOneTapCard/index.tsx | 2 +- .../src/components/ConnectorLogo/index.tsx | 2 +- .../src/components/ConnectorTester/index.tsx | 2 +- .../src/components/Conversion/index.tsx | 3 +- .../ConnectorRadio/index.tsx | 2 +- .../ConnectorRadioGroup/index.tsx | 2 +- .../CreateConnectorForm/Footer/index.tsx | 68 +- .../PlatformSelector/index.tsx | 2 +- .../Skeleton/index.module.scss | 6 +- .../CreateConnectorForm/Skeleton/index.tsx | 6 +- .../components/CreateConnectorForm/index.tsx | 4 +- .../EnvTagOptionContent/index.tsx | 2 +- .../FeaturedPlanContent/index.tsx | 6 +- .../PlanCardItem/index.tsx | 4 +- .../SkuCardItem/FeaturedSkuContent/index.tsx | 35 + .../use-featured-sku-content.ts | 77 + .../SkuCardItem/index.tsx | 100 + .../SelectTenantPlanModal/index.tsx | 86 +- .../components/CreateTenantModal/index.tsx | 8 +- .../console/src/components/DateTime/index.tsx | 34 +- .../src/components/DetailsForm/index.tsx | 2 +- .../DetailsPage/DetailsPageHeader/index.tsx | 4 +- .../DetailsPage/Skeleton/index.module.scss | 8 +- .../components/DetailsPage/Skeleton/index.tsx | 2 +- .../src/components/DetailsPage/index.tsx | 4 +- .../console/src/components/Drawer/index.tsx | 4 +- .../src/components/EditScopeModal/index.tsx | 2 +- .../components/EmptyDataPlaceholder/index.tsx | 6 +- .../components/EntityItem/index.tsx | 2 +- .../components/SourceEntitiesBox/index.tsx | 6 +- .../components/SourceEntityItem/index.tsx | 2 +- .../components/TargetEntitiesBox/index.tsx | 4 +- .../components/TargetEntityItem/index.tsx | 4 +- .../src/components/EntitiesTransfer/index.tsx | 4 +- .../src/components/FeatureTag/AddOnTag.tsx | 19 + .../src/components/FeatureTag/BetaTag.tsx | 2 +- .../src/components/FeatureTag/index.tsx | 17 +- .../console/src/components/FileIcon/index.tsx | 20 + .../FormCard/FormCardLayout/index.module.scss | 2 +- .../FormCard/FormCardLayout/index.tsx | 2 +- .../FormCard/Skeleton/index.module.scss | 14 +- .../components/FormCard/Skeleton/index.tsx | 9 +- .../console/src/components/FormCard/index.tsx | 2 +- .../Guide/GuideCard/index.module.scss | 9 +- .../src/components/Guide/GuideCard/index.tsx | 11 +- .../components/Guide/GuideCardGroup/index.tsx | 2 +- .../components/Guide/ModalFooter/index.tsx | 2 +- .../Guide/ModalHeader/RequestForm.tsx | 2 +- .../components/Guide/ModalHeader/index.tsx | 4 +- .../Guide/StepsSkeleton/index.module.scss | 6 +- .../components/Guide/StepsSkeleton/index.tsx | 2 +- .../console/src/components/Guide/index.tsx | 5 +- .../components/ImageInputs/LogoAndFavicon.tsx | 62 + .../ImageInputs}/index.module.scss | 17 +- .../src/components/ImageInputs/index.tsx | 169 + .../console/src/components/Index/index.tsx | 4 +- .../src/components/InlineUpsell/index.tsx | 2 +- .../ItemPreview/ApplicationPreview.tsx | 2 +- .../src/components/ItemPreview/index.tsx | 2 +- .../console/src/components/ListPage/index.tsx | 4 +- .../components/LivePreviewButton/index.tsx | 4 +- .../index.tsx | 2 +- .../console/src/components/Markdown/index.tsx | 4 +- .../src/components/MauExceededModal/index.tsx | 20 +- .../src/components/MfaFactorTitle/index.tsx | 10 +- .../src/components/MultiOptionInput/index.tsx | 4 +- .../components/MultiTextInputField/index.tsx | 2 +- .../src/components/OpenExternalLink/index.tsx | 2 +- .../src/components/OrganizationList/index.tsx | 6 +- .../OrganizationRolesSelect/index.tsx | 4 +- .../components/PaymentOverdueModal/index.tsx | 4 +- .../src/components/PermissionsTable/index.tsx | 8 +- .../src/components/PlanDescription/index.tsx | 14 +- .../console/src/components/PlanName/index.tsx | 22 +- .../ProPlanUsageCard/index.module.scss | 35 + .../PlanUsage/ProPlanUsageCard/index.tsx | 78 + .../components/PlanUsage/index.module.scss | 17 + .../src/components/PlanUsage/index.tsx | 64 +- .../console/src/components/PlanUsage/utils.ts | 77 + .../src/components/ProgressBar/index.tsx | 2 +- .../src/components/QuotaGuardFooter/index.tsx | 2 +- .../console/src/components/Region/index.tsx | 2 +- .../src/components/RequestDataError/index.tsx | 6 +- .../components/RoleAssignmentModal/index.tsx | 4 +- .../console/src/components/RoleIcon/index.tsx | 4 +- .../components/ResourceItem/index.tsx | 6 +- .../components/SourceScopeItem/index.tsx | 2 +- .../components/SourceScopesBox/index.tsx | 6 +- .../components/TargetScopeItem/index.tsx | 4 +- .../components/TargetScopesBox/index.tsx | 4 +- .../components/RoleScopesTransfer/index.tsx | 4 +- .../SourceRolesBox/SourceRoleItem/index.tsx | 2 +- .../RolesTransfer/SourceRolesBox/index.tsx | 6 +- .../TargetRolesBox/TargetRoleItem/index.tsx | 4 +- .../RolesTransfer/TargetRolesBox/index.tsx | 4 +- .../components/RoleInformation/index.tsx | 4 +- .../src/components/RolesTransfer/index.tsx | 6 +- .../components/ToggleUiThemeButton/index.tsx | 6 +- .../SignInExperiencePreview/index.module.scss | 24 + .../SignInExperiencePreview/index.tsx | 78 +- .../SubmitFormChangesActionBar/index.tsx | 5 +- .../src/components/TemplateTable/index.tsx | 6 +- .../src/components/TenantEnvTag/index.tsx | 2 +- .../src/components/ThemedIcon/index.tsx | 2 +- .../components/Topbar/ContactModal/hook.tsx | 17 +- .../components/Topbar/ContactModal/index.tsx | 4 +- .../TenantDropdownItem/TenantStatusTag.tsx | 29 +- .../TenantDropdownItem/index.tsx | 22 +- .../TenantInvitationDropdownItem/index.tsx | 2 +- .../Topbar/TenantSelector/index.module.scss | 7 +- .../Topbar/TenantSelector/index.tsx | 6 +- .../Topbar/UserInfo/SubMenu/index.tsx | 6 +- .../UserInfoSkeleton/index.module.scss | 4 +- .../UserInfo/UserInfoSkeleton/index.tsx | 2 +- .../src/components/Topbar/UserInfo/index.tsx | 12 +- .../src/components/Topbar/index.module.scss | 6 +- .../console/src/components/Topbar/index.tsx | 12 +- .../UnsavedChangesAlertModal/index.tsx | 2 +- .../UserAccountInformation/index.tsx | 6 +- .../src/components/UserAvatar/index.tsx | 4 +- .../src/components/UserInfoCard/index.tsx | 2 +- .../console/src/components/UserName/index.tsx | 2 +- .../VerificationCodeInput/index.tsx | 2 +- packages/console/src/consts/applications.ts | 24 +- packages/console/src/consts/connectors.ts | 4 +- packages/console/src/consts/env.ts | 11 +- packages/console/src/consts/external-links.ts | 4 + packages/console/src/consts/logs.ts | 1 + packages/console/src/consts/plan-quotas.ts | 29 + .../console/src/consts/quota-item-phrases.ts | 123 + packages/console/src/consts/subscriptions.ts | 10 + packages/console/src/consts/tenants.ts | 92 +- packages/console/src/consts/user-assets.ts | 17 - .../CreateProductionTenantBanner/index.tsx | 2 +- .../TenantEnvMigrationModal/index.tsx | 10 +- .../AppContent/TenantSuspendedPage/index.tsx | 6 +- .../src/containers/AppContent/index.tsx | 27 +- .../Sidebar/components/Item/index.tsx | 2 +- .../Sidebar/components/Section/index.tsx | 2 +- .../ConsoleContent/Sidebar/hook.tsx | 34 +- .../ConsoleContent/Sidebar/index.module.scss | 7 + .../ConsoleContent/Sidebar/index.tsx | 6 +- .../src/containers/ConsoleContent/hooks.ts | 10 +- .../ConsoleContent/index.module.scss | 11 +- .../src/containers/ConsoleContent/index.tsx | 36 +- .../src/containers/ConsoleRoutes/index.tsx | 65 +- .../src/containers/ConsoleRoutes/internal.ts | 14 + .../src/contexts/AppThemeProvider/index.tsx | 8 +- .../SubscriptionDataProvider/index.tsx | 22 +- .../SubscriptionDataProvider/types.ts | 24 +- .../use-new-subscription-data.ts | 64 + .../src/ds-components/ActionMenu/index.tsx | 2 +- .../src/ds-components/Button/index.tsx | 2 +- .../console/src/ds-components/Card/index.tsx | 2 +- .../src/ds-components/CardTitle/index.tsx | 2 +- .../CategorizedCheckboxGroup/index.tsx | 2 +- .../Checkbox/Checkbox/index.module.scss | 1 + .../ds-components/Checkbox/Checkbox/index.tsx | 2 +- .../Checkbox/CheckboxGroup/index.tsx | 2 +- .../src/ds-components/CodeEditor/index.tsx | 2 +- .../ColorPicker/index.module.scss | 4 + .../src/ds-components/ColorPicker/index.tsx | 23 +- .../src/ds-components/ConfirmModal/index.tsx | 4 +- .../CopyToClipboard/index.module.scss | 22 +- .../ds-components/CopyToClipboard/index.tsx | 18 +- .../DataTransferBox/SourceDataItem/index.tsx | 2 +- .../DataTransferBox/SourceGroupItem/index.tsx | 6 +- .../DataTransferBox/SourcePanel/index.tsx | 6 +- .../DataTransferBox/TargetDataItem/index.tsx | 4 +- .../DataTransferBox/TargetPanel/index.tsx | 4 +- .../ds-components/DataTransferBox/index.tsx | 4 +- .../src/ds-components/Divider/index.tsx | 2 +- .../DragDrop/DragDropProvider.tsx | 2 +- .../ds-components/Dropdown/DropdownItem.tsx | 2 +- .../src/ds-components/Dropdown/index.tsx | 2 +- .../FormField/Skeleton.module.scss | 11 + .../src/ds-components/FormField/Skeleton.tsx | 18 + .../ds-components/FormField/index.module.scss | 4 + .../src/ds-components/FormField/index.tsx | 8 +- .../src/ds-components/IconButton/index.tsx | 2 +- .../ImageWithErrorFallback/index.tsx | 4 +- .../InlineNotification/index.tsx | 10 +- .../KeyValueInputField/index.tsx | 6 +- .../src/ds-components/ModalHeader/index.tsx | 4 +- .../src/ds-components/ModalLayout/index.tsx | 6 +- .../ds-components/MultiTextInput/index.tsx | 6 +- .../src/ds-components/Pagination/index.tsx | 2 +- .../src/ds-components/RadioGroup/Radio.tsx | 2 +- .../src/ds-components/RadioGroup/index.tsx | 2 +- .../src/ds-components/Search/index.tsx | 4 +- .../src/ds-components/Select/MultiSelect.tsx | 4 +- .../src/ds-components/Select/index.tsx | 10 +- .../src/ds-components/Spacer/index.tsx | 2 +- .../src/ds-components/Spinner/index.tsx | 2 +- .../src/ds-components/Switch/index.tsx | 2 +- .../src/ds-components/TabNav/TabNavItem.tsx | 2 +- .../src/ds-components/TabNav/index.tsx | 2 +- .../src/ds-components/TabWrapper/index.tsx | 2 +- .../Table/Skeleton/index.module.scss | 8 +- .../ds-components/Table/Skeleton/index.tsx | 2 +- .../ds-components/Table/TableEmptyWrapper.tsx | 2 +- .../src/ds-components/Table/TableError.tsx | 6 +- .../ds-components/Table/TablePlaceholder.tsx | 2 +- .../console/src/ds-components/Table/index.tsx | 2 +- .../console/src/ds-components/Tag/index.tsx | 6 +- .../ds-components/TextInput/NumericInput.tsx | 6 +- .../ds-components/TextInput/index.module.scss | 2 +- .../src/ds-components/TextInput/index.tsx | 6 +- .../src/ds-components/TextLink/index.tsx | 2 +- .../src/ds-components/Textarea/index.tsx | 2 +- .../src/ds-components/Tip/TipBubble/index.tsx | 2 +- .../src/ds-components/Tip/TipBubble/utils.ts | 4 +- .../src/ds-components/Tip/ToggleTip/index.tsx | 4 +- .../src/ds-components/Tip/Tooltip/index.tsx | 2 +- .../console/src/ds-components/Toast/index.tsx | 6 +- .../Uploader/FileUploader/index.module.scss | 24 +- .../Uploader/FileUploader/index.tsx | 54 +- .../Uploader/ImageUploader/index.tsx | 8 +- .../Uploader/ImageUploaderField/index.tsx | 6 +- .../src/hooks/use-api-resources-usage.ts | 55 +- packages/console/src/hooks/use-api.ts | 32 +- .../src/hooks/use-applications-usage.ts | 118 +- .../use-connector-form-config-parser.tsx | 8 +- .../src/hooks/use-console-routes/index.tsx | 8 +- .../routes/api-resources.tsx | 14 +- .../routes/applications.tsx | 8 +- .../use-console-routes/routes/audit-logs.tsx | 5 +- .../use-console-routes/routes/connectors.tsx | 6 +- .../routes/customize-jwt.tsx | 5 +- .../routes/enterprise-sso.tsx | 6 +- .../hooks/use-console-routes/routes/mfa.tsx | 3 +- .../routes/organization-template.tsx | 18 +- .../routes/organizations.tsx | 14 +- .../use-console-routes/routes/profile.tsx | 15 +- .../hooks/use-console-routes/routes/roles.tsx | 14 +- .../routes/sign-in-experience.tsx | 4 +- .../routes/tenant-settings.tsx | 24 +- .../hooks/use-console-routes/routes/users.tsx | 16 +- .../use-console-routes/routes/webhooks.tsx | 12 +- packages/console/src/hooks/use-logto-skus.ts | 52 + .../src/hooks/use-new-subscription-quota.ts | 19 + .../use-new-subscription-scopes-usage.ts | 39 + .../src/hooks/use-new-subscription-usage.ts | 19 + packages/console/src/hooks/use-subscribe.ts | 58 +- .../src/hooks/use-subscription-plans.ts | 1 + .../src/hooks/use-subscription-usage.ts | 1 + .../src/hooks/use-user-assets-service.ts | 13 + .../console/src/hooks/use-user-preferences.ts | 1 + .../src/icons/ConnectorPlatformIcon.tsx | 6 +- packages/console/src/include.d/react-app.d.ts | 65 - .../src/include.d/react-router-dom.d.ts | 1 - packages/console/src/include.d/vite-env.d.ts | 6 + .../ApplicationCredentials/index.tsx | 10 +- .../mdx-components/DetailsSummary/index.tsx | 4 +- .../src/mdx-components/Mermaid/index.tsx | 29 +- .../mdx-components/OidcCallbackUri/index.tsx | 2 +- .../src/mdx-components/Sample/index.tsx | 2 +- .../SsoSamlSpMetadata/index.tsx | 2 +- .../console/src/mdx-components/Step/index.tsx | 2 +- .../src/mdx-components/Steps/index.tsx | 2 +- .../console/src/mdx-components/Tabs/index.tsx | 2 +- .../mdx-components/UriInputField/index.tsx | 5 +- .../MultiCardSelector/CardItem.tsx | 2 +- .../CardSelector/MultiCardSelector/index.tsx | 2 +- .../components/DemoConnectorNotice/index.tsx | 2 +- .../onboarding/components/Topbar/index.tsx | 4 +- packages/console/src/onboarding/index.tsx | 2 +- .../onboarding/pages/CreateTenant/index.tsx | 34 +- .../InspireMe/index.module.scss | 2 +- .../SignInExperience/InspireMe/index.tsx | 6 +- .../Preview/PlatformTabs/PlatformTab.tsx | 2 +- .../Preview/PlatformTabs/index.tsx | 6 +- .../pages/SignInExperience/Preview/index.tsx | 2 +- .../Skeleton/index.module.scss | 4 +- .../pages/SignInExperience/Skeleton/index.tsx | 6 +- .../pages/SignInExperience/index.tsx | 13 +- .../pages/SignInExperience/options.tsx | 18 +- .../src/onboarding/pages/Welcome/index.tsx | 6 +- .../src/onboarding/pages/Welcome/options.tsx | 4 +- .../AcceptInvitation/SwitchAccount/index.tsx | 4 +- .../src/pages/AcceptInvitation/index.tsx | 5 +- .../CreatePermissionModal/index.tsx | 36 +- .../components/GuideDrawer/index.tsx | 6 +- .../components/GuideModal/index.tsx | 4 +- .../src/pages/ApiResourceDetails/index.tsx | 14 +- .../components/CreateForm/Footer.tsx | 40 +- .../components/CreateForm/index.module.scss | 3 + .../components/CreateForm/index.tsx | 14 +- .../components/GuideLibrary/index.tsx | 2 +- .../components/GuideLibraryModal/index.tsx | 4 +- .../console/src/pages/ApiResources/index.tsx | 10 +- .../Branding/LogoUploader.module.scss | 34 - .../Branding/NonThirdPartyBrandingForm.tsx | 94 + .../Branding/index.module.scss | 13 + .../Branding/index.tsx | 155 +- .../Branding/utils.ts | 42 +- .../CreateSecretModal.tsx | 150 + .../EditSecretModal.tsx | 86 + .../EndpointsAndCredentials/index.module.scss | 35 + .../EndpointsAndCredentials/index.tsx | 275 + .../use-secret-table-columns.tsx | 108 + .../GuideDrawer/index.tsx | 11 +- .../MachineLogs/index.tsx | 2 +- .../index.tsx | 6 +- .../index.tsx | 2 +- .../Permissions/PermissionsCard/index.tsx | 2 +- .../PermissionsCard/use-scopes-table.tsx | 4 +- .../Permissions/index.tsx | 2 +- .../components/SessionForm.tsx | 2 +- .../ProtectedAppSettings/index.module.scss | 2 +- .../ProtectedAppSettings/index.tsx | 6 +- .../ApplicationDetailsContent/Settings.tsx | 29 +- .../index.module.scss | 15 - .../ApplicationDetailsContent/index.tsx | 78 +- .../ApplicationDetailsContent/utils.ts | 13 +- .../ApplicationDetails/GuideModal/index.tsx | 18 +- .../components/AppGuide/index.tsx | 31 +- .../src/pages/ApplicationDetails/index.tsx | 30 +- .../components/GuideLibrary/index.tsx | 4 +- .../components/GuideLibraryModal/index.tsx | 4 +- .../components/ProtectedAppCard/index.tsx | 8 +- .../components/ProtectedAppForm/index.tsx | 22 +- .../components/ProtectedAppModal/index.tsx | 2 +- .../components/TypeDescription/index.tsx | 2 +- .../console/src/pages/Applications/index.tsx | 6 +- .../components/EventIcon/index.tsx | 6 +- .../pages/AuditLogDetails/index.module.scss | 3 + .../src/pages/AuditLogDetails/index.tsx | 10 +- .../console/src/pages/AuditLogs/index.tsx | 2 +- .../pages/CheckoutSuccessCallback/index.tsx | 48 +- .../EmailServiceConnectorForm/index.tsx | 6 +- .../ConnectorContent/index.tsx | 12 +- .../ConnectorDetails/ConnectorTabs/index.tsx | 2 +- .../ConnectorDetails/EmailUsage/index.tsx | 8 +- .../src/pages/ConnectorDetails/index.tsx | 8 +- .../ConnectorDeleteButton/index.tsx | 2 +- .../pages/Connectors/ConnectorName/index.tsx | 2 +- .../Connectors/ConnectorStatusField/index.tsx | 4 +- .../src/pages/Connectors/Guide/index.tsx | 6 +- .../SignInExperienceSetupNotice/index.tsx | 2 +- .../console/src/pages/Connectors/index.tsx | 8 +- .../pages/CustomizeJwt/CreateButton/index.tsx | 18 +- .../CustomizeJwt/CustomizerItem/index.tsx | 6 +- .../UpsellNotice/index.module.scss | 52 + .../pages/CustomizeJwt/UpsellNotice/index.tsx | 48 + .../src/pages/CustomizeJwt/index.module.scss | 4 + .../console/src/pages/CustomizeJwt/index.tsx | 29 +- .../ActionButton/CodeRestoreButton.tsx | 4 +- .../MonacoCodeEditor/Dashboard/index.tsx | 4 +- .../MainContent/MonacoCodeEditor/index.tsx | 2 +- .../ScriptSection/ErrorContent/index.tsx | 2 +- .../MainContent/ScriptSection/index.tsx | 4 +- .../GuideCard/index.module.scss | 2 +- .../InstructionTab/GuideCard/index.tsx | 5 +- .../SettingsSection/InstructionTab/index.tsx | 23 +- .../SettingsSection/TestTab/index.tsx | 4 +- .../MainContent/SettingsSection/index.tsx | 6 +- .../CustomizeJwtDetails/MainContent/index.tsx | 2 +- .../PageLoadingSkeleton/index.module.scss | 5 +- .../PageLoadingSkeleton/index.tsx | 2 +- .../src/pages/CustomizeJwtDetails/index.tsx | 2 +- .../CustomizeJwtDetails/utils/config.tsx | 25 +- .../utils/type-definitions.ts | 4 + .../src/pages/Dashboard/components/Block.tsx | 8 +- .../components/ChartTooltip/index.tsx | 2 +- .../components/Skeleton/index.module.scss | 6 +- .../Dashboard/components/Skeleton/index.tsx | 2 +- .../console/src/pages/Dashboard/index.tsx | 2 +- .../EnterpriseSso/SsoConnectorLogo/index.tsx | 2 +- .../SsoConnectorRadio/index.tsx | 2 +- .../SsoConnectorRadioGroup/index.tsx | 2 +- .../SsoCreationModal/index.module.scss | 4 + .../EnterpriseSso/SsoCreationModal/index.tsx | 51 +- .../console/src/pages/EnterpriseSso/index.tsx | 26 +- .../Connection/FileReader/index.tsx | 10 +- .../ParsedConfigPreview/index.tsx | 2 +- .../Connection/OidcMetadataForm/index.tsx | 2 +- .../Connection/SamlAttributeMapping/index.tsx | 2 +- .../Connection/SamlConnectorForm.tsx | 2 +- .../ParsedConfigPreview/index.tsx | 2 +- .../SwitchFormatButton/index.tsx | 6 +- .../Connection/SamlMetadataForm/index.tsx | 2 +- .../Experience/DomainsInput/index.tsx | 4 +- .../Experience/LogosUploader/index.tsx | 10 +- .../EnterpriseSsoDetails/Experience/index.tsx | 2 +- .../EnterpriseSsoDetails/SsoGuide/index.tsx | 2 +- .../src/pages/EnterpriseSsoDetails/index.tsx | 6 +- .../index.module.scss | 2 +- .../ProtectedAppCreationForm/index.tsx | 2 +- .../console/src/pages/GetStarted/index.tsx | 14 +- .../FactorLabel/WebAuthnTipContent/index.tsx | 2 +- .../pages/Mfa/MfaForm/FactorLabel/index.tsx | 2 +- .../pages/Mfa/MfaForm/UpsellNotice/index.tsx | 51 + .../src/pages/Mfa/MfaForm/index.module.scss | 4 + .../console/src/pages/Mfa/MfaForm/index.tsx | 12 +- .../src/pages/Mfa/PageWrapper/index.tsx | 19 +- .../console/src/pages/Mfa/Skeleton/index.tsx | 2 +- packages/console/src/pages/NotFound/index.tsx | 6 +- .../EditOrganizationRolesModal/index.tsx | 2 +- .../AddAppsToOrganization.tsx | 2 +- .../MachineToMachine/index.tsx | 4 +- .../Members/AddMembersToOrganization.tsx | 2 +- .../OrganizationDetails/Members/index.tsx | 8 +- .../Settings/JitSettings.tsx | 15 +- .../Settings/index.module.scss | 6 +- .../OrganizationDetails/Settings/index.tsx | 35 +- .../OrganizationDetails/Settings/utils.ts | 14 +- .../src/pages/OrganizationDetails/index.tsx | 21 +- .../Permissions/ResourceName/index.tsx | 4 +- .../Permissions/index.tsx | 4 +- .../pages/OrganizationRoleDetails/index.tsx | 6 +- .../OrganizationPermissions/index.tsx | 8 +- .../CreateOrganizationRoleModal.tsx | 4 +- .../OrganizationRoles/index.tsx | 10 +- .../src/pages/OrganizationTemplate/index.tsx | 28 +- .../CreateOrganizationModal/index.module.scss | 3 + .../CreateOrganizationModal/index.tsx | 52 +- .../Introduction/components/FlexBox/index.tsx | 2 +- .../components/InteractiveDiagram/index.tsx | 2 +- .../Introduction/components/Panel/index.tsx | 2 +- .../components/Permission/index.tsx | 2 +- .../Introduction/components/Role/index.tsx | 2 +- .../Introduction/components/Section/index.tsx | 2 +- .../Introduction/components/User/index.tsx | 4 +- .../Introduction/components/Vector/John.tsx | 2 +- .../Introduction/components/Vector/Sarah.tsx | 2 +- .../Organizations/Introduction/index.tsx | 6 +- .../EmptyDataPlaceholder/index.tsx | 8 +- .../OrganizationsTable/index.tsx | 4 +- .../console/src/pages/Organizations/index.tsx | 26 +- .../Profile/components/CardContent/index.tsx | 2 +- .../components/ExperienceLikeModal/index.tsx | 6 +- .../components/LinkAccountSection/index.tsx | 4 +- .../pages/Profile/components/NotSet/index.tsx | 2 +- .../components/Skeleton/index.module.scss | 6 +- .../Profile/components/Skeleton/index.tsx | 2 +- .../BasicUserInfoUpdateModal/index.tsx | 2 +- .../containers/ChangePasswordModal/index.tsx | 2 +- .../DeletionConfirmationModal/index.tsx | 2 +- .../FinalConfirmationModal/index.tsx | 4 +- .../components/TenantsIssuesModal/index.tsx | 2 +- .../components/TenantsList/index.tsx | 2 +- .../containers/DeleteAccountModal/index.tsx | 2 +- .../VerificationCodeModal/index.tsx | 4 +- .../containers/VerifyPasswordModal/index.tsx | 8 +- packages/console/src/pages/Profile/index.tsx | 118 +- .../RoleDetails/RoleApplications/index.tsx | 6 +- .../AssignPermissionsModal/index.tsx | 32 +- .../src/pages/RoleDetails/RoleUsers/index.tsx | 10 +- .../console/src/pages/RoleDetails/index.tsx | 4 +- .../components/AssignRoleModal/index.tsx | 2 +- .../components/AssignedEntities/index.tsx | 2 +- .../components/CreateRoleForm/Footer.tsx | 49 +- .../Roles/components/CreateRoleForm/index.tsx | 2 +- .../components/CreateRoleModal/index.tsx | 2 +- packages/console/src/pages/Roles/index.tsx | 6 +- .../LogoAndFaviconUploader/index.tsx | 75 - .../Branding/BrandingForm/index.tsx | 103 +- .../Branding/CustomCssForm/index.tsx | 66 - .../index.module.scss | 6 + .../Branding/CustomUiForm/index.tsx | 117 + .../PageContent/Branding/index.tsx | 4 +- .../LanguageEditor/AddLanguageSelector.tsx | 6 +- .../LanguageEditor/LanguageDetails.tsx | 6 +- .../LanguageEditor/LanguageItem.tsx | 2 +- .../LanguageEditor/LanguageNav.tsx | 2 +- .../ManageLanguage/LanguageEditor/index.tsx | 4 +- .../Content/LanguagesForm/index.tsx | 2 +- .../PageContent/PasswordPolicy/index.tsx | 2 +- .../SignUpAndSignIn/AdvancedOptions/index.tsx | 2 +- .../SignInMethodEditBox/AddButton.tsx | 6 +- .../SignInMethodEditBox/SignInMethodItem.tsx | 8 +- .../SignInForm/SignInMethodEditBox/index.tsx | 2 +- .../SignUpAndSignIn/SignUpForm/index.tsx | 2 +- .../AddButton/index.tsx | 6 +- .../SelectedConnectorItem/index.tsx | 6 +- .../SocialConnectorEditBox/index.tsx | 2 +- .../ConnectorSetupWarning/index.tsx | 2 +- .../DiffSegment.tsx | 2 +- .../SignInDiffSection.tsx | 2 +- .../SignUpDiffSection.tsx | 2 +- .../SocialTargetsDiffSection.tsx | 2 +- .../SignUpAndSignInChangePreview/index.tsx | 2 +- .../components/FormFieldDescription/index.tsx | 2 +- .../components/FormSectionTitle/index.tsx | 2 +- .../SignInExperienceTabWrapper/index.tsx | 2 +- .../SignInExperience/PageContent/index.tsx | 22 +- .../PageContent/utils/parser.ts | 18 +- .../Skeleton/index.module.scss | 4 +- .../pages/SignInExperience/Skeleton/index.tsx | 6 +- .../SignInExperience/Welcome/GuideModal.tsx | 6 +- .../pages/SignInExperience/Welcome/index.tsx | 6 +- .../CustomUiAssetsUploader/index.module.scss | 62 + .../CustomUiAssetsUploader/index.tsx | 114 + .../components/Preview/index.tsx | 5 +- .../SignInExperienceContextProvider/index.tsx | 48 + .../src/pages/SignInExperience/index.tsx | 21 +- .../SigningKeyFormCard/index.module.scss | 2 +- .../SigningKeys/SigningKeyFormCard/index.tsx | 4 +- .../console/src/pages/SigningKeys/index.tsx | 2 +- .../MauLimitExceededNotification/index.tsx | 50 +- .../Subscription/CurrentPlan/index.tsx | 54 +- .../DiffQuotaItem/SkuQuotaItemPhrase.tsx | 43 + .../PlanQuotaList/DiffQuotaItem/index.tsx | 45 +- .../PlanQuotaDiffCard/PlanQuotaList/index.tsx | 34 +- .../PlanQuotaDiffCard/index.tsx | 29 +- .../DowngradeConfirmModalContent/index.tsx | 39 +- .../TableDataContent/index.tsx | 4 +- .../TableDataWrapper/index.tsx | 4 +- .../PlanComparisonTable/index.tsx | 8 +- .../SwitchPlanActionBar/index.tsx | 133 +- .../TenantSettings/Subscription/index.tsx | 17 +- .../TenantBasicSettings/DeleteCard/index.tsx | 2 +- .../TenantBasicSettings/DeleteModal/index.tsx | 2 +- .../TenantBasicSettings/LeaveCard/index.tsx | 2 +- .../ProfileForm/TenantEnvironment/index.tsx | 2 +- .../ProfileForm/TenantRegion/index.tsx | 2 +- .../TenantBasicSettings/index.tsx | 2 +- .../AddDomainForm/index.tsx | 2 +- .../DnsRecordsTable/index.tsx | 2 +- .../ActivationProcess/Step/index.tsx | 6 +- .../CustomDomain/ActivationProcess/index.tsx | 2 +- .../CustomDomain/CustomDomainHeader/index.tsx | 6 +- .../CustomDomain/index.tsx | 2 +- .../DefaultDomain/index.tsx | 2 +- .../TenantDomainSettings/index.tsx | 2 +- .../TenantMembers/EditMemberModal/index.tsx | 4 +- .../TenantMembers/Invitations/index.tsx | 14 +- .../TenantMembers/InviteEmailsInput/index.tsx | 4 +- .../InviteMemberModal/Footer/index.tsx | 12 +- .../TenantMembers/InviteMemberModal/index.tsx | 63 +- .../TenantSettings/TenantMembers/hooks.ts | 57 +- .../TenantMembers/index.module.scss | 4 + .../TenantSettings/TenantMembers/index.tsx | 8 +- .../index.tsx | 105 +- .../components/Skeleton/index.tsx | 2 +- .../src/pages/TenantSettings/index.tsx | 2 +- .../src/pages/UserDetails/UserLogs/index.tsx | 2 +- .../src/pages/UserDetails/UserRoles/index.tsx | 6 +- .../UserMfaVerifications/index.tsx | 2 +- .../components/UserSocialIdentities/index.tsx | 2 +- .../components/UserSsoIdentities/index.tsx | 2 +- .../console/src/pages/UserDetails/index.tsx | 12 +- .../Users/components/CreateForm/index.tsx | 4 +- packages/console/src/pages/Users/index.tsx | 10 +- .../WebhookDetails/WebhookLogs/index.tsx | 2 +- .../WebhookSettings/SigningKeyField/index.tsx | 4 +- .../WebhookSettings/TestWebhook/index.tsx | 2 +- .../src/pages/WebhookDetails/index.tsx | 12 +- .../Webhooks/CreateFormModal/CreateForm.tsx | 31 +- .../pages/Webhooks/CreateFormModal/index.tsx | 2 +- packages/console/src/pages/Webhooks/index.tsx | 12 +- .../src/pages/Welcome/index.module.scss | 4 +- packages/console/src/pages/Welcome/index.tsx | 4 +- .../console/src/types/sign-in-experience.ts | 11 + packages/console/src/types/skus.ts | 14 + packages/console/src/types/subscriptions.ts | 8 + packages/console/src/utils/connector-form.ts | 9 +- packages/console/src/utils/json.ts | 8 +- packages/console/src/utils/object.ts | 2 + packages/console/src/utils/quota.ts | 42 + packages/console/src/utils/subscription.ts | 54 +- packages/console/src/utils/uploader.ts | 19 +- packages/console/svgo.config.json | 13 - packages/console/tsconfig.json | 6 +- packages/console/vite.config.ts | 84 + packages/core/CHANGELOG.md | 139 + packages/core/package.json | 47 +- packages/core/src/__mocks__/index.ts | 19 +- .../core/src/__mocks__/sign-in-experience.ts | 2 +- packages/core/src/app/init.ts | 7 +- packages/core/src/caches/well-known.ts | 5 + packages/core/src/event-listeners/grant.ts | 3 +- packages/core/src/event-listeners/index.ts | 5 +- packages/core/src/event-listeners/utils.ts | 4 +- packages/core/src/libraries/ogcio-user.ts | 6 +- packages/core/src/libraries/quota.ts | 134 +- .../sign-in-experience/index.test.ts | 20 +- .../src/libraries/sign-in-experience/index.ts | 90 +- packages/core/src/libraries/user.test.ts | 39 +- packages/core/src/libraries/user.ts | 5 +- packages/core/src/libraries/user.utils.ts | 2 +- .../koa-app-secret-transpilation.test.ts | 154 + .../koa-app-secret-transpilation.ts | 141 + packages/core/src/middleware/koa-cors.ts | 4 + .../src/middleware/koa-experience-ssr.test.ts | 81 + .../core/src/middleware/koa-experience-ssr.ts | 67 + .../middleware/koa-interaction-details.ts | 0 .../src/middleware/koa-oidc-error-handler.ts | 11 +- .../core/src/middleware/koa-quota-guard.ts | 22 +- .../src/middleware/koa-security-headers.ts | 17 +- .../koa-serve-custom-ui-assets.test.ts | 91 + .../middleware/koa-serve-custom-ui-assets.ts | 40 + .../core/src/middleware/koa-serve-static.ts | 30 +- .../middleware/koa-slonik-error-handler.ts | 15 + .../core/src/middleware/koa-spa-proxy.test.ts | 34 +- packages/core/src/middleware/koa-spa-proxy.ts | 46 +- packages/core/src/oidc/extra-token-claims.ts | 52 +- .../src/oidc/grants/client-credentials.ts | 51 +- packages/core/src/oidc/grants/index.ts | 2 +- .../src/oidc/grants/refresh-token.test.ts | 40 +- .../core/src/oidc/grants/refresh-token.ts | 156 +- .../grants/token-exchange/actor-token.test.ts | 69 + .../oidc/grants/token-exchange/actor-token.ts | 38 + .../oidc/grants/token-exchange/index.test.ts | 252 + .../src/oidc/grants/token-exchange/index.ts | 207 + .../src/oidc/grants/token-exchange/types.ts | 13 + packages/core/src/oidc/grants/utils.ts | 191 + packages/core/src/oidc/init.ts | 108 +- packages/core/src/oidc/utils.test.ts | 18 +- packages/core/src/oidc/utils.ts | 24 +- .../core/src/queries/application-secrets.ts | 59 + .../queries/application-sign-in-experience.ts | 26 +- packages/core/src/queries/application.ts | 9 +- .../src/queries/sign-in-experience.test.ts | 3 +- packages/core/src/queries/users-roles.ts | 9 +- packages/core/src/routes-me/user-assets.ts | 2 +- packages/core/src/routes/admin-user/basics.ts | 8 - .../application-custom-data.openapi.json | 24 + .../applications/application-custom-data.ts | 31 + ...cation-protected-app-metadata.openapi.json | 16 +- .../application-secret.openapi.json | 104 + .../routes/applications/application-secret.ts | 130 + .../application-sign-in-experience.ts | 6 +- .../applications/application.openapi.json | 64 +- .../routes/applications/application.test.ts | 2 +- .../src/routes/applications/application.ts | 124 +- .../core/src/routes/applications/types.ts | 1 - packages/core/src/routes/connector/index.ts | 5 +- packages/core/src/routes/domain.ts | 8 +- .../classes/experience-interaction.test.ts | 128 + .../classes/experience-interaction.ts | 513 +- .../src/routes/experience/classes/helpers.ts | 162 + .../classes/libraries/mfa-validator.ts | 131 + .../classes/libraries/password-validator.ts | 73 + .../classes/libraries/profile-validator.ts | 187 + .../classes/libraries/provision-library.ts | 288 + .../classes/libraries/sentinel-guard.ts | 72 + .../sign-in-experience-validator.test.ts | 399 + .../libraries/sign-in-experience-validator.ts | 253 + .../core/src/routes/experience/classes/mfa.ts | 330 + .../src/routes/experience/classes/profile.ts | 205 + .../routes/experience/classes/utils.test.ts | 38 + .../src/routes/experience/classes/utils.ts | 66 + .../verifications/backup-code-verification.ts | 152 + .../verifications/code-verification.ts | 287 +- .../enterprise-sso-verification.ts | 278 + .../experience/classes/verifications/index.ts | 101 +- .../new-password-identity-verification.ts | 150 + .../verifications/password-verification.ts | 63 +- .../verifications/social-verification.ts | 166 +- .../verifications/totp-verification.ts | 207 + .../verifications/verification-record.ts | 44 +- .../verifications/verification-records-map.ts | 36 + .../verifications/web-authn-verification.ts | 291 + packages/core/src/routes/experience/const.ts | 2 + packages/core/src/routes/experience/index.ts | 158 +- .../koa-experience-interaction-hooks.ts | 83 + .../middleware/koa-experience-interaction.ts | 41 +- .../koa-experience-verifications-audit-log.ts | 36 + .../src/routes/experience/profile-routes.ts | 222 + packages/core/src/routes/experience/types.ts | 86 + .../backup-code-verification.ts | 104 + .../enterprise-sso-verification.ts | 163 + .../new-password-identity-verification.ts | 68 + .../password-verification.ts | 49 +- .../social-verification.ts | 79 +- .../verification-routes/totp-verification.ts | 135 + .../verification-routes/verification-code.ts | 88 +- .../web-authn-verification.ts | 224 + packages/core/src/routes/hook.ts | 7 +- packages/core/src/routes/init.ts | 7 +- .../interaction/actions/submit-interaction.ts | 5 +- .../core/src/routes/interaction/additional.ts | 4 +- .../src/routes/interaction/consent/index.ts | 8 +- packages/core/src/routes/interaction/index.ts | 20 +- packages/core/src/routes/interaction/mfa.ts | 2 +- .../middleware/koa-interaction-hooks.ts | 11 +- .../src/routes/interaction/single-sign-on.ts | 2 +- .../src/routes/interaction/types/index.ts | 1 - .../utils/single-sign-on-session.ts | 29 +- .../interaction/utils/single-sign-on.test.ts | 6 +- .../interaction/utils/single-sign-on.ts | 77 +- .../utils/social-verification.test.ts | 19 +- .../interaction/utils/social-verification.ts | 6 +- .../mandatory-user-profile-validation.ts | 6 +- .../verifications/mfa-payload-verification.ts | 20 +- .../verifications/mfa-verification.ts | 6 +- .../src/routes/logto-config/jwt-customizer.ts | 17 +- .../src/routes/organization-role/index.ts | 9 +- .../src/routes/organization-scope/index.ts | 9 +- .../application/index.openapi.json | 16 +- .../core/src/routes/organization/index.ts | 9 +- packages/core/src/routes/resource.scope.ts | 5 +- packages/core/src/routes/resource.ts | 7 +- packages/core/src/routes/role.scope.ts | 5 +- packages/core/src/routes/role.ts | 31 +- .../custom-ui-assets/index.openapi.json | 42 + .../custom-ui-assets/index.test.ts | 133 + .../custom-ui-assets/index.ts | 127 + .../src/routes/sign-in-experience/index.ts | 15 +- .../core/src/routes/sso-connector/index.ts | 7 +- .../src/routes/subject-token.openapi.json | 40 + packages/core/src/routes/subject-token.ts | 64 + packages/core/src/routes/swagger/consts.ts | 20 +- packages/core/src/routes/swagger/index.ts | 42 +- .../core/src/routes/swagger/utils/general.ts | 31 +- .../src/routes/swagger/utils/operation-id.ts | 6 +- .../src/routes/swagger/utils/parameters.ts | 14 + packages/core/src/routes/user-assets.ts | 2 +- packages/core/src/routes/well-known.ts | 30 +- packages/core/src/sso/types/session.ts | 53 +- packages/core/src/tenants/Libraries.ts | 3 +- packages/core/src/tenants/Queries.ts | 2 + packages/core/src/tenants/SystemContext.ts | 16 + packages/core/src/tenants/Tenant.ts | 22 +- packages/core/src/test-utils/quota.ts | 2 + packages/core/src/utils/SchemaRouter.ts | 12 +- packages/core/src/utils/file.test.ts | 16 + packages/core/src/utils/file.ts | 17 + packages/core/src/utils/i18n.ts | 31 + .../core/src/utils/storage/azure-storage.ts | 23 +- packages/core/src/utils/storage/consts.ts | 8 - packages/core/src/utils/subscription/index.ts | 46 +- packages/core/src/utils/subscription/types.ts | 22 + packages/core/tsconfig.base.json | 13 - packages/core/tsconfig.build.json | 10 - packages/core/tsconfig.json | 22 +- packages/core/tsconfig.test.json | 5 +- packages/core/tsup.config.ts | 11 + packages/core/tsup.dev.config.ts | 9 + packages/create/CHANGELOG.md | 7 + packages/create/package.json | 4 +- packages/demo-app/.parcelrc.arm64 | 7 - packages/demo-app/CHANGELOG.md | 12 + packages/demo-app/{src => }/index.html | 6 +- packages/demo-app/package.json | 47 +- packages/demo-app/src/App.tsx | 25 +- packages/demo-app/src/DevPanel.tsx | 30 +- packages/demo-app/src/include.d/vite-end.d.ts | 2 + packages/demo-app/src/index.tsx | 2 - packages/demo-app/src/utils.ts | 28 +- packages/demo-app/tsconfig.json | 1 + packages/demo-app/vite.config.ts | 22 + packages/elements/.gitignore | 1 + packages/elements/README.md | 41 + packages/elements/index.html | 19 + packages/elements/lit-localize.json | 15 + packages/elements/package.json | 89 + .../elements/src/components/logto-avatar.ts | 53 + .../src/components/logto-button.styles.ts | 106 + .../elements/src/components/logto-button.ts | 58 + .../src/components/logto-card-section.ts | 33 + .../elements/src/components/logto-card.ts | 33 + .../src/components/logto-form-card.ts | 78 + .../src/components/logto-icon-button.ts | 51 + .../elements/src/components/logto-list-row.ts | 55 + .../elements/src/components/logto-list.ts | 23 + .../src/components/logto-modal-layout.ts | 75 + .../src/components/logto-modal.context.ts | 16 + .../elements/src/components/logto-modal.ts | 88 + .../src/components/logto-text-input.ts | 85 + .../src/elements/logto-profile-card.ts | 129 + packages/elements/src/icons/close.svg | 5 + packages/elements/src/icons/index.d.ts | 4 + packages/elements/src/index.ts | 18 + packages/elements/src/phrases/index.ts | 6 + .../src/providers/logto-theme-provider.ts | 22 + .../src/providers/logto-user-provider.ts | 61 + packages/elements/src/react.ts | 48 + packages/elements/src/utils/api.ts | 22 + packages/elements/src/utils/css.ts | 37 + packages/elements/src/utils/locale.ts | 11 + packages/elements/src/utils/string.ts | 19 + packages/elements/src/utils/theme.ts | 174 + packages/elements/tsconfig.json | 12 + packages/elements/tsup.config.ts | 23 + packages/elements/web-dev-server.config.js | 33 + packages/elements/xliff/de.xlf | 50 + packages/elements/xliff/es.xlf | 50 + packages/elements/xliff/fr.xlf | 50 + packages/elements/xliff/it.xlf | 50 + packages/elements/xliff/ja.xlf | 50 + packages/elements/xliff/ko.xlf | 50 + packages/elements/xliff/pl-PL.xlf | 50 + packages/elements/xliff/pt-BR.xlf | 50 + packages/elements/xliff/pt-PT.xlf | 50 + packages/elements/xliff/ru.xlf | 50 + packages/elements/xliff/tr-TR.xlf | 50 + packages/elements/xliff/zh-CN.xlf | 50 + packages/elements/xliff/zh-HK.xlf | 50 + packages/elements/xliff/zh-TW.xlf | 50 + packages/experience/.eslintrc.cjs | 22 + packages/experience/.parcelrc | 16 - packages/experience/.parcelrc.arm64 | 20 - packages/experience/CHANGELOG.md | 53 + packages/experience/index.html | 20 + packages/experience/jest.config.ts | 2 +- packages/experience/package.json | 74 +- .../experience/src/Layout/AppLayout/index.tsx | 2 +- .../src/Layout/LandingPageLayout/index.tsx | 2 +- .../src/Layout/SecondaryPageLayout/index.tsx | 2 +- .../src/Layout/SectionLayout/index.tsx | 2 +- .../src/Layout/StaticPageLayout/index.tsx | 2 +- .../src/Providers/AppBoundary/AppMeta.tsx | 19 +- .../Providers/AppBoundary/use-color-theme.ts | 2 + .../Providers/ConfirmModalProvider/index.tsx | 119 +- .../ConfirmModalProvider/indext.test.tsx | 210 +- .../IframeModalProvider/IframeModal/index.tsx | 2 +- .../Providers/LoadingLayerProvider/index.tsx | 6 +- .../UserInteractionContext.tsx | 38 + .../UserInteractionContextProvider/index.tsx | 47 +- packages/experience/src/__mocks__/logto.tsx | 4 +- packages/experience/src/apis/settings.ts | 16 +- .../src/assets/icons/loading-ring.svg | 3 + .../src/components/BrandingHeader/index.tsx | 4 +- .../src/components/Button/IconButton.tsx | 2 +- .../src/components/Button/MfaFactorButton.tsx | 12 +- .../Button/RotatingRingIcon.module.scss | 14 + .../components/Button/RotatingRingIcon.tsx | 7 + .../Button/SocialLinkButton.module.scss | 9 + .../components/Button/SocialLinkButton.tsx | 28 +- .../src/components/Button/index.module.scss | 34 +- .../src/components/Button/index.tsx | 24 +- .../src/components/Checkbox/index.tsx | 4 +- .../src/components/ConfirmModal/AcModal.tsx | 10 +- .../components/ConfirmModal/MobileModal.tsx | 14 +- .../src/components/ConfirmModal/type.ts | 2 + .../src/components/Divider/index.tsx | 2 +- .../src/components/ErrorMessage/index.tsx | 2 +- .../NotchedBorder/index.module.scss | 131 + .../InputField/NotchedBorder/index.tsx | 54 + .../InputFields/InputField/index.module.scss | 176 +- .../InputFields/InputField/index.tsx | 117 +- .../InputFields/PasswordInputField/index.tsx | 4 +- .../SmartInputField/AnimatedPrefix/index.tsx | 2 +- .../CountryCodeDropdown/index.module.scss | 4 +- .../CountryCodeDropdown/index.test.tsx | 8 +- .../CountryCodeDropdown/index.tsx | 7 +- .../CountryCodeSelector/index.module.scss | 8 + .../CountryCodeSelector/index.tsx | 6 +- .../InputFields/SmartInputField/index.tsx | 5 +- .../SmartInputField/use-smart-input-field.ts | 9 +- .../InputFields/SmartInputField/utils.test.ts | 10 +- .../InputFields/SmartInputField/utils.ts | 10 +- .../components/LoadingLayer/LoadingIcon.tsx | 4 +- .../components/LoadingLayer/index.module.scss | 7 - .../src/components/LoadingLayer/index.tsx | 8 +- .../components/LoadingMask/index.module.scss | 8 + .../src/components/LoadingMask/index.tsx | 13 + .../LogtoSignature/index.module.scss | 4 + .../src/components/LogtoSignature/index.tsx | 8 +- .../src/components/NavBar/index.tsx | 6 +- .../Notification/AppNotification/index.tsx | 4 +- .../Notification/InlineNotification/index.tsx | 2 +- .../components/SwitchMfaFactorsLink/index.tsx | 2 +- .../src/components/TermsLinks/index.tsx | 2 +- .../src/components/TextLink/index.tsx | 2 +- .../experience/src/components/Toast/index.tsx | 2 +- .../src/components/VerificationCode/index.tsx | 2 +- .../DevelopmentTenantNotification/index.tsx | 2 +- .../containers/ForgotPasswordLink/index.tsx | 32 +- .../src/containers/MfaFactorList/index.tsx | 2 +- .../SetPassword/HiddenIdentifierInput.tsx | 25 + .../src/containers/SetPassword/Lite.tsx | 21 +- .../containers/SetPassword/SetPassword.tsx | 25 +- .../containers/SetPassword/TogglePassword.tsx | 2 +- .../src/containers/SetPassword/index.tsx | 2 +- .../src/containers/SocialLanding/index.tsx | 2 +- .../SocialLinkAccount/index.module.scss | 6 +- .../SocialLinkAccount/index.test.tsx | 6 +- .../containers/SocialLinkAccount/index.tsx | 52 +- .../use-social-link-related-user.ts | 2 +- .../src/containers/SocialSignInList/index.tsx | 14 +- .../containers/SocialSignInList/use-social.ts | 16 +- .../TermsAndPrivacyCheckbox/index.tsx | 2 +- .../TotpCodeVerification/index.module.scss | 4 + .../containers/TotpCodeVerification/index.tsx | 77 +- .../use-totp-code-verification.ts | 4 +- .../VerificationCode/PasswordSignInLink.tsx | 9 +- .../VerificationCode/index.module.scss | 3 +- .../src/containers/VerificationCode/index.tsx | 78 +- .../use-continue-flow-code-verification.ts | 2 +- .../use-identifier-error-alert.ts | 4 +- .../use-link-social-confirm-modal.ts | 16 +- .../use-register-flow-code-verification.ts | 38 +- .../use-sign-in-flow-code-verification.ts | 42 +- .../src/hooks/use-check-single-sign-on.ts | 10 +- .../experience/src/hooks/use-confirm-modal.ts | 47 +- .../experience/src/hooks/use-error-handler.ts | 1 + .../src/hooks/use-global-redirect-to.ts | 74 +- .../src/hooks/use-password-sign-in.ts | 2 +- .../src/hooks/use-send-mfa-payload.ts | 2 +- .../src/hooks/use-send-verification-code.ts | 5 +- .../src/hooks/use-session-storages.ts | 6 +- .../src/hooks/use-single-sign-on.ts | 16 +- packages/experience/src/hooks/use-skip-mfa.ts | 2 +- .../src/hooks/use-social-link-account.ts | 2 +- .../src/hooks/use-social-register.ts | 2 +- packages/experience/src/hooks/use-terms.ts | 4 +- packages/experience/src/i18n/utils.ts | 41 +- packages/experience/src/include.d/global.d.ts | 14 +- .../experience/src/include.d/react-app.d.ts | 65 - .../src/include.d/react-router-dom.d.ts | 1 - .../experience/src/include.d/vite-env.d.ts | 2 + packages/experience/src/index.html | 34 - packages/experience/src/jest.setup.ts | 22 +- .../experience/src/pages/Callback/index.tsx | 2 +- .../OrganizationItem/index.module.scss | 2 +- .../OrganizationItem/index.tsx | 6 +- .../OrganizationSelectorModal/index.tsx | 2 +- .../Consent/OrganizationSelector/index.tsx | 4 +- .../src/pages/Consent/ScopeGroup/index.tsx | 6 +- .../pages/Consent/ScopesListCard/index.tsx | 2 +- .../src/pages/Consent/UserProfile/index.tsx | 4 +- .../experience/src/pages/Consent/index.tsx | 10 +- .../Continue/IdentifierProfileForm/index.tsx | 8 +- .../SocialIdentityNotification.tsx | 2 +- .../pages/Continue/SetEmailOrPhone/index.tsx | 5 + .../src/pages/Continue/SetPassword/index.tsx | 8 +- .../src/pages/Continue/SetUsername/index.tsx | 6 + .../Continue/SetUsername/use-set-username.ts | 2 +- .../src/pages/DirectSignIn/index.test.tsx | 31 +- .../experience/src/pages/ErrorPage/index.tsx | 6 +- .../ForgotPasswordForm/index.test.tsx | 23 +- .../ForgotPasswordForm/index.tsx | 17 +- .../src/pages/ForgotPassword/index.test.tsx | 111 +- .../src/pages/ForgotPassword/index.tsx | 17 +- .../MfaBinding/BackupCodeBinding/index.tsx | 11 +- .../TotpBinding/SecretSection/index.tsx | 2 +- .../pages/MfaBinding/TotpBinding/index.tsx | 2 +- .../MfaBinding/WebAuthnBinding/index.tsx | 11 +- .../BackupCodeVerification/index.tsx | 14 +- .../TotpVerification/index.tsx | 2 +- .../WebAuthnVerification/index.tsx | 11 +- .../IdentifierRegisterForm/index.test.tsx | 19 +- .../Register/IdentifierRegisterForm/index.tsx | 17 +- .../experience/src/pages/Register/index.tsx | 2 +- .../src/pages/RegisterPassword/index.tsx | 8 +- .../src/pages/ResetPassword/index.tsx | 14 +- .../IdentifierSignInForm/index.test.tsx | 35 +- .../SignIn/IdentifierSignInForm/index.tsx | 16 +- .../IdentifierSignInForm/use-on-submit.ts | 33 +- packages/experience/src/pages/SignIn/Main.tsx | 2 +- .../pages/SignIn/PasswordSignInForm/index.tsx | 16 +- .../experience/src/pages/SignIn/index.tsx | 2 +- .../PasswordForm/VerificationCodeLink.tsx | 2 +- .../PasswordForm/index.test.tsx | 1 - .../SignInPassword/PasswordForm/index.tsx | 16 +- .../src/pages/SignInPassword/index.test.tsx | 26 +- .../src/pages/SignInPassword/index.tsx | 18 +- .../pages/SingleSignOnConnectors/index.tsx | 17 +- .../src/pages/SingleSignOnEmail/index.tsx | 13 +- .../src/pages/SocialLanding/index.test.tsx | 19 +- .../src/pages/SocialLanding/index.tsx | 2 +- .../pages/SocialLinkAccount/index.test.tsx | 16 +- .../use-single-sign-on-listener.ts | 4 +- .../src/pages/VerificationCode/index.test.tsx | 31 +- .../src/pages/VerificationCode/index.tsx | 42 +- packages/experience/src/scss/_colors.scss | 3 + packages/experience/src/types/guard.ts | 35 +- .../experience/src/utils/search-parameters.ts | 33 +- .../src/utils/sign-in-experience.ts | 17 +- packages/experience/tsconfig.json | 2 +- packages/experience/vite.config.ts | 54 + packages/integration-tests/CHANGELOG.md | 61 + packages/integration-tests/jest.setup.api.js | 6 + packages/integration-tests/jest.setup.js | 3 - packages/integration-tests/package.json | 17 +- .../src/__mocks__/jwt-customizer.ts | 2 +- .../integration-tests/src/api/admin-user.ts | 3 + .../integration-tests/src/api/application.ts | 52 +- .../src/api/sso-connector.ts | 1 + .../src/api/subject-token.ts | 2 +- .../src/client/experience/const.ts | 2 + .../src/client/experience/index.ts | 134 +- packages/integration-tests/src/constants.ts | 2 +- .../integration-tests/src/helpers/client.ts | 3 + .../src/helpers/connector.ts | 1 + .../experience/enterprise-sso-verification.ts | 41 + .../src/helpers/experience/index.ts | 233 +- .../helpers/experience/totp-verification.ts | 39 + .../src/include.d/global.d.ts | 4 + .../src/tests/api/admin-user.test.ts | 4 +- .../application-custom-data.test.ts | 52 + .../application-sign-in-experience.test.ts | 13 - .../application/application.secrets.test.ts | 180 + .../tests/api/application/application.test.ts | 9 +- .../bind-mfa/happpy-path.test.ts | 272 + .../experience-api/bind-mfa/sad-path.test.ts | 179 + .../api/experience-api/interaction.test.ts | 65 + .../profile/fulfill-user-profiles.test.ts | 180 + .../profile/reset-password.test.ts | 150 + .../organization-jti.test.ts | 201 + .../username-password.test.ts | 85 + .../verification-code.test.ts | 191 + .../enterprise-sso.test.ts | 191 + .../mfa-verification.test.ts | 97 + .../sign-in-interaction/password.test.ts | 77 +- .../sign-in-interaction/social.test.ts | 351 + .../verification-code.test.ts | 75 +- .../backup-code-verification.test.ts | 90 + .../enterprise-sso-verification.test.ts | 247 + ...new-password-identity-verification.test.ts | 129 + .../password-verification.test.ts | 4 +- .../verifications/social-verification.test.ts | 7 +- .../verifications/totp-verification.test.ts | 163 + .../verifications/verification-code.test.ts | 6 +- .../src/tests/api/hook/WebhookMockServer.ts | 1 + .../tests/api/hook/hook.trigger.data.test.ts | 2 + .../api/hook/hook.trigger.experience.test.ts | 336 + .../src/tests/api/hook/utils.ts | 1 + .../tests/api/interaction/mfa/totp.test.ts | 4 +- .../api/interaction/organization-jit.test.ts | 2 +- .../api/oidc/client-authentication.test.ts | 242 + .../tests/api/oidc/content-type-json.test.ts | 35 + .../src/tests/api/oidc/id-token.test.ts | 4 +- .../api/oidc/refresh-token-grant.test.ts | 18 +- .../src/tests/api/oidc/token-exchange.test.ts | 257 +- .../src/tests/api/security.test.ts | 3 - .../src/tests/api/sign-in-experience.test.ts | 8 +- .../tests/console/backchannel-logout.test.ts | 9 +- .../src/tests/console/error-handling.test.ts | 46 + .../console/sign-in-experience/helpers.ts | 2 +- .../automatic-account-linking.test.ts | 2 +- .../experience/mfa/totp/social-flow.test.ts | 2 +- .../src/tests/experience/overrides.test.ts | 304 + .../experience/server-side-rendering.test.ts | 111 + .../src/ui-helpers/expect-experience.ts | 12 + .../integration-tests/src/ui-helpers/trace.ts | 54 + packages/integration-tests/tsup.config.ts | 10 + packages/phrases-experience/package.json | 5 +- .../src/locales/de/action.ts | 2 +- .../src/locales/de/description.ts | 3 +- .../src/locales/de/error/index.ts | 2 +- .../src/locales/en/action.ts | 2 +- .../src/locales/en/description.ts | 4 +- .../src/locales/en/error/index.ts | 2 +- .../src/locales/es/action.ts | 2 +- .../src/locales/es/description.ts | 3 +- .../src/locales/es/error/index.ts | 2 +- .../src/locales/fr/action.ts | 2 +- .../src/locales/fr/description.ts | 3 +- .../src/locales/fr/error/index.ts | 2 +- .../src/locales/it/action.ts | 2 +- .../src/locales/it/description.ts | 4 +- .../src/locales/it/error/index.ts | 2 +- .../src/locales/ja/action.ts | 2 +- .../src/locales/ja/description.ts | 4 +- .../src/locales/ja/error/index.ts | 2 +- .../src/locales/ko/action.ts | 2 +- .../src/locales/ko/description.ts | 3 +- .../src/locales/pl-pl/action.ts | 2 +- .../src/locales/pl-pl/description.ts | 4 +- .../src/locales/pl-pl/error/index.ts | 2 +- .../src/locales/pt-br/action.ts | 2 +- .../src/locales/pt-br/description.ts | 3 +- .../src/locales/pt-br/error/index.ts | 2 +- .../src/locales/pt-pt/action.ts | 2 +- .../src/locales/pt-pt/description.ts | 3 +- .../src/locales/ru/action.ts | 2 +- .../src/locales/ru/description.ts | 3 +- .../src/locales/ru/error/index.ts | 2 +- .../src/locales/tr-tr/action.ts | 2 +- .../src/locales/tr-tr/description.ts | 3 +- .../src/locales/tr-tr/error/index.ts | 2 +- .../src/locales/zh-cn/action.ts | 8 +- .../src/locales/zh-cn/description.ts | 16 +- .../src/locales/zh-cn/error/index.ts | 2 +- .../src/locales/zh-cn/user-scopes.ts | 27 +- .../src/locales/zh-hk/action.ts | 2 +- .../src/locales/zh-hk/description.ts | 3 +- .../src/locales/zh-hk/error/index.ts | 2 +- .../src/locales/zh-tw/action.ts | 2 +- .../src/locales/zh-tw/description.ts | 3 +- .../src/locales/zh-tw/error/index.ts | 2 +- packages/phrases-experience/src/types.ts | 10 +- packages/phrases/CHANGELOG.md | 44 + packages/phrases/package.json | 6 +- .../phrases/src/locales/de/errors/session.ts | 3 + .../admin-console/application-details.ts | 28 +- .../de/translation/admin-console/cloud.ts | 7 + .../translation/admin-console/components.ts | 2 +- .../admin-console/connector-details.ts | 18 +- .../translation/admin-console/connectors.ts | 12 +- .../translation/admin-console/jwt-claims.ts | 5 + .../admin-console/organization-details.ts | 50 +- .../admin-console/organization-template.ts | 5 +- .../admin-console/organizations.ts | 1 + .../de/translation/admin-console/profile.ts | 38 + .../translation/admin-console/role-details.ts | 3 +- .../de/translation/admin-console/roles.ts | 6 + .../admin-console/sign-in-exp/index.ts | 62 +- .../sign-in-exp/sign-up-and-sign-in.ts | 3 + .../admin-console/subscription/quota-item.ts | 12 + .../admin-console/subscription/quota-table.ts | 6 +- .../de/translation/admin-console/tenants.ts | 11 + .../admin-console/upsell/add-on.ts | 24 + .../admin-console/upsell/paywall.ts | 2 + .../translation/admin-console/user-details.ts | 5 + .../src/locales/de/translation/demo-app.ts | 1 + .../src/locales/en/errors/application.ts | 2 + .../phrases/src/locales/en/errors/guard.ts | 1 + .../phrases/src/locales/en/errors/session.ts | 5 + .../admin-console/application-details.ts | 47 +- .../en/translation/admin-console/cloud.ts | 2 +- .../translation/admin-console/components.ts | 2 +- .../admin-console/connector-details.ts | 4 +- .../translation/admin-console/connectors.ts | 12 +- .../translation/admin-console/jwt-claims.ts | 5 + .../admin-console/organization-details.ts | 5 + .../admin-console/sign-in-exp/index.ts | 58 +- .../admin-console/subscription/index.ts | 2 + .../admin-console/subscription/quota-item.ts | 12 + .../admin-console/subscription/quota-table.ts | 4 +- .../admin-console/subscription/usage.ts | 59 + .../admin-console/upsell/add-on.ts | 18 + .../translation/admin-console/upsell/index.ts | 2 + .../admin-console/upsell/paywall.ts | 10 +- .../phrases/src/locales/es/errors/session.ts | 3 + .../admin-console/application-details.ts | 25 +- .../es/translation/admin-console/cloud.ts | 7 + .../translation/admin-console/components.ts | 2 +- .../admin-console/connector-details.ts | 18 +- .../translation/admin-console/connectors.ts | 12 +- .../translation/admin-console/jwt-claims.ts | 5 + .../admin-console/organization-details.ts | 50 +- .../admin-console/organization-template.ts | 5 +- .../admin-console/organizations.ts | 1 + .../es/translation/admin-console/profile.ts | 38 + .../es/translation/admin-console/roles.ts | 5 + .../admin-console/sign-in-exp/index.ts | 60 +- .../sign-in-exp/sign-up-and-sign-in.ts | 3 + .../admin-console/subscription/quota-item.ts | 12 + .../admin-console/subscription/quota-table.ts | 4 +- .../es/translation/admin-console/tenants.ts | 11 + .../admin-console/upsell/add-on.ts | 24 + .../admin-console/upsell/paywall.ts | 2 + .../translation/admin-console/user-details.ts | 5 + .../src/locales/es/translation/demo-app.ts | 1 + .../phrases/src/locales/fr/errors/session.ts | 3 + .../admin-console/application-details.ts | 27 +- .../fr/translation/admin-console/cloud.ts | 7 + .../translation/admin-console/components.ts | 2 +- .../admin-console/connector-details.ts | 16 +- .../translation/admin-console/connectors.ts | 12 +- .../translation/admin-console/jwt-claims.ts | 5 + .../admin-console/organization-details.ts | 50 +- .../admin-console/organization-template.ts | 5 +- .../admin-console/organizations.ts | 1 + .../fr/translation/admin-console/profile.ts | 38 + .../fr/translation/admin-console/roles.ts | 6 + .../admin-console/sign-in-exp/index.ts | 60 +- .../sign-in-exp/sign-up-and-sign-in.ts | 3 + .../admin-console/subscription/quota-item.ts | 36 +- .../admin-console/subscription/quota-table.ts | 4 +- .../fr/translation/admin-console/tenants.ts | 11 + .../admin-console/upsell/add-on.ts | 24 + .../admin-console/upsell/paywall.ts | 14 +- .../translation/admin-console/user-details.ts | 5 + .../src/locales/fr/translation/demo-app.ts | 1 + .../phrases/src/locales/it/errors/session.ts | 3 + .../admin-console/application-details.ts | 25 +- .../it/translation/admin-console/cloud.ts | 7 + .../translation/admin-console/components.ts | 2 +- .../admin-console/connector-details.ts | 17 +- .../translation/admin-console/connectors.ts | 12 +- .../translation/admin-console/jwt-claims.ts | 7 +- .../admin-console/organization-details.ts | 49 +- .../admin-console/organization-template.ts | 5 +- .../admin-console/organizations.ts | 1 + .../it/translation/admin-console/profile.ts | 38 + .../it/translation/admin-console/roles.ts | 6 + .../admin-console/sign-in-exp/index.ts | 62 +- .../sign-in-exp/sign-up-and-sign-in.ts | 3 + .../admin-console/subscription/quota-item.ts | 12 + .../admin-console/subscription/quota-table.ts | 4 +- .../it/translation/admin-console/tenants.ts | 11 + .../admin-console/upsell/add-on.ts | 24 + .../admin-console/upsell/paywall.ts | 2 + .../translation/admin-console/user-details.ts | 5 + .../src/locales/it/translation/demo-app.ts | 1 + .../phrases/src/locales/ja/errors/session.ts | 36 +- .../admin-console/application-details.ts | 79 +- .../ja/translation/admin-console/cloud.ts | 17 +- .../translation/admin-console/components.ts | 2 +- .../admin-console/connector-details.ts | 30 +- .../translation/admin-console/connectors.ts | 43 +- .../translation/admin-console/jwt-claims.ts | 5 + .../admin-console/organization-details.ts | 48 +- .../admin-console/organization-template.ts | 7 +- .../admin-console/organizations.ts | 25 +- .../ja/translation/admin-console/profile.ts | 33 + .../ja/translation/admin-console/roles.ts | 10 +- .../admin-console/sign-in-exp/index.ts | 72 +- .../sign-in-exp/sign-up-and-sign-in.ts | 9 +- .../admin-console/subscription/quota-item.ts | 28 +- .../admin-console/subscription/quota-table.ts | 14 +- .../ja/translation/admin-console/tenants.ts | 15 +- .../admin-console/upsell/add-on.ts | 24 + .../admin-console/upsell/paywall.ts | 18 +- .../translation/admin-console/user-details.ts | 11 +- .../src/locales/ja/translation/demo-app.ts | 1 + .../phrases/src/locales/ko/errors/session.ts | 28 +- .../admin-console/application-details.ts | 24 +- .../ko/translation/admin-console/cloud.ts | 7 + .../translation/admin-console/components.ts | 2 +- .../admin-console/connector-details.ts | 18 +- .../translation/admin-console/connectors.ts | 11 +- .../translation/admin-console/jwt-claims.ts | 5 + .../admin-console/organization-details.ts | 48 +- .../admin-console/organization-template.ts | 5 +- .../admin-console/organizations.ts | 1 + .../ko/translation/admin-console/profile.ts | 33 + .../ko/translation/admin-console/roles.ts | 5 + .../admin-console/sign-in-exp/index.ts | 62 +- .../sign-in-exp/sign-up-and-sign-in.ts | 3 + .../admin-console/subscription/quota-item.ts | 12 + .../admin-console/subscription/quota-table.ts | 20 +- .../ko/translation/admin-console/tenants.ts | 10 + .../admin-console/upsell/add-on.ts | 24 + .../admin-console/upsell/paywall.ts | 17 +- .../translation/admin-console/user-details.ts | 5 + .../src/locales/ko/translation/demo-app.ts | 1 + .../src/locales/pl-pl/errors/session.ts | 3 + .../admin-console/application-details.ts | 24 +- .../pl-pl/translation/admin-console/cloud.ts | 7 + .../translation/admin-console/components.ts | 2 +- .../admin-console/connector-details.ts | 18 +- .../translation/admin-console/connectors.ts | 12 +- .../translation/admin-console/jwt-claims.ts | 5 + .../admin-console/organization-details.ts | 49 +- .../admin-console/organization-template.ts | 5 +- .../admin-console/organizations.ts | 1 + .../translation/admin-console/profile.ts | 34 + .../pl-pl/translation/admin-console/roles.ts | 6 + .../admin-console/sign-in-exp/index.ts | 58 +- .../sign-in-exp/sign-up-and-sign-in.ts | 3 + .../admin-console/subscription/quota-item.ts | 12 + .../admin-console/subscription/quota-table.ts | 4 +- .../translation/admin-console/tenants.ts | 17 +- .../admin-console/upsell/add-on.ts | 24 + .../admin-console/upsell/paywall.ts | 2 + .../translation/admin-console/user-details.ts | 7 + .../src/locales/pl-pl/translation/demo-app.ts | 1 + .../src/locales/pt-br/errors/session.ts | 3 + .../admin-console/application-details.ts | 25 +- .../pt-br/translation/admin-console/cloud.ts | 7 + .../translation/admin-console/components.ts | 2 +- .../admin-console/connector-details.ts | 18 +- .../translation/admin-console/connectors.ts | 11 +- .../translation/admin-console/jwt-claims.ts | 5 + .../admin-console/organization-details.ts | 49 +- .../admin-console/organization-template.ts | 5 +- .../admin-console/organizations.ts | 3 +- .../translation/admin-console/profile.ts | 36 + .../pt-br/translation/admin-console/roles.ts | 5 + .../admin-console/sign-in-exp/index.ts | 58 +- .../sign-in-exp/sign-up-and-sign-in.ts | 3 + .../admin-console/subscription/quota-item.ts | 12 + .../admin-console/subscription/quota-table.ts | 4 +- .../translation/admin-console/tenants.ts | 11 + .../admin-console/upsell/add-on.ts | 24 + .../admin-console/upsell/paywall.ts | 2 + .../translation/admin-console/user-details.ts | 7 + .../src/locales/pt-br/translation/demo-app.ts | 1 + .../src/locales/pt-pt/errors/session.ts | 3 + .../admin-console/application-details.ts | 27 +- .../pt-pt/translation/admin-console/cloud.ts | 7 + .../translation/admin-console/components.ts | 2 +- .../admin-console/connector-details.ts | 18 +- .../translation/admin-console/connectors.ts | 12 +- .../translation/admin-console/jwt-claims.ts | 5 + .../admin-console/organization-details.ts | 49 +- .../admin-console/organization-template.ts | 5 +- .../admin-console/organizations.ts | 1 + .../translation/admin-console/profile.ts | 36 + .../pt-pt/translation/admin-console/roles.ts | 5 + .../admin-console/sign-in-exp/index.ts | 60 +- .../sign-in-exp/sign-up-and-sign-in.ts | 3 + .../admin-console/subscription/quota-item.ts | 14 +- .../admin-console/subscription/quota-table.ts | 4 +- .../translation/admin-console/tenants.ts | 13 +- .../admin-console/upsell/add-on.ts | 24 + .../admin-console/upsell/paywall.ts | 2 + .../translation/admin-console/user-details.ts | 5 + .../src/locales/pt-pt/translation/demo-app.ts | 1 + .../phrases/src/locales/ru/errors/session.ts | 3 + .../admin-console/application-details.ts | 25 +- .../ru/translation/admin-console/cloud.ts | 7 + .../translation/admin-console/components.ts | 2 +- .../admin-console/connector-details.ts | 18 +- .../translation/admin-console/connectors.ts | 12 +- .../translation/admin-console/jwt-claims.ts | 5 + .../admin-console/organization-details.ts | 49 +- .../admin-console/organization-template.ts | 5 +- .../admin-console/organizations.ts | 1 + .../ru/translation/admin-console/profile.ts | 37 + .../ru/translation/admin-console/roles.ts | 6 + .../admin-console/sign-in-exp/index.ts | 63 +- .../sign-in-exp/sign-up-and-sign-in.ts | 3 + .../admin-console/subscription/quota-item.ts | 12 + .../admin-console/subscription/quota-table.ts | 4 +- .../ru/translation/admin-console/tenants.ts | 13 +- .../admin-console/upsell/add-on.ts | 24 + .../admin-console/upsell/paywall.ts | 4 +- .../translation/admin-console/user-details.ts | 5 + .../src/locales/ru/translation/demo-app.ts | 1 + .../src/locales/tr-tr/errors/session.ts | 29 +- .../admin-console/application-details.ts | 26 +- .../tr-tr/translation/admin-console/cloud.ts | 7 + .../translation/admin-console/components.ts | 3 +- .../admin-console/connector-details.ts | 18 +- .../translation/admin-console/connectors.ts | 11 +- .../translation/admin-console/jwt-claims.ts | 5 + .../admin-console/organization-details.ts | 49 +- .../admin-console/organization-template.ts | 5 +- .../admin-console/organizations.ts | 1 + .../translation/admin-console/profile.ts | 35 + .../tr-tr/translation/admin-console/roles.ts | 5 + .../admin-console/sign-in-exp/index.ts | 64 +- .../sign-in-exp/sign-up-and-sign-in.ts | 3 + .../admin-console/subscription/quota-item.ts | 12 + .../admin-console/subscription/quota-table.ts | 4 +- .../translation/admin-console/tenants.ts | 11 + .../admin-console/upsell/add-on.ts | 24 + .../admin-console/upsell/paywall.ts | 6 +- .../translation/admin-console/user-details.ts | 6 + .../src/locales/tr-tr/translation/demo-app.ts | 1 + .../src/locales/zh-cn/errors/session.ts | 29 +- .../admin-console/application-details.ts | 25 +- .../zh-cn/translation/admin-console/cloud.ts | 6 + .../translation/admin-console/components.ts | 2 +- .../admin-console/connector-details.ts | 15 +- .../translation/admin-console/connectors.ts | 10 +- .../translation/admin-console/jwt-claims.ts | 6 +- .../admin-console/organization-details.ts | 47 +- .../admin-console/organization-template.ts | 5 +- .../admin-console/organizations.ts | 23 +- .../translation/admin-console/profile.ts | 27 + .../zh-cn/translation/admin-console/roles.ts | 10 +- .../admin-console/sign-in-exp/index.ts | 60 +- .../sign-in-exp/sign-up-and-sign-in.ts | 5 +- .../admin-console/subscription/quota-item.ts | 12 + .../admin-console/subscription/quota-table.ts | 24 +- .../translation/admin-console/tenants.ts | 9 + .../admin-console/upsell/add-on.ts | 24 + .../admin-console/upsell/paywall.ts | 1 + .../translation/admin-console/user-details.ts | 17 +- .../src/locales/zh-cn/translation/demo-app.ts | 1 + .../src/locales/zh-hk/errors/session.ts | 2 + .../admin-console/application-details.ts | 24 +- .../zh-hk/translation/admin-console/cloud.ts | 6 + .../translation/admin-console/components.ts | 2 +- .../admin-console/connector-details.ts | 15 +- .../translation/admin-console/connectors.ts | 10 +- .../translation/admin-console/jwt-claims.ts | 12 +- .../admin-console/organization-details.ts | 47 +- .../admin-console/organization-template.ts | 5 +- .../admin-console/organizations.ts | 5 +- .../translation/admin-console/profile.ts | 27 + .../zh-hk/translation/admin-console/roles.ts | 10 +- .../admin-console/sign-in-exp/index.ts | 68 +- .../sign-in-exp/sign-up-and-sign-in.ts | 5 +- .../admin-console/subscription/quota-item.ts | 12 + .../admin-console/subscription/quota-table.ts | 4 +- .../translation/admin-console/tenants.ts | 39 +- .../admin-console/upsell/add-on.ts | 24 + .../admin-console/upsell/paywall.ts | 37 +- .../translation/admin-console/user-details.ts | 13 +- .../src/locales/zh-hk/translation/demo-app.ts | 1 + .../src/locales/zh-tw/errors/session.ts | 2 + .../admin-console/application-details.ts | 26 +- .../zh-tw/translation/admin-console/cloud.ts | 6 + .../translation/admin-console/components.ts | 2 +- .../admin-console/connector-details.ts | 15 +- .../translation/admin-console/connectors.ts | 10 +- .../translation/admin-console/jwt-claims.ts | 8 +- .../admin-console/organization-details.ts | 51 +- .../admin-console/organization-template.ts | 5 +- .../admin-console/organizations.ts | 61 +- .../translation/admin-console/profile.ts | 27 + .../zh-tw/translation/admin-console/roles.ts | 10 +- .../admin-console/sign-in-exp/index.ts | 60 +- .../sign-in-exp/sign-up-and-sign-in.ts | 3 + .../admin-console/subscription/quota-item.ts | 12 + .../admin-console/subscription/quota-table.ts | 20 +- .../translation/admin-console/tenants.ts | 9 + .../admin-console/upsell/add-on.ts | 24 + .../admin-console/upsell/paywall.ts | 37 +- .../translation/admin-console/user-details.ts | 11 +- .../src/locales/zh-tw/translation/demo-app.ts | 1 + packages/schemas/CHANGELOG.md | 78 + ....0-1720253939-add-organization-branding.ts | 18 + .../1.19.0-1720345784-add-color-to-app-sie.ts | 18 + ...19.0-1720505152-update-custom-ui-assets.ts | 20 + .../1.19.0-1721483240-multiple-app-secrets.ts | 77 + ...5392-add-application-custom-data-column.ts | 18 + .../1.19.0-1722926389-argon2d-argon2id.ts | 35 + packages/schemas/package.json | 14 +- packages/schemas/src/consts/oidc.ts | 16 +- packages/schemas/src/consts/system.ts | 3 + .../jsonb-types/sign-in-experience.ts | 31 +- packages/schemas/src/seeds/application.ts | 1 + .../schemas/src/seeds/sign-in-experience.ts | 4 +- packages/schemas/src/types/cookie.ts | 11 +- packages/schemas/src/types/index.ts | 1 + packages/schemas/src/types/interactions.ts | 114 +- packages/schemas/src/types/log/interaction.ts | 9 +- .../src/types/logto-config/jwt-customizer.ts | 15 +- .../schemas/src/types/sign-in-experience.ts | 2 +- packages/schemas/src/types/ssr.ts | 28 + packages/schemas/src/types/system.ts | 6 + packages/schemas/src/types/user-assets.ts | 27 +- packages/schemas/src/utils/application.ts | 9 + packages/schemas/src/utils/index.ts | 1 + .../schemas/tables/application_secrets.sql | 17 + .../application_sign_in_experiences.sql | 2 +- packages/schemas/tables/applications.sql | 9 +- packages/schemas/tables/organizations.sql | 2 + .../schemas/tables/sign_in_experiences.sql | 2 +- packages/schemas/tables/users.sql | 2 +- .../schemas/tsconfig.build.alterations.json | 5 +- packages/schemas/tsconfig.build.gen.json | 7 +- packages/shared/package.json | 8 +- packages/toolkit/connector-kit/package.json | 8 +- .../toolkit/core-kit/declaration/index.ts | 1 - .../core-kit/declaration/react-app.d.ts | 65 - packages/toolkit/core-kit/package.json | 10 +- packages/toolkit/language-kit/package.json | 8 +- pnpm-lock.yaml | 8425 ++++++++--------- tsup.shared.config.ts | 10 + vite.shared.config.ts | 52 + 1658 files changed, 36852 insertions(+), 10874 deletions(-) delete mode 100644 .npmrc create mode 100644 AWESOME.md create mode 100644 packages/cli/src/commands/proxy/index.ts create mode 100644 packages/cli/src/commands/proxy/types.ts create mode 100644 packages/cli/src/commands/proxy/utils.ts create mode 100644 packages/connectors/connector-postmark/CHANGELOG.md create mode 100644 packages/connectors/connector-postmark/README.md create mode 100644 packages/connectors/connector-postmark/logo.svg create mode 100644 packages/connectors/connector-postmark/package.json create mode 100644 packages/connectors/connector-postmark/src/constant.ts create mode 100644 packages/connectors/connector-postmark/src/index.test.ts create mode 100644 packages/connectors/connector-postmark/src/index.ts create mode 100644 packages/connectors/connector-postmark/src/mock.ts create mode 100644 packages/connectors/connector-postmark/src/types.ts delete mode 100644 packages/connectors/templates/preset/tsconfig.base.json delete mode 100644 packages/connectors/templates/preset/tsconfig.build.json delete mode 100644 packages/connectors/templates/preset/tsconfig.test.json create mode 100644 packages/connectors/templates/preset/tsup.config.ts rename packages/console/{src => }/index.html (51%) create mode 100644 packages/console/src/assets/docs/guides/api-express/logo-dark.svg create mode 100644 packages/console/src/assets/docs/guides/m2m-general/logo-dark.svg create mode 100644 packages/console/src/assets/docs/guides/native-expo/logo-dark.svg create mode 100644 packages/console/src/assets/docs/guides/web-express/logo-dark.svg create mode 100644 packages/console/src/assets/docs/guides/web-next-app-router/logo-dark.svg create mode 100644 packages/console/src/assets/docs/guides/web-next/logo-dark.svg create mode 100644 packages/console/src/assets/docs/guides/web-outline/logo-dark.svg create mode 100644 packages/console/src/assets/docs/guides/web-passport/README.mdx create mode 100644 packages/console/src/assets/docs/guides/web-passport/config.json create mode 100644 packages/console/src/assets/docs/guides/web-passport/index.ts create mode 100644 packages/console/src/assets/docs/guides/web-passport/logo-dark.svg create mode 100644 packages/console/src/assets/docs/guides/web-passport/logo.svg create mode 100644 packages/console/src/assets/docs/guides/web-ruby/logo.svg create mode 100644 packages/console/src/assets/icons/calendar-dark.svg create mode 100644 packages/console/src/assets/images/blur-preview.svg create mode 100644 packages/console/src/components/AddOnNoticeFooter/index.module.scss create mode 100644 packages/console/src/components/AddOnNoticeFooter/index.tsx create mode 100644 packages/console/src/components/ApplicationCreation/CreateForm/Footer/index.module.scss create mode 100644 packages/console/src/components/CreateTenantModal/SelectTenantPlanModal/SkuCardItem/FeaturedSkuContent/index.tsx create mode 100644 packages/console/src/components/CreateTenantModal/SelectTenantPlanModal/SkuCardItem/FeaturedSkuContent/use-featured-sku-content.ts create mode 100644 packages/console/src/components/CreateTenantModal/SelectTenantPlanModal/SkuCardItem/index.tsx create mode 100644 packages/console/src/components/FeatureTag/AddOnTag.tsx create mode 100644 packages/console/src/components/FileIcon/index.tsx create mode 100644 packages/console/src/components/ImageInputs/LogoAndFavicon.tsx rename packages/console/src/{pages/SignInExperience/PageContent/Branding/BrandingForm/LogoAndFaviconUploader => components/ImageInputs}/index.module.scss (69%) create mode 100644 packages/console/src/components/ImageInputs/index.tsx create mode 100644 packages/console/src/components/PlanUsage/ProPlanUsageCard/index.module.scss create mode 100644 packages/console/src/components/PlanUsage/ProPlanUsageCard/index.tsx create mode 100644 packages/console/src/components/PlanUsage/utils.ts delete mode 100644 packages/console/src/consts/user-assets.ts create mode 100644 packages/console/src/containers/ConsoleRoutes/internal.ts create mode 100644 packages/console/src/contexts/SubscriptionDataProvider/use-new-subscription-data.ts create mode 100644 packages/console/src/ds-components/FormField/Skeleton.module.scss create mode 100644 packages/console/src/ds-components/FormField/Skeleton.tsx create mode 100644 packages/console/src/hooks/use-logto-skus.ts create mode 100644 packages/console/src/hooks/use-new-subscription-quota.ts create mode 100644 packages/console/src/hooks/use-new-subscription-scopes-usage.ts create mode 100644 packages/console/src/hooks/use-new-subscription-usage.ts delete mode 100644 packages/console/src/include.d/react-app.d.ts create mode 100644 packages/console/src/include.d/vite-env.d.ts create mode 100644 packages/console/src/pages/ApiResources/components/CreateForm/index.module.scss delete mode 100644 packages/console/src/pages/ApplicationDetails/ApplicationDetailsContent/Branding/LogoUploader.module.scss create mode 100644 packages/console/src/pages/ApplicationDetails/ApplicationDetailsContent/Branding/NonThirdPartyBrandingForm.tsx create mode 100644 packages/console/src/pages/ApplicationDetails/ApplicationDetailsContent/Branding/index.module.scss create mode 100644 packages/console/src/pages/ApplicationDetails/ApplicationDetailsContent/CreateSecretModal.tsx create mode 100644 packages/console/src/pages/ApplicationDetails/ApplicationDetailsContent/EditSecretModal.tsx create mode 100644 packages/console/src/pages/ApplicationDetails/ApplicationDetailsContent/EndpointsAndCredentials/index.module.scss create mode 100644 packages/console/src/pages/ApplicationDetails/ApplicationDetailsContent/EndpointsAndCredentials/index.tsx create mode 100644 packages/console/src/pages/ApplicationDetails/ApplicationDetailsContent/EndpointsAndCredentials/use-secret-table-columns.tsx create mode 100644 packages/console/src/pages/CustomizeJwt/UpsellNotice/index.module.scss create mode 100644 packages/console/src/pages/CustomizeJwt/UpsellNotice/index.tsx create mode 100644 packages/console/src/pages/Mfa/MfaForm/UpsellNotice/index.tsx create mode 100644 packages/console/src/pages/Organizations/CreateOrganizationModal/index.module.scss delete mode 100644 packages/console/src/pages/SignInExperience/PageContent/Branding/BrandingForm/LogoAndFaviconUploader/index.tsx delete mode 100644 packages/console/src/pages/SignInExperience/PageContent/Branding/CustomCssForm/index.tsx rename packages/console/src/pages/SignInExperience/PageContent/Branding/{CustomCssForm => CustomUiForm}/index.module.scss (63%) create mode 100644 packages/console/src/pages/SignInExperience/PageContent/Branding/CustomUiForm/index.tsx create mode 100644 packages/console/src/pages/SignInExperience/components/CustomUiAssetsUploader/index.module.scss create mode 100644 packages/console/src/pages/SignInExperience/components/CustomUiAssetsUploader/index.tsx create mode 100644 packages/console/src/pages/SignInExperience/contexts/SignInExperienceContextProvider/index.tsx create mode 100644 packages/console/src/pages/TenantSettings/Subscription/DowngradeConfirmModalContent/PlanQuotaDiffCard/PlanQuotaList/DiffQuotaItem/SkuQuotaItemPhrase.tsx create mode 100644 packages/console/src/types/sign-in-experience.ts create mode 100644 packages/console/src/types/skus.ts create mode 100644 packages/console/src/utils/object.ts delete mode 100644 packages/console/svgo.config.json create mode 100644 packages/console/vite.config.ts create mode 100644 packages/core/src/middleware/koa-app-secret-transpilation.test.ts create mode 100644 packages/core/src/middleware/koa-app-secret-transpilation.ts create mode 100644 packages/core/src/middleware/koa-experience-ssr.test.ts create mode 100644 packages/core/src/middleware/koa-experience-ssr.ts rename packages/core/src/{routes/interaction => }/middleware/koa-interaction-details.ts (100%) create mode 100644 packages/core/src/middleware/koa-serve-custom-ui-assets.test.ts create mode 100644 packages/core/src/middleware/koa-serve-custom-ui-assets.ts create mode 100644 packages/core/src/oidc/grants/token-exchange/actor-token.test.ts create mode 100644 packages/core/src/oidc/grants/token-exchange/actor-token.ts create mode 100644 packages/core/src/oidc/grants/token-exchange/index.test.ts create mode 100644 packages/core/src/oidc/grants/token-exchange/index.ts create mode 100644 packages/core/src/oidc/grants/token-exchange/types.ts create mode 100644 packages/core/src/oidc/grants/utils.ts create mode 100644 packages/core/src/queries/application-secrets.ts create mode 100644 packages/core/src/routes/applications/application-custom-data.openapi.json create mode 100644 packages/core/src/routes/applications/application-custom-data.ts create mode 100644 packages/core/src/routes/applications/application-secret.openapi.json create mode 100644 packages/core/src/routes/applications/application-secret.ts create mode 100644 packages/core/src/routes/experience/classes/experience-interaction.test.ts create mode 100644 packages/core/src/routes/experience/classes/helpers.ts create mode 100644 packages/core/src/routes/experience/classes/libraries/mfa-validator.ts create mode 100644 packages/core/src/routes/experience/classes/libraries/password-validator.ts create mode 100644 packages/core/src/routes/experience/classes/libraries/profile-validator.ts create mode 100644 packages/core/src/routes/experience/classes/libraries/provision-library.ts create mode 100644 packages/core/src/routes/experience/classes/libraries/sentinel-guard.ts create mode 100644 packages/core/src/routes/experience/classes/libraries/sign-in-experience-validator.test.ts create mode 100644 packages/core/src/routes/experience/classes/libraries/sign-in-experience-validator.ts create mode 100644 packages/core/src/routes/experience/classes/mfa.ts create mode 100644 packages/core/src/routes/experience/classes/profile.ts create mode 100644 packages/core/src/routes/experience/classes/utils.test.ts create mode 100644 packages/core/src/routes/experience/classes/utils.ts create mode 100644 packages/core/src/routes/experience/classes/verifications/backup-code-verification.ts create mode 100644 packages/core/src/routes/experience/classes/verifications/enterprise-sso-verification.ts create mode 100644 packages/core/src/routes/experience/classes/verifications/new-password-identity-verification.ts create mode 100644 packages/core/src/routes/experience/classes/verifications/totp-verification.ts create mode 100644 packages/core/src/routes/experience/classes/verifications/verification-records-map.ts create mode 100644 packages/core/src/routes/experience/classes/verifications/web-authn-verification.ts create mode 100644 packages/core/src/routes/experience/middleware/koa-experience-interaction-hooks.ts create mode 100644 packages/core/src/routes/experience/middleware/koa-experience-verifications-audit-log.ts create mode 100644 packages/core/src/routes/experience/profile-routes.ts create mode 100644 packages/core/src/routes/experience/verification-routes/backup-code-verification.ts create mode 100644 packages/core/src/routes/experience/verification-routes/enterprise-sso-verification.ts create mode 100644 packages/core/src/routes/experience/verification-routes/new-password-identity-verification.ts create mode 100644 packages/core/src/routes/experience/verification-routes/totp-verification.ts create mode 100644 packages/core/src/routes/experience/verification-routes/web-authn-verification.ts create mode 100644 packages/core/src/routes/sign-in-experience/custom-ui-assets/index.openapi.json create mode 100644 packages/core/src/routes/sign-in-experience/custom-ui-assets/index.test.ts create mode 100644 packages/core/src/routes/sign-in-experience/custom-ui-assets/index.ts create mode 100644 packages/core/src/routes/subject-token.openapi.json create mode 100644 packages/core/src/routes/subject-token.ts create mode 100644 packages/core/src/utils/file.test.ts create mode 100644 packages/core/src/utils/file.ts delete mode 100644 packages/core/src/utils/storage/consts.ts delete mode 100644 packages/core/tsconfig.base.json delete mode 100644 packages/core/tsconfig.build.json create mode 100644 packages/core/tsup.config.ts create mode 100644 packages/core/tsup.dev.config.ts delete mode 100644 packages/demo-app/.parcelrc.arm64 rename packages/demo-app/{src => }/index.html (55%) create mode 100644 packages/demo-app/src/include.d/vite-end.d.ts create mode 100644 packages/demo-app/vite.config.ts create mode 100644 packages/elements/.gitignore create mode 100644 packages/elements/README.md create mode 100644 packages/elements/index.html create mode 100644 packages/elements/lit-localize.json create mode 100644 packages/elements/package.json create mode 100644 packages/elements/src/components/logto-avatar.ts create mode 100644 packages/elements/src/components/logto-button.styles.ts create mode 100644 packages/elements/src/components/logto-button.ts create mode 100644 packages/elements/src/components/logto-card-section.ts create mode 100644 packages/elements/src/components/logto-card.ts create mode 100644 packages/elements/src/components/logto-form-card.ts create mode 100644 packages/elements/src/components/logto-icon-button.ts create mode 100644 packages/elements/src/components/logto-list-row.ts create mode 100644 packages/elements/src/components/logto-list.ts create mode 100644 packages/elements/src/components/logto-modal-layout.ts create mode 100644 packages/elements/src/components/logto-modal.context.ts create mode 100644 packages/elements/src/components/logto-modal.ts create mode 100644 packages/elements/src/components/logto-text-input.ts create mode 100644 packages/elements/src/elements/logto-profile-card.ts create mode 100644 packages/elements/src/icons/close.svg create mode 100644 packages/elements/src/icons/index.d.ts create mode 100644 packages/elements/src/index.ts create mode 100644 packages/elements/src/phrases/index.ts create mode 100644 packages/elements/src/providers/logto-theme-provider.ts create mode 100644 packages/elements/src/providers/logto-user-provider.ts create mode 100644 packages/elements/src/react.ts create mode 100644 packages/elements/src/utils/api.ts create mode 100644 packages/elements/src/utils/css.ts create mode 100644 packages/elements/src/utils/locale.ts create mode 100644 packages/elements/src/utils/string.ts create mode 100644 packages/elements/src/utils/theme.ts create mode 100644 packages/elements/tsconfig.json create mode 100644 packages/elements/tsup.config.ts create mode 100644 packages/elements/web-dev-server.config.js create mode 100644 packages/elements/xliff/de.xlf create mode 100644 packages/elements/xliff/es.xlf create mode 100644 packages/elements/xliff/fr.xlf create mode 100644 packages/elements/xliff/it.xlf create mode 100644 packages/elements/xliff/ja.xlf create mode 100644 packages/elements/xliff/ko.xlf create mode 100644 packages/elements/xliff/pl-PL.xlf create mode 100644 packages/elements/xliff/pt-BR.xlf create mode 100644 packages/elements/xliff/pt-PT.xlf create mode 100644 packages/elements/xliff/ru.xlf create mode 100644 packages/elements/xliff/tr-TR.xlf create mode 100644 packages/elements/xliff/zh-CN.xlf create mode 100644 packages/elements/xliff/zh-HK.xlf create mode 100644 packages/elements/xliff/zh-TW.xlf create mode 100644 packages/experience/.eslintrc.cjs delete mode 100644 packages/experience/.parcelrc delete mode 100644 packages/experience/.parcelrc.arm64 create mode 100644 packages/experience/index.html create mode 100644 packages/experience/src/assets/icons/loading-ring.svg create mode 100644 packages/experience/src/components/Button/RotatingRingIcon.module.scss create mode 100644 packages/experience/src/components/Button/RotatingRingIcon.tsx create mode 100644 packages/experience/src/components/InputFields/InputField/NotchedBorder/index.module.scss create mode 100644 packages/experience/src/components/InputFields/InputField/NotchedBorder/index.tsx create mode 100644 packages/experience/src/components/LoadingMask/index.module.scss create mode 100644 packages/experience/src/components/LoadingMask/index.tsx create mode 100644 packages/experience/src/containers/SetPassword/HiddenIdentifierInput.tsx delete mode 100644 packages/experience/src/include.d/react-app.d.ts create mode 100644 packages/experience/src/include.d/vite-env.d.ts delete mode 100644 packages/experience/src/index.html create mode 100644 packages/experience/vite.config.ts create mode 100644 packages/integration-tests/src/helpers/experience/enterprise-sso-verification.ts create mode 100644 packages/integration-tests/src/helpers/experience/totp-verification.ts create mode 100644 packages/integration-tests/src/include.d/global.d.ts create mode 100644 packages/integration-tests/src/tests/api/application/application-custom-data.test.ts create mode 100644 packages/integration-tests/src/tests/api/application/application.secrets.test.ts create mode 100644 packages/integration-tests/src/tests/api/experience-api/bind-mfa/happpy-path.test.ts create mode 100644 packages/integration-tests/src/tests/api/experience-api/bind-mfa/sad-path.test.ts create mode 100644 packages/integration-tests/src/tests/api/experience-api/interaction.test.ts create mode 100644 packages/integration-tests/src/tests/api/experience-api/profile/fulfill-user-profiles.test.ts create mode 100644 packages/integration-tests/src/tests/api/experience-api/profile/reset-password.test.ts create mode 100644 packages/integration-tests/src/tests/api/experience-api/register-interaction/organization-jti.test.ts create mode 100644 packages/integration-tests/src/tests/api/experience-api/register-interaction/username-password.test.ts create mode 100644 packages/integration-tests/src/tests/api/experience-api/register-interaction/verification-code.test.ts create mode 100644 packages/integration-tests/src/tests/api/experience-api/sign-in-interaction/enterprise-sso.test.ts create mode 100644 packages/integration-tests/src/tests/api/experience-api/sign-in-interaction/mfa-verification.test.ts create mode 100644 packages/integration-tests/src/tests/api/experience-api/sign-in-interaction/social.test.ts create mode 100644 packages/integration-tests/src/tests/api/experience-api/verifications/backup-code-verification.test.ts create mode 100644 packages/integration-tests/src/tests/api/experience-api/verifications/enterprise-sso-verification.test.ts create mode 100644 packages/integration-tests/src/tests/api/experience-api/verifications/new-password-identity-verification.test.ts create mode 100644 packages/integration-tests/src/tests/api/experience-api/verifications/totp-verification.test.ts create mode 100644 packages/integration-tests/src/tests/api/hook/hook.trigger.experience.test.ts create mode 100644 packages/integration-tests/src/tests/api/oidc/client-authentication.test.ts create mode 100644 packages/integration-tests/src/tests/console/error-handling.test.ts create mode 100644 packages/integration-tests/src/tests/experience/overrides.test.ts create mode 100644 packages/integration-tests/src/tests/experience/server-side-rendering.test.ts create mode 100644 packages/integration-tests/src/ui-helpers/trace.ts create mode 100644 packages/integration-tests/tsup.config.ts create mode 100644 packages/phrases/src/locales/de/translation/admin-console/upsell/add-on.ts create mode 100644 packages/phrases/src/locales/en/translation/admin-console/subscription/usage.ts create mode 100644 packages/phrases/src/locales/en/translation/admin-console/upsell/add-on.ts create mode 100644 packages/phrases/src/locales/es/translation/admin-console/upsell/add-on.ts create mode 100644 packages/phrases/src/locales/fr/translation/admin-console/upsell/add-on.ts create mode 100644 packages/phrases/src/locales/it/translation/admin-console/upsell/add-on.ts create mode 100644 packages/phrases/src/locales/ja/translation/admin-console/upsell/add-on.ts create mode 100644 packages/phrases/src/locales/ko/translation/admin-console/upsell/add-on.ts create mode 100644 packages/phrases/src/locales/pl-pl/translation/admin-console/upsell/add-on.ts create mode 100644 packages/phrases/src/locales/pt-br/translation/admin-console/upsell/add-on.ts create mode 100644 packages/phrases/src/locales/pt-pt/translation/admin-console/upsell/add-on.ts create mode 100644 packages/phrases/src/locales/ru/translation/admin-console/upsell/add-on.ts create mode 100644 packages/phrases/src/locales/tr-tr/translation/admin-console/upsell/add-on.ts create mode 100644 packages/phrases/src/locales/zh-cn/translation/admin-console/upsell/add-on.ts create mode 100644 packages/phrases/src/locales/zh-hk/translation/admin-console/upsell/add-on.ts create mode 100644 packages/phrases/src/locales/zh-tw/translation/admin-console/upsell/add-on.ts create mode 100644 packages/schemas/alterations/1.19.0-1720253939-add-organization-branding.ts create mode 100644 packages/schemas/alterations/1.19.0-1720345784-add-color-to-app-sie.ts create mode 100644 packages/schemas/alterations/1.19.0-1720505152-update-custom-ui-assets.ts create mode 100644 packages/schemas/alterations/1.19.0-1721483240-multiple-app-secrets.ts create mode 100644 packages/schemas/alterations/1.19.0-1721645392-add-application-custom-data-column.ts create mode 100644 packages/schemas/alterations/1.19.0-1722926389-argon2d-argon2id.ts create mode 100644 packages/schemas/src/types/ssr.ts create mode 100644 packages/schemas/src/utils/application.ts create mode 100644 packages/schemas/tables/application_secrets.sql delete mode 100644 packages/toolkit/core-kit/declaration/react-app.d.ts create mode 100644 tsup.shared.config.ts create mode 100644 vite.shared.config.ts diff --git a/.dockerignore b/.dockerignore index c741e7761be..e9715be261a 100644 --- a/.dockerignore +++ b/.dockerignore @@ -33,5 +33,4 @@ dump.rdb .devcontainer .github .husky -.parcel-cache .vscode diff --git a/.github/workflows/alteration-compatibility-integration-test.yml b/.github/workflows/alteration-compatibility-integration-test.yml index 4e82e5485c7..27d1454786c 100644 --- a/.github/workflows/alteration-compatibility-integration-test.yml +++ b/.github/workflows/alteration-compatibility-integration-test.yml @@ -91,3 +91,11 @@ jobs: GH_TOKEN: ${{ github.token }} GH_DEBUG: api run: gh workflow run rerun.yml -F run_id=${{ github.run_id }} + + alteration-compatibility-conclusion: + needs: run-logto + runs-on: ubuntu-latest + if: always() && (needs.run-logto.result == 'success' || needs.run-logto.result == 'skipped') + steps: + - name: Conclusion + run: echo "Alteration compatibility integration test completed successfully" diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index b525dd8d6f1..30cef1377c1 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -20,12 +20,25 @@ jobs: - name: Setup Node and pnpm uses: silverhand-io/actions-node-pnpm-run-steps@v5 - with: - pnpm-version: 9 - name: Build run: pnpm ci:build + main-check: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - name: Setup Node and pnpm + uses: silverhand-io/actions-node-pnpm-run-steps@v5 + + - name: Prepack + run: pnpm prepack + + - name: Check + run: pnpm -r check + main-lint: runs-on: ubuntu-latest @@ -34,8 +47,6 @@ jobs: - name: Setup Node and pnpm uses: silverhand-io/actions-node-pnpm-run-steps@v5 - with: - pnpm-version: 9 - name: Prepack run: pnpm prepack @@ -54,8 +65,6 @@ jobs: - name: Setup Node and pnpm uses: silverhand-io/actions-node-pnpm-run-steps@v5 - with: - pnpm-version: 9 - name: Build for test run: pnpm -r build:test diff --git a/.npmrc b/.npmrc deleted file mode 100644 index 573e44e096e..00000000000 --- a/.npmrc +++ /dev/null @@ -1,6 +0,0 @@ -# Hoist for Parcel -public-hoist-pattern[]=@parcel/* -public-hoist-pattern[]=postcss -public-hoist-pattern[]=process -public-hoist-pattern[]=*eslint* -public-hoist-pattern[]=buffer diff --git a/.scripts/compare-database.js b/.scripts/compare-database.js index b959db38533..f7afeaab692 100644 --- a/.scripts/compare-database.js +++ b/.scripts/compare-database.js @@ -42,14 +42,14 @@ const queryDatabaseManifest = async (database) => { `); const { rows: constraints } = await pool.query(/* sql */` - select conrelid::regclass AS table, con.*, pg_get_constraintdef(con.oid) + select conrelid::regclass as r_table, con.*, pg_get_constraintdef(con.oid) as def from pg_catalog.pg_constraint con inner join pg_catalog.pg_class rel on rel.oid = con.conrelid inner join pg_catalog.pg_namespace nsp on nsp.oid = connamespace where nsp.nspname = 'public' - order by conname asc; + order by conname asc, def asc; `); const { rows: indexes } = await pool.query(/* sql */` diff --git a/.scripts/package.sh b/.scripts/package.sh index c7654930ab8..7e2720b1840 100755 --- a/.scripts/package.sh +++ b/.scripts/package.sh @@ -18,7 +18,7 @@ fi # Some node packages use `src` as their dist folder, so ignore them from the rm list in the end find \ -.git .changeset .devcontainer .github .husky .parcel-cache .scripts .vscode pnpm-*.yaml *.js \ +.git .changeset .devcontainer .github .husky .scripts .vscode pnpm-*.yaml *.js \ packages/**/src \ packages/**/*.config.js packages/**/*.config.ts packages/**/tsconfig*.json \ ! -path '**/node_modules/**' \ diff --git a/.vscode/settings.json b/.vscode/settings.json index 805805faacf..87d0de73eba 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -55,6 +55,7 @@ "topbar", "upsell", "withtyped", - "backchannel" + "backchannel", + "deepmerge" ] } diff --git a/.vscode/tsx.code-snippets b/.vscode/tsx.code-snippets index 2f1caf11c1b..be2b52bab50 100644 --- a/.vscode/tsx.code-snippets +++ b/.vscode/tsx.code-snippets @@ -10,7 +10,7 @@ "scope": "javascriptreact,typescriptreact", "prefix": "isc", "body": [ - "import * as styles from './index.module.scss';", + "import styles from './index.module.scss';", "$0" ], "description": "Import SCSS styles from the same directory." diff --git a/AWESOME.md b/AWESOME.md new file mode 100644 index 00000000000..5b4a0dfb104 --- /dev/null +++ b/AWESOME.md @@ -0,0 +1,11 @@ +# Logto awesome + +Here's the list of awesome community-contributed resources for Logto. Feel free to add yours by submitting a pull request. + +## Account + +- [Logto Account Dashboard](https://github.com/t2vee/Logto-Account-Dashboard) by @t2vee + +## API + +- [Go API client for logto](https://github.com/mostafa/go-api-client) by @mostafa diff --git a/Dockerfile b/Dockerfile index 1be470e7711..3f189eea736 100644 --- a/Dockerfile +++ b/Dockerfile @@ -18,7 +18,6 @@ RUN apk add --no-cache python3 make g++ rsync COPY . . ### Install dependencies and build ### -RUN node .scripts/update-parcelrc.js RUN pnpm i ### Set if dev features enabled ### @@ -39,7 +38,7 @@ RUN rm -rf node_modules packages/**/node_modules RUN NODE_ENV=production pnpm i ### Clean up ### -RUN rm -rf .scripts .parcel-cache pnpm-*.yaml packages/cloud +RUN rm -rf .scripts pnpm-*.yaml packages/cloud ###### [STAGE] Seal ###### FROM node:20-alpine as app diff --git a/README.md b/README.md index 35d06147178..889aa2d71a3 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,7 @@ Logto[^info] is an Auth0 alternative designed for modern apps and SaaS products. - Enables OIDC-based authentication with Logto SDKs. - Supports passwordless sign-in, along with various options like email, phone number, username, Google, Facebook, and other social sign-in methods. - Offers beautiful UI components with customizable CSS to suit your business needs. +- Has an open community with many warm-hearted contributors and users. Check out our [awesome list](./AWESOME.md) of community-contributed resources. 📦 **Out-of-the-box infrastructure** @@ -37,12 +38,12 @@ Logto[^info] is an Auth0 alternative designed for modern apps and SaaS products. - Implements role-based access control (RBAC) for scalable role authorization, catering to a wide range of use cases. - Facilitates user management and provides audit logs for understanding identity-related user information and maintaining security. - Enables single sign-on (SSO) and multi-factor authentication (MFA) without extra coding. -- Leverages Logto Organizations to build multi-tenancy apps with ease. +- Leverages Logto organizations to build multi-tenancy apps with ease. In a more approachable way, we refer to this solution as "[Customer Identity Access Management (CIAM)](https://en.wikipedia.org/wiki/Customer_identity_access_management)" or simply, the "Customer Identity Solution." -[Subscribe to us](https://logto.io/subscribe/?utm_source=github&utm_medium=repo_logto) now to stay updated with the latest information about the Logto Cloud (SaaS) and receive feature updates in real-time. - +> [!IMPORTANT] +> [Subscribe to us](https://logto.io/subscribe/?utm_source=github&utm_medium=repo_logto) now to stay updated with the latest information about the Logto Cloud (SaaS) and receive feature updates in real-time. ## Get started diff --git a/commitlint.config.ts b/commitlint.config.ts index 5f44c75e5e8..c89743462dc 100644 --- a/commitlint.config.ts +++ b/commitlint.config.ts @@ -7,7 +7,7 @@ const config: UserConfig = { extends: ['@commitlint/config-conventional'], rules: { 'type-enum': [2, 'always', [...conventional.rules['type-enum'][2], 'api', 'release']], - 'scope-enum': [2, 'always', ['connector', 'console', 'core', 'demo-app', 'test', 'phrases', 'schemas', 'shared', 'experience', 'deps', 'deps-dev', 'cli', 'toolkit', 'cloud', 'app-insights']], + 'scope-enum': [2, 'always', ['connector', 'console', 'core', 'demo-app', 'test', 'phrases', 'schemas', 'shared', 'experience', 'deps', 'deps-dev', 'cli', 'toolkit', 'cloud', 'app-insights', 'elements']], // Slightly increase the tolerance to allow the appending PR number ...(isCi && { 'header-max-length': [2, 'always', 110] }), 'body-max-line-length': [2, 'always', 110], diff --git a/mygovid-mock-service/src/routes/static/mock-login.html b/mygovid-mock-service/src/routes/static/mock-login.html index e38fbbc5f5e..5f6d87790c9 100644 --- a/mygovid-mock-service/src/routes/static/mock-login.html +++ b/mygovid-mock-service/src/routes/static/mock-login.html @@ -236,6 +236,13 @@ sub: "7ffe40ff7d558de01c67", is_public_servant: true, }, + { + user_name: "Flesh Gordon", + govid_email: "flesh.gordon@gov.ie", + oid: "2gh4zec9143tyc4222u8", + sub: "5yz32gff7d558de0175h", + is_public_servant: true, + }, ] } diff --git a/package.json b/package.json index 28ff7ea7f52..527d8d94110 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,9 @@ "@types/pg": "^8.6.6", "husky": "^9.0.0", "pg": "^8.8.0", - "typescript": "^5.0.0" + "tsup": "^8.1.0", + "typescript": "^5.0.0", + "vite": "^5.3.4" }, "engines": { "node": "^20.9.0", @@ -52,9 +54,5 @@ }, "dependencies": { "@logto/cli": "workspace:^1.1.0" - }, - "//": "@see https://parceljs.org/features/dependency-resolution/#package-exports", - "@parcel/resolver-default": { - "packageExports": true } } diff --git a/packages/app-insights/package.json b/packages/app-insights/package.json index 8016dc02794..9591063d8af 100644 --- a/packages/app-insights/package.json +++ b/packages/app-insights/package.json @@ -32,12 +32,12 @@ "@silverhand/eslint-config": "6.0.1", "@silverhand/ts-config": "6.0.0", "@types/node": "^20.9.5", - "@vitest/coverage-v8": "^1.4.0", + "@vitest/coverage-v8": "^2.0.0", "eslint": "^8.56.0", "lint-staged": "^15.0.0", "prettier": "^3.0.0", - "typescript": "^5.3.3", - "vitest": "^1.4.0" + "typescript": "^5.5.3", + "vitest": "^2.0.0" }, "engines": { "node": "^20.9.0" diff --git a/packages/cli/CHANGELOG.md b/packages/cli/CHANGELOG.md index c0cf24da4bb..3dfb5f2e8fc 100644 --- a/packages/cli/CHANGELOG.md +++ b/packages/cli/CHANGELOG.md @@ -1,5 +1,53 @@ # Change Log +## 1.19.0 + +### Minor Changes + +- 2d0502a42: add new cli command to setup proxy for developing and debugging custom ui locally + + This command will establish a proxy tunnel between the following 3 entities together: your Logto cloud auth services, your application, and your custom sign-in UI. + + Assuming you have a custom sign-in page running on `http://localhost:4000`. + Then you can execute the command this way: + + ```bash + npm cli proxy --endpoint https://.logto.app --port 9000 --experience-uri http://localhost:4000 + ``` + + Or if you don't have your custom UI pages hosted on a dev server, you can use the `--experience-path` option to specify the path to your static files: + + ```bash + npm cli proxy --endpoint https://.logto.app --port 9000 --experience-path /path/to/your/custom/ui + ``` + + This command also works if you have enabled custom domain in your Logto tenant. E.g.: + + ```bash + npm cli proxy --endpoint https://your-custom-domain.com --port 9000 --experience-path /path/to/your/custom/ui + ``` + + This should set up the proxy and it will be running on your local machine at `http://localhost:9000/`. + + Finally, run your application and set its Logto endpoint to the proxy address `http://localhost:9000/` instead. + + If all set up correctly, when you click the "sign-in" button in your application, you should be navigated to your custom sign-in page instead of Logto's built-in UI, along with valid session (cookies) that allows you to further interact with Logto experience API. + + Happy coding! + +### Patch Changes + +- Updated dependencies [6477c6dee] +- Updated dependencies [3a839f6d6] +- Updated dependencies [b91ec0cd6] +- Updated dependencies [d203c8d2f] +- Updated dependencies [b188bb161] +- Updated dependencies [62f5e5e0c] +- Updated dependencies [d56bc2f73] +- Updated dependencies [510f681fa] + - @logto/schemas@1.19.0 + - @logto/phrases@1.13.0 + ## 1.18.0 ### Patch Changes diff --git a/packages/cli/package.json b/packages/cli/package.json index 21793fdb2e4..10c7ea85d7a 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,6 +1,6 @@ { "name": "@logto/cli", - "version": "1.18.0", + "version": "1.19.0", "description": "Logto CLI.", "author": "Silverhand Inc. ", "homepage": "https://github.com/logto-io/logto#readme", @@ -45,30 +45,32 @@ "@logto/connector-kit": "workspace:^4.0.0", "@logto/core-kit": "workspace:^2.5.0", "@logto/language-kit": "workspace:^1.1.0", - "@logto/phrases": "workspace:^1.12.0", + "@logto/phrases": "workspace:^1.13.0", "@logto/phrases-experience": "workspace:^1.7.0", - "@logto/schemas": "workspace:1.18.0", + "@logto/schemas": "workspace:1.19.0", "@logto/shared": "workspace:^3.1.1", "@silverhand/essentials": "^2.9.1", "@silverhand/slonik": "31.0.0-beta.2", - "chalk": "^5.0.0", + "chalk": "^5.3.0", "decamelize": "^6.0.0", - "dotenv": "^16.0.0", + "dotenv": "^16.4.5", "got": "^14.0.0", "hpagent": "^1.2.0", + "http-proxy-middleware": "^3.0.0", "inquirer": "^9.0.0", + "mime": "^4.0.4", "nanoid": "^5.0.1", "ora": "^8.0.1", - "p-limit": "^5.0.0", + "p-limit": "^6.0.0", "p-queue": "^8.0.0", "p-retry": "^6.0.0", "pg-protocol": "^1.6.0", "roarr": "^7.11.0", "semver": "^7.3.8", "tar": "^7.0.0", - "typescript": "^5.3.3", + "typescript": "^5.5.3", "yargs": "^17.6.0", - "zod": "^3.22.4" + "zod": "^3.23.8" }, "devDependencies": { "@silverhand/eslint-config": "6.0.1", @@ -79,13 +81,13 @@ "@types/sinon": "^17.0.0", "@types/tar": "^6.1.12", "@types/yargs": "^17.0.13", - "@vitest/coverage-v8": "^1.4.0", + "@vitest/coverage-v8": "^2.0.0", "@withtyped/server": "^0.13.6", "eslint": "^8.56.0", "lint-staged": "^15.0.0", "prettier": "^3.0.0", "sinon": "^18.0.0", - "vitest": "^1.4.0" + "vitest": "^2.0.0" }, "eslintConfig": { "extends": "@silverhand", diff --git a/packages/cli/src/commands/proxy/index.ts b/packages/cli/src/commands/proxy/index.ts new file mode 100644 index 00000000000..a12428b3ef3 --- /dev/null +++ b/packages/cli/src/commands/proxy/index.ts @@ -0,0 +1,106 @@ +import http from 'node:http'; + +import { isValidUrl } from '@logto/core-kit'; +import { conditional } from '@silverhand/essentials'; +import chalk from 'chalk'; +import type { CommandModule } from 'yargs'; + +import { consoleLog } from '../../utils.js'; + +import { type ProxyCommandArgs } from './types.js'; +import { + checkExperienceInput, + createLogtoResponseHandler, + createProxy, + createStaticFileProxy, + isLogtoRequestPath, +} from './utils.js'; + +const proxy: CommandModule = { + command: ['proxy'], + describe: 'Command for Logto proxy', + builder: (yargs) => + yargs + .options({ + 'experience-uri': { + alias: ['x'], + describe: 'The URI of your custom sign-in experience page.', + type: 'string', + }, + 'experience-path': { + alias: ['xp'], + describe: 'The local folder path of your custom sign-in experience assets.', + type: 'string', + }, + endpoint: { + alias: 'ep', + describe: + 'Logto endpoint URI, which can be found in Logto Console. E.g.: https://.logto.app/', + type: 'string', + }, + port: { + alias: 'p', + describe: 'The port number where the proxy server will be running on. Defaults to 9000.', + type: 'number', + default: 9000, + }, + verbose: { + alias: 'v', + describe: 'Show verbose output.', + type: 'boolean', + default: false, + }, + }) + .global('e'), + handler: async ({ 'experience-uri': url, 'experience-path': path, endpoint, port, verbose }) => { + checkExperienceInput(url, path); + + if (!endpoint || !isValidUrl(endpoint)) { + consoleLog.fatal('A valid Logto endpoint URI must be provided.'); + } + const logtoEndpointUrl = new URL(endpoint); + const proxyUrl = new URL(`http://localhost:${port}`); + + const proxyLogtoRequest = createProxy( + logtoEndpointUrl.href, + async (proxyResponse, request, response) => + createLogtoResponseHandler({ + proxyResponse, + request, + response, + logtoEndpointUrl, + proxyUrl, + verbose, + }) + ); + const proxyExperienceServerRequest = conditional(url && createProxy(url)); + const proxyExperienceStaticFileRequest = conditional(path && createStaticFileProxy(path)); + + const server = http.createServer((request, response) => { + if (verbose) { + consoleLog.info(`Incoming request: ${chalk.blue(request.method, request.url)}`); + } + + // Proxy the requests to Logto endpoint + if (isLogtoRequestPath(request.url)) { + void proxyLogtoRequest(request, response); + return; + } + + if (proxyExperienceServerRequest) { + void proxyExperienceServerRequest(request, response); + return; + } + + if (proxyExperienceStaticFileRequest) { + void proxyExperienceStaticFileRequest(request, response); + } + }); + + server.listen(port, () => { + consoleLog.info(`Proxy server is running on ${chalk.blue(proxyUrl.href)}`); + }); + }, +}; + +export default proxy; diff --git a/packages/cli/src/commands/proxy/types.ts b/packages/cli/src/commands/proxy/types.ts new file mode 100644 index 00000000000..af80b479254 --- /dev/null +++ b/packages/cli/src/commands/proxy/types.ts @@ -0,0 +1,18 @@ +import type * as http from 'node:http'; + +export type ProxyCommandArgs = { + 'experience-uri'?: string; + 'experience-path'?: string; + endpoint?: string; + port: number; + verbose: boolean; +}; + +export type ProxyResponseHandler = { + proxyResponse: http.IncomingMessage; + request: http.IncomingMessage; + response: http.ServerResponse; + logtoEndpointUrl: URL; + proxyUrl: URL; + verbose: boolean; +}; diff --git a/packages/cli/src/commands/proxy/utils.ts b/packages/cli/src/commands/proxy/utils.ts new file mode 100644 index 00000000000..28283be84c3 --- /dev/null +++ b/packages/cli/src/commands/proxy/utils.ts @@ -0,0 +1,157 @@ +import { existsSync } from 'node:fs'; +import fs from 'node:fs/promises'; +import type http from 'node:http'; +import path from 'node:path'; + +import { isValidUrl } from '@logto/core-kit'; +import { conditional, trySafe } from '@silverhand/essentials'; +import chalk from 'chalk'; +import { createProxyMiddleware, responseInterceptor } from 'http-proxy-middleware'; +import { type OnProxyEvent } from 'http-proxy-middleware/dist/types.js'; +import mime from 'mime'; + +import { consoleLog } from '../../utils.js'; + +import { type ProxyResponseHandler } from './types.js'; + +export const createProxy = (targetUrl: string, onProxyResponse?: OnProxyEvent['proxyRes']) => { + const hasResponseHandler = Boolean(onProxyResponse); + return createProxyMiddleware({ + target: targetUrl, + changeOrigin: true, + selfHandleResponse: hasResponseHandler, + ...conditional( + hasResponseHandler && { + on: { + proxyRes: onProxyResponse, + error: (error) => { + consoleLog.error(chalk.red(error)); + }, + }, + } + ), + }); +}; + +const index = 'index.html'; +const indexContentType = 'text/html; charset=utf-8'; +const noCache = 'no-cache, no-store, must-revalidate'; +const maxAgeSevenDays = 'max-age=604_800_000'; + +export const createStaticFileProxy = + (staticPath: string) => async (request: http.IncomingMessage, response: http.ServerResponse) => { + if (!request.url) { + response.writeHead(400).end(); + return; + } + + if (request.method === 'HEAD' || request.method === 'GET') { + const fallBackToIndex = !isFileAssetPath(request.url); + const requestPath = path.join(staticPath, fallBackToIndex ? index : request.url); + try { + const content = await fs.readFile(requestPath, 'utf8'); + response.setHeader('cache-control', fallBackToIndex ? noCache : maxAgeSevenDays); + response.setHeader('content-type', getMimeType(request.url)); + response.writeHead(200); + response.end(content); + } catch (error: unknown) { + consoleLog.error(chalk.red(error)); + response.setHeader('content-type', getMimeType(request.url)); + response.writeHead(existsSync(request.url) ? 500 : 404); + response.end(); + } + } + }; + +/** + * Intercept the response from Logto endpoint and replace Logto endpoint URLs in the response with the + * proxy URL. The string replace happens in the following cases: + * - The response is a redirect response, and the `location` property in response header may contain Logto + * endpoint URI. + * - The response body is JSON, which consists of properties such as `**_endpoint` and `redirectTo`. These + * properties may contain Logto endpoint URI. + * - The response is HTML content that contains a form. The form action URL may contain Logto endpoint URI. + * + * Note: the `issuer` and `jwks_uri` properties in the `/oidc/.well-known` response should not be replaced, + * even they also contain the Logto endpoint URI. + */ +export const createLogtoResponseHandler = async ({ + proxyResponse, + request, + response, + logtoEndpointUrl, + proxyUrl, + verbose, +}: ProxyResponseHandler) => { + const { location } = proxyResponse.headers; + if (location) { + // eslint-disable-next-line @silverhand/fp/no-mutation + proxyResponse.headers.location = location.replace(logtoEndpointUrl.href, proxyUrl.href); + } + + void responseInterceptor(async (responseBuffer, proxyResponse) => { + const responseBody = responseBuffer.toString(); + if (verbose) { + consoleLog.info(`Response received: ${chalk.green(responseBody)}`); + } + + if (proxyResponse.headers['content-type']?.includes('text/html')) { + return responseBody.replace(`action="${logtoEndpointUrl.href}`, `action="${proxyUrl.href}`); + } + + if (proxyResponse.headers['content-type']?.includes('application/json')) { + const jsonData = trySafe(() => JSON.parse(responseBody)); + + if (jsonData && typeof jsonData === 'object') { + const updatedEntries: Array<[string, unknown]> = Object.entries(jsonData).map( + ([key, value]) => { + if ((key === 'redirectTo' || key.endsWith('_endpoint')) && typeof value === 'string') { + return [key, value.replace(logtoEndpointUrl.href, proxyUrl.href)]; + } + return [key, value]; + } + ); + + return JSON.stringify(Object.fromEntries(updatedEntries)); + } + } + return responseBody; + })(proxyResponse, request, response); +}; + +export const checkExperienceInput = (url?: string, staticPath?: string) => { + if (staticPath && url) { + consoleLog.fatal('Only one of the experience URI or path can be provided.'); + } + if (!staticPath && !url) { + consoleLog.fatal('Either a sign-in experience URI or local path must be provided.'); + } + if (url && !isValidUrl(url)) { + consoleLog.fatal( + 'A valid sign-in experience URI must be provided. E.g.: http://localhost:4000' + ); + } + if (staticPath && !existsSync(path.join(staticPath, index))) { + consoleLog.fatal('The provided path does not contain a valid index.html file.'); + } +}; + +/** + * Check if the request path is a Logto request path. + * @example isLogtoRequestPath('/oidc/.well-known/openid-configuration') // true + * @example isLogtoRequestPath('/oidc/auth') // true + * @example isLogtoRequestPath('/api/interaction/submit') // true + * @example isLogtoRequestPath('/consent') // true + */ +export const isLogtoRequestPath = (requestPath?: string) => + ['/oidc/', '/api/'].some((path) => requestPath?.startsWith(path)) || requestPath === '/consent'; + +const isFileAssetPath = (url: string) => url.split('/').at(-1)?.includes('.'); + +const getMimeType = (requestPath: string) => { + const fallBackToIndex = !isFileAssetPath(requestPath); + if (fallBackToIndex) { + return indexContentType; + } + return mime.getType(requestPath) ?? 'application/octet-stream'; +}; diff --git a/packages/cli/src/index.ts b/packages/cli/src/index.ts index 13de2f79785..7afd7c9ec79 100644 --- a/packages/cli/src/index.ts +++ b/packages/cli/src/index.ts @@ -6,6 +6,7 @@ import { hideBin } from 'yargs/helpers'; import connector from './commands/connector/index.js'; import database from './commands/database/index.js'; import install from './commands/install/index.js'; +import proxy from './commands/proxy/index.js'; import translate from './commands/translate/index.js'; import { packageJson } from './package-json.js'; import { cliConfig, ConfigKey, consoleLog } from './utils.js'; @@ -48,6 +49,7 @@ void yargs(hideBin(process.argv)) .command(database) .command(connector) .command(translate) + .command(proxy) .demandCommand(1) .showHelpOnFail(false, `Specify ${chalk.green('--help')} for available options`) .strict() diff --git a/packages/connectors/.gitignore b/packages/connectors/.gitignore index 65245801929..533db69aa78 100644 --- a/packages/connectors/.gitignore +++ b/packages/connectors/.gitignore @@ -1,7 +1,6 @@ # generated files /*/tsconfig.* -/*/rollup.config.* -/*/vitest.config.* +/*/*.config.* # keep templates !/templates/** diff --git a/packages/connectors/connector-alipay-native/CHANGELOG.md b/packages/connectors/connector-alipay-native/CHANGELOG.md index f1876d9f116..827cf921a07 100644 --- a/packages/connectors/connector-alipay-native/CHANGELOG.md +++ b/packages/connectors/connector-alipay-native/CHANGELOG.md @@ -1,5 +1,15 @@ # @logto/connector-alipay-native +## 1.3.0 + +### Minor Changes + +- 510f681fa: use tsup for building + + We've updated some of the packages to use `tsup` for building. This will make the build process faster, and should not affect the functionality of the packages. + + Use minor version bump to catch your attention. + ## 1.2.1 ### Patch Changes diff --git a/packages/connectors/connector-alipay-native/package.json b/packages/connectors/connector-alipay-native/package.json index 7099bda0ce0..f9693c27791 100644 --- a/packages/connectors/connector-alipay-native/package.json +++ b/packages/connectors/connector-alipay-native/package.json @@ -1,6 +1,6 @@ { "name": "@logto/connector-alipay-native", - "version": "1.2.1", + "version": "1.3.0", "description": "Alipay Native implementation.", "author": "Silverhand Inc. ", "dependencies": { @@ -9,29 +9,24 @@ "dayjs": "^1.10.5", "got": "^14.0.0", "iconv-lite": "^0.6.3", - "snakecase-keys": "^8.0.0", - "zod": "^3.22.4" + "snakecase-keys": "^8.0.1", + "zod": "^3.23.8" }, "devDependencies": { - "@rollup/plugin-commonjs": "^26.0.0", - "@rollup/plugin-json": "^6.1.0", - "@rollup/plugin-node-resolve": "^15.2.3", - "@rollup/plugin-typescript": "^11.1.6", "@shopify/jest-koa-mocks": "^5.0.0", "@silverhand/eslint-config": "6.0.1", "@silverhand/ts-config": "6.0.0", "@types/node": "^20.11.20", "@types/supertest": "^6.0.2", - "@vitest/coverage-v8": "^1.4.0", + "@vitest/coverage-v8": "^2.0.0", "eslint": "^8.56.0", "lint-staged": "^15.0.2", "nock": "^13.3.1", "prettier": "^3.0.0", - "rollup": "^4.12.0", - "rollup-plugin-output-size": "^1.3.0", "supertest": "^7.0.0", - "typescript": "^5.3.3", - "vitest": "^1.4.0" + "tsup": "^8.1.0", + "typescript": "^5.5.3", + "vitest": "^2.0.0" }, "main": "./lib/index.js", "module": "./lib/index.js", @@ -46,9 +41,9 @@ ], "scripts": { "precommit": "lint-staged", - "build:test": "rm -rf lib/ && tsc -p tsconfig.test.json --sourcemap", - "build": "rm -rf lib/ && tsc -p tsconfig.build.json --noEmit && rollup -c", - "dev": "tsc -p tsconfig.build.json --watch --preserveWatchOutput --incremental", + "check": "tsc --noEmit", + "build": "tsup", + "dev": "tsup --watch", "lint": "eslint --ext .ts src", "lint:report": "pnpm lint --format json --output-file report.json", "test": "vitest src", diff --git a/packages/connectors/connector-alipay-web/CHANGELOG.md b/packages/connectors/connector-alipay-web/CHANGELOG.md index 5ffe877b82d..afa9b87c27b 100644 --- a/packages/connectors/connector-alipay-web/CHANGELOG.md +++ b/packages/connectors/connector-alipay-web/CHANGELOG.md @@ -1,5 +1,15 @@ # @logto/connector-alipay-web +## 1.4.0 + +### Minor Changes + +- 510f681fa: use tsup for building + + We've updated some of the packages to use `tsup` for building. This will make the build process faster, and should not affect the functionality of the packages. + + Use minor version bump to catch your attention. + ## 1.3.1 ### Patch Changes diff --git a/packages/connectors/connector-alipay-web/package.json b/packages/connectors/connector-alipay-web/package.json index 10b5095b6b4..c567bb78973 100644 --- a/packages/connectors/connector-alipay-web/package.json +++ b/packages/connectors/connector-alipay-web/package.json @@ -1,6 +1,6 @@ { "name": "@logto/connector-alipay-web", - "version": "1.3.1", + "version": "1.4.0", "description": "Alipay implementation.", "dependencies": { "@logto/connector-kit": "workspace:^4.0.0", @@ -8,29 +8,24 @@ "dayjs": "^1.10.5", "got": "^14.0.0", "iconv-lite": "^0.6.3", - "snakecase-keys": "^8.0.0", - "zod": "^3.22.4" + "snakecase-keys": "^8.0.1", + "zod": "^3.23.8" }, "devDependencies": { - "@rollup/plugin-commonjs": "^26.0.0", - "@rollup/plugin-json": "^6.1.0", - "@rollup/plugin-node-resolve": "^15.2.3", - "@rollup/plugin-typescript": "^11.1.6", "@shopify/jest-koa-mocks": "^5.0.0", "@silverhand/eslint-config": "6.0.1", "@silverhand/ts-config": "6.0.0", "@types/node": "^20.11.20", "@types/supertest": "^6.0.2", - "@vitest/coverage-v8": "^1.4.0", + "@vitest/coverage-v8": "^2.0.0", "eslint": "^8.56.0", "lint-staged": "^15.0.2", "nock": "^13.3.1", "prettier": "^3.0.0", - "rollup": "^4.12.0", - "rollup-plugin-output-size": "^1.3.0", "supertest": "^7.0.0", - "typescript": "^5.3.3", - "vitest": "^1.4.0" + "tsup": "^8.1.0", + "typescript": "^5.5.3", + "vitest": "^2.0.0" }, "main": "./lib/index.js", "module": "./lib/index.js", @@ -45,9 +40,9 @@ ], "scripts": { "precommit": "lint-staged", - "build:test": "rm -rf lib/ && tsc -p tsconfig.test.json --sourcemap", - "build": "rm -rf lib/ && tsc -p tsconfig.build.json --noEmit && rollup -c", - "dev": "tsc -p tsconfig.build.json --watch --preserveWatchOutput --incremental", + "check": "tsc --noEmit", + "build": "tsup", + "dev": "tsup --watch", "lint": "eslint --ext .ts src", "lint:report": "pnpm lint --format json --output-file report.json", "test": "vitest src", diff --git a/packages/connectors/connector-aliyun-dm/CHANGELOG.md b/packages/connectors/connector-aliyun-dm/CHANGELOG.md index 194f3b8132c..cf64e5b303d 100644 --- a/packages/connectors/connector-aliyun-dm/CHANGELOG.md +++ b/packages/connectors/connector-aliyun-dm/CHANGELOG.md @@ -1,5 +1,15 @@ # @logto/connector-aliyun-dm +## 1.2.0 + +### Minor Changes + +- 510f681fa: use tsup for building + + We've updated some of the packages to use `tsup` for building. This will make the build process faster, and should not affect the functionality of the packages. + + Use minor version bump to catch your attention. + ## 1.1.2 ### Patch Changes diff --git a/packages/connectors/connector-aliyun-dm/package.json b/packages/connectors/connector-aliyun-dm/package.json index 59e41ddd8e8..6e2d9901923 100644 --- a/packages/connectors/connector-aliyun-dm/package.json +++ b/packages/connectors/connector-aliyun-dm/package.json @@ -1,13 +1,13 @@ { "name": "@logto/connector-aliyun-dm", - "version": "1.1.2", + "version": "1.2.0", "description": "Aliyun DM connector implementation.", "dependencies": { "@logto/connector-kit": "workspace:^4.0.0", "@silverhand/essentials": "^2.9.1", "got": "^14.0.0", - "snakecase-keys": "^8.0.0", - "zod": "^3.22.4" + "snakecase-keys": "^8.0.1", + "zod": "^3.23.8" }, "main": "./lib/index.js", "module": "./lib/index.js", @@ -22,9 +22,9 @@ ], "scripts": { "precommit": "lint-staged", - "build:test": "rm -rf lib/ && tsc -p tsconfig.test.json --sourcemap", - "build": "rm -rf lib/ && tsc -p tsconfig.build.json --noEmit && rollup -c", - "dev": "tsc -p tsconfig.build.json --watch --preserveWatchOutput --incremental", + "check": "tsc --noEmit", + "build": "tsup", + "dev": "tsup --watch", "lint": "eslint --ext .ts src", "lint:report": "pnpm lint --format json --output-file report.json", "test": "vitest src", @@ -51,23 +51,18 @@ "access": "public" }, "devDependencies": { - "@rollup/plugin-commonjs": "^26.0.0", - "@rollup/plugin-json": "^6.1.0", - "@rollup/plugin-node-resolve": "^15.2.3", - "@rollup/plugin-typescript": "^11.1.6", "@silverhand/eslint-config": "6.0.1", "@silverhand/ts-config": "6.0.0", "@types/node": "^20.11.20", "@types/supertest": "^6.0.2", - "@vitest/coverage-v8": "^1.4.0", + "@vitest/coverage-v8": "^2.0.0", "eslint": "^8.56.0", "lint-staged": "^15.0.2", "nock": "^13.3.1", "prettier": "^3.0.0", - "rollup": "^4.12.0", - "rollup-plugin-output-size": "^1.3.0", "supertest": "^7.0.0", - "typescript": "^5.3.3", - "vitest": "^1.4.0" + "tsup": "^8.1.0", + "typescript": "^5.5.3", + "vitest": "^2.0.0" } } diff --git a/packages/connectors/connector-aliyun-dm/src/single-send-mail.test.ts b/packages/connectors/connector-aliyun-dm/src/single-send-mail.test.ts index 1162b5d3210..d0e91995e02 100644 --- a/packages/connectors/connector-aliyun-dm/src/single-send-mail.test.ts +++ b/packages/connectors/connector-aliyun-dm/src/single-send-mail.test.ts @@ -21,11 +21,10 @@ describe('singleSendMail', () => { }, '' ); - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment - const calledData = request.mock.calls[0]; + const calledData = request.mock.calls[0] as Array<{ form: Record }>; expect(calledData).not.toBeUndefined(); - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment - const payload = calledData?.[1]; + + const payload = calledData[1]; expect(payload).toHaveProperty('Action', 'SingleSendMail'); }); }); diff --git a/packages/connectors/connector-aliyun-dm/src/utils.test.ts b/packages/connectors/connector-aliyun-dm/src/utils.test.ts index 24da02e7a88..19dc98253a1 100644 --- a/packages/connectors/connector-aliyun-dm/src/utils.test.ts +++ b/packages/connectors/connector-aliyun-dm/src/utils.test.ts @@ -24,13 +24,13 @@ describe('request', () => { it('should call got.post with extended params', async () => { const parameters = mockedParameters; await request('http://test.endpoint.com', parameters, 'testsecret'); - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment - const calledData = post.mock.calls[0]; + const calledData = post.mock.calls[0] as Array<{ form: Record }>; expect(calledData).not.toBeUndefined(); - const payload = calledData?.[0].form as Record; - expect(payload.AccessKeyId).toEqual('testid'); - expect(payload.Timestamp).not.toBeNull(); - expect(payload.SignatureNonce).not.toBeNull(); - expect(payload.Signature).not.toBeNull(); + const payload = calledData[0] ? calledData[0].form : undefined; + expect(payload).not.toBeUndefined(); + expect(payload?.AccessKeyId).toEqual('testid'); + expect(payload?.Timestamp).not.toBeNull(); + expect(payload?.SignatureNonce).not.toBeNull(); + expect(payload?.Signature).not.toBeNull(); }); }); diff --git a/packages/connectors/connector-aliyun-sms/CHANGELOG.md b/packages/connectors/connector-aliyun-sms/CHANGELOG.md index dc502f55bae..d8cf480ef0d 100644 --- a/packages/connectors/connector-aliyun-sms/CHANGELOG.md +++ b/packages/connectors/connector-aliyun-sms/CHANGELOG.md @@ -1,5 +1,15 @@ # @logto/connector-aliyun-sms +## 1.2.0 + +### Minor Changes + +- 510f681fa: use tsup for building + + We've updated some of the packages to use `tsup` for building. This will make the build process faster, and should not affect the functionality of the packages. + + Use minor version bump to catch your attention. + ## 1.1.2 ### Patch Changes diff --git a/packages/connectors/connector-aliyun-sms/package.json b/packages/connectors/connector-aliyun-sms/package.json index 9739f43eb75..bf66618112f 100644 --- a/packages/connectors/connector-aliyun-sms/package.json +++ b/packages/connectors/connector-aliyun-sms/package.json @@ -1,13 +1,13 @@ { "name": "@logto/connector-aliyun-sms", - "version": "1.1.2", + "version": "1.2.0", "description": "Aliyun SMS connector implementation.", "dependencies": { "@logto/connector-kit": "workspace:^4.0.0", "@silverhand/essentials": "^2.9.1", "got": "^14.0.0", - "snakecase-keys": "^8.0.0", - "zod": "^3.22.4" + "snakecase-keys": "^8.0.1", + "zod": "^3.23.8" }, "main": "./lib/index.js", "module": "./lib/index.js", @@ -22,9 +22,9 @@ ], "scripts": { "precommit": "lint-staged", - "build:test": "rm -rf lib/ && tsc -p tsconfig.test.json --sourcemap", - "build": "rm -rf lib/ && tsc -p tsconfig.build.json --noEmit && rollup -c", - "dev": "tsc -p tsconfig.build.json --watch --preserveWatchOutput --incremental", + "check": "tsc --noEmit", + "build": "tsup", + "dev": "tsup --watch", "lint": "eslint --ext .ts src", "lint:report": "pnpm lint --format json --output-file report.json", "test": "vitest src", @@ -51,23 +51,18 @@ "access": "public" }, "devDependencies": { - "@rollup/plugin-commonjs": "^26.0.0", - "@rollup/plugin-json": "^6.1.0", - "@rollup/plugin-node-resolve": "^15.2.3", - "@rollup/plugin-typescript": "^11.1.6", "@silverhand/eslint-config": "6.0.1", "@silverhand/ts-config": "6.0.0", "@types/node": "^20.11.20", "@types/supertest": "^6.0.2", - "@vitest/coverage-v8": "^1.4.0", + "@vitest/coverage-v8": "^2.0.0", "eslint": "^8.56.0", "lint-staged": "^15.0.2", "nock": "^13.3.1", "prettier": "^3.0.0", - "rollup": "^4.12.0", - "rollup-plugin-output-size": "^1.3.0", "supertest": "^7.0.0", - "typescript": "^5.3.3", - "vitest": "^1.4.0" + "tsup": "^8.1.0", + "typescript": "^5.5.3", + "vitest": "^2.0.0" } } diff --git a/packages/connectors/connector-aliyun-sms/src/single-send-text.test.ts b/packages/connectors/connector-aliyun-sms/src/single-send-text.test.ts index ec7da921964..88690666aca 100644 --- a/packages/connectors/connector-aliyun-sms/src/single-send-text.test.ts +++ b/packages/connectors/connector-aliyun-sms/src/single-send-text.test.ts @@ -20,11 +20,10 @@ describe('sendSms', () => { }, '' ); - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment - const calledData = request.mock.calls[0]; + const calledData = request.mock.calls[0] as Array<{ form: Record }>; expect(calledData).not.toBeUndefined(); - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment - const payload = calledData?.[1]; + + const payload = calledData[1]; expect(payload).toHaveProperty('Action', 'SendSms'); }); }); diff --git a/packages/connectors/connector-aliyun-sms/src/utils.test.ts b/packages/connectors/connector-aliyun-sms/src/utils.test.ts index 24da02e7a88..9aae8b784bb 100644 --- a/packages/connectors/connector-aliyun-sms/src/utils.test.ts +++ b/packages/connectors/connector-aliyun-sms/src/utils.test.ts @@ -24,13 +24,12 @@ describe('request', () => { it('should call got.post with extended params', async () => { const parameters = mockedParameters; await request('http://test.endpoint.com', parameters, 'testsecret'); - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment - const calledData = post.mock.calls[0]; + const calledData = post.mock.calls[0] as Array<{ form: Record }>; expect(calledData).not.toBeUndefined(); - const payload = calledData?.[0].form as Record; - expect(payload.AccessKeyId).toEqual('testid'); - expect(payload.Timestamp).not.toBeNull(); - expect(payload.SignatureNonce).not.toBeNull(); - expect(payload.Signature).not.toBeNull(); + const payload = calledData[0] ? calledData[0].form : undefined; + expect(payload?.AccessKeyId).toEqual('testid'); + expect(payload?.Timestamp).not.toBeNull(); + expect(payload?.SignatureNonce).not.toBeNull(); + expect(payload?.Signature).not.toBeNull(); }); }); diff --git a/packages/connectors/connector-apple/CHANGELOG.md b/packages/connectors/connector-apple/CHANGELOG.md index 1e5544aa92e..3b7a9534c53 100644 --- a/packages/connectors/connector-apple/CHANGELOG.md +++ b/packages/connectors/connector-apple/CHANGELOG.md @@ -1,5 +1,15 @@ # @logto/connector-apple +## 1.4.0 + +### Minor Changes + +- 510f681fa: use tsup for building + + We've updated some of the packages to use `tsup` for building. This will make the build process faster, and should not affect the functionality of the packages. + + Use minor version bump to catch your attention. + ## 1.3.1 ### Patch Changes diff --git a/packages/connectors/connector-apple/package.json b/packages/connectors/connector-apple/package.json index 2c11467106b..3ddbbe02385 100644 --- a/packages/connectors/connector-apple/package.json +++ b/packages/connectors/connector-apple/package.json @@ -1,15 +1,15 @@ { "name": "@logto/connector-apple", - "version": "1.3.1", + "version": "1.4.0", "description": "Apple web connector implementation.", "dependencies": { "@logto/connector-kit": "workspace:^4.0.0", "@logto/shared": "workspace:^3.1.0", "@silverhand/essentials": "^2.9.1", "got": "^14.0.0", - "jose": "^5.0.0", - "snakecase-keys": "^8.0.0", - "zod": "^3.22.4" + "jose": "^5.6.3", + "snakecase-keys": "^8.0.1", + "zod": "^3.23.8" }, "main": "./lib/index.js", "module": "./lib/index.js", @@ -24,9 +24,9 @@ ], "scripts": { "precommit": "lint-staged", - "build:test": "rm -rf lib/ && tsc -p tsconfig.test.json --sourcemap", - "build": "rm -rf lib/ && tsc -p tsconfig.build.json --noEmit && rollup -c", - "dev": "tsc -p tsconfig.build.json --watch --preserveWatchOutput --incremental", + "check": "tsc --noEmit", + "build": "tsup", + "dev": "tsup --watch", "lint": "eslint --ext .ts src", "lint:report": "pnpm lint --format json --output-file report.json", "test": "vitest src", @@ -53,23 +53,18 @@ "access": "public" }, "devDependencies": { - "@rollup/plugin-commonjs": "^26.0.0", - "@rollup/plugin-json": "^6.1.0", - "@rollup/plugin-node-resolve": "^15.2.3", - "@rollup/plugin-typescript": "^11.1.6", "@silverhand/eslint-config": "6.0.1", "@silverhand/ts-config": "6.0.0", "@types/node": "^20.11.20", "@types/supertest": "^6.0.2", - "@vitest/coverage-v8": "^1.4.0", + "@vitest/coverage-v8": "^2.0.0", "eslint": "^8.56.0", "lint-staged": "^15.0.2", "nock": "^13.3.1", "prettier": "^3.0.0", - "rollup": "^4.12.0", - "rollup-plugin-output-size": "^1.3.0", "supertest": "^7.0.0", - "typescript": "^5.3.3", - "vitest": "^1.4.0" + "tsup": "^8.1.0", + "typescript": "^5.5.3", + "vitest": "^2.0.0" } } diff --git a/packages/connectors/connector-aws-ses/CHANGELOG.md b/packages/connectors/connector-aws-ses/CHANGELOG.md index c1be1d0c438..eaa603c95b1 100644 --- a/packages/connectors/connector-aws-ses/CHANGELOG.md +++ b/packages/connectors/connector-aws-ses/CHANGELOG.md @@ -1,5 +1,15 @@ # @logto/connector-aws-ses +## 1.2.0 + +### Minor Changes + +- 510f681fa: use tsup for building + + We've updated some of the packages to use `tsup` for building. This will make the build process faster, and should not affect the functionality of the packages. + + Use minor version bump to catch your attention. + ## 1.1.2 ### Patch Changes diff --git a/packages/connectors/connector-aws-ses/package.json b/packages/connectors/connector-aws-ses/package.json index 99f6582e302..9c9f32c0cb6 100644 --- a/packages/connectors/connector-aws-ses/package.json +++ b/packages/connectors/connector-aws-ses/package.json @@ -1,6 +1,6 @@ { "name": "@logto/connector-aws-ses", - "version": "1.1.2", + "version": "1.2.0", "description": "Logto Connector for Amazon SES", "author": "Jeff ", "dependencies": { @@ -9,8 +9,8 @@ "@logto/connector-kit": "workspace:^4.0.0", "@silverhand/essentials": "^2.9.1", "got": "^14.0.0", - "snakecase-keys": "^8.0.0", - "zod": "^3.22.4" + "snakecase-keys": "^8.0.1", + "zod": "^3.23.8" }, "main": "./lib/index.js", "module": "./lib/index.js", @@ -25,9 +25,9 @@ ], "scripts": { "precommit": "lint-staged", - "build:test": "rm -rf lib/ && tsc -p tsconfig.test.json --sourcemap", - "build": "rm -rf lib/ && tsc -p tsconfig.build.json --noEmit && rollup -c", - "dev": "tsc -p tsconfig.build.json --watch --preserveWatchOutput --incremental", + "check": "tsc --noEmit", + "build": "tsup", + "dev": "tsup --watch", "lint": "eslint --ext .ts src", "lint:report": "pnpm lint --format json --output-file report.json", "test": "vitest src", @@ -54,23 +54,18 @@ "access": "public" }, "devDependencies": { - "@rollup/plugin-commonjs": "^26.0.0", - "@rollup/plugin-json": "^6.1.0", - "@rollup/plugin-node-resolve": "^15.2.3", - "@rollup/plugin-typescript": "^11.1.6", "@silverhand/eslint-config": "6.0.1", "@silverhand/ts-config": "6.0.0", "@types/node": "^20.11.20", "@types/supertest": "^6.0.2", - "@vitest/coverage-v8": "^1.4.0", + "@vitest/coverage-v8": "^2.0.0", "eslint": "^8.56.0", "lint-staged": "^15.0.2", "nock": "^13.3.1", "prettier": "^3.0.0", - "rollup": "^4.12.0", - "rollup-plugin-output-size": "^1.3.0", "supertest": "^7.0.0", - "typescript": "^5.3.3", - "vitest": "^1.4.0" + "tsup": "^8.1.0", + "typescript": "^5.5.3", + "vitest": "^2.0.0" } } diff --git a/packages/connectors/connector-azuread/CHANGELOG.md b/packages/connectors/connector-azuread/CHANGELOG.md index 6fd68879451..67bbedd0686 100644 --- a/packages/connectors/connector-azuread/CHANGELOG.md +++ b/packages/connectors/connector-azuread/CHANGELOG.md @@ -1,5 +1,15 @@ # @logto/connector-azuread +## 1.4.0 + +### Minor Changes + +- 510f681fa: use tsup for building + + We've updated some of the packages to use `tsup` for building. This will make the build process faster, and should not affect the functionality of the packages. + + Use minor version bump to catch your attention. + ## 1.3.0 ### Minor Changes diff --git a/packages/connectors/connector-azuread/README.md b/packages/connectors/connector-azuread/README.md index 6bb274fa36b..07581e443ed 100644 --- a/packages/connectors/connector-azuread/README.md +++ b/packages/connectors/connector-azuread/README.md @@ -66,29 +66,6 @@ The `prompts` field is an array of strings that specifies the type of user inter Logto will concatenate the prompts with a space as the value of `prompt` in the authorization URL. -### Client ID - -You may find the **Application (client) ID** in the **Overview** section of your newly created application in the Azure Portal. - -### Client Secret - -- In your newly created application, click the **Certificates & Secrets** to get a client secret, and click the **New client secret** from the top. -- Enter a description and an expiration. -- This will only show your client secret once. Fill the **value** to the Logto connector configuration and save it to a secure location. - -### Cloud Instance - -Usually, it is `https://login.microsoftonline.com/`. See [Azure AD authentication endpoints](https://learn.microsoft.com/en-us/azure/active-directory/develop/authentication-national-cloud#azure-ad-authentication-endpoints) for more information. - -### Tenant ID - -Logto will use this field to construct the authorization endpoints. This value is dependent on the **access type** you selected when creating the application in the Azure Portal. - -- If you select **Accounts in this organizational directory only** for access type then you need to enter your **{TenantID}**. You can find the tenant ID in the **Overview** section of your Azure Active Directory. -- If you select **Accounts in any organizational directory** for access type then you need to enter **organizations**. -- If you select **Accounts in any organizational directory or personal Microsoft accounts** for access type then you need to enter **common**. -- If you select **Personal Microsoft accounts only** for access type then you need to enter **consumers**. - ## References - [Web app that signs in users](https://docs.microsoft.com/en-us/azure/active-directory/develop/scenario-web-app-sign-user-overview) diff --git a/packages/connectors/connector-azuread/package.json b/packages/connectors/connector-azuread/package.json index 773b2da57be..d95be30e90e 100644 --- a/packages/connectors/connector-azuread/package.json +++ b/packages/connectors/connector-azuread/package.json @@ -1,6 +1,6 @@ { "name": "@logto/connector-azuread", - "version": "1.3.0", + "version": "1.4.0", "description": "Microsoft Azure AD connector implementation.", "author": "Mobilist Inc. ", "dependencies": { @@ -8,8 +8,8 @@ "@logto/connector-kit": "workspace:^4.0.0", "@silverhand/essentials": "^2.9.1", "got": "^14.0.0", - "snakecase-keys": "^8.0.0", - "zod": "^3.22.4" + "snakecase-keys": "^8.0.1", + "zod": "^3.23.8" }, "main": "./lib/index.js", "module": "./lib/index.js", @@ -24,9 +24,9 @@ ], "scripts": { "precommit": "lint-staged", - "build:test": "rm -rf lib/ && tsc -p tsconfig.test.json --sourcemap", - "build": "rm -rf lib/ && tsc -p tsconfig.build.json --noEmit && rollup -c", - "dev": "tsc -p tsconfig.build.json --watch --preserveWatchOutput --incremental", + "check": "tsc --noEmit", + "build": "tsup", + "dev": "tsup --watch", "lint": "eslint --ext .ts src", "lint:report": "pnpm lint --format json --output-file report.json", "test": "vitest src", @@ -53,23 +53,18 @@ "access": "public" }, "devDependencies": { - "@rollup/plugin-commonjs": "^26.0.0", - "@rollup/plugin-json": "^6.1.0", - "@rollup/plugin-node-resolve": "^15.2.3", - "@rollup/plugin-typescript": "^11.1.6", "@silverhand/eslint-config": "6.0.1", "@silverhand/ts-config": "6.0.0", "@types/node": "^20.11.20", "@types/supertest": "^6.0.2", - "@vitest/coverage-v8": "^1.4.0", + "@vitest/coverage-v8": "^2.0.0", "eslint": "^8.56.0", "lint-staged": "^15.0.2", "nock": "^13.3.1", "prettier": "^3.0.0", - "rollup": "^4.12.0", - "rollup-plugin-output-size": "^1.3.0", "supertest": "^7.0.0", - "typescript": "^5.3.3", - "vitest": "^1.4.0" + "tsup": "^8.1.0", + "typescript": "^5.5.3", + "vitest": "^2.0.0" } } diff --git a/packages/connectors/connector-dingtalk-web/CHANGELOG.md b/packages/connectors/connector-dingtalk-web/CHANGELOG.md index 61d3dd9d940..e00eb0f6673 100644 --- a/packages/connectors/connector-dingtalk-web/CHANGELOG.md +++ b/packages/connectors/connector-dingtalk-web/CHANGELOG.md @@ -1,5 +1,15 @@ # @logto/connector-dingtalk-web +## 0.2.0 + +### Minor Changes + +- 510f681fa: use tsup for building + + We've updated some of the packages to use `tsup` for building. This will make the build process faster, and should not affect the functionality of the packages. + + Use minor version bump to catch your attention. + ## 0.1.1 ### Patch Changes diff --git a/packages/connectors/connector-dingtalk-web/package.json b/packages/connectors/connector-dingtalk-web/package.json index d2815d24c29..b099ca2d0c5 100644 --- a/packages/connectors/connector-dingtalk-web/package.json +++ b/packages/connectors/connector-dingtalk-web/package.json @@ -1,6 +1,6 @@ { "name": "@logto/connector-dingtalk-web", - "version": "0.1.1", + "version": "0.2.0", "description": "Dingtalk web connector implementation.", "dependencies": { "@logto/connector-kit": "workspace:^4.0.0", @@ -8,29 +8,24 @@ "dayjs": "^1.10.5", "got": "^14.0.0", "iconv-lite": "^0.6.3", - "snakecase-keys": "^8.0.0", - "zod": "^3.22.4" + "snakecase-keys": "^8.0.1", + "zod": "^3.23.8" }, "devDependencies": { - "@rollup/plugin-commonjs": "^26.0.0", - "@rollup/plugin-json": "^6.1.0", - "@rollup/plugin-node-resolve": "^15.2.3", - "@rollup/plugin-typescript": "^11.1.6", "@shopify/jest-koa-mocks": "^5.0.0", "@silverhand/eslint-config": "6.0.1", "@silverhand/ts-config": "6.0.0", "@types/node": "^20.11.20", "@types/supertest": "^6.0.2", - "@vitest/coverage-v8": "^1.4.0", + "@vitest/coverage-v8": "^2.0.0", "eslint": "^8.56.0", "lint-staged": "^15.0.2", "nock": "^13.3.1", "prettier": "^3.0.0", - "rollup": "^4.12.0", - "rollup-plugin-output-size": "^1.3.0", "supertest": "^7.0.0", - "typescript": "^5.3.3", - "vitest": "^1.4.0" + "tsup": "^8.1.0", + "typescript": "^5.5.3", + "vitest": "^2.0.0" }, "main": "./lib/index.js", "module": "./lib/index.js", @@ -45,9 +40,9 @@ ], "scripts": { "precommit": "lint-staged", - "build:test": "rm -rf lib/ && tsc -p tsconfig.test.json --sourcemap", - "build": "rm -rf lib/ && tsc -p tsconfig.build.json --noEmit && rollup -c", - "dev": "tsc -p tsconfig.build.json --watch --preserveWatchOutput --incremental", + "check": "tsc --noEmit", + "build": "tsup", + "dev": "tsup --watch", "lint": "eslint --ext .ts src", "lint:report": "pnpm lint --format json --output-file report.json", "test": "vitest src", diff --git a/packages/connectors/connector-discord/CHANGELOG.md b/packages/connectors/connector-discord/CHANGELOG.md index a321f0c4a49..f102353eefa 100644 --- a/packages/connectors/connector-discord/CHANGELOG.md +++ b/packages/connectors/connector-discord/CHANGELOG.md @@ -1,5 +1,15 @@ # @logto/connector-discord +## 1.4.0 + +### Minor Changes + +- 510f681fa: use tsup for building + + We've updated some of the packages to use `tsup` for building. This will make the build process faster, and should not affect the functionality of the packages. + + Use minor version bump to catch your attention. + ## 1.3.1 ### Patch Changes diff --git a/packages/connectors/connector-discord/package.json b/packages/connectors/connector-discord/package.json index eef708ea75b..0b7c856ddaf 100644 --- a/packages/connectors/connector-discord/package.json +++ b/packages/connectors/connector-discord/package.json @@ -1,14 +1,14 @@ { "name": "@logto/connector-discord", - "version": "1.3.1", + "version": "1.4.0", "description": "Discord connector implementation.", "author": "ZR3SYSTEMS. ", "dependencies": { "@logto/connector-kit": "workspace:^4.0.0", "@silverhand/essentials": "^2.9.1", "got": "^14.0.0", - "snakecase-keys": "^8.0.0", - "zod": "^3.22.4" + "snakecase-keys": "^8.0.1", + "zod": "^3.23.8" }, "main": "./lib/index.js", "module": "./lib/index.js", @@ -23,9 +23,9 @@ ], "scripts": { "precommit": "lint-staged", - "build:test": "rm -rf lib/ && tsc -p tsconfig.test.json --sourcemap", - "build": "rm -rf lib/ && tsc -p tsconfig.build.json --noEmit && rollup -c", - "dev": "tsc -p tsconfig.build.json --watch --preserveWatchOutput --incremental", + "check": "tsc --noEmit", + "build": "tsup", + "dev": "tsup --watch", "lint": "eslint --ext .ts src", "lint:report": "pnpm lint --format json --output-file report.json", "test": "vitest src", @@ -52,23 +52,18 @@ "access": "public" }, "devDependencies": { - "@rollup/plugin-commonjs": "^26.0.0", - "@rollup/plugin-json": "^6.1.0", - "@rollup/plugin-node-resolve": "^15.2.3", - "@rollup/plugin-typescript": "^11.1.6", "@silverhand/eslint-config": "6.0.1", "@silverhand/ts-config": "6.0.0", "@types/node": "^20.11.20", "@types/supertest": "^6.0.2", - "@vitest/coverage-v8": "^1.4.0", + "@vitest/coverage-v8": "^2.0.0", "eslint": "^8.56.0", "lint-staged": "^15.0.2", "nock": "^13.3.1", "prettier": "^3.0.0", - "rollup": "^4.12.0", - "rollup-plugin-output-size": "^1.3.0", "supertest": "^7.0.0", - "typescript": "^5.3.3", - "vitest": "^1.4.0" + "tsup": "^8.1.0", + "typescript": "^5.5.3", + "vitest": "^2.0.0" } } diff --git a/packages/connectors/connector-facebook/CHANGELOG.md b/packages/connectors/connector-facebook/CHANGELOG.md index 094ebede4a5..90a43257788 100644 --- a/packages/connectors/connector-facebook/CHANGELOG.md +++ b/packages/connectors/connector-facebook/CHANGELOG.md @@ -1,5 +1,15 @@ # @logto/connector-facebook +## 1.4.0 + +### Minor Changes + +- 510f681fa: use tsup for building + + We've updated some of the packages to use `tsup` for building. This will make the build process faster, and should not affect the functionality of the packages. + + Use minor version bump to catch your attention. + ## 1.3.1 ### Patch Changes diff --git a/packages/connectors/connector-facebook/package.json b/packages/connectors/connector-facebook/package.json index 787adb612c6..823c7644e73 100644 --- a/packages/connectors/connector-facebook/package.json +++ b/packages/connectors/connector-facebook/package.json @@ -1,14 +1,14 @@ { "name": "@logto/connector-facebook", - "version": "1.3.1", + "version": "1.4.0", "description": "Facebook web connector implementation.", "author": "Silverhand Inc. ", "dependencies": { "@logto/connector-kit": "workspace:^4.0.0", "@silverhand/essentials": "^2.9.1", "got": "^14.0.0", - "snakecase-keys": "^8.0.0", - "zod": "^3.22.4" + "snakecase-keys": "^8.0.1", + "zod": "^3.23.8" }, "main": "./lib/index.js", "module": "./lib/index.js", @@ -23,9 +23,9 @@ ], "scripts": { "precommit": "lint-staged", - "build:test": "rm -rf lib/ && tsc -p tsconfig.test.json --sourcemap", - "build": "rm -rf lib/ && tsc -p tsconfig.build.json --noEmit && rollup -c", - "dev": "tsc -p tsconfig.build.json --watch --preserveWatchOutput --incremental", + "check": "tsc --noEmit", + "build": "tsup", + "dev": "tsup --watch", "lint": "eslint --ext .ts src", "lint:report": "pnpm lint --format json --output-file report.json", "test": "vitest src", @@ -52,23 +52,18 @@ "access": "public" }, "devDependencies": { - "@rollup/plugin-commonjs": "^26.0.0", - "@rollup/plugin-json": "^6.1.0", - "@rollup/plugin-node-resolve": "^15.2.3", - "@rollup/plugin-typescript": "^11.1.6", "@silverhand/eslint-config": "6.0.1", "@silverhand/ts-config": "6.0.0", "@types/node": "^20.11.20", "@types/supertest": "^6.0.2", - "@vitest/coverage-v8": "^1.4.0", + "@vitest/coverage-v8": "^2.0.0", "eslint": "^8.56.0", "lint-staged": "^15.0.2", "nock": "^13.3.1", "prettier": "^3.0.0", - "rollup": "^4.12.0", - "rollup-plugin-output-size": "^1.3.0", "supertest": "^7.0.0", - "typescript": "^5.3.3", - "vitest": "^1.4.0" + "tsup": "^8.1.0", + "typescript": "^5.5.3", + "vitest": "^2.0.0" } } diff --git a/packages/connectors/connector-feishu-web/CHANGELOG.md b/packages/connectors/connector-feishu-web/CHANGELOG.md index 3d0f5dbfbf8..caeb8d362d9 100644 --- a/packages/connectors/connector-feishu-web/CHANGELOG.md +++ b/packages/connectors/connector-feishu-web/CHANGELOG.md @@ -1,5 +1,15 @@ # @logto/connector-feishu-web +## 1.3.0 + +### Minor Changes + +- 510f681fa: use tsup for building + + We've updated some of the packages to use `tsup` for building. This will make the build process faster, and should not affect the functionality of the packages. + + Use minor version bump to catch your attention. + ## 1.2.1 ### Patch Changes diff --git a/packages/connectors/connector-feishu-web/package.json b/packages/connectors/connector-feishu-web/package.json index b6db69458b6..77f01bd255b 100644 --- a/packages/connectors/connector-feishu-web/package.json +++ b/packages/connectors/connector-feishu-web/package.json @@ -1,14 +1,14 @@ { "name": "@logto/connector-feishu-web", - "version": "1.2.1", + "version": "1.3.0", "description": "Feishu web connector.", "author": "Silverhand Inc. ", "dependencies": { "@logto/connector-kit": "workspace:^4.0.0", "@silverhand/essentials": "^2.9.1", "got": "^14.0.0", - "snakecase-keys": "^8.0.0", - "zod": "^3.22.4" + "snakecase-keys": "^8.0.1", + "zod": "^3.23.8" }, "main": "./lib/index.js", "module": "./lib/index.js", @@ -23,9 +23,9 @@ ], "scripts": { "precommit": "lint-staged", - "build:test": "rm -rf lib/ && tsc -p tsconfig.test.json --sourcemap", - "build": "rm -rf lib/ && tsc -p tsconfig.build.json --noEmit && rollup -c", - "dev": "tsc -p tsconfig.build.json --watch --preserveWatchOutput --incremental", + "check": "tsc --noEmit", + "build": "tsup", + "dev": "tsup --watch", "lint": "eslint --ext .ts src", "lint:report": "pnpm lint --format json --output-file report.json", "test": "vitest src", @@ -52,23 +52,18 @@ "access": "public" }, "devDependencies": { - "@rollup/plugin-commonjs": "^26.0.0", - "@rollup/plugin-json": "^6.1.0", - "@rollup/plugin-node-resolve": "^15.2.3", - "@rollup/plugin-typescript": "^11.1.6", "@silverhand/eslint-config": "6.0.1", "@silverhand/ts-config": "6.0.0", "@types/node": "^20.11.20", "@types/supertest": "^6.0.2", - "@vitest/coverage-v8": "^1.4.0", + "@vitest/coverage-v8": "^2.0.0", "eslint": "^8.56.0", "lint-staged": "^15.0.2", "nock": "^13.3.1", "prettier": "^3.0.0", - "rollup": "^4.12.0", - "rollup-plugin-output-size": "^1.3.0", "supertest": "^7.0.0", - "typescript": "^5.3.3", - "vitest": "^1.4.0" + "tsup": "^8.1.0", + "typescript": "^5.5.3", + "vitest": "^2.0.0" } } diff --git a/packages/connectors/connector-github/CHANGELOG.md b/packages/connectors/connector-github/CHANGELOG.md index 3070f3df691..05ad1af36e9 100644 --- a/packages/connectors/connector-github/CHANGELOG.md +++ b/packages/connectors/connector-github/CHANGELOG.md @@ -1,5 +1,15 @@ # @logto/connector-github +## 1.5.0 + +### Minor Changes + +- 510f681fa: use tsup for building + + We've updated some of the packages to use `tsup` for building. This will make the build process faster, and should not affect the functionality of the packages. + + Use minor version bump to catch your attention. + ## 1.4.2 ### Patch Changes diff --git a/packages/connectors/connector-github/package.json b/packages/connectors/connector-github/package.json index 1e9eeb2a4e9..4df0c375e89 100644 --- a/packages/connectors/connector-github/package.json +++ b/packages/connectors/connector-github/package.json @@ -1,6 +1,6 @@ { "name": "@logto/connector-github", - "version": "1.4.2", + "version": "1.5.0", "description": "Github web connector implementation.", "author": "Silverhand Inc. ", "dependencies": { @@ -8,8 +8,8 @@ "@silverhand/essentials": "^2.9.1", "ky": "^1.2.3", "query-string": "^9.0.0", - "snakecase-keys": "^8.0.0", - "zod": "^3.22.4" + "snakecase-keys": "^8.0.1", + "zod": "^3.23.8" }, "main": "./lib/index.js", "module": "./lib/index.js", @@ -24,9 +24,9 @@ ], "scripts": { "precommit": "lint-staged", - "build:test": "rm -rf lib/ && tsc -p tsconfig.test.json --sourcemap", - "build": "rm -rf lib/ && tsc -p tsconfig.build.json --noEmit && rollup -c", - "dev": "tsc -p tsconfig.build.json --watch --preserveWatchOutput --incremental", + "check": "tsc --noEmit", + "build": "tsup", + "dev": "tsup --watch", "lint": "eslint --ext .ts src", "lint:report": "pnpm lint --format json --output-file report.json", "test": "vitest src", @@ -53,23 +53,18 @@ "access": "public" }, "devDependencies": { - "@rollup/plugin-commonjs": "^26.0.0", - "@rollup/plugin-json": "^6.1.0", - "@rollup/plugin-node-resolve": "^15.2.3", - "@rollup/plugin-typescript": "^11.1.6", "@silverhand/eslint-config": "6.0.1", "@silverhand/ts-config": "6.0.0", "@types/node": "^20.11.20", "@types/supertest": "^6.0.2", - "@vitest/coverage-v8": "^1.4.0", + "@vitest/coverage-v8": "^2.0.0", "eslint": "^8.56.0", "lint-staged": "^15.0.2", - "nock": "14.0.0-beta.7", + "nock": "14.0.0-beta.9", "prettier": "^3.0.0", - "rollup": "^4.12.0", - "rollup-plugin-output-size": "^1.3.0", "supertest": "^7.0.0", - "typescript": "^5.3.3", - "vitest": "^1.4.0" + "tsup": "^8.1.0", + "typescript": "^5.5.3", + "vitest": "^2.0.0" } } diff --git a/packages/connectors/connector-google/CHANGELOG.md b/packages/connectors/connector-google/CHANGELOG.md index 1525e3dea4a..81ff42db4f6 100644 --- a/packages/connectors/connector-google/CHANGELOG.md +++ b/packages/connectors/connector-google/CHANGELOG.md @@ -1,5 +1,15 @@ # @logto/connector-google +## 1.5.0 + +### Minor Changes + +- 510f681fa: use tsup for building + + We've updated some of the packages to use `tsup` for building. This will make the build process faster, and should not affect the functionality of the packages. + + Use minor version bump to catch your attention. + ## 1.4.0 ### Minor Changes diff --git a/packages/connectors/connector-google/package.json b/packages/connectors/connector-google/package.json index 6f5c8da1591..fa995562f88 100644 --- a/packages/connectors/connector-google/package.json +++ b/packages/connectors/connector-google/package.json @@ -1,15 +1,15 @@ { "name": "@logto/connector-google", - "version": "1.4.0", + "version": "1.5.0", "description": "Google web connector implementation.", "author": "Silverhand Inc. ", "dependencies": { "@logto/connector-kit": "workspace:^4.0.0", "@silverhand/essentials": "^2.9.1", "got": "^14.0.0", - "jose": "^5.0.0", - "snakecase-keys": "^8.0.0", - "zod": "^3.22.4" + "jose": "^5.6.3", + "snakecase-keys": "^8.0.1", + "zod": "^3.23.8" }, "main": "./lib/index.js", "module": "./lib/index.js", @@ -24,9 +24,9 @@ ], "scripts": { "precommit": "lint-staged", - "build:test": "rm -rf lib/ && tsc -p tsconfig.test.json --sourcemap", - "build": "rm -rf lib/ && tsc -p tsconfig.build.json --noEmit && rollup -c", - "dev": "tsc -p tsconfig.build.json --watch --preserveWatchOutput --incremental", + "check": "tsc --noEmit", + "build": "tsup", + "dev": "tsup --watch", "lint": "eslint --ext .ts src", "lint:report": "pnpm lint --format json --output-file report.json", "test": "vitest src", @@ -53,23 +53,18 @@ "access": "public" }, "devDependencies": { - "@rollup/plugin-commonjs": "^26.0.0", - "@rollup/plugin-json": "^6.1.0", - "@rollup/plugin-node-resolve": "^15.2.3", - "@rollup/plugin-typescript": "^11.1.6", "@silverhand/eslint-config": "6.0.1", "@silverhand/ts-config": "6.0.0", "@types/node": "^20.11.20", "@types/supertest": "^6.0.2", - "@vitest/coverage-v8": "^1.4.0", + "@vitest/coverage-v8": "^2.0.0", "eslint": "^8.56.0", "lint-staged": "^15.0.2", "nock": "^13.3.1", "prettier": "^3.0.0", - "rollup": "^4.12.0", - "rollup-plugin-output-size": "^1.3.0", "supertest": "^7.0.0", - "typescript": "^5.3.3", - "vitest": "^1.4.0" + "tsup": "^8.1.0", + "typescript": "^5.5.3", + "vitest": "^2.0.0" } } diff --git a/packages/connectors/connector-huggingface/CHANGELOG.md b/packages/connectors/connector-huggingface/CHANGELOG.md index 9a4e9d322cd..20c3e36594d 100644 --- a/packages/connectors/connector-huggingface/CHANGELOG.md +++ b/packages/connectors/connector-huggingface/CHANGELOG.md @@ -1,5 +1,20 @@ # @logto/connector-huggingface +## 0.2.0 + +### Minor Changes + +- 510f681fa: use tsup for building + + We've updated some of the packages to use `tsup` for building. This will make the build process faster, and should not affect the functionality of the packages. + + Use minor version bump to catch your attention. + +### Patch Changes + +- Updated dependencies [510f681fa] + - @logto/connector-oauth@1.4.0 + ## 0.1.1 ### Patch Changes diff --git a/packages/connectors/connector-huggingface/package.json b/packages/connectors/connector-huggingface/package.json index b87196f02f6..5cd070f240c 100644 --- a/packages/connectors/connector-huggingface/package.json +++ b/packages/connectors/connector-huggingface/package.json @@ -1,14 +1,14 @@ { "name": "@logto/connector-huggingface", - "version": "0.1.1", + "version": "0.2.0", "description": "Hugging Face connector implementation.", "author": "Silverhand Inc. ", "dependencies": { "@logto/connector-kit": "workspace:^4.0.0", - "@logto/connector-oauth": "workspace:^1.3.1", + "@logto/connector-oauth": "workspace:^1.4.0", "@silverhand/essentials": "^2.9.1", "ky": "^1.2.3", - "zod": "^3.22.4" + "zod": "^3.23.8" }, "main": "./lib/index.js", "module": "./lib/index.js", @@ -23,9 +23,9 @@ ], "scripts": { "precommit": "lint-staged", - "build:test": "rm -rf lib/ && tsc -p tsconfig.test.json --sourcemap", - "build": "rm -rf lib/ && tsc -p tsconfig.build.json --noEmit && rollup -c", - "dev": "tsc -p tsconfig.build.json --watch --preserveWatchOutput --incremental", + "check": "tsc --noEmit", + "build": "tsup", + "dev": "tsup --watch", "lint": "eslint --ext .ts src", "lint:report": "pnpm lint --format json --output-file report.json", "test": "vitest src", @@ -52,23 +52,18 @@ "access": "public" }, "devDependencies": { - "@rollup/plugin-commonjs": "^26.0.0", - "@rollup/plugin-json": "^6.1.0", - "@rollup/plugin-node-resolve": "^15.2.3", - "@rollup/plugin-typescript": "^11.1.6", "@silverhand/eslint-config": "6.0.1", "@silverhand/ts-config": "6.0.0", "@types/node": "^20.11.20", "@types/supertest": "^6.0.2", - "@vitest/coverage-v8": "^1.4.0", + "@vitest/coverage-v8": "^2.0.0", "eslint": "^8.56.0", "lint-staged": "^15.0.2", - "nock": "14.0.0-beta.7", + "nock": "14.0.0-beta.9", "prettier": "^3.0.0", - "rollup": "^4.12.0", - "rollup-plugin-output-size": "^1.3.0", "supertest": "^7.0.0", - "typescript": "^5.3.3", - "vitest": "^1.4.0" + "tsup": "^8.1.0", + "typescript": "^5.5.3", + "vitest": "^2.0.0" } } diff --git a/packages/connectors/connector-kakao/CHANGELOG.md b/packages/connectors/connector-kakao/CHANGELOG.md index 813a9f758ef..15c2b083ef6 100644 --- a/packages/connectors/connector-kakao/CHANGELOG.md +++ b/packages/connectors/connector-kakao/CHANGELOG.md @@ -1,5 +1,15 @@ # @logto/connector-kakao +## 1.3.0 + +### Minor Changes + +- 510f681fa: use tsup for building + + We've updated some of the packages to use `tsup` for building. This will make the build process faster, and should not affect the functionality of the packages. + + Use minor version bump to catch your attention. + ## 1.2.1 ### Patch Changes diff --git a/packages/connectors/connector-kakao/package.json b/packages/connectors/connector-kakao/package.json index 900f095e6c5..3c0091e4ea2 100644 --- a/packages/connectors/connector-kakao/package.json +++ b/packages/connectors/connector-kakao/package.json @@ -1,14 +1,14 @@ { "name": "@logto/connector-kakao", - "version": "1.2.1", + "version": "1.3.0", "description": "Kakao connector implementation.", "author": "Kyungyoon Kim. ", "dependencies": { "@logto/connector-kit": "workspace:^4.0.0", "@silverhand/essentials": "^2.9.1", "got": "^14.0.0", - "snakecase-keys": "^8.0.0", - "zod": "^3.22.4" + "snakecase-keys": "^8.0.1", + "zod": "^3.23.8" }, "main": "./lib/index.js", "module": "./lib/index.js", @@ -23,9 +23,9 @@ ], "scripts": { "precommit": "lint-staged", - "build:test": "rm -rf lib/ && tsc -p tsconfig.test.json --sourcemap", - "build": "rm -rf lib/ && tsc -p tsconfig.build.json --noEmit && rollup -c", - "dev": "tsc -p tsconfig.build.json --watch --preserveWatchOutput --incremental", + "check": "tsc --noEmit", + "build": "tsup", + "dev": "tsup --watch", "lint": "eslint --ext .ts src", "lint:report": "pnpm lint --format json --output-file report.json", "test": "vitest src", @@ -52,23 +52,18 @@ "access": "public" }, "devDependencies": { - "@rollup/plugin-commonjs": "^26.0.0", - "@rollup/plugin-json": "^6.1.0", - "@rollup/plugin-node-resolve": "^15.2.3", - "@rollup/plugin-typescript": "^11.1.6", "@silverhand/eslint-config": "6.0.1", "@silverhand/ts-config": "6.0.0", "@types/node": "^20.11.20", "@types/supertest": "^6.0.2", - "@vitest/coverage-v8": "^1.4.0", + "@vitest/coverage-v8": "^2.0.0", "eslint": "^8.56.0", "lint-staged": "^15.0.2", "nock": "^13.3.1", "prettier": "^3.0.0", - "rollup": "^4.12.0", - "rollup-plugin-output-size": "^1.3.0", "supertest": "^7.0.0", - "typescript": "^5.3.3", - "vitest": "^1.4.0" + "tsup": "^8.1.0", + "typescript": "^5.5.3", + "vitest": "^2.0.0" } } diff --git a/packages/connectors/connector-logto-email/CHANGELOG.md b/packages/connectors/connector-logto-email/CHANGELOG.md index 2a7dbe906db..727a8e00f84 100644 --- a/packages/connectors/connector-logto-email/CHANGELOG.md +++ b/packages/connectors/connector-logto-email/CHANGELOG.md @@ -1,5 +1,15 @@ # @logto/connector-logto-email +## 1.2.0 + +### Minor Changes + +- 510f681fa: use tsup for building + + We've updated some of the packages to use `tsup` for building. This will make the build process faster, and should not affect the functionality of the packages. + + Use minor version bump to catch your attention. + ## 1.1.2 ### Patch Changes diff --git a/packages/connectors/connector-logto-email/package.json b/packages/connectors/connector-logto-email/package.json index d209481cfcc..ff9df9cd506 100644 --- a/packages/connectors/connector-logto-email/package.json +++ b/packages/connectors/connector-logto-email/package.json @@ -1,14 +1,14 @@ { "name": "@logto/connector-logto-email", - "version": "1.1.2", + "version": "1.2.0", "description": "Logto email connector.", "author": "Silverhand Inc. ", "dependencies": { "@logto/connector-kit": "workspace:^4.0.0", "@silverhand/essentials": "^2.9.1", "got": "^14.0.0", - "snakecase-keys": "^8.0.0", - "zod": "^3.22.4" + "snakecase-keys": "^8.0.1", + "zod": "^3.23.8" }, "main": "./lib/index.js", "module": "./lib/index.js", @@ -23,9 +23,9 @@ ], "scripts": { "precommit": "lint-staged", - "build:test": "rm -rf lib/ && tsc -p tsconfig.test.json --sourcemap", - "build": "rm -rf lib/ && tsc -p tsconfig.build.json --noEmit && rollup -c", - "dev": "tsc -p tsconfig.build.json --watch --preserveWatchOutput --incremental", + "check": "tsc --noEmit", + "build": "tsup", + "dev": "tsup --watch", "lint": "eslint --ext .ts src", "lint:report": "pnpm lint --format json --output-file report.json", "test": "vitest src", @@ -52,24 +52,19 @@ "access": "public" }, "devDependencies": { - "@logto/cloud": "0.2.5-a7eedce", - "@rollup/plugin-commonjs": "^26.0.0", - "@rollup/plugin-json": "^6.1.0", - "@rollup/plugin-node-resolve": "^15.2.3", - "@rollup/plugin-typescript": "^11.1.6", + "@logto/cloud": "0.2.5-3b703da", "@silverhand/eslint-config": "6.0.1", "@silverhand/ts-config": "6.0.0", "@types/node": "^20.11.20", "@types/supertest": "^6.0.2", - "@vitest/coverage-v8": "^1.4.0", + "@vitest/coverage-v8": "^2.0.0", "eslint": "^8.56.0", "lint-staged": "^15.0.2", "nock": "^13.3.1", "prettier": "^3.0.0", - "rollup": "^4.12.0", - "rollup-plugin-output-size": "^1.3.0", "supertest": "^7.0.0", - "typescript": "^5.3.3", - "vitest": "^1.4.0" + "tsup": "^8.1.0", + "typescript": "^5.5.3", + "vitest": "^2.0.0" } } diff --git a/packages/connectors/connector-logto-email/src/constant.ts b/packages/connectors/connector-logto-email/src/constant.ts index 82a6157580d..a9f94c13e8f 100644 --- a/packages/connectors/connector-logto-email/src/constant.ts +++ b/packages/connectors/connector-logto-email/src/constant.ts @@ -89,7 +89,7 @@ export const defaultMetadata: ConnectorMetadata = { }, { key: 'appLogo', - label: 'App Logo', + label: 'Email logo', type: ConnectorConfigFormItemType.Text, }, ], diff --git a/packages/connectors/connector-logto-sms/CHANGELOG.md b/packages/connectors/connector-logto-sms/CHANGELOG.md index 08b1d95aa47..79ef1f9cb8d 100644 --- a/packages/connectors/connector-logto-sms/CHANGELOG.md +++ b/packages/connectors/connector-logto-sms/CHANGELOG.md @@ -1,5 +1,15 @@ # @logto/connector-logto-sms +## 1.2.0 + +### Minor Changes + +- 510f681fa: use tsup for building + + We've updated some of the packages to use `tsup` for building. This will make the build process faster, and should not affect the functionality of the packages. + + Use minor version bump to catch your attention. + ## 1.1.2 ### Patch Changes diff --git a/packages/connectors/connector-logto-sms/package.json b/packages/connectors/connector-logto-sms/package.json index 00fa94c4f50..7ad0abc5343 100644 --- a/packages/connectors/connector-logto-sms/package.json +++ b/packages/connectors/connector-logto-sms/package.json @@ -1,14 +1,14 @@ { "name": "@logto/connector-logto-sms", - "version": "1.1.2", + "version": "1.2.0", "description": "Logto SMS connector.", "author": "Silverhand Inc. ", "dependencies": { "@logto/connector-kit": "workspace:^4.0.0", "@silverhand/essentials": "^2.9.1", "got": "^14.0.0", - "snakecase-keys": "^8.0.0", - "zod": "^3.22.4" + "snakecase-keys": "^8.0.1", + "zod": "^3.23.8" }, "main": "./lib/index.js", "module": "./lib/index.js", @@ -23,9 +23,9 @@ ], "scripts": { "precommit": "lint-staged", - "build:test": "rm -rf lib/ && tsc -p tsconfig.test.json --sourcemap", - "build": "rm -rf lib/ && tsc -p tsconfig.build.json --noEmit && rollup -c", - "dev": "tsc -p tsconfig.build.json --watch --preserveWatchOutput --incremental", + "check": "tsc --noEmit", + "build": "tsup", + "dev": "tsup --watch", "lint": "eslint --ext .ts src", "lint:report": "pnpm lint --format json --output-file report.json", "test": "vitest src", @@ -52,23 +52,18 @@ "access": "public" }, "devDependencies": { - "@rollup/plugin-commonjs": "^26.0.0", - "@rollup/plugin-json": "^6.1.0", - "@rollup/plugin-node-resolve": "^15.2.3", - "@rollup/plugin-typescript": "^11.1.6", "@silverhand/eslint-config": "6.0.1", "@silverhand/ts-config": "6.0.0", "@types/node": "^20.11.20", "@types/supertest": "^6.0.2", - "@vitest/coverage-v8": "^1.4.0", + "@vitest/coverage-v8": "^2.0.0", "eslint": "^8.56.0", "lint-staged": "^15.0.2", "nock": "^13.3.1", "prettier": "^3.0.0", - "rollup": "^4.12.0", - "rollup-plugin-output-size": "^1.3.0", "supertest": "^7.0.0", - "typescript": "^5.3.3", - "vitest": "^1.4.0" + "tsup": "^8.1.0", + "typescript": "^5.5.3", + "vitest": "^2.0.0" } } diff --git a/packages/connectors/connector-logto-social-demo/CHANGELOG.md b/packages/connectors/connector-logto-social-demo/CHANGELOG.md index e641551e64a..4b77f04322b 100644 --- a/packages/connectors/connector-logto-social-demo/CHANGELOG.md +++ b/packages/connectors/connector-logto-social-demo/CHANGELOG.md @@ -1,5 +1,15 @@ # @logto/connector-logto-social-demo +## 1.2.0 + +### Minor Changes + +- 510f681fa: use tsup for building + + We've updated some of the packages to use `tsup` for building. This will make the build process faster, and should not affect the functionality of the packages. + + Use minor version bump to catch your attention. + ## 1.1.2 ### Patch Changes diff --git a/packages/connectors/connector-logto-social-demo/package.json b/packages/connectors/connector-logto-social-demo/package.json index 0e765182fbf..7ec2d21aaad 100644 --- a/packages/connectors/connector-logto-social-demo/package.json +++ b/packages/connectors/connector-logto-social-demo/package.json @@ -1,14 +1,14 @@ { "name": "@logto/connector-logto-social-demo", - "version": "1.1.2", + "version": "1.2.0", "description": "OAuth standard connector implementation.", "author": "Silverhand Inc. ", "dependencies": { "@logto/connector-kit": "workspace:^4.0.0", "@silverhand/essentials": "^2.9.1", "got": "^14.0.0", - "snakecase-keys": "^8.0.0", - "zod": "^3.22.4" + "snakecase-keys": "^8.0.1", + "zod": "^3.23.8" }, "main": "./lib/index.js", "module": "./lib/index.js", @@ -23,9 +23,9 @@ ], "scripts": { "precommit": "lint-staged", - "build:test": "rm -rf lib/ && tsc -p tsconfig.test.json --sourcemap", - "build": "rm -rf lib/ && tsc -p tsconfig.build.json --noEmit && rollup -c", - "dev": "tsc -p tsconfig.build.json --watch --preserveWatchOutput --incremental", + "check": "tsc --noEmit", + "build": "tsup", + "dev": "tsup --watch", "lint": "eslint --ext .ts src", "lint:report": "pnpm lint --format json --output-file report.json", "test": "vitest src", @@ -52,23 +52,18 @@ "access": "public" }, "devDependencies": { - "@rollup/plugin-commonjs": "^26.0.0", - "@rollup/plugin-json": "^6.1.0", - "@rollup/plugin-node-resolve": "^15.2.3", - "@rollup/plugin-typescript": "^11.1.6", "@silverhand/eslint-config": "6.0.1", "@silverhand/ts-config": "6.0.0", "@types/node": "^20.11.20", "@types/supertest": "^6.0.2", - "@vitest/coverage-v8": "^1.4.0", + "@vitest/coverage-v8": "^2.0.0", "eslint": "^8.56.0", "lint-staged": "^15.0.2", "nock": "^13.3.1", "prettier": "^3.0.0", - "rollup": "^4.12.0", - "rollup-plugin-output-size": "^1.3.0", "supertest": "^7.0.0", - "typescript": "^5.3.3", - "vitest": "^1.4.0" + "tsup": "^8.1.0", + "typescript": "^5.5.3", + "vitest": "^2.0.0" } } diff --git a/packages/connectors/connector-mailgun/CHANGELOG.md b/packages/connectors/connector-mailgun/CHANGELOG.md index 47a8407f9dc..f97a2c5e96a 100644 --- a/packages/connectors/connector-mailgun/CHANGELOG.md +++ b/packages/connectors/connector-mailgun/CHANGELOG.md @@ -1,5 +1,15 @@ # @logto/connector-mailgun +## 1.3.0 + +### Minor Changes + +- 510f681fa: use tsup for building + + We've updated some of the packages to use `tsup` for building. This will make the build process faster, and should not affect the functionality of the packages. + + Use minor version bump to catch your attention. + ## 1.2.2 ### Patch Changes diff --git a/packages/connectors/connector-mailgun/package.json b/packages/connectors/connector-mailgun/package.json index 07cacc5bdb8..77fd114c99b 100644 --- a/packages/connectors/connector-mailgun/package.json +++ b/packages/connectors/connector-mailgun/package.json @@ -1,14 +1,14 @@ { "name": "@logto/connector-mailgun", - "version": "1.2.2", + "version": "1.3.0", "description": "Mailgun connector for Logto.", "author": "Silverhand Inc. ", "dependencies": { "@logto/connector-kit": "workspace:^4.0.0", "@silverhand/essentials": "^2.9.1", "got": "^14.0.0", - "snakecase-keys": "^8.0.0", - "zod": "^3.22.4" + "snakecase-keys": "^8.0.1", + "zod": "^3.23.8" }, "main": "./lib/index.js", "module": "./lib/index.js", @@ -23,9 +23,9 @@ ], "scripts": { "precommit": "lint-staged", - "build:test": "rm -rf lib/ && tsc -p tsconfig.test.json --sourcemap", - "build": "rm -rf lib/ && tsc -p tsconfig.build.json --noEmit && rollup -c", - "dev": "tsc -p tsconfig.build.json --watch --preserveWatchOutput --incremental", + "check": "tsc --noEmit", + "build": "tsup", + "dev": "tsup --watch", "lint": "eslint --ext .ts src", "lint:report": "pnpm lint --format json --output-file report.json", "test": "vitest src", @@ -52,23 +52,18 @@ "access": "public" }, "devDependencies": { - "@rollup/plugin-commonjs": "^26.0.0", - "@rollup/plugin-json": "^6.1.0", - "@rollup/plugin-node-resolve": "^15.2.3", - "@rollup/plugin-typescript": "^11.1.6", "@silverhand/eslint-config": "6.0.1", "@silverhand/ts-config": "6.0.0", "@types/node": "^20.11.20", "@types/supertest": "^6.0.2", - "@vitest/coverage-v8": "^1.4.0", + "@vitest/coverage-v8": "^2.0.0", "eslint": "^8.56.0", "lint-staged": "^15.0.2", "nock": "^13.3.1", "prettier": "^3.0.0", - "rollup": "^4.12.0", - "rollup-plugin-output-size": "^1.3.0", "supertest": "^7.0.0", - "typescript": "^5.3.3", - "vitest": "^1.4.0" + "tsup": "^8.1.0", + "typescript": "^5.5.3", + "vitest": "^2.0.0" } } diff --git a/packages/connectors/connector-mock-email-alternative/CHANGELOG.md b/packages/connectors/connector-mock-email-alternative/CHANGELOG.md index c324ffcb4bc..e731249f313 100644 --- a/packages/connectors/connector-mock-email-alternative/CHANGELOG.md +++ b/packages/connectors/connector-mock-email-alternative/CHANGELOG.md @@ -1,5 +1,15 @@ # @logto/connector-mock-standard-email +## 2.1.0 + +### Minor Changes + +- 510f681fa: use tsup for building + + We've updated some of the packages to use `tsup` for building. This will make the build process faster, and should not affect the functionality of the packages. + + Use minor version bump to catch your attention. + ## 2.0.2 ### Patch Changes diff --git a/packages/connectors/connector-mock-email-alternative/package.json b/packages/connectors/connector-mock-email-alternative/package.json index 9132e8f8530..123de9a5780 100644 --- a/packages/connectors/connector-mock-email-alternative/package.json +++ b/packages/connectors/connector-mock-email-alternative/package.json @@ -1,20 +1,20 @@ { "name": "@logto/connector-mock-standard-email", - "version": "2.0.2", + "version": "2.1.0", "description": "Mock Standard Email Service connector implementation for integration tests only.", "author": "Silverhand Inc. ", "dependencies": { "@logto/connector-kit": "workspace:^4.0.0", "@silverhand/essentials": "^2.9.1", "got": "^14.0.0", - "snakecase-keys": "^8.0.0", - "zod": "^3.22.4" + "snakecase-keys": "^8.0.1", + "zod": "^3.23.8" }, "scripts": { "precommit": "lint-staged", - "build:test": "rm -rf lib/ && tsc -p tsconfig.test.json --sourcemap", - "build": "rm -rf lib/ && tsc -p tsconfig.build.json --noEmit && rollup -c", - "dev": "tsc -p tsconfig.build.json --watch --preserveWatchOutput --incremental", + "check": "tsc --noEmit", + "build": "tsup", + "dev": "tsup --watch", "lint": "eslint --ext .ts src", "lint:report": "pnpm lint --format json --output-file report.json", "test": "vitest src", @@ -52,23 +52,18 @@ "access": "public" }, "devDependencies": { - "@rollup/plugin-commonjs": "^26.0.0", - "@rollup/plugin-json": "^6.1.0", - "@rollup/plugin-node-resolve": "^15.2.3", - "@rollup/plugin-typescript": "^11.1.6", "@silverhand/eslint-config": "6.0.1", "@silverhand/ts-config": "6.0.0", "@types/node": "^20.11.20", "@types/supertest": "^6.0.2", - "@vitest/coverage-v8": "^1.4.0", + "@vitest/coverage-v8": "^2.0.0", "eslint": "^8.56.0", "lint-staged": "^15.0.2", "nock": "^13.3.1", "prettier": "^3.0.0", - "rollup": "^4.12.0", - "rollup-plugin-output-size": "^1.3.0", "supertest": "^7.0.0", - "typescript": "^5.3.3", - "vitest": "^1.4.0" + "tsup": "^8.1.0", + "typescript": "^5.5.3", + "vitest": "^2.0.0" } } diff --git a/packages/connectors/connector-mock-email/CHANGELOG.md b/packages/connectors/connector-mock-email/CHANGELOG.md index 9f0a121575b..ef4375a6f7c 100644 --- a/packages/connectors/connector-mock-email/CHANGELOG.md +++ b/packages/connectors/connector-mock-email/CHANGELOG.md @@ -1,5 +1,15 @@ # @logto/connector-mock-email +## 2.1.0 + +### Minor Changes + +- 510f681fa: use tsup for building + + We've updated some of the packages to use `tsup` for building. This will make the build process faster, and should not affect the functionality of the packages. + + Use minor version bump to catch your attention. + ## 2.0.2 ### Patch Changes diff --git a/packages/connectors/connector-mock-email/package.json b/packages/connectors/connector-mock-email/package.json index f1b4024346a..9f746fe443e 100644 --- a/packages/connectors/connector-mock-email/package.json +++ b/packages/connectors/connector-mock-email/package.json @@ -1,20 +1,20 @@ { "name": "@logto/connector-mock-email", - "version": "2.0.2", + "version": "2.1.0", "description": "Mock Email Service connector implementation for integration tests only.", "author": "Silverhand Inc. ", "dependencies": { "@logto/connector-kit": "workspace:^4.0.0", "@silverhand/essentials": "^2.9.1", "got": "^14.0.0", - "snakecase-keys": "^8.0.0", - "zod": "^3.22.4" + "snakecase-keys": "^8.0.1", + "zod": "^3.23.8" }, "scripts": { "precommit": "lint-staged", - "build:test": "rm -rf lib/ && tsc -p tsconfig.test.json --sourcemap", - "build": "rm -rf lib/ && tsc -p tsconfig.build.json --noEmit && rollup -c", - "dev": "tsc -p tsconfig.build.json --watch --preserveWatchOutput --incremental", + "check": "tsc --noEmit", + "build": "tsup", + "dev": "tsup --watch", "lint": "eslint --ext .ts src", "lint:report": "pnpm lint --format json --output-file report.json", "test": "vitest src", @@ -52,23 +52,18 @@ "access": "public" }, "devDependencies": { - "@rollup/plugin-commonjs": "^26.0.0", - "@rollup/plugin-json": "^6.1.0", - "@rollup/plugin-node-resolve": "^15.2.3", - "@rollup/plugin-typescript": "^11.1.6", "@silverhand/eslint-config": "6.0.1", "@silverhand/ts-config": "6.0.0", "@types/node": "^20.11.20", "@types/supertest": "^6.0.2", - "@vitest/coverage-v8": "^1.4.0", + "@vitest/coverage-v8": "^2.0.0", "eslint": "^8.56.0", "lint-staged": "^15.0.2", "nock": "^13.3.1", "prettier": "^3.0.0", - "rollup": "^4.12.0", - "rollup-plugin-output-size": "^1.3.0", "supertest": "^7.0.0", - "typescript": "^5.3.3", - "vitest": "^1.4.0" + "tsup": "^8.1.0", + "typescript": "^5.5.3", + "vitest": "^2.0.0" } } diff --git a/packages/connectors/connector-mock-sms/CHANGELOG.md b/packages/connectors/connector-mock-sms/CHANGELOG.md index db5aedaeb47..6167208e2ab 100644 --- a/packages/connectors/connector-mock-sms/CHANGELOG.md +++ b/packages/connectors/connector-mock-sms/CHANGELOG.md @@ -1,5 +1,15 @@ # @logto/connector-mock-sms +## 2.1.0 + +### Minor Changes + +- 510f681fa: use tsup for building + + We've updated some of the packages to use `tsup` for building. This will make the build process faster, and should not affect the functionality of the packages. + + Use minor version bump to catch your attention. + ## 2.0.2 ### Patch Changes diff --git a/packages/connectors/connector-mock-sms/package.json b/packages/connectors/connector-mock-sms/package.json index 1ae46035a40..fcc57351ddf 100644 --- a/packages/connectors/connector-mock-sms/package.json +++ b/packages/connectors/connector-mock-sms/package.json @@ -1,20 +1,20 @@ { "name": "@logto/connector-mock-sms", - "version": "2.0.2", + "version": "2.1.0", "description": "Mock SMS connector implementation for integration tests only.", "author": "Silverhand Inc. ", "dependencies": { "@logto/connector-kit": "workspace:^4.0.0", "@silverhand/essentials": "^2.9.1", "got": "^14.0.0", - "snakecase-keys": "^8.0.0", - "zod": "^3.22.4" + "snakecase-keys": "^8.0.1", + "zod": "^3.23.8" }, "scripts": { "precommit": "lint-staged", - "build:test": "rm -rf lib/ && tsc -p tsconfig.test.json --sourcemap", - "build": "rm -rf lib/ && tsc -p tsconfig.build.json --noEmit && rollup -c", - "dev": "tsc -p tsconfig.build.json --watch --preserveWatchOutput --incremental", + "check": "tsc --noEmit", + "build": "tsup", + "dev": "tsup --watch", "lint": "eslint --ext .ts src", "lint:report": "pnpm lint --format json --output-file report.json", "test": "vitest src", @@ -52,23 +52,18 @@ "access": "public" }, "devDependencies": { - "@rollup/plugin-commonjs": "^26.0.0", - "@rollup/plugin-json": "^6.1.0", - "@rollup/plugin-node-resolve": "^15.2.3", - "@rollup/plugin-typescript": "^11.1.6", "@silverhand/eslint-config": "6.0.1", "@silverhand/ts-config": "6.0.0", "@types/node": "^20.11.20", "@types/supertest": "^6.0.2", - "@vitest/coverage-v8": "^1.4.0", + "@vitest/coverage-v8": "^2.0.0", "eslint": "^8.56.0", "lint-staged": "^15.0.2", "nock": "^13.3.1", "prettier": "^3.0.0", - "rollup": "^4.12.0", - "rollup-plugin-output-size": "^1.3.0", "supertest": "^7.0.0", - "typescript": "^5.3.3", - "vitest": "^1.4.0" + "tsup": "^8.1.0", + "typescript": "^5.5.3", + "vitest": "^2.0.0" } } diff --git a/packages/connectors/connector-mock-social/CHANGELOG.md b/packages/connectors/connector-mock-social/CHANGELOG.md index 44cbf2e1725..1e80ef4dabe 100644 --- a/packages/connectors/connector-mock-social/CHANGELOG.md +++ b/packages/connectors/connector-mock-social/CHANGELOG.md @@ -1,5 +1,15 @@ # @logto/connector-mock-social +## 1.3.0 + +### Minor Changes + +- 510f681fa: use tsup for building + + We've updated some of the packages to use `tsup` for building. This will make the build process faster, and should not affect the functionality of the packages. + + Use minor version bump to catch your attention. + ## 1.2.1 ### Patch Changes diff --git a/packages/connectors/connector-mock-social/package.json b/packages/connectors/connector-mock-social/package.json index 902cecb18f7..700247542c4 100644 --- a/packages/connectors/connector-mock-social/package.json +++ b/packages/connectors/connector-mock-social/package.json @@ -1,20 +1,20 @@ { "name": "@logto/connector-mock-social", - "version": "1.2.1", + "version": "1.3.0", "description": "Social mock connector implementation.", "author": "Silverhand Inc. ", "dependencies": { "@logto/connector-kit": "workspace:^4.0.0", "@silverhand/essentials": "^2.9.1", "got": "^14.0.0", - "snakecase-keys": "^8.0.0", - "zod": "^3.22.4" + "snakecase-keys": "^8.0.1", + "zod": "^3.23.8" }, "scripts": { "precommit": "lint-staged", - "build:test": "rm -rf lib/ && tsc -p tsconfig.test.json --sourcemap", - "build": "rm -rf lib/ && tsc -p tsconfig.build.json --noEmit && rollup -c", - "dev": "tsc -p tsconfig.build.json --watch --preserveWatchOutput --incremental", + "check": "tsc --noEmit", + "build": "tsup", + "dev": "tsup --watch", "lint": "eslint --ext .ts src", "lint:report": "pnpm lint --format json --output-file report.json", "test": "vitest src", @@ -52,23 +52,18 @@ "access": "public" }, "devDependencies": { - "@rollup/plugin-commonjs": "^26.0.0", - "@rollup/plugin-json": "^6.1.0", - "@rollup/plugin-node-resolve": "^15.2.3", - "@rollup/plugin-typescript": "^11.1.6", "@silverhand/eslint-config": "6.0.1", "@silverhand/ts-config": "6.0.0", "@types/node": "^20.11.20", "@types/supertest": "^6.0.2", - "@vitest/coverage-v8": "^1.4.0", + "@vitest/coverage-v8": "^2.0.0", "eslint": "^8.56.0", "lint-staged": "^15.0.2", "nock": "^13.3.1", "prettier": "^3.0.0", - "rollup": "^4.12.0", - "rollup-plugin-output-size": "^1.3.0", "supertest": "^7.0.0", - "typescript": "^5.3.3", - "vitest": "^1.4.0" + "tsup": "^8.1.0", + "typescript": "^5.5.3", + "vitest": "^2.0.0" } } diff --git a/packages/connectors/connector-mock-social/src/index.ts b/packages/connectors/connector-mock-social/src/index.ts index 77c24b645a3..f9751ba22e5 100644 --- a/packages/connectors/connector-mock-social/src/index.ts +++ b/packages/connectors/connector-mock-social/src/index.ts @@ -30,7 +30,7 @@ const getAuthorizationUri: GetAuthorizationUri = async ( } } - return `http://mock.social.com/?state=${state}&redirect_uri=${redirectUri}`; + return `http://mock-social/?state=${state}&redirect_uri=${redirectUri}`; }; const getUserInfo: GetUserInfo = async (data, getSession) => { @@ -39,6 +39,8 @@ const getUserInfo: GetUserInfo = async (data, getSession) => { userId: z.optional(z.string()), email: z.string().optional(), phone: z.string().optional(), + name: z.string().optional(), + avatar: z.string().optional(), }); const result = dataGuard.safeParse(data); diff --git a/packages/connectors/connector-mygovid/package.json b/packages/connectors/connector-mygovid/package.json index 91ccf411e4d..7a086836dbf 100644 --- a/packages/connectors/connector-mygovid/package.json +++ b/packages/connectors/connector-mygovid/package.json @@ -26,9 +26,9 @@ ], "scripts": { "precommit": "lint-staged", - "build:test": "rm -rf lib/ && tsc -p tsconfig.test.json --sourcemap", - "build": "rm -rf lib/ && tsc -p tsconfig.build.json --noEmit && rollup -c", - "dev": "tsc -p tsconfig.build.json --watch --preserveWatchOutput --incremental", + "check": "tsc --noEmit", + "build": "tsup", + "dev": "tsup --watch", "lint": "eslint --ext .ts src", "lint:report": "pnpm lint --format json --output-file report.json", "test": "vitest src", diff --git a/packages/connectors/connector-naver/CHANGELOG.md b/packages/connectors/connector-naver/CHANGELOG.md index 565c435eb0d..bda3cffdf43 100644 --- a/packages/connectors/connector-naver/CHANGELOG.md +++ b/packages/connectors/connector-naver/CHANGELOG.md @@ -1,5 +1,15 @@ # @logto/connector-naver +## 1.3.0 + +### Minor Changes + +- 510f681fa: use tsup for building + + We've updated some of the packages to use `tsup` for building. This will make the build process faster, and should not affect the functionality of the packages. + + Use minor version bump to catch your attention. + ## 1.2.1 ### Patch Changes diff --git a/packages/connectors/connector-naver/package.json b/packages/connectors/connector-naver/package.json index 22a3e422816..8789957438f 100644 --- a/packages/connectors/connector-naver/package.json +++ b/packages/connectors/connector-naver/package.json @@ -1,14 +1,14 @@ { "name": "@logto/connector-naver", - "version": "1.2.1", + "version": "1.3.0", "description": "Naver connector implementation.", "author": "Kyungyoon Kim. ", "dependencies": { "@logto/connector-kit": "workspace:^4.0.0", "@silverhand/essentials": "^2.9.1", "got": "^14.0.0", - "snakecase-keys": "^8.0.0", - "zod": "^3.22.4" + "snakecase-keys": "^8.0.1", + "zod": "^3.23.8" }, "main": "./lib/index.js", "module": "./lib/index.js", @@ -23,9 +23,9 @@ ], "scripts": { "precommit": "lint-staged", - "build:test": "rm -rf lib/ && tsc -p tsconfig.test.json --sourcemap", - "build": "rm -rf lib/ && tsc -p tsconfig.build.json --noEmit && rollup -c", - "dev": "tsc -p tsconfig.build.json --watch --preserveWatchOutput --incremental", + "check": "tsc --noEmit", + "build": "tsup", + "dev": "tsup --watch", "lint": "eslint --ext .ts src", "lint:report": "pnpm lint --format json --output-file report.json", "test": "vitest src", @@ -52,23 +52,18 @@ "access": "public" }, "devDependencies": { - "@rollup/plugin-commonjs": "^26.0.0", - "@rollup/plugin-json": "^6.1.0", - "@rollup/plugin-node-resolve": "^15.2.3", - "@rollup/plugin-typescript": "^11.1.6", "@silverhand/eslint-config": "6.0.1", "@silverhand/ts-config": "6.0.0", "@types/node": "^20.11.20", "@types/supertest": "^6.0.2", - "@vitest/coverage-v8": "^1.4.0", + "@vitest/coverage-v8": "^2.0.0", "eslint": "^8.56.0", "lint-staged": "^15.0.2", "nock": "^13.3.1", "prettier": "^3.0.0", - "rollup": "^4.12.0", - "rollup-plugin-output-size": "^1.3.0", "supertest": "^7.0.0", - "typescript": "^5.3.3", - "vitest": "^1.4.0" + "tsup": "^8.1.0", + "typescript": "^5.5.3", + "vitest": "^2.0.0" } } diff --git a/packages/connectors/connector-oauth2/CHANGELOG.md b/packages/connectors/connector-oauth2/CHANGELOG.md index 6943b878a57..fa90526996a 100644 --- a/packages/connectors/connector-oauth2/CHANGELOG.md +++ b/packages/connectors/connector-oauth2/CHANGELOG.md @@ -1,5 +1,15 @@ # @logto/connector-oauth +## 1.4.0 + +### Minor Changes + +- 510f681fa: use tsup for building + + We've updated some of the packages to use `tsup` for building. This will make the build process faster, and should not affect the functionality of the packages. + + Use minor version bump to catch your attention. + ## 1.3.1 ### Patch Changes diff --git a/packages/connectors/connector-oauth2/package.json b/packages/connectors/connector-oauth2/package.json index 9fb22112f82..097b6073f97 100644 --- a/packages/connectors/connector-oauth2/package.json +++ b/packages/connectors/connector-oauth2/package.json @@ -1,17 +1,17 @@ { "name": "@logto/connector-oauth", - "version": "1.3.1", + "version": "1.4.0", "description": "OAuth standard connector implementation.", "author": "Silverhand Inc. ", "dependencies": { "@logto/connector-kit": "workspace:^4.0.0", "@logto/shared": "workspace:^3.1.1", "@silverhand/essentials": "^2.9.1", - "jose": "^5.0.0", + "jose": "^5.6.3", "ky": "^1.2.3", "query-string": "^9.0.0", - "snakecase-keys": "^8.0.0", - "zod": "^3.22.4" + "snakecase-keys": "^8.0.1", + "zod": "^3.23.8" }, "main": "./lib/index.js", "module": "./lib/index.js", @@ -26,15 +26,16 @@ ], "scripts": { "precommit": "lint-staged", - "build:test": "rm -rf lib/ && tsc -p tsconfig.test.json --sourcemap", - "build": "rm -rf lib/ && tsc -p tsconfig.build.json --noEmit && rollup -c", - "dev": "tsc -p tsconfig.build.json --watch --preserveWatchOutput --incremental", + "check": "tsc --noEmit", + "build": "tsup && tsc --declaration --emitDeclarationOnly", + "dev": "tsup --watch", "lint": "eslint --ext .ts src", "lint:report": "pnpm lint --format json --output-file report.json", "test": "vitest src", "test:ci": "pnpm run test --silent --coverage", "prepublishOnly": "pnpm build", - "prepack": "pnpm build" + "prepack": "pnpm build", + "build:test": "pnpm build" }, "engines": { "node": "^20.9.0" @@ -56,23 +57,18 @@ "access": "public" }, "devDependencies": { - "@rollup/plugin-commonjs": "^26.0.0", - "@rollup/plugin-json": "^6.1.0", - "@rollup/plugin-node-resolve": "^15.2.3", - "@rollup/plugin-typescript": "^11.1.6", "@silverhand/eslint-config": "6.0.1", "@silverhand/ts-config": "6.0.0", "@types/node": "^20.11.20", "@types/supertest": "^6.0.2", - "@vitest/coverage-v8": "^1.4.0", + "@vitest/coverage-v8": "^2.0.0", "eslint": "^8.56.0", "lint-staged": "^15.0.2", - "nock": "14.0.0-beta.7", + "nock": "14.0.0-beta.9", "prettier": "^3.0.0", - "rollup": "^4.12.0", - "rollup-plugin-output-size": "^1.3.0", "supertest": "^7.0.0", - "typescript": "^5.3.3", - "vitest": "^1.4.0" + "tsup": "^8.1.0", + "typescript": "^5.5.3", + "vitest": "^2.0.0" } } diff --git a/packages/connectors/connector-ogcio-entraid/package.json b/packages/connectors/connector-ogcio-entraid/package.json index 4e944a87e27..214f3af96b8 100644 --- a/packages/connectors/connector-ogcio-entraid/package.json +++ b/packages/connectors/connector-ogcio-entraid/package.json @@ -23,9 +23,9 @@ ], "scripts": { "precommit": "lint-staged", - "build:test": "rm -rf lib/ && tsc -p tsconfig.test.json --sourcemap", - "build": "rm -rf lib/ && tsc -p tsconfig.build.json --noEmit && rollup -c", - "dev": "tsc -p tsconfig.build.json --watch --preserveWatchOutput --incremental", + "check": "tsc --noEmit", + "build": "tsup", + "dev": "tsup --watch", "lint": "eslint --ext .ts src", "lint:report": "pnpm lint --format json --output-file report.json", "test": "vitest src", diff --git a/packages/connectors/connector-oidc/CHANGELOG.md b/packages/connectors/connector-oidc/CHANGELOG.md index 8ff39c430b4..e90805f28d1 100644 --- a/packages/connectors/connector-oidc/CHANGELOG.md +++ b/packages/connectors/connector-oidc/CHANGELOG.md @@ -1,5 +1,20 @@ # @logto/connector-oidc +## 1.4.0 + +### Minor Changes + +- 510f681fa: use tsup for building + + We've updated some of the packages to use `tsup` for building. This will make the build process faster, and should not affect the functionality of the packages. + + Use minor version bump to catch your attention. + +### Patch Changes + +- Updated dependencies [510f681fa] + - @logto/connector-oauth@1.4.0 + ## 1.3.1 ### Patch Changes diff --git a/packages/connectors/connector-oidc/package.json b/packages/connectors/connector-oidc/package.json index bffa1bbc509..432e3ccd0ca 100644 --- a/packages/connectors/connector-oidc/package.json +++ b/packages/connectors/connector-oidc/package.json @@ -1,17 +1,17 @@ { "name": "@logto/connector-oidc", - "version": "1.3.1", + "version": "1.4.0", "description": "OIDC standard connector implementation.", "dependencies": { "@logto/connector-kit": "workspace:^4.0.0", - "@logto/connector-oauth": "workspace:^1.3.1", + "@logto/connector-oauth": "workspace:^1.4.0", "@logto/shared": "workspace:^3.1.1", "@silverhand/essentials": "^2.9.1", - "jose": "^5.0.0", + "jose": "^5.6.3", "ky": "^1.2.3", "nanoid": "^5.0.1", - "snakecase-keys": "^8.0.0", - "zod": "^3.22.4" + "snakecase-keys": "^8.0.1", + "zod": "^3.23.8" }, "main": "./lib/index.js", "module": "./lib/index.js", @@ -26,9 +26,9 @@ ], "scripts": { "precommit": "lint-staged", - "build:test": "rm -rf lib/ && tsc -p tsconfig.test.json --sourcemap", - "build": "rm -rf lib/ && tsc -p tsconfig.build.json --noEmit && rollup -c", - "dev": "tsc -p tsconfig.build.json --watch --preserveWatchOutput --incremental", + "check": "tsc --noEmit", + "build": "tsup", + "dev": "tsup --watch", "lint": "eslint --ext .ts src", "lint:report": "pnpm lint --format json --output-file report.json", "test": "vitest src", @@ -55,23 +55,18 @@ "access": "public" }, "devDependencies": { - "@rollup/plugin-commonjs": "^26.0.0", - "@rollup/plugin-json": "^6.1.0", - "@rollup/plugin-node-resolve": "^15.2.3", - "@rollup/plugin-typescript": "^11.1.6", "@silverhand/eslint-config": "6.0.1", "@silverhand/ts-config": "6.0.0", "@types/node": "^20.11.20", "@types/supertest": "^6.0.2", - "@vitest/coverage-v8": "^1.4.0", + "@vitest/coverage-v8": "^2.0.0", "eslint": "^8.56.0", "lint-staged": "^15.0.2", - "nock": "14.0.0-beta.7", + "nock": "14.0.0-beta.9", "prettier": "^3.0.0", - "rollup": "^4.12.0", - "rollup-plugin-output-size": "^1.3.0", "supertest": "^7.0.0", - "typescript": "^5.3.3", - "vitest": "^1.4.0" + "tsup": "^8.1.0", + "typescript": "^5.5.3", + "vitest": "^2.0.0" } } diff --git a/packages/connectors/connector-postmark/CHANGELOG.md b/packages/connectors/connector-postmark/CHANGELOG.md new file mode 100644 index 00000000000..6e153566253 --- /dev/null +++ b/packages/connectors/connector-postmark/CHANGELOG.md @@ -0,0 +1,7 @@ +# @logto/connector-postmark + +## 1.0.0 + +### Major Changes + +- e9581d8b4: add postmark connector diff --git a/packages/connectors/connector-postmark/README.md b/packages/connectors/connector-postmark/README.md new file mode 100644 index 00000000000..f456741d78b --- /dev/null +++ b/packages/connectors/connector-postmark/README.md @@ -0,0 +1,61 @@ +# Postmark connector + +Logto connector for Postmark email service. + +## Get started + +Postmark is a mail platform for transactional and marketing email. We can use its email sending function to send a _verification code_. + +## Register Postmark account + +Create a new account at [Postmark website](https://postmark.com/). You may skip this step if you've already got an account. + +## Configure your connector + +Fill out the `serverToken` field with the Server Token you find under settings for your +server in Postmark. + +Fill out the `fromEmail` field with the senders' _From Address_. + +In order to enable full user flows, templates with usageType `Register`, `SignIn`, `ForgotPassword` and `Generic` are required + +Here is an example of Postmark connector template JSON. + +```jsonc +[ + { + "usageType": "Register", + "templateAlias": "logto-register" + }, + { + "usageType": "SignIn", + "templateAlias": "logto-sign-in" + }, + { + "usageType": "ForgotPassword", + "templateAlias": "logto-forgot-password" + }, + { + "usageType": "Generic", + "templateAlias": "logto-generic" + }, +] +``` + +## Test Postmark email connector + +You can type in an email address and click on "Send" to see whether the settings can work before "Save and Done". + +That's it. Don't forget to [Enable connector in sign-in experience](https://docs.logto.io/docs/tutorials/get-started/passwordless-sign-in-by-adding-connectors#enable-sms-or-email-passwordless-sign-in) + +## Config types + +| Name | Type | +|-------------|-------------------| +| serverToken | string | +| fromEmail | string | + +| Template Properties | Type | Enum values | +|---------------------|-------------|------------------------------------------------------| +| usageType | enum string | 'Register' \| 'SignIn' \| 'ForgotPassword' \| 'Generic' | +| templateAlias | string | N/A | diff --git a/packages/connectors/connector-postmark/logo.svg b/packages/connectors/connector-postmark/logo.svg new file mode 100644 index 00000000000..7826748742a --- /dev/null +++ b/packages/connectors/connector-postmark/logo.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/packages/connectors/connector-postmark/package.json b/packages/connectors/connector-postmark/package.json new file mode 100644 index 00000000000..ab8fd454f22 --- /dev/null +++ b/packages/connectors/connector-postmark/package.json @@ -0,0 +1,68 @@ +{ + "name": "@logto/connector-postmark", + "version": "1.0.0", + "description": "Postmark connector implementation.", + "author": "Sten Sandvik ", + "dependencies": { + "@logto/connector-kit": "workspace:^4.0.0", + "@silverhand/essentials": "^2.9.0", + "postmark": "^4.0.2", + "zod": "^3.22.4" + }, + "devDependencies": { + "@silverhand/eslint-config": "6.0.1", + "@silverhand/ts-config": "6.0.0", + "@types/node": "^20.11.20", + "@types/supertest": "^6.0.2", + "@vitest/coverage-v8": "^2.0.0", + "eslint": "^8.56.0", + "lint-staged": "^15.0.2", + "nock": "14.0.0-beta.9", + "prettier": "^3.0.0", + "supertest": "^7.0.0", + "tsup": "^8.1.0", + "typescript": "^5.5.3", + "vitest": "^2.0.0" + }, + "main": "./lib/index.js", + "module": "./lib/index.js", + "exports": "./lib/index.js", + "license": "MPL-2.0", + "type": "module", + "files": [ + "lib", + "docs", + "logo.svg", + "logo-dark.svg" + ], + "scripts": { + "precommit": "lint-staged", + "check": "tsc --noEmit", + "build": "tsup", + "dev": "tsup --watch", + "lint": "eslint --ext .ts src", + "lint:report": "pnpm lint --format json --output-file report.json", + "test": "vitest src", + "test:ci": "pnpm run test --silent --coverage", + "prepublishOnly": "pnpm build" + }, + "engines": { + "node": "^20.9.0" + }, + "eslintConfig": { + "extends": "@silverhand", + "settings": { + "import/core-modules": [ + "@silverhand/essentials", + "got", + "nock", + "snakecase-keys", + "zod" + ] + } + }, + "prettier": "@silverhand/eslint-config/.prettierrc", + "publishConfig": { + "access": "public" + } +} diff --git a/packages/connectors/connector-postmark/src/constant.ts b/packages/connectors/connector-postmark/src/constant.ts new file mode 100644 index 00000000000..694012e0934 --- /dev/null +++ b/packages/connectors/connector-postmark/src/constant.ts @@ -0,0 +1,57 @@ +import type { ConnectorMetadata } from '@logto/connector-kit'; +import { ConnectorConfigFormItemType } from '@logto/connector-kit'; + +export const defaultMetadata: ConnectorMetadata = { + id: 'postmark-mail', + target: 'postmark-mail', + platform: null, + name: { + en: 'Postmark Mail', + }, + logo: './logo.svg', + logoDark: null, + description: { + en: 'Postmark is a mail sending platform.', + }, + readme: './README.md', + formItems: [ + { + key: 'serverToken', + label: 'Server Token', + type: ConnectorConfigFormItemType.Text, + required: true, + placeholder: '', + }, + { + key: 'fromEmail', + label: 'From Email', + type: ConnectorConfigFormItemType.Text, + required: true, + placeholder: '', + }, + { + key: 'templates', + label: 'Templates', + type: ConnectorConfigFormItemType.Json, + required: true, + defaultValue: [ + { + usageType: 'SignIn', + templateAlias: 'logto-sign-in', + }, + { + usageType: 'Register', + templateAlias: 'logto-register', + }, + { + usageType: 'ForgotPassword', + templateAlias: 'logto-forgot-password', + }, + { + usageType: 'Generic', + templateAlias: 'logto-generic', + }, + ], + }, + ], +}; diff --git a/packages/connectors/connector-postmark/src/index.test.ts b/packages/connectors/connector-postmark/src/index.test.ts new file mode 100644 index 00000000000..634a0bddaa5 --- /dev/null +++ b/packages/connectors/connector-postmark/src/index.test.ts @@ -0,0 +1,42 @@ +import { TemplateType } from '@logto/connector-kit'; + +import { mockedConfig } from './mock.js'; + +const getConfig = vi.fn().mockResolvedValue(mockedConfig); +const sendEmailWithTemplate = vi.fn(); +vi.mock('postmark', () => ({ + ServerClient: vi.fn(() => ({ + sendEmailWithTemplate, + })), +})); + +const { default: createConnector } = await import('./index.js'); + +describe('Postmark connector', () => { + it('init without throwing errors', async () => { + await expect(createConnector({ getConfig })).resolves.not.toThrow(); + }); + + describe('sendMessage()', () => { + afterEach(() => { + vi.clearAllMocks(); + }); + + it('should call sendEmailWithTemplate() with correct template and content', async () => { + const connector = await createConnector({ getConfig }); + await connector.sendMessage({ + to: 'to@email.com', + type: TemplateType.SignIn, + payload: { code: '1234' }, + }); + expect(sendEmailWithTemplate).toHaveBeenCalledWith( + expect.objectContaining({ + From: mockedConfig.fromEmail, + TemplateAlias: 'logto-sign-in', + To: 'to@email.com', + TemplateModel: { code: '1234' }, + }) + ); + }); + }); +}); diff --git a/packages/connectors/connector-postmark/src/index.ts b/packages/connectors/connector-postmark/src/index.ts new file mode 100644 index 00000000000..6039796cdab --- /dev/null +++ b/packages/connectors/connector-postmark/src/index.ts @@ -0,0 +1,65 @@ +import { assert } from '@silverhand/essentials'; + +import type { + GetConnectorConfig, + CreateConnector, + EmailConnector, + SendMessageFunction, +} from '@logto/connector-kit'; +import { + ConnectorError, + ConnectorErrorCodes, + validateConfig, + ConnectorType, +} from '@logto/connector-kit'; +import { ServerClient } from 'postmark'; + +import { defaultMetadata } from './constant.js'; +import { postmarkConfigGuard } from './types.js'; + +const sendMessage = + (getConfig: GetConnectorConfig): SendMessageFunction => + async (data, inputConfig) => { + const { to, type, payload } = data; + + const config = inputConfig ?? (await getConfig(defaultMetadata.id)); + validateConfig(config, postmarkConfigGuard); + + const { serverToken, fromEmail, templates } = config; + const template = templates.find((template) => template.usageType === type); + + assert( + template, + new ConnectorError( + ConnectorErrorCodes.TemplateNotFound, + `Template not found for type: ${type}` + ) + ); + + const client = new ServerClient(serverToken); + + try { + await client.sendEmailWithTemplate({ + From: fromEmail, + TemplateAlias: template.templateAlias, + To: to, + TemplateModel: payload, + }); + } catch (error: unknown) { + throw new ConnectorError( + ConnectorErrorCodes.General, + error instanceof Error ? error.message : '' + ); + } + }; + +const createPostmarkConnector: CreateConnector = async ({ getConfig }) => { + return { + metadata: defaultMetadata, + type: ConnectorType.Email, + configGuard: postmarkConfigGuard, + sendMessage: sendMessage(getConfig), + }; +}; + +export default createPostmarkConnector; diff --git a/packages/connectors/connector-postmark/src/mock.ts b/packages/connectors/connector-postmark/src/mock.ts new file mode 100644 index 00000000000..457b541ccd1 --- /dev/null +++ b/packages/connectors/connector-postmark/src/mock.ts @@ -0,0 +1,26 @@ +import type { PostmarkConfig } from './types.js'; + +export const mockedServerToken = 'serverToken'; + +export const mockedConfig: PostmarkConfig = { + serverToken: mockedServerToken, + fromEmail: 'noreply@logto.test.io', + templates: [ + { + usageType: 'SignIn', + templateAlias: 'logto-sign-in', + }, + { + usageType: 'Register', + templateAlias: 'logto-register', + }, + { + usageType: 'ForgotPassword', + templateAlias: 'logto-forgot-password', + }, + { + usageType: 'Generic', + templateAlias: 'logto-generic', + }, + ], +}; diff --git a/packages/connectors/connector-postmark/src/types.ts b/packages/connectors/connector-postmark/src/types.ts new file mode 100644 index 00000000000..ff5a06cd636 --- /dev/null +++ b/packages/connectors/connector-postmark/src/types.ts @@ -0,0 +1,32 @@ +import { z } from 'zod'; + +/** + * UsageType here is used to specify the use case of the template, can be either + * 'Register', 'SignIn', 'ForgotPassword', 'Generic'. + */ +const requiredTemplateUsageTypes = ['Register', 'SignIn', 'ForgotPassword', 'Generic']; + +const templateGuard = z.object({ + usageType: z.string(), + templateAlias: z.string(), +}); + +export const postmarkConfigGuard = z.object({ + serverToken: z.string(), + fromEmail: z.string(), + templates: z.array(templateGuard).refine( + (templates) => + requiredTemplateUsageTypes.every((requiredType) => + templates.map((template) => template.usageType).includes(requiredType) + ), + (templates) => ({ + message: `Template with UsageType (${requiredTemplateUsageTypes + .filter( + (requiredType) => !templates.map((template) => template.usageType).includes(requiredType) + ) + .join(', ')}) should be provided!`, + }) + ), +}); + +export type PostmarkConfig = z.infer; diff --git a/packages/connectors/connector-saml/CHANGELOG.md b/packages/connectors/connector-saml/CHANGELOG.md index dabc6162ef2..ac9bf904c10 100644 --- a/packages/connectors/connector-saml/CHANGELOG.md +++ b/packages/connectors/connector-saml/CHANGELOG.md @@ -1,5 +1,15 @@ # @logto/connector-saml +## 1.2.0 + +### Minor Changes + +- 510f681fa: use tsup for building + + We've updated some of the packages to use `tsup` for building. This will make the build process faster, and should not affect the functionality of the packages. + + Use minor version bump to catch your attention. + ## 1.1.2 ### Patch Changes diff --git a/packages/connectors/connector-saml/package.json b/packages/connectors/connector-saml/package.json index 7e84b900cf4..af99429f3ca 100644 --- a/packages/connectors/connector-saml/package.json +++ b/packages/connectors/connector-saml/package.json @@ -1,6 +1,6 @@ { "name": "@logto/connector-saml", - "version": "1.1.2", + "version": "1.2.0", "description": "SAML standard connector implementation.", "author": "Silverhand Inc. ", "dependencies": { @@ -9,8 +9,8 @@ "fast-xml-parser": "^4.3.6", "got": "^14.0.0", "samlify": "2.8.11", - "snakecase-keys": "^8.0.0", - "zod": "^3.22.4" + "snakecase-keys": "^8.0.1", + "zod": "^3.23.8" }, "main": "./lib/index.js", "module": "./lib/index.js", @@ -25,9 +25,9 @@ ], "scripts": { "precommit": "lint-staged", - "build:test": "rm -rf lib/ && tsc -p tsconfig.test.json --sourcemap", - "build": "rm -rf lib/ && tsc -p tsconfig.build.json --noEmit && rollup -c", - "dev": "tsc -p tsconfig.build.json --watch --preserveWatchOutput --incremental", + "check": "tsc --noEmit", + "build": "tsup", + "dev": "tsup --watch", "lint": "eslint --ext .ts src", "lint:report": "pnpm lint --format json --output-file report.json", "test": "vitest src", @@ -54,23 +54,18 @@ "access": "public" }, "devDependencies": { - "@rollup/plugin-commonjs": "^26.0.0", - "@rollup/plugin-json": "^6.1.0", - "@rollup/plugin-node-resolve": "^15.2.3", - "@rollup/plugin-typescript": "^11.1.6", "@silverhand/eslint-config": "6.0.1", "@silverhand/ts-config": "6.0.0", "@types/node": "^20.11.20", "@types/supertest": "^6.0.2", - "@vitest/coverage-v8": "^1.4.0", + "@vitest/coverage-v8": "^2.0.0", "eslint": "^8.56.0", "lint-staged": "^15.0.2", "nock": "^13.3.1", "prettier": "^3.0.0", - "rollup": "^4.12.0", - "rollup-plugin-output-size": "^1.3.0", "supertest": "^7.0.0", - "typescript": "^5.3.3", - "vitest": "^1.4.0" + "tsup": "^8.1.0", + "typescript": "^5.5.3", + "vitest": "^2.0.0" } } diff --git a/packages/connectors/connector-sendgrid-email/CHANGELOG.md b/packages/connectors/connector-sendgrid-email/CHANGELOG.md index 421045fef2c..2b86deb802d 100644 --- a/packages/connectors/connector-sendgrid-email/CHANGELOG.md +++ b/packages/connectors/connector-sendgrid-email/CHANGELOG.md @@ -1,5 +1,15 @@ # @logto/connector-sendgrid-email +## 1.2.0 + +### Minor Changes + +- 510f681fa: use tsup for building + + We've updated some of the packages to use `tsup` for building. This will make the build process faster, and should not affect the functionality of the packages. + + Use minor version bump to catch your attention. + ## 1.1.2 ### Patch Changes diff --git a/packages/connectors/connector-sendgrid-email/package.json b/packages/connectors/connector-sendgrid-email/package.json index 58231c9eb00..68700420171 100644 --- a/packages/connectors/connector-sendgrid-email/package.json +++ b/packages/connectors/connector-sendgrid-email/package.json @@ -1,14 +1,14 @@ { "name": "@logto/connector-sendgrid-email", - "version": "1.1.2", + "version": "1.2.0", "description": "SendGrid Email Service connector implementation.", "author": "Silverhand Inc. ", "dependencies": { "@logto/connector-kit": "workspace:^4.0.0", "@silverhand/essentials": "^2.9.1", "got": "^14.0.0", - "snakecase-keys": "^8.0.0", - "zod": "^3.22.4" + "snakecase-keys": "^8.0.1", + "zod": "^3.23.8" }, "main": "./lib/index.js", "module": "./lib/index.js", @@ -23,9 +23,9 @@ ], "scripts": { "precommit": "lint-staged", - "build:test": "rm -rf lib/ && tsc -p tsconfig.test.json --sourcemap", - "build": "rm -rf lib/ && tsc -p tsconfig.build.json --noEmit && rollup -c", - "dev": "tsc -p tsconfig.build.json --watch --preserveWatchOutput --incremental", + "check": "tsc --noEmit", + "build": "tsup", + "dev": "tsup --watch", "lint": "eslint --ext .ts src", "lint:report": "pnpm lint --format json --output-file report.json", "test": "vitest src", @@ -52,23 +52,18 @@ "access": "public" }, "devDependencies": { - "@rollup/plugin-commonjs": "^26.0.0", - "@rollup/plugin-json": "^6.1.0", - "@rollup/plugin-node-resolve": "^15.2.3", - "@rollup/plugin-typescript": "^11.1.6", "@silverhand/eslint-config": "6.0.1", "@silverhand/ts-config": "6.0.0", "@types/node": "^20.11.20", "@types/supertest": "^6.0.2", - "@vitest/coverage-v8": "^1.4.0", + "@vitest/coverage-v8": "^2.0.0", "eslint": "^8.56.0", "lint-staged": "^15.0.2", "nock": "^13.3.1", "prettier": "^3.0.0", - "rollup": "^4.12.0", - "rollup-plugin-output-size": "^1.3.0", "supertest": "^7.0.0", - "typescript": "^5.3.3", - "vitest": "^1.4.0" + "tsup": "^8.1.0", + "typescript": "^5.5.3", + "vitest": "^2.0.0" } } diff --git a/packages/connectors/connector-smsaero/CHANGELOG.md b/packages/connectors/connector-smsaero/CHANGELOG.md index fe9faafda9c..77f31884710 100644 --- a/packages/connectors/connector-smsaero/CHANGELOG.md +++ b/packages/connectors/connector-smsaero/CHANGELOG.md @@ -1,5 +1,15 @@ # @logto/connector-smsaero +## 1.3.0 + +### Minor Changes + +- 510f681fa: use tsup for building + + We've updated some of the packages to use `tsup` for building. This will make the build process faster, and should not affect the functionality of the packages. + + Use minor version bump to catch your attention. + ## 1.2.2 ### Patch Changes diff --git a/packages/connectors/connector-smsaero/package.json b/packages/connectors/connector-smsaero/package.json index 306eb38dbb3..9fcc20f83d6 100644 --- a/packages/connectors/connector-smsaero/package.json +++ b/packages/connectors/connector-smsaero/package.json @@ -1,14 +1,14 @@ { "name": "@logto/connector-smsaero", - "version": "1.2.2", + "version": "1.3.0", "description": "SMSAero connector implementation.", "author": "Danil Tankov ", "dependencies": { "@logto/connector-kit": "workspace:^4.0.0", "@silverhand/essentials": "^2.9.1", "got": "^14.0.0", - "snakecase-keys": "^8.0.0", - "zod": "^3.22.4" + "snakecase-keys": "^8.0.1", + "zod": "^3.23.8" }, "main": "./lib/index.js", "module": "./lib/index.js", @@ -23,9 +23,9 @@ ], "scripts": { "precommit": "lint-staged", - "build:test": "rm -rf lib/ && tsc -p tsconfig.test.json --sourcemap", - "build": "rm -rf lib/ && tsc -p tsconfig.build.json --noEmit && rollup -c", - "dev": "tsc -p tsconfig.build.json --watch --preserveWatchOutput --incremental", + "check": "tsc --noEmit", + "build": "tsup", + "dev": "tsup --watch", "lint": "eslint --ext .ts src", "lint:report": "pnpm lint --format json --output-file report.json", "test": "vitest src", @@ -52,23 +52,18 @@ "access": "public" }, "devDependencies": { - "@rollup/plugin-commonjs": "^26.0.0", - "@rollup/plugin-json": "^6.1.0", - "@rollup/plugin-node-resolve": "^15.2.3", - "@rollup/plugin-typescript": "^11.1.6", "@silverhand/eslint-config": "6.0.1", "@silverhand/ts-config": "6.0.0", "@types/node": "^20.11.20", "@types/supertest": "^6.0.2", - "@vitest/coverage-v8": "^1.4.0", + "@vitest/coverage-v8": "^2.0.0", "eslint": "^8.56.0", "lint-staged": "^15.0.2", "nock": "^13.3.1", "prettier": "^3.0.0", - "rollup": "^4.12.0", - "rollup-plugin-output-size": "^1.3.0", "supertest": "^7.0.0", - "typescript": "^5.3.3", - "vitest": "^1.4.0" + "tsup": "^8.1.0", + "typescript": "^5.5.3", + "vitest": "^2.0.0" } } diff --git a/packages/connectors/connector-smtp/CHANGELOG.md b/packages/connectors/connector-smtp/CHANGELOG.md index 999f63372ba..0d068c29e28 100644 --- a/packages/connectors/connector-smtp/CHANGELOG.md +++ b/packages/connectors/connector-smtp/CHANGELOG.md @@ -1,5 +1,16 @@ # @logto/connector-smtp +## 1.2.0 + +### Minor Changes + +- 6fca3fe3c: enable static custom headers for SMTP connector +- 510f681fa: use tsup for building + + We've updated some of the packages to use `tsup` for building. This will make the build process faster, and should not affect the functionality of the packages. + + Use minor version bump to catch your attention. + ## 1.1.3 ### Patch Changes diff --git a/packages/connectors/connector-smtp/package.json b/packages/connectors/connector-smtp/package.json index 8fbd5f46869..1edc7fad725 100644 --- a/packages/connectors/connector-smtp/package.json +++ b/packages/connectors/connector-smtp/package.json @@ -1,6 +1,6 @@ { "name": "@logto/connector-smtp", - "version": "1.1.3", + "version": "1.2.0", "description": "SMTP connector implementation.", "author": "Silverhand Inc. ", "dependencies": { @@ -8,29 +8,24 @@ "@silverhand/essentials": "^2.9.1", "got": "^14.0.0", "nodemailer": "^6.9.9", - "snakecase-keys": "^8.0.0", - "zod": "^3.22.4" + "snakecase-keys": "^8.0.1", + "zod": "^3.23.8" }, "devDependencies": { - "@rollup/plugin-commonjs": "^26.0.0", - "@rollup/plugin-json": "^6.1.0", - "@rollup/plugin-node-resolve": "^15.2.3", - "@rollup/plugin-typescript": "^11.1.6", "@silverhand/eslint-config": "6.0.1", "@silverhand/ts-config": "6.0.0", "@types/node": "^20.11.20", "@types/nodemailer": "^6.4.7", "@types/supertest": "^6.0.2", - "@vitest/coverage-v8": "^1.4.0", + "@vitest/coverage-v8": "^2.0.0", "eslint": "^8.56.0", "lint-staged": "^15.0.2", "nock": "^13.3.1", "prettier": "^3.0.0", - "rollup": "^4.12.0", - "rollup-plugin-output-size": "^1.3.0", "supertest": "^7.0.0", - "typescript": "^5.3.3", - "vitest": "^1.4.0" + "tsup": "^8.1.0", + "typescript": "^5.5.3", + "vitest": "^2.0.0" }, "main": "./lib/index.js", "module": "./lib/index.js", @@ -45,9 +40,9 @@ ], "scripts": { "precommit": "lint-staged", - "build:test": "rm -rf lib/ && tsc -p tsconfig.test.json --sourcemap", - "build": "rm -rf lib/ && tsc -p tsconfig.build.json --noEmit && rollup -c", - "dev": "tsc -p tsconfig.build.json --watch --preserveWatchOutput --incremental", + "check": "tsc --noEmit", + "build": "tsup", + "dev": "tsup --watch", "lint": "eslint --ext .ts src", "lint:report": "pnpm lint --format json --output-file report.json", "test": "vitest src", diff --git a/packages/connectors/connector-smtp/src/constant.ts b/packages/connectors/connector-smtp/src/constant.ts index d2078b048c0..28d9a42761f 100644 --- a/packages/connectors/connector-smtp/src/constant.ts +++ b/packages/connectors/connector-smtp/src/constant.ts @@ -198,5 +198,14 @@ export const defaultMetadata: ConnectorMetadata = { type: ConnectorConfigFormItemType.Switch, required: false, }, + { + key: 'customHeaders', + label: 'Custom Headers', + type: ConnectorConfigFormItemType.Json, + required: false, + defaultValue: {}, + description: + 'Custom headers to be added to original email headers when sending messages. Both keys and values should be string-typed.', + }, ], }; diff --git a/packages/connectors/connector-smtp/src/index.test.ts b/packages/connectors/connector-smtp/src/index.test.ts index a28137dd32d..b57ad02e133 100644 --- a/packages/connectors/connector-smtp/src/index.test.ts +++ b/packages/connectors/connector-smtp/src/index.test.ts @@ -79,6 +79,28 @@ describe('SMTP connector', () => { to: 'baz', }); }); + + it('should send mail with customer headers', async () => { + const connector = await createConnector({ + getConfig: vi.fn().mockResolvedValue({ + ...mockedConfig, + customHeaders: { 'X-Test': 'test', 'X-Test-Another': ['test1', 'test2', 'test3'] }, + }), + }); + await connector.sendMessage({ + to: 'baz', + type: TemplateType.OrganizationInvitation, + payload: { code: '345678', link: 'https://example.com' }, + }); + + expect(sendMail).toHaveBeenCalledWith({ + from: '', + subject: 'Organization invitation', + text: 'This is for organization invitation. Your link is https://example.com.', + to: 'baz', + headers: { 'X-Test': 'test', 'X-Test-Another': ['test1', 'test2', 'test3'] }, + }); + }); }); describe('Test config guard', () => { diff --git a/packages/connectors/connector-smtp/src/index.ts b/packages/connectors/connector-smtp/src/index.ts index 8aed0e05dd6..f447f420e65 100644 --- a/packages/connectors/connector-smtp/src/index.ts +++ b/packages/connectors/connector-smtp/src/index.ts @@ -1,4 +1,4 @@ -import { assert } from '@silverhand/essentials'; +import { assert, conditional } from '@silverhand/essentials'; import type { GetConnectorConfig, @@ -14,6 +14,7 @@ import { replaceSendMessageHandlebars, } from '@logto/connector-kit'; import nodemailer from 'nodemailer'; +import type Mail from 'nodemailer/lib/mailer'; import type SMTPTransport from 'nodemailer/lib/smtp-transport'; import { defaultMetadata } from './constant.js'; @@ -44,11 +45,17 @@ const sendMessage = template.contentType ); - const mailOptions = { + const mailOptions: Mail.Options = { to, from: config.fromEmail, replyTo: config.replyTo, subject: replaceSendMessageHandlebars(template.subject, payload), + ...conditional( + config.customHeaders && + Object.entries(config.customHeaders).length > 0 && { + headers: config.customHeaders, + } + ), ...contentsObject, }; diff --git a/packages/connectors/connector-smtp/src/mock.ts b/packages/connectors/connector-smtp/src/mock.ts index 87f2017d3b5..bef4a38b1b1 100644 --- a/packages/connectors/connector-smtp/src/mock.ts +++ b/packages/connectors/connector-smtp/src/mock.ts @@ -35,6 +35,7 @@ export const mockedConfig = { usageType: 'OrganizationInvitation', }, ], + customHeaders: {}, }; export const mockedOauth2AuthWithToken = { diff --git a/packages/connectors/connector-smtp/src/types.ts b/packages/connectors/connector-smtp/src/types.ts index 263fe802807..cf18622105f 100644 --- a/packages/connectors/connector-smtp/src/types.ts +++ b/packages/connectors/connector-smtp/src/types.ts @@ -125,6 +125,7 @@ export const smtpConfigGuard = z.object({ servername: z.string().optional(), ignoreTLS: z.boolean().optional(), requireTLS: z.boolean().optional(), + customHeaders: z.record(z.string().or(z.string().array())).optional(), }); export type SmtpConfig = z.infer; diff --git a/packages/connectors/connector-tencent-sms/CHANGELOG.md b/packages/connectors/connector-tencent-sms/CHANGELOG.md index a0f03437d48..aee270d8a4f 100644 --- a/packages/connectors/connector-tencent-sms/CHANGELOG.md +++ b/packages/connectors/connector-tencent-sms/CHANGELOG.md @@ -1,5 +1,15 @@ # @logto/connector-tencent-sms +## 1.2.0 + +### Minor Changes + +- 510f681fa: use tsup for building + + We've updated some of the packages to use `tsup` for building. This will make the build process faster, and should not affect the functionality of the packages. + + Use minor version bump to catch your attention. + ## 1.1.2 ### Patch Changes diff --git a/packages/connectors/connector-tencent-sms/package.json b/packages/connectors/connector-tencent-sms/package.json index a0da5a6bcae..ae37f2c376d 100644 --- a/packages/connectors/connector-tencent-sms/package.json +++ b/packages/connectors/connector-tencent-sms/package.json @@ -1,14 +1,14 @@ { "name": "@logto/connector-tencent-sms", - "version": "1.1.2", + "version": "1.2.0", "description": "Tencent SMS connector implementation.", "author": "StringKe", "dependencies": { "@logto/connector-kit": "workspace:^4.0.0", "@silverhand/essentials": "^2.9.1", "got": "^14.0.0", - "snakecase-keys": "^8.0.0", - "zod": "^3.22.4" + "snakecase-keys": "^8.0.1", + "zod": "^3.23.8" }, "main": "./lib/index.js", "module": "./lib/index.js", @@ -23,9 +23,9 @@ ], "scripts": { "precommit": "lint-staged", - "build:test": "rm -rf lib/ && tsc -p tsconfig.test.json --sourcemap", - "build": "rm -rf lib/ && tsc -p tsconfig.build.json --noEmit && rollup -c", - "dev": "tsc -p tsconfig.build.json --watch --preserveWatchOutput --incremental", + "check": "tsc --noEmit", + "build": "tsup", + "dev": "tsup --watch", "lint": "eslint --ext .ts src", "lint:report": "pnpm lint --format json --output-file report.json", "test": "vitest src", @@ -52,23 +52,18 @@ "access": "public" }, "devDependencies": { - "@rollup/plugin-commonjs": "^26.0.0", - "@rollup/plugin-json": "^6.1.0", - "@rollup/plugin-node-resolve": "^15.2.3", - "@rollup/plugin-typescript": "^11.1.6", "@silverhand/eslint-config": "6.0.1", "@silverhand/ts-config": "6.0.0", "@types/node": "^20.11.20", "@types/supertest": "^6.0.2", - "@vitest/coverage-v8": "^1.4.0", + "@vitest/coverage-v8": "^2.0.0", "eslint": "^8.56.0", "lint-staged": "^15.0.2", "nock": "^13.3.1", "prettier": "^3.0.0", - "rollup": "^4.12.0", - "rollup-plugin-output-size": "^1.3.0", "supertest": "^7.0.0", - "typescript": "^5.3.3", - "vitest": "^1.4.0" + "tsup": "^8.1.0", + "typescript": "^5.5.3", + "vitest": "^2.0.0" } } diff --git a/packages/connectors/connector-twilio-sms/CHANGELOG.md b/packages/connectors/connector-twilio-sms/CHANGELOG.md index 71e7e4630f3..b9642803401 100644 --- a/packages/connectors/connector-twilio-sms/CHANGELOG.md +++ b/packages/connectors/connector-twilio-sms/CHANGELOG.md @@ -1,5 +1,15 @@ # @logto/connector-twilio-sms +## 1.2.0 + +### Minor Changes + +- 510f681fa: use tsup for building + + We've updated some of the packages to use `tsup` for building. This will make the build process faster, and should not affect the functionality of the packages. + + Use minor version bump to catch your attention. + ## 1.1.2 ### Patch Changes diff --git a/packages/connectors/connector-twilio-sms/package.json b/packages/connectors/connector-twilio-sms/package.json index 976f3070249..99f9d94d014 100644 --- a/packages/connectors/connector-twilio-sms/package.json +++ b/packages/connectors/connector-twilio-sms/package.json @@ -1,14 +1,14 @@ { "name": "@logto/connector-twilio-sms", - "version": "1.1.2", + "version": "1.2.0", "description": "Twilio SMS connector implementation.", "author": "Silverhand Inc. ", "dependencies": { "@logto/connector-kit": "workspace:^4.0.0", "@silverhand/essentials": "^2.9.1", "got": "^14.0.0", - "snakecase-keys": "^8.0.0", - "zod": "^3.22.4" + "snakecase-keys": "^8.0.1", + "zod": "^3.23.8" }, "main": "./lib/index.js", "module": "./lib/index.js", @@ -23,9 +23,9 @@ ], "scripts": { "precommit": "lint-staged", - "build:test": "rm -rf lib/ && tsc -p tsconfig.test.json --sourcemap", - "build": "rm -rf lib/ && tsc -p tsconfig.build.json --noEmit && rollup -c", - "dev": "tsc -p tsconfig.build.json --watch --preserveWatchOutput --incremental", + "check": "tsc --noEmit", + "build": "tsup", + "dev": "tsup --watch", "lint": "eslint --ext .ts src", "lint:report": "pnpm lint --format json --output-file report.json", "test": "vitest src", @@ -52,23 +52,18 @@ "access": "public" }, "devDependencies": { - "@rollup/plugin-commonjs": "^26.0.0", - "@rollup/plugin-json": "^6.1.0", - "@rollup/plugin-node-resolve": "^15.2.3", - "@rollup/plugin-typescript": "^11.1.6", "@silverhand/eslint-config": "6.0.1", "@silverhand/ts-config": "6.0.0", "@types/node": "^20.11.20", "@types/supertest": "^6.0.2", - "@vitest/coverage-v8": "^1.4.0", + "@vitest/coverage-v8": "^2.0.0", "eslint": "^8.56.0", "lint-staged": "^15.0.2", "nock": "^13.3.1", "prettier": "^3.0.0", - "rollup": "^4.12.0", - "rollup-plugin-output-size": "^1.3.0", "supertest": "^7.0.0", - "typescript": "^5.3.3", - "vitest": "^1.4.0" + "tsup": "^8.1.0", + "typescript": "^5.5.3", + "vitest": "^2.0.0" } } diff --git a/packages/connectors/connector-wechat-native/CHANGELOG.md b/packages/connectors/connector-wechat-native/CHANGELOG.md index 8a11df3eed8..ebdfaff229e 100644 --- a/packages/connectors/connector-wechat-native/CHANGELOG.md +++ b/packages/connectors/connector-wechat-native/CHANGELOG.md @@ -1,5 +1,15 @@ # @logto/connector-wechat-native +## 1.3.0 + +### Minor Changes + +- 510f681fa: use tsup for building + + We've updated some of the packages to use `tsup` for building. This will make the build process faster, and should not affect the functionality of the packages. + + Use minor version bump to catch your attention. + ## 1.2.1 ### Patch Changes diff --git a/packages/connectors/connector-wechat-native/package.json b/packages/connectors/connector-wechat-native/package.json index 9a68f2dc462..c4890f9f638 100644 --- a/packages/connectors/connector-wechat-native/package.json +++ b/packages/connectors/connector-wechat-native/package.json @@ -1,14 +1,14 @@ { "name": "@logto/connector-wechat-native", - "version": "1.2.1", + "version": "1.3.0", "description": "WeChat native connector implementation.", "author": "Silverhand Inc. ", "dependencies": { "@logto/connector-kit": "workspace:^4.0.0", "@silverhand/essentials": "^2.9.1", "got": "^14.0.0", - "snakecase-keys": "^8.0.0", - "zod": "^3.22.4" + "snakecase-keys": "^8.0.1", + "zod": "^3.23.8" }, "main": "./lib/index.js", "module": "./lib/index.js", @@ -23,9 +23,9 @@ ], "scripts": { "precommit": "lint-staged", - "build:test": "rm -rf lib/ && tsc -p tsconfig.test.json --sourcemap", - "build": "rm -rf lib/ && tsc -p tsconfig.build.json --noEmit && rollup -c", - "dev": "tsc -p tsconfig.build.json --watch --preserveWatchOutput --incremental", + "check": "tsc --noEmit", + "build": "tsup", + "dev": "tsup --watch", "lint": "eslint --ext .ts src", "lint:report": "pnpm lint --format json --output-file report.json", "test": "vitest src", @@ -52,23 +52,18 @@ "access": "public" }, "devDependencies": { - "@rollup/plugin-commonjs": "^26.0.0", - "@rollup/plugin-json": "^6.1.0", - "@rollup/plugin-node-resolve": "^15.2.3", - "@rollup/plugin-typescript": "^11.1.6", "@silverhand/eslint-config": "6.0.1", "@silverhand/ts-config": "6.0.0", "@types/node": "^20.11.20", "@types/supertest": "^6.0.2", - "@vitest/coverage-v8": "^1.4.0", + "@vitest/coverage-v8": "^2.0.0", "eslint": "^8.56.0", "lint-staged": "^15.0.2", "nock": "^13.3.1", "prettier": "^3.0.0", - "rollup": "^4.12.0", - "rollup-plugin-output-size": "^1.3.0", "supertest": "^7.0.0", - "typescript": "^5.3.3", - "vitest": "^1.4.0" + "tsup": "^8.1.0", + "typescript": "^5.5.3", + "vitest": "^2.0.0" } } diff --git a/packages/connectors/connector-wechat-web/CHANGELOG.md b/packages/connectors/connector-wechat-web/CHANGELOG.md index f9206ebff28..246624d6d66 100644 --- a/packages/connectors/connector-wechat-web/CHANGELOG.md +++ b/packages/connectors/connector-wechat-web/CHANGELOG.md @@ -1,5 +1,15 @@ # @logto/connector-wechat-web +## 1.4.0 + +### Minor Changes + +- 510f681fa: use tsup for building + + We've updated some of the packages to use `tsup` for building. This will make the build process faster, and should not affect the functionality of the packages. + + Use minor version bump to catch your attention. + ## 1.3.1 ### Patch Changes diff --git a/packages/connectors/connector-wechat-web/package.json b/packages/connectors/connector-wechat-web/package.json index 07d99ad9280..c2d7b409923 100644 --- a/packages/connectors/connector-wechat-web/package.json +++ b/packages/connectors/connector-wechat-web/package.json @@ -1,14 +1,14 @@ { "name": "@logto/connector-wechat-web", - "version": "1.3.1", + "version": "1.4.0", "description": "Wechat Web connector implementation.", "author": "Silverhand Inc. ", "dependencies": { "@logto/connector-kit": "workspace:^4.0.0", "@silverhand/essentials": "^2.9.1", "got": "^14.0.0", - "snakecase-keys": "^8.0.0", - "zod": "^3.22.4" + "snakecase-keys": "^8.0.1", + "zod": "^3.23.8" }, "main": "./lib/index.js", "module": "./lib/index.js", @@ -23,9 +23,9 @@ ], "scripts": { "precommit": "lint-staged", - "build:test": "rm -rf lib/ && tsc -p tsconfig.test.json --sourcemap", - "build": "rm -rf lib/ && tsc -p tsconfig.build.json --noEmit && rollup -c", - "dev": "tsc -p tsconfig.build.json --watch --preserveWatchOutput --incremental", + "check": "tsc --noEmit", + "build": "tsup", + "dev": "tsup --watch", "lint": "eslint --ext .ts src", "lint:report": "pnpm lint --format json --output-file report.json", "test": "vitest src", @@ -52,23 +52,18 @@ "access": "public" }, "devDependencies": { - "@rollup/plugin-commonjs": "^26.0.0", - "@rollup/plugin-json": "^6.1.0", - "@rollup/plugin-node-resolve": "^15.2.3", - "@rollup/plugin-typescript": "^11.1.6", "@silverhand/eslint-config": "6.0.1", "@silverhand/ts-config": "6.0.0", "@types/node": "^20.11.20", "@types/supertest": "^6.0.2", - "@vitest/coverage-v8": "^1.4.0", + "@vitest/coverage-v8": "^2.0.0", "eslint": "^8.56.0", "lint-staged": "^15.0.2", "nock": "^13.3.1", "prettier": "^3.0.0", - "rollup": "^4.12.0", - "rollup-plugin-output-size": "^1.3.0", "supertest": "^7.0.0", - "typescript": "^5.3.3", - "vitest": "^1.4.0" + "tsup": "^8.1.0", + "typescript": "^5.5.3", + "vitest": "^2.0.0" } } diff --git a/packages/connectors/connector-wecom/CHANGELOG.md b/packages/connectors/connector-wecom/CHANGELOG.md index 56e23dc3fb2..571d5b687d0 100644 --- a/packages/connectors/connector-wecom/CHANGELOG.md +++ b/packages/connectors/connector-wecom/CHANGELOG.md @@ -1,5 +1,15 @@ # @logto/connector-wecom +## 0.3.0 + +### Minor Changes + +- 510f681fa: use tsup for building + + We've updated some of the packages to use `tsup` for building. This will make the build process faster, and should not affect the functionality of the packages. + + Use minor version bump to catch your attention. + ## 0.2.1 ### Patch Changes diff --git a/packages/connectors/connector-wecom/package.json b/packages/connectors/connector-wecom/package.json index b06794e294c..15c3aa3555a 100644 --- a/packages/connectors/connector-wecom/package.json +++ b/packages/connectors/connector-wecom/package.json @@ -1,14 +1,14 @@ { "name": "@logto/connector-wecom", - "version": "0.2.1", + "version": "0.3.0", "description": "Wecom connector implementation.", "author": "Dove fork from Wechat Web connector", "dependencies": { "@logto/connector-kit": "workspace:^4.0.0", "@silverhand/essentials": "^2.9.1", "got": "^14.0.0", - "snakecase-keys": "^8.0.0", - "zod": "^3.22.4" + "snakecase-keys": "^8.0.1", + "zod": "^3.23.8" }, "main": "./lib/index.js", "module": "./lib/index.js", @@ -23,9 +23,9 @@ ], "scripts": { "precommit": "lint-staged", - "build:test": "rm -rf lib/ && tsc -p tsconfig.test.json --sourcemap", - "build": "rm -rf lib/ && tsc -p tsconfig.build.json --noEmit && rollup -c", - "dev": "tsc -p tsconfig.build.json --watch --preserveWatchOutput --incremental", + "check": "tsc --noEmit", + "build": "tsup", + "dev": "tsup --watch", "lint": "eslint --ext .ts src", "lint:report": "pnpm lint --format json --output-file report.json", "test": "vitest src", @@ -52,23 +52,18 @@ "access": "public" }, "devDependencies": { - "@rollup/plugin-commonjs": "^26.0.0", - "@rollup/plugin-json": "^6.1.0", - "@rollup/plugin-node-resolve": "^15.2.3", - "@rollup/plugin-typescript": "^11.1.6", "@silverhand/eslint-config": "6.0.1", "@silverhand/ts-config": "6.0.0", "@types/node": "^20.10.4", "@types/supertest": "^6.0.2", - "@vitest/coverage-v8": "^1.4.0", + "@vitest/coverage-v8": "^2.0.0", "eslint": "^8.56.0", "lint-staged": "^15.0.2", "nock": "^13.3.1", "prettier": "^3.0.0", - "rollup": "^4.12.0", - "rollup-plugin-output-size": "^1.3.0", "supertest": "^7.0.0", - "typescript": "^5.3.3", - "vitest": "^1.4.0" + "tsup": "^8.1.0", + "typescript": "^5.5.3", + "vitest": "^2.0.0" } } diff --git a/packages/connectors/templates/package.json b/packages/connectors/templates/package.json index ede58013e61..44870bc7b36 100644 --- a/packages/connectors/templates/package.json +++ b/packages/connectors/templates/package.json @@ -12,9 +12,9 @@ ], "scripts": { "precommit": "lint-staged", - "build:test": "rm -rf lib/ && tsc -p tsconfig.test.json --sourcemap", - "build": "rm -rf lib/ && tsc -p tsconfig.build.json --noEmit && rollup -c", - "dev": "tsc -p tsconfig.build.json --watch --preserveWatchOutput --incremental", + "check": "tsc --noEmit", + "build": "tsup", + "dev": "tsup --watch", "lint": "eslint --ext .ts src", "lint:report": "pnpm lint --format json --output-file report.json", "test": "vitest src", diff --git a/packages/connectors/templates/preset/tsconfig.base.json b/packages/connectors/templates/preset/tsconfig.base.json deleted file mode 100644 index ebab46568f2..00000000000 --- a/packages/connectors/templates/preset/tsconfig.base.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "extends": "@silverhand/ts-config/tsconfig.base", - "compilerOptions": { - "moduleResolution": "nodenext", - "module": "nodenext", - "outDir": "lib", - "baseUrl": "." - } -} diff --git a/packages/connectors/templates/preset/tsconfig.build.json b/packages/connectors/templates/preset/tsconfig.build.json deleted file mode 100644 index d42923dd38c..00000000000 --- a/packages/connectors/templates/preset/tsconfig.build.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "extends": "./tsconfig.base", - "include": ["src"], - "exclude": ["src/**/*.test.ts"] -} diff --git a/packages/connectors/templates/preset/tsconfig.json b/packages/connectors/templates/preset/tsconfig.json index 4fa2dd684aa..126a50cb0d9 100644 --- a/packages/connectors/templates/preset/tsconfig.json +++ b/packages/connectors/templates/preset/tsconfig.json @@ -1,7 +1,16 @@ { - "extends": "./tsconfig.base", + "extends": "@silverhand/ts-config/tsconfig.base", "compilerOptions": { - "types": ["node", "vitest/globals"] + "moduleResolution": "nodenext", + "module": "nodenext", + "outDir": "lib", + "baseUrl": ".", + "types": [ + "node", + "vitest/globals" + ] }, - "include": ["src", "types"] + "include": [ + "src" + ] } diff --git a/packages/connectors/templates/preset/tsconfig.test.json b/packages/connectors/templates/preset/tsconfig.test.json deleted file mode 100644 index 1424a155592..00000000000 --- a/packages/connectors/templates/preset/tsconfig.test.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "extends": "./tsconfig", - "compilerOptions": { - "isolatedModules": false, - "allowJs": true, - } -} diff --git a/packages/connectors/templates/preset/tsup.config.ts b/packages/connectors/templates/preset/tsup.config.ts new file mode 100644 index 00000000000..8e6ef8edb83 --- /dev/null +++ b/packages/connectors/templates/preset/tsup.config.ts @@ -0,0 +1,5 @@ +import { defineConfig } from 'tsup'; + +import { defaultConfig } from '../../../tsup.shared.config.js'; + +export default defineConfig(defaultConfig); diff --git a/packages/connectors/templates/sync-preset.js b/packages/connectors/templates/sync-preset.js index 32460417652..aa12dafb118 100644 --- a/packages/connectors/templates/sync-preset.js +++ b/packages/connectors/templates/sync-preset.js @@ -20,7 +20,7 @@ const templateKeys = Object.keys(templateJson); * Value format: `{ "": [""] }` * Example: `{ "connector-oauth2": ["prepack"] }` */ -const scriptExceptions = { 'connector-oauth2': ['prepack'] }; +const scriptExceptions = { 'connector-oauth2': ['prepack', 'build', 'build:test'] }; const sync = async () => { const packagesDirectory = './'; diff --git a/packages/console/.eslintrc.cjs b/packages/console/.eslintrc.cjs index f2cffeab3db..0997dc7409c 100644 --- a/packages/console/.eslintrc.cjs +++ b/packages/console/.eslintrc.cjs @@ -15,6 +15,7 @@ module.exports = { unnamedComponents: 'arrow-function', }, ], + 'react/jsx-pascal-case': ['error', { ignore: ['__Internal__*'] }], 'import/no-unused-modules': [ 'error', { @@ -30,6 +31,8 @@ module.exports = { '**/assets/docs/guides/*/index.ts', '**/assets/docs/guides/*/components/**/*.tsx', '**/mdx-components*/*/index.tsx', + '*.config.js', + '*.config.ts', ], rules: { 'import/no-unused-modules': 'off', @@ -49,5 +52,11 @@ module.exports = { ], }, }, + { + files: ['*.d.ts'], + rules: { + 'import/no-unassigned-import': 'off', + }, + }, ], }; diff --git a/packages/console/CHANGELOG.md b/packages/console/CHANGELOG.md index a07f5892216..7898a683d93 100644 --- a/packages/console/CHANGELOG.md +++ b/packages/console/CHANGELOG.md @@ -1,5 +1,67 @@ # Change Log +## 1.17.0 + +### Minor Changes + +- 3a839f6d6: support organization logo and sign-in experience override + + Now it's able to set light and dark logos for organizations. You can upload the logos in the organization settings page. + + Also, it's possible to override the sign-in experience logo from an organization. Simply add the `organization_id` parameter to the authentication request. In most Logto SDKs, it can be done by using the `extraParams` field in the `signIn` method. + + For example, in the JavaScript SDK: + + ```ts + import LogtoClient from "@logto/client"; + + const logtoClient = new LogtoClient(/* your configuration */); + + logtoClient.signIn({ + redirectUri: "https://your-app.com/callback", + extraParams: { + organization_id: "", + }, + }); + ``` + + The value `` can be found in the organization settings page. + + If you could not find the `extraParams` field in the SDK you are using, please let us know. + +- b91ec0cd6: add the application `custom_data` field editor to the application details page in console +- 62f5e5e0c: support app-level branding + + You can now set logos, favicons, and colors for your app. These settings will be used in the sign-in experience when the app initiates the authentication flow. For apps that have no branding settings, the omni sign-in experience branding will be used. + + If `organization_id` is provided in the authentication request, the app-level branding settings will be overridden by the organization's branding settings, if available. + +- 3bf756f2b: use Vite for transpilation and bundling + + Removed ParcelJS and replaced with Vite. No breaking changes should be expected, but use a minor version bump to catch your attention. + + > [!Important] + > The browserlist configuration for `@logto/experience` and been synced with what is stated in README.md. + +- b188bb161: support multiple app secrets with expiration + + Now secure apps (machine-to-machine, traditional web, Protected) can have multiple app secrets with expiration. This allows for secret rotation and provides an even safer experience. + + To manage your application secrets, go to Logto Console -> Applications -> Application Details -> Endpoints & Credentials. + + We've also added a set of Management APIs (`/api/applications/{id}/secrets`) for this purpose. + + > [!Important] + > You can still use existing app secrets for client authentication, but it is recommended to delete the old ones and create new secrets with expiration for enhanced security. + +- 62f5e5e0c: support dark favicon + + The favicon for the dark theme now can be set in the sign-in experience branding settings. + +### Patch Changes + +- 3aa7e57b3: fix Google connector `scope` field can not be reset bug + ## 1.16.0 ### Minor Changes diff --git a/packages/console/src/index.html b/packages/console/index.html similarity index 51% rename from packages/console/src/index.html rename to packages/console/index.html index 91e6965ac8c..a5603fdf399 100644 --- a/packages/console/src/index.html +++ b/packages/console/index.html @@ -3,14 +3,14 @@ - - + +
- + diff --git a/packages/console/package.json b/packages/console/package.json index cda9fc37676..b93ee45baf9 100644 --- a/packages/console/package.json +++ b/packages/console/package.json @@ -1,6 +1,6 @@ { "name": "@logto/console", - "version": "1.16.0", + "version": "1.17.0", "description": "> TODO: description", "author": "Silverhand Inc. ", "homepage": "https://github.com/logto-io/logto#readme", @@ -14,10 +14,10 @@ "prepack": "pnpm generate", "generate": "./generate.sh", "precommit": "lint-staged", - "start": "parcel src/index.html", - "dev": "cross-env PORT=5002 parcel src/index.html --public-url ${CONSOLE_PUBLIC_URL:-/console} --no-cache --hmr-port 6002", + "start": "vite", + "dev": "vite", "check": "tsc --noEmit", - "build": "pnpm generate && pnpm check && rm -rf dist && parcel build src/index.html --no-autoinstall --no-cache --public-url ${CONSOLE_PUBLIC_URL:-/console}", + "build": "pnpm generate && vite build", "lint": "eslint --ext .ts --ext .tsx src", "lint:report": "pnpm lint --format json --output-file report.json", "stylelint": "stylelint \"src/**/*.scss\"", @@ -27,23 +27,19 @@ "devDependencies": { "@fontsource/roboto-mono": "^5.0.0", "@jest/types": "^29.5.0", - "@logto/cloud": "0.2.5-a7eedce", + "@logto/cloud": "0.2.5-923c26f", "@logto/connector-kit": "workspace:^4.0.0", "@logto/core-kit": "workspace:^2.5.0", + "@logto/elements": "workspace:^0.0.0", "@logto/language-kit": "workspace:^1.1.0", - "@logto/phrases": "workspace:^1.12.0", + "@logto/phrases": "workspace:^1.13.0", "@logto/phrases-experience": "workspace:^1.7.0", "@logto/react": "^3.0.12", - "@logto/schemas": "workspace:^1.18.0", + "@logto/schemas": "workspace:^1.19.0", "@logto/shared": "workspace:^3.1.1", - "@mdx-js/mdx": "^3.0.1", "@mdx-js/react": "^3.0.1", + "@mdx-js/rollup": "^3.0.1", "@monaco-editor/react": "^4.6.0", - "@parcel/compressor-brotli": "2.9.3", - "@parcel/compressor-gzip": "2.9.3", - "@parcel/core": "2.9.3", - "@parcel/transformer-sass": "2.9.3", - "@parcel/transformer-svg-react": "2.9.3", "@silverhand/eslint-config": "6.0.1", "@silverhand/eslint-config-react": "6.0.2", "@silverhand/essentials": "^2.9.1", @@ -56,31 +52,30 @@ "@types/debug": "^4.1.7", "@types/jest": "^29.4.0", "@types/mdx": "^2.0.13", - "@types/react": "^18.0.31", + "@types/react": "^18.3.3", "@types/react-color": "^3.0.6", - "@types/react-dom": "^18.0.0", + "@types/react-dom": "^18.3.0", "@types/react-helmet": "^6.1.6", "@types/react-modal": "^3.13.1", "@types/react-syntax-highlighter": "^15.5.1", + "@vitejs/plugin-react": "^4.3.1", "@withtyped/client": "^0.8.7", - "buffer": "^6.0.0", "classnames": "^2.3.1", "clean-deep": "^3.4.0", - "cross-env": "^7.0.3", - "csstype": "^3.0.11", "date-fns": "^2.29.3", "dayjs": "^1.10.5", "debug": "^4.3.4", "deep-object-diff": "^1.1.9", "deepmerge": "^4.2.2", "dnd-core": "^16.0.0", + "dotenv": "^16.4.5", "eslint": "^8.56.0", - "history": "^5.3.0", + "find-up": "^7.0.0", "i18next": "^22.4.15", "i18next-browser-languagedetector": "^8.0.0", "identity-obj-proxy": "^3.0.0", "jest": "^29.7.0", - "jest-environment-jsdom": "^29.0.0", + "jest-environment-jsdom": "^29.7.0", "jest-transform-stub": "^2.0.0", "jest-transformer-svg": "^2.0.0", "just-kebab-case": "^4.2.0", @@ -91,20 +86,18 @@ "nanoid": "^5.0.1", "overlayscrollbars": "^2.0.2", "overlayscrollbars-react": "^0.5.0", - "parcel": "2.9.3", - "postcss": "^8.4.31", + "postcss": "^8.4.39", "postcss-modules": "^4.3.0", "prettier": "^3.0.0", - "process": "^0.11.10", "prop-types": "^15.8.1", "property-information": "^6.2.0", - "react": "^18.0.0", + "react": "^18.3.1", "react-animate-height": "^3.0.4", - "react-color": "^2.19.3", + "react-color-palette": "^7.2.1", "react-confetti": "^6.1.0", "react-dnd": "^16.0.0", "react-dnd-html5-backend": "^16.0.0", - "react-dom": "^18.0.0", + "react-dom": "^18.3.1", "react-dropzone": "^14.2.3", "react-helmet": "^6.1.0", "react-hook-form": "^7.43.9", @@ -113,7 +106,8 @@ "react-markdown": "^9.0.0", "react-modal": "^3.15.1", "react-paginate": "^8.1.3", - "react-router-dom": "^6.10.0", + "react-router-dom": "^6.25.1", + "react-safe-lazy": "^0.1.0", "react-syntax-highlighter": "^15.5.0", "react-timer-hook": "^3.0.5", "recharts": "^2.1.13", @@ -121,27 +115,17 @@ "remark-gfm": "^4.0.0", "stylelint": "^15.0.0", "swr": "^2.2.0", - "ts-node": "^10.9.2", - "tslib": "^2.4.1", - "typescript": "^5.3.3", - "zod": "^3.22.4", + "typescript": "^5.5.3", + "vite": "^5.3.4", + "vite-plugin-compression": "^0.5.1", + "vite-plugin-prebundle": "^0.0.4", + "vite-plugin-svgr": "^4.2.0", + "zod": "^3.23.8", "zod-to-ts": "^1.2.0" }, "engines": { "node": "^20.9.0" }, - "//": "https://github.com/parcel-bundler/parcel/issues/7636", - "targets": { - "default": { - "engines": { - "browsers": "defaults" - } - } - }, - "alias": { - "@/*": "./src/$1", - "@cloud/*": "./src/cloud/$1" - }, "stylelint": { "extends": "@silverhand/eslint-config-react/.stylelintrc" }, diff --git a/packages/console/scripts/generate-jwt-customizer-type-definition.ts b/packages/console/scripts/generate-jwt-customizer-type-definition.ts index 9b25077a20b..e7f9af524d2 100644 --- a/packages/console/scripts/generate-jwt-customizer-type-definition.ts +++ b/packages/console/scripts/generate-jwt-customizer-type-definition.ts @@ -3,6 +3,7 @@ import fs from 'node:fs'; import { accessTokenPayloadGuard, clientCredentialsPayloadGuard, + jwtCustomizerGrantContextGuard, jwtCustomizerUserContextGuard, } from '@logto/schemas'; import prettier from 'prettier'; @@ -13,6 +14,7 @@ const filePath = 'src/consts/jwt-customizer-type-definition.ts'; const typeIdentifiers = `export enum JwtCustomizerTypeDefinitionKey { JwtCustomizerUserContext = 'JwtCustomizerUserContext', + JwtCustomizerGrantContext = 'JwtCustomizerGrantContext', AccessTokenPayload = 'AccessTokenPayload', ClientCredentialsPayload = 'ClientCredentialsPayload', EnvironmentVariables = 'EnvironmentVariables', @@ -43,6 +45,11 @@ const createJwtCustomizerTypeDefinitions = async () => { 'JwtCustomizerUserContext' ); + const jwtCustomizerGrantContextTypeDefinition = inferTsDefinitionFromZod( + jwtCustomizerGrantContextGuard, + 'JwtCustomizerGrantContext' + ); + const accessTokenPayloadTypeDefinition = inferTsDefinitionFromZod( accessTokenPayloadGuard, 'AccessTokenPayload' @@ -58,6 +65,8 @@ ${typeIdentifiers} export const jwtCustomizerUserContextTypeDefinition = \`${jwtCustomizerUserContextTypeDefinition}\`; +export const jwtCustomizerGrantContextTypeDefinition = \`${jwtCustomizerGrantContextTypeDefinition}\`; + export const accessTokenPayloadTypeDefinition = \`${accessTokenPayloadTypeDefinition}\`; export const clientCredentialsPayloadTypeDefinition = \`${clientCredentialsPayloadTypeDefinition}\`; diff --git a/packages/console/src/App.tsx b/packages/console/src/App.tsx index 96ff5ed713f..30830308c53 100644 --- a/packages/console/src/App.tsx +++ b/packages/console/src/App.tsx @@ -16,6 +16,8 @@ import './scss/normalized.scss'; import './scss/overlayscrollbars.scss'; // eslint-disable-next-line import/no-unassigned-import import '@fontsource/roboto-mono'; +// eslint-disable-next-line import/no-unassigned-import +import 'react-color-palette/css'; import CloudAppRoutes from '@/cloud/AppRoutes'; import AppLoading from '@/components/AppLoading'; diff --git a/packages/console/src/assets/docs/guides/README.md b/packages/console/src/assets/docs/guides/README.md index 29f0f0dea24..c2517133e50 100644 --- a/packages/console/src/assets/docs/guides/README.md +++ b/packages/console/src/assets/docs/guides/README.md @@ -52,6 +52,9 @@ Images and other assets (if any) should be placed in the `assets` directory of t ### Update metadata +> [!Note] +> This section is outdated and we should test if it's still necessary. + Since Parcel doesn't support dynamic import (see [#112](https://github.com/parcel-bundler/parcel/issues/112) [#125](https://github.com/parcel-bundler/parcel/issues/125)), we need to run `node generate-metadata.js` to update the metadata in `index.ts`, thus we can use it in the guide components with React lazy loading. This may be fixed by replacing Parcel with something else. diff --git a/packages/console/src/assets/docs/guides/api-express/logo-dark.svg b/packages/console/src/assets/docs/guides/api-express/logo-dark.svg new file mode 100644 index 00000000000..8ed50c5f2ab --- /dev/null +++ b/packages/console/src/assets/docs/guides/api-express/logo-dark.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/packages/console/src/assets/docs/guides/api-express/logo.svg b/packages/console/src/assets/docs/guides/api-express/logo.svg index bda5f80dabc..db674128014 100644 --- a/packages/console/src/assets/docs/guides/api-express/logo.svg +++ b/packages/console/src/assets/docs/guides/api-express/logo.svg @@ -1,3 +1,10 @@ - - + + + + + + + + + diff --git a/packages/console/src/assets/docs/guides/api-python/logo.svg b/packages/console/src/assets/docs/guides/api-python/logo.svg index c33c339ecb7..1d2ba15af8d 100644 --- a/packages/console/src/assets/docs/guides/api-python/logo.svg +++ b/packages/console/src/assets/docs/guides/api-python/logo.svg @@ -1,14 +1,19 @@ - - - + + + + + - + - + + + + diff --git a/packages/console/src/assets/docs/guides/api-spring-boot/logo.svg b/packages/console/src/assets/docs/guides/api-spring-boot/logo.svg index 55b425680de..2d4fe64ea1a 100644 --- a/packages/console/src/assets/docs/guides/api-spring-boot/logo.svg +++ b/packages/console/src/assets/docs/guides/api-spring-boot/logo.svg @@ -1,10 +1,10 @@ - - - + + + - - + + diff --git a/packages/console/src/assets/docs/guides/generate-metadata.js b/packages/console/src/assets/docs/guides/generate-metadata.js index d1ca726d995..adc18258106 100644 --- a/packages/console/src/assets/docs/guides/generate-metadata.js +++ b/packages/console/src/assets/docs/guides/generate-metadata.js @@ -1,4 +1,4 @@ -// This script generates the `index.ts` file for all the guides. +// This script generates the `index.tsx` file for all the guides. // It should be run from the `packages/console/src/assets/docs/guides` (current) directory. // For conventions and specifications, see the `README.md` file in this directory. @@ -21,6 +21,9 @@ const data = await Promise.all( } const logo = ['logo.webp', 'logo.svg', 'logo.png'].find((logo) => existsSync(`${directory}/${logo}`)); + const darkLogo = ['logo-dark.webp', 'logo-dark.svg', 'logo-dark.png'].find((logo) => + existsSync(`${directory}/${logo}`) + ); const config = existsSync(`${directory}/config.json`) ? await import(`./${directory}/config.json`, { assert: { type: 'json' } }).then( @@ -31,6 +34,7 @@ const data = await Promise.all( return { name: directory, logo, + darkLogo, order: config?.order ?? Number.POSITIVE_INFINITY, }; }) @@ -45,10 +49,11 @@ const filename = 'index.tsx'; await fs.writeFile( filename, - "// This is a generated file, don't update manually.\n\nimport { lazy } from 'react';\n\nimport { type Guide } from './types';\n" + `/* eslint-disable max-lines */ +// This is a generated file, don't update manually.\n\nimport { lazy } from 'react';\n\nimport { type Guide } from './types';\n` ); -for (const { name, logo } of metadata) { +for (const { name, logo, darkLogo } of metadata) { // eslint-disable-next-line no-await-in-loop await fs.appendFile(filename, `import ${camelCase(name)} from './${name}/index';\n`); @@ -56,18 +61,23 @@ for (const { name, logo } of metadata) { // eslint-disable-next-line no-await-in-loop await fs.appendFile(filename, `import ${camelCase(name)}Logo from './${name}/${logo}';\n`); } + + if (darkLogo && !darkLogo.endsWith('.svg')) { + // eslint-disable-next-line no-await-in-loop + await fs.appendFile(filename, `import ${camelCase(name)}LogoDark from './${name}/${darkLogo}';\n`); + } } await fs.appendFile(filename, '\n'); await fs.appendFile(filename, 'export const guides: Readonly = Object.freeze(['); -const getLogo = ({ name, logo }) => { +const getLogo = ({ name, logo, isDark }) => { if (!logo) return 'undefined'; - if (logo.endsWith('.svg')) return `lazy(async () => import('./${name}/${logo}'))`; - return `({ className }: { readonly className?: string }) => ${name}`; + if (logo.endsWith('.svg')) return `lazy(async () => import('./${name}/${logo}?react'))`; + return `({ className }: { readonly className?: string }) => ${name}`; }; -for (const { name, logo, order } of metadata) { +for (const { name, logo, darkLogo, order } of metadata) { // eslint-disable-next-line no-await-in-loop await fs.appendFile( filename, @@ -76,10 +86,12 @@ for (const { name, logo, order } of metadata) { order: ${order}, id: '${name}', Logo: ${getLogo({ name, logo })}, + DarkLogo: ${getLogo({ name, logo: darkLogo, isDark: true })}, Component: lazy(async () => import('./${name}/README.mdx')), metadata: ${camelCase(name)}, },` ); } -await fs.appendFile(filename, ']);\n'); +await fs.appendFile(filename, `]); +/* eslint-enable max-lines */\n`); diff --git a/packages/console/src/assets/docs/guides/index.tsx b/packages/console/src/assets/docs/guides/index.tsx index d83d09817d4..d66e9699d27 100644 --- a/packages/console/src/assets/docs/guides/index.tsx +++ b/packages/console/src/assets/docs/guides/index.tsx @@ -1,3 +1,4 @@ +/* eslint-disable max-lines */ // This is a generated file, don't update manually. import { lazy } from 'react'; @@ -32,10 +33,10 @@ import webNextAppRouter from './web-next-app-router/index'; import webNextAuth from './web-next-auth/index'; import webNuxt from './web-nuxt/index'; import webOutline from './web-outline/index'; +import webPassport from './web-passport/index'; import webPhp from './web-php/index'; import webPython from './web-python/index'; import webRuby from './web-ruby/index'; -import webRubyLogo from './web-ruby/logo.webp'; import webSveltekit from './web-sveltekit/index'; import webWordpress from './web-wordpress/index'; @@ -43,241 +44,282 @@ export const guides: Readonly = Object.freeze([ { order: 1, id: 'web-next-app-router', - Logo: lazy(async () => import('./web-next-app-router/logo.svg')), + Logo: lazy(async () => import('./web-next-app-router/logo.svg?react')), + DarkLogo: lazy(async () => import('./web-next-app-router/logo-dark.svg?react')), Component: lazy(async () => import('./web-next-app-router/README.mdx')), metadata: webNextAppRouter, }, { order: 1.1, id: 'native-expo', - Logo: lazy(async () => import('./native-expo/logo.svg')), + Logo: lazy(async () => import('./native-expo/logo.svg?react')), + DarkLogo: lazy(async () => import('./native-expo/logo-dark.svg?react')), Component: lazy(async () => import('./native-expo/README.mdx')), metadata: nativeExpo, }, { order: 1.1, id: 'spa-angular', - Logo: lazy(async () => import('./spa-angular/logo.svg')), + Logo: lazy(async () => import('./spa-angular/logo.svg?react')), + DarkLogo: undefined, Component: lazy(async () => import('./spa-angular/README.mdx')), metadata: spaAngular, }, { order: 1.1, id: 'spa-chrome-extension', - Logo: lazy(async () => import('./spa-chrome-extension/logo.svg')), + Logo: lazy(async () => import('./spa-chrome-extension/logo.svg?react')), + DarkLogo: undefined, Component: lazy(async () => import('./spa-chrome-extension/README.mdx')), metadata: spaChromeExtension, }, { order: 1.1, id: 'spa-react', - Logo: lazy(async () => import('./spa-react/logo.svg')), + Logo: lazy(async () => import('./spa-react/logo.svg?react')), + DarkLogo: undefined, Component: lazy(async () => import('./spa-react/README.mdx')), metadata: spaReact, }, { order: 1.2, id: 'm2m-general', - Logo: lazy(async () => import('./m2m-general/logo.svg')), + Logo: lazy(async () => import('./m2m-general/logo.svg?react')), + DarkLogo: lazy(async () => import('./m2m-general/logo-dark.svg?react')), Component: lazy(async () => import('./m2m-general/README.mdx')), metadata: m2mGeneral, }, { order: 1.2, id: 'web-express', - Logo: lazy(async () => import('./web-express/logo.svg')), + Logo: lazy(async () => import('./web-express/logo.svg?react')), + DarkLogo: lazy(async () => import('./web-express/logo-dark.svg?react')), Component: lazy(async () => import('./web-express/README.mdx')), metadata: webExpress, }, { order: 1.2, id: 'web-next', - Logo: lazy(async () => import('./web-next/logo.svg')), + Logo: lazy(async () => import('./web-next/logo.svg?react')), + DarkLogo: lazy(async () => import('./web-next/logo-dark.svg?react')), Component: lazy(async () => import('./web-next/README.mdx')), metadata: webNext, }, { order: 1.2, id: 'web-sveltekit', - Logo: lazy(async () => import('./web-sveltekit/logo.svg')), + Logo: lazy(async () => import('./web-sveltekit/logo.svg?react')), + DarkLogo: undefined, Component: lazy(async () => import('./web-sveltekit/README.mdx')), metadata: webSveltekit, }, { order: 1.3, id: 'web-go', - Logo: lazy(async () => import('./web-go/logo.svg')), + Logo: lazy(async () => import('./web-go/logo.svg?react')), + DarkLogo: undefined, Component: lazy(async () => import('./web-go/README.mdx')), metadata: webGo, }, { order: 1.3, id: 'web-next-auth', - Logo: lazy(async () => import('./web-next-auth/logo.svg')), + Logo: lazy(async () => import('./web-next-auth/logo.svg?react')), + DarkLogo: undefined, Component: lazy(async () => import('./web-next-auth/README.mdx')), metadata: webNextAuth, }, { order: 1.4, id: 'web-java-spring-boot', - Logo: lazy(async () => import('./web-java-spring-boot/logo.svg')), + Logo: lazy(async () => import('./web-java-spring-boot/logo.svg?react')), + DarkLogo: undefined, Component: lazy(async () => import('./web-java-spring-boot/README.mdx')), metadata: webJavaSpringBoot, }, { order: 1.6, id: 'spa-vue', - Logo: lazy(async () => import('./spa-vue/logo.svg')), + Logo: lazy(async () => import('./spa-vue/logo.svg?react')), + DarkLogo: undefined, Component: lazy(async () => import('./spa-vue/README.mdx')), metadata: spaVue, }, { order: 1.7, id: 'native-ios-swift', - Logo: lazy(async () => import('./native-ios-swift/logo.svg')), + Logo: lazy(async () => import('./native-ios-swift/logo.svg?react')), + DarkLogo: undefined, Component: lazy(async () => import('./native-ios-swift/README.mdx')), metadata: nativeIosSwift, }, { order: 2, id: 'native-android', - Logo: lazy(async () => import('./native-android/logo.svg')), + Logo: lazy(async () => import('./native-android/logo.svg?react')), + DarkLogo: undefined, Component: lazy(async () => import('./native-android/README.mdx')), metadata: nativeAndroid, }, { order: 2, id: 'spa-vanilla', - Logo: lazy(async () => import('./spa-vanilla/logo.svg')), + Logo: lazy(async () => import('./spa-vanilla/logo.svg?react')), + DarkLogo: undefined, Component: lazy(async () => import('./spa-vanilla/README.mdx')), metadata: spaVanilla, }, { order: 2, id: 'web-nuxt', - Logo: lazy(async () => import('./web-nuxt/logo.svg')), + Logo: lazy(async () => import('./web-nuxt/logo.svg?react')), + DarkLogo: undefined, Component: lazy(async () => import('./web-nuxt/README.mdx')), metadata: webNuxt, }, { order: 2, id: 'web-php', - Logo: lazy(async () => import('./web-php/logo.svg')), + Logo: lazy(async () => import('./web-php/logo.svg?react')), + DarkLogo: undefined, Component: lazy(async () => import('./web-php/README.mdx')), metadata: webPhp, }, { order: 2, id: 'web-ruby', - Logo: ({ className }: { readonly className?: string }) => ( - web-ruby - ), + Logo: lazy(async () => import('./web-ruby/logo.svg?react')), + DarkLogo: undefined, Component: lazy(async () => import('./web-ruby/README.mdx')), metadata: webRuby, }, { order: 2.1, id: 'spa-webflow', - Logo: lazy(async () => import('./spa-webflow/logo.svg')), + Logo: lazy(async () => import('./spa-webflow/logo.svg?react')), + DarkLogo: undefined, Component: lazy(async () => import('./spa-webflow/README.mdx')), metadata: spaWebflow, }, { order: 2.2, id: 'web-wordpress', - Logo: lazy(async () => import('./web-wordpress/logo.svg')), + Logo: lazy(async () => import('./web-wordpress/logo.svg?react')), + DarkLogo: undefined, Component: lazy(async () => import('./web-wordpress/README.mdx')), metadata: webWordpress, }, { order: 3, id: 'web-python', - Logo: lazy(async () => import('./web-python/logo.svg')), + Logo: lazy(async () => import('./web-python/logo.svg?react')), + DarkLogo: undefined, Component: lazy(async () => import('./web-python/README.mdx')), metadata: webPython, }, { order: 4, id: 'native-capacitor', - Logo: lazy(async () => import('./native-capacitor/logo.svg')), + Logo: lazy(async () => import('./native-capacitor/logo.svg?react')), + DarkLogo: undefined, Component: lazy(async () => import('./native-capacitor/README.mdx')), metadata: nativeCapacitor, }, { order: 5, id: 'native-flutter', - Logo: lazy(async () => import('./native-flutter/logo.svg')), + Logo: lazy(async () => import('./native-flutter/logo.svg?react')), + DarkLogo: undefined, Component: lazy(async () => import('./native-flutter/README.mdx')), metadata: nativeFlutter, }, { order: 5, id: 'web-dotnet-core', - Logo: lazy(async () => import('./web-dotnet-core/logo.svg')), + Logo: lazy(async () => import('./web-dotnet-core/logo.svg?react')), + DarkLogo: undefined, Component: lazy(async () => import('./web-dotnet-core/README.mdx')), metadata: webDotnetCore, }, { order: 5.1, id: 'web-dotnet-core-mvc', - Logo: lazy(async () => import('./web-dotnet-core-mvc/logo.svg')), + Logo: lazy(async () => import('./web-dotnet-core-mvc/logo.svg?react')), + DarkLogo: undefined, Component: lazy(async () => import('./web-dotnet-core-mvc/README.mdx')), metadata: webDotnetCoreMvc, }, { order: 5.2, id: 'web-dotnet-core-blazor-server', - Logo: lazy(async () => import('./web-dotnet-core-blazor-server/logo.svg')), + Logo: lazy(async () => import('./web-dotnet-core-blazor-server/logo.svg?react')), + DarkLogo: undefined, Component: lazy(async () => import('./web-dotnet-core-blazor-server/README.mdx')), metadata: webDotnetCoreBlazorServer, }, { order: 5.3, id: 'web-dotnet-core-blazor-wasm', - Logo: lazy(async () => import('./web-dotnet-core-blazor-wasm/logo.svg')), + Logo: lazy(async () => import('./web-dotnet-core-blazor-wasm/logo.svg?react')), + DarkLogo: undefined, Component: lazy(async () => import('./web-dotnet-core-blazor-wasm/README.mdx')), metadata: webDotnetCoreBlazorWasm, }, { order: 6, id: 'web-outline', - Logo: lazy(async () => import('./web-outline/logo.svg')), + Logo: lazy(async () => import('./web-outline/logo.svg?react')), + DarkLogo: lazy(async () => import('./web-outline/logo-dark.svg?react')), Component: lazy(async () => import('./web-outline/README.mdx')), metadata: webOutline, }, + { + order: 6.1, + id: 'web-passport', + Logo: lazy(async () => import('./web-passport/logo.svg?react')), + DarkLogo: lazy(async () => import('./web-passport/logo-dark.svg?react')), + Component: lazy(async () => import('./web-passport/README.mdx')), + metadata: webPassport, + }, { order: 999, id: 'web-gpt-plugin', - Logo: lazy(async () => import('./web-gpt-plugin/logo.svg')), + Logo: lazy(async () => import('./web-gpt-plugin/logo.svg?react')), + DarkLogo: undefined, Component: lazy(async () => import('./web-gpt-plugin/README.mdx')), metadata: webGptPlugin, }, { order: Number.POSITIVE_INFINITY, id: 'api-express', - Logo: lazy(async () => import('./api-express/logo.svg')), + Logo: lazy(async () => import('./api-express/logo.svg?react')), + DarkLogo: lazy(async () => import('./api-express/logo-dark.svg?react')), Component: lazy(async () => import('./api-express/README.mdx')), metadata: apiExpress, }, { order: Number.POSITIVE_INFINITY, id: 'api-python', - Logo: lazy(async () => import('./api-python/logo.svg')), + Logo: lazy(async () => import('./api-python/logo.svg?react')), + DarkLogo: undefined, Component: lazy(async () => import('./api-python/README.mdx')), metadata: apiPython, }, { order: Number.POSITIVE_INFINITY, id: 'api-spring-boot', - Logo: lazy(async () => import('./api-spring-boot/logo.svg')), + Logo: lazy(async () => import('./api-spring-boot/logo.svg?react')), + DarkLogo: undefined, Component: lazy(async () => import('./api-spring-boot/README.mdx')), metadata: apiSpringBoot, }, { order: Number.POSITIVE_INFINITY, id: 'third-party-oidc', - Logo: lazy(async () => import('./third-party-oidc/logo.svg')), + Logo: lazy(async () => import('./third-party-oidc/logo.svg?react')), + DarkLogo: undefined, Component: lazy(async () => import('./third-party-oidc/README.mdx')), metadata: thirdPartyOidc, }, ]); +/* eslint-enable max-lines */ diff --git a/packages/console/src/assets/docs/guides/m2m-general/logo-dark.svg b/packages/console/src/assets/docs/guides/m2m-general/logo-dark.svg new file mode 100644 index 00000000000..7aaf3ec6f52 --- /dev/null +++ b/packages/console/src/assets/docs/guides/m2m-general/logo-dark.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/console/src/assets/docs/guides/m2m-general/logo.svg b/packages/console/src/assets/docs/guides/m2m-general/logo.svg index a2a63b7f663..5ef0d8edd3b 100644 --- a/packages/console/src/assets/docs/guides/m2m-general/logo.svg +++ b/packages/console/src/assets/docs/guides/m2m-general/logo.svg @@ -1,35 +1,35 @@ - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + - + - + - + diff --git a/packages/console/src/assets/docs/guides/native-android/logo.svg b/packages/console/src/assets/docs/guides/native-android/logo.svg index 63418a92e23..04c799220d0 100644 --- a/packages/console/src/assets/docs/guides/native-android/logo.svg +++ b/packages/console/src/assets/docs/guides/native-android/logo.svg @@ -1,4 +1,11 @@ - - - + + + + + + + + + + diff --git a/packages/console/src/assets/docs/guides/native-capacitor/logo.svg b/packages/console/src/assets/docs/guides/native-capacitor/logo.svg index e8c04da0996..84f1647a659 100644 --- a/packages/console/src/assets/docs/guides/native-capacitor/logo.svg +++ b/packages/console/src/assets/docs/guides/native-capacitor/logo.svg @@ -1,8 +1,15 @@ - - - - - - - + + + + + + + + + + + + + + diff --git a/packages/console/src/assets/docs/guides/native-expo/logo-dark.svg b/packages/console/src/assets/docs/guides/native-expo/logo-dark.svg new file mode 100644 index 00000000000..78413920df1 --- /dev/null +++ b/packages/console/src/assets/docs/guides/native-expo/logo-dark.svg @@ -0,0 +1,3 @@ + + + diff --git a/packages/console/src/assets/docs/guides/native-expo/logo.svg b/packages/console/src/assets/docs/guides/native-expo/logo.svg index 785dbbd164f..df2edaf0de0 100644 --- a/packages/console/src/assets/docs/guides/native-expo/logo.svg +++ b/packages/console/src/assets/docs/guides/native-expo/logo.svg @@ -1 +1,3 @@ - \ No newline at end of file + + + diff --git a/packages/console/src/assets/docs/guides/native-flutter/logo.svg b/packages/console/src/assets/docs/guides/native-flutter/logo.svg index ad50e5eb043..90e5276fc46 100644 --- a/packages/console/src/assets/docs/guides/native-flutter/logo.svg +++ b/packages/console/src/assets/docs/guides/native-flutter/logo.svg @@ -1,18 +1,28 @@ - - - - - - - + + + + + + + + + + + - + - + + + + + + + diff --git a/packages/console/src/assets/docs/guides/native-ios-swift/logo.svg b/packages/console/src/assets/docs/guides/native-ios-swift/logo.svg index 1f273709d07..5bc1e96e120 100644 --- a/packages/console/src/assets/docs/guides/native-ios-swift/logo.svg +++ b/packages/console/src/assets/docs/guides/native-ios-swift/logo.svg @@ -1,4 +1,11 @@ - - - + + + + + + + + + + diff --git a/packages/console/src/assets/docs/guides/spa-angular/logo.svg b/packages/console/src/assets/docs/guides/spa-angular/logo.svg index 96301efe1b4..e53c94dfce2 100644 --- a/packages/console/src/assets/docs/guides/spa-angular/logo.svg +++ b/packages/console/src/assets/docs/guides/spa-angular/logo.svg @@ -1,16 +1,12 @@ - - - - - - - - - - + + + + + + + + + + + + diff --git a/packages/console/src/assets/docs/guides/spa-chrome-extension/logo.svg b/packages/console/src/assets/docs/guides/spa-chrome-extension/logo.svg index 4fc53255e9c..e658a11e462 100644 --- a/packages/console/src/assets/docs/guides/spa-chrome-extension/logo.svg +++ b/packages/console/src/assets/docs/guides/spa-chrome-extension/logo.svg @@ -1,26 +1,21 @@ - - - - - - - - + + + + + + - + - + - + - - - diff --git a/packages/console/src/assets/docs/guides/spa-react/logo.svg b/packages/console/src/assets/docs/guides/spa-react/logo.svg index eccfaa961b4..7d1653573a7 100644 --- a/packages/console/src/assets/docs/guides/spa-react/logo.svg +++ b/packages/console/src/assets/docs/guides/spa-react/logo.svg @@ -1,3 +1,10 @@ - - + + + + + + + + + diff --git a/packages/console/src/assets/docs/guides/spa-vanilla/logo.svg b/packages/console/src/assets/docs/guides/spa-vanilla/logo.svg index 2b0ce5c72c2..ce73eb180b0 100644 --- a/packages/console/src/assets/docs/guides/spa-vanilla/logo.svg +++ b/packages/console/src/assets/docs/guides/spa-vanilla/logo.svg @@ -1,12 +1,12 @@ - - - - - + + + + + - - + + diff --git a/packages/console/src/assets/docs/guides/spa-vue/logo.svg b/packages/console/src/assets/docs/guides/spa-vue/logo.svg index d6a24d4938e..a71f46129a5 100644 --- a/packages/console/src/assets/docs/guides/spa-vue/logo.svg +++ b/packages/console/src/assets/docs/guides/spa-vue/logo.svg @@ -1,4 +1,4 @@ - - - + + + diff --git a/packages/console/src/assets/docs/guides/spa-webflow/logo.svg b/packages/console/src/assets/docs/guides/spa-webflow/logo.svg index e5df00dfe65..c4ffbd645e9 100644 --- a/packages/console/src/assets/docs/guides/spa-webflow/logo.svg +++ b/packages/console/src/assets/docs/guides/spa-webflow/logo.svg @@ -1,10 +1,3 @@ - - - - - - - - - + + diff --git a/packages/console/src/assets/docs/guides/third-party-oidc/logo.svg b/packages/console/src/assets/docs/guides/third-party-oidc/logo.svg index 0958f5836e9..3ef36eaf00c 100644 --- a/packages/console/src/assets/docs/guides/third-party-oidc/logo.svg +++ b/packages/console/src/assets/docs/guides/third-party-oidc/logo.svg @@ -1,12 +1,11 @@ - - - - - - - - - - + + + + + + + + + + diff --git a/packages/console/src/assets/docs/guides/types.ts b/packages/console/src/assets/docs/guides/types.ts index 0b18523c99e..4e6f0b29433 100644 --- a/packages/console/src/assets/docs/guides/types.ts +++ b/packages/console/src/assets/docs/guides/types.ts @@ -49,6 +49,9 @@ export type Guide = { Logo: | LazyExoticComponent | ((props: { readonly className?: string }) => JSX.Element); + DarkLogo?: + | LazyExoticComponent + | ((props: { readonly className?: string }) => JSX.Element); Component: LazyExoticComponent>; metadata: Readonly; }; diff --git a/packages/console/src/assets/docs/guides/web-dotnet-core-blazor-server/logo.svg b/packages/console/src/assets/docs/guides/web-dotnet-core-blazor-server/logo.svg index 29dc61d07a8..16f6b42fd71 100644 --- a/packages/console/src/assets/docs/guides/web-dotnet-core-blazor-server/logo.svg +++ b/packages/console/src/assets/docs/guides/web-dotnet-core-blazor-server/logo.svg @@ -1,6 +1,4 @@ - - - - - + + + diff --git a/packages/console/src/assets/docs/guides/web-dotnet-core-blazor-wasm/logo.svg b/packages/console/src/assets/docs/guides/web-dotnet-core-blazor-wasm/logo.svg index 29dc61d07a8..16f6b42fd71 100644 --- a/packages/console/src/assets/docs/guides/web-dotnet-core-blazor-wasm/logo.svg +++ b/packages/console/src/assets/docs/guides/web-dotnet-core-blazor-wasm/logo.svg @@ -1,6 +1,4 @@ - - - - - + + + diff --git a/packages/console/src/assets/docs/guides/web-dotnet-core-mvc/fragments/_add-authentication.mdx b/packages/console/src/assets/docs/guides/web-dotnet-core-mvc/fragments/_add-authentication.mdx index 34b1fe74690..62a183eab90 100644 --- a/packages/console/src/assets/docs/guides/web-dotnet-core-mvc/fragments/_add-authentication.mdx +++ b/packages/console/src/assets/docs/guides/web-dotnet-core-mvc/fragments/_add-authentication.mdx @@ -9,7 +9,7 @@ builder.Services.AddLogtoAuthentication(options => { options.Endpoint = "${props.endpoint}"; options.AppId = "${props.app.id}"; - options.AppSecret = "${props.app.secret}"; + options.AppSecret = "${props.secrets[0]?.value ?? props.app.secret}"; }); app.UseAuthentication();`} diff --git a/packages/console/src/assets/docs/guides/web-dotnet-core-mvc/logo.svg b/packages/console/src/assets/docs/guides/web-dotnet-core-mvc/logo.svg index d04bf0477bf..3aa3a41c122 100644 --- a/packages/console/src/assets/docs/guides/web-dotnet-core-mvc/logo.svg +++ b/packages/console/src/assets/docs/guides/web-dotnet-core-mvc/logo.svg @@ -1,2 +1,12 @@ - -logo_NETcore \ No newline at end of file + + + + + + + + + + + + diff --git a/packages/console/src/assets/docs/guides/web-dotnet-core/logo.svg b/packages/console/src/assets/docs/guides/web-dotnet-core/logo.svg index d04bf0477bf..3aa3a41c122 100644 --- a/packages/console/src/assets/docs/guides/web-dotnet-core/logo.svg +++ b/packages/console/src/assets/docs/guides/web-dotnet-core/logo.svg @@ -1,2 +1,12 @@ - -logo_NETcore \ No newline at end of file + + + + + + + + + + + + diff --git a/packages/console/src/assets/docs/guides/web-express/README.mdx b/packages/console/src/assets/docs/guides/web-express/README.mdx index 4325a964589..9fcb5f7a336 100644 --- a/packages/console/src/assets/docs/guides/web-express/README.mdx +++ b/packages/console/src/assets/docs/guides/web-express/README.mdx @@ -31,7 +31,7 @@ Prepare configuration for the Logto client: const config: LogtoExpressConfig = { endpoint: '${props.endpoint}', appId: '${props.app.id}', - appSecret: '${props.app.secret}', + appSecret: '${props.secrets[0]?.value ?? props.app.secret}', baseUrl: 'http://localhost:3000', // Change to your own base URL }; `} diff --git a/packages/console/src/assets/docs/guides/web-express/logo-dark.svg b/packages/console/src/assets/docs/guides/web-express/logo-dark.svg new file mode 100644 index 00000000000..8ed50c5f2ab --- /dev/null +++ b/packages/console/src/assets/docs/guides/web-express/logo-dark.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/packages/console/src/assets/docs/guides/web-express/logo.svg b/packages/console/src/assets/docs/guides/web-express/logo.svg index bda5f80dabc..db674128014 100644 --- a/packages/console/src/assets/docs/guides/web-express/logo.svg +++ b/packages/console/src/assets/docs/guides/web-express/logo.svg @@ -1,3 +1,10 @@ - - + + + + + + + + + diff --git a/packages/console/src/assets/docs/guides/web-go/README.mdx b/packages/console/src/assets/docs/guides/web-go/README.mdx index 26e34567b4a..478f88527a2 100644 --- a/packages/console/src/assets/docs/guides/web-go/README.mdx +++ b/packages/console/src/assets/docs/guides/web-go/README.mdx @@ -145,7 +145,7 @@ First, create a Logto config: logtoConfig := &client.LogtoConfig{ Endpoint: "${props.endpoint}", AppId: "${props.app.id}", - AppSecret: "${props.app.secret}", + AppSecret: "${props.secrets[0]?.value ?? props.app.secret}", } // ... diff --git a/packages/console/src/assets/docs/guides/web-go/logo.svg b/packages/console/src/assets/docs/guides/web-go/logo.svg index 35afcc5967c..ba1ff3e67aa 100644 --- a/packages/console/src/assets/docs/guides/web-go/logo.svg +++ b/packages/console/src/assets/docs/guides/web-go/logo.svg @@ -1,6 +1,6 @@ - - - - - + + + + + diff --git a/packages/console/src/assets/docs/guides/web-gpt-plugin/components/AlwaysIssueRefreshToken.tsx b/packages/console/src/assets/docs/guides/web-gpt-plugin/components/AlwaysIssueRefreshToken.tsx index 858c8fe0f8d..9a446392cda 100644 --- a/packages/console/src/assets/docs/guides/web-gpt-plugin/components/AlwaysIssueRefreshToken.tsx +++ b/packages/console/src/assets/docs/guides/web-gpt-plugin/components/AlwaysIssueRefreshToken.tsx @@ -23,6 +23,7 @@ export default function AlwaysIssueRefreshToken() { await api.patch(`api/applications/${app.id}`, { json: { customClientMetadata: { + ...app.customClientMetadata, alwaysIssueRefreshToken: value, }, }, diff --git a/packages/console/src/assets/docs/guides/web-gpt-plugin/components/ClientBasics/index.tsx b/packages/console/src/assets/docs/guides/web-gpt-plugin/components/ClientBasics/index.tsx index c7fae219f79..b5ab4e70ba7 100644 --- a/packages/console/src/assets/docs/guides/web-gpt-plugin/components/ClientBasics/index.tsx +++ b/packages/console/src/assets/docs/guides/web-gpt-plugin/components/ClientBasics/index.tsx @@ -4,7 +4,7 @@ import { GuideContext } from '@/components/Guide'; import CopyToClipboard from '@/ds-components/CopyToClipboard'; import FormField from '@/ds-components/FormField'; -import * as styles from './index.module.scss'; +import styles from './index.module.scss'; export default function ClientBasics() { const { app } = useContext(GuideContext); diff --git a/packages/console/src/assets/docs/guides/web-gpt-plugin/logo.svg b/packages/console/src/assets/docs/guides/web-gpt-plugin/logo.svg index b153d5dee60..0c89371dfdf 100644 --- a/packages/console/src/assets/docs/guides/web-gpt-plugin/logo.svg +++ b/packages/console/src/assets/docs/guides/web-gpt-plugin/logo.svg @@ -1,11 +1,11 @@ - - - - + + + + - - + + diff --git a/packages/console/src/assets/docs/guides/web-java-spring-boot/README.mdx b/packages/console/src/assets/docs/guides/web-java-spring-boot/README.mdx index 92625af90a4..80f83361dc6 100644 --- a/packages/console/src/assets/docs/guides/web-java-spring-boot/README.mdx +++ b/packages/console/src/assets/docs/guides/web-java-spring-boot/README.mdx @@ -63,7 +63,7 @@ Add the following configuration to your `application.properties` file: {`spring.security.oauth2.client.registration.logto.client-name=logto spring.security.oauth2.client.registration.logto.client-id=${props.app.id} -spring.security.oauth2.client.registration.logto.client-secret=${props.app.secret} +spring.security.oauth2.client.registration.logto.client-secret=${props.secrets[0]?.value ?? props.app.secret} spring.security.oauth2.client.registration.logto.redirect-uri={baseUrl}/login/oauth2/code/{registrationId} spring.security.oauth2.client.registration.logto.authorization-grant-type=authorization_code spring.security.oauth2.client.registration.logto.scope=openid,profile,email,offline_access diff --git a/packages/console/src/assets/docs/guides/web-java-spring-boot/index.ts b/packages/console/src/assets/docs/guides/web-java-spring-boot/index.ts index cf1e468a2cb..f40d9bd7c7e 100644 --- a/packages/console/src/assets/docs/guides/web-java-spring-boot/index.ts +++ b/packages/console/src/assets/docs/guides/web-java-spring-boot/index.ts @@ -3,7 +3,7 @@ import { ApplicationType } from '@logto/schemas'; import { type GuideMetadata } from '../types'; const metadata: Readonly = Object.freeze({ - name: 'Java Spring Boot Web', + name: 'Java Spring Boot', description: 'Spring Boot is a web framework for Java that enables developers to build secure, fast, and scalable server applications with the Java programming language.', target: ApplicationType.Traditional, @@ -11,6 +11,7 @@ const metadata: Readonly = Object.freeze({ repo: 'spring-boot-sample', path: '', }, + isFeatured: true, }); export default metadata; diff --git a/packages/console/src/assets/docs/guides/web-java-spring-boot/logo.svg b/packages/console/src/assets/docs/guides/web-java-spring-boot/logo.svg index d7256ddcf41..2d4fe64ea1a 100644 --- a/packages/console/src/assets/docs/guides/web-java-spring-boot/logo.svg +++ b/packages/console/src/assets/docs/guides/web-java-spring-boot/logo.svg @@ -1 +1,10 @@ - + + + + + + + + + + diff --git a/packages/console/src/assets/docs/guides/web-next-app-router/README.mdx b/packages/console/src/assets/docs/guides/web-next-app-router/README.mdx index 5c6196036df..1ca7e409158 100644 --- a/packages/console/src/assets/docs/guides/web-next-app-router/README.mdx +++ b/packages/console/src/assets/docs/guides/web-next-app-router/README.mdx @@ -26,7 +26,7 @@ Prepare configuration for the Logto client: {`export const logtoConfig = { endpoint: '${props.endpoint}', appId: '${props.app.id}', - appSecret: '${props.app.secret}', + appSecret: '${props.secrets[0]?.value ?? props.app.secret}', baseUrl: 'http://localhost:3000', // Change to your own base URL cookieSecret: '${generateStandardSecret()}', // Auto-generated 32 digit secret cookieSecure: process.env.NODE_ENV === 'production', diff --git a/packages/console/src/assets/docs/guides/web-next-app-router/logo-dark.svg b/packages/console/src/assets/docs/guides/web-next-app-router/logo-dark.svg new file mode 100644 index 00000000000..69d2a9cd56d --- /dev/null +++ b/packages/console/src/assets/docs/guides/web-next-app-router/logo-dark.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/packages/console/src/assets/docs/guides/web-next-app-router/logo.svg b/packages/console/src/assets/docs/guides/web-next-app-router/logo.svg index c1db01c06b7..252c045953d 100644 --- a/packages/console/src/assets/docs/guides/web-next-app-router/logo.svg +++ b/packages/console/src/assets/docs/guides/web-next-app-router/logo.svg @@ -1,10 +1,3 @@ - - - - - - - - - + + diff --git a/packages/console/src/assets/docs/guides/web-next-auth/README.mdx b/packages/console/src/assets/docs/guides/web-next-auth/README.mdx index badcf966507..2911141745d 100644 --- a/packages/console/src/assets/docs/guides/web-next-auth/README.mdx +++ b/packages/console/src/assets/docs/guides/web-next-auth/README.mdx @@ -2,6 +2,8 @@ import InlineNotification from '@/ds-components/InlineNotification'; import UriInputField from '@/mdx-components/UriInputField'; import Steps from '@/mdx-components/Steps'; import Step from '@/mdx-components/Step'; +import TabItem from '@/mdx-components/TabItem'; +import Tabs from '@/mdx-components/Tabs'; @@ -31,9 +33,43 @@ Modify your API route config of Next Auth, if you are using Pages Router, the fi The following is an example of App Router: - + + + + {`import NextAuth from 'next-auth'; +export const { handlers, signIn, signOut, auth } = NextAuth({ + providers: [ + { + id: 'logto', + name: 'Logto', + type: 'oidc', + issuer: '${props.endpoint}oidc', + clientId: '${props.app.id}', + clientSecret: '${props.secrets[0]?.value ?? props.app.secret}', + authorization: { + params: { scope: 'openid offline_access profile email' }, + }, + profile(profile) { + // You can customize the user profile mapping here + return { + id: profile.sub, + name: profile.name ?? profile.username, + email: profile.email, + image: profile.picture, + }; + }, + }, + ], +});`} + + + + + +{`import NextAuth from 'next-auth'; + const handler = NextAuth({ providers: [ { @@ -45,7 +81,7 @@ const handler = NextAuth({ wellKnown: '${props.endpoint}oidc/.well-known/openid-configuration', authorization: { params: { scope: 'openid offline_access profile email' } }, clientId: '${props.app.id}'', - clientSecret: '${props.app.secret}', + clientSecret: '${props.secrets[0]?.value ?? props.app.secret}', client: { id_token_signed_response_alg: 'ES384', }, @@ -64,6 +100,9 @@ const handler = NextAuth({ export { handler as GET, handler as POST };`} + + + diff --git a/packages/console/src/assets/docs/guides/web-next-auth/index.ts b/packages/console/src/assets/docs/guides/web-next-auth/index.ts index 003d5577c4c..bc3dfd037bc 100644 --- a/packages/console/src/assets/docs/guides/web-next-auth/index.ts +++ b/packages/console/src/assets/docs/guides/web-next-auth/index.ts @@ -3,8 +3,8 @@ import { ApplicationType } from '@logto/schemas'; import { type GuideMetadata } from '../types'; const metadata: Readonly = Object.freeze({ - name: 'Next Auth', - description: 'Authentication for Next.js.', + name: 'Passport', + description: 'Passport is authentication middleware for Node.js.', target: ApplicationType.Traditional, }); diff --git a/packages/console/src/assets/docs/guides/web-next-auth/logo.svg b/packages/console/src/assets/docs/guides/web-next-auth/logo.svg index 47b9c27d79a..5bd92bb887f 100644 --- a/packages/console/src/assets/docs/guides/web-next-auth/logo.svg +++ b/packages/console/src/assets/docs/guides/web-next-auth/logo.svg @@ -1,25 +1,27 @@ - - - - - - - - - - + + + + + + - - - + + + - - - + + + + - - - + + + + + + + + diff --git a/packages/console/src/assets/docs/guides/web-next/README.mdx b/packages/console/src/assets/docs/guides/web-next/README.mdx index 961465f691c..6cb14c8c16f 100644 --- a/packages/console/src/assets/docs/guides/web-next/README.mdx +++ b/packages/console/src/assets/docs/guides/web-next/README.mdx @@ -28,7 +28,7 @@ Import and initialize LogtoClient: export const logtoClient = new LogtoClient({ endpoint: '${props.endpoint}', appId: '${props.app.id}', - appSecret: '${props.app.secret}', + appSecret: '${props.secrets[0]?.value ?? props.app.secret}', baseUrl: '${defaultBaseUrl}', // Change to your own base URL cookieSecret: '${generateStandardSecret()}', // Auto-generated 32 digit secret cookieSecure: process.env.NODE_ENV === 'production', diff --git a/packages/console/src/assets/docs/guides/web-next/logo-dark.svg b/packages/console/src/assets/docs/guides/web-next/logo-dark.svg new file mode 100644 index 00000000000..69d2a9cd56d --- /dev/null +++ b/packages/console/src/assets/docs/guides/web-next/logo-dark.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/packages/console/src/assets/docs/guides/web-next/logo.svg b/packages/console/src/assets/docs/guides/web-next/logo.svg index c1db01c06b7..252c045953d 100644 --- a/packages/console/src/assets/docs/guides/web-next/logo.svg +++ b/packages/console/src/assets/docs/guides/web-next/logo.svg @@ -1,10 +1,3 @@ - - - - - - - - - + + diff --git a/packages/console/src/assets/docs/guides/web-nuxt/README.mdx b/packages/console/src/assets/docs/guides/web-nuxt/README.mdx index b274d4849e7..29c58fa6663 100644 --- a/packages/console/src/assets/docs/guides/web-nuxt/README.mdx +++ b/packages/console/src/assets/docs/guides/web-nuxt/README.mdx @@ -35,7 +35,7 @@ In your Nuxt config file, add the Logto module and configure it: logto: { endpoint: '${props.endpoint}', appId: '${props.app.id}', - appSecret: '${props.app.secret}', + appSecret: '${props.secrets[0]?.value ?? props.app.secret}', cookieEncryptionKey: '${cookieEncryptionKey}', // Random-generated }, }, @@ -48,7 +48,7 @@ Since these information are sensitive, it's recommended to use environment varia {`NUXT_LOGTO_ENDPOINT=${props.endpoint} NUXT_LOGTO_APP_ID=${props.app.id} -NUXT_LOGTO_APP_SECRET=${props.app.secret} +NUXT_LOGTO_APP_SECRET=${props.secrets[0]?.value ?? props.app.secret} NUXT_LOGTO_COOKIE_ENCRYPTION_KEY=${cookieEncryptionKey} # Random-generated `} diff --git a/packages/console/src/assets/docs/guides/web-nuxt/logo.svg b/packages/console/src/assets/docs/guides/web-nuxt/logo.svg index ead151fc7ad..a2f1522d636 100644 --- a/packages/console/src/assets/docs/guides/web-nuxt/logo.svg +++ b/packages/console/src/assets/docs/guides/web-nuxt/logo.svg @@ -1,3 +1,3 @@ - - + + diff --git a/packages/console/src/assets/docs/guides/web-outline/logo-dark.svg b/packages/console/src/assets/docs/guides/web-outline/logo-dark.svg new file mode 100644 index 00000000000..34cb2b54aee --- /dev/null +++ b/packages/console/src/assets/docs/guides/web-outline/logo-dark.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/packages/console/src/assets/docs/guides/web-outline/logo.svg b/packages/console/src/assets/docs/guides/web-outline/logo.svg index eadcc194278..15f815789be 100644 --- a/packages/console/src/assets/docs/guides/web-outline/logo.svg +++ b/packages/console/src/assets/docs/guides/web-outline/logo.svg @@ -1,5 +1,10 @@ - - + + + + + + + + + diff --git a/packages/console/src/assets/docs/guides/web-passport/README.mdx b/packages/console/src/assets/docs/guides/web-passport/README.mdx new file mode 100644 index 00000000000..70d294ae5df --- /dev/null +++ b/packages/console/src/assets/docs/guides/web-passport/README.mdx @@ -0,0 +1,163 @@ +import InlineNotification from '@/ds-components/InlineNotification'; +import UriInputField from '@/mdx-components/UriInputField'; +import Steps from '@/mdx-components/Steps'; +import Step from '@/mdx-components/Step'; +import NpmLikeInstallation from '@/mdx-components/NpmLikeInstallation'; + + + + + +In this guide, we assume you have set up Express with session in you project. If you haven't, check out the [Express.js website](https://expressjs.com/) to get started. + + + + + +Install `passport` and the OIDC strategy plugin, `passport-openidconnect`: + + + + + + + + + In the following steps, we assume your app is running on http://localhost:3000. + + +First, let’s enter your redirect URI. + + + +Don't forget to click the **Save** button. + + + + + + + {`import passport from 'passport'; +import OpenIDConnectStrategy, { type Profile, type VerifyCallback } from 'passport-openidconnect'; + +const endpoint = '${props.endpoint}'; +const appId = '${props.app.id}'; +const appSecret = '${props.app.secret}'; + +export default function initPassport() { + passport.use( + new OpenIDConnectStrategy( + { + issuer: \`\${endpoint}/oidc\`, + authorizationURL: \`\${endpoint}/oidc/auth\`, + tokenURL: \`\${endpoint}/oidc/token\`, + userInfoURL: \`\${endpoint}/oidc/me\`, + clientID: appId, + clientSecret: appSecret, + callbackURL: '/callback', + scope: ['profile', 'offline_access'], + }, + (issuer: string, profile: Profile, callback: VerifyCallback) => { + callback(null, profile); + } + ) + ); + + passport.serializeUser((user, callback) => { + callback(null, user); + }); + + passport.deserializeUser(function (user, callback) { + callback(null, user as Express.User); + }); +}`} + + +This code initializes Passport with the **`OpenIDConnectStrategy`**. The serialize and deserialize methods are set for demonstration purposes. + +Ensure to initialize and attach Passport middleware in your application: + +```tsx +import initPassport from 'src/passport'; + +// ... other code +initPassport(); +// ... other code +app.use(passport.authenticate('session')); +// ... other code +``` + + + + + +We'll now create specific routes for authentication processes: + +### Sign in: `/sign-in` + +```tsx +app.get('/sign-in', passport.authenticate('openidconnect')); +``` + +This route builds and redirects to an OIDC auth route. + +### Handle sign in callback: `/callback` + +```tsx +app.get( + '/callback', + passport.authenticate('openidconnect', { + successReturnToOrRedirect: '/', + }) +); +``` + +This handles the OIDC sign-in callback, stores tokens, and redirects to the homepage. + +### Sign out: `/sign-out` + +```tsx +app.get('/sign-out', (request, response, next) => { + request.logout((error) => { + if (error) { + next(error); + return; + } + response.redirect(`${endpoint}/oidc/session/end?client_id=${appId}`); + }); +}); +``` + +This redirects to Logto's session end URL, then back to the homepage. + +### Add to the homepage + +```tsx +app.get('/', (request: Request, response) => { + const { user } = request; + response.setHeader('content-type', 'text/html'); + + if (user) { + response.end( + `

Hello Logto

Signed in as ${JSON.stringify( + user + )}, Sign Out

` + ); + } else { + response.end(`

Hello Logto

Sign In

`); + } +}); +``` + +
+ + + +Now, you can test your application to see if the authentication works as expected. + + + + diff --git a/packages/console/src/assets/docs/guides/web-passport/config.json b/packages/console/src/assets/docs/guides/web-passport/config.json new file mode 100644 index 00000000000..c81c3a59b30 --- /dev/null +++ b/packages/console/src/assets/docs/guides/web-passport/config.json @@ -0,0 +1,3 @@ +{ + "order": 6.1 +} diff --git a/packages/console/src/assets/docs/guides/web-passport/index.ts b/packages/console/src/assets/docs/guides/web-passport/index.ts new file mode 100644 index 00000000000..bc3dfd037bc --- /dev/null +++ b/packages/console/src/assets/docs/guides/web-passport/index.ts @@ -0,0 +1,11 @@ +import { ApplicationType } from '@logto/schemas'; + +import { type GuideMetadata } from '../types'; + +const metadata: Readonly = Object.freeze({ + name: 'Passport', + description: 'Passport is authentication middleware for Node.js.', + target: ApplicationType.Traditional, +}); + +export default metadata; diff --git a/packages/console/src/assets/docs/guides/web-passport/logo-dark.svg b/packages/console/src/assets/docs/guides/web-passport/logo-dark.svg new file mode 100644 index 00000000000..a9337f4c359 --- /dev/null +++ b/packages/console/src/assets/docs/guides/web-passport/logo-dark.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/packages/console/src/assets/docs/guides/web-passport/logo.svg b/packages/console/src/assets/docs/guides/web-passport/logo.svg new file mode 100644 index 00000000000..f11c4f4d8a2 --- /dev/null +++ b/packages/console/src/assets/docs/guides/web-passport/logo.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/packages/console/src/assets/docs/guides/web-php/README.mdx b/packages/console/src/assets/docs/guides/web-php/README.mdx index 6dfe1d3d7af..32ea660d4fa 100644 --- a/packages/console/src/assets/docs/guides/web-php/README.mdx +++ b/packages/console/src/assets/docs/guides/web-php/README.mdx @@ -35,7 +35,7 @@ $client = new LogtoClient( new LogtoConfig( endpoint: "${props.endpoint}", appId: "${props.app.id}", - appSecret: "${props.app.secret}", + appSecret: "${props.secrets[0]?.value ?? props.app.secret}", ), );`}
diff --git a/packages/console/src/assets/docs/guides/web-php/logo.svg b/packages/console/src/assets/docs/guides/web-php/logo.svg index e9f2a895255..8ca1c32c63f 100644 --- a/packages/console/src/assets/docs/guides/web-php/logo.svg +++ b/packages/console/src/assets/docs/guides/web-php/logo.svg @@ -1,5 +1,12 @@ - - - - + + + + + + + + + + + diff --git a/packages/console/src/assets/docs/guides/web-python/README.mdx b/packages/console/src/assets/docs/guides/web-python/README.mdx index 52fd2300a3b..1616da8d390 100644 --- a/packages/console/src/assets/docs/guides/web-python/README.mdx +++ b/packages/console/src/assets/docs/guides/web-python/README.mdx @@ -32,7 +32,7 @@ client = LogtoClient( LogtoConfig( endpoint="${props.endpoint}", appId="${props.app.id}", - appSecret="${props.app.secret}", + appSecret="${props.secrets[0]?.value ?? props.app.secret}", ) )`}
diff --git a/packages/console/src/assets/docs/guides/web-python/logo.svg b/packages/console/src/assets/docs/guides/web-python/logo.svg index c33c339ecb7..1d2ba15af8d 100644 --- a/packages/console/src/assets/docs/guides/web-python/logo.svg +++ b/packages/console/src/assets/docs/guides/web-python/logo.svg @@ -1,14 +1,19 @@ - - - + + + + + - + - + + + + diff --git a/packages/console/src/assets/docs/guides/web-ruby/README.mdx b/packages/console/src/assets/docs/guides/web-ruby/README.mdx index 63d9e9e5470..89f05318152 100644 --- a/packages/console/src/assets/docs/guides/web-ruby/README.mdx +++ b/packages/console/src/assets/docs/guides/web-ruby/README.mdx @@ -41,7 +41,7 @@ In the file where you want to initialize the Logto client (e.g. a base controlle config: LogtoClient::Config.new( endpoint: "${props.endpoint}", app_id: "${props.app.id}", - app_secret: "${props.app.secret}" + app_secret: "${props.secrets[0]?.value ?? props.app.secret}" ), navigate: ->(uri) { a_redirect_method(uri) }, storage: LogtoClient::SessionStorage.new(the_session_object) @@ -64,7 +64,7 @@ class SampleController < ApplicationController config: LogtoClient::Config.new( endpoint: "${props.endpoint}", app_id: "${props.app.id}", - app_secret: "${props.app.secret}" + app_secret: "${props.secrets[0]?.value ?? props.app.secret}" ), # Allow the client to redirect to other hosts (i.e. your Logto tenant) navigate: ->(uri) { redirect_to(uri, allow_other_host: true) }, diff --git a/packages/console/src/assets/docs/guides/web-ruby/logo.svg b/packages/console/src/assets/docs/guides/web-ruby/logo.svg new file mode 100644 index 00000000000..99dbe45db06 --- /dev/null +++ b/packages/console/src/assets/docs/guides/web-ruby/logo.svg @@ -0,0 +1,199 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/console/src/assets/docs/guides/web-sveltekit/README.mdx b/packages/console/src/assets/docs/guides/web-sveltekit/README.mdx index bd361427691..d3b1cbff7b8 100644 --- a/packages/console/src/assets/docs/guides/web-sveltekit/README.mdx +++ b/packages/console/src/assets/docs/guides/web-sveltekit/README.mdx @@ -40,7 +40,7 @@ export const handle = handleLogto( { endpoint: '${props.endpoint}', appId: '${props.app.id}', - appSecret: '${props.app.secret}', + appSecret: '${props.secrets[0]?.value ?? props.app.secret}', }, { encryptionKey: '${cookieEncryptionKey}' } // Random-generated key );`} diff --git a/packages/console/src/assets/docs/guides/web-sveltekit/logo.svg b/packages/console/src/assets/docs/guides/web-sveltekit/logo.svg index 0ab1ab0c3c0..09759b47f8a 100644 --- a/packages/console/src/assets/docs/guides/web-sveltekit/logo.svg +++ b/packages/console/src/assets/docs/guides/web-sveltekit/logo.svg @@ -1 +1,4 @@ - \ No newline at end of file + + + + diff --git a/packages/console/src/assets/docs/guides/web-wordpress/logo.svg b/packages/console/src/assets/docs/guides/web-wordpress/logo.svg index 72183e90424..30eb694c1ee 100644 --- a/packages/console/src/assets/docs/guides/web-wordpress/logo.svg +++ b/packages/console/src/assets/docs/guides/web-wordpress/logo.svg @@ -1 +1,7 @@ - \ No newline at end of file + + + + + + + diff --git a/packages/console/src/assets/icons/calendar-dark.svg b/packages/console/src/assets/icons/calendar-dark.svg new file mode 100644 index 00000000000..d63565f701f --- /dev/null +++ b/packages/console/src/assets/icons/calendar-dark.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/packages/console/src/assets/icons/calendar.svg b/packages/console/src/assets/icons/calendar.svg index b8ffd462547..59e439e9150 100644 --- a/packages/console/src/assets/icons/calendar.svg +++ b/packages/console/src/assets/icons/calendar.svg @@ -1,5 +1,5 @@ - + diff --git a/packages/console/src/assets/icons/email.svg b/packages/console/src/assets/icons/email.svg index 6d156693a7f..36cdd5c31d8 100644 --- a/packages/console/src/assets/icons/email.svg +++ b/packages/console/src/assets/icons/email.svg @@ -1,4 +1,4 @@ - + diff --git a/packages/console/src/assets/icons/github.svg b/packages/console/src/assets/icons/github.svg index 52779b17747..3e30da2e97b 100644 --- a/packages/console/src/assets/icons/github.svg +++ b/packages/console/src/assets/icons/github.svg @@ -1,4 +1,4 @@ - + diff --git a/packages/console/src/assets/images/blur-preview.svg b/packages/console/src/assets/images/blur-preview.svg new file mode 100644 index 00000000000..9d07235496a --- /dev/null +++ b/packages/console/src/assets/images/blur-preview.svg @@ -0,0 +1,102 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/console/src/cloud/AppRoutes.tsx b/packages/console/src/cloud/AppRoutes.tsx index 9870c709ac6..2e49878cfa8 100644 --- a/packages/console/src/cloud/AppRoutes.tsx +++ b/packages/console/src/cloud/AppRoutes.tsx @@ -9,7 +9,7 @@ import CheckoutSuccessCallback from '@/pages/CheckoutSuccessCallback'; import Profile from '@/pages/Profile'; import HandleSocialCallback from '@/pages/Profile/containers/HandleSocialCallback'; -import * as styles from './AppRoutes.module.scss'; +import styles from './AppRoutes.module.scss'; import Main from './pages/Main'; import SocialDemoCallback from './pages/SocialDemoCallback'; diff --git a/packages/console/src/cloud/pages/Main/InvitationList/index.tsx b/packages/console/src/cloud/pages/Main/InvitationList/index.tsx index e86b71147fe..13e17b42a47 100644 --- a/packages/console/src/cloud/pages/Main/InvitationList/index.tsx +++ b/packages/console/src/cloud/pages/Main/InvitationList/index.tsx @@ -2,7 +2,7 @@ import { OrganizationInvitationStatus, getTenantIdFromOrganizationId } from '@lo import { useContext, useState } from 'react'; import { useTranslation } from 'react-i18next'; -import OrganizationIcon from '@/assets/icons/organization-preview.svg'; +import OrganizationIcon from '@/assets/icons/organization-preview.svg?react'; import { useCloudApi } from '@/cloud/hooks/use-cloud-api'; import { type InvitationListResponse } from '@/cloud/types/router'; import TenantEnvTag from '@/components/TenantEnvTag'; @@ -13,7 +13,7 @@ import Spacer from '@/ds-components/Spacer'; import useTenantPathname from '@/hooks/use-tenant-pathname'; import useUserOnboardingData from '@/onboarding/hooks/use-user-onboarding-data'; -import * as styles from './index.module.scss'; +import styles from './index.module.scss'; type Props = { readonly invitations: InvitationListResponse; diff --git a/packages/console/src/cloud/pages/Main/TenantLandingPage/TenantLandingPageContent/index.tsx b/packages/console/src/cloud/pages/Main/TenantLandingPage/TenantLandingPageContent/index.tsx index 6978b899366..e51c9c24c4b 100644 --- a/packages/console/src/cloud/pages/Main/TenantLandingPage/TenantLandingPageContent/index.tsx +++ b/packages/console/src/cloud/pages/Main/TenantLandingPage/TenantLandingPageContent/index.tsx @@ -2,9 +2,9 @@ import { Theme } from '@logto/schemas'; import classNames from 'classnames'; import { useContext, useState } from 'react'; -import Plus from '@/assets/icons/plus.svg'; -import TenantLandingPageImageDark from '@/assets/images/tenant-landing-page-dark.svg'; -import TenantLandingPageImage from '@/assets/images/tenant-landing-page.svg'; +import Plus from '@/assets/icons/plus.svg?react'; +import TenantLandingPageImageDark from '@/assets/images/tenant-landing-page-dark.svg?react'; +import TenantLandingPageImage from '@/assets/images/tenant-landing-page.svg?react'; import { type TenantResponse } from '@/cloud/types/router'; import CreateTenantModal from '@/components/CreateTenantModal'; import { TenantsContext } from '@/contexts/TenantsProvider'; @@ -12,7 +12,7 @@ import Button from '@/ds-components/Button'; import DynamicT from '@/ds-components/DynamicT'; import useTheme from '@/hooks/use-theme'; -import * as styles from './index.module.scss'; +import styles from './index.module.scss'; type Props = { readonly className?: string; diff --git a/packages/console/src/cloud/pages/Main/TenantLandingPage/index.tsx b/packages/console/src/cloud/pages/Main/TenantLandingPage/index.tsx index fb99b70dcc4..d5fd24d6c70 100644 --- a/packages/console/src/cloud/pages/Main/TenantLandingPage/index.tsx +++ b/packages/console/src/cloud/pages/Main/TenantLandingPage/index.tsx @@ -1,7 +1,7 @@ import Topbar from '@/components/Topbar'; import TenantLandingPageContent from './TenantLandingPageContent'; -import * as styles from './index.module.scss'; +import styles from './index.module.scss'; function TenantLandingPage() { return ( diff --git a/packages/console/src/cloud/pages/SocialDemoCallback/index.tsx b/packages/console/src/cloud/pages/SocialDemoCallback/index.tsx index 5c18de94f1c..b83cd0c46a5 100644 --- a/packages/console/src/cloud/pages/SocialDemoCallback/index.tsx +++ b/packages/console/src/cloud/pages/SocialDemoCallback/index.tsx @@ -3,12 +3,12 @@ import { useEffect } from 'react'; import { useTranslation } from 'react-i18next'; import { useSearchParams } from 'react-router-dom'; -import CongratsDark from '@/assets/images/congrats-dark.svg'; -import Congrats from '@/assets/images/congrats.svg'; +import CongratsDark from '@/assets/images/congrats-dark.svg?react'; +import Congrats from '@/assets/images/congrats.svg?react'; import Card from '@/ds-components/Card'; import useTheme from '@/hooks/use-theme'; -import * as styles from './index.module.scss'; +import styles from './index.module.scss'; function SocialDemoCallback() { const theme = useTheme(); diff --git a/packages/console/src/cloud/types/router.ts b/packages/console/src/cloud/types/router.ts index ed175b7afda..7d6cf2f10bc 100644 --- a/packages/console/src/cloud/types/router.ts +++ b/packages/console/src/cloud/types/router.ts @@ -11,10 +11,30 @@ export type SubscriptionPlanResponse = GuardedResponse< GetRoutes['/api/subscription-plans'] >[number]; +export type LogtoSkuResponse = GetArrayElementType>; + export type Subscription = GuardedResponse; +/** @deprecated */ export type SubscriptionUsage = GuardedResponse; +/* ===== Use `New` in the naming to avoid confusion with legacy types ===== */ +/** The response of `GET /api/tenants/my/subscription/quota` has the same response type. */ +export type NewSubscriptionQuota = GuardedResponse< + GetRoutes['/api/tenants/:tenantId/subscription/quota'] +>; + +/** The response of `GET /api/tenants/my/subscription/usage` has the same response type. */ +export type NewSubscriptionUsage = GuardedResponse< + GetRoutes['/api/tenants/:tenantId/subscription/usage'] +>; + +/** The response of `GET /api/tenants/my/subscription/usage/:entityName/scopes` has the same response type. */ +export type NewSubscriptionScopeUsage = GuardedResponse< + GetRoutes['/api/tenants/:tenantId/subscription/usage/:entityName/scopes'] +>; +/* ===== Use `New` in the naming to avoid confusion with legacy types ===== */ + export type InvoicesResponse = GuardedResponse; export type InvitationResponse = GuardedResponse; diff --git a/packages/console/src/components/ActionBar/index.tsx b/packages/console/src/components/ActionBar/index.tsx index 11d09537973..403f3a981cc 100644 --- a/packages/console/src/components/ActionBar/index.tsx +++ b/packages/console/src/components/ActionBar/index.tsx @@ -2,7 +2,7 @@ import type { ReactNode } from 'react'; import ProgressBar from '../ProgressBar'; -import * as styles from './index.module.scss'; +import styles from './index.module.scss'; type Props = { readonly step: number; diff --git a/packages/console/src/components/ActionsButton/index.tsx b/packages/console/src/components/ActionsButton/index.tsx index 575b05f1bd6..00a27113274 100644 --- a/packages/console/src/components/ActionsButton/index.tsx +++ b/packages/console/src/components/ActionsButton/index.tsx @@ -2,15 +2,15 @@ import { type AdminConsoleKey } from '@logto/phrases'; import { useCallback, useState } from 'react'; import { useTranslation } from 'react-i18next'; -import Delete from '@/assets/icons/delete.svg'; -import Edit from '@/assets/icons/edit.svg'; -import More from '@/assets/icons/more.svg'; +import Delete from '@/assets/icons/delete.svg?react'; +import Edit from '@/assets/icons/edit.svg?react'; +import More from '@/assets/icons/more.svg?react'; import ActionMenu, { ActionMenuItem } from '@/ds-components/ActionMenu'; import ConfirmModal from '@/ds-components/ConfirmModal'; import DynamicT from '@/ds-components/DynamicT'; import useActionTranslation from '@/hooks/use-action-translation'; -import * as styles from './index.module.scss'; +import styles from './index.module.scss'; type Props = { /** A function that will be called when the user confirms the deletion. If not provided, diff --git a/packages/console/src/components/AddOnNoticeFooter/index.module.scss b/packages/console/src/components/AddOnNoticeFooter/index.module.scss new file mode 100644 index 00000000000..4a3dc3faa6e --- /dev/null +++ b/packages/console/src/components/AddOnNoticeFooter/index.module.scss @@ -0,0 +1,17 @@ +@use '@/scss/underscore' as _; + +.container { + display: flex; + align-items: center; + gap: _.unit(6); + padding: _.unit(6); + background-color: var(--color-info-container); + margin: 0 _.unit(-6) _.unit(-6); + flex: 1; // Should display in full width + + .description { + flex: 1; + flex-shrink: 0; + font: var(--font-body-2); + } +} diff --git a/packages/console/src/components/AddOnNoticeFooter/index.tsx b/packages/console/src/components/AddOnNoticeFooter/index.tsx new file mode 100644 index 00000000000..6f40c55f4e5 --- /dev/null +++ b/packages/console/src/components/AddOnNoticeFooter/index.tsx @@ -0,0 +1,30 @@ +import { type AdminConsoleKey } from '@logto/phrases'; +import { type ReactNode } from 'react'; + +import Button from '@/ds-components/Button'; + +import styles from './index.module.scss'; + +type Props = { + readonly children: ReactNode; + readonly isLoading?: boolean; + readonly buttonTitle?: AdminConsoleKey; + readonly onClick: () => void; +}; + +function AddOnNoticeFooter({ children, isLoading, onClick, buttonTitle }: Props) { + return ( +
+
{children}
+
+ ); +} + +export default AddOnNoticeFooter; diff --git a/packages/console/src/components/AppError/index.tsx b/packages/console/src/components/AppError/index.tsx index 49a2bfdbb89..468aa8d80fe 100644 --- a/packages/console/src/components/AppError/index.tsx +++ b/packages/console/src/components/AppError/index.tsx @@ -3,15 +3,15 @@ import { Theme } from '@logto/schemas'; import { useState } from 'react'; import { useTranslation } from 'react-i18next'; -import KeyboardArrowDown from '@/assets/icons/keyboard-arrow-down.svg'; -import KeyboardArrowUp from '@/assets/icons/keyboard-arrow-up.svg'; -import ErrorDark from '@/assets/images/error-dark.svg'; -import Error from '@/assets/images/error.svg'; +import KeyboardArrowDown from '@/assets/icons/keyboard-arrow-down.svg?react'; +import KeyboardArrowUp from '@/assets/icons/keyboard-arrow-up.svg?react'; +import ErrorDark from '@/assets/images/error-dark.svg?react'; +import Error from '@/assets/images/error.svg?react'; import Button from '@/ds-components/Button'; import useTheme from '@/hooks/use-theme'; import { onKeyDownHandler } from '@/utils/a11y'; -import * as styles from './index.module.scss'; +import styles from './index.module.scss'; type Props = { readonly title?: string; diff --git a/packages/console/src/components/AppLoading/index.tsx b/packages/console/src/components/AppLoading/index.tsx index 036e8efa270..c0db14cb006 100644 --- a/packages/console/src/components/AppLoading/index.tsx +++ b/packages/console/src/components/AppLoading/index.tsx @@ -1,7 +1,7 @@ -import Logo from '@/assets/images/logo.svg'; +import Logo from '@/assets/images/logo.svg?react'; import { Daisy as Spinner } from '@/ds-components/Spinner'; -import * as styles from './index.module.scss'; +import styles from './index.module.scss'; function AppLoading() { return ( diff --git a/packages/console/src/components/ApplicationCreation/CreateForm/Footer/index.module.scss b/packages/console/src/components/ApplicationCreation/CreateForm/Footer/index.module.scss new file mode 100644 index 00000000000..c9daaa78419 --- /dev/null +++ b/packages/console/src/components/ApplicationCreation/CreateForm/Footer/index.module.scss @@ -0,0 +1,3 @@ +.strong { + font-weight: 500; +} diff --git a/packages/console/src/components/ApplicationCreation/CreateForm/Footer/index.tsx b/packages/console/src/components/ApplicationCreation/CreateForm/Footer/index.tsx index 0928e6cf980..1f5845f4a6b 100644 --- a/packages/console/src/components/ApplicationCreation/CreateForm/Footer/index.tsx +++ b/packages/console/src/components/ApplicationCreation/CreateForm/Footer/index.tsx @@ -2,13 +2,19 @@ import { ApplicationType, ReservedPlanId } from '@logto/schemas'; import { useContext } from 'react'; import { Trans, useTranslation } from 'react-i18next'; +import AddOnNoticeFooter from '@/components/AddOnNoticeFooter'; import ContactUsPhraseLink from '@/components/ContactUsPhraseLink'; import PlanName from '@/components/PlanName'; import QuotaGuardFooter from '@/components/QuotaGuardFooter'; +import { isDevFeaturesEnabled } from '@/consts/env'; +import { machineToMachineAddOnUnitPrice } from '@/consts/subscriptions'; import { SubscriptionDataContext } from '@/contexts/SubscriptionDataProvider'; import Button from '@/ds-components/Button'; +import TextLink from '@/ds-components/TextLink'; import useApplicationsUsage from '@/hooks/use-applications-usage'; +import styles from './index.module.scss'; + type Props = { readonly selectedType?: ApplicationType; readonly isLoading: boolean; @@ -17,8 +23,8 @@ type Props = { }; function Footer({ selectedType, isLoading, onClickCreate, isThirdParty }: Props) { - const { currentPlan } = useContext(SubscriptionDataContext); - const { t } = useTranslation(undefined, { keyPrefix: 'admin_console.upsell.paywall' }); + const { currentPlan, currentSku } = useContext(SubscriptionDataContext); + const { t } = useTranslation(undefined, { keyPrefix: 'admin_console.upsell' }); const { hasAppsReachedLimit, hasMachineToMachineAppsReachedLimit, @@ -28,11 +34,36 @@ function Footer({ selectedType, isLoading, onClickCreate, isThirdParty }: Props) if (selectedType) { const { id: planId, name: planName, quota } = currentPlan; + if ( + selectedType === ApplicationType.MachineToMachine && + isDevFeaturesEnabled && + planId === ReservedPlanId.Pro + ) { + return ( + + , + a: , + }} + > + {t('add_on.footer.machine_to_machine_app', { + price: machineToMachineAddOnUnitPrice, + })} + + + ); + } + if ( selectedType === ApplicationType.MachineToMachine && hasMachineToMachineAppsReachedLimit && // For paid plan (pro plan), we don't guard the m2m app creation since it's an add-on feature. - planId === ReservedPlanId.Free + (isDevFeaturesEnabled ? currentSku.id : planId) === ReservedPlanId.Free ) { return ( @@ -41,7 +72,7 @@ function Footer({ selectedType, isLoading, onClickCreate, isThirdParty }: Props) a: , }} > - {t('machine_to_machine_feature')} + {t('paywall.machine_to_machine_feature')} ); @@ -56,7 +87,7 @@ function Footer({ selectedType, isLoading, onClickCreate, isThirdParty }: Props) a: , }} > - {t('third_party_apps')} + {t('paywall.third_party_apps')} ); @@ -68,10 +99,10 @@ function Footer({ selectedType, isLoading, onClickCreate, isThirdParty }: Props) , - planName: , + planName: , }} > - {t('applications', { count: quota.applicationsLimit ?? 0 })} + {t('paywall.applications', { count: quota.applicationsLimit ?? 0 })} ); diff --git a/packages/console/src/components/ApplicationCreation/CreateForm/index.tsx b/packages/console/src/components/ApplicationCreation/CreateForm/index.tsx index 21c88536a07..097c7cf7010 100644 --- a/packages/console/src/components/ApplicationCreation/CreateForm/index.tsx +++ b/packages/console/src/components/ApplicationCreation/CreateForm/index.tsx @@ -1,7 +1,8 @@ import { type AdminConsoleKey } from '@logto/phrases'; import type { Application } from '@logto/schemas'; -import { ApplicationType } from '@logto/schemas'; -import { type ReactElement, useMemo } from 'react'; +import { ApplicationType, ReservedPlanId } from '@logto/schemas'; +import { conditional } from '@silverhand/essentials'; +import { type ReactElement, useContext, useMemo } from 'react'; import { useController, useForm } from 'react-hook-form'; import { toast } from 'react-hot-toast'; import { useTranslation } from 'react-i18next'; @@ -9,6 +10,8 @@ import Modal from 'react-modal'; import { useSWRConfig } from 'swr'; import { GtagConversionId, reportConversion } from '@/components/Conversion/utils'; +import { isDevFeaturesEnabled } from '@/consts/env'; +import { SubscriptionDataContext } from '@/contexts/SubscriptionDataProvider'; import DynamicT from '@/ds-components/DynamicT'; import FormField from '@/ds-components/FormField'; import ModalLayout from '@/ds-components/ModalLayout'; @@ -17,12 +20,12 @@ import TextInput from '@/ds-components/TextInput'; import useApi from '@/hooks/use-api'; import useCurrentUser from '@/hooks/use-current-user'; import TypeDescription from '@/pages/Applications/components/TypeDescription'; -import * as modalStyles from '@/scss/modal.module.scss'; +import modalStyles from '@/scss/modal.module.scss'; import { applicationTypeI18nKey } from '@/types/applications'; import { trySubmitSafe } from '@/utils/form'; import Footer from './Footer'; -import * as styles from './index.module.scss'; +import styles from './index.module.scss'; type FormData = { type: ApplicationType; @@ -52,6 +55,9 @@ function CreateForm({ } = useForm({ defaultValues: { type: defaultCreateType, isThirdParty: isDefaultCreateThirdParty }, }); + const { + currentSubscription: { planId }, + } = useContext(SubscriptionDataContext); const { user } = useCurrentUser(); const { mutate: mutateGlobal } = useSWRConfig(); @@ -115,6 +121,9 @@ function CreateForm({ )} {!to &&
{title}
} + {eventKey === 'ExchangeTokenBy.TokenExchange' && Impersonation} ); } diff --git a/packages/console/src/components/AuditLogTable/index.tsx b/packages/console/src/components/AuditLogTable/index.tsx index 6901f5fa3a6..8cd31e744b3 100644 --- a/packages/console/src/components/AuditLogTable/index.tsx +++ b/packages/console/src/components/AuditLogTable/index.tsx @@ -19,7 +19,7 @@ import EmptyDataPlaceholder from '../EmptyDataPlaceholder'; import ApplicationSelector from './components/ApplicationSelector'; import EventName from './components/EventName'; import EventSelector from './components/EventSelector'; -import * as styles from './index.module.scss'; +import styles from './index.module.scss'; const auditLogEventOptions = Object.entries(auditLogEventTitle).map(([value, title]) => ({ value, diff --git a/packages/console/src/components/BasicWebhookForm/index.tsx b/packages/console/src/components/BasicWebhookForm/index.tsx index f110c7b852c..98ba5b7097e 100644 --- a/packages/console/src/components/BasicWebhookForm/index.tsx +++ b/packages/console/src/components/BasicWebhookForm/index.tsx @@ -14,7 +14,7 @@ import FormField from '@/ds-components/FormField'; import TextInput from '@/ds-components/TextInput'; import { uriValidator } from '@/utils/validator'; -import * as styles from './index.module.scss'; +import styles from './index.module.scss'; const hookEventGroups: Array> = [ ...schemaGroupedDataHookEvents.map(([schema, events]) => ({ diff --git a/packages/console/src/components/BillInfo/index.tsx b/packages/console/src/components/BillInfo/index.tsx index c2a3a25f2df..85ec6946fed 100644 --- a/packages/console/src/components/BillInfo/index.tsx +++ b/packages/console/src/components/BillInfo/index.tsx @@ -1,7 +1,7 @@ import { useContext, useState } from 'react'; import { Trans, useTranslation } from 'react-i18next'; -import Tip from '@/assets/icons/tip.svg'; +import Tip from '@/assets/icons/tip.svg?react'; import { newPlansBlogLink } from '@/consts'; import { TenantsContext } from '@/contexts/TenantsProvider'; import Button from '@/ds-components/Button'; @@ -11,7 +11,7 @@ import TextLink from '@/ds-components/TextLink'; import { ToggleTip } from '@/ds-components/Tip'; import useSubscribe from '@/hooks/use-subscribe'; -import * as styles from './index.module.scss'; +import styles from './index.module.scss'; type Props = { readonly cost: number; diff --git a/packages/console/src/components/Breakable/index.tsx b/packages/console/src/components/Breakable/index.tsx index ca5bf216797..45de5954c8c 100644 --- a/packages/console/src/components/Breakable/index.tsx +++ b/packages/console/src/components/Breakable/index.tsx @@ -1,4 +1,4 @@ -import * as styles from './index.module.scss'; +import styles from './index.module.scss'; type Props = { readonly children: React.ReactNode; diff --git a/packages/console/src/components/ChargeNotification/index.tsx b/packages/console/src/components/ChargeNotification/index.tsx index 2fd62a5f4df..e2ce6ffe3ce 100644 --- a/packages/console/src/components/ChargeNotification/index.tsx +++ b/packages/console/src/components/ChargeNotification/index.tsx @@ -5,6 +5,7 @@ import { useContext } from 'react'; import { Trans, useTranslation } from 'react-i18next'; import { newPlansBlogLink } from '@/consts'; +import { isDevFeaturesEnabled } from '@/consts/env'; import { SubscriptionDataContext } from '@/contexts/SubscriptionDataProvider'; import InlineNotification from '@/ds-components/InlineNotification'; import TextLink from '@/ds-components/TextLink'; @@ -38,7 +39,7 @@ function ChargeNotification({ checkedFlagKey, }: Props) { const { t } = useTranslation(undefined, { keyPrefix: 'admin_console.upsell' }); - const { currentPlan } = useContext(SubscriptionDataContext); + const { currentPlan, currentSku } = useContext(SubscriptionDataContext); const { configs, updateConfigs } = useConfigs(); // Display null when loading @@ -52,7 +53,7 @@ function ChargeNotification({ Boolean(checkedChargeNotification?.[checkedFlagKey]) || !hasSurpassedLimit || // No charge notification for free plan - currentPlan.id === ReservedPlanId.Free + (isDevFeaturesEnabled ? currentSku.id : currentPlan.id) === ReservedPlanId.Free ) { return null; } diff --git a/packages/console/src/components/ConnectorForm/BasicForm/index.tsx b/packages/console/src/components/ConnectorForm/BasicForm/index.tsx index 2a72ed192cb..0711588a6a2 100644 --- a/packages/console/src/components/ConnectorForm/BasicForm/index.tsx +++ b/packages/console/src/components/ConnectorForm/BasicForm/index.tsx @@ -1,12 +1,10 @@ -import { useState } from 'react'; +import { Theme } from '@logto/schemas'; import { Controller, useFormContext } from 'react-hook-form'; import { Trans, useTranslation } from 'react-i18next'; -import CaretDown from '@/assets/icons/caret-down.svg'; -import CaretUp from '@/assets/icons/caret-up.svg'; -import Error from '@/assets/icons/toast-error.svg'; +import Error from '@/assets/icons/toast-error.svg?react'; +import ImageInputs from '@/components/ImageInputs'; import UnnamedTrans from '@/components/UnnamedTrans'; -import Button from '@/ds-components/Button'; import FormField from '@/ds-components/FormField'; import Select from '@/ds-components/Select'; import TextInput from '@/ds-components/TextInput'; @@ -14,23 +12,21 @@ import TextLink from '@/ds-components/TextLink'; import useDocumentationUrl from '@/hooks/use-documentation-url'; import type { ConnectorFormType } from '@/types/connector'; import { SyncProfileMode } from '@/types/connector'; -import { uriValidator } from '@/utils/validator'; -import * as styles from './index.module.scss'; +import styles from './index.module.scss'; + +const themeToField = Object.freeze({ + [Theme.Light]: 'logo', + [Theme.Dark]: 'logoDark', +} as const satisfies Record); type Props = { readonly isAllowEditTarget?: boolean; - readonly isDarkDefaultVisible?: boolean; readonly isStandard?: boolean; readonly conflictConnectorName?: Record; }; -function BasicForm({ - isAllowEditTarget, - isDarkDefaultVisible, - isStandard, - conflictConnectorName, -}: Props) { +function BasicForm({ isAllowEditTarget, isStandard, conflictConnectorName }: Props) { const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' }); const { getDocumentationUrl } = useDocumentationUrl(); const { @@ -38,17 +34,6 @@ function BasicForm({ register, formState: { errors }, } = useFormContext(); - const [darkVisible, setDarkVisible] = useState(Boolean(isDarkDefaultVisible)); - - const toggleDarkVisible = () => { - setDarkVisible((previous) => !previous); - }; - - const toggleVisibleButtonTitle = darkVisible - ? 'connectors.guide.logo_dark_collapse' - : 'connectors.guide.logo_dark_show'; - - const ToggleVisibleCaretIcon = darkVisible ? CaretUp : CaretDown; const syncProfileOptions = [ { @@ -72,37 +57,18 @@ function BasicForm({ {...register('name', { required: true })} /> - - - !value || uriValidator(value) || t('errors.invalid_uri_format'), - })} - /> - - {darkVisible && ( - - - !value || uriValidator(value) || t('errors.invalid_uri_format'), - })} - /> - - )} -
-
+ ({ + name: themeToField[theme], + error: errors[themeToField[theme]], + type: 'connector_logo', + theme, + }))} + /> )} diff --git a/packages/console/src/components/CreateConnectorForm/ConnectorRadioGroup/ConnectorRadio/index.tsx b/packages/console/src/components/CreateConnectorForm/ConnectorRadioGroup/ConnectorRadio/index.tsx index b722f3f99bb..fc2293ab59d 100644 --- a/packages/console/src/components/CreateConnectorForm/ConnectorRadioGroup/ConnectorRadio/index.tsx +++ b/packages/console/src/components/CreateConnectorForm/ConnectorRadioGroup/ConnectorRadio/index.tsx @@ -5,7 +5,7 @@ import ConnectorLogo from '@/components/ConnectorLogo'; import UnnamedTrans from '@/components/UnnamedTrans'; import { type ConnectorGroup } from '@/types/connector'; -import * as styles from './index.module.scss'; +import styles from './index.module.scss'; type Props = { readonly data: ConnectorGroup; diff --git a/packages/console/src/components/CreateConnectorForm/ConnectorRadioGroup/index.tsx b/packages/console/src/components/CreateConnectorForm/ConnectorRadioGroup/index.tsx index f682f929e8a..38a81ebe01b 100644 --- a/packages/console/src/components/CreateConnectorForm/ConnectorRadioGroup/index.tsx +++ b/packages/console/src/components/CreateConnectorForm/ConnectorRadioGroup/index.tsx @@ -5,7 +5,7 @@ import RadioGroup, { Radio } from '@/ds-components/RadioGroup'; import { type ConnectorGroup } from '@/types/connector'; import ConnectorRadio from './ConnectorRadio'; -import * as styles from './index.module.scss'; +import styles from './index.module.scss'; export type ConnectorRadioGroupSize = 'medium' | 'large' | 'xlarge'; diff --git a/packages/console/src/components/CreateConnectorForm/Footer/index.tsx b/packages/console/src/components/CreateConnectorForm/Footer/index.tsx index 53c7b4032cb..8c86cce555c 100644 --- a/packages/console/src/components/CreateConnectorForm/Footer/index.tsx +++ b/packages/console/src/components/CreateConnectorForm/Footer/index.tsx @@ -10,10 +10,11 @@ import { Trans, useTranslation } from 'react-i18next'; import ContactUsPhraseLink from '@/components/ContactUsPhraseLink'; import PlanName from '@/components/PlanName'; import QuotaGuardFooter from '@/components/QuotaGuardFooter'; +import { isDevFeaturesEnabled } from '@/consts/env'; import { SubscriptionDataContext } from '@/contexts/SubscriptionDataProvider'; import Button from '@/ds-components/Button'; import { type ConnectorGroup } from '@/types/connector'; -import { hasReachedQuotaLimit } from '@/utils/quota'; +import { hasReachedQuotaLimit, hasReachedSubscriptionQuotaLimit } from '@/utils/quota'; type Props = { readonly isCreatingSocialConnector: boolean; @@ -31,35 +32,51 @@ function Footer({ onClickCreateButton, }: Props) { const { t } = useTranslation(undefined, { keyPrefix: 'admin_console.upsell.paywall' }); - const { currentPlan } = useContext(SubscriptionDataContext); + const { currentPlan, currentSku, currentSubscriptionUsage, currentSubscriptionQuota } = + useContext(SubscriptionDataContext); const standardConnectorCount = useMemo( () => - existingConnectors.filter( - ({ isStandard, isDemo, type }) => isStandard && !isDemo && type === ConnectorType.Social - ).length, + isDevFeaturesEnabled + ? // No more standard connector limit in new pricing model. + 0 + : existingConnectors.filter( + ({ isStandard, isDemo, type }) => isStandard && !isDemo && type === ConnectorType.Social + ).length, [existingConnectors] ); const socialConnectorCount = useMemo( () => - existingConnectors.filter( - ({ isStandard, isDemo, type }) => !isStandard && !isDemo && type === ConnectorType.Social - ).length, - [existingConnectors] + isDevFeaturesEnabled + ? currentSubscriptionUsage.socialConnectorsLimit + : existingConnectors.filter( + ({ isStandard, isDemo, type }) => + !isStandard && !isDemo && type === ConnectorType.Social + ).length, + [existingConnectors, currentSubscriptionUsage.socialConnectorsLimit] ); - const isStandardConnectorsReachLimit = hasReachedQuotaLimit({ - quotaKey: 'standardConnectorsLimit', - plan: currentPlan, - usage: standardConnectorCount, - }); + const isStandardConnectorsReachLimit = isDevFeaturesEnabled + ? // No more standard connector limit in new pricing model. + false + : hasReachedQuotaLimit({ + quotaKey: 'standardConnectorsLimit', + plan: currentPlan, + usage: standardConnectorCount, + }); - const isSocialConnectorsReachLimit = hasReachedQuotaLimit({ - quotaKey: 'socialConnectorsLimit', - plan: currentPlan, - usage: socialConnectorCount, - }); + const isSocialConnectorsReachLimit = isDevFeaturesEnabled + ? hasReachedSubscriptionQuotaLimit({ + quotaKey: 'socialConnectorsLimit', + usage: currentSubscriptionUsage.socialConnectorsLimit, + quota: currentSubscriptionQuota, + }) + : hasReachedQuotaLimit({ + quotaKey: 'socialConnectorsLimit', + plan: currentPlan, + usage: socialConnectorCount, + }); if (isCreatingSocialConnector && selectedConnectorGroup) { const { id: planId, name: planName, quota } = currentPlan; @@ -70,13 +87,15 @@ function Footer({ , - planName: , + planName: , }} > {quota.standardConnectorsLimit === 0 ? t('standard_connectors_feature') : t( - planId === ReservedPlanId.Pro ? 'standard_connectors_pro' : 'standard_connectors', + (isDevFeaturesEnabled ? currentSku.id : planId) === ReservedPlanId.Pro + ? 'standard_connectors_pro' + : 'standard_connectors', { count: quota.standardConnectorsLimit ?? 0, } @@ -92,11 +111,14 @@ function Footer({ , - planName: , + planName: , }} > {t('social_connectors', { - count: quota.socialConnectorsLimit ?? 0, + count: + (isDevFeaturesEnabled + ? currentSubscriptionQuota.socialConnectorsLimit + : quota.socialConnectorsLimit) ?? 0, })} diff --git a/packages/console/src/components/CreateConnectorForm/PlatformSelector/index.tsx b/packages/console/src/components/CreateConnectorForm/PlatformSelector/index.tsx index 658db4e286d..01a9eac6eab 100644 --- a/packages/console/src/components/CreateConnectorForm/PlatformSelector/index.tsx +++ b/packages/console/src/components/CreateConnectorForm/PlatformSelector/index.tsx @@ -6,7 +6,7 @@ import { connectorPlatformLabel } from '@/consts/connectors'; import RadioGroup, { Radio } from '@/ds-components/RadioGroup'; import type { ConnectorGroup } from '@/types/connector'; -import * as styles from './index.module.scss'; +import styles from './index.module.scss'; type Props = { readonly connectorGroup: ConnectorGroup; diff --git a/packages/console/src/components/CreateConnectorForm/Skeleton/index.module.scss b/packages/console/src/components/CreateConnectorForm/Skeleton/index.module.scss index dbe6a3872a4..e53ce9df54d 100644 --- a/packages/console/src/components/CreateConnectorForm/Skeleton/index.module.scss +++ b/packages/console/src/components/CreateConnectorForm/Skeleton/index.module.scss @@ -7,23 +7,23 @@ } .logo { - @include _.shimmering-animation; width: 40px; height: 40px; border-radius: 8px; + @include _.shimmering-animation; } .name { - @include _.shimmering-animation; width: 50px; height: 16px; margin-bottom: _.unit(1); + @include _.shimmering-animation; } .description { - @include _.shimmering-animation; height: 14px; margin-bottom: _.unit(0.5); + @include _.shimmering-animation; &.shortDescription { width: 50%; diff --git a/packages/console/src/components/CreateConnectorForm/Skeleton/index.tsx b/packages/console/src/components/CreateConnectorForm/Skeleton/index.tsx index 9ecdb68975f..c305f630c42 100644 --- a/packages/console/src/components/CreateConnectorForm/Skeleton/index.tsx +++ b/packages/console/src/components/CreateConnectorForm/Skeleton/index.tsx @@ -1,9 +1,9 @@ import classNames from 'classnames'; -import * as radioStyles from '../ConnectorRadioGroup/ConnectorRadio/index.module.scss'; -import * as radioGroupStyles from '../ConnectorRadioGroup/index.module.scss'; +import radioStyles from '../ConnectorRadioGroup/ConnectorRadio/index.module.scss'; +import radioGroupStyles from '../ConnectorRadioGroup/index.module.scss'; -import * as styles from './index.module.scss'; +import styles from './index.module.scss'; type Props = { readonly numberOfLoadingConnectors?: number; diff --git a/packages/console/src/components/CreateConnectorForm/index.tsx b/packages/console/src/components/CreateConnectorForm/index.tsx index 5ed33692ef9..db935cd198a 100644 --- a/packages/console/src/components/CreateConnectorForm/index.tsx +++ b/packages/console/src/components/CreateConnectorForm/index.tsx @@ -10,7 +10,7 @@ import useSWR from 'swr'; import DynamicT from '@/ds-components/DynamicT'; import ModalLayout from '@/ds-components/ModalLayout'; import type { RequestError } from '@/hooks/use-api'; -import * as modalStyles from '@/scss/modal.module.scss'; +import modalStyles from '@/scss/modal.module.scss'; import { getConnectorGroups } from '../../pages/Connectors/utils'; @@ -18,7 +18,7 @@ import ConnectorRadioGroup from './ConnectorRadioGroup'; import Footer from './Footer'; import PlatformSelector from './PlatformSelector'; import Skeleton from './Skeleton'; -import * as styles from './index.module.scss'; +import styles from './index.module.scss'; import { compareConnectors, getConnectorRadioGroupSize, getModalTitle } from './utils'; type Props = { diff --git a/packages/console/src/components/CreateTenantModal/EnvTagOptionContent/index.tsx b/packages/console/src/components/CreateTenantModal/EnvTagOptionContent/index.tsx index f9d6a10549d..48b2f75e2d7 100644 --- a/packages/console/src/components/CreateTenantModal/EnvTagOptionContent/index.tsx +++ b/packages/console/src/components/CreateTenantModal/EnvTagOptionContent/index.tsx @@ -7,7 +7,7 @@ import DynamicT from '@/ds-components/DynamicT'; import Tag from '@/ds-components/Tag'; import { ReservedPlanName } from '@/types/subscriptions'; -import * as styles from './index.module.scss'; +import styles from './index.module.scss'; type Props = { readonly tag: TenantTag; diff --git a/packages/console/src/components/CreateTenantModal/SelectTenantPlanModal/PlanCardItem/FeaturedPlanContent/index.tsx b/packages/console/src/components/CreateTenantModal/SelectTenantPlanModal/PlanCardItem/FeaturedPlanContent/index.tsx index 8e95a6a2a3a..9007d706273 100644 --- a/packages/console/src/components/CreateTenantModal/SelectTenantPlanModal/PlanCardItem/FeaturedPlanContent/index.tsx +++ b/packages/console/src/components/CreateTenantModal/SelectTenantPlanModal/PlanCardItem/FeaturedPlanContent/index.tsx @@ -1,9 +1,9 @@ import classNames from 'classnames'; -import Failed from '@/assets/icons/failed.svg'; -import Success from '@/assets/icons/success.svg'; +import Failed from '@/assets/icons/failed.svg?react'; +import Success from '@/assets/icons/success.svg?react'; -import * as styles from './index.module.scss'; +import styles from './index.module.scss'; import useFeaturedPlanContent from './use-featured-plan-content'; type Props = { diff --git a/packages/console/src/components/CreateTenantModal/SelectTenantPlanModal/PlanCardItem/index.tsx b/packages/console/src/components/CreateTenantModal/SelectTenantPlanModal/PlanCardItem/index.tsx index f6836d4041c..417d5d77a66 100644 --- a/packages/console/src/components/CreateTenantModal/SelectTenantPlanModal/PlanCardItem/index.tsx +++ b/packages/console/src/components/CreateTenantModal/SelectTenantPlanModal/PlanCardItem/index.tsx @@ -3,7 +3,7 @@ import classNames from 'classnames'; import { useContext, useMemo } from 'react'; import { Trans, useTranslation } from 'react-i18next'; -import ArrowRight from '@/assets/icons/arrow-right.svg'; +import ArrowRight from '@/assets/icons/arrow-right.svg?react'; import PlanDescription from '@/components/PlanDescription'; import PlanName from '@/components/PlanName'; import { pricingLink } from '@/consts'; @@ -15,7 +15,7 @@ import TextLink from '@/ds-components/TextLink'; import { type SubscriptionPlan } from '@/types/subscriptions'; import FeaturedPlanContent from './FeaturedPlanContent'; -import * as styles from './index.module.scss'; +import styles from './index.module.scss'; type Props = { readonly plan: SubscriptionPlan; diff --git a/packages/console/src/components/CreateTenantModal/SelectTenantPlanModal/SkuCardItem/FeaturedSkuContent/index.tsx b/packages/console/src/components/CreateTenantModal/SelectTenantPlanModal/SkuCardItem/FeaturedSkuContent/index.tsx new file mode 100644 index 00000000000..6ecbbeead51 --- /dev/null +++ b/packages/console/src/components/CreateTenantModal/SelectTenantPlanModal/SkuCardItem/FeaturedSkuContent/index.tsx @@ -0,0 +1,35 @@ +import classNames from 'classnames'; + +import Failed from '@/assets/icons/failed.svg?react'; +import Success from '@/assets/icons/success.svg?react'; + +import styles from '../../PlanCardItem/FeaturedPlanContent/index.module.scss'; + +import useFeaturedSkuContent from './use-featured-sku-content'; + +type Props = { + readonly skuId: string; +}; + +function FeaturedSkuContent({ skuId }: Props) { + const contentData = useFeaturedSkuContent(skuId); + + return ( +
    + {contentData.map(({ title, isAvailable }) => { + return ( +
  • + {isAvailable ? ( + + ) : ( + + )} + {title} +
  • + ); + })} +
+ ); +} + +export default FeaturedSkuContent; diff --git a/packages/console/src/components/CreateTenantModal/SelectTenantPlanModal/SkuCardItem/FeaturedSkuContent/use-featured-sku-content.ts b/packages/console/src/components/CreateTenantModal/SelectTenantPlanModal/SkuCardItem/FeaturedSkuContent/use-featured-sku-content.ts new file mode 100644 index 00000000000..70662e19b03 --- /dev/null +++ b/packages/console/src/components/CreateTenantModal/SelectTenantPlanModal/SkuCardItem/FeaturedSkuContent/use-featured-sku-content.ts @@ -0,0 +1,77 @@ +import { ReservedPlanId } from '@logto/schemas'; +import { cond } from '@silverhand/essentials'; +import { useMemo } from 'react'; +import { useTranslation } from 'react-i18next'; + +import { + freePlanAuditLogsRetentionDays, + freePlanM2mLimit, + freePlanMauLimit, + freePlanPermissionsLimit, + freePlanRoleLimit, + proPlanAuditLogsRetentionDays, +} from '@/consts/subscriptions'; + +type ContentData = { + readonly title: string; + readonly isAvailable: boolean; +}; + +const useFeaturedSkuContent = (skuId: string) => { + const { t } = useTranslation(undefined, { + keyPrefix: 'admin_console.upsell.featured_plan_content', + }); + + const contentData: ContentData[] = useMemo(() => { + const isFreePlan = skuId === ReservedPlanId.Free; + const planPhraseKey = isFreePlan ? 'free_plan' : 'pro_plan'; + + return [ + { + title: t(`mau.${planPhraseKey}`, { ...cond(isFreePlan && { count: freePlanMauLimit }) }), + isAvailable: true, + }, + { + title: t(`m2m.${planPhraseKey}`, { ...cond(isFreePlan && { count: freePlanM2mLimit }) }), + isAvailable: true, + }, + { + title: t('third_party_apps'), + isAvailable: !isFreePlan, + }, + { + title: t('mfa'), + isAvailable: !isFreePlan, + }, + { + title: t('sso'), + isAvailable: !isFreePlan, + }, + { + title: t(`role_and_permissions.${planPhraseKey}`, { + ...cond( + isFreePlan && { + roleCount: freePlanRoleLimit, + permissionCount: freePlanPermissionsLimit, + } + ), + }), + isAvailable: true, + }, + { + title: t('organizations'), + isAvailable: !isFreePlan, + }, + { + title: t('audit_logs', { + count: isFreePlan ? freePlanAuditLogsRetentionDays : proPlanAuditLogsRetentionDays, + }), + isAvailable: true, + }, + ]; + }, [t, skuId]); + + return contentData; +}; + +export default useFeaturedSkuContent; diff --git a/packages/console/src/components/CreateTenantModal/SelectTenantPlanModal/SkuCardItem/index.tsx b/packages/console/src/components/CreateTenantModal/SelectTenantPlanModal/SkuCardItem/index.tsx new file mode 100644 index 00000000000..81fbcb7c64e --- /dev/null +++ b/packages/console/src/components/CreateTenantModal/SelectTenantPlanModal/SkuCardItem/index.tsx @@ -0,0 +1,100 @@ +import { maxFreeTenantLimit, adminTenantId, ReservedPlanId } from '@logto/schemas'; +import classNames from 'classnames'; +import { useContext, useMemo } from 'react'; +import { Trans, useTranslation } from 'react-i18next'; + +import ArrowRight from '@/assets/icons/arrow-right.svg?react'; +import { type LogtoSkuResponse } from '@/cloud/types/router'; +import PlanDescription from '@/components/PlanDescription'; +import PlanName from '@/components/PlanName'; +import { pricingLink } from '@/consts'; +import { TenantsContext } from '@/contexts/TenantsProvider'; +import Button, { type Props as ButtonProps } from '@/ds-components/Button'; +import DangerousRaw from '@/ds-components/DangerousRaw'; +import DynamicT from '@/ds-components/DynamicT'; +import TextLink from '@/ds-components/TextLink'; + +import styles from '../PlanCardItem/index.module.scss'; + +import FeaturedSkuContent from './FeaturedSkuContent'; + +type Props = { + readonly sku: LogtoSkuResponse; + readonly onSelect: () => void; + readonly buttonProps?: Partial; +}; + +function SkuCardItem({ sku, onSelect, buttonProps }: Props) { + const { t } = useTranslation(undefined, { keyPrefix: 'admin_console.upsell.create_tenant' }); + const { tenants } = useContext(TenantsContext); + const { unitPrice: basePrice, id: skuId } = sku; + + const isFreeSku = skuId === ReservedPlanId.Free; + + const isFreeTenantExceeded = useMemo( + () => + /** Should not block admin tenant owners from creating more than three tenants */ + !tenants.some(({ id }) => id === adminTenantId) && + tenants.filter(({ planId }) => planId === ReservedPlanId.Free).length >= maxFreeTenantLimit, + [tenants] + ); + + return ( +
+
+
+ +
+
+
{t('base_price')}
+
+ ${t('monthly_price', { value: (basePrice ?? 0) / 100 })} +
+
+
+ +
+
+
+ + {isFreeSku && isFreeTenantExceeded && ( +
+ {t('free_tenants_limit', { count: maxFreeTenantLimit })} +
+ )} + {!isFreeSku && ( +
+ } + className={styles.link} + > + + +
+ )} +
+ {skuId === ReservedPlanId.Pro && ( +
{t('most_popular')}
+ )} +
+ ); +} + +export default SkuCardItem; diff --git a/packages/console/src/components/CreateTenantModal/SelectTenantPlanModal/index.tsx b/packages/console/src/components/CreateTenantModal/SelectTenantPlanModal/index.tsx index 38d4260599f..f7bfbfdbbd0 100644 --- a/packages/console/src/components/CreateTenantModal/SelectTenantPlanModal/index.tsx +++ b/packages/console/src/components/CreateTenantModal/SelectTenantPlanModal/index.tsx @@ -5,22 +5,25 @@ import { Trans, useTranslation } from 'react-i18next'; import Modal from 'react-modal'; import { useCloudApi, toastResponseError } from '@/cloud/hooks/use-cloud-api'; -import { type TenantResponse } from '@/cloud/types/router'; +import { type TenantResponse, type LogtoSkuResponse } from '@/cloud/types/router'; import { GtagConversionId, reportToGoogle } from '@/components/Conversion/utils'; import { pricingLink } from '@/consts'; +import { isDevFeaturesEnabled } from '@/consts/env'; import DangerousRaw from '@/ds-components/DangerousRaw'; import ModalLayout from '@/ds-components/ModalLayout'; import TextLink from '@/ds-components/TextLink'; +import useLogtoSkus from '@/hooks/use-logto-skus'; import useSubscribe from '@/hooks/use-subscribe'; import useSubscriptionPlans from '@/hooks/use-subscription-plans'; -import * as modalStyles from '@/scss/modal.module.scss'; +import modalStyles from '@/scss/modal.module.scss'; import { type SubscriptionPlan } from '@/types/subscriptions'; -import { pickupFeaturedPlans } from '@/utils/subscription'; +import { pickupFeaturedPlans, pickupFeaturedLogtoSkus } from '@/utils/subscription'; import { type CreateTenantData } from '../types'; import PlanCardItem from './PlanCardItem'; -import * as styles from './index.module.scss'; +import SkuCardItem from './SkuCardItem'; +import styles from './index.module.scss'; type Props = { readonly tenantData?: CreateTenantData; @@ -28,21 +31,27 @@ type Props = { }; function SelectTenantPlanModal({ tenantData, onClose }: Props) { - const [isSubmitting, setIsSubmitting] = useState(); + const [processingPlanId, setProcessingPlanId] = useState(); + const [processingSkuId, setProcessingSkuId] = useState(); const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' }); + const { data: subscriptionPlans } = useSubscriptionPlans(); + const { data: logtoSkus } = useLogtoSkus(); + const { subscribe } = useSubscribe(); const cloudApi = useCloudApi({ hideErrorToast: true }); + const reservedPlans = conditional(subscriptionPlans && pickupFeaturedPlans(subscriptionPlans)); + const reservedBasicLogtoSkus = conditional(logtoSkus && pickupFeaturedLogtoSkus(logtoSkus)); - if (!reservedPlans || !tenantData) { + if (!reservedPlans || !reservedBasicLogtoSkus || !tenantData) { return null; } const handleSelectPlan = async (plan: SubscriptionPlan) => { const { id: planId } = plan; try { - setIsSubmitting(planId); + setProcessingPlanId(planId); if (planId === ReservedPlanId.Free) { const { name, tag, regionName } = tenantData; const newTenant = await cloudApi.post('/api/tenants', { body: { name, tag, regionName } }); @@ -56,7 +65,28 @@ function SelectTenantPlanModal({ tenantData, onClose }: Props) { } catch (error: unknown) { void toastResponseError(error); } finally { - setIsSubmitting(undefined); + setProcessingPlanId(undefined); + } + }; + + const handleSelectSku = async (logtoSku: LogtoSkuResponse) => { + const { id: skuId } = logtoSku; + try { + setProcessingSkuId(skuId); + if (skuId === ReservedPlanId.Free) { + const { name, tag, regionName } = tenantData; + const newTenant = await cloudApi.post('/api/tenants', { body: { name, tag, regionName } }); + + reportToGoogle(GtagConversionId.CreateProductionTenant, { transactionId: newTenant.id }); + onClose(newTenant); + return; + } + + await subscribe({ skuId, planId: skuId, tenantData }); + } catch (error: unknown) { + void toastResponseError(error); + } finally { + setProcessingSkuId(undefined); } }; @@ -83,19 +113,33 @@ function SelectTenantPlanModal({ tenantData, onClose }: Props) { onClose={onClose} >
- {reservedPlans.map((plan) => ( - { - void handleSelectPlan(plan); - }} - /> - ))} + {isDevFeaturesEnabled + ? reservedBasicLogtoSkus.map((logtoSku) => ( + { + void handleSelectSku(logtoSku); + }} + /> + )) + : reservedPlans.map((plan) => ( + { + void handleSelectPlan(plan); + }} + /> + ))}
diff --git a/packages/console/src/components/CreateTenantModal/index.tsx b/packages/console/src/components/CreateTenantModal/index.tsx index d6525cc5162..3dc2fd67878 100644 --- a/packages/console/src/components/CreateTenantModal/index.tsx +++ b/packages/console/src/components/CreateTenantModal/index.tsx @@ -5,8 +5,8 @@ import { toast } from 'react-hot-toast'; import { useTranslation } from 'react-i18next'; import Modal from 'react-modal'; -import CreateTenantHeaderIconDark from '@/assets/icons/create-tenant-header-dark.svg'; -import CreateTenantHeaderIcon from '@/assets/icons/create-tenant-header.svg'; +import CreateTenantHeaderIconDark from '@/assets/icons/create-tenant-header-dark.svg?react'; +import CreateTenantHeaderIcon from '@/assets/icons/create-tenant-header.svg?react'; import { useCloudApi } from '@/cloud/hooks/use-cloud-api'; import { type TenantResponse } from '@/cloud/types/router'; import Region, { RegionName } from '@/components/Region'; @@ -17,11 +17,11 @@ import ModalLayout from '@/ds-components/ModalLayout'; import RadioGroup, { Radio } from '@/ds-components/RadioGroup'; import TextInput from '@/ds-components/TextInput'; import useTheme from '@/hooks/use-theme'; -import * as modalStyles from '@/scss/modal.module.scss'; +import modalStyles from '@/scss/modal.module.scss'; import EnvTagOptionContent from './EnvTagOptionContent'; import SelectTenantPlanModal from './SelectTenantPlanModal'; -import * as styles from './index.module.scss'; +import styles from './index.module.scss'; import { type CreateTenantData } from './types'; type Props = { diff --git a/packages/console/src/components/DateTime/index.tsx b/packages/console/src/components/DateTime/index.tsx index 766d94d28d7..c40b39bfd4a 100644 --- a/packages/console/src/components/DateTime/index.tsx +++ b/packages/console/src/components/DateTime/index.tsx @@ -1,18 +1,30 @@ -import type { Nullable } from '@silverhand/essentials'; +import { type Nullable } from '@silverhand/essentials'; import { isValid } from 'date-fns'; -type Props = { - readonly children: Nullable; -}; +const parseDate = (date: Nullable) => { + if (!date) { + return; + } -function DateTime({ children }: Props) { - const date = children && new Date(children); + const parsed = new Date(date); + return isValid(parsed) ? parsed : undefined; +}; - if (!date || !isValid(date)) { - return -; - } +type Props = { + readonly children: Nullable; +}; - return {date.toLocaleDateString()}; +/** + * Safely display a date in the user's locale. If the date is invalid, it will display a dash. + */ +export function LocaleDate({ children }: Props) { + return {parseDate(children)?.toLocaleDateString() ?? '-'}; } -export default DateTime; +/** + * Safely display a date and time in the user's locale. If the date is invalid, it will display a + * dash. + */ +export function LocaleDateTime({ children }: Props) { + return {parseDate(children)?.toLocaleString() ?? '-'}; +} diff --git a/packages/console/src/components/DetailsForm/index.tsx b/packages/console/src/components/DetailsForm/index.tsx index c19161d60c4..fb2b8ef231a 100644 --- a/packages/console/src/components/DetailsForm/index.tsx +++ b/packages/console/src/components/DetailsForm/index.tsx @@ -3,7 +3,7 @@ import type { ReactNode } from 'react'; import SubmitFormChangesActionBar from '../SubmitFormChangesActionBar'; -import * as styles from './index.module.scss'; +import styles from './index.module.scss'; type Props = { readonly autoComplete?: string; diff --git a/packages/console/src/components/DetailsPage/DetailsPageHeader/index.tsx b/packages/console/src/components/DetailsPage/DetailsPageHeader/index.tsx index b4b431a33a9..d72e741f6bf 100644 --- a/packages/console/src/components/DetailsPage/DetailsPageHeader/index.tsx +++ b/packages/console/src/components/DetailsPage/DetailsPageHeader/index.tsx @@ -10,7 +10,7 @@ import { } from 'react'; import { useTranslation } from 'react-i18next'; -import More from '@/assets/icons/more.svg'; +import More from '@/assets/icons/more.svg?react'; import ActionMenu, { ActionMenuItem } from '@/ds-components/ActionMenu'; import Button from '@/ds-components/Button'; import Card from '@/ds-components/Card'; @@ -20,7 +20,7 @@ import DynamicT from '@/ds-components/DynamicT'; import Tag, { type Props as TagProps } from '@/ds-components/Tag'; import useWindowResize from '@/hooks/use-window-resize'; -import * as styles from './index.module.scss'; +import styles from './index.module.scss'; type StatusTag = { status: TagProps['status']; diff --git a/packages/console/src/components/DetailsPage/Skeleton/index.module.scss b/packages/console/src/components/DetailsPage/Skeleton/index.module.scss index f01e5691a71..d7a86f5d7c4 100644 --- a/packages/console/src/components/DetailsPage/Skeleton/index.module.scss +++ b/packages/console/src/components/DetailsPage/Skeleton/index.module.scss @@ -18,11 +18,11 @@ background-color: var(--color-layer-1); .icon { - @include _.shimmering-animation; width: 60px; height: 60px; border-radius: 12px; margin-right: _.unit(6); + @include _.shimmering-animation; } .wrapper { @@ -30,23 +30,23 @@ flex-direction: column; .title { - @include _.shimmering-animation; width: 113px; height: 28px; + @include _.shimmering-animation; } .tags { - @include _.shimmering-animation; width: 453px; height: 20px; margin-top: _.unit(3); + @include _.shimmering-animation; } } .button { - @include _.shimmering-animation; width: 158px; height: 44px; + @include _.shimmering-animation; } } diff --git a/packages/console/src/components/DetailsPage/Skeleton/index.tsx b/packages/console/src/components/DetailsPage/Skeleton/index.tsx index b796c621e91..58bfcb30b24 100644 --- a/packages/console/src/components/DetailsPage/Skeleton/index.tsx +++ b/packages/console/src/components/DetailsPage/Skeleton/index.tsx @@ -1,7 +1,7 @@ import { FormCardSkeleton } from '@/components/FormCard'; import Spacer from '@/ds-components/Spacer'; -import * as styles from './index.module.scss'; +import styles from './index.module.scss'; function Skeleton() { return ( diff --git a/packages/console/src/components/DetailsPage/index.tsx b/packages/console/src/components/DetailsPage/index.tsx index c6083122d0f..2f4f8677413 100644 --- a/packages/console/src/components/DetailsPage/index.tsx +++ b/packages/console/src/components/DetailsPage/index.tsx @@ -3,7 +3,7 @@ import classNames from 'classnames'; import type { ReactElement, ReactNode } from 'react'; import { type To } from 'react-router-dom'; -import Back from '@/assets/icons/back.svg'; +import Back from '@/assets/icons/back.svg?react'; import type DangerousRaw from '@/ds-components/DangerousRaw'; import DynamicT from '@/ds-components/DynamicT'; import TextLink from '@/ds-components/TextLink'; @@ -12,7 +12,7 @@ import type { RequestError } from '@/hooks/use-api'; import RequestDataError from '../RequestDataError'; import Skeleton from './Skeleton'; -import * as styles from './index.module.scss'; +import styles from './index.module.scss'; type Props = { readonly backLink: To; diff --git a/packages/console/src/components/Drawer/index.tsx b/packages/console/src/components/Drawer/index.tsx index 99e004b664d..bf920ab5d79 100644 --- a/packages/console/src/components/Drawer/index.tsx +++ b/packages/console/src/components/Drawer/index.tsx @@ -1,12 +1,12 @@ import type { AdminConsoleKey } from '@logto/phrases'; import ReactModal from 'react-modal'; -import Close from '@/assets/icons/close.svg'; +import Close from '@/assets/icons/close.svg?react'; import CardTitle from '@/ds-components/CardTitle'; import IconButton from '@/ds-components/IconButton'; import Spacer from '@/ds-components/Spacer'; -import * as styles from './index.module.scss'; +import styles from './index.module.scss'; type Props = { readonly title?: AdminConsoleKey; diff --git a/packages/console/src/components/EditScopeModal/index.tsx b/packages/console/src/components/EditScopeModal/index.tsx index 1ba3bc37bee..5e8a3cc1fda 100644 --- a/packages/console/src/components/EditScopeModal/index.tsx +++ b/packages/console/src/components/EditScopeModal/index.tsx @@ -8,7 +8,7 @@ import Button from '@/ds-components/Button'; import FormField from '@/ds-components/FormField'; import ModalLayout from '@/ds-components/ModalLayout'; import TextInput from '@/ds-components/TextInput'; -import * as modalStyles from '@/scss/modal.module.scss'; +import modalStyles from '@/scss/modal.module.scss'; import { trySubmitSafe } from '@/utils/form'; export type EditScopeData = { diff --git a/packages/console/src/components/EmptyDataPlaceholder/index.tsx b/packages/console/src/components/EmptyDataPlaceholder/index.tsx index bdf1706507b..4b7d12ad7b0 100644 --- a/packages/console/src/components/EmptyDataPlaceholder/index.tsx +++ b/packages/console/src/components/EmptyDataPlaceholder/index.tsx @@ -3,11 +3,11 @@ import classNames from 'classnames'; import { type ReactNode } from 'react'; import { useTranslation } from 'react-i18next'; -import EmptyDark from '@/assets/images/table-empty-dark.svg'; -import Empty from '@/assets/images/table-empty.svg'; +import EmptyDark from '@/assets/images/table-empty-dark.svg?react'; +import Empty from '@/assets/images/table-empty.svg?react'; import useTheme from '@/hooks/use-theme'; -import * as styles from './index.module.scss'; +import styles from './index.module.scss'; type Props = { readonly title?: ReactNode; diff --git a/packages/console/src/components/EntitiesTransfer/components/EntityItem/index.tsx b/packages/console/src/components/EntitiesTransfer/components/EntityItem/index.tsx index 0b8ccaa9db2..7646f9f66ee 100644 --- a/packages/console/src/components/EntitiesTransfer/components/EntityItem/index.tsx +++ b/packages/console/src/components/EntitiesTransfer/components/EntityItem/index.tsx @@ -5,7 +5,7 @@ import UserAvatar from '@/components/UserAvatar'; import SuspendedTag from '@/pages/Users/components/SuspendedTag'; import { getUserTitle } from '@/utils/user'; -import * as styles from './index.module.scss'; +import styles from './index.module.scss'; type UserItemProps = { readonly entity: User; diff --git a/packages/console/src/components/EntitiesTransfer/components/SourceEntitiesBox/index.tsx b/packages/console/src/components/EntitiesTransfer/components/SourceEntitiesBox/index.tsx index e8402edf490..01715df9161 100644 --- a/packages/console/src/components/EntitiesTransfer/components/SourceEntitiesBox/index.tsx +++ b/packages/console/src/components/EntitiesTransfer/components/SourceEntitiesBox/index.tsx @@ -6,7 +6,7 @@ import { useState } from 'react'; import { useTranslation } from 'react-i18next'; import useSWR from 'swr'; -import Search from '@/assets/icons/search.svg'; +import Search from '@/assets/icons/search.svg?react'; import EmptyDataPlaceholder from '@/components/EmptyDataPlaceholder'; import { defaultPageSize } from '@/consts'; import DynamicT from '@/ds-components/DynamicT'; @@ -14,13 +14,13 @@ import Pagination from '@/ds-components/Pagination'; import TextInput from '@/ds-components/TextInput'; import type { RequestError } from '@/hooks/use-api'; import useDebounce from '@/hooks/use-debounce'; -import * as transferLayout from '@/scss/transfer.module.scss'; +import transferLayout from '@/scss/transfer.module.scss'; import { type Identifiable } from '@/types/general'; import { buildUrl, formatSearchKeyword } from '@/utils/url'; import SourceEntityItem from '../SourceEntityItem'; -import * as styles from './index.module.scss'; +import styles from './index.module.scss'; type SearchProps = { pathname: string; diff --git a/packages/console/src/components/EntitiesTransfer/components/SourceEntityItem/index.tsx b/packages/console/src/components/EntitiesTransfer/components/SourceEntityItem/index.tsx index b26f110b3ae..1c3dc0d1820 100644 --- a/packages/console/src/components/EntitiesTransfer/components/SourceEntityItem/index.tsx +++ b/packages/console/src/components/EntitiesTransfer/components/SourceEntityItem/index.tsx @@ -4,7 +4,7 @@ import Checkbox from '@/ds-components/Checkbox'; import { type Identifiable } from '@/types/general'; import { onKeyDownHandler } from '@/utils/a11y'; -import * as styles from './index.module.scss'; +import styles from './index.module.scss'; type Props = { readonly entity: T; diff --git a/packages/console/src/components/EntitiesTransfer/components/TargetEntitiesBox/index.tsx b/packages/console/src/components/EntitiesTransfer/components/TargetEntitiesBox/index.tsx index 145cbbfb31b..7c19d6e69cf 100644 --- a/packages/console/src/components/EntitiesTransfer/components/TargetEntitiesBox/index.tsx +++ b/packages/console/src/components/EntitiesTransfer/components/TargetEntitiesBox/index.tsx @@ -1,11 +1,11 @@ import { useTranslation } from 'react-i18next'; -import * as transferLayout from '@/scss/transfer.module.scss'; +import transferLayout from '@/scss/transfer.module.scss'; import { type Identifiable } from '@/types/general'; import TargetEntityItem from '../TargetEntityItem'; -import * as styles from './index.module.scss'; +import styles from './index.module.scss'; type Props = { readonly renderEntity: (entity: T) => React.ReactNode; diff --git a/packages/console/src/components/EntitiesTransfer/components/TargetEntityItem/index.tsx b/packages/console/src/components/EntitiesTransfer/components/TargetEntityItem/index.tsx index 8c71be5d205..47c4f05b19b 100644 --- a/packages/console/src/components/EntitiesTransfer/components/TargetEntityItem/index.tsx +++ b/packages/console/src/components/EntitiesTransfer/components/TargetEntityItem/index.tsx @@ -1,10 +1,10 @@ import { type ReactNode } from 'react'; -import Close from '@/assets/icons/close.svg'; +import Close from '@/assets/icons/close.svg?react'; import IconButton from '@/ds-components/IconButton'; import { type Identifiable } from '@/types/general'; -import * as styles from './index.module.scss'; +import styles from './index.module.scss'; type Props = { readonly entity: T; diff --git a/packages/console/src/components/EntitiesTransfer/index.tsx b/packages/console/src/components/EntitiesTransfer/index.tsx index ffec093f2ef..87d4ca74344 100644 --- a/packages/console/src/components/EntitiesTransfer/index.tsx +++ b/packages/console/src/components/EntitiesTransfer/index.tsx @@ -1,11 +1,11 @@ import classNames from 'classnames'; -import * as transferLayout from '@/scss/transfer.module.scss'; +import transferLayout from '@/scss/transfer.module.scss'; import { type Identifiable } from '@/types/general'; import SourceEntitiesBox, { type Props as SourceProps } from './components/SourceEntitiesBox'; import TargetEntitiesBox from './components/TargetEntitiesBox'; -import * as styles from './index.module.scss'; +import styles from './index.module.scss'; type Props = SourceProps & { readonly errorMessage?: string; diff --git a/packages/console/src/components/FeatureTag/AddOnTag.tsx b/packages/console/src/components/FeatureTag/AddOnTag.tsx new file mode 100644 index 00000000000..68112af7ab2 --- /dev/null +++ b/packages/console/src/components/FeatureTag/AddOnTag.tsx @@ -0,0 +1,19 @@ +import classNames from 'classnames'; + +/** + * AddOnTag static component + * + * Used to indicate that a feature is add-on feature and will be charged according to usage. + */ + +import styles from './index.module.scss'; + +type Props = { + readonly className?: string; +}; + +function AddOnTag({ className }: Props) { + return
Add-on
; +} + +export default AddOnTag; diff --git a/packages/console/src/components/FeatureTag/BetaTag.tsx b/packages/console/src/components/FeatureTag/BetaTag.tsx index 4bbe194a095..452eab39d3b 100644 --- a/packages/console/src/components/FeatureTag/BetaTag.tsx +++ b/packages/console/src/components/FeatureTag/BetaTag.tsx @@ -6,7 +6,7 @@ import classNames from 'classnames'; * Used to indicate that a new released feature is in beta. */ -import * as styles from './index.module.scss'; +import styles from './index.module.scss'; type Props = { readonly className?: string; diff --git a/packages/console/src/components/FeatureTag/index.tsx b/packages/console/src/components/FeatureTag/index.tsx index 6363a58518a..152ae00f037 100644 --- a/packages/console/src/components/FeatureTag/index.tsx +++ b/packages/console/src/components/FeatureTag/index.tsx @@ -1,14 +1,17 @@ -import { type ReservedPlanId } from '@logto/schemas'; +import { ReservedPlanId } from '@logto/schemas'; import classNames from 'classnames'; import { useContext } from 'react'; +import { isDevFeaturesEnabled } from '@/consts/env'; +import { SubscriptionDataContext } from '@/contexts/SubscriptionDataProvider'; import { TenantsContext } from '@/contexts/TenantsProvider'; -import * as styles from './index.module.scss'; +import AddOnTag from './AddOnTag'; +import styles from './index.module.scss'; export { default as BetaTag } from './BetaTag'; -type Props = { +export type Props = { /** * Whether the tag should be visible. It should be `true` if the tenant's subscription * plan has NO access to the feature (paywall), but it will always be visible for dev @@ -50,6 +53,9 @@ type Props = { function FeatureTag(props: Props) { const { className } = props; const { isDevTenant } = useContext(TenantsContext); + const { + currentSubscription: { planId }, + } = useContext(SubscriptionDataContext); const { isVisible, plan } = props; @@ -59,6 +65,11 @@ function FeatureTag(props: Props) { return null; } + // Show the add-on tag for Pro plan when dev features are enabled. + if (isDevFeaturesEnabled && planId === ReservedPlanId.Pro) { + return ; + } + return
{plan}
; } diff --git a/packages/console/src/components/FileIcon/index.tsx b/packages/console/src/components/FileIcon/index.tsx new file mode 100644 index 00000000000..29c8585ff8b --- /dev/null +++ b/packages/console/src/components/FileIcon/index.tsx @@ -0,0 +1,20 @@ +import { Theme } from '@logto/schemas'; +import { type ReactNode } from 'react'; + +import FileIconDark from '@/assets/icons/file-icon-dark.svg?react'; +import FileIconLight from '@/assets/icons/file-icon.svg?react'; +import useTheme from '@/hooks/use-theme'; + +const themeToRoleIcon = Object.freeze({ + [Theme.Light]: , + [Theme.Dark]: , +} satisfies Record); + +/** Render a role icon according to the current theme. */ +const FileIcon = () => { + const theme = useTheme(); + + return themeToRoleIcon[theme]; +}; + +export default FileIcon; diff --git a/packages/console/src/components/FormCard/FormCardLayout/index.module.scss b/packages/console/src/components/FormCard/FormCardLayout/index.module.scss index a929b9f9f85..cb10864dbc3 100644 --- a/packages/console/src/components/FormCard/FormCardLayout/index.module.scss +++ b/packages/console/src/components/FormCard/FormCardLayout/index.module.scss @@ -25,7 +25,7 @@ $column-width: calc((100% - 23 * $gutter-width) / 24); width: calc($column-width * 16 + $gutter-width * 15); } - @container (max-width: 600px) { + @container (max-width: 800px) { .container { flex-direction: column; justify-content: unset; diff --git a/packages/console/src/components/FormCard/FormCardLayout/index.tsx b/packages/console/src/components/FormCard/FormCardLayout/index.tsx index a19c3c66343..1622ed74cf7 100644 --- a/packages/console/src/components/FormCard/FormCardLayout/index.tsx +++ b/packages/console/src/components/FormCard/FormCardLayout/index.tsx @@ -2,7 +2,7 @@ import { type ReactNode } from 'react'; import Card from '@/ds-components/Card'; -import * as styles from './index.module.scss'; +import styles from './index.module.scss'; type Props = { readonly introduction: ReactNode; diff --git a/packages/console/src/components/FormCard/Skeleton/index.module.scss b/packages/console/src/components/FormCard/Skeleton/index.module.scss index 35406566d05..6a11b36f3c9 100644 --- a/packages/console/src/components/FormCard/Skeleton/index.module.scss +++ b/packages/console/src/components/FormCard/Skeleton/index.module.scss @@ -1,27 +1,17 @@ @use '@/scss/underscore' as _; .title { - @include _.shimmering-animation; height: 16px; width: 80px; + @include _.shimmering-animation; } .text { - @include _.shimmering-animation; width: 100%; height: 10px; + @include _.shimmering-animation; } .text + .text { margin-top: _.unit(2); } - -.field { - @include _.shimmering-animation; - width: 100%; - height: 44px; -} - -.field + .field { - margin-top: _.unit(6); -} diff --git a/packages/console/src/components/FormCard/Skeleton/index.tsx b/packages/console/src/components/FormCard/Skeleton/index.tsx index cafb1f21940..c9fc9f5a216 100644 --- a/packages/console/src/components/FormCard/Skeleton/index.tsx +++ b/packages/console/src/components/FormCard/Skeleton/index.tsx @@ -1,6 +1,8 @@ +import FormFieldSkeleton from '@/ds-components/FormField/Skeleton'; + import FormCardLayout from '../FormCardLayout'; -import * as styles from './index.module.scss'; +import styles from './index.module.scss'; type Props = { readonly formFieldCount?: number; @@ -21,10 +23,7 @@ function Skeleton({ formFieldCount = 4 }: Props) { } > - {Array.from({ length: formFieldCount }).map((_, index) => ( - // eslint-disable-next-line react/no-array-index-key -
- ))} + ); } diff --git a/packages/console/src/components/FormCard/index.tsx b/packages/console/src/components/FormCard/index.tsx index 565a3615a49..6befab89d5c 100644 --- a/packages/console/src/components/FormCard/index.tsx +++ b/packages/console/src/components/FormCard/index.tsx @@ -6,7 +6,7 @@ import TextLink from '@/ds-components/TextLink'; import type { Props as TextLinkProps } from '@/ds-components/TextLink'; import FormCardLayout from './FormCardLayout'; -import * as styles from './index.module.scss'; +import styles from './index.module.scss'; export type Props = { readonly title: AdminConsoleKey; diff --git a/packages/console/src/components/Guide/GuideCard/index.module.scss b/packages/console/src/components/Guide/GuideCard/index.module.scss index c962c7593e1..bf6890d3348 100644 --- a/packages/console/src/components/Guide/GuideCard/index.module.scss +++ b/packages/console/src/components/Guide/GuideCard/index.module.scss @@ -32,9 +32,14 @@ } .logo { - width: 48px; - height: 48px; + padding: _.unit(1.5); flex-shrink: 0; + + > svg, + > img { + width: 36px; + height: 36px; + } } .tagWrapper { diff --git a/packages/console/src/components/Guide/GuideCard/index.tsx b/packages/console/src/components/Guide/GuideCard/index.tsx index fef3471ecf8..c785aaf1326 100644 --- a/packages/console/src/components/Guide/GuideCard/index.tsx +++ b/packages/console/src/components/Guide/GuideCard/index.tsx @@ -1,4 +1,4 @@ -import { ReservedPlanId } from '@logto/schemas'; +import { ReservedPlanId, Theme } from '@logto/schemas'; import classNames from 'classnames'; import { Suspense, useCallback, useContext } from 'react'; @@ -7,9 +7,10 @@ import FeatureTag, { BetaTag } from '@/components/FeatureTag'; import { isCloud } from '@/consts/env'; import { SubscriptionDataContext } from '@/contexts/SubscriptionDataProvider'; import Button from '@/ds-components/Button'; +import useTheme from '@/hooks/use-theme'; import { onKeyDownHandler } from '@/utils/a11y'; -import * as styles from './index.module.scss'; +import styles from './index.module.scss'; export type SelectedGuide = { id: Guide['id']; @@ -29,11 +30,13 @@ function GuideCard({ data, onClick, hasBorder, hasButton }: Props) { const { id, Logo, + DarkLogo, metadata: { target, name, description, isThirdParty }, } = data; const buttonText = target === 'API' ? 'guide.get_started' : 'guide.start_building'; const { currentPlan } = useContext(SubscriptionDataContext); + const theme = useTheme(); const showPaywallTag = isCloud && isThirdParty; const showBetaTag = isCloud && isThirdParty; @@ -58,7 +61,9 @@ function GuideCard({ data, onClick, hasBorder, hasButton }: Props) { >
}> - +
+ {theme === Theme.Dark && DarkLogo ? : } +
diff --git a/packages/console/src/components/Guide/GuideCardGroup/index.tsx b/packages/console/src/components/Guide/GuideCardGroup/index.tsx index e23fb721fef..a979d68e5d0 100644 --- a/packages/console/src/components/Guide/GuideCardGroup/index.tsx +++ b/packages/console/src/components/Guide/GuideCardGroup/index.tsx @@ -5,7 +5,7 @@ import { type Guide } from '@/assets/docs/guides/types'; import GuideCard, { type SelectedGuide } from '../GuideCard'; -import * as styles from './index.module.scss'; +import styles from './index.module.scss'; type Props = { readonly className?: string; diff --git a/packages/console/src/components/Guide/ModalFooter/index.tsx b/packages/console/src/components/Guide/ModalFooter/index.tsx index d43a8960221..42862ea5d18 100644 --- a/packages/console/src/components/Guide/ModalFooter/index.tsx +++ b/packages/console/src/components/Guide/ModalFooter/index.tsx @@ -4,7 +4,7 @@ import classNames from 'classnames'; import Button from '@/ds-components/Button'; import DynamicT from '@/ds-components/DynamicT'; -import * as styles from './index.module.scss'; +import styles from './index.module.scss'; type Props = { readonly wrapperClassName?: string; diff --git a/packages/console/src/components/Guide/ModalHeader/RequestForm.tsx b/packages/console/src/components/Guide/ModalHeader/RequestForm.tsx index afa1a94c72b..7232c3b6cd8 100644 --- a/packages/console/src/components/Guide/ModalHeader/RequestForm.tsx +++ b/packages/console/src/components/Guide/ModalHeader/RequestForm.tsx @@ -10,7 +10,7 @@ import FormField from '@/ds-components/FormField'; import ModalLayout from '@/ds-components/ModalLayout'; import TextInput from '@/ds-components/TextInput'; import useCurrentUser from '@/hooks/use-current-user'; -import * as modalStyles from '@/scss/modal.module.scss'; +import modalStyles from '@/scss/modal.module.scss'; type Props = { readonly title: AdminConsoleKey; diff --git a/packages/console/src/components/Guide/ModalHeader/index.tsx b/packages/console/src/components/Guide/ModalHeader/index.tsx index dbef8c32208..99f40efdb20 100644 --- a/packages/console/src/components/Guide/ModalHeader/index.tsx +++ b/packages/console/src/components/Guide/ModalHeader/index.tsx @@ -1,14 +1,14 @@ import { type AdminConsoleKey } from '@logto/phrases'; import { useCallback, useState } from 'react'; -import Box from '@/assets/icons/box.svg'; +import Box from '@/assets/icons/box.svg?react'; import { githubIssuesLink } from '@/consts'; import { isCloud } from '@/consts/env'; import Button from '@/ds-components/Button'; import DsModalHeader from '@/ds-components/ModalHeader'; import RequestForm from './RequestForm'; -import * as styles from './index.module.scss'; +import styles from './index.module.scss'; type Props = { readonly title: AdminConsoleKey; diff --git a/packages/console/src/components/Guide/StepsSkeleton/index.module.scss b/packages/console/src/components/Guide/StepsSkeleton/index.module.scss index e221c516409..e9c657a4ac3 100644 --- a/packages/console/src/components/Guide/StepsSkeleton/index.module.scss +++ b/packages/console/src/components/Guide/StepsSkeleton/index.module.scss @@ -11,11 +11,11 @@ margin: 0 auto; .index { - @include _.shimmering-animation; width: 28px; height: 28px; border-radius: 50%; margin-right: _.unit(4); + @include _.shimmering-animation; } .wrapper { @@ -24,16 +24,16 @@ flex-direction: column; .title { - @include _.shimmering-animation; width: 140px; height: 24px; + @include _.shimmering-animation; } .subtitle { - @include _.shimmering-animation; width: 400px; height: 20px; margin-top: _.unit(1); + @include _.shimmering-animation; } } } diff --git a/packages/console/src/components/Guide/StepsSkeleton/index.tsx b/packages/console/src/components/Guide/StepsSkeleton/index.tsx index 7d3ed4e75d9..5557f532f57 100644 --- a/packages/console/src/components/Guide/StepsSkeleton/index.tsx +++ b/packages/console/src/components/Guide/StepsSkeleton/index.tsx @@ -1,4 +1,4 @@ -import * as styles from './index.module.scss'; +import styles from './index.module.scss'; function StepsSkeleton() { return ( diff --git a/packages/console/src/components/Guide/index.tsx b/packages/console/src/components/Guide/index.tsx index be312df981e..d68f7613928 100644 --- a/packages/console/src/components/Guide/index.tsx +++ b/packages/console/src/components/Guide/index.tsx @@ -7,10 +7,11 @@ import { type GuideMetadata } from '@/assets/docs/guides/types'; import Button from '@/ds-components/Button'; import OverlayScrollbar from '@/ds-components/OverlayScrollbar'; import MdxProvider from '@/mdx-components/MdxProvider'; +import { type ApplicationSecretRow } from '@/pages/ApplicationDetails/ApplicationDetailsContent/EndpointsAndCredentials'; import NotFound from '@/pages/NotFound'; import StepsSkeleton from './StepsSkeleton'; -import * as styles from './index.module.scss'; +import styles from './index.module.scss'; export type GuideContextType = { metadata: Readonly; @@ -19,6 +20,7 @@ export type GuideContextType = { | ((props: { readonly className?: string }) => JSX.Element); isCompact: boolean; app?: ApplicationResponse; + secrets?: ApplicationSecretRow[]; endpoint?: string; redirectUris?: string[]; postLogoutRedirectUris?: string[]; @@ -40,6 +42,7 @@ export const GuideContext = createContext({ metadata: {} as GuideMetadata, // eslint-disable-next-line @typescript-eslint/consistent-type-assertions, no-restricted-syntax app: {} as ApplicationResponse, + secrets: [], endpoint: '', redirectUris: [], postLogoutRedirectUris: [], diff --git a/packages/console/src/components/ImageInputs/LogoAndFavicon.tsx b/packages/console/src/components/ImageInputs/LogoAndFavicon.tsx new file mode 100644 index 00000000000..b60af048eb6 --- /dev/null +++ b/packages/console/src/components/ImageInputs/LogoAndFavicon.tsx @@ -0,0 +1,62 @@ +import { type Theme } from '@logto/schemas'; +import { type FieldValues, type Control, type UseFormRegister } from 'react-hook-form'; +import { useTranslation } from 'react-i18next'; + +import ImageInputs, { type ImageField } from '.'; + +type Field = Pick, 'name' | 'error'>; + +type Props = { + readonly theme: Theme; + readonly control: Control; + readonly register: UseFormRegister; + /** + * Form-related data of the logo input, including the name (field path) and error in the form. + */ + readonly logo: Field; + /** + * Form-related data of the favicon input, including the name (field path) and error in the form. + */ + readonly favicon: Field; + /** The type of the logo. It will affect the translation key. */ + readonly type: 'app_logo' | 'company_logo'; +}; + +/** + * A component that renders the logo and favicon inputs for a form. + * + * When user assets service is available, it will render two image uploader components side-by-side; + * otherwise, it will render two text inputs. + * + * @see {@link ImageInputs} for the implementation of the inner components. + */ +function LogoAndFavicon({ + theme, + control, + register, + logo, + favicon, + type, +}: Props) { + const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' }); + + return ( + + {t(`sign_in_exp.branding.with_${theme}`, { + value: t(`sign_in_exp.branding.${type}_and_favicon`), + })} + + } + control={control} + register={register} + fields={[ + { ...logo, theme, type }, + { ...favicon, theme, type: 'favicon' }, + ]} + /> + ); +} + +export default LogoAndFavicon; diff --git a/packages/console/src/pages/SignInExperience/PageContent/Branding/BrandingForm/LogoAndFaviconUploader/index.module.scss b/packages/console/src/components/ImageInputs/index.module.scss similarity index 69% rename from packages/console/src/pages/SignInExperience/PageContent/Branding/BrandingForm/LogoAndFaviconUploader/index.module.scss rename to packages/console/src/components/ImageInputs/index.module.scss index 1f8c81e86ab..4e24be27ac4 100644 --- a/packages/console/src/pages/SignInExperience/PageContent/Branding/BrandingForm/LogoAndFaviconUploader/index.module.scss +++ b/packages/console/src/components/ImageInputs/index.module.scss @@ -1,20 +1,19 @@ @use '@/scss/underscore' as _; .container { - display: flex; - flex-direction: column; -} - -.uploader { display: flex; gap: _.unit(2); - .logoUploader { - flex: 2 0; + > * { + flex: 1; + + &.dark { + background-color: #111; + } } - .faviconUploader { - flex: 1; + .logo { + flex: 3; } } diff --git a/packages/console/src/components/ImageInputs/index.tsx b/packages/console/src/components/ImageInputs/index.tsx new file mode 100644 index 00000000000..6dea4890cba --- /dev/null +++ b/packages/console/src/components/ImageInputs/index.tsx @@ -0,0 +1,169 @@ +import { type LocalePhrase } from '@logto/phrases'; +import { Theme } from '@logto/schemas'; +import { cond, noop } from '@silverhand/essentials'; +import classNames from 'classnames'; +import type React from 'react'; +import { useMemo, useState } from 'react'; +import { + Controller, + type FieldPath, + type FieldValues, + type Control, + type UseFormRegister, + type FieldError, +} from 'react-hook-form'; +import { useTranslation } from 'react-i18next'; + +import FormField from '@/ds-components/FormField'; +import Skeleton from '@/ds-components/FormField/Skeleton'; +import TextInput from '@/ds-components/TextInput'; +import ImageUploader from '@/ds-components/Uploader/ImageUploader'; +import useImageMimeTypes from '@/hooks/use-image-mime-types'; +import useUserAssetsService from '@/hooks/use-user-assets-service'; +import { uriValidator } from '@/utils/validator'; + +import styles from './index.module.scss'; + +export const themeToLogoName = Object.freeze({ + [Theme.Light]: 'logoUrl', + [Theme.Dark]: 'darkLogoUrl', +} as const satisfies Record); + +export type ImageField = { + /** The name (field path) of the field in the form. */ + name: FieldPath; + /** + * The type of the field. It should match the existing structure in the translation file to get + * the correct translations. + */ + type: keyof LocalePhrase['translation']['admin_console']['sign_in_exp']['branding_uploads']; + theme: Theme; + /** The error message of the field in the form. */ + error?: FieldError; +}; + +type Props = { + /** The condensed title when user assets service is available. */ + readonly uploadTitle: React.ComponentProps['title']; + /** + * When user assets service is available, the tip will be displayed for the `uploadTitle`; + * otherwise, it will be displayed for each text input. + */ + readonly tip?: React.ComponentProps['tip']; + readonly control: Control; + readonly register: UseFormRegister; + readonly fields: Array>; +}; + +/** + * A component that renders the logo inputs for a form. + * + * When user assets service is available, it will render the image uploader components side-by-side; + * otherwise, it will render the text inputs. + */ +function ImageInputs({ + uploadTitle, + tip, + control, + register, + fields, +}: Props) { + const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' }); + const [uploadErrors, setUploadErrors] = useState>>({}); + const { description } = useImageMimeTypes(); + const { isReady: isUserAssetsServiceReady, isLoading } = useUserAssetsService(); + const uploadErrorChangeHandlers = useMemo( + () => + Object.fromEntries( + fields.map((field) => [ + field.name, + (message?: string) => { + setUploadErrors((previous) => ({ ...previous, [field.name]: message })); + }, + ]) + ), + [fields] + ); + + if (isLoading) { + return ; + } + + if (!isUserAssetsServiceReady) { + return ( + <> + {fields.map((field) => ( + + {t(`sign_in_exp.branding.with_${field.theme}`, { + value: t(`sign_in_exp.branding_uploads.${field.type}.url`), + })} + + } + > + + !value || uriValidator(value) || t('errors.invalid_uri_format'), + shouldUnregister: true, + })} + placeholder={t(`sign_in_exp.branding_uploads.${field.type}.url_placeholder`)} + error={field.error?.message} + /> + + ))} + + ); + } + + return ( + +
+ {fields.map((field) => ( + ( + { + onChange(url); + }} + // Noop fallback should not be necessary, but for TypeScript to be happy + onUploadErrorChange={uploadErrorChangeHandlers[field.name] ?? noop} + onDelete={() => { + onChange(''); + }} + /> + )} + /> + ))} +
+ {fields.map( + (field) => + uploadErrors[field.name] && ( +
+ {t(`sign_in_exp.branding_uploads.${field.type}.error`, { + error: uploadErrors[field.name], + })} +
+ ) + )} + +
{description}
+
+ ); +} + +export default ImageInputs; diff --git a/packages/console/src/components/Index/index.tsx b/packages/console/src/components/Index/index.tsx index d9584593dca..4c9036e0e44 100644 --- a/packages/console/src/components/Index/index.tsx +++ b/packages/console/src/components/Index/index.tsx @@ -1,8 +1,8 @@ import classNames from 'classnames'; -import Tick from '@/assets/icons/tick.svg'; +import Tick from '@/assets/icons/tick.svg?react'; -import * as styles from './index.module.scss'; +import styles from './index.module.scss'; type Props = { readonly className?: string; diff --git a/packages/console/src/components/InlineUpsell/index.tsx b/packages/console/src/components/InlineUpsell/index.tsx index 1f57a042c43..ca2fd0eb152 100644 --- a/packages/console/src/components/InlineUpsell/index.tsx +++ b/packages/console/src/components/InlineUpsell/index.tsx @@ -8,7 +8,7 @@ import useTenantPathname from '@/hooks/use-tenant-pathname'; import ContactUsPhraseLink from '../ContactUsPhraseLink'; -import * as styles from './index.module.scss'; +import styles from './index.module.scss'; type Props = { readonly className?: string; diff --git a/packages/console/src/components/ItemPreview/ApplicationPreview.tsx b/packages/console/src/components/ItemPreview/ApplicationPreview.tsx index e284a5894c6..438d322834d 100644 --- a/packages/console/src/components/ItemPreview/ApplicationPreview.tsx +++ b/packages/console/src/components/ItemPreview/ApplicationPreview.tsx @@ -5,7 +5,7 @@ import ApplicationIcon from '@/components/ApplicationIcon'; import { applicationTypeI18nKey } from '@/types/applications'; import ItemPreview from '.'; -import * as styles from './index.module.scss'; +import styles from './index.module.scss'; const applicationsPathname = '/applications'; const buildDetailsPathname = (id: string) => `${applicationsPathname}/${id}`; diff --git a/packages/console/src/components/ItemPreview/index.tsx b/packages/console/src/components/ItemPreview/index.tsx index e7447b76e06..2728e184848 100644 --- a/packages/console/src/components/ItemPreview/index.tsx +++ b/packages/console/src/components/ItemPreview/index.tsx @@ -5,7 +5,7 @@ import { Link } from 'react-router-dom'; import useTenantPathname from '@/hooks/use-tenant-pathname'; -import * as styles from './index.module.scss'; +import styles from './index.module.scss'; type Props = { readonly title: ReactNode; diff --git a/packages/console/src/components/ListPage/index.tsx b/packages/console/src/components/ListPage/index.tsx index c59d75fea1d..26abe9e481b 100644 --- a/packages/console/src/components/ListPage/index.tsx +++ b/packages/console/src/components/ListPage/index.tsx @@ -2,14 +2,14 @@ import classNames from 'classnames'; import { type ReactNode } from 'react'; import { type FieldValues, type FieldPath } from 'react-hook-form'; -import Plus from '@/assets/icons/plus.svg'; +import Plus from '@/assets/icons/plus.svg?react'; import PageMeta, { type Props as PageMetaProps } from '@/components/PageMeta'; import { type Props as ButtonProps } from '@/ds-components/Button'; import Button from '@/ds-components/Button'; import { type Props as CardTitleProps } from '@/ds-components/CardTitle'; import CardTitle from '@/ds-components/CardTitle'; import Table, { type Props as TableProps } from '@/ds-components/Table'; -import * as pageLayout from '@/scss/page-layout.module.scss'; +import pageLayout from '@/scss/page-layout.module.scss'; type CreateButtonProps = { title: ButtonProps['title']; diff --git a/packages/console/src/components/LivePreviewButton/index.tsx b/packages/console/src/components/LivePreviewButton/index.tsx index 6a1ec955d3f..c773cfaac34 100644 --- a/packages/console/src/components/LivePreviewButton/index.tsx +++ b/packages/console/src/components/LivePreviewButton/index.tsx @@ -3,13 +3,13 @@ import classNames from 'classnames'; import { useContext } from 'react'; import { useTranslation } from 'react-i18next'; -import ExternalLinkIcon from '@/assets/icons/external-link.svg'; +import ExternalLinkIcon from '@/assets/icons/external-link.svg?react'; import { AppDataContext } from '@/contexts/AppDataProvider'; import type { Props as ButtonProps, ButtonType } from '@/ds-components/Button'; import Button from '@/ds-components/Button'; import { Tooltip } from '@/ds-components/Tip'; -import * as styles from './index.module.scss'; +import styles from './index.module.scss'; type Props = { readonly size?: ButtonProps['size']; diff --git a/packages/console/src/components/ManageOrganizationPermissionModal/index.tsx b/packages/console/src/components/ManageOrganizationPermissionModal/index.tsx index bca34f4503a..153802ff340 100644 --- a/packages/console/src/components/ManageOrganizationPermissionModal/index.tsx +++ b/packages/console/src/components/ManageOrganizationPermissionModal/index.tsx @@ -10,7 +10,7 @@ import FormField from '@/ds-components/FormField'; import ModalLayout from '@/ds-components/ModalLayout'; import TextInput from '@/ds-components/TextInput'; import useApi from '@/hooks/use-api'; -import * as modalStyles from '@/scss/modal.module.scss'; +import modalStyles from '@/scss/modal.module.scss'; import { trySubmitSafe } from '@/utils/form'; type Props = { diff --git a/packages/console/src/components/Markdown/index.tsx b/packages/console/src/components/Markdown/index.tsx index c8cf7c6eb97..7fb575a7474 100644 --- a/packages/console/src/components/Markdown/index.tsx +++ b/packages/console/src/components/Markdown/index.tsx @@ -4,6 +4,8 @@ import classNames from 'classnames'; import { memo, useRef } from 'react'; import ReactMarkdown from 'react-markdown'; import remarkGfm from 'remark-gfm'; + +// TODO: @charles double check if this is still needed /** * Workaround for the markdown crash issue in the parcel dev build. It seems parcel does * something clever in dev mode and messing up the `hastToReact` module. Manually adding @@ -17,7 +19,7 @@ import 'property-information'; import CodeEditor from '@/ds-components/CodeEditor'; import GithubRawImage from './components/GithubRawImage'; -import * as styles from './index.module.scss'; +import styles from './index.module.scss'; type Props = { readonly className?: string; diff --git a/packages/console/src/components/MauExceededModal/index.tsx b/packages/console/src/components/MauExceededModal/index.tsx index 3d44dddf692..835a14b4007 100644 --- a/packages/console/src/components/MauExceededModal/index.tsx +++ b/packages/console/src/components/MauExceededModal/index.tsx @@ -4,6 +4,7 @@ import ReactModal from 'react-modal'; import PlanUsage from '@/components/PlanUsage'; import { contactEmailLink } from '@/consts'; +import { isDevFeaturesEnabled } from '@/consts/env'; import { subscriptionPage } from '@/consts/pages'; import { SubscriptionDataContext } from '@/contexts/SubscriptionDataProvider'; import { TenantsContext } from '@/contexts/TenantsProvider'; @@ -12,16 +13,22 @@ import FormField from '@/ds-components/FormField'; import InlineNotification from '@/ds-components/InlineNotification'; import ModalLayout from '@/ds-components/ModalLayout'; import useTenantPathname from '@/hooks/use-tenant-pathname'; -import * as modalStyles from '@/scss/modal.module.scss'; +import modalStyles from '@/scss/modal.module.scss'; import PlanName from '../PlanName'; -import * as styles from './index.module.scss'; +import styles from './index.module.scss'; function MauExceededModal() { const { currentTenant } = useContext(TenantsContext); const { usage } = currentTenant ?? {}; - const { currentPlan, currentSubscription } = useContext(SubscriptionDataContext); + const { + currentPlan, + currentSubscription, + currentSku, + currentSubscriptionQuota, + currentSubscriptionUsage, + } = useContext(SubscriptionDataContext); const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' }); const { navigate } = useTenantPathname(); @@ -40,7 +47,10 @@ function MauExceededModal() { name: planName, } = currentPlan; - const isMauExceeded = mauLimit !== null && usage.activeUsers >= mauLimit; + const isMauExceeded = isDevFeaturesEnabled + ? currentSubscriptionQuota.mauLimit !== null && + currentSubscriptionUsage.mauLimit >= currentSubscriptionQuota.mauLimit + : mauLimit !== null && usage.activeUsers >= mauLimit; if (!isMauExceeded) { return null; @@ -76,7 +86,7 @@ function MauExceededModal() { , + planName: , }} > {t('upsell.mau_exceeded_modal.notification')} diff --git a/packages/console/src/components/MfaFactorTitle/index.tsx b/packages/console/src/components/MfaFactorTitle/index.tsx index a32c32339f5..8f75cafb8b4 100644 --- a/packages/console/src/components/MfaFactorTitle/index.tsx +++ b/packages/console/src/components/MfaFactorTitle/index.tsx @@ -1,16 +1,16 @@ import { MfaFactor } from '@logto/schemas'; import { type ReactNode } from 'react'; -import FactorBackupCode from '@/assets/icons/factor-backup-code.svg'; -import FactorTotp from '@/assets/icons/factor-totp.svg'; -import FactorWebAuthn from '@/assets/icons/factor-webauthn.svg'; -import Tip from '@/assets/icons/tip.svg'; +import FactorBackupCode from '@/assets/icons/factor-backup-code.svg?react'; +import FactorTotp from '@/assets/icons/factor-totp.svg?react'; +import FactorWebAuthn from '@/assets/icons/factor-webauthn.svg?react'; +import Tip from '@/assets/icons/tip.svg?react'; import IconButton from '@/ds-components/IconButton'; import { ToggleTip } from '@/ds-components/Tip'; import MfaFactorName, { type Props as MfaFactorNameProps } from '../MfaFactorName'; -import * as styles from './index.module.scss'; +import styles from './index.module.scss'; const factorIcon: Record = { [MfaFactor.TOTP]: FactorTotp, diff --git a/packages/console/src/components/MultiOptionInput/index.tsx b/packages/console/src/components/MultiOptionInput/index.tsx index 68d5db09eb7..47cc0f85c79 100644 --- a/packages/console/src/components/MultiOptionInput/index.tsx +++ b/packages/console/src/components/MultiOptionInput/index.tsx @@ -2,12 +2,12 @@ import { isKeyInObject, type Nullable } from '@silverhand/essentials'; import classNames from 'classnames'; import { type ReactNode, useRef, useState, useCallback } from 'react'; -import Close from '@/assets/icons/close.svg'; +import Close from '@/assets/icons/close.svg?react'; import IconButton from '@/ds-components/IconButton'; import Tag from '@/ds-components/Tag'; import { onKeyDownHandler } from '@/utils/a11y'; -import * as styles from './index.module.scss'; +import styles from './index.module.scss'; type CanBePromise = T | Promise; diff --git a/packages/console/src/components/MultiTextInputField/index.tsx b/packages/console/src/components/MultiTextInputField/index.tsx index 69791ecaeff..d797a4e1891 100644 --- a/packages/console/src/components/MultiTextInputField/index.tsx +++ b/packages/console/src/components/MultiTextInputField/index.tsx @@ -5,7 +5,7 @@ import FormField from '@/ds-components/FormField'; import type { Props as MultiTextInputProps } from '@/ds-components/MultiTextInput'; import MultiTextInput from '@/ds-components/MultiTextInput'; -import * as styles from './index.module.scss'; +import styles from './index.module.scss'; type Props = MultiTextInputProps & Pick & { diff --git a/packages/console/src/components/OpenExternalLink/index.tsx b/packages/console/src/components/OpenExternalLink/index.tsx index c6e93e6c345..649fbde7fd3 100644 --- a/packages/console/src/components/OpenExternalLink/index.tsx +++ b/packages/console/src/components/OpenExternalLink/index.tsx @@ -1,6 +1,6 @@ import { useTranslation } from 'react-i18next'; -import ExternalLinkIcon from '@/assets/icons/external-link.svg'; +import ExternalLinkIcon from '@/assets/icons/external-link.svg?react'; import IconButton from '@/ds-components/IconButton'; import { Tooltip } from '@/ds-components/Tip'; diff --git a/packages/console/src/components/OrganizationList/index.tsx b/packages/console/src/components/OrganizationList/index.tsx index a924e830646..aaef30d4f74 100644 --- a/packages/console/src/components/OrganizationList/index.tsx +++ b/packages/console/src/components/OrganizationList/index.tsx @@ -3,8 +3,8 @@ import { type ReactNode, useState } from 'react'; import { useTranslation } from 'react-i18next'; import useSWR from 'swr'; -import OrganizationIcon from '@/assets/icons/organization-preview.svg'; -import Tip from '@/assets/icons/tip.svg'; +import OrganizationIcon from '@/assets/icons/organization-preview.svg?react'; +import Tip from '@/assets/icons/tip.svg?react'; import EmptyDataPlaceholder from '@/components/EmptyDataPlaceholder'; import ItemPreview from '@/components/ItemPreview'; import { RoleOption } from '@/components/OrganizationRolesSelect'; @@ -18,7 +18,7 @@ import { ToggleTip } from '@/ds-components/Tip'; import { type RequestError } from '@/hooks/use-api'; import useTenantPathname from '@/hooks/use-tenant-pathname'; -import * as styles from './index.module.scss'; +import styles from './index.module.scss'; type Props = { readonly type: 'user' | 'application'; diff --git a/packages/console/src/components/OrganizationRolesSelect/index.tsx b/packages/console/src/components/OrganizationRolesSelect/index.tsx index 452100f8980..f78a09f0876 100644 --- a/packages/console/src/components/OrganizationRolesSelect/index.tsx +++ b/packages/console/src/components/OrganizationRolesSelect/index.tsx @@ -1,14 +1,14 @@ import { type OrganizationRole, type RoleType } from '@logto/schemas'; import classNames from 'classnames'; -import RoleIcon from '@/assets/icons/organization-role-feature.svg'; +import RoleIcon from '@/assets/icons/organization-role-feature.svg?react'; import MultiSelect, { type Option } from '@/ds-components/Select/MultiSelect'; import useSearchValues from '@/hooks/use-search-values'; import Breakable from '../Breakable'; import ThemedIcon from '../ThemedIcon'; -import * as styles from './index.module.scss'; +import styles from './index.module.scss'; type RoleOptionProps = { readonly title?: string; diff --git a/packages/console/src/components/PaymentOverdueModal/index.tsx b/packages/console/src/components/PaymentOverdueModal/index.tsx index 78029388510..73e31ff27fe 100644 --- a/packages/console/src/components/PaymentOverdueModal/index.tsx +++ b/packages/console/src/components/PaymentOverdueModal/index.tsx @@ -10,11 +10,11 @@ import FormField from '@/ds-components/FormField'; import InlineNotification from '@/ds-components/InlineNotification'; import ModalLayout from '@/ds-components/ModalLayout'; import useSubscribe from '@/hooks/use-subscribe'; -import * as modalStyles from '@/scss/modal.module.scss'; +import modalStyles from '@/scss/modal.module.scss'; import BillInfo from '../BillInfo'; -import * as styles from './index.module.scss'; +import styles from './index.module.scss'; function PaymentOverdueModal() { const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' }); diff --git a/packages/console/src/components/PermissionsTable/index.tsx b/packages/console/src/components/PermissionsTable/index.tsx index 3097491f369..0a2b62fab26 100644 --- a/packages/console/src/components/PermissionsTable/index.tsx +++ b/packages/console/src/components/PermissionsTable/index.tsx @@ -5,9 +5,9 @@ import { useState } from 'react'; import { toast } from 'react-hot-toast'; import { useTranslation } from 'react-i18next'; -import Plus from '@/assets/icons/plus.svg'; -import PermissionsEmptyDark from '@/assets/images/permissions-empty-dark.svg'; -import PermissionsEmpty from '@/assets/images/permissions-empty.svg'; +import Plus from '@/assets/icons/plus.svg?react'; +import PermissionsEmptyDark from '@/assets/images/permissions-empty-dark.svg?react'; +import PermissionsEmpty from '@/assets/images/permissions-empty.svg?react'; import { ApiResourceDetailsTabs } from '@/consts/page-tabs'; import Button from '@/ds-components/Button'; import type { Props as PaginationProps } from '@/ds-components/Pagination'; @@ -24,7 +24,7 @@ import ActionsButton from '../ActionsButton'; import EditScopeModal, { type EditScopeData } from '../EditScopeModal'; import EmptyDataPlaceholder from '../EmptyDataPlaceholder'; -import * as styles from './index.module.scss'; +import styles from './index.module.scss'; type SearchProps = { keyword: string; diff --git a/packages/console/src/components/PlanDescription/index.tsx b/packages/console/src/components/PlanDescription/index.tsx index f39a94c1b66..1db3e078542 100644 --- a/packages/console/src/components/PlanDescription/index.tsx +++ b/packages/console/src/components/PlanDescription/index.tsx @@ -1,4 +1,5 @@ import { ReservedPlanId } from '@logto/schemas'; +import { conditional } from '@silverhand/essentials'; import { type TFuncKey } from 'i18next'; import DynamicT from '@/ds-components/DynamicT'; @@ -11,10 +12,17 @@ const registeredPlanDescriptionPhrasesMap: Record< [ReservedPlanId.Pro]: 'pro_plan_description', }; -type Props = { readonly planId: string }; +type Props = { + /** Temporarily mark as optional. */ + readonly skuId?: string; + /** @deprecated */ + readonly planId: string; +}; -function PlanDescription({ planId }: Props) { - const description = registeredPlanDescriptionPhrasesMap[planId]; +function PlanDescription({ skuId, planId }: Props) { + const description = + conditional(skuId && registeredPlanDescriptionPhrasesMap[skuId]) ?? + registeredPlanDescriptionPhrasesMap[planId]; if (!description) { return null; diff --git a/packages/console/src/components/PlanName/index.tsx b/packages/console/src/components/PlanName/index.tsx index 2dc5f8e77b4..45cdc98d5ff 100644 --- a/packages/console/src/components/PlanName/index.tsx +++ b/packages/console/src/components/PlanName/index.tsx @@ -1,7 +1,8 @@ +import { conditional } from '@silverhand/essentials'; import { type TFuncKey } from 'i18next'; import { useTranslation } from 'react-i18next'; -import { ReservedPlanName } from '@/types/subscriptions'; +import { ReservedPlanName, ReservedSkuId } from '@/types/subscriptions'; const registeredPlanNamePhraseMap: Record< string, @@ -14,13 +15,28 @@ const registeredPlanNamePhraseMap: Record< [ReservedPlanName.Enterprise]: 'enterprise', }; +const registeredSkuIdNamePhraseMap: Record< + string, + TFuncKey<'translation', 'admin_console.subscription'> | undefined +> = { + quotaKey: undefined, + [ReservedSkuId.Free]: 'free_plan', + [ReservedSkuId.Pro]: 'pro_plan', + [ReservedSkuId.Enterprise]: 'enterprise', +}; + type Props = { + /** Temporarily use optional for backward compatibility. */ + readonly skuId?: string; + /** @deprecated */ readonly name: string; }; -function PlanName({ name }: Props) { +// TODO: rename the component once new pricing model is ready, should be `SkuName`. +function PlanName({ skuId, name }: Props) { const { t } = useTranslation(undefined, { keyPrefix: 'admin_console.subscription' }); - const planNamePhrase = registeredPlanNamePhraseMap[name]; + const planNamePhrase = + conditional(skuId && registeredSkuIdNamePhraseMap[skuId]) ?? registeredPlanNamePhraseMap[name]; /** * Note: fallback to the plan name if the phrase is not registered. diff --git a/packages/console/src/components/PlanUsage/ProPlanUsageCard/index.module.scss b/packages/console/src/components/PlanUsage/ProPlanUsageCard/index.module.scss new file mode 100644 index 00000000000..3a5a84e5344 --- /dev/null +++ b/packages/console/src/components/PlanUsage/ProPlanUsageCard/index.module.scss @@ -0,0 +1,35 @@ +@use '@/scss/underscore' as _; + +.card { + display: flex; + flex-direction: column; + justify-content: space-between; + align-items: left; + border-radius: 12px; + border: 1px solid var(--color-divider); + background: var(--color-layer-1); + padding: _.unit(5.5) _.unit(6); + gap: _.unit(6); +} + +.title { + font: var(--font-title-3); + color: var(--color-text-secondary); + display: flex; + align-items: center; +} + +.description { + font: var(--font-title-3); + color: var(--color-text); +} + +.usageTip { + font: var(--font-body-2); + color: var(--color-text-secondary); +} + +.tag { + padding-top: 1px; + padding-bottom: 1px; +} diff --git a/packages/console/src/components/PlanUsage/ProPlanUsageCard/index.tsx b/packages/console/src/components/PlanUsage/ProPlanUsageCard/index.tsx new file mode 100644 index 00000000000..70b60b8876e --- /dev/null +++ b/packages/console/src/components/PlanUsage/ProPlanUsageCard/index.tsx @@ -0,0 +1,78 @@ +import { type AdminConsoleKey } from '@logto/phrases'; +import classNames from 'classnames'; +import { Trans, useTranslation } from 'react-i18next'; + +import Tip from '@/assets/icons/tip.svg?react'; +import DynamicT from '@/ds-components/DynamicT'; +import IconButton from '@/ds-components/IconButton'; +import Tag from '@/ds-components/Tag'; +import TextLink from '@/ds-components/TextLink'; +import { ToggleTip } from '@/ds-components/Tip'; + +import { formatNumber } from '../utils'; + +import styles from './index.module.scss'; + +export type Props = { + readonly usage: number | boolean; + readonly quota?: number; + readonly usageKey: AdminConsoleKey; + readonly titleKey: AdminConsoleKey; + readonly tooltipKey: AdminConsoleKey; + readonly className?: string; +}; + +function ProPlanUsageCard({ usage, quota, usageKey, titleKey, tooltipKey, className }: Props) { + const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' }); + + return ( +
+
+ + + + , + }} + > + {t(tooltipKey)} + + } + > + + + + +
+ {typeof usage === 'number' ? ( +
+ , + }} + > + {t(usageKey, { + usage: + quota && typeof quota === 'number' + ? `${formatNumber(usage)} / ${formatNumber(quota)}` + : formatNumber(usage), + })} + +
+ ) : ( +
+ + + +
+ )} +
+ ); +} + +export default ProPlanUsageCard; diff --git a/packages/console/src/components/PlanUsage/index.module.scss b/packages/console/src/components/PlanUsage/index.module.scss index 49bf92bd922..c01e37937d6 100644 --- a/packages/console/src/components/PlanUsage/index.module.scss +++ b/packages/console/src/components/PlanUsage/index.module.scss @@ -18,10 +18,27 @@ align-items: center; } +.newPricingModelUsage { + margin-top: _.unit(1); + display: flex; + flex-wrap: wrap; + gap: _.unit(2); +} + +.cardItem { + flex: 0 0 calc(33.333% - _.unit(2) * 2); + max-width: calc(33.333% - _.unit(2) * 2); + max-height: 112px; +} + .planCycle { font: var(--font-body-2); } +.planCycleNewPricingModel { + color: var(--color-text-secondary); +} + .usageBar { border-radius: 4px; background-color: var(--color-layer-2); diff --git a/packages/console/src/components/PlanUsage/index.tsx b/packages/console/src/components/PlanUsage/index.tsx index 96fb6345b54..6714d41f0c1 100644 --- a/packages/console/src/components/PlanUsage/index.tsx +++ b/packages/console/src/components/PlanUsage/index.tsx @@ -1,30 +1,80 @@ -import { conditional } from '@silverhand/essentials'; +import { ReservedPlanId } from '@logto/schemas'; +import { cond, conditional } from '@silverhand/essentials'; import classNames from 'classnames'; import dayjs from 'dayjs'; +import { useContext } from 'react'; import { type SubscriptionUsage, type Subscription } from '@/cloud/types/router'; +import { isDevFeaturesEnabled } from '@/consts/env'; +import { SubscriptionDataContext } from '@/contexts/SubscriptionDataProvider'; import DynamicT from '@/ds-components/DynamicT'; import { type SubscriptionPlan } from '@/types/subscriptions'; import { formatPeriod } from '@/utils/subscription'; -import * as styles from './index.module.scss'; +import ProPlanUsageCard, { type Props as ProPlanUsageCardProps } from './ProPlanUsageCard'; +import styles from './index.module.scss'; +import { usageKeys, usageKeyMap, titleKeyMap, tooltipKeyMap } from './utils'; type Props = { + /** @deprecated */ readonly subscriptionUsage: SubscriptionUsage; + /** @deprecated */ readonly currentSubscription: Subscription; + /** @deprecated */ readonly currentPlan: SubscriptionPlan; }; function PlanUsage({ subscriptionUsage, currentSubscription, currentPlan }: Props) { - const { currentPeriodStart, currentPeriodEnd } = currentSubscription; - const { activeUsers } = subscriptionUsage; const { - quota: { mauLimit }, - } = currentPlan; + currentSubscriptionQuota, + currentSubscriptionUsage, + currentSubscription: currentSubscriptionFromNewPricingModel, + } = useContext(SubscriptionDataContext); + + const { currentPeriodStart, currentPeriodEnd } = isDevFeaturesEnabled + ? currentSubscriptionFromNewPricingModel + : currentSubscription; + + const [activeUsers, mauLimit] = isDevFeaturesEnabled + ? [currentSubscriptionUsage.mauLimit, currentSubscriptionQuota.mauLimit] + : [subscriptionUsage.activeUsers, currentPlan.quota.mauLimit]; const usagePercent = conditional(mauLimit && activeUsers / mauLimit); - return ( + const usages: ProPlanUsageCardProps[] = usageKeys.map((key) => ({ + usage: currentSubscriptionUsage[key], + usageKey: `subscription.usage.${usageKeyMap[key]}`, + titleKey: `subscription.usage.${titleKeyMap[key]}`, + tooltipKey: `subscription.usage.${tooltipKeyMap[key]}`, + ...cond( + key === 'tokenLimit' && + currentSubscriptionQuota.tokenLimit && { quota: currentSubscriptionQuota.tokenLimit } + ), + })); + + return isDevFeaturesEnabled && + currentSubscriptionFromNewPricingModel.planId === ReservedPlanId.Pro ? ( +
+
+ +
+
+ {usages.map((props, index) => ( + // eslint-disable-next-line react/no-array-index-key + + ))} +
+
+ ) : (
{`${activeUsers} / `} diff --git a/packages/console/src/components/PlanUsage/utils.ts b/packages/console/src/components/PlanUsage/utils.ts new file mode 100644 index 00000000000..4234148079c --- /dev/null +++ b/packages/console/src/components/PlanUsage/utils.ts @@ -0,0 +1,77 @@ +import { type TFuncKey } from 'i18next'; + +import { type NewSubscriptionQuota } from '@/cloud/types/router'; + +type UsageKey = Pick< + NewSubscriptionQuota, + | 'mauLimit' + | 'organizationsEnabled' + | 'mfaEnabled' + | 'enterpriseSsoLimit' + | 'resourcesLimit' + | 'machineToMachineLimit' + | 'tenantMembersLimit' + | 'tokenLimit' + | 'hooksLimit' +>; + +export const usageKeys: Array = [ + 'mauLimit', + 'organizationsEnabled', + 'mfaEnabled', + 'enterpriseSsoLimit', + 'resourcesLimit', + 'machineToMachineLimit', + 'tenantMembersLimit', + 'tokenLimit', + 'hooksLimit', +]; + +export const usageKeyMap: Record< + keyof UsageKey, + TFuncKey<'translation', 'admin_console.subscription.usage'> +> = { + mauLimit: 'mau.description', + organizationsEnabled: 'organizations.description', + mfaEnabled: 'mfa.description', + enterpriseSsoLimit: 'enterprise_sso.description', + resourcesLimit: 'api_resources.description', + machineToMachineLimit: 'machine_to_machine.description', + tenantMembersLimit: 'tenant_members.description', + tokenLimit: 'tokens.description', + hooksLimit: 'hooks.description', +}; + +export const titleKeyMap: Record< + keyof UsageKey, + TFuncKey<'translation', 'admin_console.subscription.usage'> +> = { + mauLimit: 'mau.title', + organizationsEnabled: 'organizations.title', + mfaEnabled: 'mfa.title', + enterpriseSsoLimit: 'enterprise_sso.title', + resourcesLimit: 'api_resources.title', + machineToMachineLimit: 'machine_to_machine.title', + tenantMembersLimit: 'tenant_members.title', + tokenLimit: 'tokens.title', + hooksLimit: 'hooks.title', +}; + +export const tooltipKeyMap: Record< + keyof UsageKey, + TFuncKey<'translation', 'admin_console.subscription.usage'> +> = { + mauLimit: 'mau.tooltip', + organizationsEnabled: 'organizations.tooltip', + mfaEnabled: 'mfa.tooltip', + enterpriseSsoLimit: 'enterprise_sso.tooltip', + resourcesLimit: 'api_resources.tooltip', + machineToMachineLimit: 'machine_to_machine.tooltip', + tenantMembersLimit: 'tenant_members.tooltip', + tokenLimit: 'tokens.tooltip', + hooksLimit: 'hooks.tooltip', +}; + +export const formatNumber = (number: number): string => { + return number.toString().replaceAll(/\B(?=(\d{3})+(?!\d))/g, ','); +}; diff --git a/packages/console/src/components/ProgressBar/index.tsx b/packages/console/src/components/ProgressBar/index.tsx index 25af66bc818..5977e5fc00e 100644 --- a/packages/console/src/components/ProgressBar/index.tsx +++ b/packages/console/src/components/ProgressBar/index.tsx @@ -1,6 +1,6 @@ import classNames from 'classnames'; -import * as styles from './index.module.scss'; +import styles from './index.module.scss'; type Props = { readonly currentStep: number; diff --git a/packages/console/src/components/QuotaGuardFooter/index.tsx b/packages/console/src/components/QuotaGuardFooter/index.tsx index c5d57f0ded6..ecd9408dc3a 100644 --- a/packages/console/src/components/QuotaGuardFooter/index.tsx +++ b/packages/console/src/components/QuotaGuardFooter/index.tsx @@ -3,7 +3,7 @@ import { type ReactNode } from 'react'; import Button from '@/ds-components/Button'; import useTenantPathname from '@/hooks/use-tenant-pathname'; -import * as styles from './index.module.scss'; +import styles from './index.module.scss'; type Props = { readonly children: ReactNode; diff --git a/packages/console/src/components/Region/index.tsx b/packages/console/src/components/Region/index.tsx index 9a50cb97ed2..ff4164aa88f 100644 --- a/packages/console/src/components/Region/index.tsx +++ b/packages/console/src/components/Region/index.tsx @@ -1,7 +1,7 @@ import classNames from 'classnames'; import { useTranslation } from 'react-i18next'; -import * as styles from './index.module.scss'; +import styles from './index.module.scss'; // TODO: This is a copy from `@logto/cloud-models`, make a SSoT for this later export enum RegionName { diff --git a/packages/console/src/components/RequestDataError/index.tsx b/packages/console/src/components/RequestDataError/index.tsx index daed530f2c5..b0134d6f37f 100644 --- a/packages/console/src/components/RequestDataError/index.tsx +++ b/packages/console/src/components/RequestDataError/index.tsx @@ -2,14 +2,14 @@ import { Theme } from '@logto/schemas'; import classNames from 'classnames'; import { useTranslation } from 'react-i18next'; -import RequestErrorDarkImage from '@/assets/images/request-error-dark.svg'; -import RequestErrorImage from '@/assets/images/request-error.svg'; +import RequestErrorDarkImage from '@/assets/images/request-error-dark.svg?react'; +import RequestErrorImage from '@/assets/images/request-error.svg?react'; import Button from '@/ds-components/Button'; import Card from '@/ds-components/Card'; import type { RequestError } from '@/hooks/use-api'; import useTheme from '@/hooks/use-theme'; -import * as styles from './index.module.scss'; +import styles from './index.module.scss'; type Props = { readonly error: RequestError; diff --git a/packages/console/src/components/RoleAssignmentModal/index.tsx b/packages/console/src/components/RoleAssignmentModal/index.tsx index cd2e9fed36b..baa1056ecfe 100644 --- a/packages/console/src/components/RoleAssignmentModal/index.tsx +++ b/packages/console/src/components/RoleAssignmentModal/index.tsx @@ -11,10 +11,10 @@ import DangerousRaw from '@/ds-components/DangerousRaw'; import ModalLayout from '@/ds-components/ModalLayout'; import TextLink from '@/ds-components/TextLink'; import useApi from '@/hooks/use-api'; -import * as modalStyles from '@/scss/modal.module.scss'; +import modalStyles from '@/scss/modal.module.scss'; import { getUserTitle } from '@/utils/user'; -import * as styles from './index.module.scss'; +import styles from './index.module.scss'; type Props = ( | { diff --git a/packages/console/src/components/RoleIcon/index.tsx b/packages/console/src/components/RoleIcon/index.tsx index 10914329113..878a790de51 100644 --- a/packages/console/src/components/RoleIcon/index.tsx +++ b/packages/console/src/components/RoleIcon/index.tsx @@ -1,8 +1,8 @@ import { Theme } from '@logto/schemas'; import { type ReactNode } from 'react'; -import UserRoleIconDark from '@/assets/icons/role-feature-dark.svg'; -import UserRoleIcon from '@/assets/icons/role-feature.svg'; +import UserRoleIconDark from '@/assets/icons/role-feature-dark.svg?react'; +import UserRoleIcon from '@/assets/icons/role-feature.svg?react'; import useTheme from '@/hooks/use-theme'; const themeToRoleIcon = Object.freeze({ diff --git a/packages/console/src/components/RoleScopesTransfer/components/ResourceItem/index.tsx b/packages/console/src/components/RoleScopesTransfer/components/ResourceItem/index.tsx index a0280753fbe..ee93f79ce1b 100644 --- a/packages/console/src/components/RoleScopesTransfer/components/ResourceItem/index.tsx +++ b/packages/console/src/components/RoleScopesTransfer/components/ResourceItem/index.tsx @@ -3,8 +3,8 @@ import classNames from 'classnames'; import { useState } from 'react'; import { useTranslation } from 'react-i18next'; -import CaretExpanded from '@/assets/icons/caret-expanded.svg'; -import CaretFolded from '@/assets/icons/caret-folded.svg'; +import CaretExpanded from '@/assets/icons/caret-expanded.svg?react'; +import CaretFolded from '@/assets/icons/caret-folded.svg?react'; import Checkbox from '@/ds-components/Checkbox'; import IconButton from '@/ds-components/IconButton'; import { onKeyDownHandler } from '@/utils/a11y'; @@ -12,7 +12,7 @@ import { onKeyDownHandler } from '@/utils/a11y'; import type { DetailedResourceResponse } from '../../types'; import SourceScopeItem from '../SourceScopeItem'; -import * as styles from './index.module.scss'; +import styles from './index.module.scss'; type Props = { readonly resource: DetailedResourceResponse; diff --git a/packages/console/src/components/RoleScopesTransfer/components/SourceScopeItem/index.tsx b/packages/console/src/components/RoleScopesTransfer/components/SourceScopeItem/index.tsx index 04f84802ae0..869b746a28a 100644 --- a/packages/console/src/components/RoleScopesTransfer/components/SourceScopeItem/index.tsx +++ b/packages/console/src/components/RoleScopesTransfer/components/SourceScopeItem/index.tsx @@ -3,7 +3,7 @@ import type { ScopeResponse } from '@logto/schemas'; import Checkbox from '@/ds-components/Checkbox'; import { onKeyDownHandler } from '@/utils/a11y'; -import * as styles from './index.module.scss'; +import styles from './index.module.scss'; type Props = { readonly scope: ScopeResponse; diff --git a/packages/console/src/components/RoleScopesTransfer/components/SourceScopesBox/index.tsx b/packages/console/src/components/RoleScopesTransfer/components/SourceScopesBox/index.tsx index a67684e135c..aea029d47b3 100644 --- a/packages/console/src/components/RoleScopesTransfer/components/SourceScopesBox/index.tsx +++ b/packages/console/src/components/RoleScopesTransfer/components/SourceScopesBox/index.tsx @@ -7,16 +7,16 @@ import { useMemo, useState } from 'react'; import { useTranslation } from 'react-i18next'; import useSWR from 'swr'; -import Search from '@/assets/icons/search.svg'; +import Search from '@/assets/icons/search.svg?react'; import EmptyDataPlaceholder from '@/components/EmptyDataPlaceholder'; import type { DetailedResourceResponse } from '@/components/RoleScopesTransfer/types'; import TextInput from '@/ds-components/TextInput'; import type { RequestError } from '@/hooks/use-api'; -import * as transferLayout from '@/scss/transfer.module.scss'; +import transferLayout from '@/scss/transfer.module.scss'; import ResourceItem from '../ResourceItem'; -import * as styles from './index.module.scss'; +import styles from './index.module.scss'; type Props = { readonly roleId?: string; diff --git a/packages/console/src/components/RoleScopesTransfer/components/TargetScopeItem/index.tsx b/packages/console/src/components/RoleScopesTransfer/components/TargetScopeItem/index.tsx index 65793d4f2f5..41fbec835aa 100644 --- a/packages/console/src/components/RoleScopesTransfer/components/TargetScopeItem/index.tsx +++ b/packages/console/src/components/RoleScopesTransfer/components/TargetScopeItem/index.tsx @@ -1,9 +1,9 @@ import type { ScopeResponse } from '@logto/schemas'; -import Close from '@/assets/icons/close.svg'; +import Close from '@/assets/icons/close.svg?react'; import IconButton from '@/ds-components/IconButton'; -import * as styles from './index.module.scss'; +import styles from './index.module.scss'; type Props = { readonly scope: ScopeResponse; diff --git a/packages/console/src/components/RoleScopesTransfer/components/TargetScopesBox/index.tsx b/packages/console/src/components/RoleScopesTransfer/components/TargetScopesBox/index.tsx index c7edebe2562..bc0319fdd90 100644 --- a/packages/console/src/components/RoleScopesTransfer/components/TargetScopesBox/index.tsx +++ b/packages/console/src/components/RoleScopesTransfer/components/TargetScopesBox/index.tsx @@ -1,11 +1,11 @@ import type { ScopeResponse } from '@logto/schemas'; import { useTranslation } from 'react-i18next'; -import * as transferLayout from '@/scss/transfer.module.scss'; +import transferLayout from '@/scss/transfer.module.scss'; import TargetScopeItem from '../TargetScopeItem'; -import * as styles from './index.module.scss'; +import styles from './index.module.scss'; type Props = { readonly selectedScopes: ScopeResponse[]; diff --git a/packages/console/src/components/RoleScopesTransfer/index.tsx b/packages/console/src/components/RoleScopesTransfer/index.tsx index 5baf6c1205e..ce1610c9e57 100644 --- a/packages/console/src/components/RoleScopesTransfer/index.tsx +++ b/packages/console/src/components/RoleScopesTransfer/index.tsx @@ -1,11 +1,11 @@ import type { ScopeResponse, RoleType } from '@logto/schemas'; import classNames from 'classnames'; -import * as transferLayout from '@/scss/transfer.module.scss'; +import transferLayout from '@/scss/transfer.module.scss'; import SourceScopesBox from './components/SourceScopesBox'; import TargetScopesBox from './components/TargetScopesBox'; -import * as styles from './index.module.scss'; +import styles from './index.module.scss'; /** * @deprecated Use `@/ds-component/DataTransferBox` instead. diff --git a/packages/console/src/components/RolesTransfer/SourceRolesBox/SourceRoleItem/index.tsx b/packages/console/src/components/RolesTransfer/SourceRolesBox/SourceRoleItem/index.tsx index c943633cc2e..9a128849bdf 100644 --- a/packages/console/src/components/RolesTransfer/SourceRolesBox/SourceRoleItem/index.tsx +++ b/packages/console/src/components/RolesTransfer/SourceRolesBox/SourceRoleItem/index.tsx @@ -5,7 +5,7 @@ import { onKeyDownHandler } from '@/utils/a11y'; import RoleInformation from '../../components/RoleInformation'; -import * as styles from './index.module.scss'; +import styles from './index.module.scss'; type Props = { readonly role: RoleResponse; diff --git a/packages/console/src/components/RolesTransfer/SourceRolesBox/index.tsx b/packages/console/src/components/RolesTransfer/SourceRolesBox/index.tsx index 1da49e842e6..ccc485c3764 100644 --- a/packages/console/src/components/RolesTransfer/SourceRolesBox/index.tsx +++ b/packages/console/src/components/RolesTransfer/SourceRolesBox/index.tsx @@ -7,18 +7,18 @@ import { useState } from 'react'; import { useTranslation } from 'react-i18next'; import useSWR from 'swr'; -import Search from '@/assets/icons/search.svg'; +import Search from '@/assets/icons/search.svg?react'; import EmptyDataPlaceholder from '@/components/EmptyDataPlaceholder'; import { defaultPageSize } from '@/consts'; import Pagination from '@/ds-components/Pagination'; import TextInput from '@/ds-components/TextInput'; import type { RequestError } from '@/hooks/use-api'; import useDebounce from '@/hooks/use-debounce'; -import * as transferLayout from '@/scss/transfer.module.scss'; +import transferLayout from '@/scss/transfer.module.scss'; import { buildUrl } from '@/utils/url'; import SourceRoleItem from './SourceRoleItem'; -import * as styles from './index.module.scss'; +import styles from './index.module.scss'; type Props = { readonly entityId: string; diff --git a/packages/console/src/components/RolesTransfer/TargetRolesBox/TargetRoleItem/index.tsx b/packages/console/src/components/RolesTransfer/TargetRolesBox/TargetRoleItem/index.tsx index af35c72caa1..ec1690c3e68 100644 --- a/packages/console/src/components/RolesTransfer/TargetRolesBox/TargetRoleItem/index.tsx +++ b/packages/console/src/components/RolesTransfer/TargetRolesBox/TargetRoleItem/index.tsx @@ -1,11 +1,11 @@ import { type RoleResponse } from '@logto/schemas'; -import Close from '@/assets/icons/close.svg'; +import Close from '@/assets/icons/close.svg?react'; import IconButton from '@/ds-components/IconButton'; import RoleInformation from '../../components/RoleInformation'; -import * as styles from './index.module.scss'; +import styles from './index.module.scss'; type Props = { readonly role: RoleResponse; diff --git a/packages/console/src/components/RolesTransfer/TargetRolesBox/index.tsx b/packages/console/src/components/RolesTransfer/TargetRolesBox/index.tsx index ea9bcc2e4ea..56c82584ca0 100644 --- a/packages/console/src/components/RolesTransfer/TargetRolesBox/index.tsx +++ b/packages/console/src/components/RolesTransfer/TargetRolesBox/index.tsx @@ -1,10 +1,10 @@ import type { RoleResponse } from '@logto/schemas'; import { useTranslation } from 'react-i18next'; -import * as transferLayout from '@/scss/transfer.module.scss'; +import transferLayout from '@/scss/transfer.module.scss'; import TargetRoleItem from './TargetRoleItem'; -import * as styles from './index.module.scss'; +import styles from './index.module.scss'; type Props = { readonly selectedRoles: RoleResponse[]; diff --git a/packages/console/src/components/RolesTransfer/components/RoleInformation/index.tsx b/packages/console/src/components/RolesTransfer/components/RoleInformation/index.tsx index 4602f85758d..93bd4751218 100644 --- a/packages/console/src/components/RolesTransfer/components/RoleInformation/index.tsx +++ b/packages/console/src/components/RolesTransfer/components/RoleInformation/index.tsx @@ -1,11 +1,11 @@ import { RoleType, type ScopeResponse, isManagementApi, type RoleResponse } from '@logto/schemas'; import useSWR from 'swr'; -import ManagementApiAccessFlag from '@/assets/icons/management-api-access.svg'; +import ManagementApiAccessFlag from '@/assets/icons/management-api-access.svg?react'; import DynamicT from '@/ds-components/DynamicT'; import { Tooltip } from '@/ds-components/Tip'; -import * as styles from './index.module.scss'; +import styles from './index.module.scss'; type Props = { readonly role: RoleResponse; diff --git a/packages/console/src/components/RolesTransfer/index.tsx b/packages/console/src/components/RolesTransfer/index.tsx index 152aa6fd41c..c642f628959 100644 --- a/packages/console/src/components/RolesTransfer/index.tsx +++ b/packages/console/src/components/RolesTransfer/index.tsx @@ -2,15 +2,15 @@ import { type RoleResponse, RoleType } from '@logto/schemas'; import classNames from 'classnames'; import { Trans, useTranslation } from 'react-i18next'; -import ManagementApiAccessFlag from '@/assets/icons/management-api-access.svg'; +import ManagementApiAccessFlag from '@/assets/icons/management-api-access.svg?react'; import FormField from '@/ds-components/FormField'; import InlineNotification from '@/ds-components/InlineNotification'; import useUserPreferences from '@/hooks/use-user-preferences'; -import * as transferLayout from '@/scss/transfer.module.scss'; +import transferLayout from '@/scss/transfer.module.scss'; import SourceRolesBox from './SourceRolesBox'; import TargetRolesBox from './TargetRolesBox'; -import * as styles from './index.module.scss'; +import styles from './index.module.scss'; type Props = { readonly entityId: string; diff --git a/packages/console/src/components/SignInExperiencePreview/components/ToggleUiThemeButton/index.tsx b/packages/console/src/components/SignInExperiencePreview/components/ToggleUiThemeButton/index.tsx index c0e9dbce37f..ffc859394e8 100644 --- a/packages/console/src/components/SignInExperiencePreview/components/ToggleUiThemeButton/index.tsx +++ b/packages/console/src/components/SignInExperiencePreview/components/ToggleUiThemeButton/index.tsx @@ -1,12 +1,12 @@ import { Theme } from '@logto/schemas'; import classNames from 'classnames'; -import Moon from '@/assets/icons/moon.svg'; -import Sun from '@/assets/icons/sun.svg'; +import Moon from '@/assets/icons/moon.svg?react'; +import Sun from '@/assets/icons/sun.svg?react'; import Button from '@/ds-components/Button'; import type { Props as ButtonProps } from '@/ds-components/Button'; -import * as styles from './index.module.scss'; +import styles from './index.module.scss'; type Props = { readonly value: Theme; diff --git a/packages/console/src/components/SignInExperiencePreview/index.module.scss b/packages/console/src/components/SignInExperiencePreview/index.module.scss index 7f945749665..c8d4d83a7ea 100644 --- a/packages/console/src/components/SignInExperiencePreview/index.module.scss +++ b/packages/console/src/components/SignInExperiencePreview/index.module.scss @@ -85,4 +85,28 @@ } } } + + &.disabled { + background: url('../../assets/images/blur-preview.svg') 0 0 / 100% auto no-repeat; + } + + .placeholder { + width: 100%; + height: calc(_screenSize.$web-height + _.unit(20)); + padding: _.unit(10); + backdrop-filter: blur(25px); + display: flex; + flex-direction: column; + color: var(--color-static-white); + + .title { + font: var(--font-label-2); + } + + .description { + margin-top: _.unit(1.5); + font: var(--font-body-2); + white-space: pre-wrap; + } + } } diff --git a/packages/console/src/components/SignInExperiencePreview/index.tsx b/packages/console/src/components/SignInExperiencePreview/index.tsx index ca0a61ac8a1..cf20714f359 100644 --- a/packages/console/src/components/SignInExperiencePreview/index.tsx +++ b/packages/console/src/components/SignInExperiencePreview/index.tsx @@ -4,16 +4,24 @@ import type { ConnectorMetadata, SignInExperience, ConnectorResponse } from '@lo import { conditional } from '@silverhand/essentials'; import classNames from 'classnames'; import { format } from 'date-fns'; -import { useContext, useRef, useMemo, useCallback, useEffect, useState } from 'react'; +import { + useContext, + useRef, + useMemo, + useCallback, + useEffect, + useState, + type ReactNode, +} from 'react'; import { useTranslation } from 'react-i18next'; import useSWR from 'swr'; -import PhoneInfo from '@/assets/images/phone-info.svg'; +import PhoneInfo from '@/assets/images/phone-info.svg?react'; import { AppDataContext } from '@/contexts/AppDataProvider'; import type { RequestError } from '@/hooks/use-api'; import useUiLanguages from '@/hooks/use-ui-languages'; -import * as styles from './index.module.scss'; +import styles from './index.module.scss'; import { PreviewPlatform } from './types'; export { default as ToggleUiThemeButton } from './components/ToggleUiThemeButton'; @@ -28,6 +36,16 @@ type Props = { * the `AppDataContext` will be used. */ readonly endpoint?: URL; + /** + * Whether the preview is disabled. If `true`, the preview will be disabled and a placeholder will + * be shown instead. Defaults to `false`. + */ + // eslint-disable-next-line react/boolean-prop-naming + readonly disabled?: boolean; + /** + * The placeholder to show when the preview is disabled. + */ + readonly disabledPlaceholder?: ReactNode; }; function SignInExperiencePreview({ @@ -36,6 +54,8 @@ function SignInExperiencePreview({ language = 'en', signInExperience, endpoint: endpointInput, + disabled = false, + disabledPlaceholder, }: Props) { const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' }); @@ -97,6 +117,10 @@ function SignInExperiencePreview({ }, []); useEffect(() => { + if (disabled) { + setIframeLoaded(false); + return; + } const iframe = previewRef.current; iframe?.addEventListener('load', iframeOnLoadEventHandler); @@ -104,7 +128,7 @@ function SignInExperiencePreview({ return () => { iframe?.removeEventListener('load', iframeOnLoadEventHandler); }; - }, [iframeLoaded, iframeOnLoadEventHandler]); + }, [iframeLoaded, disabled, iframeOnLoadEventHandler]); useEffect(() => { if (!iframeLoaded) { @@ -122,7 +146,8 @@ function SignInExperiencePreview({
-
-
- {platform !== PreviewPlatform.DesktopWeb && ( -
-
{format(Date.now(), 'HH:mm')}
- -
- )} -