0
Fork 0
mirror of https://github.com/logto-io/logto.git synced 2024-12-30 20:33:54 -05:00

Merge pull request #3138 from logto-io/gao-init-cloud

feat: init cloud
This commit is contained in:
Gao Sun 2023-02-20 12:48:17 +08:00 committed by GitHub
commit f3a8dfc947
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
26 changed files with 421 additions and 80 deletions

View file

@ -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": "pnpm -r --parallel --filter=!@logto/integration-tests dev",
"start": "cd packages/core && NODE_ENV=production node .",
"cli": "logto",
"alteration": "logto db alt",

View file

@ -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",

View file

@ -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
}

View file

@ -0,0 +1,49 @@
{
"name": "@logto/cloud",
"version": "0.1.0",
"description": "☁️ Logto Cloud service.",
"main": "build/index.js",
"author": "Silverhand Inc. <contact@silverhand.io>",
"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",
"start": "NODE_ENV=production node build/index.js"
},
"dependencies": {
"@logto/shared": "workspace:*",
"@silverhand/essentials": "2.2.0",
"@withtyped/postgres": "^0.6.0",
"@withtyped/server": "^0.6.0",
"chalk": "^5.0.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"
}

View file

@ -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}`);
});

View file

@ -0,0 +1,47 @@
import type { HttpContext, NextFunction, RequestContext } from '@withtyped/server';
import chalk from 'chalk';
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<InputContext extends RequestContext>(
pathname: string,
options: ServerOptions
) {
const proxy = createProxy(options);
proxy.on('start', (request, __, target) => {
console.log(
`\t${chalk.italic(chalk.gray('proxy ->'))}`,
new URL(request.url ?? '/', typeof target === 'object' ? target.href : target).toString()
);
});
return async (
context: InputContext,
next: NextFunction<InputContext>,
{ request, response }: HttpContext
) => {
const {
request: { url },
} = context;
const matched = matchPathname(pathname, url.pathname);
if (!matched) {
return next(context);
}
await new Promise<void>((resolve) => {
response.once('finish', resolve);
proxy.web(request, response, options);
});
return next({ ...context, status: 'ignore' });
};
}
export type { ServerOptions } from 'http-proxy';

View file

@ -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<InputContext extends RequestContext>({
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<InputContext>) => {
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 {}
};

View file

@ -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;
};

View file

@ -0,0 +1,7 @@
{
"extends": "./tsconfig",
"exclude": [
"src/**/*.test.ts",
"src/**/__mocks__/",
]
}

View file

@ -0,0 +1,15 @@
{
"extends": "@silverhand/ts-config/tsconfig.base",
"compilerOptions": {
"types": ["node"],
"declaration": false,
"outDir": "build",
"baseUrl": ".",
"paths": {
"#src/*": [
"src/*"
]
}
},
"include": ["src"]
}

View file

@ -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",

View file

@ -1,4 +1,7 @@
import { defaultTenantId } from '@logto/schemas';
export const adminTenantEndpoint = process.env.ADMIN_TENANT_ENDPOINT ?? window.location.origin;
const isProduction = process.env.NODE_ENV === 'production';
export const adminTenantEndpoint =
process.env.ADMIN_TENANT_ENDPOINT ??
(isProduction ? window.location.origin : 'http://localhost:3002');
export const userTenantId = process.env.USER_TENANT_ID ?? defaultTenantId;

View file

@ -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",

View file

@ -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('*');

View file

@ -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<StateT, ContextT, ResponseBodyT>(
...urlSets: UrlSet[]
): MiddlewareType<StateT, ContextT, ResponseBodyT> {
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: '*',
});
}

View file

@ -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),

View file

@ -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;

View file

@ -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());

View file

@ -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"
}
}

View file

@ -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": {

View file

@ -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": {

View file

@ -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"
}
}

View file

@ -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"

View file

@ -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",

View file

@ -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",

View file

@ -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,45 @@ importers:
sinon: 15.0.0
typescript: 4.9.4
packages/cloud:
specifiers:
'@logto/shared': workspace:*
'@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
chalk: ^5.0.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:
'@logto/shared': link:../shared
'@silverhand/essentials': 2.2.0
'@withtyped/postgres': 0.6.0_@withtyped+server@0.6.0
'@withtyped/server': 0.6.0
chalk: 5.1.2
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 +160,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 +233,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 +303,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 +321,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 +380,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 +525,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 +544,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 +553,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 +576,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 +586,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 +601,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 +612,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 +631,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 +655,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 +682,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 +696,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 +749,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 +776,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 +835,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 +892,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
@ -3561,6 +3600,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==}
@ -3592,6 +3636,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}
@ -4023,6 +4076,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:
@ -4154,6 +4213,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
@ -4498,21 +4561,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
@ -5501,7 +5564,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==}
@ -7155,16 +7218,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'}
@ -7173,7 +7226,6 @@ packages:
peerDependenciesMeta:
debug:
optional: true
dev: true
/for-in/0.1.8:
resolution: {integrity: sha512-F0to7vbBSHP8E3l6dCjxNOLuSFAACIxFy3UehTUlG7svlXi37HHsDkyVcHo0Pq8QwrE+pXvWSVX3ZT1T9wAZ9g==}
@ -7881,7 +7933,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
@ -12934,7 +12986,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: