mirror of
https://github.com/logto-io/logto.git
synced 2025-01-13 21:30:30 -05:00
feat(cli): seed tables
This commit is contained in:
parent
fb65c65893
commit
ada4da2fbf
17 changed files with 161 additions and 53 deletions
|
@ -37,8 +37,10 @@
|
|||
"prettier": "@silverhand/eslint-config/.prettierrc",
|
||||
"dependencies": {
|
||||
"@logto/schemas": "^0.1.0",
|
||||
"decamelize": "^5.0.0",
|
||||
"roarr": "^7.11.0",
|
||||
"slonik": "^28.1.0",
|
||||
"slonik-interceptor-preset": "^1.2.10",
|
||||
"slonik-sql-tag-raw": "^1.1.4"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,13 +1,19 @@
|
|||
import { readdir, readFile } from 'fs/promises';
|
||||
import path from 'path';
|
||||
|
||||
import { seeds } from '@logto/schemas';
|
||||
import { createPool, sql } from 'slonik';
|
||||
import { createInterceptors } from 'slonik-interceptor-preset';
|
||||
import { raw } from 'slonik-sql-tag-raw';
|
||||
|
||||
import { insertInto } from './utilities';
|
||||
|
||||
const { managementResource, defaultSignInExperience, createDefaultSetting } = seeds;
|
||||
const tableDirectory = 'node_modules/@logto/schemas/tables';
|
||||
const domain = 'http://localhost:3001';
|
||||
|
||||
export const createDatabaseCli = (uri: string) => {
|
||||
const pool = createPool(uri);
|
||||
const pool = createPool(uri, { interceptors: createInterceptors() });
|
||||
|
||||
const createTables = async () => {
|
||||
const directory = await readdir(tableDirectory);
|
||||
|
@ -23,13 +29,22 @@ export const createDatabaseCli = (uri: string) => {
|
|||
for (const [file, query] of queries) {
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
await pool.query(sql`${raw(query)}`);
|
||||
console.log(`Run ${file} succeeded.`);
|
||||
console.log(`Create Tables: Run ${file} succeeded.`);
|
||||
}
|
||||
};
|
||||
|
||||
return { createTables };
|
||||
const seedTables = async () => {
|
||||
await Promise.all([
|
||||
pool.query(insertInto(managementResource, 'resources')),
|
||||
pool.query(insertInto(createDefaultSetting(domain), 'settings')),
|
||||
pool.query(insertInto(defaultSignInExperience, 'sign_in_experiences')),
|
||||
]);
|
||||
console.log('Seed Tables: Seed tables succeeded.');
|
||||
};
|
||||
|
||||
return { createTables, seedTables };
|
||||
};
|
||||
|
||||
// For testing purpose, will remove later
|
||||
const cli = createDatabaseCli(process.env.DSN ?? '');
|
||||
void cli.createTables();
|
||||
void cli.seedTables();
|
||||
|
|
10
packages/cli/src/include.d/slonik-interceptor-preset.d.ts
vendored
Normal file
10
packages/cli/src/include.d/slonik-interceptor-preset.d.ts
vendored
Normal file
|
@ -0,0 +1,10 @@
|
|||
declare module 'slonik-interceptor-preset' {
|
||||
import { InterceptorType } from 'slonik';
|
||||
|
||||
export const createInterceptors: (config?: {
|
||||
benchmarkQueries: boolean;
|
||||
logQueries: boolean;
|
||||
normaliseQueries: boolean;
|
||||
transformFieldNames: boolean;
|
||||
}) => readonly InterceptorType[];
|
||||
}
|
54
packages/cli/src/utilities.ts
Normal file
54
packages/cli/src/utilities.ts
Normal file
|
@ -0,0 +1,54 @@
|
|||
// LOG-2133 Create `shared` package for common utilities
|
||||
|
||||
import { SchemaLike, SchemaValue, SchemaValuePrimitive } from '@logto/schemas';
|
||||
import decamelize from 'decamelize';
|
||||
import { sql, SqlToken } from 'slonik';
|
||||
|
||||
/**
|
||||
* Note `undefined` is removed from the acceptable list,
|
||||
* since you should NOT call this function if ignoring the field is the desired behavior.
|
||||
* Calling this function with `null` means an explicit `null` setting in database is expected.
|
||||
* @param key The key of value. Will treat as `timestamp` if it ends with `_at` or 'At' AND value is a number;
|
||||
* @param value The value to convert.
|
||||
* @returns A primitive that can be saved into database.
|
||||
*/
|
||||
export const convertToPrimitiveOrSql = (
|
||||
key: string,
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
value: NonNullable<SchemaValue> | null
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
): NonNullable<SchemaValuePrimitive> | SqlToken | null => {
|
||||
if (value === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (typeof value === 'object') {
|
||||
return JSON.stringify(value);
|
||||
}
|
||||
|
||||
if (['_at', 'At'].some((value) => key.endsWith(value)) && typeof value === 'number') {
|
||||
return sql`to_timestamp(${value / 1000})`;
|
||||
}
|
||||
|
||||
if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {
|
||||
return value;
|
||||
}
|
||||
|
||||
throw new Error(`Cannot convert ${key} to primitive`);
|
||||
};
|
||||
|
||||
export const insertInto = <T extends SchemaLike>(object: T, table: string) => {
|
||||
const keys = Object.keys(object);
|
||||
|
||||
return sql`
|
||||
insert into ${sql.identifier([table])}
|
||||
(${sql.join(
|
||||
keys.map((key) => sql.identifier([decamelize(key)])),
|
||||
sql`, `
|
||||
)})
|
||||
values (${sql.join(
|
||||
keys.map((key) => convertToPrimitiveOrSql(key, object[key] ?? null)),
|
||||
sql`, `
|
||||
)})
|
||||
`;
|
||||
};
|
|
@ -1,15 +1,14 @@
|
|||
import { Application, ApplicationType, Setting } from '@logto/schemas';
|
||||
import { Application, ApplicationType } from '@logto/schemas';
|
||||
import React, { useState } from 'react';
|
||||
import { useController, useForm } from 'react-hook-form';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import useSWR from 'swr';
|
||||
|
||||
import Button from '@/components/Button';
|
||||
import FormField from '@/components/FormField';
|
||||
import ModalLayout from '@/components/ModalLayout';
|
||||
import RadioGroup, { Radio } from '@/components/RadioGroup';
|
||||
import TextInput from '@/components/TextInput';
|
||||
import useApi, { RequestError } from '@/hooks/use-api';
|
||||
import useApi from '@/hooks/use-api';
|
||||
import { applicationTypeI18nKey } from '@/types/applications';
|
||||
import { GetStartedForm } from '@/types/get-started';
|
||||
|
||||
|
@ -40,11 +39,8 @@ const CreateForm = ({ onClose }: Props) => {
|
|||
field: { onChange, value, name, ref },
|
||||
} = useController({ name: 'type', control, rules: { required: true } });
|
||||
const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' });
|
||||
const { data: setting } = useSWR<Setting, RequestError>('/api/settings');
|
||||
const api = useApi();
|
||||
|
||||
const isGetStartedSkipped = setting?.adminConsole.applicationSkipGetStarted;
|
||||
|
||||
const closeModal = () => {
|
||||
setIsGetStartedModalOpen(false);
|
||||
onClose?.(createdApp);
|
||||
|
@ -58,11 +54,7 @@ const CreateForm = ({ onClose }: Props) => {
|
|||
const createdApp = await api.post('/api/applications', { json: data }).json<Application>();
|
||||
setCreatedApp(createdApp);
|
||||
|
||||
if (isGetStartedSkipped) {
|
||||
closeModal();
|
||||
} else {
|
||||
setIsGetStartedModalOpen(true);
|
||||
}
|
||||
setIsGetStartedModalOpen(true);
|
||||
});
|
||||
|
||||
const onComplete = async (data: GetStartedForm) => {
|
||||
|
@ -124,7 +116,7 @@ const CreateForm = ({ onClose }: Props) => {
|
|||
<TextInput {...register('description')} />
|
||||
</FormField>
|
||||
</form>
|
||||
{!isGetStartedSkipped && createdApp && (
|
||||
{createdApp && (
|
||||
<GetStartedModal
|
||||
appName={createdApp.name}
|
||||
isOpen={isGetStartedModalOpen}
|
||||
|
|
|
@ -43,9 +43,7 @@ export const mockRole: Role = {
|
|||
export const mockSetting: Setting = {
|
||||
id: 'foo setting',
|
||||
customDomain: 'mock-logto.dev',
|
||||
adminConsole: {
|
||||
applicationSkipGetStarted: false,
|
||||
},
|
||||
adminConsole: {},
|
||||
};
|
||||
|
||||
export const mockPasscode: Passcode = {
|
||||
|
|
|
@ -13,9 +13,7 @@ export const mockSignInExperience: SignInExperience = {
|
|||
id: 'foo',
|
||||
branding: {
|
||||
primaryColor: '#000',
|
||||
backgroundColor: '#fff',
|
||||
darkMode: true,
|
||||
darkBackgroundColor: '#000',
|
||||
isDarkModeEnabled: true,
|
||||
darkPrimaryColor: '#fff',
|
||||
style: BrandingStyle.Logo,
|
||||
logoUrl: 'http://logto.png',
|
||||
|
@ -24,7 +22,6 @@ export const mockSignInExperience: SignInExperience = {
|
|||
termsOfUse: {
|
||||
enabled: false,
|
||||
},
|
||||
forgetPasswordEnabled: true,
|
||||
languageInfo: {
|
||||
autoDetect: true,
|
||||
fallbackLanguage: Language.english,
|
||||
|
@ -41,9 +38,7 @@ export const mockSignInExperience: SignInExperience = {
|
|||
|
||||
export const mockBranding: Branding = {
|
||||
primaryColor: '#000',
|
||||
backgroundColor: '#fff',
|
||||
darkMode: true,
|
||||
darkBackgroundColor: '#000',
|
||||
isDarkModeEnabled: true,
|
||||
darkPrimaryColor: '#fff',
|
||||
style: BrandingStyle.Logo_Slogan,
|
||||
logoUrl: 'http://silverhand.png',
|
||||
|
|
|
@ -30,7 +30,7 @@ describe('sign-in-experience query', () => {
|
|||
it('findDefaultSignInExperience', async () => {
|
||||
/* eslint-disable sql/no-unsafe-query */
|
||||
const expectSql = `
|
||||
select "id", "branding", "language_info", "terms_of_use", "forget_password_enabled", "sign_in_methods", "social_sign_in_connector_ids"
|
||||
select "id", "branding", "language_info", "terms_of_use", "sign_in_methods", "social_sign_in_connector_ids"
|
||||
from "sign_in_experiences"
|
||||
where "id" = $1
|
||||
`;
|
||||
|
|
|
@ -22,7 +22,6 @@ export type CreateSignInExperience = {
|
|||
branding?: Branding;
|
||||
languageInfo?: LanguageInfo;
|
||||
termsOfUse?: TermsOfUse;
|
||||
forgetPasswordEnabled?: boolean;
|
||||
signInMethods?: SignInMethods;
|
||||
socialSignInConnectorIds?: ConnectorIds;
|
||||
};
|
||||
|
@ -32,7 +31,6 @@ export type SignInExperience = {
|
|||
branding: Branding;
|
||||
languageInfo: LanguageInfo;
|
||||
termsOfUse: TermsOfUse;
|
||||
forgetPasswordEnabled: boolean;
|
||||
signInMethods: SignInMethods;
|
||||
socialSignInConnectorIds: ConnectorIds;
|
||||
};
|
||||
|
@ -42,7 +40,6 @@ const createGuard: Guard<CreateSignInExperience> = z.object({
|
|||
branding: brandingGuard.optional(),
|
||||
languageInfo: languageInfoGuard.optional(),
|
||||
termsOfUse: termsOfUseGuard.optional(),
|
||||
forgetPasswordEnabled: z.boolean().optional(),
|
||||
signInMethods: signInMethodsGuard.optional(),
|
||||
socialSignInConnectorIds: connectorIdsGuard.optional(),
|
||||
});
|
||||
|
@ -55,7 +52,6 @@ export const SignInExperiences: GeneratedSchema<CreateSignInExperience> = Object
|
|||
branding: 'branding',
|
||||
languageInfo: 'language_info',
|
||||
termsOfUse: 'terms_of_use',
|
||||
forgetPasswordEnabled: 'forget_password_enabled',
|
||||
signInMethods: 'sign_in_methods',
|
||||
socialSignInConnectorIds: 'social_sign_in_connector_ids',
|
||||
},
|
||||
|
@ -64,7 +60,6 @@ export const SignInExperiences: GeneratedSchema<CreateSignInExperience> = Object
|
|||
'branding',
|
||||
'languageInfo',
|
||||
'termsOfUse',
|
||||
'forgetPasswordEnabled',
|
||||
'signInMethods',
|
||||
'socialSignInConnectorIds',
|
||||
],
|
||||
|
|
|
@ -76,9 +76,7 @@ export type UserLogPayload = z.infer<typeof userLogPayloadGuard>;
|
|||
* Settings
|
||||
*/
|
||||
|
||||
export const adminConsoleConfigGuard = z.object({
|
||||
applicationSkipGetStarted: z.boolean(),
|
||||
});
|
||||
export const adminConsoleConfigGuard = z.object({});
|
||||
|
||||
export type AdminConsoleConfig = z.infer<typeof adminConsoleConfigGuard>;
|
||||
|
||||
|
@ -95,10 +93,8 @@ export const hexColorRegEx = /^#[\da-f]{3}([\da-f]{3})?$/i;
|
|||
|
||||
export const brandingGuard = z.object({
|
||||
primaryColor: z.string().regex(hexColorRegEx),
|
||||
backgroundColor: z.string().regex(hexColorRegEx),
|
||||
darkMode: z.boolean(),
|
||||
isDarkModeEnabled: z.boolean(),
|
||||
darkPrimaryColor: z.string().regex(hexColorRegEx),
|
||||
darkBackgroundColor: z.string().regex(hexColorRegEx),
|
||||
style: z.nativeEnum(BrandingStyle),
|
||||
logoUrl: z.string().url(),
|
||||
slogan: z.string().nonempty().optional(),
|
||||
|
|
|
@ -2,3 +2,4 @@ export * from './foundations';
|
|||
export * from './db-entries';
|
||||
export * from './types';
|
||||
export * from './api';
|
||||
export * as seeds from './seeds';
|
||||
|
|
3
packages/schemas/src/seeds/index.ts
Normal file
3
packages/schemas/src/seeds/index.ts
Normal file
|
@ -0,0 +1,3 @@
|
|||
export * from './resource';
|
||||
export * from './setting';
|
||||
export * from './sign-in-experience';
|
7
packages/schemas/src/seeds/resource.ts
Normal file
7
packages/schemas/src/seeds/resource.ts
Normal file
|
@ -0,0 +1,7 @@
|
|||
import { CreateResource } from '../db-entries';
|
||||
|
||||
export const managementResource: Readonly<CreateResource> = Object.freeze({
|
||||
id: 'management-api',
|
||||
indicator: 'https://logto.io/api',
|
||||
name: 'Logto Management API',
|
||||
});
|
10
packages/schemas/src/seeds/setting.ts
Normal file
10
packages/schemas/src/seeds/setting.ts
Normal file
|
@ -0,0 +1,10 @@
|
|||
import { CreateSetting } from '../db-entries';
|
||||
|
||||
export const defaultSettingId = 'default';
|
||||
|
||||
export const createDefaultSetting = (customDomain: string): Readonly<CreateSetting> =>
|
||||
Object.freeze({
|
||||
id: defaultSettingId,
|
||||
customDomain,
|
||||
adminConsole: {},
|
||||
});
|
28
packages/schemas/src/seeds/sign-in-experience.ts
Normal file
28
packages/schemas/src/seeds/sign-in-experience.ts
Normal file
|
@ -0,0 +1,28 @@
|
|||
import { CreateSignInExperience } from '../db-entries';
|
||||
import { BrandingStyle, Language, SignInMethodState } from '../foundations';
|
||||
|
||||
export const defaultSignInExperience: Readonly<CreateSignInExperience> = {
|
||||
id: 'default',
|
||||
branding: {
|
||||
primaryColor: '#6139F6',
|
||||
isDarkModeEnabled: false,
|
||||
darkPrimaryColor: '#6139F6',
|
||||
style: BrandingStyle.Logo,
|
||||
logoUrl: 'https://logto.io/logo.svg',
|
||||
},
|
||||
languageInfo: {
|
||||
autoDetect: true,
|
||||
fallbackLanguage: Language.english,
|
||||
fixedLanguage: Language.english,
|
||||
},
|
||||
termsOfUse: {
|
||||
enabled: false,
|
||||
},
|
||||
signInMethods: {
|
||||
username: SignInMethodState.primary,
|
||||
email: SignInMethodState.disabled,
|
||||
sms: SignInMethodState.disabled,
|
||||
social: SignInMethodState.disabled,
|
||||
},
|
||||
socialSignInConnectorIds: [],
|
||||
};
|
|
@ -3,7 +3,6 @@ create table sign_in_experiences (
|
|||
branding jsonb /* @use Branding */ not null default '{}'::jsonb,
|
||||
language_info jsonb /* @use LanguageInfo */ not null default '{}'::jsonb,
|
||||
terms_of_use jsonb /* @use TermsOfUse */ not null default '{}'::jsonb,
|
||||
forget_password_enabled boolean not null default false,
|
||||
sign_in_methods jsonb /* @use SignInMethods */ not null default '{}'::jsonb,
|
||||
social_sign_in_connector_ids jsonb /* @use ConnectorIds */ not null default '[]'::jsonb,
|
||||
primary key (id)
|
||||
|
|
31
pnpm-lock.yaml
generated
31
pnpm-lock.yaml
generated
|
@ -24,18 +24,22 @@ importers:
|
|||
'@silverhand/eslint-config': ^0.10.2
|
||||
'@silverhand/ts-config': ^0.10.2
|
||||
'@types/node': '14'
|
||||
decamelize: ^5.0.0
|
||||
eslint: ^8.10.0
|
||||
lint-staged: ^11.1.1
|
||||
prettier: ^2.3.2
|
||||
roarr: ^7.11.0
|
||||
slonik: ^28.1.0
|
||||
slonik-interceptor-preset: ^1.2.10
|
||||
slonik-sql-tag-raw: ^1.1.4
|
||||
ts-node: ^10.0.0
|
||||
typescript: ^4.6.3
|
||||
dependencies:
|
||||
'@logto/schemas': link:../schemas
|
||||
decamelize: 5.0.1
|
||||
roarr: 7.11.0
|
||||
slonik: 28.1.0
|
||||
slonik-interceptor-preset: 1.2.10
|
||||
slonik-sql-tag-raw: 1.1.4_roarr@7.11.0+slonik@28.1.0
|
||||
devDependencies:
|
||||
'@silverhand/eslint-config': 0.10.2_bbe1a6794670f389df81805f22999709
|
||||
|
@ -2338,6 +2342,7 @@ packages:
|
|||
dependencies:
|
||||
'@babel/helper-validator-identifier': 7.15.7
|
||||
to-fast-properties: 2.0.0
|
||||
dev: true
|
||||
|
||||
/@babel/types/7.17.0:
|
||||
resolution: {integrity: sha512-TmKSNO4D5rzhL5bjWFcVHHLETzfQ/AmbKpKPOSjlP0WoHZ6L911fgoOKY4Alp/emzG4cHJdyN49zpgkbXFEHHw==}
|
||||
|
@ -6886,9 +6891,9 @@ packages:
|
|||
/babel-plugin-macros/2.8.0:
|
||||
resolution: {integrity: sha512-SEP5kJpfGYqYKpBrj5XU3ahw5p5GOHJ0U5ssOSQ/WBVdwkD2Dzlce95exQTs3jOVWPPKLBN2rlEWkCK7dSmLvg==}
|
||||
dependencies:
|
||||
'@babel/runtime': 7.16.3
|
||||
'@babel/runtime': 7.17.9
|
||||
cosmiconfig: 6.0.0
|
||||
resolve: 1.20.0
|
||||
resolve: 1.22.0
|
||||
dev: false
|
||||
|
||||
/babel-plugin-polyfill-corejs2/0.3.1_@babel+core@7.17.9:
|
||||
|
@ -7314,6 +7319,7 @@ packages:
|
|||
/camelcase/6.2.1:
|
||||
resolution: {integrity: sha512-tVI4q5jjFV5CavAU8DXfza/TJcZutVKo/5Foskmsqcm0MsL91moHvwiGNnqaa2o6PF/7yT5ikDRcVcl8Rj6LCA==}
|
||||
engines: {node: '>=10'}
|
||||
dev: true
|
||||
|
||||
/camelcase/6.3.0:
|
||||
resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==}
|
||||
|
@ -7947,11 +7953,6 @@ packages:
|
|||
requiresBuild: true
|
||||
dev: false
|
||||
|
||||
/core-js/3.19.3:
|
||||
resolution: {integrity: sha512-LeLBMgEGSsG7giquSzvgBrTS7V5UL6ks3eQlUSbN8dJStlLFiRzUm5iqsRyzUB8carhfKjkJ2vzKqE6z1Vga9g==}
|
||||
requiresBuild: true
|
||||
dev: false
|
||||
|
||||
/core-js/3.21.1:
|
||||
resolution: {integrity: sha512-FRq5b/VMrWlrmCzwRrpDYNxyHP9BcAZC+xHJaqTgIE5091ZV1NTmyh0sGOg5XqpnHvR0svdy0sv1gWA1zmhxig==}
|
||||
requiresBuild: true
|
||||
|
@ -10937,7 +10938,7 @@ packages:
|
|||
/inline-loops.macro/1.2.2:
|
||||
resolution: {integrity: sha512-w5cOGQGnNoBTSibg6IzaIG2OG9sbXJxTn3uzYP717C/SvcJVEFz5Zu1dJwvCLlnwtBWQgcfnV2BNEQaRoIAfIw==}
|
||||
dependencies:
|
||||
'@babel/types': 7.16.0
|
||||
'@babel/types': 7.17.0
|
||||
babel-plugin-macros: 2.8.0
|
||||
dev: false
|
||||
|
||||
|
@ -11070,6 +11071,7 @@ packages:
|
|||
resolution: {integrity: sha512-vd15qHsaqrRL7dtH6QNuy0ndJmRDrS9HAM1CAiSifNUFv4x1a0CCVsj18hJ1mShxIG6T2i1sO78MkP56r0nYRw==}
|
||||
dependencies:
|
||||
has: 1.0.3
|
||||
dev: true
|
||||
|
||||
/is-core-module/2.8.1:
|
||||
resolution: {integrity: sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA==}
|
||||
|
@ -16717,6 +16719,7 @@ packages:
|
|||
dependencies:
|
||||
is-core-module: 2.8.0
|
||||
path-parse: 1.0.7
|
||||
dev: true
|
||||
|
||||
/resolve/1.22.0:
|
||||
resolution: {integrity: sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==}
|
||||
|
@ -17201,8 +17204,8 @@ packages:
|
|||
peerDependencies:
|
||||
slonik: '*'
|
||||
dependencies:
|
||||
camelcase: 6.2.1
|
||||
core-js: 3.19.3
|
||||
camelcase: 6.3.0
|
||||
core-js: 3.21.1
|
||||
slonik: 22.7.1
|
||||
dev: false
|
||||
|
||||
|
@ -17223,7 +17226,7 @@ packages:
|
|||
resolution: {integrity: sha512-f9jxhsu+8u0ssf2pdzLx1jSlGODkAitNbGrprJWGOjmnQzZKW4jWaq54DZGwyNv4HotOb9m4Lp0u9XQODKXyng==}
|
||||
engines: {node: '>=8.0'}
|
||||
dependencies:
|
||||
core-js: 3.19.3
|
||||
core-js: 3.21.1
|
||||
pg-formatter: 1.3.0
|
||||
pretty-ms: 6.0.1
|
||||
slonik: 22.7.1
|
||||
|
@ -17249,7 +17252,7 @@ packages:
|
|||
resolution: {integrity: sha512-TAuWVFBVnq7I5KcEY/x1JgVgIVZ0yyyeRlMTzKs+u4wRYhszQW2hMIYnDak/UUfWR1h6wp3+hODiC4gKyBOUcg==}
|
||||
engines: {node: '>=8.0'}
|
||||
dependencies:
|
||||
core-js: 3.19.3
|
||||
core-js: 3.21.1
|
||||
slonik: 22.7.1
|
||||
transitivePeerDependencies:
|
||||
- pg-native
|
||||
|
@ -17279,11 +17282,11 @@ packages:
|
|||
inline-loops.macro: 1.2.2
|
||||
is-plain-object: 5.0.0
|
||||
iso8601-duration: 1.3.0
|
||||
pg: 8.7.1
|
||||
pg: 8.7.3
|
||||
pg-connection-string: 2.5.0
|
||||
pg-copy-streams: 5.1.1
|
||||
pg-copy-streams-binary: 2.2.0
|
||||
pg-cursor: 2.7.1_pg@8.7.1
|
||||
pg-cursor: 2.7.3_pg@8.7.3
|
||||
pg-types: 3.0.1
|
||||
postgres-array: 2.0.0
|
||||
postgres-interval: 2.1.0
|
||||
|
|
Loading…
Add table
Reference in a new issue