Add docker, prisma and worker POC
Add docker-compose with Postgres Install Prisma and generate empty schema Install Prisma client Add app config model and migration Add repository for Algolia Configuration Migrate metadata to postgres Replace webhooks metadata with PRisma Add worker and skeleton code Implement worker job and removed from the frontend Attempt to display jobs list Worker utils Run worker in the same thread on dev Run worker in the same thread on dev Build scripts fix dev mode Dockerfiles prod dockerfiles docker wip docker wip wip working docker wip working docker wip - working without prisma migrate
This commit is contained in:
parent
a8834a11fe
commit
7240f6efa7
39 changed files with 1044 additions and 301 deletions
2
.dockerignore
Normal file
2
.dockerignore
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
node_modules/
|
||||||
|
**/.env
|
2
apps/search/.dockerignore
Normal file
2
apps/search/.dockerignore
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
node_modules/
|
||||||
|
**/.env
|
|
@ -1,4 +1,10 @@
|
||||||
# Encryption key used by the EncryptedSettingsManager. Required by the production builds
|
# Encryption key used by the EncryptedSettingsManager. Required by the production builds
|
||||||
SECRET_KEY=
|
SECRET_KEY=
|
||||||
|
|
||||||
APP_LOG_LEVEL=info
|
APP_LOG_LEVEL=info
|
||||||
|
|
||||||
|
DATABASE_URL=postgresql://USER:PASSWORD@HOST:PORT/DATABASE
|
||||||
|
|
||||||
|
# Conditionally run worker with Next use instrumentation hook (src/instrmentation.ts)
|
||||||
|
# This is handy for development but in production it should be a separate process
|
||||||
|
RUN_WORKER_IN_NEXT_PROCESS=false
|
1
apps/search/.gitignore
vendored
Normal file
1
apps/search/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
worker-dist/
|
71
apps/search/app.prod.Dockerfile
Normal file
71
apps/search/app.prod.Dockerfile
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
# Source
|
||||||
|
# https://turbo.build/repo/docs/handbook/deploying-with-docker#example
|
||||||
|
# TODO https://pnpm.io/cli/fetch
|
||||||
|
|
||||||
|
FROM node:18 AS base
|
||||||
|
|
||||||
|
FROM base AS builder
|
||||||
|
#RUN apk add --no-cache libc6-compat
|
||||||
|
#RUN apk update
|
||||||
|
|
||||||
|
# Set working directory
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
RUN yarn global add turbo@1.9.1
|
||||||
|
RUN yarn global add pnpm@8.2.0
|
||||||
|
|
||||||
|
# Copy entire monorepo
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
RUN turbo prune --scope="saleor-app-search" --docker
|
||||||
|
|
||||||
|
# Add lockfile and package.json's of isolated subworkspace
|
||||||
|
FROM base AS installer
|
||||||
|
#RUN apk add --no-cache libc6-compat
|
||||||
|
#RUN apk update
|
||||||
|
WORKDIR /app
|
||||||
|
RUN yarn global add pnpm@8.2.0
|
||||||
|
|
||||||
|
ARG DATABASE_URL
|
||||||
|
ENV DATABASE_URL=${DATABASE_URL}
|
||||||
|
|
||||||
|
# First install the dependencies (as they change less often)
|
||||||
|
COPY .gitignore .gitignore
|
||||||
|
COPY --from=builder /app/out/full/ .
|
||||||
|
#COPY --from=builder /app/out/json/ .
|
||||||
|
COPY --from=builder /app/out/pnpm-lock.yaml ./pnpm-lock.yaml
|
||||||
|
COPY --from=builder /app/out/pnpm-workspace.yaml ./pnpm-workspace.yaml
|
||||||
|
|
||||||
|
RUN pnpm install --frozen-lockfile
|
||||||
|
|
||||||
|
# Build the project
|
||||||
|
#COPY --from=builder /app/out/full/ .
|
||||||
|
COPY turbo.json turbo.json
|
||||||
|
|
||||||
|
RUN pnpm turbo run build:app --filter="saleor-app-search"
|
||||||
|
|
||||||
|
FROM base AS runner
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
ARG DATABASE_URL
|
||||||
|
ENV DATABASE_URL=${DATABASE_URL}
|
||||||
|
|
||||||
|
# Don't run production as root
|
||||||
|
RUN addgroup --system --gid 1001 nodejs
|
||||||
|
RUN adduser --system --uid 1001 nextjs
|
||||||
|
USER nextjs
|
||||||
|
|
||||||
|
COPY --from=installer /app/apps/search/next.config.js .
|
||||||
|
COPY --from=installer /app/apps/search/package.json .
|
||||||
|
|
||||||
|
# Automatically leverage output traces to reduce image size
|
||||||
|
# https://nextjs.org/docs/advanced-features/output-file-tracing
|
||||||
|
COPY --from=installer --chown=nextjs:nodejs /app/apps/search/.next/standalone ./
|
||||||
|
COPY --from=installer --chown=nextjs:nodejs /app/apps/search/.next/static ./apps/search/.next/static
|
||||||
|
COPY --from=installer --chown=nextjs:nodejs /app/apps/search/public ./apps/search/public
|
||||||
|
COPY --from=installer --chown=nextjs:nodejs /app/apps/search/prisma ./apps/search/prisma
|
||||||
|
|
||||||
|
|
||||||
|
CMD ["node", "apps/search/server.js"]
|
||||||
|
|
||||||
|
# TODO Another entrypoint for worker
|
|
@ -15,6 +15,9 @@ const isSentryPropertiesInEnvironment =
|
||||||
*/
|
*/
|
||||||
const moduleExports = {
|
const moduleExports = {
|
||||||
reactStrictMode: true,
|
reactStrictMode: true,
|
||||||
|
experimental: {
|
||||||
|
instrumentationHook: true
|
||||||
|
},
|
||||||
images: {
|
images: {
|
||||||
remotePatterns: [
|
remotePatterns: [
|
||||||
{
|
{
|
||||||
|
@ -37,6 +40,7 @@ const moduleExports = {
|
||||||
disableServerWebpackPlugin: !isSentryPropertiesInEnvironment,
|
disableServerWebpackPlugin: !isSentryPropertiesInEnvironment,
|
||||||
disableClientWebpackPlugin: !isSentryPropertiesInEnvironment,
|
disableClientWebpackPlugin: !isSentryPropertiesInEnvironment,
|
||||||
},
|
},
|
||||||
|
output: "standalone",
|
||||||
};
|
};
|
||||||
|
|
||||||
const sentryWebpackPluginOptions = {
|
const sentryWebpackPluginOptions = {
|
||||||
|
|
|
@ -2,17 +2,25 @@
|
||||||
"name": "saleor-app-search",
|
"name": "saleor-app-search",
|
||||||
"version": "1.9.3",
|
"version": "1.9.3",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "pnpm generate && next build",
|
"dev:app": "pnpm generate && NODE_OPTIONS='--inspect' next dev",
|
||||||
"dev": "pnpm generate && NODE_OPTIONS='--inspect' next dev",
|
"build:app": "pnpm generate && next build",
|
||||||
"fetch-schema": "curl https://raw.githubusercontent.com/saleor/saleor/${npm_package_saleor_schemaVersion}/saleor/graphql/schema.graphql > graphql/schema.graphql",
|
"start:app": "next start",
|
||||||
"generate": "graphql-codegen",
|
"build": "concurrently \"pnpm build:app\" \"pnpm build:worker\"",
|
||||||
|
"dev": "concurrently \"pnpm dev:app\" \"pnpm dev:worker\"",
|
||||||
"lint": "next lint",
|
"lint": "next lint",
|
||||||
"lint:fix": "eslint --fix .",
|
"lint:fix": "eslint --fix .",
|
||||||
"start": "next start",
|
"fetch-schema": "curl https://raw.githubusercontent.com/saleor/saleor/${npm_package_saleor_schemaVersion}/saleor/graphql/schema.graphql > graphql/schema.graphql",
|
||||||
"test": "vitest"
|
"generate": "graphql-codegen && npm run prisma:generate",
|
||||||
|
"test": "vitest",
|
||||||
|
"dev:worker": "pnpm generate && tsx src/worker/runner.ts --watch",
|
||||||
|
"build:worker": "pnpm generate && tsup src/worker/runner.ts --outDir worker-dist",
|
||||||
|
"start:worker": "node worker-dist/runner.js",
|
||||||
|
"prisma:generate": "prisma generate"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"graphile-worker": "^0.13.0",
|
||||||
"@hookform/resolvers": "^3.1.0",
|
"@hookform/resolvers": "^3.1.0",
|
||||||
|
"@prisma/client": "^4.15.0",
|
||||||
"@saleor/app-sdk": "0.39.1",
|
"@saleor/app-sdk": "0.39.1",
|
||||||
"@saleor/apps-shared": "workspace:*",
|
"@saleor/apps-shared": "workspace:*",
|
||||||
"@saleor/apps-ui": "workspace:*",
|
"@saleor/apps-ui": "workspace:*",
|
||||||
|
@ -36,7 +44,9 @@
|
||||||
"react-hook-form": "^7.43.9",
|
"react-hook-form": "^7.43.9",
|
||||||
"react-query": "^3.39.3",
|
"react-query": "^3.39.3",
|
||||||
"urql": "^3.0.3",
|
"urql": "^3.0.3",
|
||||||
"zod": "^3.21.4"
|
"zod": "^3.21.4",
|
||||||
|
"dotenv": "^16.1.4",
|
||||||
|
"prisma": "^4.15.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@graphql-codegen/cli": "3.2.2",
|
"@graphql-codegen/cli": "3.2.2",
|
||||||
|
@ -56,7 +66,10 @@
|
||||||
"node-mocks-http": "^1.12.2",
|
"node-mocks-http": "^1.12.2",
|
||||||
"typescript": "5.1.3",
|
"typescript": "5.1.3",
|
||||||
"vite": "4.3.9",
|
"vite": "4.3.9",
|
||||||
"vitest": "0.31.3"
|
"vitest": "0.31.3",
|
||||||
|
"tsup": "^6.7.0",
|
||||||
|
"concurrently": "^8.1.0",
|
||||||
|
"tsx": "^3.12.7"
|
||||||
},
|
},
|
||||||
"private": true,
|
"private": true,
|
||||||
"saleor": {
|
"saleor": {
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "AlgoliaConfiguration" (
|
||||||
|
"id" SERIAL NOT NULL,
|
||||||
|
"appId" TEXT NOT NULL,
|
||||||
|
"indexNamePrefix" TEXT,
|
||||||
|
"secretKey" TEXT NOT NULL,
|
||||||
|
"saleorApiUrl" TEXT NOT NULL,
|
||||||
|
|
||||||
|
CONSTRAINT "AlgoliaConfiguration_pkey" PRIMARY KEY ("id")
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE UNIQUE INDEX "AlgoliaConfiguration_saleorApiUrl_key" ON "AlgoliaConfiguration"("saleorApiUrl");
|
3
apps/search/prisma/migrations/migration_lock.toml
Normal file
3
apps/search/prisma/migrations/migration_lock.toml
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
# Please do not edit this file manually
|
||||||
|
# It should be added in your version-control system (i.e. Git)
|
||||||
|
provider = "postgresql"
|
19
apps/search/prisma/schema.prisma
Normal file
19
apps/search/prisma/schema.prisma
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
// This is your Prisma schema file,
|
||||||
|
// learn more about it in the docs: https://pris.ly/d/prisma-schema
|
||||||
|
|
||||||
|
generator client {
|
||||||
|
provider = "prisma-client-js"
|
||||||
|
}
|
||||||
|
|
||||||
|
datasource db {
|
||||||
|
provider = "postgresql"
|
||||||
|
url = env("DATABASE_URL")
|
||||||
|
}
|
||||||
|
|
||||||
|
model AlgoliaConfiguration {
|
||||||
|
id Int @id @default(autoincrement())
|
||||||
|
appId String
|
||||||
|
indexNamePrefix String?
|
||||||
|
secretKey String // TODO encryption
|
||||||
|
saleorApiUrl String @unique // Reference - maybe it can be unique id? This will share config where 2 apps installed
|
||||||
|
}
|
0
apps/search/public/.gitkeep
Normal file
0
apps/search/public/.gitkeep
Normal file
|
@ -37,15 +37,6 @@ switch (aplType) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!process.env.SECRET_KEY && process.env.NODE_ENV === "production") {
|
|
||||||
throw new Error(
|
|
||||||
"For production deployment SECRET_KEY is mandatory to use EncryptedSettingsManager."
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use placeholder value for the development
|
|
||||||
export const settingsManagerSecretKey = process.env.SECRET_KEY || "CHANGE_ME";
|
|
||||||
|
|
||||||
export const saleorApp = new SaleorApp({
|
export const saleorApp = new SaleorApp({
|
||||||
apl,
|
apl,
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,19 +1,14 @@
|
||||||
import { Box, Button, Text } from "@saleor/macaw-ui/next";
|
import { Box, Button, Text } from "@saleor/macaw-ui/next";
|
||||||
import React, { useCallback, useEffect, useMemo, useState } from "react";
|
import React, { useEffect, useMemo, useState } from "react";
|
||||||
import { AlgoliaSearchProvider } from "../lib/algolia/algoliaSearchProvider";
|
import { AlgoliaSearchProvider } from "../lib/algolia/algoliaSearchProvider";
|
||||||
import { useConfiguration } from "../lib/configuration";
|
import { useConfiguration } from "../lib/configuration";
|
||||||
import { Products, useQueryAllProducts } from "./useQueryAllProducts";
|
import { Products } from "./useQueryAllProducts";
|
||||||
import { useWebhooksStatus } from "../lib/useWebhooksStatus";
|
import { useAuthenticatedFetch } from "@saleor/app-sdk/app-bridge";
|
||||||
|
|
||||||
const BATCH_SIZE = 100;
|
|
||||||
|
|
||||||
export const ImportProductsToAlgolia = () => {
|
export const ImportProductsToAlgolia = () => {
|
||||||
const [algoliaConfigured, setAlgoliaConfigured] = useState<null | boolean>(null);
|
const fetch = useAuthenticatedFetch();
|
||||||
const [started, setStarted] = useState(false);
|
|
||||||
const [currentProductIndex, setCurrentProductIndex] = useState(0);
|
|
||||||
const [isAlgoliaImporting, setIsAlgoliaImporting] = useState(false);
|
|
||||||
|
|
||||||
const products = useQueryAllProducts(!started);
|
const [algoliaConfigured, setAlgoliaConfigured] = useState<null | boolean>(null);
|
||||||
|
|
||||||
const algoliaConfiguration = useConfiguration();
|
const algoliaConfiguration = useConfiguration();
|
||||||
|
|
||||||
|
@ -32,10 +27,6 @@ export const ImportProductsToAlgolia = () => {
|
||||||
algoliaConfiguration?.data?.secretKey,
|
algoliaConfiguration?.data?.secretKey,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const importProducts = useCallback(() => {
|
|
||||||
setStarted(true);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (searchProvider) {
|
if (searchProvider) {
|
||||||
searchProvider
|
searchProvider
|
||||||
|
@ -45,39 +36,29 @@ export const ImportProductsToAlgolia = () => {
|
||||||
}
|
}
|
||||||
}, [searchProvider]);
|
}, [searchProvider]);
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (!searchProvider || isAlgoliaImporting || products.length <= currentProductIndex) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
(async () => {
|
|
||||||
setIsAlgoliaImporting(true);
|
|
||||||
const productsBatchStartIndex = currentProductIndex;
|
|
||||||
const productsBatchEndIndex = Math.min(currentProductIndex + BATCH_SIZE, products.length);
|
|
||||||
const productsBatch = products.slice(productsBatchStartIndex, productsBatchEndIndex);
|
|
||||||
|
|
||||||
await searchProvider.updatedBatchProducts(productsBatch);
|
|
||||||
|
|
||||||
setIsAlgoliaImporting(false);
|
|
||||||
setCurrentProductIndex(productsBatchEndIndex);
|
|
||||||
})();
|
|
||||||
}, [searchProvider, currentProductIndex, isAlgoliaImporting, products]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box __cursor={started ? "wait" : "auto"}>
|
<Box>
|
||||||
{searchProvider && algoliaConfigured ? (
|
{searchProvider && algoliaConfigured ? (
|
||||||
<Box>
|
<Box>
|
||||||
<Text variant={"heading"} as={"p"} marginBottom={4}>
|
<Text variant={"heading"} as={"p"} marginBottom={4}>
|
||||||
Importing products & variants
|
Importing products & variants
|
||||||
</Text>
|
</Text>
|
||||||
<Text as={"p"}>
|
<Text as={"p"}>
|
||||||
Trigger initial indexing for products catalogue. It can take few minutes.{" "}
|
Trigger initial indexing for products catalogue. It can take few minutes and will run in
|
||||||
|
the background
|
||||||
</Text>
|
</Text>
|
||||||
<Text marginBottom={8} variant={"bodyStrong"}>
|
<Box display={"flex"} justifyContent={"flex-end"} marginTop={13}>
|
||||||
Do not close the app - its running client-side
|
<Button onClick={() => fetch("/api/index-products")}>Start importing</Button>
|
||||||
</Text>
|
<Button
|
||||||
<Box display={"flex"} justifyContent={"flex-end"}>
|
onClick={() =>
|
||||||
<Button disabled={started || !searchProvider} onClick={importProducts}>
|
fetch("/api/jobs")
|
||||||
Start importing
|
.then((r: any) => r.json())
|
||||||
|
.then((jobs: unknown) => {
|
||||||
|
console.log(jobs);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
>
|
||||||
|
Check status
|
||||||
</Button>
|
</Button>
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
|
@ -89,29 +70,6 @@ export const ImportProductsToAlgolia = () => {
|
||||||
<Text>Configure Algolia first</Text>
|
<Text>Configure Algolia first</Text>
|
||||||
</Box>
|
</Box>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{started && (
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
marginTop: "20px",
|
|
||||||
display: "flex",
|
|
||||||
flexDirection: "column",
|
|
||||||
alignItems: "center",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{countVariants(products, currentProductIndex)} /{" "}
|
|
||||||
{countVariants(products, products.length)}
|
|
||||||
<progress
|
|
||||||
value={currentProductIndex}
|
|
||||||
max={products.length}
|
|
||||||
style={{
|
|
||||||
height: "30px",
|
|
||||||
width: "500px",
|
|
||||||
maxWidth: "100%",
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -13,6 +13,9 @@ export type Products = NonNullable<
|
||||||
ProductsDataForImportQuery["products"]
|
ProductsDataForImportQuery["products"]
|
||||||
>["edges"][number]["node"][];
|
>["edges"][number]["node"][];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated
|
||||||
|
*/
|
||||||
export const useQueryAllProducts = (paused: boolean) => {
|
export const useQueryAllProducts = (paused: boolean) => {
|
||||||
const { appBridgeState } = useAppBridge();
|
const { appBridgeState } = useAppBridge();
|
||||||
const saleorApiUrl = appBridgeState?.saleorApiUrl!;
|
const saleorApiUrl = appBridgeState?.saleorApiUrl!;
|
||||||
|
|
9
apps/search/src/db/prisma.ts
Normal file
9
apps/search/src/db/prisma.ts
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
import { PrismaClient } from "@prisma/client";
|
||||||
|
|
||||||
|
export const prisma = new PrismaClient();
|
||||||
|
export type Prisma = typeof prisma;
|
||||||
|
|
||||||
|
// todo verify if this is enough cleanup
|
||||||
|
process.on("exit", () => {
|
||||||
|
prisma.$disconnect();
|
||||||
|
});
|
|
@ -0,0 +1,42 @@
|
||||||
|
import { prisma, Prisma } from "../../db/prisma";
|
||||||
|
|
||||||
|
export class AlgoliaConfigurationRepository {
|
||||||
|
constructor(private prisma: Prisma) {}
|
||||||
|
|
||||||
|
getConfiguration(saleorApiUrl: string) {
|
||||||
|
return this.prisma.algoliaConfiguration.findFirst({
|
||||||
|
where: {
|
||||||
|
saleorApiUrl: saleorApiUrl,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
setConfiguration(
|
||||||
|
saleorApiUrl: string,
|
||||||
|
configuration: {
|
||||||
|
appId: string;
|
||||||
|
indexNamePrefix?: string;
|
||||||
|
secretKey: string;
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
return this.prisma.algoliaConfiguration.upsert({
|
||||||
|
where: {
|
||||||
|
saleorApiUrl: saleorApiUrl,
|
||||||
|
},
|
||||||
|
create: {
|
||||||
|
saleorApiUrl,
|
||||||
|
appId: configuration.appId,
|
||||||
|
indexNamePrefix: configuration.indexNamePrefix,
|
||||||
|
secretKey: configuration.secretKey,
|
||||||
|
},
|
||||||
|
update: {
|
||||||
|
saleorApiUrl,
|
||||||
|
appId: configuration.appId,
|
||||||
|
indexNamePrefix: configuration.indexNamePrefix,
|
||||||
|
secretKey: configuration.secretKey,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const algoliaConfigurationRepository = new AlgoliaConfigurationRepository(prisma);
|
17
apps/search/src/instrumentation.ts
Normal file
17
apps/search/src/instrumentation.ts
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
import { prisma } from "./db/prisma";
|
||||||
|
|
||||||
|
export const register = async () => {
|
||||||
|
if (process.env.RUN_WORKER_IN_NEXT_PROCESS === "true" && process.env.NEXT_RUNTIME === "nodejs") {
|
||||||
|
console.log("RUN_WORKER_IN_NEXT_PROCESS env is set, will inject worker to Next.js process");
|
||||||
|
|
||||||
|
await import("./worker/runner").catch();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (process.env.NEXT_RUNTIME === "nodejs") {
|
||||||
|
prisma.$connect().catch((e: any) => {
|
||||||
|
console.error(e);
|
||||||
|
console.error("Cant connect to database, will exit");
|
||||||
|
process.exit(1);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
|
@ -1,64 +1,20 @@
|
||||||
import { AuthData } from "@saleor/app-sdk/APL";
|
import { AuthData } from "@saleor/app-sdk/APL";
|
||||||
import { createDebug } from "../debug";
|
import { algoliaConfigurationRepository } from "../../domain/algolia-configuration/AlgoliaConfigurationRepository";
|
||||||
import { createClient } from "../graphql";
|
|
||||||
import { createSettingsManager } from "../metadata";
|
|
||||||
|
|
||||||
interface GetAlgoliaConfigurationArgs {
|
interface GetAlgoliaConfigurationArgs {
|
||||||
authData: AuthData;
|
authData: AuthData;
|
||||||
}
|
}
|
||||||
|
|
||||||
const debug = createDebug("getAlgoliaConfiguration");
|
|
||||||
|
|
||||||
export const getAlgoliaConfiguration = async ({ authData }: GetAlgoliaConfigurationArgs) => {
|
export const getAlgoliaConfiguration = async ({ authData }: GetAlgoliaConfigurationArgs) => {
|
||||||
const client = createClient(authData.saleorApiUrl, async () =>
|
const configuration = await algoliaConfigurationRepository.getConfiguration(
|
||||||
Promise.resolve({ token: authData.token })
|
authData.saleorApiUrl
|
||||||
);
|
);
|
||||||
|
|
||||||
const settings = createSettingsManager(client);
|
return configuration
|
||||||
|
? {
|
||||||
try {
|
settings: configuration,
|
||||||
const secretKey = await settings.get("secretKey", authData.domain);
|
}
|
||||||
|
: {
|
||||||
if (!secretKey?.length) {
|
errors: [{ message: "Configuration doesnt exist" }],
|
||||||
return {
|
|
||||||
errors: [
|
|
||||||
{
|
|
||||||
message:
|
|
||||||
"Missing secret key to the Algolia API. Please, configure the application first.",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
const appId = await settings.get("appId", authData.domain);
|
|
||||||
|
|
||||||
if (!appId?.length) {
|
|
||||||
return {
|
|
||||||
errors: [
|
|
||||||
{
|
|
||||||
message: "Missing App ID to the Algolia API. Please, configure the application first.",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
const indexNamePrefix = (await settings.get("indexNamePrefix", authData.domain)) || "";
|
|
||||||
|
|
||||||
debug("Configuration fetched");
|
|
||||||
return {
|
|
||||||
settings: {
|
|
||||||
appId,
|
|
||||||
secretKey,
|
|
||||||
indexNamePrefix,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
} catch (error) {
|
|
||||||
debug("Unexpected error during fetching the configuration");
|
|
||||||
if (error instanceof Error) {
|
|
||||||
debug(error.message);
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
errors: [{ message: "Couldn't fetch the settings from the API" }],
|
|
||||||
};
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,84 +0,0 @@
|
||||||
import { EncryptedMetadataManager, MetadataEntry, SettingsManager } from "@saleor/app-sdk/settings-manager";
|
|
||||||
|
|
||||||
import { FetchAppDetailsDocument, FetchAppDetailsQuery, UpdateAppMetadataDocument } from "../../generated/graphql";
|
|
||||||
import { settingsManagerSecretKey } from "../../saleor-app";
|
|
||||||
import { SimpleGraphqlClient } from "./graphql";
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Function is using urql graphql client to fetch all available metadata.
|
|
||||||
* Before returning query result, we are transforming response to list of objects with key and value fields
|
|
||||||
* which can be used by the manager.
|
|
||||||
* Result of this query is cached by the manager.
|
|
||||||
*/
|
|
||||||
export async function fetchAllMetadata(client: SimpleGraphqlClient): Promise<MetadataEntry[]> {
|
|
||||||
const { error, data } = await client
|
|
||||||
.query<FetchAppDetailsQuery>(FetchAppDetailsDocument, {})
|
|
||||||
.toPromise();
|
|
||||||
|
|
||||||
if (error) {
|
|
||||||
console.debug("Error during fetching the metadata: ", error);
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
return data?.app?.privateMetadata.map((md) => ({ key: md.key, value: md.value })) || [];
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Mutate function takes urql client and metadata entries, and construct mutation to the API.
|
|
||||||
* Before data are send, additional query for required App ID is made.
|
|
||||||
* The manager will use updated entries returned by this mutation to update it's cache.
|
|
||||||
*/
|
|
||||||
export async function mutateMetadata(client: SimpleGraphqlClient, metadata: MetadataEntry[]) {
|
|
||||||
// to update the metadata, ID is required
|
|
||||||
const { error: idQueryError, data: idQueryData } = await client
|
|
||||||
.query(FetchAppDetailsDocument, {})
|
|
||||||
.toPromise();
|
|
||||||
|
|
||||||
if (idQueryError) {
|
|
||||||
console.debug("Could not fetch the app id: ", idQueryError);
|
|
||||||
throw new Error(
|
|
||||||
"Could not fetch the app id. Please check if auth data for the client are valid."
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const appId = idQueryData?.app?.id;
|
|
||||||
|
|
||||||
if (!appId) {
|
|
||||||
console.debug("Missing app id");
|
|
||||||
throw new Error("Could not fetch the app ID");
|
|
||||||
}
|
|
||||||
|
|
||||||
const { error: mutationError, data: mutationData } = await client
|
|
||||||
.mutation(UpdateAppMetadataDocument, {
|
|
||||||
id: appId,
|
|
||||||
input: metadata,
|
|
||||||
})
|
|
||||||
.toPromise();
|
|
||||||
|
|
||||||
if (mutationError) {
|
|
||||||
console.debug("Mutation error: ", mutationError);
|
|
||||||
throw new Error(`Mutation error: ${mutationError.message}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
mutationData?.updatePrivateMetadata?.item?.privateMetadata.map((md) => ({
|
|
||||||
key: md.key,
|
|
||||||
value: md.value,
|
|
||||||
})) || []
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export const createSettingsManager = (client: SimpleGraphqlClient): SettingsManager => {
|
|
||||||
/*
|
|
||||||
* EncryptedMetadataManager gives you interface to manipulate metadata and cache values in memory.
|
|
||||||
* We recommend it for production, because all values are encrypted.
|
|
||||||
* If your use case require plain text values, you can use MetadataManager.
|
|
||||||
*/
|
|
||||||
return new EncryptedMetadataManager({
|
|
||||||
// Secret key should be randomly created for production and set as environment variable
|
|
||||||
encryptionKey: settingsManagerSecretKey,
|
|
||||||
fetchMetadata: () => fetchAllMetadata(client),
|
|
||||||
mutateMetadata: (metadata) => mutateMetadata(client, metadata),
|
|
||||||
});
|
|
||||||
};
|
|
|
@ -1,45 +1,19 @@
|
||||||
import type { NextApiRequest, NextApiResponse } from "next";
|
import type { NextApiRequest, NextApiResponse } from "next";
|
||||||
import { SettingsManager } from "@saleor/app-sdk/settings-manager";
|
|
||||||
|
|
||||||
import { createClient } from "../../lib/graphql";
|
import { createClient } from "../../lib/graphql";
|
||||||
import { createSettingsManager } from "../../lib/metadata";
|
|
||||||
import { saleorApp } from "../../../saleor-app";
|
import { saleorApp } from "../../../saleor-app";
|
||||||
|
|
||||||
import { createProtectedHandler, ProtectedHandlerContext } from "@saleor/app-sdk/handlers/next";
|
import { createProtectedHandler, ProtectedHandlerContext } from "@saleor/app-sdk/handlers/next";
|
||||||
import { createLogger } from "../../lib/logger";
|
import { createLogger } from "../../lib/logger";
|
||||||
import { AppConfigurationFields } from "../../domain/configuration";
|
import { AppConfigurationFields, AppConfigurationSchema } from "../../domain/configuration";
|
||||||
import { AlgoliaSearchProvider } from "../../lib/algolia/algoliaSearchProvider";
|
import { AlgoliaSearchProvider } from "../../lib/algolia/algoliaSearchProvider";
|
||||||
import { WebhookActivityTogglerService } from "../../domain/WebhookActivityToggler.service";
|
import { WebhookActivityTogglerService } from "../../domain/WebhookActivityToggler.service";
|
||||||
|
import { algoliaConfigurationRepository } from "../../domain/algolia-configuration/AlgoliaConfigurationRepository";
|
||||||
|
|
||||||
const logger = createLogger({
|
const logger = createLogger({
|
||||||
handler: "api/configuration",
|
handler: "api/configuration",
|
||||||
});
|
});
|
||||||
|
|
||||||
export interface SettingsApiResponse {
|
|
||||||
success: boolean;
|
|
||||||
data?: AppConfigurationFields;
|
|
||||||
}
|
|
||||||
|
|
||||||
const sendResponse = async (
|
|
||||||
res: NextApiResponse<SettingsApiResponse>,
|
|
||||||
statusCode: number,
|
|
||||||
settings: SettingsManager,
|
|
||||||
domain: string
|
|
||||||
) => {
|
|
||||||
const data = {
|
|
||||||
secretKey: (await settings.get("secretKey", domain)) || "",
|
|
||||||
appId: (await settings.get("appId", domain)) || "",
|
|
||||||
indexNamePrefix: (await settings.get("indexNamePrefix", domain)) || "",
|
|
||||||
};
|
|
||||||
|
|
||||||
logger.debug(data, "Will return following settings");
|
|
||||||
|
|
||||||
res.status(statusCode).json({
|
|
||||||
success: statusCode === 200,
|
|
||||||
data,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
export const handler = async (
|
export const handler = async (
|
||||||
req: NextApiRequest,
|
req: NextApiRequest,
|
||||||
res: NextApiResponse,
|
res: NextApiResponse,
|
||||||
|
@ -53,15 +27,20 @@ export const handler = async (
|
||||||
|
|
||||||
const client = createClient(saleorApiUrl, async () => Promise.resolve({ token: token }));
|
const client = createClient(saleorApiUrl, async () => Promise.resolve({ token: token }));
|
||||||
|
|
||||||
const settings = createSettingsManager(client);
|
// todo extract endpoints, add trpc
|
||||||
|
|
||||||
const domain = new URL(saleorApiUrl).host;
|
|
||||||
|
|
||||||
if (req.method === "GET") {
|
if (req.method === "GET") {
|
||||||
logger.debug("Returning configuration");
|
logger.debug("Returning configuration");
|
||||||
|
|
||||||
await sendResponse(res, 200, settings, domain);
|
const configuration = await algoliaConfigurationRepository.getConfiguration(saleorApiUrl);
|
||||||
return;
|
|
||||||
|
return configuration
|
||||||
|
? res.status(200).send({
|
||||||
|
success: true,
|
||||||
|
data: AppConfigurationSchema.parse(configuration), // todo probably remove Zod at this point
|
||||||
|
})
|
||||||
|
: res.status(404).send({
|
||||||
|
success: false,
|
||||||
|
});
|
||||||
} else if (req.method === "POST") {
|
} else if (req.method === "POST") {
|
||||||
logger.debug("Updating the configuration");
|
logger.debug("Updating the configuration");
|
||||||
|
|
||||||
|
@ -79,11 +58,11 @@ export const handler = async (
|
||||||
|
|
||||||
logger.debug("Algolia connection is ok. Will save settings");
|
logger.debug("Algolia connection is ok. Will save settings");
|
||||||
|
|
||||||
await settings.set([
|
const configuration = await algoliaConfigurationRepository.setConfiguration(saleorApiUrl, {
|
||||||
{ key: "secretKey", value: secretKey || "", domain },
|
appId,
|
||||||
{ key: "appId", value: appId || "", domain },
|
secretKey,
|
||||||
{ key: "indexNamePrefix", value: indexNamePrefix || "", domain },
|
indexNamePrefix,
|
||||||
]);
|
});
|
||||||
|
|
||||||
logger.debug("Settings set");
|
logger.debug("Settings set");
|
||||||
|
|
||||||
|
@ -92,13 +71,14 @@ export const handler = async (
|
||||||
await webhooksToggler.enableOwnWebhooks();
|
await webhooksToggler.enableOwnWebhooks();
|
||||||
|
|
||||||
logger.debug("Webhooks enabled");
|
logger.debug("Webhooks enabled");
|
||||||
|
|
||||||
|
return res.status(200).send({
|
||||||
|
success: true,
|
||||||
|
data: AppConfigurationSchema.parse(configuration), // todo probably remove Zod at this point
|
||||||
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return res.status(400).end();
|
return res.status(400).end();
|
||||||
}
|
}
|
||||||
|
|
||||||
await sendResponse(res, 200, settings, domain);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
logger.error("Method not supported");
|
logger.error("Method not supported");
|
||||||
|
|
||||||
|
|
18
apps/search/src/pages/api/index-products.ts
Normal file
18
apps/search/src/pages/api/index-products.ts
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
import { createProtectedHandler } from "@saleor/app-sdk/handlers/next";
|
||||||
|
import { saleorApp } from "../../../saleor-app";
|
||||||
|
import { runIndexSaleorProducts } from "../../worker/index-saleor-products/index-saleor-products";
|
||||||
|
|
||||||
|
export default createProtectedHandler(
|
||||||
|
async (req, res, ctx) => {
|
||||||
|
const job = await runIndexSaleorProducts({
|
||||||
|
saleorApiUrl: ctx.authData.saleorApiUrl,
|
||||||
|
}); //todo handle error
|
||||||
|
|
||||||
|
console.log("Added job");
|
||||||
|
console.log(job.id);
|
||||||
|
|
||||||
|
return res.status(200).end();
|
||||||
|
},
|
||||||
|
saleorApp.apl,
|
||||||
|
["MANAGE_APPS", "MANAGE_PRODUCTS"]
|
||||||
|
);
|
10
apps/search/src/pages/api/jobs.ts
Normal file
10
apps/search/src/pages/api/jobs.ts
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
import { createProtectedHandler } from "@saleor/app-sdk/handlers/next";
|
||||||
|
import { saleorApp } from "../../../saleor-app";
|
||||||
|
|
||||||
|
export default createProtectedHandler(
|
||||||
|
async (req, res) => {
|
||||||
|
// todo https://github.com/graphile/worker/issues/330
|
||||||
|
},
|
||||||
|
saleorApp.apl,
|
||||||
|
["MANAGE_APPS"]
|
||||||
|
);
|
|
@ -3,15 +3,16 @@ import { saleorApp } from "../../../saleor-app";
|
||||||
import { createClient, SimpleGraphqlClient } from "../../lib/graphql";
|
import { createClient, SimpleGraphqlClient } from "../../lib/graphql";
|
||||||
import { FetchOwnWebhooksDocument } from "../../../generated/graphql";
|
import { FetchOwnWebhooksDocument } from "../../../generated/graphql";
|
||||||
import { AlgoliaSearchProvider } from "../../lib/algolia/algoliaSearchProvider";
|
import { AlgoliaSearchProvider } from "../../lib/algolia/algoliaSearchProvider";
|
||||||
import { createSettingsManager } from "../../lib/metadata";
|
|
||||||
import {
|
import {
|
||||||
IWebhookActivityTogglerService,
|
IWebhookActivityTogglerService,
|
||||||
WebhookActivityTogglerService,
|
WebhookActivityTogglerService,
|
||||||
} from "../../domain/WebhookActivityToggler.service";
|
} from "../../domain/WebhookActivityToggler.service";
|
||||||
import { createLogger } from "../../lib/logger";
|
import { createLogger } from "../../lib/logger";
|
||||||
import { SettingsManager } from "@saleor/app-sdk/settings-manager";
|
|
||||||
import { Client } from "urql";
|
|
||||||
import { SearchProvider } from "../../lib/searchProvider";
|
import { SearchProvider } from "../../lib/searchProvider";
|
||||||
|
import {
|
||||||
|
AlgoliaConfigurationRepository,
|
||||||
|
algoliaConfigurationRepository,
|
||||||
|
} from "../../domain/algolia-configuration/AlgoliaConfigurationRepository";
|
||||||
|
|
||||||
const logger = createLogger({
|
const logger = createLogger({
|
||||||
service: "webhooksStatusHandler",
|
service: "webhooksStatusHandler",
|
||||||
|
@ -21,7 +22,7 @@ const logger = createLogger({
|
||||||
* Simple dependency injection - factory injects all services, in tests everything can be configured without mocks
|
* Simple dependency injection - factory injects all services, in tests everything can be configured without mocks
|
||||||
*/
|
*/
|
||||||
type FactoryProps = {
|
type FactoryProps = {
|
||||||
settingsManagerFactory: (client: SimpleGraphqlClient) => SettingsManager;
|
algoliaConfigurationRepository: Pick<AlgoliaConfigurationRepository, "getConfiguration">;
|
||||||
webhookActivityTogglerFactory: (
|
webhookActivityTogglerFactory: (
|
||||||
appId: string,
|
appId: string,
|
||||||
client: SimpleGraphqlClient
|
client: SimpleGraphqlClient
|
||||||
|
@ -32,7 +33,7 @@ type FactoryProps = {
|
||||||
|
|
||||||
export const webhooksStatusHandlerFactory =
|
export const webhooksStatusHandlerFactory =
|
||||||
({
|
({
|
||||||
settingsManagerFactory,
|
algoliaConfigurationRepository,
|
||||||
webhookActivityTogglerFactory,
|
webhookActivityTogglerFactory,
|
||||||
algoliaSearchProviderFactory,
|
algoliaSearchProviderFactory,
|
||||||
graphqlClientFactory,
|
graphqlClientFactory,
|
||||||
|
@ -43,25 +44,17 @@ export const webhooksStatusHandlerFactory =
|
||||||
*/
|
*/
|
||||||
const client = graphqlClientFactory(authData.saleorApiUrl, authData.token);
|
const client = graphqlClientFactory(authData.saleorApiUrl, authData.token);
|
||||||
const webhooksToggler = webhookActivityTogglerFactory(authData.appId, client);
|
const webhooksToggler = webhookActivityTogglerFactory(authData.appId, client);
|
||||||
const settingsManager = settingsManagerFactory(client);
|
|
||||||
|
|
||||||
const domain = new URL(authData.saleorApiUrl).host;
|
const configuration = await algoliaConfigurationRepository.getConfiguration(
|
||||||
|
authData.saleorApiUrl
|
||||||
const [secretKey, appId] = await Promise.all([
|
);
|
||||||
settingsManager.get("secretKey", domain),
|
|
||||||
settingsManager.get("appId", domain),
|
|
||||||
]);
|
|
||||||
|
|
||||||
const settings = { secretKey, appId };
|
|
||||||
|
|
||||||
logger.debug(settings, "fetched settings");
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If settings are incomplete, disable webhooks
|
* If settings are incomplete, disable webhooks
|
||||||
*
|
*
|
||||||
* TODO Extract config operations to domain/
|
* TODO Extract config operations to domain/
|
||||||
*/
|
*/
|
||||||
if (!settings.appId || !settings.secretKey) {
|
if (!configuration) {
|
||||||
logger.debug("Settings not set, will disable webhooks");
|
logger.debug("Settings not set, will disable webhooks");
|
||||||
|
|
||||||
await webhooksToggler.disableOwnWebhooks();
|
await webhooksToggler.disableOwnWebhooks();
|
||||||
|
@ -69,7 +62,10 @@ export const webhooksStatusHandlerFactory =
|
||||||
/**
|
/**
|
||||||
* Otherwise, if settings are set, check in Algolia if tokens are valid
|
* Otherwise, if settings are set, check in Algolia if tokens are valid
|
||||||
*/
|
*/
|
||||||
const algoliaService = algoliaSearchProviderFactory(settings.appId, settings.secretKey);
|
const algoliaService = algoliaSearchProviderFactory(
|
||||||
|
configuration.appId,
|
||||||
|
configuration.secretKey
|
||||||
|
);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
logger.debug("Settings set, will ping Algolia");
|
logger.debug("Settings set, will ping Algolia");
|
||||||
|
@ -105,7 +101,7 @@ export const webhooksStatusHandlerFactory =
|
||||||
|
|
||||||
export default createProtectedHandler(
|
export default createProtectedHandler(
|
||||||
webhooksStatusHandlerFactory({
|
webhooksStatusHandlerFactory({
|
||||||
settingsManagerFactory: createSettingsManager,
|
algoliaConfigurationRepository: algoliaConfigurationRepository,
|
||||||
webhookActivityTogglerFactory: function (appId, client) {
|
webhookActivityTogglerFactory: function (appId, client) {
|
||||||
return new WebhookActivityTogglerService(appId, client);
|
return new WebhookActivityTogglerService(appId, client);
|
||||||
},
|
},
|
||||||
|
|
|
@ -41,15 +41,17 @@ export const handler: NextWebhookApiHandler<ProductCreated> = async (req, res, c
|
||||||
logger.warn("Aborting due to lack of settings");
|
logger.warn("Aborting due to lack of settings");
|
||||||
logger.debug(errors);
|
logger.debug(errors);
|
||||||
|
|
||||||
|
const error = (errors && errors[0] && errors[0].message) ?? "Unknown error";
|
||||||
|
|
||||||
return res.status(400).json({
|
return res.status(400).json({
|
||||||
message: errors[0].message,
|
message: error,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const searchProvider = new AlgoliaSearchProvider({
|
const searchProvider = new AlgoliaSearchProvider({
|
||||||
appId: settings.appId,
|
appId: settings.appId,
|
||||||
apiKey: settings.secretKey,
|
apiKey: settings.secretKey,
|
||||||
indexNamePrefix: settings.indexNamePrefix,
|
indexNamePrefix: settings.indexNamePrefix ?? undefined,
|
||||||
});
|
});
|
||||||
|
|
||||||
const { product } = context.payload;
|
const { product } = context.payload;
|
||||||
|
|
|
@ -42,15 +42,17 @@ export const handler: NextWebhookApiHandler<ProductDeleted> = async (req, res, c
|
||||||
logger.warn("Aborting due to lack of settings");
|
logger.warn("Aborting due to lack of settings");
|
||||||
logger.debug(errors);
|
logger.debug(errors);
|
||||||
|
|
||||||
|
const error = (errors && errors[0] && errors[0].message) ?? "Unknown error";
|
||||||
|
|
||||||
return res.status(400).json({
|
return res.status(400).json({
|
||||||
message: errors[0].message,
|
message: error,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const searchProvider = new AlgoliaSearchProvider({
|
const searchProvider = new AlgoliaSearchProvider({
|
||||||
appId: settings.appId,
|
appId: settings.appId,
|
||||||
apiKey: settings.secretKey,
|
apiKey: settings.secretKey,
|
||||||
indexNamePrefix: settings.indexNamePrefix,
|
indexNamePrefix: settings.indexNamePrefix ?? undefined,
|
||||||
});
|
});
|
||||||
|
|
||||||
const { product } = context.payload;
|
const { product } = context.payload;
|
||||||
|
|
|
@ -41,15 +41,17 @@ export const handler: NextWebhookApiHandler<ProductUpdated> = async (req, res, c
|
||||||
logger.warn("Aborting due to lack of settings");
|
logger.warn("Aborting due to lack of settings");
|
||||||
logger.debug(errors);
|
logger.debug(errors);
|
||||||
|
|
||||||
|
const error = (errors && errors[0] && errors[0].message) ?? "Unknown error";
|
||||||
|
|
||||||
return res.status(400).json({
|
return res.status(400).json({
|
||||||
message: errors[0].message,
|
message: error,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const searchProvider = new AlgoliaSearchProvider({
|
const searchProvider = new AlgoliaSearchProvider({
|
||||||
appId: settings.appId,
|
appId: settings.appId,
|
||||||
apiKey: settings.secretKey,
|
apiKey: settings.secretKey,
|
||||||
indexNamePrefix: settings.indexNamePrefix,
|
indexNamePrefix: settings.indexNamePrefix ?? undefined,
|
||||||
});
|
});
|
||||||
|
|
||||||
const { product } = context.payload;
|
const { product } = context.payload;
|
||||||
|
|
|
@ -44,15 +44,17 @@ export const handler: NextWebhookApiHandler<ProductVariantCreated> = async (req,
|
||||||
if (errors?.length || !settings) {
|
if (errors?.length || !settings) {
|
||||||
logger.warn("Aborting due to lack of settings");
|
logger.warn("Aborting due to lack of settings");
|
||||||
logger.debug(errors);
|
logger.debug(errors);
|
||||||
|
const error = (errors && errors[0] && errors[0].message) ?? "Unknown error";
|
||||||
|
|
||||||
return res.status(400).json({
|
return res.status(400).json({
|
||||||
message: errors[0].message,
|
message: error,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const searchProvider = new AlgoliaSearchProvider({
|
const searchProvider = new AlgoliaSearchProvider({
|
||||||
appId: settings.appId,
|
appId: settings.appId,
|
||||||
apiKey: settings.secretKey,
|
apiKey: settings.secretKey,
|
||||||
indexNamePrefix: settings.indexNamePrefix,
|
indexNamePrefix: settings.indexNamePrefix ?? undefined,
|
||||||
});
|
});
|
||||||
|
|
||||||
const { productVariant } = context.payload;
|
const { productVariant } = context.payload;
|
||||||
|
|
|
@ -45,15 +45,17 @@ export const handler: NextWebhookApiHandler<ProductVariantDeleted> = async (req,
|
||||||
logger.warn("Aborting due to lack of settings");
|
logger.warn("Aborting due to lack of settings");
|
||||||
logger.debug(errors);
|
logger.debug(errors);
|
||||||
|
|
||||||
|
const error = (errors && errors[0] && errors[0].message) ?? "Unknown error";
|
||||||
|
|
||||||
return res.status(400).json({
|
return res.status(400).json({
|
||||||
message: errors[0].message,
|
message: error,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const searchProvider = new AlgoliaSearchProvider({
|
const searchProvider = new AlgoliaSearchProvider({
|
||||||
appId: settings.appId,
|
appId: settings.appId,
|
||||||
apiKey: settings.secretKey,
|
apiKey: settings.secretKey,
|
||||||
indexNamePrefix: settings.indexNamePrefix,
|
indexNamePrefix: settings.indexNamePrefix ?? undefined,
|
||||||
});
|
});
|
||||||
|
|
||||||
const { productVariant } = context.payload;
|
const { productVariant } = context.payload;
|
||||||
|
|
|
@ -45,15 +45,17 @@ export const handler: NextWebhookApiHandler<ProductVariantUpdated> = async (req,
|
||||||
logger.warn("Aborting due to lack of settings");
|
logger.warn("Aborting due to lack of settings");
|
||||||
logger.debug(errors);
|
logger.debug(errors);
|
||||||
|
|
||||||
|
const error = (errors && errors[0] && errors[0].message) ?? "Unknown error";
|
||||||
|
|
||||||
return res.status(400).json({
|
return res.status(400).json({
|
||||||
message: errors[0].message,
|
message: error,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const searchProvider = new AlgoliaSearchProvider({
|
const searchProvider = new AlgoliaSearchProvider({
|
||||||
appId: settings.appId,
|
appId: settings.appId,
|
||||||
apiKey: settings.secretKey,
|
apiKey: settings.secretKey,
|
||||||
indexNamePrefix: settings.indexNamePrefix,
|
indexNamePrefix: settings.indexNamePrefix ?? undefined,
|
||||||
});
|
});
|
||||||
|
|
||||||
const { productVariant } = context.payload;
|
const { productVariant } = context.payload;
|
||||||
|
|
|
@ -0,0 +1,93 @@
|
||||||
|
import { saleorApp } from "../../../saleor-app";
|
||||||
|
import { createClient } from "../../lib/graphql";
|
||||||
|
import { algoliaConfigurationRepository } from "../../domain/algolia-configuration/AlgoliaConfigurationRepository";
|
||||||
|
import { AlgoliaSearchProvider } from "../../lib/algolia/algoliaSearchProvider";
|
||||||
|
import {
|
||||||
|
ChannelsDocument,
|
||||||
|
ProductsDataForImportDocument,
|
||||||
|
ProductsDataForImportQuery,
|
||||||
|
} from "../../../generated/graphql";
|
||||||
|
import { Client } from "urql";
|
||||||
|
|
||||||
|
export type Products = NonNullable<
|
||||||
|
ProductsDataForImportQuery["products"]
|
||||||
|
>["edges"][number]["node"][];
|
||||||
|
|
||||||
|
const getChannels = (client: Client) => client.query(ChannelsDocument, {}).toPromise();
|
||||||
|
|
||||||
|
const PER_PAGE = 100;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO - refactor and split into small tested chunks, not a scope of a POC
|
||||||
|
*/
|
||||||
|
export const getProductsAndSendToAlgolia = async (saleorApiUrl: string) => {
|
||||||
|
let products: Products = [];
|
||||||
|
|
||||||
|
const authData = await saleorApp.apl.get(saleorApiUrl);
|
||||||
|
|
||||||
|
if (!authData) {
|
||||||
|
throw new Error();
|
||||||
|
}
|
||||||
|
|
||||||
|
const client = createClient(authData.saleorApiUrl, async () => ({
|
||||||
|
token: authData.token,
|
||||||
|
}));
|
||||||
|
|
||||||
|
const getProducts = async (channelSlug: string, cursor: string): Promise<void> => {
|
||||||
|
const response = await client
|
||||||
|
.query(ProductsDataForImportDocument, {
|
||||||
|
after: cursor,
|
||||||
|
first: PER_PAGE,
|
||||||
|
channel: channelSlug!,
|
||||||
|
})
|
||||||
|
.toPromise();
|
||||||
|
|
||||||
|
const newProducts = response?.data?.products?.edges.map((e) => e.node) ?? [];
|
||||||
|
|
||||||
|
if (newProducts.length > 0) {
|
||||||
|
products = [...products, ...newProducts];
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
response?.data?.products?.pageInfo.hasNextPage &&
|
||||||
|
response?.data?.products?.pageInfo.endCursor
|
||||||
|
) {
|
||||||
|
// get next page of products
|
||||||
|
return getProducts(channelSlug, response.data.products?.pageInfo.endCursor);
|
||||||
|
} else {
|
||||||
|
// do nothing
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
await (async () => {
|
||||||
|
const channels = await getChannels(client);
|
||||||
|
// get all products for each channel
|
||||||
|
|
||||||
|
await channels.data?.channels?.reduce(async (acc, channel) => {
|
||||||
|
await acc;
|
||||||
|
await getProducts(channel.slug, "");
|
||||||
|
}, Promise.resolve());
|
||||||
|
})();
|
||||||
|
|
||||||
|
const configuration = await algoliaConfigurationRepository.getConfiguration(
|
||||||
|
authData.saleorApiUrl
|
||||||
|
); // todo handle error
|
||||||
|
|
||||||
|
const algolia = new AlgoliaSearchProvider({
|
||||||
|
appId: configuration!.appId,
|
||||||
|
apiKey: configuration!.secretKey,
|
||||||
|
indexNamePrefix: configuration!.indexNamePrefix ?? undefined,
|
||||||
|
});
|
||||||
|
|
||||||
|
let currentProductIndex = 0;
|
||||||
|
|
||||||
|
await (async () => {
|
||||||
|
const productsBatchStartIndex = currentProductIndex;
|
||||||
|
const productsBatchEndIndex = Math.min(currentProductIndex + PER_PAGE, products.length);
|
||||||
|
const productsBatch = products.slice(productsBatchStartIndex, productsBatchEndIndex);
|
||||||
|
|
||||||
|
await algolia.updatedBatchProducts(productsBatch);
|
||||||
|
|
||||||
|
currentProductIndex = productsBatchEndIndex;
|
||||||
|
})();
|
||||||
|
};
|
|
@ -0,0 +1,42 @@
|
||||||
|
import { Task } from "graphile-worker/dist/interfaces";
|
||||||
|
import { z } from "zod";
|
||||||
|
import { getProductsAndSendToAlgolia } from "./get-products-and-send-to-algolia";
|
||||||
|
import { getWorkerUtils } from "../worker-utils";
|
||||||
|
|
||||||
|
const payloadSchema = z.object({
|
||||||
|
saleorApiUrl: z.string().url(),
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO Is it secure to pass only saleorApiUrl
|
||||||
|
*
|
||||||
|
* TODO Refactor to extract all product fetching etc
|
||||||
|
*/
|
||||||
|
export const IndexSaleorProducts: Task = async (payload, helpers) => {
|
||||||
|
/**
|
||||||
|
* Parse payload - in graphile its always unknown, so its a good place to ensure its correct
|
||||||
|
*/
|
||||||
|
const typedPayload = payloadSchema.parse(payload);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform some business logic
|
||||||
|
*/
|
||||||
|
await getProductsAndSendToAlgolia(typedPayload.saleorApiUrl);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const IndexSaleorProductsJobName = "IndexSaleorProducts";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Factory that pushed job to the worker
|
||||||
|
*
|
||||||
|
* https://github.com/graphile/worker#makeworkerutilsoptions-workerutilsoptions-promiseworkerutils
|
||||||
|
*/
|
||||||
|
export const runIndexSaleorProducts = async (payload: z.infer<typeof payloadSchema>) => {
|
||||||
|
const utils = await getWorkerUtils();
|
||||||
|
|
||||||
|
await utils.migrate();
|
||||||
|
|
||||||
|
return utils.addJob(IndexSaleorProductsJobName, payload).finally(() => {
|
||||||
|
return utils.release();
|
||||||
|
});
|
||||||
|
};
|
30
apps/search/src/worker/runner.ts
Normal file
30
apps/search/src/worker/runner.ts
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
import { IndexSaleorProducts } from "./index-saleor-products/index-saleor-products";
|
||||||
|
|
||||||
|
require("dotenv").config();
|
||||||
|
const { run } = require("graphile-worker");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* todo probably use another DB so Prisma will not destroy queue?
|
||||||
|
*
|
||||||
|
* how it will expose itself to kubernetes
|
||||||
|
*/
|
||||||
|
async function main() {
|
||||||
|
// Run a worker to execute jobs:
|
||||||
|
const runner = await run({
|
||||||
|
connectionString: process.env.DATABASE_URL as string,
|
||||||
|
concurrency: 5,
|
||||||
|
// Install signal handlers for graceful shutdown on SIGINT, SIGTERM, etc
|
||||||
|
noHandleSignals: false,
|
||||||
|
pollInterval: 1000,
|
||||||
|
taskList: {
|
||||||
|
IndexSaleorProducts,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
await runner.promise;
|
||||||
|
}
|
||||||
|
|
||||||
|
main().catch((err) => {
|
||||||
|
console.error(err);
|
||||||
|
process.exit(1);
|
||||||
|
});
|
18
apps/search/src/worker/worker-utils.ts
Normal file
18
apps/search/src/worker/worker-utils.ts
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
import { makeWorkerUtils, WorkerUtils } from "graphile-worker";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ensure Singleton
|
||||||
|
*/
|
||||||
|
let _workerUtils: WorkerUtils | null = null;
|
||||||
|
|
||||||
|
export const getWorkerUtils = async () => {
|
||||||
|
if (_workerUtils) {
|
||||||
|
return _workerUtils;
|
||||||
|
}
|
||||||
|
|
||||||
|
_workerUtils = await makeWorkerUtils({
|
||||||
|
connectionString: process.env.DATABASE_URL,
|
||||||
|
});
|
||||||
|
|
||||||
|
return _workerUtils;
|
||||||
|
};
|
|
@ -16,5 +16,5 @@
|
||||||
"incremental": true
|
"incremental": true
|
||||||
},
|
},
|
||||||
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
|
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
|
||||||
"exclude": ["node_modules"]
|
"exclude": ["node_modules", "src/worker/runner.ts", "src/worker/worker-utils.ts"]
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,10 @@
|
||||||
"SENTRY_PROJECT",
|
"SENTRY_PROJECT",
|
||||||
"SENTRY_DSN",
|
"SENTRY_DSN",
|
||||||
"SENTRY_ORG",
|
"SENTRY_ORG",
|
||||||
"NEXT_PUBLIC_VERCEL_ENV"
|
"NEXT_PUBLIC_VERCEL_ENV",
|
||||||
|
"DATABASE_URL",
|
||||||
|
"RUN_WORKER_IN_NEXT_PROCESS",
|
||||||
|
"NEXT_RUNTIME"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
23
docker-compose.db.yml
Normal file
23
docker-compose.db.yml
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
# This compose contains only Database required for local development.
|
||||||
|
# App can be run locally without the container
|
||||||
|
#
|
||||||
|
# TODO Include app and worker services for local development with fullstack setup (and prod setup)
|
||||||
|
|
||||||
|
version: '3'
|
||||||
|
|
||||||
|
services:
|
||||||
|
postgres:
|
||||||
|
container_name: search_app_postgres
|
||||||
|
image: postgres # Todo maybe some alpine image?
|
||||||
|
environment:
|
||||||
|
POSTGRES_USER: ${POSTGRES_USER:-postgres}
|
||||||
|
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-postgres}
|
||||||
|
PGDATA: /data/postgres
|
||||||
|
volumes:
|
||||||
|
- postgres:/data/postgres
|
||||||
|
ports:
|
||||||
|
- "5432:5432"
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
postgres:
|
57
docker-compose.search.prod.yml
Normal file
57
docker-compose.search.prod.yml
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
version: '3'
|
||||||
|
|
||||||
|
services:
|
||||||
|
postgres:
|
||||||
|
container_name: search_app_postgres
|
||||||
|
image: postgres # Todo maybe some alpine image?
|
||||||
|
environment:
|
||||||
|
POSTGRES_USER: ${POSTGRES_USER:-postgres}
|
||||||
|
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-postgres}
|
||||||
|
PGDATA: /data/postgres
|
||||||
|
volumes:
|
||||||
|
- postgres:/data/postgres
|
||||||
|
ports:
|
||||||
|
- "5432:5432"
|
||||||
|
restart: unless-stopped
|
||||||
|
networks:
|
||||||
|
- saleor-app-search
|
||||||
|
saleor-app-search:
|
||||||
|
container_name: saleor-app-search
|
||||||
|
depends_on:
|
||||||
|
- postgres
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: apps/search/app.prod.Dockerfile
|
||||||
|
args:
|
||||||
|
DATABASE_URL: "postgres://postgres:postgres@postgres/postgres"
|
||||||
|
environment:
|
||||||
|
APP_DEBUG: "info"
|
||||||
|
DATABASE_URL: "postgres://postgres:postgres@postgres/postgres"
|
||||||
|
restart: always
|
||||||
|
# command: TODO
|
||||||
|
# - npx prisma migrate deploy
|
||||||
|
# - node apps/search/server.js
|
||||||
|
# entrypoint: ["/bin/bash", "./apps/search/run-app.sh"]
|
||||||
|
ports:
|
||||||
|
- 3000:3000
|
||||||
|
networks:
|
||||||
|
- saleor-app-search
|
||||||
|
# saleor-app-search-worker:
|
||||||
|
# container_name: saleor-app-search-worker
|
||||||
|
# depends_on:
|
||||||
|
# - postgres
|
||||||
|
# build:
|
||||||
|
# context: . # In examples its ./next-app, we can do that too todo
|
||||||
|
# dockerfile: worker.prod.Dockerfile
|
||||||
|
# environment:
|
||||||
|
# DATABASE_URL: "postgres://postgres:postgres@postgres/postgres"
|
||||||
|
# restart: always
|
||||||
|
# networks:
|
||||||
|
# - saleor-app-search
|
||||||
|
volumes:
|
||||||
|
postgres:
|
||||||
|
|
||||||
|
|
||||||
|
networks:
|
||||||
|
saleor-app-search:
|
||||||
|
driver: bridge
|
446
pnpm-lock.yaml
446
pnpm-lock.yaml
|
@ -1170,6 +1170,9 @@ importers:
|
||||||
'@hookform/resolvers':
|
'@hookform/resolvers':
|
||||||
specifier: ^3.1.0
|
specifier: ^3.1.0
|
||||||
version: 3.1.0(react-hook-form@7.43.9)
|
version: 3.1.0(react-hook-form@7.43.9)
|
||||||
|
'@prisma/client':
|
||||||
|
specifier: ^4.15.0
|
||||||
|
version: 4.15.0(prisma@4.15.0)
|
||||||
'@saleor/app-sdk':
|
'@saleor/app-sdk':
|
||||||
specifier: 0.39.1
|
specifier: 0.39.1
|
||||||
version: 0.39.1(next@13.3.0)(react-dom@18.2.0)(react@18.2.0)
|
version: 0.39.1(next@13.3.0)(react-dom@18.2.0)(react@18.2.0)
|
||||||
|
@ -1203,6 +1206,12 @@ importers:
|
||||||
debug:
|
debug:
|
||||||
specifier: ^4.3.4
|
specifier: ^4.3.4
|
||||||
version: 4.3.4
|
version: 4.3.4
|
||||||
|
dotenv:
|
||||||
|
specifier: ^16.1.4
|
||||||
|
version: 16.1.4
|
||||||
|
graphile-worker:
|
||||||
|
specifier: ^0.13.0
|
||||||
|
version: 0.13.0
|
||||||
graphql:
|
graphql:
|
||||||
specifier: 16.6.0
|
specifier: 16.6.0
|
||||||
version: 16.6.0
|
version: 16.6.0
|
||||||
|
@ -1221,6 +1230,9 @@ importers:
|
||||||
pino-pretty:
|
pino-pretty:
|
||||||
specifier: ^10.0.0
|
specifier: ^10.0.0
|
||||||
version: 10.0.0
|
version: 10.0.0
|
||||||
|
prisma:
|
||||||
|
specifier: ^4.15.0
|
||||||
|
version: 4.15.0
|
||||||
react:
|
react:
|
||||||
specifier: 18.2.0
|
specifier: 18.2.0
|
||||||
version: 18.2.0
|
version: 18.2.0
|
||||||
|
@ -1279,6 +1291,9 @@ importers:
|
||||||
'@vitejs/plugin-react':
|
'@vitejs/plugin-react':
|
||||||
specifier: 4.0.0
|
specifier: 4.0.0
|
||||||
version: 4.0.0(vite@4.3.9)
|
version: 4.0.0(vite@4.3.9)
|
||||||
|
concurrently:
|
||||||
|
specifier: ^8.1.0
|
||||||
|
version: 8.1.0
|
||||||
eslint:
|
eslint:
|
||||||
specifier: 8.42.0
|
specifier: 8.42.0
|
||||||
version: 8.42.0
|
version: 8.42.0
|
||||||
|
@ -1288,6 +1303,12 @@ importers:
|
||||||
node-mocks-http:
|
node-mocks-http:
|
||||||
specifier: ^1.12.2
|
specifier: ^1.12.2
|
||||||
version: 1.12.2
|
version: 1.12.2
|
||||||
|
tsup:
|
||||||
|
specifier: ^6.7.0
|
||||||
|
version: 6.7.0(typescript@5.1.3)
|
||||||
|
tsx:
|
||||||
|
specifier: ^3.12.7
|
||||||
|
version: 3.12.7
|
||||||
typescript:
|
typescript:
|
||||||
specifier: 5.1.3
|
specifier: 5.1.3
|
||||||
version: 5.1.3
|
version: 5.1.3
|
||||||
|
@ -4921,6 +4942,27 @@ packages:
|
||||||
resolution: {integrity: sha512-AHPmaAx+RYfZz0eYu6Gviiagpmiyw98ySSlQvCUhVGDRtDFe4DBS0x1bSjdF3gqUDYOczB+yYvBTtEylYSdRhg==}
|
resolution: {integrity: sha512-AHPmaAx+RYfZz0eYu6Gviiagpmiyw98ySSlQvCUhVGDRtDFe4DBS0x1bSjdF3gqUDYOczB+yYvBTtEylYSdRhg==}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/@esbuild-kit/cjs-loader@2.4.2:
|
||||||
|
resolution: {integrity: sha512-BDXFbYOJzT/NBEtp71cvsrGPwGAMGRB/349rwKuoxNSiKjPraNNnlK6MIIabViCjqZugu6j+xeMDlEkWdHHJSg==}
|
||||||
|
dependencies:
|
||||||
|
'@esbuild-kit/core-utils': 3.1.0
|
||||||
|
get-tsconfig: 4.4.0
|
||||||
|
dev: true
|
||||||
|
|
||||||
|
/@esbuild-kit/core-utils@3.1.0:
|
||||||
|
resolution: {integrity: sha512-Uuk8RpCg/7fdHSceR1M6XbSZFSuMrxcePFuGgyvsBn+u339dk5OeL4jv2EojwTN2st/unJGsVm4qHWjWNmJ/tw==}
|
||||||
|
dependencies:
|
||||||
|
esbuild: 0.17.17
|
||||||
|
source-map-support: 0.5.21
|
||||||
|
dev: true
|
||||||
|
|
||||||
|
/@esbuild-kit/esm-loader@2.5.5:
|
||||||
|
resolution: {integrity: sha512-Qwfvj/qoPbClxCRNuac1Du01r9gvNOT+pMYtJDapfB1eoGN1YlJ1BixLyL9WVENRx5RXgNLdfYdx/CuswlGhMw==}
|
||||||
|
dependencies:
|
||||||
|
'@esbuild-kit/core-utils': 3.1.0
|
||||||
|
get-tsconfig: 4.4.0
|
||||||
|
dev: true
|
||||||
|
|
||||||
/@esbuild/android-arm64@0.17.17:
|
/@esbuild/android-arm64@0.17.17:
|
||||||
resolution: {integrity: sha512-jaJ5IlmaDLFPNttv0ofcwy/cfeY4bh/n705Tgh+eLObbGtQBK3EPAu+CzL95JVE4nFAliyrnEu0d32Q5foavqg==}
|
resolution: {integrity: sha512-jaJ5IlmaDLFPNttv0ofcwy/cfeY4bh/n705Tgh+eLObbGtQBK3EPAu+CzL95JVE4nFAliyrnEu0d32Q5foavqg==}
|
||||||
engines: {node: '>=12'}
|
engines: {node: '>=12'}
|
||||||
|
@ -5440,6 +5482,10 @@ packages:
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- '@types/react'
|
- '@types/react'
|
||||||
|
|
||||||
|
/@graphile/logger@0.2.0:
|
||||||
|
resolution: {integrity: sha512-jjcWBokl9eb1gVJ85QmoaQ73CQ52xAaOCF29ukRbYNl6lY+ts0ErTaDYOBlejcbUs2OpaiqYLO5uDhyLFzWw4w==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/@graphql-codegen/cli@3.2.2(@babel/core@7.22.1)(@types/node@18.15.3)(graphql@16.6.0):
|
/@graphql-codegen/cli@3.2.2(@babel/core@7.22.1)(@types/node@18.15.3)(graphql@16.6.0):
|
||||||
resolution: {integrity: sha512-u+dm/SW1heLnUL4Tyf5Uv0AxOFhTCmUPHKwRLq2yE8MPhv7+Ti4vxxUP/XGoaMNRuHlN37wLI7tpFLV1Hhm22Q==}
|
resolution: {integrity: sha512-u+dm/SW1heLnUL4Tyf5Uv0AxOFhTCmUPHKwRLq2yE8MPhv7+Ti4vxxUP/XGoaMNRuHlN37wLI7tpFLV1Hhm22Q==}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
@ -5930,7 +5976,7 @@ packages:
|
||||||
'@types/jsonwebtoken': 9.0.1
|
'@types/jsonwebtoken': 9.0.1
|
||||||
chalk: 4.1.2
|
chalk: 4.1.2
|
||||||
debug: 4.3.4
|
debug: 4.3.4
|
||||||
dotenv: 16.0.3
|
dotenv: 16.1.4
|
||||||
graphql: 16.6.0
|
graphql: 16.6.0
|
||||||
graphql-request: 5.2.0(graphql@16.6.0)
|
graphql-request: 5.2.0(graphql@16.6.0)
|
||||||
http-proxy-agent: 5.0.0
|
http-proxy-agent: 5.0.0
|
||||||
|
@ -6768,6 +6814,29 @@ packages:
|
||||||
resolution: {integrity: sha512-50/17A98tWUfQ176raKiOGXuYpLyyVMkxxG6oylzL3BPOlA6ADGdK7EYunSa4I064xerltq9TGXs8HmOk5E+vw==}
|
resolution: {integrity: sha512-50/17A98tWUfQ176raKiOGXuYpLyyVMkxxG6oylzL3BPOlA6ADGdK7EYunSa4I064xerltq9TGXs8HmOk5E+vw==}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/@prisma/client@4.15.0(prisma@4.15.0):
|
||||||
|
resolution: {integrity: sha512-xnROvyABcGiwqRNdrObHVZkD9EjkJYHOmVdlKy1yGgI+XOzvMzJ4tRg3dz1pUlsyhKxXGCnjIQjWW+2ur+YXuw==}
|
||||||
|
engines: {node: '>=14.17'}
|
||||||
|
requiresBuild: true
|
||||||
|
peerDependencies:
|
||||||
|
prisma: '*'
|
||||||
|
peerDependenciesMeta:
|
||||||
|
prisma:
|
||||||
|
optional: true
|
||||||
|
dependencies:
|
||||||
|
'@prisma/engines-version': 4.15.0-28.8fbc245156db7124f997f4cecdd8d1219e360944
|
||||||
|
prisma: 4.15.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/@prisma/engines-version@4.15.0-28.8fbc245156db7124f997f4cecdd8d1219e360944:
|
||||||
|
resolution: {integrity: sha512-sVOig4tjGxxlYaFcXgE71f/rtFhzyYrfyfNFUsxCIEJyVKU9rdOWIlIwQ2NQ7PntvGnn+x0XuFo4OC1jvPJKzg==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/@prisma/engines@4.15.0:
|
||||||
|
resolution: {integrity: sha512-FTaOCGs0LL0OW68juZlGxFtYviZa4xdQj/rQEdat2txw0s3Vu/saAPKjNVXfIgUsGXmQ72HPgNr6935/P8FNAA==}
|
||||||
|
requiresBuild: true
|
||||||
|
dev: false
|
||||||
|
|
||||||
/@radix-ui/number@1.0.0:
|
/@radix-ui/number@1.0.0:
|
||||||
resolution: {integrity: sha512-Ofwh/1HX69ZfJRiRBMTy7rgjAzHmwe4kW9C9Y99HTRUcYLUuVT0KESFj15rPjRgKJs20GPq8Bm5aEDJ8DuA3vA==}
|
resolution: {integrity: sha512-Ofwh/1HX69ZfJRiRBMTy7rgjAzHmwe4kW9C9Y99HTRUcYLUuVT0KESFj15rPjRgKJs20GPq8Bm5aEDJ8DuA3vA==}
|
||||||
dependencies:
|
dependencies:
|
||||||
|
@ -9464,7 +9533,7 @@ packages:
|
||||||
engines: {node: '>=12'}
|
engines: {node: '>=12'}
|
||||||
dependencies:
|
dependencies:
|
||||||
'@babel/code-frame': 7.21.4
|
'@babel/code-frame': 7.21.4
|
||||||
'@babel/runtime': 7.20.13
|
'@babel/runtime': 7.22.3
|
||||||
'@types/aria-query': 5.0.1
|
'@types/aria-query': 5.0.1
|
||||||
aria-query: 5.1.3
|
aria-query: 5.1.3
|
||||||
chalk: 4.1.2
|
chalk: 4.1.2
|
||||||
|
@ -9980,6 +10049,14 @@ packages:
|
||||||
/@types/parse-json@4.0.0:
|
/@types/parse-json@4.0.0:
|
||||||
resolution: {integrity: sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==}
|
resolution: {integrity: sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==}
|
||||||
|
|
||||||
|
/@types/pg@8.10.1:
|
||||||
|
resolution: {integrity: sha512-AmEHA/XxMxemQom5iDwP62FYNkv+gDDnetRG7v2N2dPtju7UKI7FknUimcZo7SodKTHtckYPzaTqUEvUKbVJEA==}
|
||||||
|
dependencies:
|
||||||
|
'@types/node': 18.15.3
|
||||||
|
pg-protocol: 1.6.0
|
||||||
|
pg-types: 4.0.1
|
||||||
|
dev: false
|
||||||
|
|
||||||
/@types/pikaday@1.7.4:
|
/@types/pikaday@1.7.4:
|
||||||
resolution: {integrity: sha512-0KsHVyw5pTG829nqG4IRu7m+BFQlFEBdbE/1i3S5182HeKUKv1uEW0gyEmkJVp5i4IV+9pyh23O83+KpRkSQbw==}
|
resolution: {integrity: sha512-0KsHVyw5pTG829nqG4IRu7m+BFQlFEBdbE/1i3S5182HeKUKv1uEW0gyEmkJVp5i4IV+9pyh23O83+KpRkSQbw==}
|
||||||
dependencies:
|
dependencies:
|
||||||
|
@ -10881,6 +10958,10 @@ packages:
|
||||||
engines: {node: '>=12'}
|
engines: {node: '>=12'}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/any-promise@1.3.0:
|
||||||
|
resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==}
|
||||||
|
dev: true
|
||||||
|
|
||||||
/anymatch@3.1.3:
|
/anymatch@3.1.3:
|
||||||
resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==}
|
resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==}
|
||||||
engines: {node: '>= 8'}
|
engines: {node: '>= 8'}
|
||||||
|
@ -11535,6 +11616,11 @@ packages:
|
||||||
engines: {node: '>=0.10'}
|
engines: {node: '>=0.10'}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/buffer-writer@2.0.0:
|
||||||
|
resolution: {integrity: sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw==}
|
||||||
|
engines: {node: '>=4'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/buffer@5.7.1:
|
/buffer@5.7.1:
|
||||||
resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==}
|
resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==}
|
||||||
dependencies:
|
dependencies:
|
||||||
|
@ -11553,6 +11639,16 @@ packages:
|
||||||
engines: {node: '>=0.2.0'}
|
engines: {node: '>=0.2.0'}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/bundle-require@4.0.1(esbuild@0.17.17):
|
||||||
|
resolution: {integrity: sha512-9NQkRHlNdNpDBGmLpngF3EFDcwodhMUuLz9PaWYciVcQF9SE4LFjM2DB/xV1Li5JiuDMv7ZUWuC3rGbqR0MAXQ==}
|
||||||
|
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
|
||||||
|
peerDependencies:
|
||||||
|
esbuild: '>=0.17'
|
||||||
|
dependencies:
|
||||||
|
esbuild: 0.17.17
|
||||||
|
load-tsconfig: 0.2.5
|
||||||
|
dev: true
|
||||||
|
|
||||||
/busboy@1.6.0:
|
/busboy@1.6.0:
|
||||||
resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==}
|
resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==}
|
||||||
engines: {node: '>=10.16.0'}
|
engines: {node: '>=10.16.0'}
|
||||||
|
@ -12030,7 +12126,6 @@ packages:
|
||||||
/commander@4.1.1:
|
/commander@4.1.1:
|
||||||
resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==}
|
resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==}
|
||||||
engines: {node: '>= 6'}
|
engines: {node: '>= 6'}
|
||||||
dev: false
|
|
||||||
|
|
||||||
/commander@5.1.0:
|
/commander@5.1.0:
|
||||||
resolution: {integrity: sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==}
|
resolution: {integrity: sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==}
|
||||||
|
@ -12127,6 +12222,22 @@ packages:
|
||||||
semver: 7.5.1
|
semver: 7.5.1
|
||||||
well-known-symbols: 2.0.0
|
well-known-symbols: 2.0.0
|
||||||
|
|
||||||
|
/concurrently@8.1.0:
|
||||||
|
resolution: {integrity: sha512-0AB6eOAtaW/r/kX2lCdolaWtT191ICeuJjEJvI9hT3zbPFuZ/iZaJwMRKwbuwADome7OKxk73L7od+fsveZ7tA==}
|
||||||
|
engines: {node: ^14.13.0 || >=16.0.0}
|
||||||
|
hasBin: true
|
||||||
|
dependencies:
|
||||||
|
chalk: 4.1.2
|
||||||
|
date-fns: 2.29.3
|
||||||
|
lodash: 4.17.21
|
||||||
|
rxjs: 7.8.0
|
||||||
|
shell-quote: 1.8.0
|
||||||
|
spawn-command: 0.0.2-1
|
||||||
|
supports-color: 8.1.1
|
||||||
|
tree-kill: 1.2.2
|
||||||
|
yargs: 17.7.2
|
||||||
|
dev: true
|
||||||
|
|
||||||
/config-chain@1.1.13:
|
/config-chain@1.1.13:
|
||||||
resolution: {integrity: sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==}
|
resolution: {integrity: sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==}
|
||||||
dependencies:
|
dependencies:
|
||||||
|
@ -12409,7 +12520,6 @@ packages:
|
||||||
/date-fns@2.29.3:
|
/date-fns@2.29.3:
|
||||||
resolution: {integrity: sha512-dDCnyH2WnnKusqvZZ6+jA1O51Ibt8ZMRNkDZdyAyK4YfbDwa/cEmuztzG5pk6hqlp9aSBPYcjOlktquahGwGeA==}
|
resolution: {integrity: sha512-dDCnyH2WnnKusqvZZ6+jA1O51Ibt8ZMRNkDZdyAyK4YfbDwa/cEmuztzG5pk6hqlp9aSBPYcjOlktquahGwGeA==}
|
||||||
engines: {node: '>=0.11'}
|
engines: {node: '>=0.11'}
|
||||||
dev: false
|
|
||||||
|
|
||||||
/date-time@3.1.0:
|
/date-time@3.1.0:
|
||||||
resolution: {integrity: sha512-uqCUKXE5q1PNBXjPqvwhwJf9SwMoAHBgWJ6DcrnS5o+W2JOiIILl0JEdVD8SGujrNS02GGxgwAg2PN2zONgtjg==}
|
resolution: {integrity: sha512-uqCUKXE5q1PNBXjPqvwhwJf9SwMoAHBgWJ6DcrnS5o+W2JOiIILl0JEdVD8SGujrNS02GGxgwAg2PN2zONgtjg==}
|
||||||
|
@ -12764,6 +12874,10 @@ packages:
|
||||||
resolution: {integrity: sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==}
|
resolution: {integrity: sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==}
|
||||||
engines: {node: '>=12'}
|
engines: {node: '>=12'}
|
||||||
|
|
||||||
|
/dotenv@16.1.4:
|
||||||
|
resolution: {integrity: sha512-m55RtE8AsPeJBpOIFKihEmqUcoVncQIwo7x9U8ZwLEZw9ZpXboz2c+rvog+jUaJvVrZ5kBOeYQBX5+8Aa/OZQw==}
|
||||||
|
engines: {node: '>=12'}
|
||||||
|
|
||||||
/dotenv@8.6.0:
|
/dotenv@8.6.0:
|
||||||
resolution: {integrity: sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g==}
|
resolution: {integrity: sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
|
@ -14200,6 +14314,17 @@ packages:
|
||||||
path-scurry: 1.9.2
|
path-scurry: 1.9.2
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/glob@7.1.6:
|
||||||
|
resolution: {integrity: sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==}
|
||||||
|
dependencies:
|
||||||
|
fs.realpath: 1.0.0
|
||||||
|
inflight: 1.0.6
|
||||||
|
inherits: 2.0.4
|
||||||
|
minimatch: 3.1.2
|
||||||
|
once: 1.4.0
|
||||||
|
path-is-absolute: 1.0.1
|
||||||
|
dev: true
|
||||||
|
|
||||||
/glob@7.1.7:
|
/glob@7.1.7:
|
||||||
resolution: {integrity: sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==}
|
resolution: {integrity: sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==}
|
||||||
dependencies:
|
dependencies:
|
||||||
|
@ -14308,6 +14433,24 @@ packages:
|
||||||
/graphemer@1.4.0:
|
/graphemer@1.4.0:
|
||||||
resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==}
|
resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==}
|
||||||
|
|
||||||
|
/graphile-worker@0.13.0:
|
||||||
|
resolution: {integrity: sha512-8Hl5XV6hkabZRhYzvbUfvjJfPFR5EPxYRVWlzQC2rqYHrjULTLBgBYZna5R9ukbnsbWSvn4vVrzOBIOgIC1jjw==}
|
||||||
|
engines: {node: '>=10.0.0'}
|
||||||
|
hasBin: true
|
||||||
|
dependencies:
|
||||||
|
'@graphile/logger': 0.2.0
|
||||||
|
'@types/debug': 4.1.7
|
||||||
|
'@types/pg': 8.10.1
|
||||||
|
chokidar: 3.5.3
|
||||||
|
cosmiconfig: 7.1.0
|
||||||
|
json5: 2.2.3
|
||||||
|
pg: 8.11.0
|
||||||
|
tslib: 2.5.3
|
||||||
|
yargs: 16.2.0
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- pg-native
|
||||||
|
dev: false
|
||||||
|
|
||||||
/graphql-config@4.5.0(@types/node@18.15.3)(graphql@16.6.0):
|
/graphql-config@4.5.0(@types/node@18.15.3)(graphql@16.6.0):
|
||||||
resolution: {integrity: sha512-x6D0/cftpLUJ0Ch1e5sj1TZn6Wcxx4oMfmhaG9shM0DKajA9iR+j1z86GSTQ19fShbGvrSSvbIQsHku6aQ6BBw==}
|
resolution: {integrity: sha512-x6D0/cftpLUJ0Ch1e5sj1TZn6Wcxx4oMfmhaG9shM0DKajA9iR+j1z86GSTQ19fShbGvrSSvbIQsHku6aQ6BBw==}
|
||||||
engines: {node: '>= 10.0.0'}
|
engines: {node: '>= 10.0.0'}
|
||||||
|
@ -15307,7 +15450,6 @@ packages:
|
||||||
/joycon@3.1.1:
|
/joycon@3.1.1:
|
||||||
resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==}
|
resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
dev: false
|
|
||||||
|
|
||||||
/js-beautify@1.14.7:
|
/js-beautify@1.14.7:
|
||||||
resolution: {integrity: sha512-5SOX1KXPFKx+5f6ZrPsIPEY7NwKeQz47n3jm2i+XeHx9MoRsfQenlOP13FQhWvg8JRS0+XLO6XYUQ2GX+q+T9A==}
|
resolution: {integrity: sha512-5SOX1KXPFKx+5f6ZrPsIPEY7NwKeQz47n3jm2i+XeHx9MoRsfQenlOP13FQhWvg8JRS0+XLO6XYUQ2GX+q+T9A==}
|
||||||
|
@ -15657,7 +15799,7 @@ packages:
|
||||||
engines: {node: '>=14.0.0'}
|
engines: {node: '>=14.0.0'}
|
||||||
dependencies:
|
dependencies:
|
||||||
app-root-dir: 1.0.2
|
app-root-dir: 1.0.2
|
||||||
dotenv: 16.0.3
|
dotenv: 16.1.4
|
||||||
dotenv-expand: 10.0.0
|
dotenv-expand: 10.0.0
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
@ -15790,6 +15932,11 @@ packages:
|
||||||
wrap-ansi: 7.0.0
|
wrap-ansi: 7.0.0
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/load-tsconfig@0.2.5:
|
||||||
|
resolution: {integrity: sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg==}
|
||||||
|
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
|
||||||
|
dev: true
|
||||||
|
|
||||||
/load-yaml-file@0.2.0:
|
/load-yaml-file@0.2.0:
|
||||||
resolution: {integrity: sha512-OfCBkGEw4nN6JLtgRidPX6QxjBQGQf72q3si2uvqyFEMbycSFFHwAZeXx6cJgFM9wmLrf9zBwCP3Ivqa+LLZPw==}
|
resolution: {integrity: sha512-OfCBkGEw4nN6JLtgRidPX6QxjBQGQf72q3si2uvqyFEMbycSFFHwAZeXx6cJgFM9wmLrf9zBwCP3Ivqa+LLZPw==}
|
||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
|
@ -15891,6 +16038,10 @@ packages:
|
||||||
/lodash.merge@4.6.2:
|
/lodash.merge@4.6.2:
|
||||||
resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==}
|
resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==}
|
||||||
|
|
||||||
|
/lodash.sortby@4.7.0:
|
||||||
|
resolution: {integrity: sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==}
|
||||||
|
dev: true
|
||||||
|
|
||||||
/lodash.startcase@4.4.0:
|
/lodash.startcase@4.4.0:
|
||||||
resolution: {integrity: sha512-+WKqsK294HMSc2jEbNgpHpd0JfIBhp7rEV4aqXWqFr6AlXov+SlcgB1Fv01y2kGe3Gc8nMW7VA0SrGuSkRfIEg==}
|
resolution: {integrity: sha512-+WKqsK294HMSc2jEbNgpHpd0JfIBhp7rEV4aqXWqFr6AlXov+SlcgB1Fv01y2kGe3Gc8nMW7VA0SrGuSkRfIEg==}
|
||||||
|
|
||||||
|
@ -16940,6 +17091,14 @@ packages:
|
||||||
resolution: {integrity: sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==}
|
resolution: {integrity: sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/mz@2.7.0:
|
||||||
|
resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==}
|
||||||
|
dependencies:
|
||||||
|
any-promise: 1.3.0
|
||||||
|
object-assign: 4.1.1
|
||||||
|
thenify-all: 1.6.0
|
||||||
|
dev: true
|
||||||
|
|
||||||
/nano-css@5.3.5(react-dom@18.2.0)(react@18.2.0):
|
/nano-css@5.3.5(react-dom@18.2.0)(react@18.2.0):
|
||||||
resolution: {integrity: sha512-vSB9X12bbNu4ALBu7nigJgRViZ6ja3OU7CeuiV1zMIbXOdmkLahgtPmh3GBOlDxbKY0CitqlPdOReGlBLSp+yg==}
|
resolution: {integrity: sha512-vSB9X12bbNu4ALBu7nigJgRViZ6ja3OU7CeuiV1zMIbXOdmkLahgtPmh3GBOlDxbKY0CitqlPdOReGlBLSp+yg==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
|
@ -17381,6 +17540,10 @@ packages:
|
||||||
resolution: {integrity: sha512-z+pI07qxo4c2CulUHCDf9lcqDlMSo72N/4rLUpRXf6fu+q8vjt8y0xS+Tlf8NTJDdTXHbdeO1n3MlbctwEoXZw==}
|
resolution: {integrity: sha512-z+pI07qxo4c2CulUHCDf9lcqDlMSo72N/4rLUpRXf6fu+q8vjt8y0xS+Tlf8NTJDdTXHbdeO1n3MlbctwEoXZw==}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/obuf@1.1.2:
|
||||||
|
resolution: {integrity: sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/on-exit-leak-free@2.1.0:
|
/on-exit-leak-free@2.1.0:
|
||||||
resolution: {integrity: sha512-VuCaZZAjReZ3vUwgOB8LxAosIurDiAW0s13rI1YwmaP++jvcxP77AWoQvenZebpCA2m8WC1/EosPYPMjnRAp/w==}
|
resolution: {integrity: sha512-VuCaZZAjReZ3vUwgOB8LxAosIurDiAW0s13rI1YwmaP++jvcxP77AWoQvenZebpCA2m8WC1/EosPYPMjnRAp/w==}
|
||||||
dev: false
|
dev: false
|
||||||
|
@ -17544,6 +17707,10 @@ packages:
|
||||||
resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==}
|
resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==}
|
||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
|
|
||||||
|
/packet-reader@1.0.0:
|
||||||
|
resolution: {integrity: sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/pako@0.2.9:
|
/pako@0.2.9:
|
||||||
resolution: {integrity: sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA==}
|
resolution: {integrity: sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA==}
|
||||||
|
|
||||||
|
@ -17717,6 +17884,88 @@ packages:
|
||||||
resolution: {integrity: sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==}
|
resolution: {integrity: sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/pg-cloudflare@1.1.0:
|
||||||
|
resolution: {integrity: sha512-tGM8/s6frwuAIyRcJ6nWcIvd3+3NmUKIs6OjviIm1HPPFEt5MzQDOTBQyhPWg/m0kCl95M6gA1JaIXtS8KovOA==}
|
||||||
|
requiresBuild: true
|
||||||
|
dev: false
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
/pg-connection-string@2.6.0:
|
||||||
|
resolution: {integrity: sha512-x14ibktcwlHKoHxx9X3uTVW9zIGR41ZB6QNhHb21OPNdCCO3NaRnpJuwKIQSR4u+Yqjx4HCvy7Hh7VSy1U4dGg==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/pg-int8@1.0.1:
|
||||||
|
resolution: {integrity: sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==}
|
||||||
|
engines: {node: '>=4.0.0'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/pg-numeric@1.0.2:
|
||||||
|
resolution: {integrity: sha512-BM/Thnrw5jm2kKLE5uJkXqqExRUY/toLHda65XgFTBTFYZyopbKjBe29Ii3RbkvlsMoFwD+tHeGaCjjv0gHlyw==}
|
||||||
|
engines: {node: '>=4'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/pg-pool@3.6.0(pg@8.11.0):
|
||||||
|
resolution: {integrity: sha512-clFRf2ksqd+F497kWFyM21tMjeikn60oGDmqMT8UBrynEwVEX/5R5xd2sdvdo1cZCFlguORNpVuqxIj+aK4cfQ==}
|
||||||
|
peerDependencies:
|
||||||
|
pg: '>=8.0'
|
||||||
|
dependencies:
|
||||||
|
pg: 8.11.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/pg-protocol@1.6.0:
|
||||||
|
resolution: {integrity: sha512-M+PDm637OY5WM307051+bsDia5Xej6d9IR4GwJse1qA1DIhiKlksvrneZOYQq42OM+spubpcNYEo2FcKQrDk+Q==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/pg-types@2.2.0:
|
||||||
|
resolution: {integrity: sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==}
|
||||||
|
engines: {node: '>=4'}
|
||||||
|
dependencies:
|
||||||
|
pg-int8: 1.0.1
|
||||||
|
postgres-array: 2.0.0
|
||||||
|
postgres-bytea: 1.0.0
|
||||||
|
postgres-date: 1.0.7
|
||||||
|
postgres-interval: 1.2.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/pg-types@4.0.1:
|
||||||
|
resolution: {integrity: sha512-hRCSDuLII9/LE3smys1hRHcu5QGcLs9ggT7I/TCs0IE+2Eesxi9+9RWAAwZ0yaGjxoWICF/YHLOEjydGujoJ+g==}
|
||||||
|
engines: {node: '>=10'}
|
||||||
|
dependencies:
|
||||||
|
pg-int8: 1.0.1
|
||||||
|
pg-numeric: 1.0.2
|
||||||
|
postgres-array: 3.0.2
|
||||||
|
postgres-bytea: 3.0.0
|
||||||
|
postgres-date: 2.0.1
|
||||||
|
postgres-interval: 3.0.0
|
||||||
|
postgres-range: 1.1.3
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/pg@8.11.0:
|
||||||
|
resolution: {integrity: sha512-meLUVPn2TWgJyLmy7el3fQQVwft4gU5NGyvV0XbD41iU9Jbg8lCH4zexhIkihDzVHJStlt6r088G6/fWeNjhXA==}
|
||||||
|
engines: {node: '>= 8.0.0'}
|
||||||
|
peerDependencies:
|
||||||
|
pg-native: '>=3.0.1'
|
||||||
|
peerDependenciesMeta:
|
||||||
|
pg-native:
|
||||||
|
optional: true
|
||||||
|
dependencies:
|
||||||
|
buffer-writer: 2.0.0
|
||||||
|
packet-reader: 1.0.0
|
||||||
|
pg-connection-string: 2.6.0
|
||||||
|
pg-pool: 3.6.0(pg@8.11.0)
|
||||||
|
pg-protocol: 1.6.0
|
||||||
|
pg-types: 2.2.0
|
||||||
|
pgpass: 1.0.5
|
||||||
|
optionalDependencies:
|
||||||
|
pg-cloudflare: 1.1.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/pgpass@1.0.5:
|
||||||
|
resolution: {integrity: sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==}
|
||||||
|
dependencies:
|
||||||
|
split2: 4.1.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
/picocolors@1.0.0:
|
/picocolors@1.0.0:
|
||||||
resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==}
|
resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==}
|
||||||
|
|
||||||
|
@ -17878,6 +18127,54 @@ packages:
|
||||||
picocolors: 1.0.0
|
picocolors: 1.0.0
|
||||||
source-map-js: 1.0.2
|
source-map-js: 1.0.2
|
||||||
|
|
||||||
|
/postgres-array@2.0.0:
|
||||||
|
resolution: {integrity: sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==}
|
||||||
|
engines: {node: '>=4'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/postgres-array@3.0.2:
|
||||||
|
resolution: {integrity: sha512-6faShkdFugNQCLwucjPcY5ARoW1SlbnrZjmGl0IrrqewpvxvhSLHimCVzqeuULCbG0fQv7Dtk1yDbG3xv7Veog==}
|
||||||
|
engines: {node: '>=12'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/postgres-bytea@1.0.0:
|
||||||
|
resolution: {integrity: sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==}
|
||||||
|
engines: {node: '>=0.10.0'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/postgres-bytea@3.0.0:
|
||||||
|
resolution: {integrity: sha512-CNd4jim9RFPkObHSjVHlVrxoVQXz7quwNFpz7RY1okNNme49+sVyiTvTRobiLV548Hx/hb1BG+iE7h9493WzFw==}
|
||||||
|
engines: {node: '>= 6'}
|
||||||
|
dependencies:
|
||||||
|
obuf: 1.1.2
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/postgres-date@1.0.7:
|
||||||
|
resolution: {integrity: sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==}
|
||||||
|
engines: {node: '>=0.10.0'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/postgres-date@2.0.1:
|
||||||
|
resolution: {integrity: sha512-YtMKdsDt5Ojv1wQRvUhnyDJNSr2dGIC96mQVKz7xufp07nfuFONzdaowrMHjlAzY6GDLd4f+LUHHAAM1h4MdUw==}
|
||||||
|
engines: {node: '>=12'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/postgres-interval@1.2.0:
|
||||||
|
resolution: {integrity: sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==}
|
||||||
|
engines: {node: '>=0.10.0'}
|
||||||
|
dependencies:
|
||||||
|
xtend: 4.0.2
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/postgres-interval@3.0.0:
|
||||||
|
resolution: {integrity: sha512-BSNDnbyZCXSxgA+1f5UU2GmwhoI0aU5yMxRGO8CdFEcY2BQF9xm/7MqKnYoM1nJDk8nONNWDk9WeSmePFhQdlw==}
|
||||||
|
engines: {node: '>=12'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/postgres-range@1.1.3:
|
||||||
|
resolution: {integrity: sha512-VdlZoocy5lCP0c/t66xAfclglEapXPCIVhqqJRncYpvbCgImF0w67aPKfbqUMr72tO2k5q0TdTZwCLjPTI6C9g==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/preferred-pm@3.0.3:
|
/preferred-pm@3.0.3:
|
||||||
resolution: {integrity: sha512-+wZgbxNES/KlJs9q40F/1sfOd/j7f1O9JaHcW5Dsn3aUUOZg3L2bjpVUcKV2jvtElYfoTuQiNeMfQJ4kwUAhCQ==}
|
resolution: {integrity: sha512-+wZgbxNES/KlJs9q40F/1sfOd/j7f1O9JaHcW5Dsn3aUUOZg3L2bjpVUcKV2jvtElYfoTuQiNeMfQJ4kwUAhCQ==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
|
@ -17935,6 +18232,15 @@ packages:
|
||||||
prettier: 2.8.8
|
prettier: 2.8.8
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/prisma@4.15.0:
|
||||||
|
resolution: {integrity: sha512-iKZZpobPl48gTcSZVawLMQ3lEy6BnXwtoMj7hluoGFYu2kQ6F9LBuBrUyF95zRVnNo8/3KzLXJXJ5TEnLSJFiA==}
|
||||||
|
engines: {node: '>=14.17'}
|
||||||
|
hasBin: true
|
||||||
|
requiresBuild: true
|
||||||
|
dependencies:
|
||||||
|
'@prisma/engines': 4.15.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
/process-nextick-args@2.0.1:
|
/process-nextick-args@2.0.1:
|
||||||
resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==}
|
resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==}
|
||||||
|
|
||||||
|
@ -19452,6 +19758,13 @@ packages:
|
||||||
resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==}
|
resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
|
|
||||||
|
/source-map@0.8.0-beta.0:
|
||||||
|
resolution: {integrity: sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==}
|
||||||
|
engines: {node: '>= 8'}
|
||||||
|
dependencies:
|
||||||
|
whatwg-url: 7.1.0
|
||||||
|
dev: true
|
||||||
|
|
||||||
/sourcemap-codec@1.4.8:
|
/sourcemap-codec@1.4.8:
|
||||||
resolution: {integrity: sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==}
|
resolution: {integrity: sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==}
|
||||||
deprecated: Please use @jridgewell/sourcemap-codec instead
|
deprecated: Please use @jridgewell/sourcemap-codec instead
|
||||||
|
@ -19465,6 +19778,10 @@ packages:
|
||||||
resolution: {integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==}
|
resolution: {integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/spawn-command@0.0.2-1:
|
||||||
|
resolution: {integrity: sha512-n98l9E2RMSJ9ON1AKisHzz7V42VDiBQGY6PB1BwRglz99wpVsSuGzQ+jOi6lFXBGVTCrRpltvjm+/XA+tpeJrg==}
|
||||||
|
dev: true
|
||||||
|
|
||||||
/spawndamnit@2.0.0:
|
/spawndamnit@2.0.0:
|
||||||
resolution: {integrity: sha512-j4JKEcncSjFlqIwU5L/rp2N5SIPsdxaRsIv678+TZxZ0SRDJTm8JrxJMjE/XuiEZNEir3S8l0Fa3Ke339WI4qA==}
|
resolution: {integrity: sha512-j4JKEcncSjFlqIwU5L/rp2N5SIPsdxaRsIv678+TZxZ0SRDJTm8JrxJMjE/XuiEZNEir3S8l0Fa3Ke339WI4qA==}
|
||||||
dependencies:
|
dependencies:
|
||||||
|
@ -19776,6 +20093,20 @@ packages:
|
||||||
resolution: {integrity: sha512-GP6WDNWf+o403jrEp9c5jibKavrtLW+/qYGhFxFrG8maXhwTBI7gLLhiBb0o7uFccWN+EOS9aMO6cGHWAO07OA==}
|
resolution: {integrity: sha512-GP6WDNWf+o403jrEp9c5jibKavrtLW+/qYGhFxFrG8maXhwTBI7gLLhiBb0o7uFccWN+EOS9aMO6cGHWAO07OA==}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/sucrase@3.32.0:
|
||||||
|
resolution: {integrity: sha512-ydQOU34rpSyj2TGyz4D2p8rbktIOZ8QY9s+DGLvFU1i5pWJE8vkpruCjGCMHsdXwnD7JDcS+noSwM/a7zyNFDQ==}
|
||||||
|
engines: {node: '>=8'}
|
||||||
|
hasBin: true
|
||||||
|
dependencies:
|
||||||
|
'@jridgewell/gen-mapping': 0.3.3
|
||||||
|
commander: 4.1.1
|
||||||
|
glob: 7.1.6
|
||||||
|
lines-and-columns: 1.2.4
|
||||||
|
mz: 2.7.0
|
||||||
|
pirates: 4.0.5
|
||||||
|
ts-interface-checker: 0.1.13
|
||||||
|
dev: true
|
||||||
|
|
||||||
/superagent@3.8.1:
|
/superagent@3.8.1:
|
||||||
resolution: {integrity: sha512-VMBFLYgFuRdfeNQSMLbxGSLfmXL/xc+OO+BZp41Za/NRDBet/BNbkRJrYzCUu0u4GU0i/ml2dtT8b9qgkw9z6Q==}
|
resolution: {integrity: sha512-VMBFLYgFuRdfeNQSMLbxGSLfmXL/xc+OO+BZp41Za/NRDBet/BNbkRJrYzCUu0u4GU0i/ml2dtT8b9qgkw9z6Q==}
|
||||||
engines: {node: '>= 4.0'}
|
engines: {node: '>= 4.0'}
|
||||||
|
@ -19982,6 +20313,19 @@ packages:
|
||||||
/text-table@0.2.0:
|
/text-table@0.2.0:
|
||||||
resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==}
|
resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==}
|
||||||
|
|
||||||
|
/thenify-all@1.6.0:
|
||||||
|
resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==}
|
||||||
|
engines: {node: '>=0.8'}
|
||||||
|
dependencies:
|
||||||
|
thenify: 3.3.1
|
||||||
|
dev: true
|
||||||
|
|
||||||
|
/thenify@3.3.1:
|
||||||
|
resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==}
|
||||||
|
dependencies:
|
||||||
|
any-promise: 1.3.0
|
||||||
|
dev: true
|
||||||
|
|
||||||
/thread-stream@2.3.0:
|
/thread-stream@2.3.0:
|
||||||
resolution: {integrity: sha512-kaDqm1DET9pp3NXwR8382WHbnpXnRkN9xGN9dQt3B2+dmXiW8X1SOwmFOxAErEQ47ObhZ96J6yhZNXuyCOL7KA==}
|
resolution: {integrity: sha512-kaDqm1DET9pp3NXwR8382WHbnpXnRkN9xGN9dQt3B2+dmXiW8X1SOwmFOxAErEQ47ObhZ96J6yhZNXuyCOL7KA==}
|
||||||
dependencies:
|
dependencies:
|
||||||
|
@ -20128,6 +20472,12 @@ packages:
|
||||||
/tr46@0.0.3:
|
/tr46@0.0.3:
|
||||||
resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==}
|
resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==}
|
||||||
|
|
||||||
|
/tr46@1.0.1:
|
||||||
|
resolution: {integrity: sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==}
|
||||||
|
dependencies:
|
||||||
|
punycode: 2.3.0
|
||||||
|
dev: true
|
||||||
|
|
||||||
/tr46@3.0.0:
|
/tr46@3.0.0:
|
||||||
resolution: {integrity: sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==}
|
resolution: {integrity: sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==}
|
||||||
engines: {node: '>=12'}
|
engines: {node: '>=12'}
|
||||||
|
@ -20146,6 +20496,11 @@ packages:
|
||||||
resolution: {integrity: sha512-iawgk0hLP3SxGKDfnDJf8wTz4p2qImnyihM5Hh/sGvQ3K37dPi/w8sRhdNIxYA1TwFwc5mDhIJq+O0RsvXBKdQ==}
|
resolution: {integrity: sha512-iawgk0hLP3SxGKDfnDJf8wTz4p2qImnyihM5Hh/sGvQ3K37dPi/w8sRhdNIxYA1TwFwc5mDhIJq+O0RsvXBKdQ==}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/tree-kill@1.2.2:
|
||||||
|
resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==}
|
||||||
|
hasBin: true
|
||||||
|
dev: true
|
||||||
|
|
||||||
/trim-lines@3.0.1:
|
/trim-lines@3.0.1:
|
||||||
resolution: {integrity: sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==}
|
resolution: {integrity: sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==}
|
||||||
dev: false
|
dev: false
|
||||||
|
@ -20167,6 +20522,10 @@ packages:
|
||||||
resolution: {integrity: sha512-Z86EW+fFFh/IFB1fqQ3/+7Zpf9t2ebOAxNI/V6Wo7r5gqiqtxmgTlQ1qbqQcjLKYeSHPTsEmvlJUDg/EuL0uHQ==}
|
resolution: {integrity: sha512-Z86EW+fFFh/IFB1fqQ3/+7Zpf9t2ebOAxNI/V6Wo7r5gqiqtxmgTlQ1qbqQcjLKYeSHPTsEmvlJUDg/EuL0uHQ==}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/ts-interface-checker@0.1.13:
|
||||||
|
resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==}
|
||||||
|
dev: true
|
||||||
|
|
||||||
/ts-log@2.2.5:
|
/ts-log@2.2.5:
|
||||||
resolution: {integrity: sha512-PGcnJoTBnVGy6yYNFxWVNkdcAuAMstvutN9MgDJIV6L0oG8fB+ZNNy1T+wJzah8RPGor1mZuPQkVfXNDpy9eHA==}
|
resolution: {integrity: sha512-PGcnJoTBnVGy6yYNFxWVNkdcAuAMstvutN9MgDJIV6L0oG8fB+ZNNy1T+wJzah8RPGor1mZuPQkVfXNDpy9eHA==}
|
||||||
dev: true
|
dev: true
|
||||||
|
@ -20197,6 +20556,42 @@ packages:
|
||||||
/tslib@2.5.3:
|
/tslib@2.5.3:
|
||||||
resolution: {integrity: sha512-mSxlJJwl3BMEQCUNnxXBU9jP4JBktcEGhURcPR6VQVlnP0FdDEsIaz0C35dXNGLyRfrATNofF0F5p2KPxQgB+w==}
|
resolution: {integrity: sha512-mSxlJJwl3BMEQCUNnxXBU9jP4JBktcEGhURcPR6VQVlnP0FdDEsIaz0C35dXNGLyRfrATNofF0F5p2KPxQgB+w==}
|
||||||
|
|
||||||
|
/tsup@6.7.0(typescript@5.1.3):
|
||||||
|
resolution: {integrity: sha512-L3o8hGkaHnu5TdJns+mCqFsDBo83bJ44rlK7e6VdanIvpea4ArPcU3swWGsLVbXak1PqQx/V+SSmFPujBK+zEQ==}
|
||||||
|
engines: {node: '>=14.18'}
|
||||||
|
hasBin: true
|
||||||
|
peerDependencies:
|
||||||
|
'@swc/core': ^1
|
||||||
|
postcss: ^8.4.12
|
||||||
|
typescript: '>=4.1.0'
|
||||||
|
peerDependenciesMeta:
|
||||||
|
'@swc/core':
|
||||||
|
optional: true
|
||||||
|
postcss:
|
||||||
|
optional: true
|
||||||
|
typescript:
|
||||||
|
optional: true
|
||||||
|
dependencies:
|
||||||
|
bundle-require: 4.0.1(esbuild@0.17.17)
|
||||||
|
cac: 6.7.14
|
||||||
|
chokidar: 3.5.3
|
||||||
|
debug: 4.3.4
|
||||||
|
esbuild: 0.17.17
|
||||||
|
execa: 5.1.1
|
||||||
|
globby: 11.1.0
|
||||||
|
joycon: 3.1.1
|
||||||
|
postcss-load-config: 3.1.4(postcss@8.4.21)
|
||||||
|
resolve-from: 5.0.0
|
||||||
|
rollup: 3.23.0
|
||||||
|
source-map: 0.8.0-beta.0
|
||||||
|
sucrase: 3.32.0
|
||||||
|
tree-kill: 1.2.2
|
||||||
|
typescript: 5.1.3
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- supports-color
|
||||||
|
- ts-node
|
||||||
|
dev: true
|
||||||
|
|
||||||
/tsutils@3.21.0(typescript@5.1.3):
|
/tsutils@3.21.0(typescript@5.1.3):
|
||||||
resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==}
|
resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==}
|
||||||
engines: {node: '>= 6'}
|
engines: {node: '>= 6'}
|
||||||
|
@ -20207,6 +20602,17 @@ packages:
|
||||||
typescript: 5.1.3
|
typescript: 5.1.3
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/tsx@3.12.7:
|
||||||
|
resolution: {integrity: sha512-C2Ip+jPmqKd1GWVQDvz/Eyc6QJbGfE7NrR3fx5BpEHMZsEHoIxHL1j+lKdGobr8ovEyqeNkPLSKp6SCSOt7gmw==}
|
||||||
|
hasBin: true
|
||||||
|
dependencies:
|
||||||
|
'@esbuild-kit/cjs-loader': 2.4.2
|
||||||
|
'@esbuild-kit/core-utils': 3.1.0
|
||||||
|
'@esbuild-kit/esm-loader': 2.5.5
|
||||||
|
optionalDependencies:
|
||||||
|
fsevents: 2.3.2
|
||||||
|
dev: true
|
||||||
|
|
||||||
/tty-table@4.1.6:
|
/tty-table@4.1.6:
|
||||||
resolution: {integrity: sha512-kRj5CBzOrakV4VRRY5kUWbNYvo/FpOsz65DzI5op9P+cHov3+IqPbo1JE1ZnQGkHdZgNFDsrEjrfqqy/Ply9fw==}
|
resolution: {integrity: sha512-kRj5CBzOrakV4VRRY5kUWbNYvo/FpOsz65DzI5op9P+cHov3+IqPbo1JE1ZnQGkHdZgNFDsrEjrfqqy/Ply9fw==}
|
||||||
engines: {node: '>=8.0.0'}
|
engines: {node: '>=8.0.0'}
|
||||||
|
@ -20218,7 +20624,7 @@ packages:
|
||||||
smartwrap: 2.0.2
|
smartwrap: 2.0.2
|
||||||
strip-ansi: 6.0.1
|
strip-ansi: 6.0.1
|
||||||
wcwidth: 1.0.1
|
wcwidth: 1.0.1
|
||||||
yargs: 17.6.2
|
yargs: 17.7.2
|
||||||
|
|
||||||
/tunnel-agent@0.6.0:
|
/tunnel-agent@0.6.0:
|
||||||
resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==}
|
resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==}
|
||||||
|
@ -21178,6 +21584,10 @@ packages:
|
||||||
/webidl-conversions@3.0.1:
|
/webidl-conversions@3.0.1:
|
||||||
resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==}
|
resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==}
|
||||||
|
|
||||||
|
/webidl-conversions@4.0.2:
|
||||||
|
resolution: {integrity: sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==}
|
||||||
|
dev: true
|
||||||
|
|
||||||
/webidl-conversions@7.0.0:
|
/webidl-conversions@7.0.0:
|
||||||
resolution: {integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==}
|
resolution: {integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==}
|
||||||
engines: {node: '>=12'}
|
engines: {node: '>=12'}
|
||||||
|
@ -21261,6 +21671,14 @@ packages:
|
||||||
tr46: 0.0.3
|
tr46: 0.0.3
|
||||||
webidl-conversions: 3.0.1
|
webidl-conversions: 3.0.1
|
||||||
|
|
||||||
|
/whatwg-url@7.1.0:
|
||||||
|
resolution: {integrity: sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==}
|
||||||
|
dependencies:
|
||||||
|
lodash.sortby: 4.7.0
|
||||||
|
tr46: 1.0.1
|
||||||
|
webidl-conversions: 4.0.2
|
||||||
|
dev: true
|
||||||
|
|
||||||
/which-boxed-primitive@1.0.2:
|
/which-boxed-primitive@1.0.2:
|
||||||
resolution: {integrity: sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==}
|
resolution: {integrity: sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==}
|
||||||
dependencies:
|
dependencies:
|
||||||
|
@ -21447,7 +21865,6 @@ packages:
|
||||||
/xtend@4.0.2:
|
/xtend@4.0.2:
|
||||||
resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==}
|
resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==}
|
||||||
engines: {node: '>=0.4'}
|
engines: {node: '>=0.4'}
|
||||||
dev: true
|
|
||||||
|
|
||||||
/y18n@4.0.3:
|
/y18n@4.0.3:
|
||||||
resolution: {integrity: sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==}
|
resolution: {integrity: sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==}
|
||||||
|
@ -21532,6 +21949,19 @@ packages:
|
||||||
string-width: 4.2.3
|
string-width: 4.2.3
|
||||||
y18n: 5.0.8
|
y18n: 5.0.8
|
||||||
yargs-parser: 21.1.1
|
yargs-parser: 21.1.1
|
||||||
|
dev: true
|
||||||
|
|
||||||
|
/yargs@17.7.2:
|
||||||
|
resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==}
|
||||||
|
engines: {node: '>=12'}
|
||||||
|
dependencies:
|
||||||
|
cliui: 8.0.1
|
||||||
|
escalade: 3.1.1
|
||||||
|
get-caller-file: 2.0.5
|
||||||
|
require-directory: 2.1.1
|
||||||
|
string-width: 4.2.3
|
||||||
|
y18n: 5.0.8
|
||||||
|
yargs-parser: 21.1.1
|
||||||
|
|
||||||
/yauzl@2.10.0:
|
/yauzl@2.10.0:
|
||||||
resolution: {integrity: sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==}
|
resolution: {integrity: sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==}
|
||||||
|
|
|
@ -8,6 +8,11 @@
|
||||||
"dependsOn": ["^build"],
|
"dependsOn": ["^build"],
|
||||||
"outputs": ["dist/**", ".next/**"]
|
"outputs": ["dist/**", ".next/**"]
|
||||||
},
|
},
|
||||||
|
"build:app": {
|
||||||
|
"env": ["NEXT_PUBLIC_VERCEL_ENV"],
|
||||||
|
"dependsOn": ["^build"],
|
||||||
|
"outputs": ["dist/**", ".next/**"]
|
||||||
|
},
|
||||||
"lint": {
|
"lint": {
|
||||||
"inputs": ["src"],
|
"inputs": ["src"],
|
||||||
"outputs": []
|
"outputs": []
|
||||||
|
|
Loading…
Reference in a new issue