diff --git a/package.json b/package.json index 289bc0e6a..d6c628b80 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,9 @@ "prepare": "if test \"$NODE_ENV\" != \"production\" && test \"$CI\" != \"true\" ; then husky install ; fi", "prepack": "pnpm -r prepack", "dev": "pnpm -r prepack && pnpm start:dev", - "start:dev": "pnpm -r --parallel --filter=!@logto/integration-tests dev", + "dev:cloud": "pnpm -r prepack && pnpm start:dev:cloud", + "start:dev": "pnpm -r --parallel --filter=!@logto/integration-tests --filter=!@logto/cloud dev", + "start:dev:cloud": "ADMIN_TENANT_ENDPOINT=http://localhost:3002 pnpm -r --parallel --filter=!@logto/integration-tests dev", "start": "cd packages/core && NODE_ENV=production node .", "cli": "logto", "alteration": "logto db alt", diff --git a/packages/cli/package.json b/packages/cli/package.json index c2272a7af..dc1783e0a 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -46,7 +46,7 @@ "@logto/core-kit": "workspace:*", "@logto/schemas": "workspace:*", "@logto/shared": "workspace:*", - "@silverhand/essentials": "2.1.0", + "@silverhand/essentials": "2.2.0", "chalk": "^5.0.0", "decamelize": "^6.0.0", "dotenv": "^16.0.0", diff --git a/packages/cloud/nodemon.json b/packages/cloud/nodemon.json new file mode 100644 index 000000000..4a7654bd3 --- /dev/null +++ b/packages/cloud/nodemon.json @@ -0,0 +1,14 @@ +{ + "exec": "tsc -p tsconfig.build.json --incremental && node ./build/index.js || exit 1", + "ignore": [ + "node_modules/**/node_modules", + "../integration-tests/" + ], + "watch": [ + "./src/", + "./node_modules/", + "../../.env" + ], + "ext": "json,js,jsx,ts,tsx", + "delay": 500 +} diff --git a/packages/cloud/package.json b/packages/cloud/package.json new file mode 100644 index 000000000..8c2e56e93 --- /dev/null +++ b/packages/cloud/package.json @@ -0,0 +1,46 @@ +{ + "name": "@logto/cloud", + "version": "0.1.0", + "description": "☁️ Logto Cloud service.", + "main": "build/index.js", + "author": "Silverhand Inc. ", + "license": "Elastic-2.0", + "type": "module", + "private": true, + "imports": { + "#src/*": "./build/*" + }, + "scripts": { + "precommit": "lint-staged", + "build": "rm -rf build/ && tsc -p tsconfig.build.json", + "lint": "eslint --ext .ts src", + "lint:report": "pnpm lint --format json --output-file report.json", + "dev": "rm -rf build/ && nodemon" + }, + "dependencies": { + "@silverhand/essentials": "2.2.0", + "@withtyped/postgres": "^0.6.0", + "@withtyped/server": "^0.6.0", + "http-proxy": "^1.18.1", + "mime-types": "^2.1.35" + }, + "devDependencies": { + "@silverhand/eslint-config": "2.0.1", + "@silverhand/ts-config": "2.0.2", + "@types/http-proxy": "^1.17.9", + "@types/mime-types": "^2.1.1", + "@types/node": "^18.11.18", + "eslint": "^8.21.0", + "lint-staged": "^13.0.0", + "nodemon": "^2.0.19", + "prettier": "^2.8.1", + "typescript": "^4.9.4" + }, + "engines": { + "node": "^18.12.0" + }, + "eslintConfig": { + "extends": "@silverhand" + }, + "prettier": "@silverhand/eslint-config/.prettierrc" +} diff --git a/packages/cloud/src/index.ts b/packages/cloud/src/index.ts new file mode 100644 index 000000000..af3bbbe3a --- /dev/null +++ b/packages/cloud/src/index.ts @@ -0,0 +1,19 @@ +import createServer, { compose, withRequest } from '@withtyped/server'; + +import withHttpProxy from './middleware/with-http-proxy.js'; +import withSpa from './middleware/with-spa.js'; + +const isProduction = process.env.NODE_ENV === 'production'; + +const { listen } = createServer({ + port: 3003, + composer: compose(withRequest()).and( + isProduction + ? withSpa({ pathname: '/console', root: '../console/dist' }) + : withHttpProxy('/console', { target: 'http://localhost:5002', changeOrigin: true }) + ), +}); + +await listen((port) => { + console.log(`Logto cloud is running at http://localhost:${port}`); +}); diff --git a/packages/cloud/src/middleware/with-http-proxy.ts b/packages/cloud/src/middleware/with-http-proxy.ts new file mode 100644 index 000000000..744542563 --- /dev/null +++ b/packages/cloud/src/middleware/with-http-proxy.ts @@ -0,0 +1,41 @@ +import type { HttpContext, NextFunction, RequestContext } from '@withtyped/server'; +import type { ServerOptions } from 'http-proxy'; +import HttpProxy from 'http-proxy'; + +import { matchPathname } from '#src/utils/url.js'; + +const { createProxy } = HttpProxy; + +export default function withHttpProxy( + pathname: string, + options: ServerOptions +) { + const proxy = createProxy(options); + + return async ( + context: InputContext, + next: NextFunction, + { request, response }: HttpContext + ) => { + const { + request: { url }, + } = context; + + const matched = matchPathname(pathname, url.pathname); + + if (!matched) { + return next(context); + } + + await new Promise((resolve) => { + proxy.web(request, response, options); + proxy.on('proxyRes', (_, __, response) => { + response.on('end', resolve); + }); + }); + + return next({ ...context, status: 'ignore' }); + }; +} + +export type { ServerOptions } from 'http-proxy'; diff --git a/packages/cloud/src/middleware/with-spa.ts b/packages/cloud/src/middleware/with-spa.ts new file mode 100644 index 000000000..788f1bf1f --- /dev/null +++ b/packages/cloud/src/middleware/with-spa.ts @@ -0,0 +1,94 @@ +import { createReadStream } from 'node:fs'; +import fs from 'node:fs/promises'; +import path from 'node:path'; + +import { assert } from '@silverhand/essentials'; +import type { NextFunction, RequestContext } from '@withtyped/server'; +import mime from 'mime-types'; + +import { matchPathname } from '#src/utils/url.js'; + +export type WithSpaConfig = { + /** + * Browser cache max-age in seconds. + * @default 604_800 // 7 days + */ + maxAge?: number; + /** The root directory to serve files. */ + root: string; + /** + * The URL pathname to serve as root. + * @default '/' + */ + pathname?: string; + /** + * The path to file to serve when the given path cannot be found in the file system. + * @default 'index.html' + */ + indexPath?: string; +}; + +export default function withSpa({ + maxAge = 604_800, + root, + pathname: rootPathname = '/', + indexPath: index = 'index.html', +}: WithSpaConfig) { + assert(root, new Error('Root directory is required to serve files.')); + + return async (context: InputContext, next: NextFunction) => { + const { + headers, + request: { url }, + } = context; + + const pathname = matchPathname(rootPathname, url.pathname); + + if (!pathname) { + return next(context); + } + + const indexPath = path.resolve(root, index); + const requestPath = path.resolve(path.join(root, pathname)); + const isHidden = pathname.split('/').some((segment) => segment.startsWith('.')); + + // Intended + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing + const result = (!isHidden && (await tryStat(requestPath))) || (await tryStat(indexPath)); + + if (!result) { + return next({ ...context, status: 404 }); + } + + const [pathLike, stat] = result; + + return next({ + ...context, + headers: { + ...headers, + 'Content-Length': stat.size, + 'Content-Type': mime.lookup(pathLike), + 'Last-Modified': stat.mtime.toUTCString(), + 'Cache-Control': `max-age=${maxAge}`, + }, + stream: createReadStream(pathLike), + status: 200, + }); + }; +} + +const normalize = (pathLike: string) => { + const value = path.normalize(pathLike); + + return value.length > 1 && value.endsWith('/') ? value.slice(0, -1) : value; +}; + +const tryStat = async (pathLike: string) => { + try { + const stat = await fs.stat(pathLike); + + if (stat.isFile()) { + return [pathLike, stat] as const; + } + } catch {} +}; diff --git a/packages/cloud/src/utils/url.ts b/packages/cloud/src/utils/url.ts new file mode 100644 index 000000000..5fbb26998 --- /dev/null +++ b/packages/cloud/src/utils/url.ts @@ -0,0 +1,22 @@ +import path from 'node:path'; + +export const normalizePath = (pathLike: string) => { + const value = path.normalize(pathLike); + + return value.length > 1 && value.endsWith('/') ? value.slice(0, -1) : value; +}; + +export const matchPathname = (toMatch: string, pathname: string) => { + const toMatchPathname = normalizePath(toMatch); + const normalized = normalizePath(pathname); + + if (normalized === toMatchPathname) { + return '/'; + } + + if (normalized.startsWith(toMatchPathname + '/')) { + return normalized.slice(toMatchPathname.length); + } + + return false; +}; diff --git a/packages/cloud/tsconfig.build.json b/packages/cloud/tsconfig.build.json new file mode 100644 index 000000000..3d11574b3 --- /dev/null +++ b/packages/cloud/tsconfig.build.json @@ -0,0 +1,7 @@ +{ + "extends": "./tsconfig", + "exclude": [ + "src/**/*.test.ts", + "src/**/__mocks__/", + ] +} diff --git a/packages/cloud/tsconfig.json b/packages/cloud/tsconfig.json new file mode 100644 index 000000000..25c25afba --- /dev/null +++ b/packages/cloud/tsconfig.json @@ -0,0 +1,15 @@ +{ + "extends": "@silverhand/ts-config/tsconfig.base", + "compilerOptions": { + "types": ["node"], + "declaration": false, + "outDir": "build", + "baseUrl": ".", + "paths": { + "#src/*": [ + "src/*" + ] + } + }, + "include": ["src"] +} diff --git a/packages/console/package.json b/packages/console/package.json index 1c5d59318..dda0ef273 100644 --- a/packages/console/package.json +++ b/packages/console/package.json @@ -33,7 +33,7 @@ "@parcel/transformer-svg-react": "2.8.3", "@silverhand/eslint-config": "2.0.1", "@silverhand/eslint-config-react": "2.0.1", - "@silverhand/essentials": "2.1.0", + "@silverhand/essentials": "2.2.0", "@silverhand/ts-config": "2.0.3", "@silverhand/ts-config-react": "2.0.3", "@tsconfig/docusaurus": "^1.0.5", diff --git a/packages/core/package.json b/packages/core/package.json index cda4aaf0c..ee0b7b9ac 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -34,9 +34,9 @@ "@logto/phrases-ui": "workspace:*", "@logto/schemas": "workspace:*", "@logto/shared": "workspace:*", - "@silverhand/essentials": "2.1.0", - "@withtyped/postgres": "^0.5.1", - "@withtyped/server": "^0.5.1", + "@silverhand/essentials": "2.2.0", + "@withtyped/postgres": "^0.6.0", + "@withtyped/server": "^0.6.0", "chalk": "^5.0.0", "clean-deep": "^3.4.0", "date-fns": "^2.29.3", diff --git a/packages/core/src/env-set/GlobalValues.ts b/packages/core/src/env-set/GlobalValues.ts index 06ef9439a..38c2a394d 100644 --- a/packages/core/src/env-set/GlobalValues.ts +++ b/packages/core/src/env-set/GlobalValues.ts @@ -16,6 +16,7 @@ export default class GlobalValues { public readonly urlSet = new UrlSet(this.isHttpsEnabled, 3001); public readonly adminUrlSet = new UrlSet(this.isHttpsEnabled, 3002, 'ADMIN_'); + public readonly cloudUrlSet = new UrlSet(this.isHttpsEnabled, 3003, 'CLOUD_'); public readonly isDomainBasedMultiTenancy = this.urlSet.endpoint.hostname.includes('*'); diff --git a/packages/core/src/middleware/koa-cors.ts b/packages/core/src/middleware/koa-cors.ts new file mode 100644 index 000000000..a05fff924 --- /dev/null +++ b/packages/core/src/middleware/koa-cors.ts @@ -0,0 +1,22 @@ +import cors from '@koa/cors'; +import type { MiddlewareType } from 'koa'; + +import type UrlSet from '#src/env-set/UrlSet.js'; + +export default function koaCors( + ...urlSets: UrlSet[] +): MiddlewareType { + return cors({ + origin: (ctx) => { + const { origin } = ctx.request.headers; + + return origin && + urlSets + .flatMap((set) => set.deduplicated()) + .some((value) => new URL(value).origin === origin) + ? origin + : ''; + }, + exposeHeaders: '*', + }); +} diff --git a/packages/core/src/oidc/adapter.ts b/packages/core/src/oidc/adapter.ts index 5e308c20a..df9b28744 100644 --- a/packages/core/src/oidc/adapter.ts +++ b/packages/core/src/oidc/adapter.ts @@ -14,8 +14,10 @@ import { appendPath } from '#src/utils/url.js'; import { getConstantClientMetadata } from './utils.js'; const buildAdminConsoleClientMetadata = (envSet: EnvSet): AllClientMetadata => { - const { adminUrlSet } = EnvSet.values; - const urls = adminUrlSet.deduplicated().map((url) => appendPath(url, '/console').toString()); + const { adminUrlSet, cloudUrlSet } = EnvSet.values; + const urls = [...adminUrlSet.deduplicated(), ...cloudUrlSet.deduplicated()].map((url) => + appendPath(url, '/console').toString() + ); return { ...getConstantClientMetadata(envSet, ApplicationType.SPA), diff --git a/packages/core/src/routes-me/init.ts b/packages/core/src/routes-me/init.ts index a20b00e38..3bb0529c0 100644 --- a/packages/core/src/routes-me/init.ts +++ b/packages/core/src/routes-me/init.ts @@ -6,9 +6,11 @@ import { import Koa from 'koa'; import Router from 'koa-router'; +import { EnvSet } from '#src/env-set/index.js'; import RequestError from '#src/errors/RequestError/index.js'; import type { WithAuthContext } from '#src/middleware/koa-auth/index.js'; import koaAuth from '#src/middleware/koa-auth/index.js'; +import koaCors from '#src/middleware/koa-cors.js'; import koaGuard from '#src/middleware/koa-guard.js'; import type TenantContext from '#src/tenants/TenantContext.js'; import assertThat from '#src/utils/assert-that.js'; @@ -65,6 +67,7 @@ export default function initMeApis(tenant: TenantContext): Koa { ); const meApp = new Koa(); + meApp.use(koaCors(EnvSet.values.cloudUrlSet)); meApp.use(meRouter.routes()).use(meRouter.allowedMethods()); return meApp; diff --git a/packages/core/src/routes/init.ts b/packages/core/src/routes/init.ts index 029296fc9..e2b7c7a74 100644 --- a/packages/core/src/routes/init.ts +++ b/packages/core/src/routes/init.ts @@ -1,9 +1,9 @@ -import cors from '@koa/cors'; import { getManagementApiResourceIndicator } from '@logto/schemas'; import Koa from 'koa'; import Router from 'koa-router'; import { EnvSet } from '#src/env-set/index.js'; +import koaCors from '#src/middleware/koa-cors.js'; import type TenantContext from '#src/tenants/TenantContext.js'; import koaAuth from '../middleware/koa-auth/index.js'; @@ -64,19 +64,8 @@ const createRouters = (tenant: TenantContext) => { export default function initApis(tenant: TenantContext): Koa { const apisApp = new Koa(); - apisApp.use( - cors({ - origin: (ctx) => { - const { origin } = ctx.request.headers; - - return origin && - EnvSet.values.adminUrlSet.deduplicated().some((value) => new URL(value).origin === origin) - ? origin - : ''; - }, - exposeHeaders: '*', - }) - ); + const { adminUrlSet, cloudUrlSet } = EnvSet.values; + apisApp.use(koaCors(adminUrlSet, cloudUrlSet)); for (const router of createRouters(tenant)) { apisApp.use(router.routes()).use(router.allowedMethods()); diff --git a/packages/integration-tests/package.json b/packages/integration-tests/package.json index 047523e9d..61d97360f 100644 --- a/packages/integration-tests/package.json +++ b/packages/integration-tests/package.json @@ -27,7 +27,7 @@ "@logto/schemas": "workspace:*", "@peculiar/webcrypto": "^1.3.3", "@silverhand/eslint-config": "2.0.1", - "@silverhand/essentials": "2.1.0", + "@silverhand/essentials": "2.2.0", "@silverhand/ts-config": "2.0.3", "@types/jest": "^29.1.2", "@types/jest-environment-puppeteer": "^5.0.2", @@ -53,6 +53,6 @@ }, "prettier": "@silverhand/eslint-config/.prettierrc", "dependencies": { - "@withtyped/server": "^0.5.1" + "@withtyped/server": "^0.6.0" } } diff --git a/packages/phrases-ui/package.json b/packages/phrases-ui/package.json index 836455195..62d66001e 100644 --- a/packages/phrases-ui/package.json +++ b/packages/phrases-ui/package.json @@ -35,7 +35,7 @@ "dependencies": { "@logto/core-kit": "workspace:*", "@logto/language-kit": "workspace:*", - "@silverhand/essentials": "2.1.0", + "@silverhand/essentials": "2.2.0", "zod": "^3.20.2" }, "devDependencies": { diff --git a/packages/phrases/package.json b/packages/phrases/package.json index afebaa4c9..1c662e9c0 100644 --- a/packages/phrases/package.json +++ b/packages/phrases/package.json @@ -35,7 +35,7 @@ "dependencies": { "@logto/core-kit": "workspace:*", "@logto/language-kit": "workspace:*", - "@silverhand/essentials": "2.1.0", + "@silverhand/essentials": "2.2.0", "zod": "^3.20.2" }, "devDependencies": { diff --git a/packages/schemas/package.json b/packages/schemas/package.json index 4ed290167..82c2d9ef2 100644 --- a/packages/schemas/package.json +++ b/packages/schemas/package.json @@ -41,7 +41,7 @@ }, "devDependencies": { "@silverhand/eslint-config": "2.0.1", - "@silverhand/essentials": "2.1.0", + "@silverhand/essentials": "2.2.0", "@silverhand/ts-config": "2.0.3", "@types/inquirer": "^9.0.0", "@types/jest": "^29.1.2", @@ -84,7 +84,7 @@ "@logto/language-kit": "workspace:*", "@logto/phrases": "workspace:*", "@logto/phrases-ui": "workspace:*", - "@withtyped/server": "^0.5.1", + "@withtyped/server": "^0.6.0", "zod": "^3.20.2" } } diff --git a/packages/shared/package.json b/packages/shared/package.json index 4d5e3e947..5fe410e7a 100644 --- a/packages/shared/package.json +++ b/packages/shared/package.json @@ -56,7 +56,7 @@ "prettier": "@silverhand/eslint-config/.prettierrc", "dependencies": { "@logto/schemas": "workspace:*", - "@silverhand/essentials": "2.1.0", + "@silverhand/essentials": "2.2.0", "find-up": "^6.3.0", "nanoid": "^4.0.0", "slonik": "^30.0.0" diff --git a/packages/toolkit/core-kit/package.json b/packages/toolkit/core-kit/package.json index b11dd0e3d..c62f28841 100644 --- a/packages/toolkit/core-kit/package.json +++ b/packages/toolkit/core-kit/package.json @@ -50,7 +50,7 @@ "@jest/types": "^29.0.3", "@silverhand/eslint-config": "2.0.1", "@silverhand/eslint-config-react": "2.0.1", - "@silverhand/essentials": "2.1.0", + "@silverhand/essentials": "2.2.0", "@silverhand/ts-config": "2.0.3", "@types/color": "^3.0.3", "@types/jest": "^29.0.3", diff --git a/packages/ui/package.json b/packages/ui/package.json index 5f611af06..47be3da05 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -30,7 +30,7 @@ "@react-spring/web": "^9.6.1", "@silverhand/eslint-config": "2.0.1", "@silverhand/eslint-config-react": "2.0.1", - "@silverhand/essentials": "2.1.0", + "@silverhand/essentials": "2.2.0", "@silverhand/jest-config": "1.2.2", "@silverhand/ts-config": "2.0.3", "@silverhand/ts-config-react": "2.0.3", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 53f7ea97b..f9a4883bd 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -31,7 +31,7 @@ importers: '@logto/schemas': workspace:* '@logto/shared': workspace:* '@silverhand/eslint-config': 2.0.1 - '@silverhand/essentials': 2.1.0 + '@silverhand/essentials': 2.2.0 '@silverhand/ts-config': 2.0.3 '@types/inquirer': ^9.0.0 '@types/jest': ^29.1.2 @@ -68,7 +68,7 @@ importers: '@logto/core-kit': link:../toolkit/core-kit '@logto/schemas': link:../schemas '@logto/shared': link:../shared - '@silverhand/essentials': 2.1.0 + '@silverhand/essentials': 2.2.0 chalk: 5.1.2 decamelize: 6.0.0 dotenv: 16.0.0 @@ -104,6 +104,41 @@ importers: sinon: 15.0.0 typescript: 4.9.4 + packages/cloud: + specifiers: + '@silverhand/eslint-config': 2.0.1 + '@silverhand/essentials': 2.2.0 + '@silverhand/ts-config': 2.0.2 + '@types/http-proxy': ^1.17.9 + '@types/mime-types': ^2.1.1 + '@types/node': ^18.11.18 + '@withtyped/postgres': ^0.6.0 + '@withtyped/server': ^0.6.0 + eslint: ^8.21.0 + http-proxy: ^1.18.1 + lint-staged: ^13.0.0 + mime-types: ^2.1.35 + nodemon: ^2.0.19 + prettier: ^2.8.1 + typescript: ^4.9.4 + dependencies: + '@silverhand/essentials': 2.2.0 + '@withtyped/postgres': 0.6.0_@withtyped+server@0.6.0 + '@withtyped/server': 0.6.0 + http-proxy: 1.18.1 + mime-types: 2.1.35 + devDependencies: + '@silverhand/eslint-config': 2.0.1_kjzxg5porcw5dx54sezsklj5cy + '@silverhand/ts-config': 2.0.2_typescript@4.9.4 + '@types/http-proxy': 1.17.9 + '@types/mime-types': 2.1.1 + '@types/node': 18.11.18 + eslint: 8.34.0 + lint-staged: 13.0.0 + nodemon: 2.0.19 + prettier: 2.8.4 + typescript: 4.9.4 + packages/console: specifiers: '@fontsource/roboto-mono': ^4.5.7 @@ -121,7 +156,7 @@ importers: '@parcel/transformer-svg-react': 2.8.3 '@silverhand/eslint-config': 2.0.1 '@silverhand/eslint-config-react': 2.0.1 - '@silverhand/essentials': 2.1.0 + '@silverhand/essentials': 2.2.0 '@silverhand/ts-config': 2.0.3 '@silverhand/ts-config-react': 2.0.3 '@tsconfig/docusaurus': ^1.0.5 @@ -194,7 +229,7 @@ importers: '@parcel/transformer-svg-react': 2.8.3_@parcel+core@2.8.3 '@silverhand/eslint-config': 2.0.1_kjzxg5porcw5dx54sezsklj5cy '@silverhand/eslint-config-react': 2.0.1_kz2ighe3mj4zdkvq5whtl3dq4u - '@silverhand/essentials': 2.1.0 + '@silverhand/essentials': 2.2.0 '@silverhand/ts-config': 2.0.3_typescript@4.9.4 '@silverhand/ts-config-react': 2.0.3_typescript@4.9.4 '@tsconfig/docusaurus': 1.0.5 @@ -264,7 +299,7 @@ importers: '@logto/schemas': workspace:* '@logto/shared': workspace:* '@silverhand/eslint-config': 2.0.1 - '@silverhand/essentials': 2.1.0 + '@silverhand/essentials': 2.2.0 '@silverhand/ts-config': 2.0.3 '@types/debug': ^4.1.7 '@types/etag': ^1.8.1 @@ -282,8 +317,8 @@ importers: '@types/semver': ^7.3.12 '@types/sinon': ^10.0.13 '@types/supertest': ^2.0.11 - '@withtyped/postgres': ^0.5.1 - '@withtyped/server': ^0.5.1 + '@withtyped/postgres': ^0.6.0 + '@withtyped/server': ^0.6.0 chalk: ^5.0.0 clean-deep: ^3.4.0 copyfiles: ^2.4.1 @@ -341,9 +376,9 @@ importers: '@logto/phrases-ui': link:../phrases-ui '@logto/schemas': link:../schemas '@logto/shared': link:../shared - '@silverhand/essentials': 2.1.0 - '@withtyped/postgres': 0.5.1_@withtyped+server@0.5.1 - '@withtyped/server': 0.5.1 + '@silverhand/essentials': 2.2.0 + '@withtyped/postgres': 0.6.0_@withtyped+server@0.6.0 + '@withtyped/server': 0.6.0 chalk: 5.1.2 clean-deep: 3.4.0 date-fns: 2.29.3 @@ -486,12 +521,12 @@ importers: '@logto/schemas': workspace:* '@peculiar/webcrypto': ^1.3.3 '@silverhand/eslint-config': 2.0.1 - '@silverhand/essentials': 2.1.0 + '@silverhand/essentials': 2.2.0 '@silverhand/ts-config': 2.0.3 '@types/jest': ^29.1.2 '@types/jest-environment-puppeteer': ^5.0.2 '@types/node': ^18.11.18 - '@withtyped/server': ^0.5.1 + '@withtyped/server': ^0.6.0 dotenv: ^16.0.0 eslint: ^8.34.0 got: ^12.5.3 @@ -505,7 +540,7 @@ importers: text-encoder: ^0.0.4 typescript: ^4.9.4 dependencies: - '@withtyped/server': 0.5.1 + '@withtyped/server': 0.6.0 devDependencies: '@jest/types': 29.1.2 '@logto/connector-kit': link:../toolkit/connector-kit @@ -514,7 +549,7 @@ importers: '@logto/schemas': link:../schemas '@peculiar/webcrypto': 1.3.3 '@silverhand/eslint-config': 2.0.1_kjzxg5porcw5dx54sezsklj5cy - '@silverhand/essentials': 2.1.0 + '@silverhand/essentials': 2.2.0 '@silverhand/ts-config': 2.0.3_typescript@4.9.4 '@types/jest': 29.1.2 '@types/jest-environment-puppeteer': 5.0.2 @@ -537,7 +572,7 @@ importers: '@logto/core-kit': workspace:* '@logto/language-kit': workspace:* '@silverhand/eslint-config': 2.0.1 - '@silverhand/essentials': 2.1.0 + '@silverhand/essentials': 2.2.0 '@silverhand/ts-config': 2.0.3 eslint: ^8.34.0 lint-staged: ^13.0.0 @@ -547,7 +582,7 @@ importers: dependencies: '@logto/core-kit': link:../toolkit/core-kit '@logto/language-kit': link:../toolkit/language-kit - '@silverhand/essentials': 2.1.0 + '@silverhand/essentials': 2.2.0 zod: 3.20.2 devDependencies: '@silverhand/eslint-config': 2.0.1_kjzxg5porcw5dx54sezsklj5cy @@ -562,7 +597,7 @@ importers: '@logto/core-kit': workspace:* '@logto/language-kit': workspace:* '@silverhand/eslint-config': 2.0.1 - '@silverhand/essentials': 2.1.0 + '@silverhand/essentials': 2.2.0 '@silverhand/ts-config': 2.0.3 buffer: ^5.7.1 eslint: ^8.34.0 @@ -573,7 +608,7 @@ importers: dependencies: '@logto/core-kit': link:../toolkit/core-kit '@logto/language-kit': link:../toolkit/language-kit - '@silverhand/essentials': 2.1.0 + '@silverhand/essentials': 2.2.0 zod: 3.20.2 devDependencies: '@silverhand/eslint-config': 2.0.1_kjzxg5porcw5dx54sezsklj5cy @@ -592,13 +627,13 @@ importers: '@logto/phrases': workspace:* '@logto/phrases-ui': workspace:* '@silverhand/eslint-config': 2.0.1 - '@silverhand/essentials': 2.1.0 + '@silverhand/essentials': 2.2.0 '@silverhand/ts-config': 2.0.3 '@types/inquirer': ^9.0.0 '@types/jest': ^29.1.2 '@types/node': ^18.11.18 '@types/pluralize': ^0.0.29 - '@withtyped/server': ^0.5.1 + '@withtyped/server': ^0.6.0 camelcase: ^7.0.0 eslint: ^8.34.0 jest: ^29.1.2 @@ -616,11 +651,11 @@ importers: '@logto/language-kit': link:../toolkit/language-kit '@logto/phrases': link:../phrases '@logto/phrases-ui': link:../phrases-ui - '@withtyped/server': 0.5.1 + '@withtyped/server': 0.6.0 zod: 3.20.2 devDependencies: '@silverhand/eslint-config': 2.0.1_kjzxg5porcw5dx54sezsklj5cy - '@silverhand/essentials': 2.1.0 + '@silverhand/essentials': 2.2.0 '@silverhand/ts-config': 2.0.3_typescript@4.9.4 '@types/inquirer': 9.0.3 '@types/jest': 29.1.2 @@ -643,7 +678,7 @@ importers: '@logto/core-kit': workspace:* '@logto/schemas': workspace:* '@silverhand/eslint-config': 2.0.1 - '@silverhand/essentials': 2.1.0 + '@silverhand/essentials': 2.2.0 '@silverhand/ts-config': 2.0.3 '@types/jest': ^29.1.2 '@types/node': ^18.11.18 @@ -657,7 +692,7 @@ importers: typescript: ^4.9.4 dependencies: '@logto/schemas': link:../schemas - '@silverhand/essentials': 2.1.0 + '@silverhand/essentials': 2.2.0 find-up: 6.3.0 nanoid: 4.0.0 slonik: 30.1.2 @@ -710,7 +745,7 @@ importers: '@logto/language-kit': workspace:* '@silverhand/eslint-config': 2.0.1 '@silverhand/eslint-config-react': 2.0.1 - '@silverhand/essentials': 2.1.0 + '@silverhand/essentials': 2.2.0 '@silverhand/ts-config': 2.0.3 '@types/color': ^3.0.3 '@types/jest': ^29.0.3 @@ -737,7 +772,7 @@ importers: '@jest/types': 29.3.1 '@silverhand/eslint-config': 2.0.1_kjzxg5porcw5dx54sezsklj5cy '@silverhand/eslint-config-react': 2.0.1_wfldc7mlde5bb3fdzap5arn6me - '@silverhand/essentials': 2.1.0 + '@silverhand/essentials': 2.2.0 '@silverhand/ts-config': 2.0.3_typescript@4.9.4 '@types/color': 3.0.3 '@types/jest': 29.1.2 @@ -796,7 +831,7 @@ importers: '@react-spring/web': ^9.6.1 '@silverhand/eslint-config': 2.0.1 '@silverhand/eslint-config-react': 2.0.1 - '@silverhand/essentials': 2.1.0 + '@silverhand/essentials': 2.2.0 '@silverhand/jest-config': 1.2.2 '@silverhand/ts-config': 2.0.3 '@silverhand/ts-config-react': 2.0.3 @@ -853,7 +888,7 @@ importers: '@react-spring/web': 9.6.1_biqbaboplfbrettd7655fr4n2y '@silverhand/eslint-config': 2.0.1_kjzxg5porcw5dx54sezsklj5cy '@silverhand/eslint-config-react': 2.0.1_kz2ighe3mj4zdkvq5whtl3dq4u - '@silverhand/essentials': 2.1.0 + '@silverhand/essentials': 2.2.0 '@silverhand/jest-config': 1.2.2_ky6c64xxalg2hsll4xx3evq2dy '@silverhand/ts-config': 2.0.3_typescript@4.9.4 '@silverhand/ts-config-react': 2.0.3_typescript@4.9.4 @@ -3582,6 +3617,11 @@ packages: /@silverhand/essentials/2.1.0: resolution: {integrity: sha512-1/f+FZ+9+fq0GSueTp+8+7dY7SuXGc0b+k6Bsuod7HqMAZdJr42TUy6lphriThshiaAC/I9ZhXyKkphTkHfa9Q==} engines: {node: ^16.13.0 || ^18.12.0 || ^19.2.0, pnpm: ^7} + dev: false + + /@silverhand/essentials/2.2.0: + resolution: {integrity: sha512-xoj/wAnPUt9ZAzt7QCHhSKZPweZnNJU7tBYrDTf54db6L+++SiXYIyckKDY+vKkGACn9kTAWPF74qSfYt1OQtA==} + engines: {node: ^16.13.0 || ^18.12.0 || ^19.2.0, pnpm: ^7} /@silverhand/jest-config/1.2.2_ky6c64xxalg2hsll4xx3evq2dy: resolution: {integrity: sha512-sCOIHN3kIG9nyySkDao8nz6HK8VhGoUV4WG1CCriDDeGTqbHs4IprzTp1p+ChFdC8JGBCElQC0cIFrWYTFnTAQ==} @@ -3613,6 +3653,15 @@ packages: typescript: 4.9.4 dev: true + /@silverhand/ts-config/2.0.2_typescript@4.9.4: + resolution: {integrity: sha512-F1Xwlu9w9CMNwKQgRE0HzVSAa4oqMMjl7W6iXCJ74wyKBgP5BDQs5GtklTlhlR9YyYGOfXqRnlTgfXIcjePg0A==} + engines: {node: ^18.12.0} + peerDependencies: + typescript: ^4.9.4 + dependencies: + typescript: 4.9.4 + dev: true + /@silverhand/ts-config/2.0.3_typescript@4.9.4: resolution: {integrity: sha512-98m+7b2gUIkV5AgpwiMRbnYjclkZYGZnNrLioTtvYtKWz3TZZ6EFTVPK1isSrCwSUuYzx38+QNSVi89t4G1IDA==} engines: {node: ^18.12.0} @@ -4044,6 +4093,12 @@ packages: resolution: {integrity: sha512-EqX+YQxINb+MeXaIqYDASb6U6FCHbWjkj4a1CKDBks3d/QiB2+PqBLyO72vLDgAO1wUI4O+9gweRcQK11bTL/w==} dev: true + /@types/http-proxy/1.17.9: + resolution: {integrity: sha512-QsbSjA/fSk7xB+UXlCT3wHBy5ai9wOcNDWwZAtud+jXhwOM3l+EYZh8Lng4+/6n8uar0J7xILzqftJdJ/Wdfkw==} + dependencies: + '@types/node': 18.11.18 + dev: true + /@types/inquirer/9.0.3: resolution: {integrity: sha512-CzNkWqQftcmk2jaCWdBTf9Sm7xSw4rkI1zpU/Udw3HX5//adEZUIm9STtoRP1qgWj0CWQtJ9UTvqmO2NNjhMJw==} dependencies: @@ -4175,6 +4230,10 @@ packages: resolution: {integrity: sha512-JPEv4iAl0I+o7g8yVWDwk30es8mfVrjkvh5UeVR2sYPpZCK44vrAPsbJpIS+rJAUxLgaSAMKTEH5Vn5qd9XsrQ==} dev: true + /@types/mime-types/2.1.1: + resolution: {integrity: sha512-vXOTGVSLR2jMw440moWTC7H19iUyLtP3Z1YTj7cSsubOICinjMxFeb/V57v9QdyyPGbbWolUFSSmSiRSn94tFw==} + dev: true + /@types/mime/1.3.2: resolution: {integrity: sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==} dev: true @@ -4519,21 +4578,21 @@ packages: eslint-visitor-keys: 3.3.0 dev: true - /@withtyped/postgres/0.5.1_@withtyped+server@0.5.1: - resolution: {integrity: sha512-Le4iIHEc4LRgDn4rjnwbGJ/J15PpqEoltgoZAOhYgnZznKBzkp4W3vxbav29x7IMOvzgum+Jo5HOW1q0kRfROg==} + /@withtyped/postgres/0.6.0_@withtyped+server@0.6.0: + resolution: {integrity: sha512-Mq4/beT7vqtaxbNeFpP2mananch9OauwbQdvNR8YVaoolgPycxGuTB0LvnsLa4/7r4KQORQJcCxj+fckqkOFwA==} peerDependencies: - '@withtyped/server': ^0.5.1 + '@withtyped/server': ^0.6.0 dependencies: '@types/pg': 8.6.6 - '@withtyped/server': 0.5.1 + '@withtyped/server': 0.6.0 '@withtyped/shared': 0.2.0 pg: 8.8.0 transitivePeerDependencies: - pg-native dev: false - /@withtyped/server/0.5.1: - resolution: {integrity: sha512-CR7Y4R2YsUNJ7STEzhJjBjCKIJg49r2Jun5tFuTmmH8IAdHacisWPuKyGMz8o8jnatGTBRJNvc2wjjhg0l8ptw==} + /@withtyped/server/0.6.0: + resolution: {integrity: sha512-p4rlk2EIq1zjQnwDe6cDNGl3VYJQL+sSxgoCfn9wqinExQ1ReegwujOBXaBuk/LQZ0HtSqDV0ayIE/NB8AQZew==} dependencies: '@withtyped/shared': 0.2.0 dev: false @@ -5522,7 +5581,7 @@ packages: dev: true /concat-map/0.0.1: - resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + resolution: {integrity: sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=} /concat-stream/2.0.0: resolution: {integrity: sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==} @@ -7176,16 +7235,6 @@ packages: resolution: {integrity: sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg==} dev: true - /follow-redirects/1.14.6: - resolution: {integrity: sha512-fhUl5EwSJbbl8AR+uYL2KQDxLkdSjZGR36xy46AO7cOMTrCMON6Sa28FmAnC2tRTDbd/Uuzz3aJBv7EBN7JH8A==} - engines: {node: '>=4.0'} - peerDependencies: - debug: '*' - peerDependenciesMeta: - debug: - optional: true - dev: false - /follow-redirects/1.15.1: resolution: {integrity: sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA==} engines: {node: '>=4.0'} @@ -7194,7 +7243,6 @@ packages: peerDependenciesMeta: debug: optional: true - dev: true /for-in/0.1.8: resolution: {integrity: sha512-F0to7vbBSHP8E3l6dCjxNOLuSFAACIxFy3UehTUlG7svlXi37HHsDkyVcHo0Pq8QwrE+pXvWSVX3ZT1T9wAZ9g==} @@ -7902,7 +7950,7 @@ packages: engines: {node: '>=8.0.0'} dependencies: eventemitter3: 4.0.7 - follow-redirects: 1.14.6 + follow-redirects: 1.15.1 requires-port: 1.0.0 transitivePeerDependencies: - debug @@ -12956,7 +13004,7 @@ packages: resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} hasBin: true dependencies: - glob: 7.2.0 + glob: 7.2.3 dev: true /roarr/2.15.4: